Browse Source

init-repo

set-sast-config-1
Ilya Fedorov 4 years ago
parent
commit
fb43d81ffb
  1. 10
      .editorconfig
  2. 7
      .gitlab-ci.yml
  3. 19
      LICENSE
  4. 18
      Makefile
  5. 3
      README.md
  6. 6
      app/.env.test
  7. 3
      app/.gitignore
  8. 13
      app/.php-cs-fixer.php
  9. 17
      app/bin/console
  10. 19
      app/bin/phpunit
  11. 127
      app/composer.json
  12. 7816
      app/composer.lock
  13. 9
      app/config/bundles.php
  14. 4
      app/config/packages/cache.yaml
  15. 8
      app/config/packages/dev/web_profiler.yaml
  16. 20
      app/config/packages/framework.yaml
  17. 17
      app/config/packages/nelmio_api_doc.yaml
  18. 10
      app/config/packages/routing.yaml
  19. 8
      app/config/packages/test/web_profiler.yaml
  20. 8
      app/config/packages/twig.yaml
  21. 5
      app/config/preload.php
  22. 6
      app/config/routes.yaml
  23. 9
      app/config/routes/annotations.yaml
  24. 9
      app/config/routes/dev/web_profiler.yaml
  25. 6
      app/config/routes/framework.yaml
  26. 11
      app/config/routes/nelmio_api_doc.yaml
  27. 29
      app/config/services.yaml
  28. 35
      app/phpunit.xml.dist
  29. 1
      app/public/bundles/.gitignore
  30. 9
      app/public/index.php
  31. 56
      app/src/Controller/Api/v1/MattermostController.php
  32. 38
      app/src/Kernel.php
  33. 15
      app/src/Service/BaseService.php
  34. 55
      app/src/Service/Mattermost/MattermostService.php
  35. 12
      app/src/Service/Mattermost/MattermostServiceInterface.php
  36. 433
      app/symfony.lock
  37. 19
      app/templates/base.html.twig
  38. 19
      app/tests/Unit/Controller/Api/v1/MattermostControllerTest.php
  39. 19
      app/tests/Unit/KernelTest.php
  40. 102
      app/tests/Unit/Service/Mattermost/MattermostServiceTest.php
  41. 27
      app/tests/Unit/UnitTester.php
  42. 2
      app/tests/_coverage/.gitignore
  43. 11
      app/tests/bootstrap.php
  44. 2
      app/var/cache/.gitignore
  45. 2
      app/var/log/.gitignore
  46. 2
      app/var/php-cs-fixer/.gitignore
  47. 2
      app/var/sessions/.gitignore
  48. 2
      app/vendor/.gitignore
  49. 27
      devops/docker/nginx/etc/nginx/conf.d/default.conf
  50. 36
      devops/docker/php/Dockerfile
  51. 9
      devops/docker/php/xdebug.ini
  52. 22
      devops/gitlab/merge_requests/build/1_build.yml
  53. 19
      devops/gitlab/release/1_release-tag.yml
  54. 19
      devops/gitlab/release/2_deploy.yml
  55. 35
      docker-compose-local.yml
  56. 27
      docker-compose.yml
  57. 1
      env/.gitignore
  58. 8
      env/app/app.env-dist

10
.editorconfig

@ -0,0 +1,10 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

7
.gitlab-ci.yml

@ -0,0 +1,7 @@
---
include:
- project: infra/kernel/ci-templates
ref: master
file: /${CI_PROJECT_PATH}.yml
- local: /devops/gitlab/merge_requests/build/1_build.yml
...

19
LICENSE

@ -0,0 +1,19 @@
MIT License Copyright (c) 2021 fedy95
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

18
Makefile

@ -0,0 +1,18 @@
MAKEFLAGS += --silent
.PHONY: *
restart-local:
docker-compose -f docker-compose-local.yml pull
docker-compose -f docker-compose-local.yml down
docker-compose -f docker-compose-local.yml up -d
restart:
docker-compose -f docker-compose.yml pull
docker-compose -f docker-compose.yml down
docker-compose -f docker-compose.yml up -d
cleanup:
docker system prune --all --force
docker system prune --volumes --force
.DEFAULT_GOAL := lint

3
README.md

@ -1,2 +1 @@
# notification-provider
### notification-provider

6
app/.env.test

