diff --git a/.env-dist b/.env-dist index a4fcd1c..8357fea 100644 --- a/.env-dist +++ b/.env-dist @@ -29,13 +29,6 @@ REDIS_PORT=6379 REDIS_DATABASE=0 REDIS_PASSWORD= -## Параметры подключения к rabbitmq -RABBITMQ_HOST=rabbitmq -RABBITMQ_PORT=5672 -RABBITMQ_USER=ely-accounts-app -RABBITMQ_PASS=ely-accounts-app-password -RABBITMQ_VHOST=/ely.by - ## Параметры Statsd STATSD_HOST=statsd.ely.by STATSD_PORT=8125 @@ -59,8 +52,3 @@ MYSQL_ROOT_PASSWORD= MYSQL_DATABASE=ely_accounts MYSQL_USER=ely_accounts_user MYSQL_PASSWORD=ely_accounts_password - -# RabbitMQ -RABBITMQ_DEFAULT_USER=ely-accounts-app -RABBITMQ_DEFAULT_PASS=ely-accounts-app-password -RABBITMQ_DEFAULT_VHOST=/ely.by diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8deb81b..6fda076 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,50 +6,52 @@ stages: variables: CONTAINER_IMAGE: "registry.ely.by/elyby/accounts" -test:backend: - image: docker:18.02 +check backend codestyle: + image: edbizarro/gitlab-ci-pipeline-php:7.2-alpine + stage: test + cache: + key: backend-vendor + paths: + - vendor + script: + - composer install + - vendor/bin/php-cs-fixer fix -v --dry-run + +test backend: + image: edbizarro/gitlab-ci-pipeline-php:7.2-alpine services: - - mariadb:10.2.11 - - redis:3.0-alpine + - name: redis:4.0.10-alpine + alias: redis + - name: mariadb:10.2.11 + alias: db variables: - # mariadb config + # App config + DB_HOST: "db" + DB_DATABASE: "ely_accounts_test" + DB_USER: "ely_accounts_tester" + DB_PASSWORD: "ely_accounts_tester_password" + REDIS_HOST: "redis" + REDIS_PORT: "6379" + # MariaDB config MYSQL_RANDOM_ROOT_PASSWORD: "true" MYSQL_DATABASE: "ely_accounts_test" MYSQL_USER: "ely_accounts_tester" MYSQL_PASSWORD: "ely_accounts_tester_password" stage: test + cache: + key: backend-vendor + paths: + - vendor before_script: - - docker login -u gitlab-ci -p $CI_BUILD_TOKEN registry.ely.by - - echo "$SSH_PRIVATE_KEY" > id_rsa + # While we not counting coverage, xdebug only slow down tests + - sudo rm /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini script: - - export TEMP_DEV_IMAGE="${CONTAINER_IMAGE}:ci-${CI_BUILD_ID}" - - docker build --pull -f Dockerfile-dev -t $TEMP_DEV_IMAGE . - - > - docker run --rm - $TEMP_DEV_IMAGE - bash -c " - rm /usr/local/etc/php/conf.d/xdebug.ini && - cp -r /var/www/vendor /var/www/html/vendor && - vendor/bin/php-cs-fixer fix -v --dry-run - " - - > - docker run --rm - --add-host=mariadb:`getent hosts mariadb | awk '{ print $1 ; exit }'` - --add-host=redis:`getent hosts redis | awk '{ print $1 ; exit }'` - -e YII_DEBUG="true" - -e YII_ENV="test" - -e DB_HOST="mariadb" - -e DB_DATABASE="ely_accounts_test" - -e DB_USER="ely_accounts_tester" - -e DB_PASSWORD="ely_accounts_tester_password" - -e REDIS_HOST="redis" - $TEMP_DEV_IMAGE - bash -c " - rm /usr/local/etc/php/conf.d/xdebug.ini && - docker-entrypoint.sh php vendor/bin/codecept run -c tests - " + - composer install + - php tests/codeception/bin/yii rbac/generate + - ./docker/php/wait-for-it.sh "${DB_HOST}:3306" -s -t 0 -- "php tests/codeception/bin/yii migrate/up --interactive=0" + - vendor/bin/codecept run -c tests -test:frontend: +test frontend: image: node:9.2.1-alpine stage: test cache: @@ -58,10 +60,10 @@ test:frontend: before_script: # Enable SSL support for wget - apk add --update openssl - # https://github.com/facebook/flow/issues/3649#issuecomment-308070179 - - wget -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub - - wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.25-r0/glibc-2.25-r0.apk - - apk add glibc-2.25-r0.apk + # https://github.com/facebook/flow/issues/3649#issuecomment-414691014 + - wget -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub + - wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk + - apk add glibc-2.28-r0.apk script: - cd frontend - yarn run build:install @@ -90,7 +92,7 @@ build:production: - sed -i"" -e "s/{{PLACE_VERSION_HERE}}/$VERSION/g" common/config/config.php script: - export IMAGE_NAME="$CONTAINER_IMAGE:latest" - - docker build --pull -t $IMAGE_NAME . + - docker build --pull --build-arg build_env=prod -t $IMAGE_NAME . only: - develop - tags diff --git a/Dockerfile b/Dockerfile index a6f7285..652ab21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,55 +1,86 @@ -FROM registry.ely.by/elyby/accounts-php:1.7.0 +FROM node:9.11.2-alpine as frontend -# bootstrap скрипт для проекта -COPY docker/php/bootstrap.sh /bootstrap.sh -# Вносим конфигурации для крона и воркеров -COPY docker/cron/* /etc/cron.d/ -COPY docker/supervisor/* /etc/supervisor/conf.d/ +WORKDIR /app -COPY id_rsa /root/.ssh/id_rsa +COPY ./frontend/package.json ./ +COPY ./frontend/scripts ./scripts +COPY ./frontend/webpack-utils ./webpack-utils +COPY ./frontend/yarn.lock ./ +RUN yarn build:install -# Включаем поддержку ssh -RUN chmod 400 ~/.ssh/id_rsa \ - && eval $(ssh-agent -s) \ - && ssh-add /root/.ssh/id_rsa \ - && touch /root/.ssh/known_hosts \ - && ssh-keyscan github.com gitlab.ely.by >> /root/.ssh/known_hosts +COPY ./frontend . +RUN yarn build:quiet -# Копируем списки зависимостей composer в родительскую директорию, которая не будет синкаться -# с хостом через volume на dev окружении. В entrypoint эта папка будет скопирована обратно -COPY ./composer.json /var/www/composer.json -COPY ./composer.lock /var/www/composer.lock -# Устанавливаем зависимости PHP -RUN cd .. \ - && composer install --no-interaction --no-suggest --no-dev --optimize-autoloader \ - && cd - +FROM php:7.2.7-fpm-alpine3.7 -# Устанавливаем зависимости для Node.js -# Делаем это отдельно, чтобы можно было воспользоваться кэшем, если от предыдущего билда -# ничего не менялось в зависимостях -RUN mkdir -p /var/www/frontend +# bash needed to support wait-for-it script +RUN apk add --update --no-cache \ + git \ + bash \ + openssh \ + dcron \ + zlib-dev \ + icu-dev \ + libintl \ + imagemagick-dev \ + imagemagick \ + && docker-php-ext-install \ + zip \ + pdo_mysql \ + intl \ + pcntl \ + opcache \ + && apk add --no-cache --virtual ".phpize-deps" $PHPIZE_DEPS \ + && yes | pecl install xdebug-2.6.0 \ + && yes | pecl install imagick \ + && docker-php-ext-enable imagick \ + && apk del ".phpize-deps" \ + && rm -rf /usr/share/man \ + && rm -rf /tmp/* \ + && mkdir /etc/cron.d -COPY ./frontend/package.json /var/www/frontend/ -COPY ./frontend/yarn.lock /var/www/frontend/ -COPY ./frontend/scripts /var/www/frontend/scripts -COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils +COPY --from=composer:1.6.5 /usr/bin/composer /usr/bin/composer +COPY --from=node:9.11.2-alpine /usr/local/bin/node /usr/bin/ +COPY --from=node:9.11.2-alpine /usr/lib/libgcc* /usr/lib/libstdc* /usr/lib/* /usr/lib/ -RUN cd /var/www/frontend \ - && yarn run build:install \ - && cd - +# ENV variables for composer +ENV COMPOSER_NO_INTERACTION 1 +ENV COMPOSER_ALLOW_SUPERUSER 1 -# Удаляем ключи из production контейнера на всякий случай -RUN rm -rf /root/.ssh +RUN mkdir /root/.composer \ + && echo '{"github-oauth": {"github.com": "***REMOVED***"}}' > ~/.composer/auth.json \ + && composer global require --no-progress "hirak/prestissimo:^0.3.7" \ + && composer clear-cache -# Наконец переносим все сорцы внутрь контейнера -COPY . /var/www/html +COPY ./docker/php/wait-for-it.sh /usr/local/bin/wait-for-it -# Билдим фронт -RUN cd frontend \ - && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && yarn run build:quiet \ - && rm node_modules \ - # Копируем билд наружу, чтобы его не затёрло volume в dev режиме - && cp -r ./dist /var/www/dist \ - && cd - +COPY ./composer.* /var/www/html/ + +ARG build_env=prod +ENV YII_ENV=$build_env + +RUN if [ "$build_env" = "prod" ] ; then \ + composer install --no-interaction --no-suggest --no-dev --optimize-autoloader; \ + else \ + composer install --no-interaction --no-suggest; \ + fi \ + && composer clear-cache + +COPY ./docker/php/*.ini /usr/local/etc/php/conf.d/ +COPY ./docker/php/docker-entrypoint.sh /usr/local/bin/ +COPY ./docker/cron/* /etc/cron.d/ + +COPY --from=frontend /app/dist /var/www/html/frontend/dist + +COPY ./api /var/www/html/api/ +COPY ./common /var/www/html/common/ +COPY ./console /var/www/html/console/ +COPY ./yii /var/www/html/yii + +# Expose everything under /var/www/html to share it with nginx +VOLUME ["/var/www/html"] + +WORKDIR /var/www/html +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["php-fpm"] diff --git a/Dockerfile-dev b/Dockerfile-dev deleted file mode 100644 index 07ec96a..0000000 --- a/Dockerfile-dev +++ /dev/null @@ -1,52 +0,0 @@ -FROM registry.ely.by/elyby/accounts-php:1.7.0-dev - -# bootstrap скрипт для проекта -COPY docker/php/bootstrap.sh /bootstrap.sh -# Вносим конфигурации для крона и воркеров -COPY docker/cron/* /etc/cron.d/ -COPY docker/supervisor/* /etc/supervisor/conf.d/ - -COPY id_rsa /root/.ssh/id_rsa - -# Включаем поддержку ssh -RUN chmod 400 ~/.ssh/id_rsa \ - && eval $(ssh-agent -s) \ - && ssh-add /root/.ssh/id_rsa \ - && touch /root/.ssh/known_hosts \ - && ssh-keyscan github.com gitlab.ely.by >> /root/.ssh/known_hosts - -# Копируем списки зависимостей composer в родительскую директорию, которая не будет синкаться -# с хостом через volume на dev окружении. В entrypoint эта папка будет скопирована обратно -COPY ./composer.json /var/www/composer.json -COPY ./composer.lock /var/www/composer.lock - -# Устанавливаем зависимости PHP -RUN cd .. \ - && composer install --no-interaction --no-suggest \ - && cd - - -# Устанавливаем зависимости для Node.js -# Делаем это отдельно, чтобы можно было воспользоваться кэшем, если от предыдущего билда -# ничего не менялось в зависимостях -RUN mkdir -p /var/www/frontend - -COPY ./frontend/package.json /var/www/frontend/ -COPY ./frontend/yarn.lock /var/www/frontend/ -COPY ./frontend/scripts /var/www/frontend/scripts -COPY ./frontend/webpack-utils /var/www/frontend/webpack-utils - -RUN cd /var/www/frontend \ - && yarn run build:install \ - && cd - - -# Наконец переносим все сорцы внутрь контейнера -COPY . /var/www/html - -# Билдим фронт -RUN cd frontend \ - && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && yarn run build:quiet \ - && rm node_modules \ - # Копируем билд наружу, чтобы его не затёрло volume в dev режиме - && cp -r ./dist /var/www/dist \ - && cd - diff --git a/api/config/config.php b/api/config/config.php index 5637f01..ffe0ee2 100644 --- a/api/config/config.php +++ b/api/config/config.php @@ -58,6 +58,7 @@ return [ ], 'request' => [ 'baseUrl' => '/api', + 'enableCsrfCookie' => false, 'parsers' => [ '*' => api\request\RequestParser::class, ], diff --git a/api/models/authentication/ConfirmEmailForm.php b/api/models/authentication/ConfirmEmailForm.php index c813ac0..5d6b7cc 100644 --- a/api/models/authentication/ConfirmEmailForm.php +++ b/api/models/authentication/ConfirmEmailForm.php @@ -1,9 +1,10 @@ createEventTask($account->id, $account->username, null); - $transaction->commit(); return Yii::$app->user->createJwtAuthenticationToken($account, true); diff --git a/api/modules/accounts/models/BanAccountForm.php b/api/modules/accounts/models/BanAccountForm.php index 35f0d30..d35fec4 100644 --- a/api/modules/accounts/models/BanAccountForm.php +++ b/api/modules/accounts/models/BanAccountForm.php @@ -1,13 +1,11 @@ getAccount()->status === Account::STATUS_BANNED) { $this->addError('account', E::ACCOUNT_ALREADY_BANNED); } @@ -54,27 +52,14 @@ class BanAccountForm extends AccountActionForm { $account = $this->getAccount(); $account->status = Account::STATUS_BANNED; if (!$account->save()) { - throw new ErrorException('Cannot ban account'); + throw new ThisShouldNotHappenException('Cannot ban account'); } - $this->createTask(); + Yii::$app->queue->push(ClearAccountSessions::createFromAccount($account)); $transaction->commit(); return true; } - public function createTask(): void { - $model = new AccountBanned(); - $model->accountId = $this->getAccount()->id; - $model->duration = $this->duration; - $model->message = $this->message; - - $message = Amqp::getInstance()->prepareMessage($model, [ - 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, - ]); - - Amqp::sendToEventsExchange('accounts.account-banned', $message); - } - } diff --git a/api/modules/accounts/models/ChangeEmailForm.php b/api/modules/accounts/models/ChangeEmailForm.php index 1f03b67..3de16c6 100644 --- a/api/modules/accounts/models/ChangeEmailForm.php +++ b/api/modules/accounts/models/ChangeEmailForm.php @@ -2,13 +2,10 @@ namespace api\modules\accounts\models; use api\aop\annotations\CollectModelMetrics; +use api\exceptions\ThisShouldNotHappenException; use api\validators\EmailActivationKeyValidator; -use common\helpers\Amqp; -use common\models\amqp\EmailChanged; use common\models\EmailActivation; -use PhpAmqpLib\Message\AMQPMessage; use Yii; -use yii\base\ErrorException; class ChangeEmailForm extends AccountActionForm { @@ -35,30 +32,14 @@ class ChangeEmailForm extends AccountActionForm { $activation->delete(); $account = $this->getAccount(); - $oldEmail = $account->email; $account->email = $activation->newEmail; if (!$account->save()) { - throw new ErrorException('Cannot save new account email value'); + throw new ThisShouldNotHappenException('Cannot save new account email value'); } - $this->createTask($account->id, $account->email, $oldEmail); - $transaction->commit(); return true; } - public function createTask(int $accountId, string $newEmail, string $oldEmail): void { - $model = new EmailChanged(); - $model->accountId = $accountId; - $model->oldEmail = $oldEmail; - $model->newEmail = $newEmail; - - $message = Amqp::getInstance()->prepareMessage($model, [ - 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, - ]); - - Amqp::sendToEventsExchange('accounts.email-changed', $message); - } - } diff --git a/api/modules/accounts/models/ChangeUsernameForm.php b/api/modules/accounts/models/ChangeUsernameForm.php index 86fa961..53ad10d 100644 --- a/api/modules/accounts/models/ChangeUsernameForm.php +++ b/api/modules/accounts/models/ChangeUsernameForm.php @@ -4,13 +4,10 @@ namespace api\modules\accounts\models; use api\aop\annotations\CollectModelMetrics; use api\exceptions\ThisShouldNotHappenException; use api\validators\PasswordRequiredValidator; -use common\helpers\Amqp; -use common\models\amqp\UsernameChanged; use common\models\UsernameHistory; +use common\tasks\PullMojangUsername; use common\validators\UsernameValidator; -use PhpAmqpLib\Message\AMQPMessage; use Yii; -use yii\base\ErrorException; class ChangeUsernameForm extends AccountActionForm { @@ -42,7 +39,6 @@ class ChangeUsernameForm extends AccountActionForm { $transaction = Yii::$app->db->beginTransaction(); - $oldNickname = $account->username; $account->username = $this->username; if (!$account->save()) { throw new ThisShouldNotHappenException('Cannot save account model with new username'); @@ -52,36 +48,14 @@ class ChangeUsernameForm extends AccountActionForm { $usernamesHistory->account_id = $account->id; $usernamesHistory->username = $account->username; if (!$usernamesHistory->save()) { - throw new ErrorException('Cannot save username history record'); + throw new ThisShouldNotHappenException('Cannot save username history record'); } - $this->createEventTask($account->id, $account->username, $oldNickname); + Yii::$app->queue->push(PullMojangUsername::createFromAccount($account)); $transaction->commit(); return true; } - /** - * TODO: вынести это в отдельную сущность, т.к. эта команда используется внутри формы регистрации - * - * @param integer $accountId - * @param string $newNickname - * @param string $oldNickname - * - * @throws \PhpAmqpLib\Exception\AMQPExceptionInterface|\yii\base\Exception - */ - public function createEventTask($accountId, $newNickname, $oldNickname): void { - $model = new UsernameChanged(); - $model->accountId = $accountId; - $model->oldUsername = $oldNickname; - $model->newUsername = $newNickname; - - $message = Amqp::getInstance()->prepareMessage($model, [ - 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, - ]); - - Amqp::sendToEventsExchange('accounts.username-changed', $message); - } - } diff --git a/api/modules/accounts/models/PardonAccountForm.php b/api/modules/accounts/models/PardonAccountForm.php index 2c337d7..fe9c073 100644 --- a/api/modules/accounts/models/PardonAccountForm.php +++ b/api/modules/accounts/models/PardonAccountForm.php @@ -1,13 +1,10 @@ getAccount(); $account->status = Account::STATUS_ACTIVE; if (!$account->save()) { - throw new ErrorException('Cannot pardon account'); + throw new ThisShouldNotHappenException('Cannot pardon account'); } - $this->createTask(); - $transaction->commit(); return true; } - public function createTask(): void { - $model = new AccountPardoned(); - $model->accountId = $this->getAccount()->id; - - $message = Amqp::getInstance()->prepareMessage($model, [ - 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, - ]); - - Amqp::sendToEventsExchange('accounts.account-pardoned', $message); - } - } diff --git a/api/modules/session/filters/RateLimiter.php b/api/modules/session/filters/RateLimiter.php index 72081bc..96be790 100644 --- a/api/modules/session/filters/RateLimiter.php +++ b/api/modules/session/filters/RateLimiter.php @@ -56,10 +56,9 @@ class RateLimiter extends \yii\filters\RateLimiter { $ip = $request->getUserIP(); $key = $this->buildKey($ip); - $redis = $this->getRedis(); - $countRequests = (int)$redis->incr($key); + $countRequests = (int)Yii::$app->redis->incr($key); if ($countRequests === 1) { - $redis->executeCommand('EXPIRE', [$key, $this->limitTime]); + Yii::$app->redis->expire($key, $this->limitTime); } if ($countRequests > $this->limit) { @@ -67,13 +66,6 @@ class RateLimiter extends \yii\filters\RateLimiter { } } - /** - * @return \common\components\Redis\Connection - */ - public function getRedis() { - return Yii::$app->redis; - } - /** * @param Request $request * @return OauthClient|null diff --git a/api/modules/session/models/SessionModel.php b/api/modules/session/models/SessionModel.php index ed5e626..7d37728 100644 --- a/api/modules/session/models/SessionModel.php +++ b/api/modules/session/models/SessionModel.php @@ -19,7 +19,7 @@ class SessionModel { public static function find(string $username, string $serverId): ?self { $key = static::buildKey($username, $serverId); - $result = Yii::$app->redis->executeCommand('GET', [$key]); + $result = Yii::$app->redis->get($key); if (!$result) { return null; } @@ -36,11 +36,11 @@ class SessionModel { 'serverId' => $this->serverId, ]); - return Yii::$app->redis->executeCommand('SETEX', [$key, self::KEY_TIME, $data]); + return Yii::$app->redis->setex($key, self::KEY_TIME, $data); } public function delete() { - return Yii::$app->redis->executeCommand('DEL', [static::buildKey($this->username, $this->serverId)]); + return Yii::$app->redis->del(static::buildKey($this->username, $this->serverId)); } public function getAccount(): ?Account { diff --git a/autocompletion.php b/autocompletion.php index 07b6667..a70d827 100644 --- a/autocompletion.php +++ b/autocompletion.php @@ -16,16 +16,15 @@ class Yii extends \yii\BaseYii { * Class BaseApplication * Used for properties that are identical for both WebApplication and ConsoleApplication * - * @property \yii\db\Connection $unbufferedDb - * @property \yii\swiftmailer\Mailer $mailer - * @property \common\components\Redis\Connection $redis - * @property \common\components\RabbitMQ\Component $amqp - * @property \GuzzleHttp\Client $guzzle - * @property \common\components\EmailRenderer $emailRenderer - * @property \mito\sentry\Component $sentry - * @property \api\components\OAuth2\Component $oauth - * @property \common\components\StatsD $statsd - * @property \yii\queue\Queue $queue + * @property \yii\db\Connection $unbufferedDb + * @property \yii\swiftmailer\Mailer $mailer + * @property \yii\redis\Connection $redis + * @property \GuzzleHttp\Client $guzzle + * @property \common\components\EmailRenderer $emailRenderer + * @property \mito\sentry\Component $sentry + * @property \api\components\OAuth2\Component $oauth + * @property \common\components\StatsD $statsd + * @property \yii\queue\Queue $queue */ abstract class BaseApplication extends yii\base\Application { } diff --git a/common/components/RabbitMQ/Component.php b/common/components/RabbitMQ/Component.php deleted file mode 100644 index b7e6177..0000000 --- a/common/components/RabbitMQ/Component.php +++ /dev/null @@ -1,177 +0,0 @@ - - * - * @property AMQPStreamConnection $connection AMQP connection. - * @property AMQPChannel $channel AMQP channel. - */ -class Component extends \yii\base\Component { - - public const TYPE_TOPIC = 'topic'; - public const TYPE_DIRECT = 'direct'; - public const TYPE_HEADERS = 'headers'; - public const TYPE_FANOUT = 'fanout'; - - /** - * @var string - */ - public $host = '127.0.0.1'; - - /** - * @var integer - */ - public $port = 5672; - - /** - * @var string - */ - public $user; - - /** - * @var string - */ - public $password; - - /** - * @var string - */ - public $vhost = '/'; - - /** - * @var AMQPStreamConnection - */ - protected $amqpConnection; - - /** - * @var AMQPChannel[] - */ - protected $channels = []; - - /** - * @inheritdoc - */ - public function init() { - parent::init(); - if (empty($this->user)) { - throw new Exception("Parameter 'user' was not set for AMQP connection."); - } - } - - /** - * @return AMQPStreamConnection - */ - public function getConnection() { - if (!$this->amqpConnection) { - $this->amqpConnection = new AMQPStreamConnection( - $this->host, - $this->port, - $this->user, - $this->password, - $this->vhost - ); - } - - return $this->amqpConnection; - } - - /** - * @param string $channel_id - * @return AMQPChannel - */ - public function getChannel($channel_id = null) { - $index = $channel_id ?: 'default'; - if (!array_key_exists($index, $this->channels)) { - $this->channels[$index] = $this->getConnection()->channel($channel_id); - } - - return $this->channels[$index]; - } - - // TODO: метод sendToQueue - - /** - * Sends message to the exchange. - * - * @param string $exchangeName - * @param string $routingKey - * @param string|array $message - * @param array $exchangeArgs - * @param array $publishArgs - */ - public function sendToExchange($exchangeName, $routingKey, $message, $exchangeArgs = [], $publishArgs = []) { - $message = $this->prepareMessage($message); - $channel = $this->getChannel(); - $channel->exchange_declare(...$this->prepareExchangeArgs($exchangeName, $exchangeArgs)); - $channel->basic_publish(...$this->preparePublishArgs($message, $exchangeName, $routingKey, $publishArgs)); - } - - /** - * Returns prepaired AMQP message. - * - * @param string|array|object $message - * @param array $properties - * @return AMQPMessage - * @throws Exception If message is empty. - */ - public function prepareMessage($message, $properties = null) { - if ($message instanceof AMQPMessage) { - return $message; - } - - if (empty($message)) { - throw new Exception('AMQP message can not be empty'); - } - - if (is_array($message) || is_object($message)) { - $message = Json::encode($message); - } - - return new AMQPMessage($message, $properties); - } - - /** - * Объединяет переданный набор аргументов с поведением по умолчанию - * - * @param string $exchangeName - * @param array $args - * @return array - */ - protected function prepareExchangeArgs($exchangeName, array $args) { - return array_replace([ - $exchangeName, - self::TYPE_FANOUT, - false, - false, - false, - ], $args); - } - - /** - * Объединяет переданный набор аргументов с поведением по умолчанию - * - * @param AMQPMessage $message - * @param string $exchangeName - * @param string $routeKey - * @param array $args - * - * @return array - */ - protected function preparePublishArgs($message, $exchangeName, $routeKey, array $args) { - return array_replace([ - $message, - $exchangeName, - $routeKey, - ], $args); - } - -} diff --git a/common/components/RabbitMQ/Helper.php b/common/components/RabbitMQ/Helper.php deleted file mode 100644 index e3b5f7a..0000000 --- a/common/components/RabbitMQ/Helper.php +++ /dev/null @@ -1,26 +0,0 @@ -amqp; - } - - public static function sendToExchange($exchange, $routingKey, $message, $exchangeArgs = []) { - static::getInstance()->sendToExchange($exchange, $routingKey, $message, $exchangeArgs); - } - - public static function sendToEventsExchange($routingKey, $message) { - static::sendToExchange('events', $routingKey, $message, [ - 1 => Component::TYPE_TOPIC, // type -> topic - 3 => true, // durable -> true - ]); - } - -} diff --git a/common/components/Redis/Cache.php b/common/components/Redis/Cache.php deleted file mode 100644 index 6a120a1..0000000 --- a/common/components/Redis/Cache.php +++ /dev/null @@ -1,13 +0,0 @@ -redis = Instance::ensure($this->redis, ConnectionInterface::class); - } - -} diff --git a/common/components/Redis/Connection.php b/common/components/Redis/Connection.php deleted file mode 100644 index 28d62c4..0000000 --- a/common/components/Redis/Connection.php +++ /dev/null @@ -1,415 +0,0 @@ -executeCommand($name, $params); - } - - return parent::__call($name, $params); - } - - public function getConnection(): ClientInterface { - if ($this->_client === null) { - $this->_client = new Client($this->prepareParams(), $this->options); - } - - return $this->_client; - } - - public function executeCommand(string $name, array $params = []) { - return $this->getConnection()->$name(...$params); - } - - private function prepareParams() { - if ($this->parameters !== null) { - return $this->parameters; - } - - if ($this->unixSocket) { - $parameters = [ - 'scheme' => 'unix', - 'path' => $this->unixSocket, - ]; - } else { - $parameters = [ - 'scheme' => 'tcp', - 'host' => $this->hostname, - 'port' => $this->port, - ]; - } - - return array_merge($parameters, [ - 'database' => $this->database, - ]); - } - -} diff --git a/common/components/Redis/ConnectionInterface.php b/common/components/Redis/ConnectionInterface.php deleted file mode 100644 index f4195fe..0000000 --- a/common/components/Redis/ConnectionInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -key = $this->buildKey($key); } - public function getRedis(): Connection { - return Yii::$app->redis; - } - public function getKey(): string { return $this->key; } public function getValue() { - return $this->getRedis()->get($this->key); + return Yii::$app->redis->get($this->key); } public function setValue($value): self { - $this->getRedis()->set($this->key, $value); - + Yii::$app->redis->set($this->key, $value); return $this; } public function delete(): self { - $this->getRedis()->del([$this->getKey()]); - + Yii::$app->redis->del($this->getKey()); return $this; } public function exists(): bool { - return (bool)$this->getRedis()->exists($this->key); + return (bool)Yii::$app->redis->exists($this->key); } public function expire(int $ttl): self { - $this->getRedis()->expire($this->key, $ttl); - + Yii::$app->redis->expire($this->key, $ttl); return $this; } public function expireAt(int $unixTimestamp): self { - $this->getRedis()->expireat($this->key, $unixTimestamp); - + Yii::$app->redis->expireat($this->key, $unixTimestamp); return $this; } diff --git a/common/components/Redis/Set.php b/common/components/Redis/Set.php index b106304..b6a07ec 100644 --- a/common/components/Redis/Set.php +++ b/common/components/Redis/Set.php @@ -3,23 +3,22 @@ namespace common\components\Redis; use ArrayIterator; use IteratorAggregate; +use Yii; class Set extends Key implements IteratorAggregate { public function add($value): self { - $this->getRedis()->sadd($this->getKey(), $value); - + Yii::$app->redis->sadd($this->getKey(), $value); return $this; } public function remove($value): self { - $this->getRedis()->srem($this->getKey(), $value); - + Yii::$app->redis->srem($this->getKey(), $value); return $this; } public function members(): array { - return $this->getRedis()->smembers($this->getKey()); + return Yii::$app->redis->smembers($this->getKey()); } public function getValue(): array { @@ -31,11 +30,11 @@ class Set extends Key implements IteratorAggregate { return parent::exists(); } - return (bool)$this->getRedis()->sismember($this->getKey(), $value); + return (bool)Yii::$app->redis->sismember($this->getKey(), $value); } public function diff(array $sets): array { - return $this->getRedis()->sdiff([$this->getKey(), implode(' ', $sets)]); + return Yii::$app->redis->sdiff([$this->getKey(), implode(' ', $sets)]); } /** diff --git a/common/config/bootstrap.php b/common/config/bootstrap.php index 64528ff..bce9d52 100644 --- a/common/config/bootstrap.php +++ b/common/config/bootstrap.php @@ -1,5 +1,4 @@ dirname(__DIR__, 2) . '/vendor', 'components' => [ 'cache' => [ - 'class' => common\components\Redis\Cache::class, - 'redis' => 'redis', + 'class' => yii\redis\Cache::class, ], 'db' => [ 'class' => yii\db\Connection::class, @@ -61,20 +60,12 @@ return [ 'passwordHashStrategy' => 'password_hash', ], 'redis' => [ - 'class' => common\components\Redis\Connection::class, + 'class' => yii\redis\Connection::class, 'hostname' => getenv('REDIS_HOST') ?: 'redis', 'password' => getenv('REDIS_PASS') ?: null, 'port' => getenv('REDIS_PORT') ?: 6379, 'database' => getenv('REDIS_DATABASE') ?: 0, ], - 'amqp' => [ - 'class' => common\components\RabbitMQ\Component::class, - 'host' => getenv('RABBITMQ_HOST') ?: 'rabbitmq', - 'port' => getenv('RABBITMQ_PORT') ?: 5672, - 'user' => getenv('RABBITMQ_USER'), - 'password' => getenv('RABBITMQ_PASS'), - 'vhost' => getenv('RABBITMQ_VHOST'), - ], 'guzzle' => [ 'class' => GuzzleHttp\Client::class, ], @@ -97,15 +88,7 @@ return [ 'namespace' => getenv('STATSD_NAMESPACE') ?: 'ely.accounts.' . gethostname() . '.app', ], 'queue' => [ - 'class' => yii\queue\amqp_interop\Queue::class, - 'driver' => yii\queue\amqp_interop\Queue::ENQUEUE_AMQP_LIB, - 'host' => getenv('RABBITMQ_HOST') ?: 'rabbitmq', - 'port' => getenv('RABBITMQ_PORT') ?: 5672, - 'user' => getenv('RABBITMQ_USER'), - 'password' => getenv('RABBITMQ_PASS'), - 'vhost' => getenv('RABBITMQ_VHOST'), - 'queueName' => 'worker', - 'exchangeName' => 'tasks', + 'class' => yii\queue\redis\Queue::class, ], ], 'container' => [ diff --git a/common/models/Account.php b/common/models/Account.php index 06d1961..dfc8dfc 100644 --- a/common/models/Account.php +++ b/common/models/Account.php @@ -1,7 +1,10 @@ registration_ip === null ? null : inet_ntop($this->registration_ip); } + public function afterSave($insert, $changedAttributes) { + parent::afterSave($insert, $changedAttributes); + + if ($insert) { + return; + } + + $meaningfulFields = ['username', 'email', 'uuid', 'status', 'lang']; + $meaningfulChangedAttributes = array_filter($changedAttributes, function(string $key) use ($meaningfulFields) { + return in_array($key, $meaningfulFields, true); + }, ARRAY_FILTER_USE_KEY); + if (empty($meaningfulChangedAttributes)) { + return; + } + + Yii::$app->queue->push(CreateWebHooksDeliveries::createAccountEdit($this, $meaningfulChangedAttributes)); + } + } diff --git a/common/models/WebHook.php b/common/models/WebHook.php new file mode 100644 index 0000000..586fa9e --- /dev/null +++ b/common/models/WebHook.php @@ -0,0 +1,42 @@ + TimestampBehavior::class, + 'updatedAtAttribute' => false, + ], + ]; + } + + public function getEvents(): ActiveQueryInterface { + return $this->hasMany(WebHookEvent::class, ['webhook_id' => 'id']); + } + +} diff --git a/common/models/WebHookEvent.php b/common/models/WebHookEvent.php new file mode 100644 index 0000000..280d4ab --- /dev/null +++ b/common/models/WebHookEvent.php @@ -0,0 +1,27 @@ +hasOne(WebHook::class, ['id' => 'webhook_id']); + } + +} diff --git a/common/tasks/ClearAccountSessions.php b/common/tasks/ClearAccountSessions.php new file mode 100644 index 0000000..86a5043 --- /dev/null +++ b/common/tasks/ClearAccountSessions.php @@ -0,0 +1,64 @@ +accountId = $account->id; + + return $result; + } + + /** + * @return int time to reserve in seconds + */ + public function getTtr(): int { + return 5 * 60; + } + + /** + * @param int $attempt number + * @param \Exception|\Throwable $error from last execute of the job + * + * @return bool + */ + public function canRetry($attempt, $error): bool { + return true; + } + + /** + * @param \yii\queue\Queue $queue which pushed and is handling the job + * @throws \Exception + */ + public function execute($queue): void { + $account = Account::findOne($this->accountId); + if ($account === null) { + return; + } + + foreach ($account->getSessions()->each(100, Yii::$app->unbufferedDb) as $authSession) { + /** @var \common\models\AccountSession $authSession */ + $authSession->delete(); + } + + foreach ($account->getMinecraftAccessKeys()->each(100, Yii::$app->unbufferedDb) as $key) { + /** @var \common\models\MinecraftAccessKey $key */ + $key->delete(); + } + + foreach ($account->getOauthSessions()->each(100, Yii::$app->unbufferedDb) as $oauthSession) { + /** @var \common\models\OauthSession $oauthSession */ + $oauthSession->delete(); + } + } + +} diff --git a/common/tasks/CreateWebHooksDeliveries.php b/common/tasks/CreateWebHooksDeliveries.php new file mode 100644 index 0000000..8ba6fef --- /dev/null +++ b/common/tasks/CreateWebHooksDeliveries.php @@ -0,0 +1,76 @@ +type = 'account.edit'; + $result->payloads = [ + 'id' => $account->id, + 'uuid' => $account->uuid, + 'username' => $account->username, + 'email' => $account->email, + 'lang' => $account->lang, + 'isActive' => $account->status === Account::STATUS_ACTIVE, + 'registered' => date('c', (int)$account->created_at), + 'changedAttributes' => $changedAttributes, + ]; + + return $result; + } + + /** + * @return int time to reserve in seconds + */ + public function getTtr() { + return 10; + } + + /** + * @param int $attempt number + * @param \Exception|\Throwable $error from last execute of the job + * + * @return bool + */ + public function canRetry($attempt, $error) { + return true; + } + + /** + * @param \yii\queue\Queue $queue which pushed and is handling the job + */ + public function execute($queue) { + /** @var WebHook[] $targets */ + $targets = WebHook::find() + ->joinWith('events e', false) + ->andWhere(['e.event_type' => $this->type]) + ->all(); + foreach ($targets as $target) { + $job = new DeliveryWebHook(); + $job->type = $this->type; + $job->url = $target->url; + $job->secret = $target->secret; + $job->payloads = $this->payloads; + Yii::$app->queue->push($job); + } + } + +} diff --git a/common/tasks/DeliveryWebHook.php b/common/tasks/DeliveryWebHook.php new file mode 100644 index 0000000..a3d639b --- /dev/null +++ b/common/tasks/DeliveryWebHook.php @@ -0,0 +1,111 @@ += 5) { + return false; + } + + if ($error instanceof ServerException || $error instanceof ConnectException) { + return true; + } + + return false; + } + + /** + * @param \yii\queue\Queue $queue which pushed and is handling the job + * + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function execute($queue): void { + $client = $this->createClient(); + try { + $client->request('POST', $this->url, [ + 'headers' => [ + 'User-Agent' => 'Account-Ely-Hookshot/' . Yii::$app->version, + 'X-Ely-Accounts-Event' => $this->type, + ], + 'form_params' => $this->payloads, + ]); + } catch (ClientException $e) { + Yii::info("Delivery for {$this->url} has failed with {$e->getResponse()->getStatusCode()} status."); + + return; + } + } + + protected function createClient(): ClientInterface { + return new GuzzleClient([ + 'handler' => $this->createStack(), + 'timeout' => 60, + 'connect_timeout' => 10, + ]); + } + + protected function createStack(): HandlerStack { + $stack = HandlerStack::create(); + $stack->push(Middleware::mapRequest(function(RequestInterface $request): RequestInterface { + if (empty($this->secret)) { + return $request; + } + + $payload = (string)$request->getBody(); + $signature = hash_hmac('sha1', $payload, $this->secret); + + /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ + return $request->withHeader('X-Hub-Signature', 'sha1=' . $signature); + })); + + return $stack; + } + +} diff --git a/common/tasks/PullMojangUsername.php b/common/tasks/PullMojangUsername.php new file mode 100644 index 0000000..169ddfb --- /dev/null +++ b/common/tasks/PullMojangUsername.php @@ -0,0 +1,72 @@ +username = $account->username; + + return $result; + } + + /** + * @param \yii\queue\Queue $queue which pushed and is handling the job + * + * @throws \Exception + */ + public function execute($queue) { + Yii::$app->statsd->inc('queue.pullMojangUsername.attempt'); + $mojangApi = $this->createMojangApi(); + try { + $response = $mojangApi->usernameToUUID($this->username); + Yii::$app->statsd->inc('queue.pullMojangUsername.found'); + } catch (NoContentException $e) { + $response = false; + Yii::$app->statsd->inc('queue.pullMojangUsername.not_found'); + } catch (RequestException | MojangApiException $e) { + Yii::$app->statsd->inc('queue.pullMojangUsername.error'); + return; + } + + /** @var MojangUsername|null $mojangUsername */ + $mojangUsername = MojangUsername::findOne($this->username); + if ($response === false) { + if ($mojangUsername !== null) { + $mojangUsername->delete(); + } + } else { + if ($mojangUsername === null) { + $mojangUsername = new MojangUsername(); + $mojangUsername->username = $response->name; + $mojangUsername->uuid = $response->id; + } else { + $mojangUsername->uuid = $response->id; + $mojangUsername->touch('last_pulled_at'); + } + + if (!$mojangUsername->save()) { + throw new ThisShouldNotHappenException('Cannot save mojang username'); + } + } + } + + protected function createMojangApi(): MojangApi { + return new MojangApi(); + } + +} diff --git a/common/validators/LanguageValidator.php b/common/validators/LanguageValidator.php index 409e4a4..075eba1 100644 --- a/common/validators/LanguageValidator.php +++ b/common/validators/LanguageValidator.php @@ -1,39 +1,37 @@ getFilesNames(); - if (in_array($value, $files)) { - return null; + $primary = Locale::getPrimaryLanguage($value); + $region = Locale::getRegion($value); + $locales = ResourceBundle::getLocales(''); // http://php.net/manual/ru/resourcebundle.locales.php#115965 + if (($region !== '' && strtolower($primary) !== strtolower($region)) && !in_array($value, $locales)) { + return [$this->message, []]; } - return [$this->message, []]; - } - - protected function getFilesNames() { - $files = array_values(array_filter(scandir($this->getFolderPath()), function(&$value) { - return $value !== '..' && $value !== '.'; - })); - - return array_map(function($value) { - return basename($value, '.json'); - }, $files); - } - - protected function getFolderPath() { - return Yii::getAlias('@frontend/src/i18n'); + return null; } } diff --git a/composer.json b/composer.json index 0b2d338..d6448ff 100644 --- a/composer.json +++ b/composer.json @@ -6,19 +6,15 @@ "minimum-stability": "stable", "require": { "php": "^7.1", - "roave/security-advisories": "dev-master", - "yiisoft/yii2": "2.0.14", + "yiisoft/yii2": "2.0.15.1", "yiisoft/yii2-swiftmailer": "~2.1.0", "ramsey/uuid": "^3.5", "league/oauth2-server": "^4.1", "yiisoft/yii2-redis": "~2.0.0", "guzzlehttp/guzzle": "^6.0.0", - "php-amqplib/php-amqplib": "^2.6.2", "ely/yii2-tempmail-validator": "^2.0", "emarref/jwt": "~1.0.3", - "ely/amqp-controller": "dev-master#d7f8cdbc66c45e477c9c7d5d509bc0c1b11fd3ec", "ely/email-renderer": "dev-master#8aa2e71c5b3b8e4a726c3c090b2997030ba29f73", - "predis/predis": "^1.0", "mito/yii2-sentry": "^1.0", "spomky-labs/otphp": "^9.0.2", "bacon/bacon-qr-code": "^1.0", @@ -26,13 +22,12 @@ "webmozart/assert": "^1.2.0", "goaop/framework": "~2.2.0", "domnikl/statsd": "^2.6", - "yiisoft/yii2-queue": "~2.0.2", - "enqueue/amqp-lib": "^0.8.11" + "yiisoft/yii2-queue": "~2.1.0" }, "require-dev": { "yiisoft/yii2-debug": "*", "yiisoft/yii2-faker": "*", - "flow/jsonpath": "^0.3.1", + "flow/jsonpath": "^0.4.0", "phpunit/phpunit": "^6.0", "codeception/codeception": "2.3.8", "codeception/specify": "^1.0.0", @@ -40,7 +35,9 @@ "mockery/mockery": "^1.0.0", "php-mock/php-mock-mockery": "^1.2.0", "friendsofphp/php-cs-fixer": "^2.11", - "ely/php-code-style": "^0.1.0" + "ely/php-code-style": "^0.1.0", + "predis/predis": "^1.1", + "roave/security-advisories": "dev-master" }, "repositories": [ { @@ -49,11 +46,7 @@ }, { "type": "git", - "url": "git@gitlab.ely.by:elyby/amqp-controller.git" - }, - { - "type": "git", - "url": "git@gitlab.ely.by:elyby/email-renderer.git" + "url": "https://gitlab+deploy-token-1:FDGgmcnLdykcsyJJ_8Uv@gitlab.ely.by/elyby/email-renderer.git" } ], "autoload": { diff --git a/composer.lock b/composer.lock index 19ec143..cba9321 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "63497214afa6b50f50d3bc80fe9eb269", + "content-hash": "7368afb90e5f3ed26a7b6d98551da170", "packages": [ { "name": "bacon/bacon-qr-code", @@ -153,7 +153,7 @@ "version": "v1.3.2", "source": { "type": "git", - "url": "https://github.com/bestiejs/punycode.js.git", + "url": "git@github.com:bestiejs/punycode.js.git", "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" }, "dist": { @@ -508,16 +508,16 @@ }, { "name": "domnikl/statsd", - "version": "2.6.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/domnikl/statsd-php.git", - "reference": "ca9daa049fd9f353c0551384612bb4f17615b14a" + "reference": "529578b05e455280fbb2748bb0080026d86452bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/domnikl/statsd-php/zipball/ca9daa049fd9f353c0551384612bb4f17615b14a", - "reference": "ca9daa049fd9f353c0551384612bb4f17615b14a", + "url": "https://api.github.com/repos/domnikl/statsd-php/zipball/529578b05e455280fbb2748bb0080026d86452bb", + "reference": "529578b05e455280fbb2748bb0080026d86452bb", "shasum": "" }, "require": { @@ -551,7 +551,7 @@ "statsd", "udp" ], - "time": "2017-07-30T17:40:00+00:00" + "time": "2018-04-29T18:04:03+00:00" }, { "name": "egulias/email-validator", @@ -610,48 +610,12 @@ ], "time": "2017-11-15T23:40:40+00:00" }, - { - "name": "ely/amqp-controller", - "version": "dev-master", - "source": { - "type": "git", - "url": "git@gitlab.ely.by:elyby/amqp-controller.git", - "reference": "d7f8cdbc66c45e477c9c7d5d509bc0c1b11fd3ec" - }, - "require": { - "php-amqplib/php-amqplib": "^2.6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Ely\\Amqp\\": "src/" - } - }, - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ely.by team", - "email": "team@ely.by" - }, - { - "name": "ErickSkrauch", - "email": "erickskrauch@ely.by" - } - ], - "homepage": "http://ely.by", - "keywords": [ - "" - ], - "time": "2016-11-15T19:40:20+00:00" - }, { "name": "ely/email-renderer", "version": "dev-master", "source": { "type": "git", - "url": "git@gitlab.ely.by:elyby/email-renderer.git", + "url": "https://gitlab+deploy-token-1:FDGgmcnLdykcsyJJ_8Uv@gitlab.ely.by/elyby/email-renderer.git", "reference": "8aa2e71c5b3b8e4a726c3c090b2997030ba29f73" }, "require": { @@ -779,117 +743,6 @@ "description": "A JWT implementation", "time": "2016-09-05T20:33:06+00:00" }, - { - "name": "enqueue/amqp-lib", - "version": "0.8.21", - "source": { - "type": "git", - "url": "https://github.com/php-enqueue/amqp-lib.git", - "reference": "5a0da2f2eccb2ebda4d0b2526e1753c96cf0ef75" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-enqueue/amqp-lib/zipball/5a0da2f2eccb2ebda4d0b2526e1753c96cf0ef75", - "reference": "5a0da2f2eccb2ebda4d0b2526e1753c96cf0ef75", - "shasum": "" - }, - "require": { - "enqueue/amqp-tools": "^0.8.5@dev", - "php": ">=5.6", - "php-amqplib/php-amqplib": "^2.7@dev", - "queue-interop/amqp-interop": "^0.7@dev", - "queue-interop/queue-interop": "^0.6@dev" - }, - "require-dev": { - "enqueue/enqueue": "^0.8@dev", - "enqueue/null": "^0.8@dev", - "enqueue/test": "^0.8@dev", - "phpunit/phpunit": "~5.4.0", - "queue-interop/queue-spec": "^0.5.3@dev", - "symfony/config": "^2.8|^3|^4", - "symfony/dependency-injection": "^2.8|^3|^4" - }, - "suggest": { - "enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.8.x-dev" - } - }, - "autoload": { - "psr-4": { - "Enqueue\\AmqpLib\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Message Queue Amqp Transport", - "homepage": "https://enqueue.forma-pro.com/", - "keywords": [ - "AMQP", - "messaging", - "queue" - ], - "time": "2018-02-16T11:05:22+00:00" - }, - { - "name": "enqueue/amqp-tools", - "version": "0.8.14", - "source": { - "type": "git", - "url": "https://github.com/php-enqueue/amqp-tools.git", - "reference": "f375dee4d8609fca565a80df1c0f238bf0fe774f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-enqueue/amqp-tools/zipball/f375dee4d8609fca565a80df1c0f238bf0fe774f", - "reference": "f375dee4d8609fca565a80df1c0f238bf0fe774f", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "queue-interop/amqp-interop": "^0.7@dev", - "queue-interop/queue-interop": "^0.6@dev" - }, - "require-dev": { - "enqueue/null": "^0.8@dev", - "enqueue/test": "^0.8@dev", - "phpunit/phpunit": "~5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.8.x-dev" - } - }, - "autoload": { - "psr-4": { - "Enqueue\\AmqpTools\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Message Queue Amqp Tools", - "homepage": "https://enqueue.forma-pro.com/", - "keywords": [ - "AMQP", - "messaging", - "queue" - ], - "time": "2018-01-10T12:00:35+00:00" - }, { "name": "ezyang/htmlpurifier", "version": "v4.9.3", @@ -1056,16 +909,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.0", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", - "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", "shasum": "" }, "require": { @@ -1075,7 +928,7 @@ }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "^4.0 || ^5.0", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", "psr/log": "^1.0" }, "suggest": { @@ -1084,7 +937,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.2-dev" + "dev-master": "6.3-dev" } }, "autoload": { @@ -1117,7 +970,7 @@ "rest", "web service" ], - "time": "2017-06-22T18:50:49+00:00" + "time": "2018-04-22T15:46:56+00:00" }, { "name": "guzzlehttp/promises", @@ -1511,24 +1364,24 @@ }, { "name": "paragonie/constant_time_encoding", - "version": "v2.2.1", + "version": "v2.2.2", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "7c74c5d08761ead7b5e89d07c854bc28eb0b2186" + "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/7c74c5d08761ead7b5e89d07c854bc28eb0b2186", - "reference": "7c74c5d08761ead7b5e89d07c854bc28eb0b2186", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/eccf915f45f911bfb189d1d1638d940ec6ee6e33", + "reference": "eccf915f45f911bfb189d1d1638d940ec6ee6e33", "shasum": "" }, "require": { "php": "^7" }, "require-dev": { - "phpunit/phpunit": "^6", - "vimeo/psalm": "^0.3|^1" + "phpunit/phpunit": "^6|^7", + "vimeo/psalm": "^1" }, "type": "library", "autoload": { @@ -1569,7 +1422,7 @@ "hex2bin", "rfc4648" ], - "time": "2018-01-23T00:54:57+00:00" + "time": "2018-03-10T19:47:49+00:00" }, { "name": "paragonie/random_compat", @@ -1619,127 +1472,6 @@ ], "time": "2017-09-27T21:40:39+00:00" }, - { - "name": "php-amqplib/php-amqplib", - "version": "v2.7.2", - "source": { - "type": "git", - "url": "https://github.com/php-amqplib/php-amqplib.git", - "reference": "dfd3694a86f1a7394d3693485259d4074a6ec79b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/dfd3694a86f1a7394d3693485259d4074a6ec79b", - "reference": "dfd3694a86f1a7394d3693485259d4074a6ec79b", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "replace": { - "videlalvaro/php-amqplib": "self.version" - }, - "require-dev": { - "phpdocumentor/phpdocumentor": "^2.9", - "phpunit/phpunit": "^4.8", - "scrutinizer/ocular": "^1.1", - "squizlabs/php_codesniffer": "^2.5" - }, - "suggest": { - "ext-sockets": "Use AMQPSocketConnection" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "PhpAmqpLib\\": "PhpAmqpLib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-or-later" - ], - "authors": [ - { - "name": "Alvaro Videla", - "role": "Original Maintainer" - }, - { - "name": "John Kelly", - "email": "johnmkelly86@gmail.com", - "role": "Maintainer" - }, - { - "name": "Raúl Araya", - "email": "nubeiro@gmail.com", - "role": "Maintainer" - } - ], - "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", - "homepage": "https://github.com/php-amqplib/php-amqplib/", - "keywords": [ - "message", - "queue", - "rabbitmq" - ], - "time": "2018-02-11T19:28:00+00:00" - }, - { - "name": "predis/predis", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/nrk/predis.git", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" - }, - "type": "library", - "autoload": { - "psr-4": { - "Predis\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net" - } - ], - "description": "Flexible and feature-complete Redis client for PHP and HHVM", - "homepage": "http://github.com/nrk/predis", - "keywords": [ - "nosql", - "predis", - "redis" - ], - "time": "2016-06-16T16:22:20+00:00" - }, { "name": "psr/http-message", "version": "1.0.1", @@ -1790,87 +1522,6 @@ ], "time": "2016-08-06T14:39:51+00:00" }, - { - "name": "queue-interop/amqp-interop", - "version": "0.7.2", - "source": { - "type": "git", - "url": "https://github.com/queue-interop/amqp-interop.git", - "reference": "03cfac42483d07ab45d1896a6a2e1d873a216bba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/queue-interop/amqp-interop/zipball/03cfac42483d07ab45d1896a6a2e1d873a216bba", - "reference": "03cfac42483d07ab45d1896a6a2e1d873a216bba", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "queue-interop/queue-interop": "^0.6@dev" - }, - "require-dev": { - "phpunit/phpunit": "~5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Interop\\Amqp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "time": "2018-01-04T09:52:06+00:00" - }, - { - "name": "queue-interop/queue-interop", - "version": "0.6.1", - "source": { - "type": "git", - "url": "https://github.com/queue-interop/queue-interop.git", - "reference": "38579005c0492c0275bbae31170edf30a7e740fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/queue-interop/queue-interop/zipball/38579005c0492c0275bbae31170edf30a7e740fa", - "reference": "38579005c0492c0275bbae31170edf30a7e740fa", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Interop\\Queue\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Promoting the interoperability of MQs objects. Based on Java JMS", - "homepage": "https://github.com/queue-interop/queue-interop", - "keywords": [ - "MQ", - "jms", - "message queue", - "messaging", - "queue" - ], - "time": "2017-08-10T11:24:15+00:00" - }, { "name": "ramsey/uuid", "version": "3.7.3", @@ -1951,153 +1602,6 @@ ], "time": "2018-01-20T00:28:24+00:00" }, - { - "name": "roave/security-advisories", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "94230db36bded9d164ffccabcb38c67eedd63595" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/94230db36bded9d164ffccabcb38c67eedd63595", - "reference": "94230db36bded9d164ffccabcb38c67eedd63595", - "shasum": "" - }, - "conflict": { - "adodb/adodb-php": "<5.20.6", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1.0.0-alpha11", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.32", - "contao/core-bundle": ">=4,<4.4.8", - "contao/listing-bundle": ">=4,<4.4.8", - "contao/newsletter-bundle": ">=4,<4.1", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=8,<8.3.7", - "drupal/drupal": ">=8,<8.3.7", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.2|>=5.4,<5.4.10.1|>=2017.8,<2017.8.1.1", - "firebase/php-jwt": "<2", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "gree/jose": "<=2.2", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", - "joomla/session": "<1.3.1", - "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", - "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/magento2ce": ">=2,<2.2", - "monolog/monolog": ">=1.8,<1.12", - "namshi/jose": "<2.2", - "onelogin/php-saml": "<2.10.4", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "padraic/humbug_get_contents": "<1.1.2", - "phpmailer/phpmailer": ">=5,<5.2.24", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpxmlrpc/extras": "<0.6.1", - "pusher/pusher-php-server": "<2.2.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "shopware/shopware": "<5.3.7", - "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.3", - "silverstripe/userforms": "<3", - "simplesamlphp/saml2": "<1.10.4|>=2,<2.3.5|>=3,<3.1.1", - "simplesamlphp/simplesamlphp": "<1.15.2", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "socalnick/scn-social-auth": "<1.15.2", - "squizlabs/php_codesniffer": ">=1,<2.8.1", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "symfony/dependency-injection": ">=2,<2.0.17", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", - "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9|>=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.6|>=2.8.23,<2.8.25|>=3,<3.0.6|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", - "symfony/security-csrf": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", - "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", - "willdurand/js-translation-bundle": "<2.1.1", - "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.14", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.14", - "yiisoft/yii2-gii": "<2.0.4", - "yiisoft/yii2-jui": "<2.0.4", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-diactoros": ">=1,<1.0.4", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-02-19T09:31:21+00:00" - }, { "name": "sentry/sentry", "version": "1.8.3", @@ -2164,16 +1668,16 @@ }, { "name": "spomky-labs/otphp", - "version": "v9.0.3", + "version": "v9.1.0", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/otphp.git", - "reference": "26d19c0baff675fb64193e22b777aa9be63b8deb" + "reference": "4b303e33972f6c886f32b38fea60f41be6d74ec1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/26d19c0baff675fb64193e22b777aa9be63b8deb", - "reference": "26d19c0baff675fb64193e22b777aa9be63b8deb", + "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/4b303e33972f6c886f32b38fea60f41be6d74ec1", + "reference": "4b303e33972f6c886f32b38fea60f41be6d74ec1", "shasum": "" }, "require": { @@ -2221,7 +1725,7 @@ "otp", "totp" ], - "time": "2017-11-23T08:44:21+00:00" + "time": "2018-02-26T13:45:15+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -2280,16 +1784,16 @@ }, { "name": "symfony/http-foundation", - "version": "v3.4.4", + "version": "v3.4.12", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "8c39071ac9cc7e6d8dab1d556c990dc0d2cc3d30" + "reference": "1c28679fcbb0d9b35e4fd49fbb74d2ca4ea17bce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/8c39071ac9cc7e6d8dab1d556c990dc0d2cc3d30", - "reference": "8c39071ac9cc7e6d8dab1d556c990dc0d2cc3d30", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1c28679fcbb0d9b35e4fd49fbb74d2ca4ea17bce", + "reference": "1c28679fcbb0d9b35e4fd49fbb74d2ca4ea17bce", "shasum": "" }, "require": { @@ -2330,7 +1834,7 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-01-29T09:03:43+00:00" + "time": "2018-06-21T11:10:19+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2551,16 +2055,16 @@ }, { "name": "yiisoft/yii2", - "version": "2.0.14", + "version": "2.0.15.1", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-framework.git", - "reference": "1c9cf916b1394681c7d043e79e1522c33e5bc6c1" + "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/1c9cf916b1394681c7d043e79e1522c33e5bc6c1", - "reference": "1c9cf916b1394681c7d043e79e1522c33e5bc6c1", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ed3a9e1c4abe206e1c3ce48a6b3624119b79850d", + "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d", "shasum": "" }, "require": { @@ -2647,7 +2151,7 @@ "framework", "yii2" ], - "time": "2018-02-18T22:52:12+00:00" + "time": "2018-03-21T18:36:53+00:00" }, { "name": "yiisoft/yii2-composer", @@ -2701,24 +2205,25 @@ }, { "name": "yiisoft/yii2-queue", - "version": "2.0.2", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-queue.git", - "reference": "8c2b337f7d9ea934c2affdfc21c9fb387d0a0773" + "reference": "d04b4b3c932081200876a351cc6c3502e89e11b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-queue/zipball/8c2b337f7d9ea934c2affdfc21c9fb387d0a0773", - "reference": "8c2b337f7d9ea934c2affdfc21c9fb387d0a0773", + "url": "https://api.github.com/repos/yiisoft/yii2-queue/zipball/d04b4b3c932081200876a351cc6c3502e89e11b8", + "reference": "d04b4b3c932081200876a351cc6c3502e89e11b8", "shasum": "" }, "require": { "php": ">=5.5.0", "symfony/process": "*", - "yiisoft/yii2": "~2.0.13" + "yiisoft/yii2": "~2.0.14" }, "require-dev": { + "aws/aws-sdk-php": ">=2.4", "enqueue/amqp-lib": "^0.8", "jeremeamia/superclosure": "*", "pda/pheanstalk": "*", @@ -2729,6 +2234,7 @@ "yiisoft/yii2-redis": "*" }, "suggest": { + "aws/aws-sdk-php": "Need for aws SQS.", "enqueue/amqp-lib": "Need for AMQP interop queue.", "ext-gearman": "Need for Gearman queue.", "ext-pcntl": "Need for process signals.", @@ -2752,7 +2258,8 @@ "yii\\queue\\file\\": "src/drivers/file", "yii\\queue\\gearman\\": "src/drivers/gearman", "yii\\queue\\redis\\": "src/drivers/redis", - "yii\\queue\\sync\\": "src/drivers/sync" + "yii\\queue\\sync\\": "src/drivers/sync", + "yii\\queue\\sqs\\": "src/drivers/sqs" } }, "notification-url": "https://packagist.org/downloads/", @@ -2765,7 +2272,7 @@ "email": "zhuravljov@gmail.com" } ], - "description": "Yii2 Queue Extension which supported DB, Redis, RabbitMQ, Beanstalk and Gearman", + "description": "Yii2 Queue Extension which supported DB, Redis, RabbitMQ, Beanstalk, SQS and Gearman", "keywords": [ "async", "beanstalk", @@ -2775,26 +2282,30 @@ "queue", "rabbitmq", "redis", + "sqs", "yii" ], - "time": "2017-12-26T17:16:14+00:00" + "time": "2018-05-23T21:04:57+00:00" }, { "name": "yiisoft/yii2-redis", - "version": "2.0.7", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-redis.git", - "reference": "3891bb19f3ddc7ad744b439fe1d656ebb5b60a99" + "reference": "ffe6bff8dc6be4bb84c9495cd3ef7ef1161c1314" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-redis/zipball/3891bb19f3ddc7ad744b439fe1d656ebb5b60a99", - "reference": "3891bb19f3ddc7ad744b439fe1d656ebb5b60a99", + "url": "https://api.github.com/repos/yiisoft/yii2-redis/zipball/ffe6bff8dc6be4bb84c9495cd3ef7ef1161c1314", + "reference": "ffe6bff8dc6be4bb84c9495cd3ef7ef1161c1314", "shasum": "" }, "require": { - "yiisoft/yii2": "~2.0.13" + "yiisoft/yii2": "~2.0.14" + }, + "require-dev": { + "yiisoft/yii2-dev": "~2.0.14" }, "type": "yii2-extension", "extra": { @@ -2804,7 +2315,7 @@ }, "autoload": { "psr-4": { - "yii\\redis\\": "" + "yii\\redis\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2825,20 +2336,20 @@ "session", "yii2" ], - "time": "2017-12-11T21:17:34+00:00" + "time": "2018-03-20T11:01:04+00:00" }, { "name": "yiisoft/yii2-swiftmailer", - "version": "2.1.0", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/yiisoft/yii2-swiftmailer.git", - "reference": "563570c9aa19ca47c1b22e3032983229378e9274" + "reference": "fd917fbe63b7ea796c52902143b83b98e65bfb73" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/563570c9aa19ca47c1b22e3032983229378e9274", - "reference": "563570c9aa19ca47c1b22e3032983229378e9274", + "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/fd917fbe63b7ea796c52902143b83b98e65bfb73", + "reference": "fd917fbe63b7ea796c52902143b83b98e65bfb73", "shasum": "" }, "require": { @@ -2848,12 +2359,12 @@ "type": "yii2-extension", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { "psr-4": { - "yii\\swiftmailer\\": "" + "yii\\swiftmailer\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2875,7 +2386,7 @@ "swiftmailer", "yii2" ], - "time": "2017-08-04T10:48:17+00:00" + "time": "2018-04-24T23:17:42+00:00" } ], "packages-dev": [ @@ -3227,6 +2738,50 @@ ], "time": "2016-08-30T16:08:34+00:00" }, + { + "name": "composer/xdebug-handler", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/c919dc6c62e221fc6406f861ea13433c0aa24f08", + "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2018-04-11T15:42:36+00:00" + }, { "name": "doctrine/instantiator", "version": "1.1.0", @@ -3387,16 +2942,16 @@ }, { "name": "flow/jsonpath", - "version": "0.3.4", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/FlowCommunications/JSONPath.git", - "reference": "00aa9c361e4d0a210dd95f3c917a1e0dde3a957f" + "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/00aa9c361e4d0a210dd95f3c917a1e0dde3a957f", - "reference": "00aa9c361e4d0a210dd95f3c917a1e0dde3a957f", + "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/f0222818d5c938e4ab668ab2e2c079bd51a27112", + "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112", "shasum": "" }, "require": { @@ -3424,24 +2979,25 @@ } ], "description": "JSONPath implementation for parsing, searching and flattening arrays", - "time": "2016-09-06T17:43:18+00:00" + "time": "2018-03-04T16:39:47+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.11.1", + "version": "v2.12.2", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "ad94441c17b8ef096e517acccdbf3238af8a2da8" + "reference": "dcc87d5414e9d0bd316fce81a5bedb9ce720b183" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ad94441c17b8ef096e517acccdbf3238af8a2da8", - "reference": "ad94441c17b8ef096e517acccdbf3238af8a2da8", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/dcc87d5414e9d0bd316fce81a5bedb9ce720b183", + "reference": "dcc87d5414e9d0bd316fce81a5bedb9ce720b183", "shasum": "" }, "require": { "composer/semver": "^1.4", + "composer/xdebug-handler": "^1.0", "doctrine/annotations": "^1.2", "ext-json": "*", "ext-tokenizer": "*", @@ -3463,27 +3019,26 @@ "require-dev": { "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", "justinrainbow/json-schema": "^5.0", - "keradus/cli-executor": "^1.0", + "keradus/cli-executor": "^1.1", "mikey179/vfsstream": "^1.6", - "php-coveralls/php-coveralls": "^2.0", + "php-coveralls/php-coveralls": "^2.1", "php-cs-fixer/accessible-object": "^1.0", - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "phpunitgoodpractices/traits": "^1.3.1", - "symfony/phpunit-bridge": "^3.2.2 || ^4.0" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1", + "phpunitgoodpractices/traits": "^1.5.1", + "symfony/phpunit-bridge": "^4.0" }, "suggest": { "ext-mbstring": "For handling non-UTF8 characters in cache signature.", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.", "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible." }, "bin": [ "php-cs-fixer" ], "type": "application", - "extra": { - "branch-alias": { - "dev-master": "2.11-dev" - } - }, "autoload": { "psr-4": { "PhpCsFixer\\": "src/" @@ -3493,9 +3048,6 @@ "tests/Test/AbstractIntegrationCaseFactory.php", "tests/Test/AbstractIntegrationTestCase.php", "tests/Test/Assert/AssertTokensTrait.php", - "tests/Test/Constraint/SameStringsConstraint.php", - "tests/Test/Constraint/SameStringsConstraintForV5.php", - "tests/Test/Constraint/SameStringsConstraintForV7.php", "tests/Test/IntegrationCase.php", "tests/Test/IntegrationCaseFactory.php", "tests/Test/IntegrationCaseFactoryInterface.php", @@ -3518,7 +3070,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2018-03-21T17:41:26+00:00" + "time": "2018-07-06T10:37:40+00:00" }, { "name": "fzaninotto/faker", @@ -4657,6 +4209,270 @@ ], "time": "2018-01-06T05:45:45+00:00" }, + { + "name": "predis/predis", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/nrk/predis.git", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/nrk/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "time": "2016-06-16T16:22:20+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "roave/security-advisories", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "0253937ef2720f45fbe421e3ba486587b3080c35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0253937ef2720f45fbe421e3ba486587b3080c35", + "reference": "0253937ef2720f45fbe421e3ba486587b3080c35", + "shasum": "" + }, + "conflict": { + "3f/pygmentize": "<1.2", + "adodb/adodb-php": "<5.20.12", + "amphp/artax": "<1.0.6|>=2,<2.0.6", + "amphp/http": "<1.0.1", + "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "aws/aws-sdk-php": ">=3,<3.2.1", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<=2.1.6", + "codeigniter/framework": "<=3.0.6", + "composer/composer": "<=1.0.0-alpha11", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2,<3.5.35", + "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8", + "contao/listing-bundle": ">=4,<4.4.8", + "contao/newsletter-bundle": ">=4,<4.1", + "doctrine/annotations": ">=1,<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<=0.7.1", + "doctrine/mongodb-odm": ">=1,<1.0.2", + "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", + "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", + "drupal/drupal": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", + "erusev/parsedown": "<1.7", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1", + "firebase/php-jwt": "<2", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "fuel/core": "<1.8.1", + "gree/jose": "<=2.2", + "gregwar/rst": "<1.0.3", + "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", + "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", + "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "joomla/session": "<1.3.1", + "kreait/firebase-php": ">=3.2,<3.8.1", + "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", + "magento/magento1ee": ">=1.9,<1.14.3.2", + "magento/product-community-edition": ">=2,<2.2.5", + "monolog/monolog": ">=1.8,<1.12", + "namshi/jose": "<2.2", + "onelogin/php-saml": "<2.10.4", + "oro/crm": ">=1.7,<1.7.4", + "oro/platform": ">=1.7,<1.7.4", + "padraic/humbug_get_contents": "<1.1.2", + "pagarme/pagarme-php": ">=0,<3", + "paragonie/random_compat": "<2", + "paypal/merchant-sdk-php": "<3.12", + "phpmailer/phpmailer": ">=5,<5.2.24", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpxmlrpc/extras": "<0.6.1", + "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", + "propel/propel1": ">=1,<=1.7.1", + "pusher/pusher-php-server": "<2.2.1", + "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "sensiolabs/connect": "<4.2.3", + "shopware/shopware": "<5.3.7", + "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": ">=3,<3.3", + "silverstripe/userforms": "<3", + "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/simplesamlphp": "<1.15.2", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "slim/slim": "<2.6", + "socalnick/scn-social-auth": "<1.15.2", + "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", + "stormpath/sdk": ">=0,<9.9.99", + "swiftmailer/swiftmailer": ">=4,<5.4.5", + "symfony/dependency-injection": ">=2,<2.0.17", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", + "symfony/http-foundation": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", + "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/routing": ">=2,<2.0.19", + "symfony/security": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", + "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/serializer": ">=2,<2.0.11", + "symfony/symfony": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/translation": ">=2,<2.0.17", + "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "thelia/backoffice-default-template": ">=2.1,<2.1.2", + "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "titon/framework": ">=0,<9.9.99", + "twig/twig": "<1.20", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "willdurand/js-translation-bundle": "<2.1.1", + "yiisoft/yii": ">=1.1.14,<1.1.15", + "yiisoft/yii2": "<2.0.15", + "yiisoft/yii2-bootstrap": "<2.0.4", + "yiisoft/yii2-dev": "<2.0.15", + "yiisoft/yii2-elasticsearch": "<2.0.5", + "yiisoft/yii2-gii": "<2.0.4", + "yiisoft/yii2-jui": "<2.0.4", + "yiisoft/yii2-redis": "<2.0.8", + "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", + "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-diactoros": ">=1,<1.0.4", + "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", + "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", + "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-validator": ">=2.3,<2.3.6", + "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", + "zendframework/zendframework1": "<1.12.20", + "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendxml": ">=1,<1.0.1", + "zetacomponents/mail": "<1.8.2", + "zf-commons/zfc-user": "<1.2.2", + "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", + "zfr/zfr-oauth2-server-module": "<0.1.2" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" + } + ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "time": "2018-07-04T05:48:21+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -6025,9 +5841,8 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "roave/security-advisories": 20, - "ely/amqp-controller": 20, - "ely/email-renderer": 20 + "ely/email-renderer": 20, + "roave/security-advisories": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/console/controllers/AccountQueueController.php b/console/controllers/AccountQueueController.php deleted file mode 100644 index 04ee523..0000000 --- a/console/controllers/AccountQueueController.php +++ /dev/null @@ -1,98 +0,0 @@ -exchange->topic()->durable(); - $configurator->queue->name('accounts-accounts-events')->durable(); - $configurator->bind->routingKey('accounts.username-changed') - ->add()->routingKey('account.account-banned'); - } - - public function getRoutesMap() { - return [ - 'accounts.username-changed' => 'routeUsernameChanged', - 'accounts.account-banned' => 'routeAccountBanned', - ]; - } - - public function routeUsernameChanged(UsernameChanged $body): bool { - Yii::$app->statsd->inc('worker.account.usernameChanged.attempt'); - $mojangApi = $this->createMojangApi(); - try { - $response = $mojangApi->usernameToUUID($body->newUsername); - Yii::$app->statsd->inc('worker.account.usernameChanged.found'); - } catch (NoContentException $e) { - $response = false; - Yii::$app->statsd->inc('worker.account.usernameChanged.not_found'); - } catch (RequestException $e) { - return true; - } - - /** @var MojangUsername|null $mojangUsername */ - $mojangUsername = MojangUsername::findOne($body->newUsername); - if ($response === false) { - if ($mojangUsername !== null) { - $mojangUsername->delete(); - } - } else { - if ($mojangUsername === null) { - $mojangUsername = new MojangUsername(); - $mojangUsername->username = $response->name; - $mojangUsername->uuid = $response->id; - } else { - $mojangUsername->uuid = $response->id; - $mojangUsername->touch('last_pulled_at'); - } - - $mojangUsername->save(); - } - - return true; - } - - public function routeAccountBanned(AccountBanned $body): bool { - $account = Account::findOne($body->accountId); - if ($account === null) { - Yii::warning('Cannot find banned account ' . $body->accountId . '. Skipping.'); - return true; - } - - foreach ($account->sessions as $authSession) { - $authSession->delete(); - } - - foreach ($account->minecraftAccessKeys as $key) { - $key->delete(); - } - - foreach ($account->oauthSessions as $oauthSession) { - $oauthSession->delete(); - } - - return true; - } - - /** - * @return MojangApi - */ - protected function createMojangApi(): MojangApi { - return new MojangApi(); - } - -} diff --git a/console/controllers/AmqpController.php b/console/controllers/AmqpController.php deleted file mode 100644 index 1c6360c..0000000 --- a/console/controllers/AmqpController.php +++ /dev/null @@ -1,72 +0,0 @@ -start(); - } - - public function getRoutesMap() { - return []; - } - - /** - * Переопределяем метод callback, чтобы избержать логгирования в консоль ошибок, - * связанных с обвалом того или иного соединения. Это нормально, PHP рождён умирать, - * а не работать 24/7 в качестве демона. - * - * @param AMQPMessage $msg - * @throws YiiDbException - */ - public function callback(AMQPMessage $msg) { - try { - $this->_callback($msg); - } catch (YiiDbException $e) { - if ($this->reconnected || !$this->isRestorableException($e)) { - throw $e; - } - - $this->reconnected = true; - Yii::$app->db->close(); - Yii::$app->db->open(); - $this->callback($msg); - } - - $this->reconnected = false; - } - - /** - * @inheritdoc - */ - protected function getConnection() { - return Yii::$app->amqp->getConnection(); - } - - /** - * @inheritdoc - */ - protected function buildRouteActionName($route) { - return ArrayHelper::getValue($this->getRoutesMap(), $route, 'route' . Inflector::camelize($route)); - } - - private function isRestorableException(Exception $e): bool { - return strpos($e->getMessage(), 'MySQL server has gone away') !== false - || strcmp($e->getMessage(), 'Error while sending QUERY packet') !== false; - } - -} diff --git a/console/controllers/WebhooksController.php b/console/controllers/WebhooksController.php new file mode 100644 index 0000000..1dcd731 --- /dev/null +++ b/console/controllers/WebhooksController.php @@ -0,0 +1,57 @@ + true, + 'validator' => function(string $input, ?string &$error) use ($form): bool { + $form->url = $input; + if (!$form->validate('url')) { + $error = $form->getFirstError('url'); + return false; + } + + return true; + }, + ]); + $secret = Console::prompt('Enter webhook secret (empty to no secret):'); + + $options = $form::getEvents(); + $options[''] = 'Finish input'; // It's needed to allow finish input cycle + $events = []; + + do { + $availableOptions = array_diff($options, $events); + $eventIndex = Console::select('Choose wanted events (submit no input to finish):', $availableOptions); + if ($eventIndex !== '') { + $events[] = $options[$eventIndex]; + } + } while ($eventIndex !== '' || empty($events)); + + $form->url = $url; + $form->events = $events; + if ($secret !== '') { + $form->secret = $secret; + } + + if (!$form->save()) { + Console::error('Unable to create new webhook. Check errors list below' . PHP_EOL . Console::errorSummary($form)); + return ExitCode::UNSPECIFIED_ERROR; + } + + return ExitCode::OK; + } + +} diff --git a/console/db/Migration.php b/console/db/Migration.php index e05b6aa..3ec8284 100644 --- a/console/db/Migration.php +++ b/console/db/Migration.php @@ -25,28 +25,12 @@ class Migration extends YiiMigration { parent::createTable($table, $columns, $options); } - protected function primary(...$columns) { - switch (count($columns)) { - case 0: - $key = ''; - break; - case 1: - $key = $columns[0]; - break; - default: - $key = $this->buildKey($columns); + protected function primary(string ...$columns): string { + foreach ($columns as &$column) { + $column = $this->db->quoteColumnName($column); } - return " PRIMARY KEY ($key) "; - } - - private function buildKey(array $columns) { - $key = ''; - foreach ($columns as $i => $column) { - $key .= $i === count($columns) ? $column : "$column,"; - } - - return $key; + return ' PRIMARY KEY (' . implode(', ', $columns) . ') '; } } diff --git a/console/migrations/m180706_230451_webhooks.php b/console/migrations/m180706_230451_webhooks.php new file mode 100644 index 0000000..df6a620 --- /dev/null +++ b/console/migrations/m180706_230451_webhooks.php @@ -0,0 +1,28 @@ +createTable('{{%webhooks}}', [ + 'id' => $this->primaryKey(11)->unsigned(), + 'url' => $this->string()->notNull(), + 'secret' => $this->string(), + 'created_at' => $this->integer(11)->unsigned()->notNull(), + ]); + + $this->createTable('{{%webhooks_events}}', [ + 'webhook_id' => $this->db->getTableSchema('{{%webhooks}}')->getColumn('id')->dbType . ' NOT NULL', + 'event_type' => $this->string()->notNull(), + $this->primary('webhook_id', 'event_type'), + ]); + $this->addForeignKey('FK_webhook_event_to_webhook', '{{%webhooks_events}}', 'webhook_id', 'webhooks', 'id', 'CASCADE', 'CASCADE'); + } + + public function safeDown() { + $this->dropTable('{{%webhooks_events}}'); + $this->dropTable('{{%webhooks}}'); + } + +} diff --git a/console/migrations/m180708_155425_extends_locale_field.php b/console/migrations/m180708_155425_extends_locale_field.php new file mode 100644 index 0000000..600442b --- /dev/null +++ b/console/migrations/m180708_155425_extends_locale_field.php @@ -0,0 +1,15 @@ +alterColumn('{{%accounts}}', 'lang', $this->string()->notNull()->defaultValue('en')); + } + + public function safeDown() { + $this->alterColumn('{{%accounts}}', 'lang', $this->string(5)->notNull()->defaultValue('en')); + } + +} diff --git a/console/models/.gitkeep b/console/models/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/console/models/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/console/models/WebHookForm.php b/console/models/WebHookForm.php new file mode 100644 index 0000000..4f9cfcd --- /dev/null +++ b/console/models/WebHookForm.php @@ -0,0 +1,70 @@ +webHook = $webHook; + } + + public function rules(): array { + return [ + [['url'], 'required'], + [['url'], 'url'], + [['secret'], 'string'], + [['events'], 'in', 'range' => static::getEvents(), 'allowArray' => true], + ]; + } + + public function save(): bool { + if (!$this->validate()) { + return false; + } + + $transaction = Yii::$app->db->beginTransaction(); + + $webHook = $this->webHook; + $webHook->url = $this->url; + $webHook->secret = $this->secret; + if (!$webHook->save()) { + throw new ThisShouldNotHappenException('Cannot save webhook.'); + } + + foreach ($this->events as $event) { + $eventModel = new WebHookEvent(); + $eventModel->webhook_id = $webHook->id; + $eventModel->event_type = $event; + if (!$eventModel->save()) { + throw new ThisShouldNotHappenException('Cannot save webhook event.'); + } + } + + $transaction->commit(); + + return true; + } + + public static function getEvents(): array { + return [ + 'account.edit', + ]; + } + +} diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index f93f1f7..7854586 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,13 +1,42 @@ version: '2' services: app: + image: registry.ely.by/elyby/accounts:dev build: - dockerfile: Dockerfile-dev context: . + args: + build_env: dev + depends_on: + - db + - redis + volumes: + - ./:/var/www/html/ + env_file: .env + + worker: + image: registry.ely.by/elyby/accounts:dev + build: + context: . + args: + build_env: dev + command: ['php', 'yii', 'queue/listen', '-v'] + depends_on: + - db + - redis + volumes: + - ./:/var/www/html/ + env_file: .env + + cron: + image: registry.ely.by/elyby/accounts:dev + build: + context: . + args: + build_env: dev + command: ['crond', '-s', '/etc/cron.d', '-f', '-L', '/var/log/cron.log'] depends_on: - db - redis - - rabbitmq volumes: - ./:/var/www/html/ env_file: .env @@ -34,16 +63,6 @@ services: volumes: - ./data/redis:/data - rabbitmq: - image: rabbitmq:3.6-management - env_file: .env - environment: - - VIRTUAL_HOST=rabbitmq.account.ely.by.local - - VIRTUAL_PORT=15672 - networks: - - default - - nginx-proxy - phpmyadmin: build: ./docker/phpmyadmin environment: @@ -57,17 +76,6 @@ services: - default - nginx-proxy - # Эта штука работает дико медленно, грузит процессор и т.д. и т.п. - # Раскоментировать только в случае лютой надобности - #node-dev-server: - # build: ./frontend - # ports: - # - "8080:8080" - # volumes: - # - ./frontend/:/usr/src/app/ - # environment: - # DOCKERIZED: "true" - networks: nginx-proxy: external: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 47b6e78..687baab 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -2,14 +2,33 @@ version: '2' services: app: image: registry.ely.by/elyby/accounts:latest + restart: always + depends_on: + - db + - redis + env_file: .env + + worker: + image: registry.ely.by/elyby/accounts:latest + restart: always + command: ['php', 'yii', 'queue/listen', '-v'] + depends_on: + - db + - redis + env_file: .env + + worker: + image: registry.ely.by/elyby/accounts:latest + restart: always + command: ['crond', '-s', '/etc/cron.d', '-f', '-L', '/var/log/cron.log'] depends_on: - db - redis - - rabbitmq env_file: .env web: image: registry.ely.by/elyby/accounts-nginx:1.0.3 + restart: always volumes_from: - app links: @@ -21,19 +40,17 @@ services: db: build: ./docker/mariadb + restart: always env_file: .env volumes: - ./data/mysql:/var/lib/mysql redis: image: redis:3.0-alpine + restart: always volumes: - ./data/redis:/data - rabbitmq: - image: rabbitmq:3.6 - env_file: .env - networks: nginx-proxy: external: diff --git a/docker/php/bootstrap.sh b/docker/php/bootstrap.sh deleted file mode 100755 index 65617dd..0000000 --- a/docker/php/bootstrap.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -mkdir -p api/runtime api/web/assets console/runtime -chown www-data:www-data api/runtime api/web/assets console/runtime - -if [ "$YII_ENV" = "test" ] -then - YII_EXEC="/var/www/html/tests/codeception/bin/yii" -else - YII_EXEC="/var/www/html/yii" -fi - -if ! cmp -s ./../vendor/autoload.php ./vendor/autoload.php -then - echo "Vendor have diffs" - echo "Removing not bundled vendor..." - rm -rf ./vendor - echo "Copying new one..." - cp -r ./../vendor ./vendor -fi - -# Переносим dist, если его нету или он изменился (или затёрся силами volume) -if ! cmp -s ./../dist/index.html ./frontend/dist/index.html -then - echo "Frontend dist have diffs" - echo "Removing not bundled dist..." - rm -rf ./frontend/dist - echo "Copying new one..." - cp -r ./../dist ./frontend/dist -fi - -# Генерируем правила RBAC -echo "Generating RBAC rules" -php $YII_EXEC rbac/generate - -if [ "$YII_ENV" != "test" ] -then - wait-for-it "${DB_HOST:-db}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" -else - wait-for-it "${DB_HOST:-testdb}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" -fi diff --git a/docker/php/docker-entrypoint.sh b/docker/php/docker-entrypoint.sh new file mode 100755 index 0000000..c34f9fa --- /dev/null +++ b/docker/php/docker-entrypoint.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -e + +XDEBUG_EXTENSION_FILE="/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini" +PHP_PROD_INI="/usr/local/etc/php/conf.d/php.prod.ini" +PHP_DEV_INI="/usr/local/etc/php/conf.d/php.dev.ini" + +if [ "$YII_DEBUG" = "true" ] || [ "$YII_DEBUG" = "1" ] ; then + echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > $XDEBUG_EXTENSION_FILE + mv ${PHP_PROD_INI}{,.disabled} 2> /dev/null || true + mv ${PHP_DEV_INI}{.disabled,} 2> /dev/null || true +else + rm -f $XDEBUG_EXTENSION_FILE + mv ${PHP_DEV_INI}{,.disabled} 2> /dev/null || true + mv ${PHP_PROD_INI}{.disabled,} 2> /dev/null || true +fi + +cd /var/www/html + +# Create all necessary folders +mkdir -p api/runtime api/web/assets console/runtime +chown -R www-data:www-data api/runtime api/web/assets console/runtime + +if [ "$YII_ENV" = "test" ] +then + YII_EXEC="/var/www/html/tests/codeception/bin/yii" +else + YII_EXEC="/var/www/html/yii" +fi + +# Fix permissions for cron tasks +chmod 644 /etc/cron.d/* + +if [ "$1" = "crond" ] ; then + # see: https://github.com/dubiousjim/dcron/issues/13 + # ignore using `exec` for `dcron` to get another pid instead of `1` + # exec "$@" + "$@" +fi + +if [ "$1" = "yii" ] ; then + shift + php $YII_EXEC "$@" + exit 0 +fi + +if [ "$1" = "sh" ] || [ "$1" = "bash" ] || [ "$1" = "composer" ] || [ "$1" = "php" ] ; then + exec "$@" + exit 0 +fi + +echo "Generating RBAC rules" +php $YII_EXEC rbac/generate + +if [ "$YII_ENV" != "test" ] +then + wait-for-it "${DB_HOST:-db}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" +else + wait-for-it "${DB_HOST:-testdb}:3306" -s -t 0 -- "php $YII_EXEC migrate/up --interactive=0" +fi + +exec "$@" diff --git a/docker/php/php.dev.ini b/docker/php/php.dev.ini new file mode 100644 index 0000000..7114082 --- /dev/null +++ b/docker/php/php.dev.ini @@ -0,0 +1,5 @@ +error_reporting = E_ALL; +display_errors = On; + +# Disable Opcache caching +opcache.validate_timestamps = 1; diff --git a/docker/php/php.prod.ini b/docker/php/php.prod.ini new file mode 100644 index 0000000..f0cc3e5 --- /dev/null +++ b/docker/php/php.prod.ini @@ -0,0 +1,14 @@ +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT +display_errors = Off +display_startup_errors = Off +log_errors = On +html_errors = Off +expose_php = Off + +# Opcache tuning +opcache.revalidate_freq = 0 +opcache.validate_timestamps = 0 +opcache.max_accelerated_files = 7963 +opcache.memory_consumption = 192 +opcache.interned_strings_buffer = 16 +opcache.fast_shutdown = 1 diff --git a/docker/wait-for-it.sh b/docker/php/wait-for-it.sh similarity index 100% rename from docker/wait-for-it.sh rename to docker/php/wait-for-it.sh diff --git a/docker/php/xdebug.ini b/docker/php/xdebug.ini new file mode 100644 index 0000000..431323d --- /dev/null +++ b/docker/php/xdebug.ini @@ -0,0 +1,11 @@ +xdebug.default_enable=1 +xdebug.remote_enable=1 +xdebug.remote_handler=dbgp +xdebug.remote_mode=req +xdebug.remote_autostart=1 +xdebug.remote_port=9000 +xdebug.remote_connect_back=0 +xdebug.cli_color=1 +xdebug.var_display_max_depth=10 +xdebug.profiler_enable_trigger=1 +xdebug.profiler_output_dir=/tmp/xdebug-profiler diff --git a/docker/phpmyadmin/Dockerfile b/docker/phpmyadmin/Dockerfile index 62e24d4..6b03cfe 100644 --- a/docker/phpmyadmin/Dockerfile +++ b/docker/phpmyadmin/Dockerfile @@ -1,4 +1,4 @@ -FROM phpmyadmin/phpmyadmin +FROM phpmyadmin/phpmyadmin:4.7.9-1 RUN printf "\n\nrequire('./config.local.php');\n" >> /www/config.inc.php diff --git a/api/models/profile/TwoFactorAuthForm.php b/docker/supervisor/.gitkeep similarity index 100% rename from api/models/profile/TwoFactorAuthForm.php rename to docker/supervisor/.gitkeep diff --git a/docker/supervisor/account-queue-worker.conf b/docker/supervisor/account-queue-worker.conf deleted file mode 100644 index aed1af3..0000000 --- a/docker/supervisor/account-queue-worker.conf +++ /dev/null @@ -1,6 +0,0 @@ -[program:account-queue-worker] -directory=/var/www/html -command=wait-for-it rabbitmq:5672 -- php yii account-queue -autostart=true -autorestart=true -priority=10 diff --git a/docker/supervisor/worker-queue.conf b/docker/supervisor/worker-queue.conf deleted file mode 100644 index 397c104..0000000 --- a/docker/supervisor/worker-queue.conf +++ /dev/null @@ -1,6 +0,0 @@ -[program:queue-worker] -directory=/var/www/html -command=wait-for-it rabbitmq:5672 -- php yii queue/listen -v -autostart=true -autorestart=true -priority=10 diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..c40b483 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +.bash_history diff --git a/tests/codeception/api/functional.suite.yml b/tests/codeception/api/functional.suite.yml index 9a6ac97..570a025 100644 --- a/tests/codeception/api/functional.suite.yml +++ b/tests/codeception/api/functional.suite.yml @@ -4,7 +4,6 @@ modules: - Filesystem - Yii2 - tests\codeception\common\_support\FixtureHelper - - tests\codeception\common\_support\amqp\Helper - tests\codeception\common\_support\Mockery - Redis - Asserts diff --git a/tests/codeception/api/functional/RegisterCest.php b/tests/codeception/api/functional/RegisterCest.php index 4730d8f..c4ee698 100644 --- a/tests/codeception/api/functional/RegisterCest.php +++ b/tests/codeception/api/functional/RegisterCest.php @@ -1,258 +1,299 @@ 'erickskrauch@ely.by', - 'username' => 'ErickSkrauch', - ]); + /** + * @var SignupRoute + */ + private $route; + + public function _before(FunctionalTester $I) { + $this->route = new SignupRoute($I); } - public function testIncorrectRegistration(FunctionalTester $I) { - $route = new SignupRoute($I); - - $I->wantTo('get error.rulesAgreement_required if we don\'t accept rules'); - $route->register([ - 'username' => 'ErickSkrauch', - 'email' => 'erickskrauch@ely.by', - 'password' => 'some_password', - 'rePassword' => 'some_password', - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'rulesAgreement' => 'error.rulesAgreement_required', - ], - ]); - - $I->wantTo('don\'t see error.rulesAgreement_requireds if we accept rules'); - $route->register([ - 'rulesAgreement' => true, - ]); - $I->cantSeeResponseContainsJson([ - 'errors' => [ - 'rulesAgreement' => 'error.rulesAgreement_required', - ], - ]); - - $I->wantTo('see error.username_required if username is not set'); - $route->register([ - 'username' => '', - 'email' => '', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'username' => 'error.username_required', - ], - ]); - - $I->wantTo('don\'t see error.username_required if username is not set'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => '', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->cantSeeResponseContainsJson([ - 'errors' => [ - 'username' => 'error.username_required', - ], - ]); - - $I->wantTo('see error.email_required if email is not set'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => '', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'email' => 'error.email_required', - ], - ]); - - $I->wantTo('see error.email_invalid if email is set, but invalid'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'invalid@email', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'email' => 'error.email_invalid', - ], - ]); - - $I->wantTo('see error.email_invalid if email is set, valid, but domain doesn\'t exist or don\'t have mx record'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'invalid@govnomail.com', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'email' => 'error.email_invalid', - ], - ]); - - $I->wantTo('see error.email_not_available if email is set, fully valid, but not available for registration'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'admin@ely.by', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'email' => 'error.email_not_available', - ], - ]); - - $I->wantTo('don\'t see errors on email if all valid'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'erickskrauch@ely.by', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->cantSeeResponseJsonMatchesJsonPath('$.errors.email'); - - $I->wantTo('see error.password_required if password is not set'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'erickskrauch@ely.by', - 'password' => '', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'password' => 'error.password_required', - ], - ]); - - $I->wantTo('see error.password_too_short before it will be compared with rePassword'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'correct-email@ely.by', - 'password' => 'short', - 'rePassword' => 'password', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'password' => 'error.password_too_short', - ], - ]); - $I->cantSeeResponseJsonMatchesJsonPath('$.errors.rePassword'); - - $I->wantTo('see error.rePassword_required if password valid and rePassword not set'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'correct-email@ely.by', - 'password' => 'valid-password', - 'rePassword' => '', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'rePassword' => 'error.rePassword_required', - ], - ]); - - $I->wantTo('see error.rePassword_does_not_match if password valid and rePassword donen\'t match it'); - $route->register([ - 'username' => 'valid_nickname', - 'email' => 'correct-email@ely.by', - 'password' => 'valid-password', - 'rePassword' => 'password', - 'rulesAgreement' => true, - ]); - $I->canSeeResponseContainsJson([ - 'success' => false, - 'errors' => [ - 'rePassword' => 'error.rePassword_does_not_match', - ], - ]); - $I->cantSeeResponseJsonMatchesJsonPath('$.errors.password'); - } - - public function testUserCorrectRegistration(FunctionalTester $I) { - $route = new SignupRoute($I); - - $I->wantTo('ensure that signup works'); - $route->register([ - 'username' => 'some_username', - 'email' => 'some_email@example.com', - 'password' => 'some_password', - 'rePassword' => 'some_password', - 'rulesAgreement' => true, - 'lang' => 'ru', - ]); - $this->assertSuccessRegistration($I); - } - - public function testUserCorrectRegistrationWithReassignUsername(FunctionalTester $I) { - $route = new SignupRoute($I); - - $I->wantTo('ensure that signup allow reassign not finished registration username'); - $route->register([ - 'username' => 'howe.garnett', - 'email' => 'custom-email@gmail.com', - 'password' => 'some_password', - 'rePassword' => 'some_password', - 'rulesAgreement' => true, - 'lang' => 'ru', - ]); - $this->assertSuccessRegistration($I); - } - - public function testUserCorrectRegistrationWithReassignEmail(FunctionalTester $I) { - $route = new SignupRoute($I); - - $I->wantTo('ensure that signup allow reassign not finished registration email'); - $route->register([ - 'username' => 'CustomUsername', - 'email' => 'achristiansen@gmail.com', - 'password' => 'some_password', - 'rePassword' => 'some_password', - 'rulesAgreement' => true, - 'lang' => 'ru', - ]); - $this->assertSuccessRegistration($I); - } - - private function assertSuccessRegistration(FunctionalTester $I) { + /** + * @dataProvider getSuccessInputExamples + */ + public function testUserCorrectRegistration(FunctionalTester $I, Example $example) { + $I->wantTo($example->offsetGet('case')); + $this->route->register($example->offsetGet('request')); $I->canSeeResponseCodeIs(200); $I->canSeeResponseIsJson(); $I->canSeeResponseContainsJson(['success' => true]); $I->cantSeeResponseJsonMatchesJsonPath('$.errors'); } + /** + * @dataProvider getInvalidInputExamples + */ + public function testIncorrectRegistration(FunctionalTester $I, Example $example) { + $I->wantTo($example->offsetGet('case')); + $this->route->register($example->offsetGet('request')); + if ($example->offsetExists('canSee')) { + $I->canSeeResponseContainsJson($example->offsetGet('canSee')); + } + + if ($example->offsetExists('cantSee')) { + $I->cantSeeResponseContainsJson($example->offsetGet('cantSee')); + } + + if ($example->offsetExists('shouldNotMatch')) { + foreach ((array)$example->offsetGet('shouldNotMatch') as $jsonPath) { + $I->cantSeeResponseJsonMatchesJsonPath($jsonPath); + } + } + } + + protected function getSuccessInputExamples(): array { + return [ + [ + 'case' => 'ensure that signup works', + 'request' => [ + 'username' => 'some_username', + 'email' => 'some_email@example.com', + 'password' => 'some_password', + 'rePassword' => 'some_password', + 'rulesAgreement' => true, + 'lang' => 'ru', + ], + ], + [ + 'case' => 'ensure that signup allow reassign not finished registration username', + 'request' => [ + 'username' => 'howe.garnett', + 'email' => 'custom-email@gmail.com', + 'password' => 'some_password', + 'rePassword' => 'some_password', + 'rulesAgreement' => true, + 'lang' => 'ru', + ], + ], + [ + 'case' => 'ensure that signup allow reassign not finished registration email', + 'request' => [ + 'username' => 'CustomUsername', + 'email' => 'achristiansen@gmail.com', + 'password' => 'some_password', + 'rePassword' => 'some_password', + 'rulesAgreement' => true, + 'lang' => 'ru', + ], + ], + ]; + } + + protected function getInvalidInputExamples(): array { + return [ + [ + 'case' => 'get error.rulesAgreement_required if we don\'t accept rules', + 'request' => [ + 'username' => 'ErickSkrauch', + 'email' => 'erickskrauch@ely.by', + 'password' => 'some_password', + 'rePassword' => 'some_password', + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'rulesAgreement' => 'error.rulesAgreement_required', + ], + ], + ], + [ + 'case' => 'don\'t see error.rulesAgreement_requireds if we accept rules', + 'request' => [ + 'rulesAgreement' => true, + ], + 'cantSee' => [ + 'errors' => [ + 'rulesAgreement' => 'error.rulesAgreement_required', + ], + ], + ], + [ + 'case' => 'see error.username_required if username is not set', + 'request' => [ + 'username' => '', + 'email' => '', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'username' => 'error.username_required', + ], + ], + ], + [ + 'case' => 'don\'t see error.username_required if username is not set', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => '', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'cantSee' => [ + 'errors' => [ + 'username' => 'error.username_required', + ], + ], + ], + [ + 'case' => 'see error.email_required if email is not set', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => '', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'email' => 'error.email_required', + ], + ], + ], + [ + 'case' => 'see error.email_invalid if email is set, but invalid', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'invalid@email', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'email' => 'error.email_invalid', + ], + ], + ], + [ + 'case' => 'see error.email_invalid if email is set, valid, but domain doesn\'t exist or don\'t have mx record', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'invalid@this-should-be-really-no-exists-domain-63efd7ab-1529-46d5-9426-fa5ed9f710e6.com', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'email' => 'error.email_invalid', + ], + ], + ], + [ + 'case' => 'see error.email_not_available if email is set, fully valid, but not available for registration', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'admin@ely.by', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'email' => 'error.email_not_available', + ], + ], + ], + [ + 'case' => 'don\'t see errors on email if email valid', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'erickskrauch@ely.by', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'shouldNotMatch' => [ + '$.errors.email', + ], + ], + [ + 'case' => 'see error.password_required if password is not set', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'erickskrauch@ely.by', + 'password' => '', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'password' => 'error.password_required', + ], + ], + ], + [ + 'case' => 'see error.password_too_short before it will be compared with rePassword', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'correct-email@ely.by', + 'password' => 'short', + 'rePassword' => 'password', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'password' => 'error.password_too_short', + ], + ], + 'shouldNotMatch' => [ + '$.errors.rePassword', + ], + ], + [ + 'case' => 'see error.rePassword_required if password valid and rePassword not set', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'correct-email@ely.by', + 'password' => 'valid-password', + 'rePassword' => '', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'rePassword' => 'error.rePassword_required', + ], + ], + ], + [ + 'case' => 'see error.rePassword_does_not_match if password valid and rePassword doesn\'t match it', + 'request' => [ + 'username' => 'valid_nickname', + 'email' => 'correct-email@ely.by', + 'password' => 'valid-password', + 'rePassword' => 'password', + 'rulesAgreement' => true, + ], + 'canSee' => [ + 'success' => false, + 'errors' => [ + 'rePassword' => 'error.rePassword_does_not_match', + ], + ], + 'shouldNotMatch' => [ + '$.errors.password', + ], + ], + ]; + } + } diff --git a/tests/codeception/api/unit.suite.yml b/tests/codeception/api/unit.suite.yml index 7de7236..beea248 100644 --- a/tests/codeception/api/unit.suite.yml +++ b/tests/codeception/api/unit.suite.yml @@ -3,7 +3,6 @@ modules: enabled: - Yii2: part: [orm, email, fixtures] - - tests\codeception\common\_support\amqp\Helper - tests\codeception\common\_support\queue\CodeceptionQueueHelper - tests\codeception\common\_support\Mockery config: diff --git a/tests/codeception/api/unit/models/authentication/ConfirmEmailFormTest.php b/tests/codeception/api/unit/models/authentication/ConfirmEmailFormTest.php index 404b994..c392830 100644 --- a/tests/codeception/api/unit/models/authentication/ConfirmEmailFormTest.php +++ b/tests/codeception/api/unit/models/authentication/ConfirmEmailFormTest.php @@ -28,12 +28,6 @@ class ConfirmEmailFormTest extends TestCase { /** @var Account $account */ $account = Account::findOne($fixture['account_id']); $this->assertEquals(Account::STATUS_ACTIVE, $account->status, 'user status changed to active'); - - $message = $this->tester->grabLastSentAmqpMessage('events'); - $body = json_decode($message->getBody(), true); - $this->assertEquals($account->id, $body['accountId']); - $this->assertEquals($account->username, $body['newUsername']); - $this->assertNull($body['oldUsername']); } private function createModel($key) { diff --git a/tests/codeception/api/unit/modules/accounts/models/ChangeEmailFormTest.php b/tests/codeception/api/unit/modules/accounts/models/ChangeEmailFormTest.php index eb7f8f5..abf041d 100644 --- a/tests/codeception/api/unit/modules/accounts/models/ChangeEmailFormTest.php +++ b/tests/codeception/api/unit/modules/accounts/models/ChangeEmailFormTest.php @@ -32,19 +32,6 @@ class ChangeEmailFormTest extends TestCase { /** @noinspection UnserializeExploitsInspection */ $data = unserialize($newEmailConfirmationFixture['_data']); $this->assertEquals($data['newEmail'], $account->email); - $this->tester->canSeeAmqpMessageIsCreated('events'); - } - - public function testCreateTask() { - /** @var Account $account */ - $account = Account::findOne($this->getAccountId()); - $model = new ChangeEmailForm($account); - $model->createTask(1, 'test1@ely.by', 'test@ely.by'); - $message = $this->tester->grabLastSentAmqpMessage('events'); - $body = json_decode($message->getBody(), true); - $this->assertEquals(1, $body['accountId']); - $this->assertEquals('test1@ely.by', $body['newEmail']); - $this->assertEquals('test@ely.by', $body['oldEmail']); } private function getAccountId() { diff --git a/tests/codeception/api/unit/modules/accounts/models/ChangeUsernameFormTest.php b/tests/codeception/api/unit/modules/accounts/models/ChangeUsernameFormTest.php index 1931272..67d6db5 100644 --- a/tests/codeception/api/unit/modules/accounts/models/ChangeUsernameFormTest.php +++ b/tests/codeception/api/unit/modules/accounts/models/ChangeUsernameFormTest.php @@ -4,6 +4,7 @@ namespace tests\codeception\api\unit\modules\accounts\models; use api\modules\accounts\models\ChangeUsernameForm; use common\models\Account; use common\models\UsernameHistory; +use common\tasks\PullMojangUsername; use tests\codeception\api\unit\TestCase; use tests\codeception\common\fixtures\AccountFixture; use tests\codeception\common\fixtures\UsernameHistoryFixture; @@ -25,7 +26,10 @@ class ChangeUsernameFormTest extends TestCase { $this->assertTrue($model->performAction()); $this->assertEquals('my_new_nickname', Account::findOne($this->getAccountId())->username); $this->assertInstanceOf(UsernameHistory::class, UsernameHistory::findOne(['username' => 'my_new_nickname'])); - $this->tester->canSeeAmqpMessageIsCreated('events'); + /** @var PullMojangUsername $job */ + $job = $this->tester->grabLastQueuedJob(); + $this->assertInstanceOf(PullMojangUsername::class, $job); + $this->assertSame($job->username, 'my_new_nickname'); } public function testPerformActionWithTheSameUsername() { @@ -42,7 +46,7 @@ class ChangeUsernameFormTest extends TestCase { 'username' => $username, ['>=', 'applied_in', $callTime], ]), 'no new UsernameHistory record, if we don\'t change username'); - $this->tester->cantSeeAmqpMessageIsCreated('events'); + $this->assertNull($this->tester->grabLastQueuedJob()); } public function testPerformActionWithChangeCase() { @@ -58,17 +62,10 @@ class ChangeUsernameFormTest extends TestCase { UsernameHistory::findOne(['username' => $newUsername]), 'username should change, if we change case of some letters' ); - $this->tester->canSeeAmqpMessageIsCreated('events'); - } - - public function testCreateTask() { - $model = new ChangeUsernameForm($this->getAccount()); - $model->createEventTask(1, 'test1', 'test'); - $message = $this->tester->grabLastSentAmqpMessage('events'); - $body = json_decode($message->getBody(), true); - $this->assertEquals(1, $body['accountId']); - $this->assertEquals('test1', $body['newUsername']); - $this->assertEquals('test', $body['oldUsername']); + /** @var PullMojangUsername $job */ + $job = $this->tester->grabLastQueuedJob(); + $this->assertInstanceOf(PullMojangUsername::class, $job); + $this->assertSame($job->username, $newUsername); } private function getAccount(): Account { diff --git a/tests/codeception/api/unit/modules/internal/models/BanFormTest.php b/tests/codeception/api/unit/modules/internal/models/BanFormTest.php index 4cd3c02..3894f7f 100644 --- a/tests/codeception/api/unit/modules/internal/models/BanFormTest.php +++ b/tests/codeception/api/unit/modules/internal/models/BanFormTest.php @@ -4,6 +4,7 @@ namespace tests\codeception\api\unit\modules\internal\models; use api\modules\accounts\models\BanAccountForm; use api\modules\internal\helpers\Error as E; use common\models\Account; +use common\tasks\ClearAccountSessions; use tests\codeception\api\unit\TestCase; class BanFormTest extends TestCase { @@ -35,28 +36,10 @@ class BanFormTest extends TestCase { $model = new BanAccountForm($account); $this->assertTrue($model->performAction()); $this->assertEquals(Account::STATUS_BANNED, $account->status); - $this->tester->canSeeAmqpMessageIsCreated('events'); - } - - public function testCreateTask() { - $account = new Account(); - $account->id = 3; - - $model = new BanAccountForm($account); - $model->createTask(); - $message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true); - $this->assertSame(3, $message['accountId']); - $this->assertSame(-1, $message['duration']); - $this->assertSame('', $message['message']); - - $model = new BanAccountForm($account); - $model->duration = 123; - $model->message = 'test'; - $model->createTask(); - $message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true); - $this->assertSame(3, $message['accountId']); - $this->assertSame(123, $message['duration']); - $this->assertSame('test', $message['message']); + /** @var ClearAccountSessions $job */ + $job = $this->tester->grabLastQueuedJob(); + $this->assertInstanceOf(ClearAccountSessions::class, $job); + $this->assertSame($job->accountId, $account->id); } } diff --git a/tests/codeception/api/unit/modules/internal/models/PardonFormTest.php b/tests/codeception/api/unit/modules/internal/models/PardonFormTest.php index 1d6e2a7..362271f 100644 --- a/tests/codeception/api/unit/modules/internal/models/PardonFormTest.php +++ b/tests/codeception/api/unit/modules/internal/models/PardonFormTest.php @@ -36,17 +36,6 @@ class PardonFormTest extends TestCase { $model = new PardonAccountForm($account); $this->assertTrue($model->performAction()); $this->assertEquals(Account::STATUS_ACTIVE, $account->status); - $this->tester->canSeeAmqpMessageIsCreated('events'); - } - - public function testCreateTask() { - $account = new Account(); - $account->id = 3; - - $model = new PardonAccountForm($account); - $model->createTask(); - $message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true); - $this->assertSame(3, $message['accountId']); } } diff --git a/tests/codeception/common/_support/amqp/Helper.php b/tests/codeception/common/_support/amqp/Helper.php deleted file mode 100644 index e623646..0000000 --- a/tests/codeception/common/_support/amqp/Helper.php +++ /dev/null @@ -1,91 +0,0 @@ -seeAmqpMessageIsCreated(); - * - * // check that only 3 messages were created - * $I->seeAmqpMessageIsCreated(3); - * ``` - * - * @param string|null $exchange - * @param int|null $num - */ - public function seeAmqpMessageIsCreated($exchange = null, $num = null) { - if ($num === null) { - $this->assertNotEmpty($this->grabSentAmqpMessages($exchange), 'message were created'); - return; - } - - $this->assertCount( - $num, - $this->grabSentAmqpMessages($exchange), - 'number of created messages is equal to ' . $num - ); - } - - /** - * Checks that no messages was created - * - * @param string|null $exchange - */ - public function dontSeeAmqpMessageIsCreated($exchange = null) { - $this->seeAmqpMessageIsCreated($exchange, 0); - } - - /** - * Returns last sent message - * - * @param string|null $exchange - * @return \PhpAmqpLib\Message\AMQPMessage - */ - public function grabLastSentAmqpMessage($exchange = null) { - $this->seeAmqpMessageIsCreated(); - $messages = $this->grabSentAmqpMessages($exchange); - - return end($messages); - } - - /** - * Returns array of all sent amqp messages. - * Each message is `\PhpAmqpLib\Message\AMQPMessage` instance. - * Useful to perform additional checks using `Asserts` module. - * - * @param string|null $exchange - * @return \PhpAmqpLib\Message\AMQPMessage[] - * @throws ModuleException - */ - public function grabSentAmqpMessages($exchange = null) { - $amqp = $this->grabComponent('amqp'); - if (!$amqp instanceof TestComponent) { - throw new ModuleException($this, 'AMQP module is not mocked, can\'t test messages'); - } - - return $amqp->getSentMessages($exchange); - } - - private function grabComponent(string $component) { - return $this->getYii2()->grabComponent($component); - } - - private function getYii2(): Yii2 { - $yii2 = $this->getModule('Yii2'); - if (!$yii2 instanceof Yii2) { - throw new ModuleException($this, 'Yii2 module must be configured'); - } - - return $yii2; - } - -} diff --git a/tests/codeception/common/_support/amqp/TestComponent.php b/tests/codeception/common/_support/amqp/TestComponent.php deleted file mode 100644 index ed90730..0000000 --- a/tests/codeception/common/_support/amqp/TestComponent.php +++ /dev/null @@ -1,58 +0,0 @@ -sentMessages[$exchangeName][] = $this->prepareMessage($message); - } - - /** - * @param string|null $exchangeName - * @return \PhpAmqpLib\Message\AMQPMessage[] - */ - public function getSentMessages(string $exchangeName = null): array { - if ($exchangeName !== null) { - return $this->sentMessages[$exchangeName] ?? []; - } - - $messages = []; - foreach ($this->sentMessages as $exchangeGroup) { - foreach ($exchangeGroup as $message) { - $messages[] = $message; - } - } - - return $messages; - } - -} diff --git a/tests/codeception/common/_support/queue/CodeceptionQueueHelper.php b/tests/codeception/common/_support/queue/CodeceptionQueueHelper.php index 8878ea3..326e7f3 100644 --- a/tests/codeception/common/_support/queue/CodeceptionQueueHelper.php +++ b/tests/codeception/common/_support/queue/CodeceptionQueueHelper.php @@ -14,7 +14,12 @@ class CodeceptionQueueHelper extends Module { */ public function grabLastQueuedJob() { $messages = $this->grabQueueJobs(); - return end($messages); + $last = end($messages); + if ($last === false) { + return null; + } + + return $last; } /** diff --git a/tests/codeception/common/fixtures/WebHooksEventsFixture.php b/tests/codeception/common/fixtures/WebHooksEventsFixture.php new file mode 100644 index 0000000..300a7ea --- /dev/null +++ b/tests/codeception/common/fixtures/WebHooksEventsFixture.php @@ -0,0 +1,19 @@ + 1, + 'event_type' => 'account.edit', + ], + [ + 'webhook_id' => 2, + 'event_type' => 'account.edit', + ], +]; diff --git a/tests/codeception/common/fixtures/data/webhooks.php b/tests/codeception/common/fixtures/data/webhooks.php new file mode 100644 index 0000000..238c90a --- /dev/null +++ b/tests/codeception/common/fixtures/data/webhooks.php @@ -0,0 +1,21 @@ + [ + 'id' => 1, + 'url' => 'http://localhost:80/webhooks/ely', + 'secret' => 'my-secret', + 'created_at' => 1531054333, + ], + 'webhook-without-secret' => [ + 'id' => 2, + 'url' => 'http://localhost:81/webhooks/ely', + 'secret' => null, + 'created_at' => 1531054837, + ], + 'webhook-without-events' => [ + 'id' => 3, + 'url' => 'http://localhost:82/webhooks/ely', + 'secret' => null, + 'created_at' => 1531054990, + ], +]; diff --git a/tests/codeception/common/unit.suite.yml b/tests/codeception/common/unit.suite.yml index 11d4bb4..ac95de3 100644 --- a/tests/codeception/common/unit.suite.yml +++ b/tests/codeception/common/unit.suite.yml @@ -3,6 +3,7 @@ modules: enabled: - Yii2: part: [orm, email, fixtures] + - tests\codeception\common\_support\queue\CodeceptionQueueHelper - tests\codeception\common\_support\Mockery config: Yii2: diff --git a/tests/codeception/common/unit/fixtures/.gitkeep b/tests/codeception/common/unit/fixtures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/codeception/common/unit/fixtures/data/i18n/en.json b/tests/codeception/common/unit/fixtures/data/i18n/en.json deleted file mode 100644 index cacf5c2..0000000 --- a/tests/codeception/common/unit/fixtures/data/i18n/en.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "testString": "testValue" -} diff --git a/tests/codeception/common/unit/fixtures/data/i18n/ru.json b/tests/codeception/common/unit/fixtures/data/i18n/ru.json deleted file mode 100644 index 9734d39..0000000 --- a/tests/codeception/common/unit/fixtures/data/i18n/ru.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "testString": "тестовоеЗначение" -} diff --git a/tests/codeception/common/unit/models/AccountTest.php b/tests/codeception/common/unit/models/AccountTest.php index afb5de9..ab9b477 100644 --- a/tests/codeception/common/unit/models/AccountTest.php +++ b/tests/codeception/common/unit/models/AccountTest.php @@ -1,14 +1,20 @@ assertNull($account->getRegistrationIp()); } + public function testAfterSaveInsertEvent() { + $account = new Account(); + $account->afterSave(true, [ + 'username' => 'old-username', + ]); + $this->assertNull($this->tester->grabLastQueuedJob()); + } + + public function testAfterSaveNotMeaningfulAttributes() { + $account = new Account(); + $account->afterSave(false, [ + 'updatedAt' => time(), + ]); + $this->assertNull($this->tester->grabLastQueuedJob()); + } + + public function testAfterSavePushEvent() { + $changedAttributes = [ + 'username' => 'old-username', + 'email' => 'old-email@ely.by', + 'uuid' => 'c3cc0121-fa87-4818-9c0e-4acb7f9a28c5', + 'status' => 10, + 'lang' => 'en', + ]; + + $account = new Account(); + $account->afterSave(false, $changedAttributes); + /** @var CreateWebHooksDeliveries $job */ + $job = $this->tester->grabLastQueuedJob(); + $this->assertInstanceOf(CreateWebHooksDeliveries::class, $job); + $this->assertSame($job->payloads['changedAttributes'], $changedAttributes); + } + } diff --git a/tests/codeception/common/unit/tasks/ClearAccountSessionsTest.php b/tests/codeception/common/unit/tasks/ClearAccountSessionsTest.php new file mode 100644 index 0000000..af0e554 --- /dev/null +++ b/tests/codeception/common/unit/tasks/ClearAccountSessionsTest.php @@ -0,0 +1,44 @@ + fixtures\AccountFixture::class, + 'oauthSessions' => fixtures\OauthSessionFixture::class, + 'minecraftAccessKeys' => fixtures\MinecraftAccessKeyFixture::class, + 'authSessions' => fixtures\AccountSessionFixture::class, + ]; + } + + public function testCreateFromAccount() { + $account = new Account(); + $account->id = 123; + $task = ClearAccountSessions::createFromAccount($account); + $this->assertSame(123, $task->accountId); + } + + public function testExecute() { + /** @var \common\models\Account $bannedAccount */ + $bannedAccount = $this->tester->grabFixture('accounts', 'banned-account'); + $task = new ClearAccountSessions(); + $task->accountId = $bannedAccount->id; + $task->execute(mock(Queue::class)); + $this->assertEmpty($bannedAccount->sessions); + $this->assertEmpty($bannedAccount->minecraftAccessKeys); + $this->assertEmpty($bannedAccount->oauthSessions); + } + +} diff --git a/tests/codeception/common/unit/tasks/CreateWebHooksDeliveriesTest.php b/tests/codeception/common/unit/tasks/CreateWebHooksDeliveriesTest.php new file mode 100644 index 0000000..4596a51 --- /dev/null +++ b/tests/codeception/common/unit/tasks/CreateWebHooksDeliveriesTest.php @@ -0,0 +1,91 @@ + fixtures\WebHooksFixture::class, + 'webhooksEvents' => fixtures\WebHooksEventsFixture::class, + ]; + } + + public function testCreateAccountEdit() { + $account = new Account(); + $account->id = 123; + $account->username = 'mock-username'; + $account->uuid = 'afc8dc7a-4bbf-4d3a-8699-68890088cf84'; + $account->email = 'mock@ely.by'; + $account->lang = 'en'; + $account->status = Account::STATUS_ACTIVE; + $account->created_at = 1531008814; + $changedAttributes = [ + 'username' => 'old-username', + 'uuid' => 'e05d33e9-ff91-4d26-9f5c-8250f802a87a', + 'email' => 'old-email@ely.by', + 'status' => 0, + ]; + $result = CreateWebHooksDeliveries::createAccountEdit($account, $changedAttributes); + $this->assertInstanceOf(CreateWebHooksDeliveries::class, $result); + $this->assertSame('account.edit', $result->type); + $this->assertArraySubset([ + 'id' => 123, + 'uuid' => 'afc8dc7a-4bbf-4d3a-8699-68890088cf84', + 'username' => 'mock-username', + 'email' => 'mock@ely.by', + 'lang' => 'en', + 'isActive' => true, + 'registered' => '2018-07-08T00:13:34+00:00', + 'changedAttributes' => $changedAttributes, + ], $result->payloads); + } + + public function testExecute() { + $task = new CreateWebHooksDeliveries(); + $task->type = 'account.edit'; + $task->payloads = [ + 'id' => 123, + 'uuid' => 'afc8dc7a-4bbf-4d3a-8699-68890088cf84', + 'username' => 'mock-username', + 'email' => 'mock@ely.by', + 'lang' => 'en', + 'isActive' => true, + 'registered' => '2018-07-08T00:13:34+00:00', + 'changedAttributes' => [ + 'username' => 'old-username', + 'uuid' => 'e05d33e9-ff91-4d26-9f5c-8250f802a87a', + 'email' => 'old-email@ely.by', + 'status' => 0, + ], + ]; + $task->execute(mock(Queue::class)); + /** @var DeliveryWebHook[] $tasks */ + $tasks = $this->tester->grabQueueJobs(); + $this->assertCount(2, $tasks); + + $this->assertInstanceOf(DeliveryWebHook::class, $tasks[0]); + $this->assertSame($task->type, $tasks[0]->type); + $this->assertSame($task->payloads, $tasks[0]->payloads); + $this->assertSame('http://localhost:80/webhooks/ely', $tasks[0]->url); + $this->assertSame('my-secret', $tasks[0]->secret); + + $this->assertInstanceOf(DeliveryWebHook::class, $tasks[1]); + $this->assertSame($task->type, $tasks[1]->type); + $this->assertSame($task->payloads, $tasks[1]->payloads); + $this->assertSame('http://localhost:81/webhooks/ely', $tasks[1]->url); + $this->assertNull($tasks[1]->secret); + } + +} diff --git a/tests/codeception/common/unit/tasks/DeliveryWebHookTest.php b/tests/codeception/common/unit/tasks/DeliveryWebHookTest.php new file mode 100644 index 0000000..f798b60 --- /dev/null +++ b/tests/codeception/common/unit/tasks/DeliveryWebHookTest.php @@ -0,0 +1,133 @@ +assertFalse($task->canRetry(1, new \Exception())); + $request = new Request('POST', 'http://localhost'); + $this->assertTrue($task->canRetry(4, new ConnectException('', $request))); + $this->assertTrue($task->canRetry(4, new ServerException('', $request))); + $this->assertFalse($task->canRetry(5, new ConnectException('', $request))); + $this->assertFalse($task->canRetry(5, new ServerException('', $request))); + } + + public function testExecuteSuccessDelivery() { + $this->response = new Response(); + $task = $this->createMockedTask(); + $task->type = 'account.edit'; + $task->url = 'http://localhost:81/webhooks/ely'; + $task->payloads = [ + 'key' => 'value', + 'another' => 'value', + ]; + $task->execute(mock(Queue::class)); + /** @var Request $request */ + $request = $this->historyContainer[0]['request']; + $this->assertSame('http://localhost:81/webhooks/ely', (string)$request->getUri()); + $this->assertStringStartsWith('Account-Ely-Hookshot/', $request->getHeaders()['User-Agent'][0]); + $this->assertSame('account.edit', $request->getHeaders()['X-Ely-Accounts-Event'][0]); + $this->assertSame('application/x-www-form-urlencoded', $request->getHeaders()['Content-Type'][0]); + $this->assertArrayNotHasKey('X-Hub-Signature', $request->getHeaders()); + $this->assertEquals('key=value&another=value', (string)$request->getBody()); + } + + public function testExecuteSuccessDeliveryWithSignature() { + $this->response = new Response(); + $task = $this->createMockedTask(); + $task->type = 'account.edit'; + $task->url = 'http://localhost:81/webhooks/ely'; + $task->secret = 'secret'; + $task->payloads = [ + 'key' => 'value', + 'another' => 'value', + ]; + $task->execute(mock(Queue::class)); + /** @var Request $request */ + $request = $this->historyContainer[0]['request']; + $this->assertSame('http://localhost:81/webhooks/ely', (string)$request->getUri()); + $this->assertStringStartsWith('Account-Ely-Hookshot/', $request->getHeaders()['User-Agent'][0]); + $this->assertSame('account.edit', $request->getHeaders()['X-Ely-Accounts-Event'][0]); + $this->assertSame('application/x-www-form-urlencoded', $request->getHeaders()['Content-Type'][0]); + $this->assertSame('sha1=3c0b1eef564b2d3a5e9c0f2a8302b1b42b3d4784', $request->getHeaders()['X-Hub-Signature'][0]); + $this->assertEquals('key=value&another=value', (string)$request->getBody()); + } + + public function testExecuteHandleClientException() { + $this->response = new Response(403); + $task = $this->createMockedTask(); + $task->type = 'account.edit'; + $task->url = 'http://localhost:81/webhooks/ely'; + $task->secret = 'secret'; + $task->payloads = [ + 'key' => 'value', + 'another' => 'value', + ]; + $task->execute(mock(Queue::class)); + } + + /** + * @expectedException \GuzzleHttp\Exception\ServerException + */ + public function testExecuteUnhandledException() { + $this->response = new Response(502); + $task = $this->createMockedTask(); + $task->type = 'account.edit'; + $task->url = 'http://localhost:81/webhooks/ely'; + $task->secret = 'secret'; + $task->payloads = [ + 'key' => 'value', + 'another' => 'value', + ]; + $task->execute(mock(Queue::class)); + } + + private function createMockedTask(): DeliveryWebHook { + $container = &$this->historyContainer; + $response = $this->response; + + return new class($container, $response) extends DeliveryWebHook { + private $historyContainer; + + private $response; + + public function __construct(array &$historyContainer, $response) { + $this->historyContainer = &$historyContainer; + $this->response = $response; + } + + protected function createStack(): HandlerStack { + $stack = parent::createStack(); + $stack->setHandler(new MockHandler([$this->response])); + $stack->push(Middleware::history($this->historyContainer)); + + return $stack; + } + }; + } + +} diff --git a/tests/codeception/console/unit/controllers/AccountQueueControllerTest.php b/tests/codeception/common/unit/tasks/PullMojangUsernameTest.php similarity index 50% rename from tests/codeception/console/unit/controllers/AccountQueueControllerTest.php rename to tests/codeception/common/unit/tasks/PullMojangUsernameTest.php index 0fbe3fe..cac50b4 100644 --- a/tests/codeception/console/unit/controllers/AccountQueueControllerTest.php +++ b/tests/codeception/common/unit/tasks/PullMojangUsernameTest.php @@ -1,30 +1,32 @@ AccountFixture::class, 'mojangUsernames' => MojangUsernameFixture::class, ]; } @@ -32,10 +34,9 @@ class AccountQueueControllerTest extends TestCase { public function _before() { parent::_before(); - /** @var AccountQueueController|\PHPUnit_Framework_MockObject_MockObject $controller */ - $controller = $this->getMockBuilder(AccountQueueController::class) + /** @var PullMojangUsername|\PHPUnit_Framework_MockObject_MockObject $task */ + $task = $this->getMockBuilder(PullMojangUsername::class) ->setMethods(['createMojangApi']) - ->setConstructorArgs(['account-queue', Yii::$app]) ->getMock(); /** @var Api|\PHPUnit_Framework_MockObject_MockObject $apiMock */ @@ -54,30 +55,31 @@ class AccountQueueControllerTest extends TestCase { return $this->expectedResponse; }); - $controller + $task ->expects($this->any()) ->method('createMojangApi') ->willReturn($apiMock); - $this->controller = $controller; + $this->task = $task; } - public function testRouteUsernameChangedUsernameExists() { + public function testCreateFromAccount() { + $account = new Account(); + $account->username = 'find-me'; + $result = PullMojangUsername::createFromAccount($account); + $this->assertSame('find-me', $result->username); + } + + public function testExecuteUsernameExists() { $expectedResponse = new UsernameToUUIDResponse(); $expectedResponse->id = '069a79f444e94726a5befca90e38aaf5'; $expectedResponse->name = 'Notch'; $this->expectedResponse = $expectedResponse; - /** @var \common\models\Account $accountInfo */ - $accountInfo = $this->tester->grabFixture('accounts', 'admin'); - /** @var MojangUsername $mojangUsernameFixture */ + /** @var \common\models\MojangUsername $mojangUsernameFixture */ $mojangUsernameFixture = $this->tester->grabFixture('mojangUsernames', 'Notch'); - $body = new UsernameChanged([ - 'accountId' => $accountInfo->id, - 'oldUsername' => $accountInfo->username, - 'newUsername' => 'Notch', - ]); - $this->controller->routeUsernameChanged($body); + $this->task->username = 'Notch'; + $this->task->execute(mock(Queue::class)); /** @var MojangUsername|null $mojangUsername */ $mojangUsername = MojangUsername::findOne('Notch'); $this->assertInstanceOf(MojangUsername::class, $mojangUsername); @@ -85,81 +87,62 @@ class AccountQueueControllerTest extends TestCase { $this->assertLessThanOrEqual(time(), $mojangUsername->last_pulled_at); } - public function testRouteUsernameChangedUsernameNotExists() { + public function testExecuteChangedUsernameExists() { + $expectedResponse = new UsernameToUUIDResponse(); + $expectedResponse->id = '069a79f444e94726a5befca90e38aaf5'; + $expectedResponse->name = 'Notch'; + $this->expectedResponse = $expectedResponse; + + /** @var MojangUsername $mojangUsernameFixture */ + $mojangUsernameFixture = $this->tester->grabFixture('mojangUsernames', 'Notch'); + $this->task->username = 'Notch'; + $this->task->execute(mock(Queue::class)); + /** @var MojangUsername|null $mojangUsername */ + $mojangUsername = MojangUsername::findOne('Notch'); + $this->assertInstanceOf(MojangUsername::class, $mojangUsername); + $this->assertGreaterThan($mojangUsernameFixture->last_pulled_at, $mojangUsername->last_pulled_at); + $this->assertLessThanOrEqual(time(), $mojangUsername->last_pulled_at); + } + + public function testExecuteChangedUsernameNotExists() { $expectedResponse = new UsernameToUUIDResponse(); $expectedResponse->id = '607153852b8c4909811f507ed8ee737f'; $expectedResponse->name = 'Chest'; $this->expectedResponse = $expectedResponse; - /** @var \common\models\Account $accountInfo */ - $accountInfo = $this->tester->grabFixture('accounts', 'admin'); - $body = new UsernameChanged([ - 'accountId' => $accountInfo['id'], - 'oldUsername' => $accountInfo['username'], - 'newUsername' => 'Chest', - ]); - $this->controller->routeUsernameChanged($body); + $this->task->username = 'Chest'; + $this->task->execute(mock(Queue::class)); /** @var MojangUsername|null $mojangUsername */ $mojangUsername = MojangUsername::findOne('Chest'); $this->assertInstanceOf(MojangUsername::class, $mojangUsername); } - public function testRouteUsernameChangedRemoveIfExistsNoMore() { + public function testExecuteRemoveIfExistsNoMore() { $this->expectedResponse = false; - /** @var \common\models\Account $accountInfo */ - $accountInfo = $this->tester->grabFixture('accounts', 'admin'); $username = $this->tester->grabFixture('mojangUsernames', 'not-exists')['username']; - $body = new UsernameChanged([ - 'accountId' => $accountInfo['id'], - 'oldUsername' => $accountInfo['username'], - 'newUsername' => $username, - ]); - $this->controller->routeUsernameChanged($body); + $this->task->username = $username; + $this->task->execute(mock(Queue::class)); /** @var MojangUsername|null $mojangUsername */ $mojangUsername = MojangUsername::findOne($username); $this->assertNull($mojangUsername); } - public function testRouteUsernameChangedUuidUpdated() { + public function testExecuteUuidUpdated() { $expectedResponse = new UsernameToUUIDResponse(); $expectedResponse->id = 'f498513ce8c84773be26ecfc7ed5185d'; $expectedResponse->name = 'jeb'; $this->expectedResponse = $expectedResponse; - /** @var \common\models\Account $accountInfo */ - $accountInfo = $this->tester->grabFixture('accounts', 'admin'); /** @var MojangUsername $mojangInfo */ $mojangInfo = $this->tester->grabFixture('mojangUsernames', 'uuid-changed'); $username = $mojangInfo['username']; - $body = new UsernameChanged([ - 'accountId' => $accountInfo['id'], - 'oldUsername' => $accountInfo['username'], - 'newUsername' => $username, - ]); - $this->controller->routeUsernameChanged($body); + $this->task->username = $username; + $this->task->execute(mock(Queue::class)); /** @var MojangUsername|null $mojangUsername */ $mojangUsername = MojangUsername::findOne($username); $this->assertInstanceOf(MojangUsername::class, $mojangUsername); $this->assertNotEquals($mojangInfo->uuid, $mojangUsername->uuid); } - public function testRouteAccountBanned() { - /** @var \common\models\Account $bannedAccount */ - $bannedAccount = $this->tester->grabFixture('accounts', 'banned-account'); - $this->tester->haveFixtures([ - 'oauthSessions' => \tests\codeception\common\fixtures\OauthSessionFixture::class, - 'minecraftAccessKeys' => \tests\codeception\common\fixtures\MinecraftAccessKeyFixture::class, - 'authSessions' => \tests\codeception\common\fixtures\AccountSessionFixture::class, - ]); - - $body = new AccountBanned(); - $body->accountId = $bannedAccount->id; - - $this->controller->routeAccountBanned($body); - $this->assertEmpty($bannedAccount->sessions); - $this->assertEmpty($bannedAccount->minecraftAccessKeys); - $this->assertEmpty($bannedAccount->oauthSessions); - } - } diff --git a/tests/codeception/common/unit/validators/LanguageValidatorTest.php b/tests/codeception/common/unit/validators/LanguageValidatorTest.php index e40e72c..e6d077e 100644 --- a/tests/codeception/common/unit/validators/LanguageValidatorTest.php +++ b/tests/codeception/common/unit/validators/LanguageValidatorTest.php @@ -1,39 +1,50 @@ createModelWithFixturePath(); - $this->assertEquals(['en', 'ru'], $this->callProtected($model, 'getFilesNames')); - } - - public function testValidateValueSupportedLanguage() { - $model = $this->createModelWithFixturePath(); - $this->assertNull($this->callProtected($model, 'validateValue', 'ru')); - } - - public function testValidateNotSupportedLanguage() { - $model = $this->createModelWithFixturePath(); - $this->assertEquals([$model->message, []], $this->callProtected($model, 'validateValue', 'by')); - } /** - * @return LanguageValidator + * @param string $locale + * @param bool $shouldBeValid + * + * @dataProvider getTestCases */ - private function createModelWithFixturePath() { - return new class extends LanguageValidator { - public function getFolderPath() { - return __DIR__ . '/../fixtures/data/i18n'; - } - }; + public function testValidate(string $locale, bool $shouldBeValid): void { + $validator = new LanguageValidator(); + $result = $validator->validate($locale, $error); + $this->assertSame($shouldBeValid, $result, $locale); + if (!$shouldBeValid) { + $this->assertSame($validator->message, $error); + } + } + + public function getTestCases(): array { + return [ + // valid + ['de', true], + ['de_DE', true], + ['deu', true], + ['en', true], + ['en_US', true], + ['fil', true], + ['fil_PH', true], + ['zh', true], + ['zh_Hans_CN', true], + ['zh_Hant_HK', true], + // invalid + ['de_FR', false], + ['fr_US', false], + ['foo_bar', false], + ['foo_bar_baz', false], + ]; } } diff --git a/tests/codeception/config/config.php b/tests/codeception/config/config.php index 78b097c..72c5fa3 100644 --- a/tests/codeception/config/config.php +++ b/tests/codeception/config/config.php @@ -20,9 +20,6 @@ return [ // Для тестов нам не сильно важна безопасность, а вот время прохождения тестов значительно сокращается 'passwordHashCost' => 4, ], - 'amqp' => [ - 'class' => tests\codeception\common\_support\amqp\TestComponent::class, - ], 'queue' => [ 'class' => tests\codeception\common\_support\queue\Queue::class, ], diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 42c486d..5a8fb5b 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -2,10 +2,11 @@ version: '2' services: testphp: container_name: accountelyby_testphp - image: account_testphp + image: registry.ely.by/elyby/accounts:dev build: context: ../ - dockerfile: Dockerfile-dev + args: + build_env: dev depends_on: - testdb - testredis diff --git a/tests/php.sh b/tests/php.sh deleted file mode 100755 index c6a53a2..0000000 --- a/tests/php.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname "$0")" - -./../vendor/bin/codecept build -./../vendor/bin/codecept run $* diff --git a/tests/run-tests.sh b/tests/run-tests.sh deleted file mode 100755 index 7ff68f2..0000000 --- a/tests/run-tests.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname "$0")" - -docker-compose run --rm testphp ./tests/php.sh $* -docker-compose stop # docker не останавливает зависимые контейнеры после завершения работы главного процесса