@ -0,0 +1,6 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots

3
app/.gitignore

@ -0,0 +1,3 @@
/.env
/.phpunit.result.cache
/phpunit.xml

13
app/.php-cs-fixer.php

@ -0,0 +1,13 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude('var')
;
return (new PhpCsFixer\Config())->setRules([
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
])
->setFinder($finder)
;

17
app/bin/console

@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

19
app/bin/phpunit

@ -0,0 +1,19 @@
#!/usr/bin/env php
<?php
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
}

127
app/composer.json

@ -0,0 +1,127 @@
{
"name": "dev/notification-provider",
"type": "project",
"description": "notification-provider",
"license": "MIT",
"require": {
"php": "8.0.*",
"ext-ctype": "8.0.*",
"ext-iconv": "8.0.*",
"doctrine/annotations": "^1.13",
"guzzlehttp/guzzle": "^7.3",
"nelmio/api-doc-bundle": "^4.6",
"symfony/asset": "5.3.*",
"symfony/console": "5.3.*",
"symfony/dotenv": "5.3.*",
"symfony/flex": "^1.16",
"symfony/framework-bundle": "5.3.*",
"symfony/runtime": "5.3.*",
"symfony/twig-bundle": "5.3.*",
"symfony/yaml": "5.3.*",
"twig/extra-bundle": "^2.12 || ^3.0",
"twig/twig": "^2.12 || ^3.0"
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*"
},
"conflict": {
"symfony/symfony": "*"
},
"require-dev": {
"ext-xdebug": "3.*",
"ergebnis/composer-normalize": "^2.13",
"fakerphp/faker": "^1.0",
"friendsofphp/php-cs-fixer": "^3.1",
"php-parallel-lint/php-parallel-lint": "1.3.*",
"phpunit/phpunit": "^9.5",
"roave/security-advisories": "dev-latest",
"symfony/browser-kit": "5.3.*",
"symfony/css-selector": "5.3.*",
"symfony/phpunit-bridge": "^5.3",
"symfony/stopwatch": "5.3.*",
"symfony/web-profiler-bundle": "5.3.*"
},
"config": {
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "5.3.*"
}
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"scripts": {
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
],
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"json-cs-fix": "composer normalize",
"lint:php": [
"parallel-lint --no-progress --no-colors --blame ./bin/console",
"parallel-lint --no-progress --no-colors --blame ./config/bundles.php",
"parallel-lint --no-progress --no-colors --blame ./config/preload.php",
"parallel-lint --no-progress --no-colors --blame ./public/index.php",
"parallel-lint --no-progress --no-colors --blame ./src",
"parallel-lint --no-progress --no-colors --blame ./tests/bootstrap.php",
"parallel-lint --no-progress --no-colors --blame .php-cs-fixer.php"
],
"lint:yaml": [
"bin/console --quiet --no-debug l:yaml ./config/packages",
"bin/console --quiet --no-debug l:yaml ./config/routes",
"bin/console --quiet --no-debug l:yaml ./config/routes.yaml",
"bin/console --quiet --no-debug l:yaml ./config/services.yaml"
],
"php-cs-check": [
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache bin/console",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache config/bundles.php",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache config/preload.php",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache public/index.php",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache src",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache tests/bootstrap.php",
"php vendor/bin/php-cs-fixer fix --dry-run --cache-file=var/php-cs-fixer/.php-cs.cache .php-cs-fixer.php"
],
"php-cs-fix": [
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache bin/console",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache config/bundles.php",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache config/preload.php",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache public/index.php",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache src",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache tests/bootstrap.php",
"php vendor/bin/php-cs-fixer fix --cache-file=var/php-cs-fixer/.php-cs.cache .php-cs-fixer.php"
],
"test": [
"@php ./vendor/bin/phpunit --coverage-html tests/_coverage --coverage-text"
],
"test:unit": [
"@php ./vendor/bin/phpunit --coverage-html tests/_coverage --coverage-text --colors=never"
],
"validate:composer": {
"check:platform": "@composer check-platform-reqs",
"validate": "@composer validate --strict"
}
}
}

7816
app/composer.lock
File diff suppressed because it is too large
View File

9
app/config/bundles.php

@ -0,0 +1,9 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
];

4
app/config/packages/cache.yaml

@ -0,0 +1,4 @@
---
framework:
cache:
...

8
app/config/packages/dev/web_profiler.yaml

@ -0,0 +1,8 @@
---
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler: { only_exceptions: false }
...

20
app/config/packages/framework.yaml

@ -0,0 +1,20 @@
---
framework:
secret: '%env(APP_SECRET)%'
http_method_override: false
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
php_errors:
log: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
...

17
app/config/packages/nelmio_api_doc.yaml

@ -0,0 +1,17 @@
---
nelmio_api_doc:
documentation:
servers:
- url: http://127.0.0.1:8054
description: localhost API over HTTP
- url: https://notification-provider.fedy95.com
description: server API over HTTPS
info:
title: notification-provider
description: notification-provider api doc
version: 0.0.1
areas:
default:
path_patterns:
- ^/api/v1
...

10
app/config/packages/routing.yaml

@ -0,0 +1,10 @@
---
framework:
router:
utf8: true
when@prod:
framework:
router:
strict_requirements: null
...

8
app/config/packages/test/web_profiler.yaml

@ -0,0 +1,8 @@
---
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }
...

8
app/config/packages/twig.yaml

@ -0,0 +1,8 @@
---
twig:
default_path: '%kernel.project_dir%/templates'
when@test:
twig:
strict_variables: true
...

5
app/config/preload.php

@ -0,0 +1,5 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
}

6
app/config/routes.yaml

@ -0,0 +1,6 @@
---
app.swagger_ui:
path: /api/doc/{area}
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui, area: default }
...

9
app/config/routes/annotations.yaml

@ -0,0 +1,9 @@
---
controllers:
resource: ../../src/Controller/
type: annotation
kernel:
resource: ../../src/Kernel.php
type: annotation
...

9
app/config/routes/dev/web_profiler.yaml

@ -0,0 +1,9 @@
---
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler
...

6
app/config/routes/framework.yaml

@ -0,0 +1,6 @@
---
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error
...

11
app/config/routes/nelmio_api_doc.yaml

@ -0,0 +1,11 @@
---
app.swagger:
path: /api/doc.json
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger }
app.swagger_ui:
path: /api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
...

29
app/config/services.yaml

@ -0,0 +1,29 @@
---
parameters:
app.mattermost.url: '%env(resolve:MATTERMOST_URL)%'
app.mattermost.uri: '%env(resolve:MATTERMOST_URI)%'
app.mattermost.channel_name: '%env(resolve:MATTERMOST_CHANNEL_NAME)%'
app.mattermost.bot.name: '%env(resolve:MATTERMOST_BOT_NAME)%'
app.mattermost.bot.icon: '%env(resolve:MATTERMOST_BOT_ICON)%'
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/Tests/'
App\Service\Mattermost\MattermostService:
arguments:
$mattermostUrl: '%app.mattermost.url%'
$mattermostUri: '%app.mattermost.uri%'
$channelName: '%app.mattermost.channel_name%'
$botName: '%app.mattermost.bot.name%'
$botIcon: '%app.mattermost.bot.icon%'
...

35
app/phpunit.xml.dist

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
convertDeprecationsToExceptions="false"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
</phpunit>

1
app/public/bundles/.gitignore

@ -0,0 +1 @@
/nelmioapidoc

9
app/public/index.php

@ -0,0 +1,9 @@
<?php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

56
app/src/Controller/Api/v1/MattermostController.php

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\v1;
use App\Service\Mattermost\MattermostServiceInterface;
use OpenApi\Annotations as OA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Throwable;
class MattermostController extends AbstractController
{
protected MattermostServiceInterface $mattermostService;
public function __construct(MattermostServiceInterface $mattermostService)
{
$this->mattermostService = $mattermostService;
}
/**
* Send message to a mattermost chat.
*
* Docs https://docs.mattermost.com/developer/webhooks-incoming.html
*
* @Route("/api/v1/send_message", methods={"POST"})
* @OA\Tag(name="mattermost")
* @OA\Parameter(
* name="message",
* in="query",
* required=true,
* @OA\Schema(type="string")
* )
* @OA\Response(
* response=200,
* description="Success delivery"
* )
*/
public function sendMessage(Request $request): Response
{
try {
$message = $request->query->get('message');
$response = $this->mattermostService->sendMessage($message);
return new Response($response->getBody()->getContents());
} catch (Throwable $e) {
return new Response(
$e->getMessage(),
0 === $e->getCode() ? Response::HTTP_INTERNAL_SERVER_ERROR : $e->getCode()
);
}
}
}

38
app/src/Kernel.php

@ -0,0 +1,38 @@
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
protected function configureContainer(ContainerConfigurator $container): void
{
$container->import('../config/{packages}/*.yaml');
$container->import('../config/{packages}/'.$this->environment.'/*.yaml');
if (is_file(\dirname(__DIR__).'/config/services.yaml')) {
$container->import('../config/services.yaml');
$container->import('../config/{services}_'.$this->environment.'.yaml');
} else {
$container->import('../config/{services}.php');
}
}
protected function configureRoutes(RoutingConfigurator $routes): void
{
$routes->import('../config/{routes}/'.$this->environment.'/*.yaml');
$routes->import('../config/{routes}/*.yaml');
if (is_file(\dirname(__DIR__).'/config/routes.yaml')) {
$routes->import('../config/routes.yaml');
} else {
$routes->import('../config/{routes}.php');
}
}
}

15
app/src/Service/BaseService.php

@ -0,0 +1,15 @@
<?php
namespace App\Service;
use GuzzleHttp\Client;
abstract class BaseService
{
protected Client $client;
public function __construct(string $baseUri)
{
$this->client = new Client(['base_uri' => $baseUri]);
}
}

55
app/src/Service/Mattermost/MattermostService.php

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace App\Service\Mattermost;
use App\Service\BaseService;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\ResponseInterface;
class MattermostService extends BaseService implements MattermostServiceInterface
{
protected string $mattermostUri;
protected string $channelName;
protected string $botName;
protected string $botIcon;
public function __construct(
string $mattermostUrl,
string $mattermostUri,
string $channelName,
string $botName,
string $botIcon
) {
parent::__construct($mattermostUrl);
$this->mattermostUri = $mattermostUri;
$this->channelName = $channelName;
$this->botName = $botName;
$this->botIcon = $botIcon;
}
/**
* @throws GuzzleException
* @throws \JsonException
*/
public function sendMessage(string $message): ResponseInterface
{
$request = new Request('POST', $this->mattermostUri);
$options = [
'headers' => [
'Content-Type' => 'application/json',
],
'body' => json_encode([
'channel' => $this->channelName,
'username' => $this->botName,
'icon_url' => $this->botIcon,
'text' => $message,
], JSON_THROW_ON_ERROR),
];
return $this->client->send($request, $options);
}
}

12
app/src/Service/Mattermost/MattermostServiceInterface.php

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Service\Mattermost;
use Psr\Http\Message\ResponseInterface;
interface MattermostServiceInterface
{
public function sendMessage(string $message): ResponseInterface;
}

433
app/symfony.lock

@ -0,0 +1,433 @@
{
"composer/semver": {
"version": "3.2.5"
},
"composer/xdebug-handler": {
"version": "2.0.2"
},
"doctrine/annotations": {
"version": "1.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.0",
"ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
},
"files": [
"config/routes/annotations.yaml"
]
},
"doctrine/instantiator": {
"version": "1.4.0"
},
"doctrine/lexer": {
"version": "1.2.1"
},
"ergebnis/composer-normalize": {
"version": "2.13.4"
},
"ergebnis/json-normalizer": {
"version": "1.0.3"
},
"ergebnis/json-printer": {
"version": "3.1.1"
},
"fakerphp/faker": {
"version": "v1.16.0"
},
"friendsofphp/php-cs-fixer": {
"version": "3.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "3.0",
"ref": "be2103eb4a20942e28a6dd87736669b757132435"
},
"files": [
".php-cs-fixer.dist.php"
]
},
"guzzlehttp/guzzle": {
"version": "7.3.0"
},
"guzzlehttp/promises": {
"version": "1.4.1"
},
"guzzlehttp/psr7": {
"version": "2.0.0"
},
"justinrainbow/json-schema": {
"version": "5.2.11"
},
"localheinz/diff": {
"version": "1.1.1"
},
"myclabs/deep-copy": {
"version": "1.10.2"
},
"nelmio/api-doc-bundle": {
"version": "3.0",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "master",
"version": "3.0",
"ref": "c8e0c38e1a280ab9e37587a8fa32b251d5bc1c94"
},
"files": [
"config/packages/nelmio_api_doc.yaml",
"config/routes/nelmio_api_doc.yaml"
]
},
"nikic/php-parser": {
"version": "v4.13.0"
},
"phar-io/manifest": {
"version": "2.0.3"
},
"phar-io/version": {
"version": "3.1.0"
},
"php-cs-fixer/diff": {
"version": "v2.0.2"
},
"php-parallel-lint/php-parallel-lint": {
"version": "v1.2.0"
},
"phpdocumentor/reflection-common": {
"version": "2.2.0"
},
"phpdocumentor/reflection-docblock": {
"version": "5.2.2"
},
"phpdocumentor/type-resolver": {
"version": "1.5.0"
},
"phpspec/prophecy": {
"version": "1.14.0"
},
"phpunit/php-code-coverage": {
"version": "9.2.7"
},
"phpunit/php-file-iterator": {
"version": "3.0.5"
},
"phpunit/php-invoker": {
"version": "3.1.1"
},
"phpunit/php-text-template": {
"version": "2.0.4"
},
"phpunit/php-timer": {
"version": "5.0.3"
},
"phpunit/phpunit": {
"version": "9.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "9.3",
"ref": "a6249a6c4392e9169b87abf93225f7f9f59025e6"
},
"files": [
".env.test",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"psr/cache": {
"version": "2.0.0"
},
"psr/container": {
"version": "1.1.1"
},
"psr/event-dispatcher": {
"version": "1.0.0"
},
"psr/http-client": {
"version": "1.0.1"
},
"psr/http-factory": {
"version": "1.0.1"
},
"psr/http-message": {
"version": "1.0.1"
},
"psr/log": {
"version": "2.0.0"
},
"ralouphie/getallheaders": {
"version": "3.0.3"
},
"roave/security-advisories": {
"version": "dev-latest"
},
"sebastian/cli-parser": {
"version": "1.0.1"
},
"sebastian/code-unit": {
"version": "1.0.8"
},
"sebastian/code-unit-reverse-lookup": {
"version": "2.0.3"
},
"sebastian/comparator": {
"version": "4.0.6"
},
"sebastian/complexity": {
"version": "2.0.2"
},
"sebastian/diff": {
"version": "4.0.4"
},
"sebastian/environment": {
"version": "5.1.3"
},
"sebastian/exporter": {
"version": "4.0.3"
},
"sebastian/global-state": {
"version": "5.0.3"
},
"sebastian/lines-of-code": {
"version": "1.0.3"
},
"sebastian/object-enumerator": {
"version": "4.0.4"
},
"sebastian/object-reflector": {
"version": "2.0.4"
},
"sebastian/recursion-context": {
"version": "4.0.4"
},
"sebastian/resource-operations": {
"version": "3.0.3"
},
"sebastian/type": {
"version": "2.3.4"
},
"sebastian/version": {
"version": "3.0.2"
},
"symfony/asset": {
"version": "v5.3.4"
},
"symfony/browser-kit": {
"version": "v5.3.4"
},
"symfony/cache": {
"version": "v5.3.7"
},
"symfony/cache-contracts": {
"version": "v2.4.0"
},
"symfony/config": {
"version": "v5.3.4"
},
"symfony/console": {
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"
]
},
"symfony/css-selector": {
"version": "v5.3.4"
},
"symfony/dependency-injection": {
"version": "v5.3.7"
},
"symfony/deprecation-contracts": {
"version": "v2.4.0"
},
"symfony/dom-crawler": {
"version": "v5.3.7"
},
"symfony/dotenv": {
"version": "v5.3.7"
},
"symfony/error-handler": {
"version": "v5.3.7"
},
"symfony/event-dispatcher": {
"version": "v5.3.7"
},
"symfony/event-dispatcher-contracts": {
"version": "v2.4.0"
},
"symfony/filesystem": {
"version": "v5.3.4"
},
"symfony/finder": {
"version": "v5.3.7"
},
"symfony/flex": {
"version": "1.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.0",
"ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e"
},
"files": [
".env"
]
},
"symfony/framework-bundle": {
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.3",
"ref": "414ba00ad43fa71be42c7906a551f1831716b03c"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php"
]
},
"symfony/http-client-contracts": {
"version": "v2.4.0"
},
"symfony/http-foundation": {
"version": "v5.3.7"
},
"symfony/http-kernel": {
"version": "v5.3.7"
},
"symfony/options-resolver": {
"version": "v5.3.7"
},
"symfony/phpunit-bridge": {
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.3",
"ref": "97cb3dc7b0f39c7cfc4b7553504c9d7b7795de96"
},
"files": [
".env.test",
"bin/phpunit",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"symfony/polyfill-intl-grapheme": {
"version": "v1.23.1"
},
"symfony/polyfill-intl-normalizer": {
"version": "v1.23.0"
},
"symfony/polyfill-mbstring": {
"version": "v1.23.1"
},
"symfony/polyfill-php73": {
"version": "v1.23.0"
},
"symfony/polyfill-php80": {
"version": "v1.23.1"
},
"symfony/polyfill-php81": {
"version": "v1.23.0"
},
"symfony/process": {
"version": "v5.3.7"
},
"symfony/property-info": {
"version": "v5.3.7"
},
"symfony/routing": {
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.3",
"ref": "44633353926a0382d7dfb0530922c5c0b30fae11"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
},
"symfony/runtime": {
"version": "v5.3.4"
},
"symfony/service-contracts": {
"version": "v2.4.0"
},
"symfony/stopwatch": {
"version": "v5.3.4"
},
"symfony/string": {
"version": "v5.3.7"
},
"symfony/translation-contracts": {
"version": "v2.4.0"
},
"symfony/twig-bridge": {
"version": "v5.3.7"
},
"symfony/twig-bundle": {
"version": "5.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "5.3",
"ref": "3dd530739a4284e3272274c128dbb7a8140a66f1"
},
"files": [
"config/packages/twig.yaml",
"templates/base.html.twig"
]
},
"symfony/var-dumper": {
"version": "v5.3.7"
},
"symfony/var-exporter": {
"version": "v5.3.7"
},
"symfony/web-profiler-bundle": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "3.3",
"ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6"
},
"files": [
"config/packages/dev/web_profiler.yaml",
"config/packages/test/web_profiler.yaml",
"config/routes/dev/web_profiler.yaml"
]
},
"symfony/yaml": {
"version": "v5.3.6"
},
"theseer/tokenizer": {
"version": "1.2.1"
},
"twig/extra-bundle": {
"version": "v3.3.3"
},
"twig/twig": {
"version": "v3.3.3"
},
"webmozart/assert": {
"version": "1.10.0"
},
"zircote/swagger-php": {
"version": "3.2.3"
}
}

19
app/templates/base.html.twig

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
{# Run `composer require symfony/webpack-encore-bundle`
and uncomment the following Encore helpers to start using Symfony UX #}
{% block stylesheets %}
{#{{ encore_entry_link_tags('app') }}#}
{% endblock %}
{% block javascripts %}
{#{{ encore_entry_script_tags('app') }}#}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

19
app/tests/Unit/Controller/Api/v1/MattermostControllerTest.php

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace App\Tests\Unit\Controller\Api\v1;
use App\Controller\Api\v1\MattermostController;
use App\Tests\Unit\UnitTester;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class MattermostControllerTest extends UnitTester
{
public function testIsExtends(): void
{
$stub = $this->createStub(MattermostController::class);
self::assertTrue(is_subclass_of($stub, AbstractController::class));
}
}

19
app/tests/Unit/KernelTest.php

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace App\Tests\Unit;
use App\Kernel;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class KernelTest extends TestCase
{
public function testIsExtends(): void
{
$kernelStub = $this->createStub(Kernel::class);
self::assertTrue(is_subclass_of($kernelStub, BaseKernel::class));
}
}

102
app/tests/Unit/Service/Mattermost/MattermostServiceTest.php

@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace App\Tests\Unit\Service\Mattermost;
use App\Service\BaseService;
use App\Service\Mattermost\MattermostService;
use App\Service\Mattermost\MattermostServiceInterface;
use Faker\Factory;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use App\Tests\Unit\UnitTester;
use Psr\Http\Message\ResponseInterface;
class MattermostServiceTest extends UnitTester
{
public function testIsExtends(): void
{
$stub = $this->createStub(MattermostService::class);
self::assertTrue(is_subclass_of($stub, BaseService::class));
}
public function testIsImplements(): void
{
$stub = $this->createStub(MattermostService::class);
self::assertInstanceOf(MattermostServiceInterface::class, $stub);
}
/**
* @dataProvider sendMessageDataProvider
* @throws \ReflectionException
*/
public function testSendMessage(
string $mattermostUrl,
string $mattermostUri,
string $channelName,
string $botName,
string $botIcon,
string $message,
array $options
): void
{
$mattermostService = new MattermostService(
$mattermostUrl, $mattermostUri, $channelName, $botName, $botIcon
);
$clientMock = $this->getMockBuilder(Client::class)
->disableOriginalConstructor()
->onlyMethods(['send'])
->getMock();
$clientProperty = $this->getClassProperty($mattermostService, 'client');
$clientProperty->setValue($mattermostService, $clientMock);
$responseMock = $this->getMockForAbstractClass(ResponseInterface::class);
$request = new Request('POST', $mattermostUri);
$clientMock->expects(self::once())
->method('send')
->with($request, $options)
->willReturn($responseMock);
self::assertEquals(
$responseMock,
$mattermostService->sendMessage($message)
);
}
/**
* @throws \JsonException
*/
public function sendMessageDataProvider(): array
{
$faker = (Factory::create('en_EN'));
$channelName = $faker->sha256();
$botName = $faker->sha256();
$botIcon = $faker->sha256();
$message = $faker->sha256();
return [
[
'mattermostUrl' => $faker->sha256(),
'mattermostUri' => $faker->sha256(),
'channelName' => $channelName,
'botName' => $botName,
'botIcon' => $botIcon,
'message' => $message,
'options' => [
'headers' => [
'Content-Type' => 'application/json',
],
'body' => json_encode([
'channel' => $channelName,
'username' => $botName,
'icon_url' => $botIcon,
'text' => $message,
], JSON_THROW_ON_ERROR),
]
]
];
}
}

27
app/tests/Unit/UnitTester.php

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Tests\Unit;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionException;
use ReflectionProperty;
class UnitTester extends TestCase
{
/**
* @throws ReflectionException
*/
public function getClassProperty(
mixed $classObject, string $propertyName
): ReflectionProperty
{
$reflector = new ReflectionClass($classObject);
$property = $reflector->getProperty($propertyName);
$property->setAccessible(true);
return $property;
}
}

2
app/tests/_coverage/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

11
app/tests/bootstrap.php

@ -0,0 +1,11 @@
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
require dirname(__DIR__).'/config/bootstrap.php';
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}

2
app/var/cache/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

2
app/var/log/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

2
app/var/php-cs-fixer/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

2
app/var/sessions/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

2
app/vendor/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

27
devops/docker/nginx/etc/nginx/conf.d/default.conf

@ -0,0 +1,27 @@
server {
set $projectLocation /var/www/localhost;
server_name localhost;
client_max_body_size 10M;
client_body_buffer_size 1024k;
location / {
root $projectLocation/public;
error_log /var/log/nginx/localhost-error.log;
access_log /var/log/nginx/localhost-access.log;
location ~ ^/(.*)$ {
try_files $uri /index.php =404;
fastcgi_pass app:9000;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
location ~* \.(jpg|gif|png|css|js|jpeg|pdf|doc|docx|map|ico|eof|woff|woff2|ttf|svg|xls|xlsx|pptx|odt|ods|odp|txt)$ {
try_files $uri $uri/ /$1 =404;
}
}
}
}

36
devops/docker/php/Dockerfile

@ -0,0 +1,36 @@
FROM php:8.0-fpm-alpine3.14 AS base
RUN apk update && apk upgrade && \
apk add --no-cache $PHPIZE_DEPS libzip-dev && \
docker-php-ext-install zip pcntl
RUN php -r "readfile('https://getcomposer.org/installer');" \
| php -- --install-dir=/usr/local/bin --version=2.1.6 --filename=composer
RUN mkdir -p /var/www/localhost
WORKDIR /var/www/localhost
COPY ./app .
FROM base AS test
ARG XDEBUG_VERSION=3.0.4
RUN curl --proto =https --tlsv1.2 "https://pecl.php.net/get/xdebug-${XDEBUG_VERSION}.tgz" && \
pecl install xdebug-${XDEBUG_VERSION}.tgz && \
rm -rf xdebug-${XDEBUG_VERSION}.tgz && \
rm -rf /tmp/pear && \
docker-php-ext-enable xdebug
COPY devops/docker/php/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
COPY env/app/app.env-dist .env
RUN composer install
FROM test AS local
ARG HOME=/home/fedy95
ARG USER=fedy95
ARG UID=1000
ARG GID=1000
RUN addgroup --gid ${GID} -S ${USER} && \
adduser --uid ${UID} -S ${USER} -G ${USER}
USER ${USER}

9
devops/docker/php/xdebug.ini

@ -0,0 +1,9 @@
zend_extension=xdebug.so
xdebug.client_host=host.docker.internal
xdebug.mode=coverage,debug,profile
xdebug.discover_client_host=1
xdebug.start_with_request=yes
xdebug.client_port=9000
xdebug.extended_info=1
xdebug.idekey="PHPSTORM"
xdebug.log_level=0

22
devops/gitlab/merge_requests/build/1_build.yml

@ -0,0 +1,22 @@
---
build-test:
stage: build-test
only:
- merge_requests
tags:
- docker
image: docker
services:
- name: docker:dind
alias: dockerhost
before_script:
- echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin "$DOCKER_URL"
script:
- |
docker build --file devops/docker/php/Dockerfile \
--tag "$PROJECT_IMAGE_TEST" \
--target=test .
- docker push "$PROJECT_IMAGE_TEST"
after_script:
- docker logout "$DOCKER_URL"
...

19
devops/gitlab/release/1_release-tag.yml

@ -0,0 +1,19 @@
---
release-tag:
stage: release
only:
- tags
tags:
- docker
image: docker
services:
- name: docker:dind
alias: dockerhost
before_script:
- echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin "$DOCKER_URL"
script:
- docker build -t ${PROJECT_IMAGE}:latest image -f image/Dockerfile
- docker push ${PROJECT_IMAGE}:latest
after_script:
- docker logout "$DOCKER_URL"
...

19
devops/gitlab/release/2_deploy.yml

@ -0,0 +1,19 @@
---
deploy:
stage: deploy
only:
- tags
tags:
- ssh-1.160
variables:
GIT_STRATEGY: none
before_script:
- echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin "$DOCKER_URL"
script:
- cd /home/fedy95/gitlab/${CI_PROJECT_PATH}
- git pull
- make restart
- make cleanup
after_script:
- docker logout "$DOCKER_URL"
...

35
docker-compose-local.yml

@ -0,0 +1,35 @@
---
version: "3.4"
services:
app:
build:
context: .
dockerfile: devops/docker/php/Dockerfile
target: local
restart: unless-stopped
env_file:
- env/app/app.env
environment:
COMPOSER_MEMORY_LIMIT: "-1"
PHP_IDE_CONFIG: "serverName=notification-provider_php"
volumes:
- ./app:/var/www/localhost
- ${HOME}/.composer:${HOME}/.composer
- ${HOME}/.ssh:${HOME}/.ssh
expose:
- "9000"
nginx:
image: nginx:1.21-alpine
restart: unless-stopped
depends_on:
- app
volumes:
- ./app:/var/www/localhost
- ./devops/docker/nginx/etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "8054:80"
...

27
docker-compose.yml

@ -0,0 +1,27 @@
---
version: "3.4"
services:
app:
image: registry.fedy95.com/dev/notification-provider:latest
restart: unless-stopped
env_file:
- env/app/app.env
environment:
COMPOSER_MEMORY_LIMIT: "-1"
expose:
- "9000"
nginx:
image: nginx:1.21-alpine
restart: unless-stopped
depends_on:
- app
volumes:
- ./app:/var/www/localhost
- ./devops/docker/nginx/etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "8054:80"
...

1
env/.gitignore

@ -0,0 +1 @@
app.env

8
env/app/app.env-dist

@ -0,0 +1,8 @@
APP_ENV=dev
APP_SECRET=a1desf1573d162b7d97ed994df9dd37949
MATTERMOST_URL=
MATTERMOST_URI=
MATTERMOST_CHANNEL_NAME=
MATTERMOST_BOT_NAME=
MATTERMOST_BOT_ICON=
Loading…
Cancel
Save