├── http
├── api_numbers.http
├── http-client.env.json.dist
└── myfleet_create_ship.http
├── config
├── packages
│ ├── monolog.yaml
│ ├── test
│ │ ├── twig.yaml
│ │ ├── debug.yaml
│ │ ├── routing.yaml
│ │ ├── validator.yaml
│ │ ├── web_profiler.yaml
│ │ ├── framework.php
│ │ ├── jwt_auth.yaml
│ │ └── monolog.yaml
│ ├── assets.yaml
│ ├── beta
│ │ ├── sentry.yaml
│ │ ├── doctrine.yaml
│ │ ├── routing.yaml
│ │ └── monolog.yaml
│ ├── dev
│ │ ├── debug.yaml
│ │ ├── routing.yaml
│ │ ├── hautelook_alice.yaml
│ │ ├── web_profiler.yaml
│ │ ├── nelmio_alice.yaml
│ │ ├── nelmio_api_doc.yaml
│ │ └── monolog.yaml
│ ├── prod
│ │ ├── routing.yaml
│ │ ├── doctrine.yaml
│ │ └── sentry.yaml
│ ├── validator.yaml
│ ├── sensio_framework_extra.yaml
│ ├── http_client.yaml
│ ├── mailer.yaml
│ ├── doctrine_migrations.yaml
│ ├── test_acceptance
│ │ ├── import_test.yaml
│ │ └── messenger.yaml
│ ├── routing.yaml
│ ├── translation.yaml
│ ├── notifier.yaml
│ ├── twig.yaml
│ ├── cache.yaml
│ ├── framework.yaml
│ ├── httplug.yaml
│ ├── doctrine.yaml
│ ├── security.yaml
│ ├── psr_http_message_bridge.yaml
│ ├── nyholm_psr7.yaml
│ ├── messenger.yaml
│ └── jwt_auth.yaml
├── routes
│ ├── dev
│ │ ├── framework.yaml
│ │ ├── web_profiler.yaml
│ │ └── nelmio_api_doc.yaml
│ └── annotations.yaml
├── preload.php
├── services_test.yaml
└── bundles.php
├── .dockerignore
├── public
├── favicon.ico
└── index.php
├── src
├── Domain
│ ├── OrgaId.php
│ ├── ShipId.php
│ ├── UserId.php
│ ├── MemberId.php
│ ├── FundingId.php
│ ├── PatchNoteId.php
│ ├── ShipTemplateId.php
│ ├── TemplateAuthorId.php
│ ├── OrganizationShipId.php
│ ├── MonthlyCostCoverageId.php
│ ├── MyFleet
│ │ ├── FleetShipImport.php
│ │ └── UserShipTemplate.php
│ ├── Service
│ │ └── EntityIdGeneratorInterface.php
│ ├── Event
│ │ ├── DeletedUserEvent.php
│ │ ├── UpdatedShip.php
│ │ └── UpdatedFleetEvent.php
│ ├── MemberProfile.php
│ ├── UserFleet.php
│ ├── UserProfile.php
│ ├── Exception
│ │ ├── DomainException.php
│ │ ├── NotFoundOrganizationException.php
│ │ ├── NotFoundFleetByUserException.php
│ │ ├── ConflictVersionException.php
│ │ ├── FailedValidationException.php
│ │ ├── NotFoundUserException.php
│ │ ├── NotFoundOrganizationFleetException.php
│ │ ├── AlreadyExistingFleetForUserException.php
│ │ ├── NoMemberHandleException.php
│ │ ├── NotFoundShipException.php
│ │ ├── NotFounderOfOrganizationException.php
│ │ ├── NotFoundShipTemplateByUserException.php
│ │ ├── FounderOfOrganizationException.php
│ │ ├── NotJoinedOrganizationMemberException.php
│ │ ├── AlreadyMemberOfOrganizationException.php
│ │ ├── NotMemberOfOrganizationException.php
│ │ └── FullyJoinedMemberOfOrganizationException.php
│ ├── EntityId.php
│ ├── UserShip.php
│ └── Notification
│ │ └── FeedbackNotification.php
├── Application
│ ├── Common
│ │ └── Clock.php
│ ├── Repository
│ │ ├── Auth0RepositoryInterface.php
│ │ ├── PatchNoteRepositoryInterface.php
│ │ ├── ShipTemplateRepositoryInterface.php
│ │ ├── FleetRepositoryInterface.php
│ │ ├── UserRepositoryInterface.php
│ │ ├── OrganizationFleetRepositoryInterface.php
│ │ └── OrganizationRepositoryInterface.php
│ ├── PatchNote
│ │ ├── Output
│ │ │ ├── HasNewPatchNoteOutput.php
│ │ │ ├── LastPatchNotesOutput.php
│ │ │ └── LastPatchNoteOutput.php
│ │ └── HasNewPatchNoteService.php
│ ├── Home
│ │ ├── Output
│ │ │ └── NumbersOutput.php
│ │ └── NumbersService.php
│ ├── Provider
│ │ ├── UserFleetProviderInterface.php
│ │ ├── ListTemplatesProviderInterface.php
│ │ └── MemberProfileProviderInterface.php
│ ├── MyFleet
│ │ ├── Input
│ │ │ └── ImportFleetShip.php
│ │ ├── Output
│ │ │ ├── MyFleetOutput.php
│ │ │ ├── MyFleetShipsCollectionOutput.php
│ │ │ └── MyFleetShipOutput.php
│ │ ├── DeleteAccountHandler.php
│ │ ├── ClearMyFleetService.php
│ │ ├── CreateShipService.php
│ │ ├── DeleteShipService.php
│ │ ├── UpdateShipService.php
│ │ ├── MyFleetService.php
│ │ ├── ImportFleetService.php
│ │ └── UpdateShipFromTemplateService.php
│ ├── ShipTemplate
│ │ ├── Output
│ │ │ ├── ListTemplatesOutput.php
│ │ │ ├── CargoCapacityOutput.php
│ │ │ ├── ShipChassisOutput.php
│ │ │ ├── CrewOutput.php
│ │ │ ├── ManufacturerOutput.php
│ │ │ ├── PriceOutput.php
│ │ │ └── ListTemplatesItemOutput.php
│ │ ├── Input
│ │ │ └── CreateTemplateInput.php
│ │ └── CreateTemplateService.php
│ ├── MyOrganizations
│ │ ├── Output
│ │ │ ├── MyOrganizationsOutput.php
│ │ │ ├── OrganizationMembersOutput.php
│ │ │ ├── OrganizationShipOwnersOutput.php
│ │ │ ├── OrganizationCandidatesOutput.php
│ │ │ ├── OrganizationsCollectionOutput.php
│ │ │ ├── OrganizationsItemFleetOutput.php
│ │ │ ├── OrganizationMembersItemOutput.php
│ │ │ ├── OrganizationCandidatesItemOutput.php
│ │ │ ├── OrganizationShipOwnersItemOutput.php
│ │ │ ├── OrganizationsItemOutput.php
│ │ │ ├── OrganizationsItemFleetShipsOutput.php
│ │ │ ├── MyOrganizationsItemOutput.php
│ │ │ └── OrganizationsItemWithFleetOutput.php
│ │ ├── UpdateOrganizationService.php
│ │ ├── DisbandOrganizationService.php
│ │ ├── MyOrganizationsService.php
│ │ ├── UnjoinOrganizationService.php
│ │ └── OrganizationsService.php
│ ├── Profile
│ │ ├── Output
│ │ │ └── PublicProfileOutput.php
│ │ ├── DeleteAccountHandler.php
│ │ ├── ChangeHandleService.php
│ │ ├── ChangeNicknameService.php
│ │ ├── SavePreferencesService.php
│ │ ├── DeleteAccountService.php
│ │ ├── PublicProfilesService.php
│ │ └── ProfileService.php
│ └── Support
│ │ └── GiveFeedbackService.php
├── Form
│ ├── Dto
│ │ ├── PayPalCaptureTransaction.php
│ │ ├── PatchNote.php
│ │ ├── FundingPayment.php
│ │ └── MonthlyCostCoverage.php
│ └── PatchNoteForm.php
├── Infrastructure
│ ├── Common
│ │ ├── SystemClock.php
│ │ └── FakeClock.php
│ ├── Security
│ │ └── FakeAuth0Service.php
│ ├── Controller
│ │ ├── Profile
│ │ │ ├── Input
│ │ │ │ ├── SavePreferencesInput.php
│ │ │ │ ├── ChangeNicknameInput.php
│ │ │ │ └── ChangeHandleInput.php
│ │ │ └── DeleteAccountController.php
│ │ ├── ShipTemplate
│ │ │ └── Input
│ │ │ │ ├── CreateTemplateChassisInput.php
│ │ │ │ ├── CreateTemplatePriceInput.php
│ │ │ │ ├── CreateTemplateCrewInput.php
│ │ │ │ └── CreateTemplateManufacturerInput.php
│ │ ├── MyFleet
│ │ │ ├── Input
│ │ │ │ ├── UpdateShipFromTemplateInput.php
│ │ │ │ └── CreateShipFromTemplateInput.php
│ │ │ └── ClearMyFleetController.php
│ │ └── Home
│ │ │ └── NumbersController.php
│ ├── Service
│ │ ├── SystemEntityIdGenerator.php
│ │ └── InMemoryEntityIdGenerator.php
│ ├── Repository
│ │ ├── User
│ │ │ ├── FakeAuth0Repository.php
│ │ │ └── Auth0Repository.php
│ │ └── ShipTemplate
│ │ │ └── InMemoryShipTemplateRepository.php
│ ├── Provider
│ │ ├── Organizations
│ │ │ ├── InMemoryUserFleetProvider.php
│ │ │ ├── InMemoryMemberProfileProvider.php
│ │ │ └── DirectCallMemberProfileProvider.php
│ │ └── MyFleet
│ │ │ ├── InMemoryListTemplatesProvider.php
│ │ │ └── DirectCallListTemplatesProvider.php
│ ├── Validator
│ │ ├── UniqueOrganizationSid.php
│ │ ├── CountShipsLessThan.php
│ │ ├── CountOrganizationsLessThan.php
│ │ ├── UniqueUserHandle.php
│ │ ├── UniqueOrganizationSidValidator.php
│ │ └── CountOrganizationsLessThanValidator.php
│ └── Listener
│ │ └── FormatExceptionListener.php
├── Message
│ └── Funding
│ │ ├── SendOrderRefundMail.php
│ │ └── SendOrderCaptureSummaryMail.php
├── Entity
│ ├── VersionnableTrait.php
│ ├── ShipChassis.php
│ ├── CargoCapacity.php
│ ├── ShipRole.php
│ ├── ShipSize.php
│ ├── Price.php
│ ├── Manufacturer.php
│ ├── Crew.php
│ └── Membership.php
├── Event
│ └── FundingUpdatedEvent.php
├── Exception
│ └── UnableToCreatePaypalOrderException.php
├── Repository
│ └── MonthlyCostCoverageRepository.php
├── Security
│ └── ApiAccessDeniedHandler.php
├── Service
│ └── Funding
│ │ ├── PaypalCheckoutInterface.php
│ │ └── VerifyWebhookSignatureFactory.php
├── Validator
│ └── Constraints
│ │ ├── UniqueField.php
│ │ └── UniqueFieldValidator.php
├── Controller
│ ├── Funding
│ │ ├── ConfigurationController.php
│ │ └── MyBackingsController.php
│ └── BackOffice
│ │ └── PatchNote
│ │ └── PatchNoteListController.php
├── Command
│ └── DeleteOldCreatedFundingCommand.php
├── Listener
│ └── Funding
│ │ └── UpdateSupporterAdvantagesListener.php
├── Kernel.php
└── Serializer
│ └── EntityIdNormalizer.php
├── docker
├── php
│ ├── entrypoint.sh
│ ├── php-fpm.dev.conf
│ ├── php-fpm.prod.conf
│ ├── php-cli.dev.ini
│ ├── php-cli.prod.ini
│ ├── www.dev.conf
│ ├── www.prod.conf
│ ├── php-fpm-fcgi.prod.ini
│ └── php-fpm-fcgi.dev.ini
├── supervisor
│ ├── supervisord.conf
│ ├── app.conf
│ └── app.prod.conf
└── mysql
│ └── config-file.cnf
├── templates
├── back_office_layout.html.twig
├── emails
│ └── order_capture_summary.txt.twig
└── back_office
│ ├── patch_note
│ ├── create.html.twig
│ └── edit.html.twig
│ └── funding
│ └── monthly_cost_coverage_create.html.twig
├── tests
├── bootstrap.php
├── Acceptance
│ └── KernelTestCase.php
├── Integration
│ └── KernelTestCase.php
├── Service
│ └── PayPal
│ │ └── MockVerifyWebhookSignatureFactory.php
├── End2End
│ └── Controller
│ │ └── PatchNote
│ │ └── HasNewPatchNoteControllerTest.php
└── Poubelle
│ └── BackOffice
│ └── PatchNote
│ └── PatchNoteCreateControllerTest.php
├── .editorconfig
├── bin
├── phpunit
└── console
├── .env.test
├── .gitignore
├── migrations
├── Version20210425163351.php
├── Version20210407181655.php
├── Version20210502100109.php
├── Version20210505165223.php
├── Version20210523102656.php
├── Version20210410225927.php
├── Version20210413195714.php
├── Version20210412224435.php
├── Version20210522155300.php
└── Version20210506210323.php
├── docker-compose.yml
├── README.md
├── fixtures
├── patch_note.yaml
└── monthly_cost_coverage.yaml
├── phpunit.xml.dist
└── .env
/http/api_numbers.http:
--------------------------------------------------------------------------------
1 | GET {{base_url}}/api/numbers
2 |
3 | ###
4 |
--------------------------------------------------------------------------------
/config/packages/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | channels: ['funding']
3 |
--------------------------------------------------------------------------------
/config/packages/test/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | strict_variables: true
3 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | /var
2 | /vendor
3 | /.env.local
4 | /.env.*.local
5 | /dumps
6 |
--------------------------------------------------------------------------------
/config/packages/assets.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | assets:
3 | base_path: 'api'
4 |
--------------------------------------------------------------------------------
/config/packages/beta/sentry.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: '../prod/sentry.*' }
3 |
--------------------------------------------------------------------------------
/config/packages/beta/doctrine.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: '../prod/doctrine.*' }
3 |
--------------------------------------------------------------------------------
/config/packages/beta/routing.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: '../prod/routing.*' }
3 |
--------------------------------------------------------------------------------
/config/packages/dev/debug.yaml:
--------------------------------------------------------------------------------
1 | debug:
2 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
3 |
--------------------------------------------------------------------------------
/config/packages/dev/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/config/packages/prod/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: null
4 |
--------------------------------------------------------------------------------
/config/packages/test/debug.yaml:
--------------------------------------------------------------------------------
1 | debug:
2 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
3 |
--------------------------------------------------------------------------------
/config/packages/test/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/config/packages/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | email_validation_mode: html5
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SC-Fleet-Manager/fleet-manager-api/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/Domain/OrgaId.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BO
6 |
7 |
8 | {% block body %}
9 | {% endblock %}
10 |
11 | {% block javascripts %}
12 | {% endblock %}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/Application/Home/Output/NumbersOutput.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__).'/.env');
11 | }
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = LF
5 | charset = utf-8
6 | indent_style = space
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [Makefile]
11 | indent_style = tab
12 | indent_size = 8
13 |
14 | [{*.php, *.yml, *.yaml, *.feature, *.yml.dist, *.yaml.dist}]
15 | indent_size = 4
16 |
17 | [*.md]
18 | trim_trailing_whitespace = false
19 |
--------------------------------------------------------------------------------
/src/Message/Funding/SendOrderRefundMail.php:
--------------------------------------------------------------------------------
1 | fundingId;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config/preload.php:
--------------------------------------------------------------------------------
1 | fundingId;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/docker/supervisor/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | logfile=/var/log/supervisor/supervisord.log
3 | pidfile=/var/run/supervisord.pid
4 | nodaemon=true
5 | user=root
6 |
7 | [rpcinterface:supervisor]
8 | supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
9 |
10 | [supervisorctl]
11 | serverurl=unix:///var/run/supervisor.sock
12 |
13 | [include]
14 | files=/etc/supervisor/conf.d/*.conf
15 |
--------------------------------------------------------------------------------
/src/Application/Provider/MemberProfileProviderInterface.php:
--------------------------------------------------------------------------------
1 | version;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Application/PatchNote/Output/LastPatchNotesOutput.php:
--------------------------------------------------------------------------------
1 | patchNotes, LastPatchNoteOutput::class);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/config/packages/test/framework.php:
--------------------------------------------------------------------------------
1 | loadFromExtension('framework', [
4 | 'test' => true,
5 | 'session' => [
6 | 'storage_id' => isset($_SERVER['TESTING_WITH_SESSION']) ? 'session.storage.native' : 'session.storage.mock_file',
7 | 'handler_id' => 'session.handler.native_file',
8 | ],
9 | 'cache' => [
10 | 'app' => 'cache.adapter.apcu',
11 | 'pools' => [],
12 | ],
13 | ]);
14 |
--------------------------------------------------------------------------------
/src/Form/Dto/PatchNote.php:
--------------------------------------------------------------------------------
1 | 'test_acceptance']);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/docker/supervisor/app.prod.conf:
--------------------------------------------------------------------------------
1 | [program:organizations_sub_consumers]
2 | directory=/app
3 | command=php bin/console messenger:consume organizations_sub --limit=300 --time-limit=3600
4 | user=www-data
5 | stopsignal=TERM
6 | autostart=true
7 | startsecs=0
8 | autorestart=true
9 | numprocs=1
10 | process_name=%(program_name)s_%(process_num)02d
11 | stdout_logfile=/dev/fd/1
12 | stdout_logfile_maxbytes=0
13 | stderr_logfile=/dev/fd/2
14 | stderr_logfile_maxbytes=0
15 |
--------------------------------------------------------------------------------
/src/Event/FundingUpdatedEvent.php:
--------------------------------------------------------------------------------
1 | funding = $funding;
15 | }
16 |
17 | public function getFunding(): Funding
18 | {
19 | return $this->funding;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/bin/phpunit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | paypalError = $paypalError;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Form/Dto/FundingPayment.php:
--------------------------------------------------------------------------------
1 | now = $now;
14 | }
15 |
16 | public function now(): \DateTimeInterface
17 | {
18 | return new \DateTimeImmutable($this->now);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Form/Dto/MonthlyCostCoverage.php:
--------------------------------------------------------------------------------
1 | profile = $profile;
14 | }
15 |
16 | public function getUserProfileByA0UID(string $jwt): ?array
17 | {
18 | return $this->profile;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Domain/Event/DeletedUserEvent.php:
--------------------------------------------------------------------------------
1 | userId;
18 | }
19 |
20 | public function getAuth0Username(): string
21 | {
22 | return $this->auth0Username;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Application/Repository/PatchNoteRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | getModel(),
20 | $ship->getImageUrl(),
21 | $ship->getQuantity(),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ###> symfony/framework-bundle ###
2 | /.env.local
3 | /.env.local.php
4 | /.env.*.local
5 | /config/secrets/prod/prod.decrypt.private.php
6 | /public/bundles/
7 | /var/
8 | /vendor/
9 | ###< symfony/framework-bundle ###
10 | ###> symfony/phpunit-bridge ###
11 | .phpunit
12 | .phpunit.result.cache
13 | /phpunit.xml
14 | ###< symfony/phpunit-bridge ###
15 |
16 | /docker-compose.override.yml
17 | /dumps/*
18 |
19 | ###> friendsofphp/php-cs-fixer ###
20 | /.php_cs
21 | /.php_cs.cache
22 | ###< friendsofphp/php-cs-fixer ###
23 |
24 | /http/http-client.env.json
25 |
--------------------------------------------------------------------------------
/docker/php/php-cli.prod.ini:
--------------------------------------------------------------------------------
1 | expose_php = Off
2 |
3 | max_execution_time = -1
4 | max_input_time = -1
5 | memory_limit = 512M
6 | error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
7 | display_errors = Off
8 | display_startup_errors = Off
9 |
10 | date.timezone = UTC
11 |
12 | opcache.enable=1
13 | opcache.enable_cli=1
14 | opcache.file_cache="/tmp"
15 | opcache.file_cache_only=1
16 | opcache.file_cache_consistency_checks=1
17 |
18 | realpath_cache_size = 4096K
19 | realpath_cache_ttl = 600
20 |
21 | ;error_log = /var/log/php/error-cli.log
22 | error_log = /proc/self/fd/2
23 |
--------------------------------------------------------------------------------
/src/Application/Repository/ShipTemplateRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | addSql('ALTER TABLE users ADD handle VARCHAR(31) DEFAULT NULL');
13 | }
14 |
15 | public function down(Schema $schema): void
16 | {
17 | $this->addSql('CREATE SCHEMA public');
18 | $this->addSql('ALTER TABLE users DROP handle');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Domain/MemberProfile.php:
--------------------------------------------------------------------------------
1 | id;
17 | }
18 |
19 | public function getNickname(): ?string
20 | {
21 | return $this->nickname;
22 | }
23 |
24 | public function getHandle(): ?string
25 | {
26 | return $this->handle;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/migrations/Version20210407181655.php:
--------------------------------------------------------------------------------
1 | addSql('ALTER TABLE users ADD nickname VARCHAR(31) DEFAULT NULL');
13 | }
14 |
15 | public function down(Schema $schema): void
16 | {
17 | $this->addSql('CREATE SCHEMA public');
18 | $this->addSql('ALTER TABLE users DROP nickname');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Entity/ShipChassis.php:
--------------------------------------------------------------------------------
1 | name = $name;
22 | }
23 |
24 | public function getName(): string
25 | {
26 | return $this->name;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/migrations/Version20210502100109.php:
--------------------------------------------------------------------------------
1 | addSql('ALTER TABLE ships ALTER model TYPE VARCHAR(60)');
13 | }
14 |
15 | public function down(Schema $schema): void
16 | {
17 | $this->addSql('CREATE SCHEMA public');
18 | $this->addSql('ALTER TABLE ships ALTER model TYPE VARCHAR(32)');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/Output/CargoCapacityOutput.php:
--------------------------------------------------------------------------------
1 | getCapacity(),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Domain/UserFleet.php:
--------------------------------------------------------------------------------
1 | userId = $userId;
14 | $this->ships = $ships;
15 | }
16 |
17 | public function getUserId(): UserId
18 | {
19 | return $this->userId;
20 | }
21 |
22 | /**
23 | * @return UserShip[]
24 | */
25 | public function getShips(): array
26 | {
27 | return $this->ships;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Entity/CargoCapacity.php:
--------------------------------------------------------------------------------
1 | capacity = $capacity;
22 | }
23 |
24 | public function getCapacity(): int
25 | {
26 | return $this->capacity;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/migrations/Version20210505165223.php:
--------------------------------------------------------------------------------
1 | addSql('ALTER TABLE organization_ships ALTER model TYPE VARCHAR(60)');
13 | }
14 |
15 | public function down(Schema $schema): void
16 | {
17 | $this->addSql('CREATE SCHEMA public');
18 | $this->addSql('ALTER TABLE organization_ships ALTER model TYPE VARCHAR(32)');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/Output/ShipChassisOutput.php:
--------------------------------------------------------------------------------
1 | getName(),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Domain/UserProfile.php:
--------------------------------------------------------------------------------
1 | nickname;
17 | }
18 |
19 | public function getEmail(): ?string
20 | {
21 | return $this->email;
22 | }
23 |
24 | public function getDiscordId(): ?string
25 | {
26 | return $this->discordId;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__).'/.env');
11 |
12 | if ($_SERVER['APP_DEBUG']) {
13 | umask(0000);
14 |
15 | Debug::enable();
16 | }
17 |
18 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
19 | $request = Request::createFromGlobals();
20 | $response = $kernel->handle($request);
21 | $response->send();
22 | $kernel->terminate($request, $response);
23 |
--------------------------------------------------------------------------------
/config/packages/test/jwt_auth.yaml:
--------------------------------------------------------------------------------
1 | jwt_auth:
2 | domain: "%env(AUTH0_DOMAIN)%"
3 | client_id: "%env(AUTH0_CLIENT_ID)%"
4 | audience: "%env(AUTH0_API_AUDIENCE)%"
5 |
6 | algorithm: "HS256"
7 | client_secret: "%env(AUTH0_CLIENT_SECRET)%"
8 |
9 | cache: "cache.app"
10 |
11 | validations:
12 | # Validate AUD claim against a value, such as an API identifier. Set to false to skip. Defaults to jwt_auth.audience.
13 | aud: "%env(AUTH0_API_AUDIENCE)%"
14 | # Validate the AZP claim against a value, such as a client ID. Set to false to skip. Defaults to false.
15 | azp: "%env(AUTH0_CLIENT_ID)%"
16 |
--------------------------------------------------------------------------------
/src/Infrastructure/Repository/User/FakeAuth0Repository.php:
--------------------------------------------------------------------------------
1 | deletedUsers[] = $auth0Username;
15 | }
16 |
17 | /**
18 | * @return string[]
19 | */
20 | public function getDeletedUsers(): array
21 | {
22 | return $this->deletedUsers;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/config/packages/prod/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | orm:
3 | auto_generate_proxy_classes: false
4 | metadata_cache_driver:
5 | type: pool
6 | pool: doctrine.system_cache_pool
7 | query_cache_driver:
8 | type: pool
9 | pool: doctrine.system_cache_pool
10 | result_cache_driver:
11 | type: pool
12 | pool: doctrine.result_cache_pool
13 |
14 | framework:
15 | cache:
16 | pools:
17 | doctrine.result_cache_pool:
18 | adapter: cache.app
19 | doctrine.system_cache_pool:
20 | adapter: cache.system
21 |
--------------------------------------------------------------------------------
/config/packages/doctrine.yaml:
--------------------------------------------------------------------------------
1 | parameters:
2 | env(DATABASE_URL): 'postgresql://localhost:5432/postgres?serverVersion=13&charset=utf8'
3 |
4 | doctrine:
5 | dbal:
6 | url: '%env(resolve:DATABASE_URL)%'
7 | override_url: true
8 | orm:
9 | auto_generate_proxy_classes: true
10 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
11 | auto_mapping: true
12 | mappings:
13 | App:
14 | is_bundle: false
15 | type: annotation
16 | dir: '%kernel.project_dir%/src/Entity'
17 | prefix: 'App\Entity'
18 | alias: App
19 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationsCollectionOutput.php:
--------------------------------------------------------------------------------
1 | role = $role;
24 | }
25 |
26 | public function getRole(): ?string
27 | {
28 | return $this->role;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/templates/emails/order_capture_summary.txt.twig:
--------------------------------------------------------------------------------
1 | Funding properties :
2 |
3 | Amount : {{ (funding.amount / 100)|number_format(2) }} {{ funding.currency }}
4 | Net Amount : {{ (funding.netAmount / 100)|number_format(2) }} {{ funding.currency }}
5 | ID : {{ funding.id }}
6 | Payer ID : {{ funding.user.id }}
7 | Payer nickname : {{ funding.user.nickname }}
8 | Payer email : {{ funding.user.email }}
9 | Gateway : {{ funding.gateway }}
10 | Created at : {{ funding.createdAt|date('r') }}
11 | Paypal Order Id : {{ funding.paypalOrderId }}
12 | Paypal Status : {{ funding.paypalStatus }}
13 | Paypal Purchase :
14 | {{ funding.paypalPurchase|json_encode(constant('JSON_PRETTY_PRINT')) }}
15 |
--------------------------------------------------------------------------------
/migrations/Version20210523102656.php:
--------------------------------------------------------------------------------
1 | addSql('ALTER TABLE ships ADD template_id UUID DEFAULT NULL');
13 | $this->addSql('COMMENT ON COLUMN ships.template_id IS \'(DC2Type:ulid)\'');
14 | }
15 |
16 | public function down(Schema $schema): void
17 | {
18 | $this->addSql('CREATE SCHEMA public');
19 | $this->addSql('ALTER TABLE ships DROP template_id');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Application/Profile/DeleteAccountHandler.php:
--------------------------------------------------------------------------------
1 | getAuth0Username();
19 |
20 | $this->auth0Repository->delete($username);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Domain/Exception/DomainException.php:
--------------------------------------------------------------------------------
1 | error = $error;
19 | $this->userMessage = $userMessage;
20 | $this->context = $context;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/config/packages/test/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: fingers_crossed
5 | action_level: error
6 | handler: nested
7 | excluded_http_codes: [404, 405]
8 | buffer_size: 50 # How many messages should be saved? Prevent memory leaks
9 | nested:
10 | type: stream
11 | path: "%kernel.logs_dir%/%kernel.environment%-error.log"
12 | level: info
13 | ####################
14 | streamed_main:
15 | type: stream
16 | path: "%kernel.logs_dir%/%kernel.environment%.log"
17 | level: debug
18 | channels: [ "!event" ]
19 |
--------------------------------------------------------------------------------
/src/Application/Repository/FleetRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | 'forbidden',
17 | ], 403);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/config/packages/prod/sentry.yaml:
--------------------------------------------------------------------------------
1 | parameters:
2 | env(SENTRY_DSN): ''
3 |
4 | sentry:
5 | dsn: '%env(SENTRY_DSN)%'
6 | options:
7 | integrations:
8 | - 'Sentry\Integration\IgnoreErrorsIntegration'
9 |
10 | services:
11 | Sentry\Integration\IgnoreErrorsIntegration:
12 | arguments:
13 | $options:
14 | ignore_exceptions:
15 | - 'Symfony\Component\Security\Core\Exception\AccessDeniedException'
16 | - 'Symfony\Component\Security\Core\Exception\AuthenticationException'
17 | - 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'
18 | - 'App\Domain\Exception\DomainException'
19 |
--------------------------------------------------------------------------------
/src/Application/Repository/UserRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | getShips() as $ship) {
21 | $ships[] = OrganizationsItemFleetShipsOutput::createFromShip($ship);
22 | }
23 |
24 | return new self($ships);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Service/Funding/PaypalCheckoutInterface.php:
--------------------------------------------------------------------------------
1 | addSql('DROP INDEX fleetid_name_idx');
13 | $this->addSql('ALTER TABLE ships RENAME COLUMN name TO model');
14 | }
15 |
16 | public function down(Schema $schema): void
17 | {
18 | $this->addSql('CREATE SCHEMA public');
19 | $this->addSql('ALTER TABLE ships RENAME COLUMN model TO name');
20 | $this->addSql('CREATE UNIQUE INDEX fleetid_name_idx ON ships (fleet_id, name)');
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/Output/CrewOutput.php:
--------------------------------------------------------------------------------
1 | getMin(),
26 | $crew->getMax(),
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Infrastructure/Provider/Organizations/InMemoryUserFleetProvider.php:
--------------------------------------------------------------------------------
1 | userFleet = $userFleet;
17 | }
18 |
19 | public function getUserFleet(MemberId $memberId): UserFleet
20 | {
21 | return $this->userFleet ?? new UserFleet(UserId::fromString((string) $memberId), []);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/Integration/KernelTestCase.php:
--------------------------------------------------------------------------------
1 | get('doctrine.dbal.default_connection');
16 | static::$connection->beginTransaction();
17 | }
18 |
19 | protected function tearDown(): void
20 | {
21 | if (static::$connection->isTransactionActive()) {
22 | static::$connection->rollBack();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationMembersItemOutput.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
21 | if ($user === null) {
22 | throw new NotFoundUserException($userId);
23 | }
24 |
25 | $user->changeHandle($handle);
26 |
27 | $this->userRepository->save($user);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Application/Profile/ChangeNicknameService.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
19 | if ($user === null) {
20 | throw new NotFoundUserException($userId);
21 | }
22 |
23 | $user->changeNickname($nickname);
24 |
25 | $this->userRepository->save($user);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Domain/Event/UpdatedFleetEvent.php:
--------------------------------------------------------------------------------
1 | getShips() as $ship) {
22 | $ships[] = UpdatedShip::createFromShip($ship);
23 | }
24 |
25 | return new self(
26 | $fleet->getUserId(),
27 | $ships,
28 | $fleet->getVersion(),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.5'
2 | services:
3 | php:
4 | image: 186694923554.dkr.ecr.eu-west-1.amazonaws.com/fleet-manager-api-php:test-latest
5 | hostname: php
6 | depends_on:
7 | - redis
8 | supervisor:
9 | image: 186694923554.dkr.ecr.eu-west-1.amazonaws.com/fleet-manager-api-supervisor:test-latest
10 | hostname: supervisor
11 | depends_on:
12 | - redis
13 | apache:
14 | image: 186694923554.dkr.ecr.eu-west-1.amazonaws.com/fleet-manager-api-apache:test-latest
15 | hostname: apache
16 | environment:
17 | PHP_HANDLER_HOST: php:9000
18 | depends_on:
19 | - php
20 | redis:
21 | image: bitnami/redis:5.0.9-debian-10-r6
22 | hostname: redis
23 |
--------------------------------------------------------------------------------
/src/Infrastructure/Provider/MyFleet/InMemoryListTemplatesProvider.php:
--------------------------------------------------------------------------------
1 | templateOfUser = $template;
17 | }
18 |
19 | public function getShipTemplateOfUser(ShipTemplateId $templateId, UserId $userId): ?UserShipTemplate
20 | {
21 | return $this->templateOfUser;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Infrastructure/Validator/UniqueOrganizationSid.php:
--------------------------------------------------------------------------------
1 | excludeOrgaId = $excludeOrgaId;
21 | $this->message = $message ?? 'This SID is already taken.';
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Application/Profile/SavePreferencesService.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
19 | if ($user === null) {
20 | throw new NotFoundUserException($userId);
21 | }
22 |
23 | $user->setSupporterVisible($supporterVisible);
24 |
25 | $this->userRepository->save($user);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Star Citizen Fleet Manager #
2 |
3 | ## Installation for development ##
4 |
5 | **Requirements**
6 |
7 | - git
8 | - docker
9 | - docker-compose
10 |
11 | **Clone repository**
12 |
13 | ```
14 | git clone https://github.com/Ioni14/starcitizen-fleet-manager.git
15 | cd starcitizen-fleet-manager
16 | ```
17 |
18 | **Customize environment variables**
19 |
20 | ```
21 | echo "APP_ENV=dev" > .env.local
22 | ```
23 |
24 | **Customize docker-compose.override.yml**
25 |
26 | cp docker-compose.override.yml.dist docker-compose.override.yml
27 |
28 | Customize the ports according to your needs, configure your dev reverse-proxy, etc.
29 |
30 | **Launch the stack (build & up containers)**
31 |
32 | ```
33 | make install
34 | ```
35 |
36 | **Launch all tests**
37 | ```
38 | make -j8 tests
39 | ```
40 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/ShipTemplate/Input/CreateTemplateCrewInput.php:
--------------------------------------------------------------------------------
1 | getUserId();
19 |
20 | $fleet = $this->fleetRepository->getFleetByUser($userId);
21 | if ($fleet === null) {
22 | return;
23 | }
24 |
25 | $this->fleetRepository->delete($fleet);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Domain/MyFleet/UserShipTemplate.php:
--------------------------------------------------------------------------------
1 | id = $id;
16 | $this->model = $model;
17 | $this->pictureUrl = $pictureUrl;
18 | }
19 |
20 | public function getId(): ShipTemplateId
21 | {
22 | return $this->id;
23 | }
24 |
25 | public function getModel(): string
26 | {
27 | return $this->model;
28 | }
29 |
30 | public function getPictureUrl(): ?string
31 | {
32 | return $this->pictureUrl;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotFoundOrganizationException.php:
--------------------------------------------------------------------------------
1 | entityClass);
23 | Assert::propertyExists($this->entityClass, $field);
24 | $this->message = $message ?: 'This email is taken. Please choose another.';
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Infrastructure/Validator/CountShipsLessThan.php:
--------------------------------------------------------------------------------
1 | message = $message ?? "You have reached the limit of $max ships.";
19 | $this->max = $max;
20 | }
21 |
22 | public function getTargets(): string
23 | {
24 | return self::CLASS_CONSTRAINT;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Domain/EntityId.php:
--------------------------------------------------------------------------------
1 | ulid;
24 | }
25 |
26 | public function equals(EntityId $other): bool
27 | {
28 | return $this->ulid->equals($other->ulid);
29 | }
30 |
31 | public function __toString(): string
32 | {
33 | return $this->ulid->toRfc4122();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotFoundFleetByUserException.php:
--------------------------------------------------------------------------------
1 | getName(),
26 | $manufacturer->getCode(),
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Domain/Exception/ConflictVersionException.php:
--------------------------------------------------------------------------------
1 | getMessage() ?? ''),
24 | $code,
25 | $previous,
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Domain/Exception/FailedValidationException.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
21 | if ($user === null) {
22 | return;
23 | }
24 |
25 | $this->userRepository->delete($user);
26 | $this->bus->dispatch(new DeletedUserEvent($userId, $user->getAuth0Username()));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotFoundOrganizationFleetException.php:
--------------------------------------------------------------------------------
1 | message = $message ?? "You have reached the limit of $max organizations created.";
19 | $this->max = $max;
20 | }
21 |
22 | public function getTargets(): string
23 | {
24 | return self::CLASS_CONSTRAINT;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationShipOwnersItemOutput.php:
--------------------------------------------------------------------------------
1 | json([
23 | 'currency' => $this->currency,
24 | 'paypalClientId' => $this->paypalClientId,
25 | ]);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/config/packages/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | # enable_authenticator_manager: true
3 | providers:
4 | user_entity_jwt:
5 | id: 'App\Security\UserEntityJwtProvider'
6 | firewalls:
7 | dev:
8 | pattern: ^/(_(profiler|wdt)|favicon\.ico)/
9 | security: false
10 | main:
11 | provider: user_entity_jwt
12 | stateless: true
13 | anonymous: true
14 | guard:
15 | authenticators:
16 | - jwt_auth.security.guard.jwt_guard_authenticator
17 | logout:
18 | path: logout
19 | access_denied_handler: App\Security\ApiAccessDeniedHandler
20 |
21 | role_hierarchy:
22 | ROLE_ADMIN: ROLE_USER
23 |
24 | access_control:
25 | - { path: ^/bo/, roles: ROLE_ADMIN }
26 | - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
27 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/ClearMyFleetService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
23 | if ($fleet === null) {
24 | return;
25 | }
26 |
27 | $fleet->deleteAllShips($this->clock->now());
28 |
29 | $this->fleetRepository->save($fleet);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Infrastructure/Repository/User/Auth0Repository.php:
--------------------------------------------------------------------------------
1 | managementApi->users()->delete($auth0Username);
23 | } catch (\Throwable $e) {
24 | $this->logger->error('Unable to delete user on Auth0 : '.$e->getMessage(), ['exception' => $e, 'username' => $auth0Username]);
25 |
26 | throw $e;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/fixtures/patch_note.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\PatchNote:
2 | patch_note_1:
3 | __construct:
4 | - '<(new \App\Domain\PatchNoteId(\Symfony\Component\Uid\Ulid::fromString("01F17Y39FNFNJG7ECMM4YG9SBE")))>'
5 | - 'My new patch 1'
6 | - |
7 | Hello everyone,
8 | Here is my new patch 1
9 | Goodbye!
10 | - 'https://blog.fleet-manager.space/my-patch-1'
11 | - '<(new \DateTimeImmutable("2019-04-03 11:22:33"))>'
12 | patch_note_2:
13 | __construct:
14 | - '<(new \App\Domain\PatchNoteId(\Symfony\Component\Uid\Ulid::fromString("01F17Y4GWNQ89CNPM6T6M1R894")))>'
15 | - 'My new patch 2'
16 | - |
17 | Hello everyone,
18 | Here is my new patch 2
19 | Goodbye!
20 | - null
21 | - '<(new \DateTimeImmutable("2019-04-04 11:22:33"))>'
22 |
--------------------------------------------------------------------------------
/src/Domain/UserShip.php:
--------------------------------------------------------------------------------
1 | shipId = $shipId;
15 | $this->model = $model;
16 | $this->imageUrl = $imageUrl;
17 | $this->quantity = $quantity;
18 | }
19 |
20 | public function getShipId(): ShipId
21 | {
22 | return $this->shipId;
23 | }
24 |
25 | public function getModel(): string
26 | {
27 | return $this->model;
28 | }
29 |
30 | public function getImageUrl(): ?string
31 | {
32 | return $this->imageUrl;
33 | }
34 |
35 | public function getQuantity(): int
36 | {
37 | return $this->quantity;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Application/Home/NumbersService.php:
--------------------------------------------------------------------------------
1 | userRepository->countUsers(),
23 | $this->organizationFleetRepository->countFleets(),
24 | $this->fleetRepository->countShips(),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/Output/PriceOutput.php:
--------------------------------------------------------------------------------
1 | getPledge() !== null ? $price->getPledge()->getAmount() : null,
26 | $price->getIngame() !== null ? $price->getIngame()->getAmount() : null,
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/MyFleet/Input/CreateShipFromTemplateInput.php:
--------------------------------------------------------------------------------
1 |
5 | Patch Note Create
6 |
7 | Back to the list
8 |
9 |
19 |
20 | {% endblock %}
21 |
22 | {% block javascripts %}
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/CreateShipService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
22 | if ($fleet === null) {
23 | $fleet = new Fleet($userId, $this->clock->now());
24 | }
25 |
26 | $fleet->addShip($shipId, $model, $imageUrl, $quantity ?? 1, $this->clock->now());
27 |
28 | $this->fleetRepository->save($fleet);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Infrastructure/Provider/Organizations/InMemoryMemberProfileProvider.php:
--------------------------------------------------------------------------------
1 | memberProfiles = [];
19 | foreach ($memberProfiles as $memberProfile) {
20 | $this->memberProfiles[(string) $memberProfile->getId()] = $memberProfile;
21 | }
22 | }
23 |
24 | /**
25 | * {@inheritDoc}
26 | */
27 | public function getProfiles(array $memberIds): array
28 | {
29 | return $this->memberProfiles;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Service/PayPal/MockVerifyWebhookSignatureFactory.php:
--------------------------------------------------------------------------------
1 | verifyWebhookSignature = new VerifyWebhookSignature();
17 | }
18 |
19 | public function setVerifyWebhookSignature(VerifyWebhookSignature $verifyWebhookSignature): void
20 | {
21 | $this->verifyWebhookSignature = $verifyWebhookSignature;
22 | }
23 |
24 | public function createVerifyWebhookSignature(Request $request): VerifyWebhookSignature
25 | {
26 | return $this->verifyWebhookSignature;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotFoundShipException.php:
--------------------------------------------------------------------------------
1 | fieldHandle = $fieldHandle;
19 | $this->fieldExcludeUserId = $fieldExcludeUserId;
20 | $this->message = $message ?? 'This handle is already taken.';
21 | }
22 |
23 | public function getTargets(): string
24 | {
25 | return Constraint::CLASS_CONSTRAINT;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/templates/back_office/patch_note/edit.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'back_office_layout.html.twig' %}
2 |
3 | {% block body %}
4 |
20 | {% endblock %}
21 |
22 | {% block javascripts %}
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/src/Application/Profile/PublicProfilesService.php:
--------------------------------------------------------------------------------
1 | userRepository->getByIds($userIds);
24 |
25 | $result = [];
26 | foreach ($users as $user) {
27 | $result[] = new PublicProfileOutput(
28 | $user->getId(),
29 | $user->getNickname(),
30 | $user->getHandle(),
31 | );
32 | }
33 |
34 | return $result;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationsItemOutput.php:
--------------------------------------------------------------------------------
1 | pictureUrl ?? 'http', 'http');
28 | Assert::lengthBetween($this->model, 2, 60);
29 | Assert::maxLength($this->pictureUrl, 1023);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Controller/Funding/MyBackingsController.php:
--------------------------------------------------------------------------------
1 | denyAccessUnlessGranted('ROLE_USER');
22 |
23 | /** @var User $user */
24 | $user = $this->getUser();
25 |
26 | $fundings = $this->fundingRepository->findBy(['user' => $user]);
27 |
28 | return $this->json($fundings, 200, [], ['groups' => 'my_backings']);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotFounderOfOrganizationException.php:
--------------------------------------------------------------------------------
1 | getThrowable();
20 | if (!$e instanceof DomainException) {
21 | return;
22 | }
23 |
24 | $data = array_merge([
25 | 'error' => $e->error,
26 | 'errorMessage' => $e->userMessage,
27 | ], $e->context);
28 |
29 | $event->setResponse(
30 | new JsonResponse($this->serializer->serialize($data, 'json'), 400, [], true)
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Validator/Constraints/UniqueFieldValidator.php:
--------------------------------------------------------------------------------
1 | entityManager->getRepository($constraint->entityClass);
22 | $foundEntity = $repo->findOneBy([$constraint->field => $value]);
23 | if ($foundEntity === null) {
24 | return;
25 | }
26 |
27 | $this->context->buildViolation($constraint->message)->addViolation();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/docker/php/www.dev.conf:
--------------------------------------------------------------------------------
1 | [www]
2 | user = www-data
3 | group = www-data
4 | listen = 127.0.0.1:9000
5 |
6 | ; https://symfony.com/blog/logging-in-symfony-and-the-cloud
7 | catch_workers_output = yes
8 | decorate_workers_output = no
9 | access.log = /proc/self/fd/2
10 | access.format='{"time_local":"%{%Y-%m-%dT%H:%M:%S%z}T","client_ip":"%{HTTP_X_FORWARDED_FOR}e","remote_addr":"%R","remote_user":"%u","request":"%m %{REQUEST_URI}e %{SERVER_PROTOCOL}e","status":"%s","body_bytes_sent":"%l","request_time":"%d","http_referrer":"%{HTTP_REFERER}e","http_user_agent":"%{HTTP_USER_AGENT}e","request_id":"%{HTTP_X_REQUEST_ID}e"}'
11 | ; slowlog = /app/var/log/php/$pool.slow.log
12 | ; request_slowlog_timeout = 3s
13 | request_terminate_timeout = 120s
14 |
15 | pm = dynamic
16 | pm.max_children = 8
17 | pm.start_servers = 3
18 | pm.min_spare_servers = 2
19 | pm.max_spare_servers = 4
20 | pm.max_requests = 300
21 |
22 | ; Web-UI
23 | ; pm.status_path = /status
24 | ; Healthcheck
25 | ; ping.path = /ping
26 |
27 | security.limit_extensions = .php
28 |
--------------------------------------------------------------------------------
/docker/php/www.prod.conf:
--------------------------------------------------------------------------------
1 | [www]
2 | user = www-data
3 | group = www-data
4 | listen = 127.0.0.1:9000
5 |
6 | ; https://symfony.com/blog/logging-in-symfony-and-the-cloud
7 | catch_workers_output = yes
8 | decorate_workers_output = no
9 | access.log = /proc/self/fd/2
10 | access.format='{"time_local":"%{%Y-%m-%dT%H:%M:%S%z}T","client_ip":"%{HTTP_X_FORWARDED_FOR}e","remote_addr":"%R","remote_user":"%u","request":"%m %{REQUEST_URI}e %{SERVER_PROTOCOL}e","status":"%s","body_bytes_sent":"%l","request_time":"%d","http_referrer":"%{HTTP_REFERER}e","http_user_agent":"%{HTTP_USER_AGENT}e","request_id":"%{HTTP_X_REQUEST_ID}e"}'
11 | ; slowlog = /app/var/log/php/$pool.slow.log
12 | ; request_slowlog_timeout = 3s
13 | request_terminate_timeout = 120s
14 |
15 | pm = dynamic
16 | pm.max_children = 8
17 | pm.start_servers = 3
18 | pm.min_spare_servers = 2
19 | pm.max_spare_servers = 4
20 | pm.max_requests = 300
21 |
22 | ; Web-UI
23 | ; pm.status_path = /status
24 | ; Healthcheck
25 | ; ping.path = /ping
26 |
27 | security.limit_extensions = .php
28 |
--------------------------------------------------------------------------------
/src/Application/Profile/ProfileService.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
20 | if ($user === null) {
21 | throw new NotFoundUserException($userId);
22 | }
23 |
24 | return new ProfileOutput(
25 | $userId,
26 | $user->getAuth0Username(),
27 | $user->getNickname(),
28 | $user->getHandle(),
29 | $user->isSupporterVisible(),
30 | $user->getCoins(),
31 | $user->getCreatedAt(),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/config/packages/psr_http_message_bridge.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | _defaults:
3 | autowire: true
4 | autoconfigure: true
5 |
6 | Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface:
7 | '@Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory'
8 |
9 | Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface:
10 | '@Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory'
11 |
12 | Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory: null
13 | Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory: null
14 |
15 | # Uncomment the following line to allow controllers to receive a
16 | # PSR-7 server request object instead of an HttpFoundation request
17 | #Symfony\Bridge\PsrHttpMessage\ArgumentValueResolver\PsrServerRequestResolver: null
18 |
19 | # Uncomment the following line to allow controllers to return a
20 | # PSR-7 response object instead of an HttpFoundation response
21 | #Symfony\Bridge\PsrHttpMessage\EventListener\PsrResponseListener: null
22 |
--------------------------------------------------------------------------------
/src/Domain/Exception/FounderOfOrganizationException.php:
--------------------------------------------------------------------------------
1 | patchNoteRepository->findBy([], ['createdAt' => 'DESC']);
23 |
24 | return $this->render('back_office/patch_note/list.html.twig', [
25 | 'patch_notes' => $patchNotes,
26 | ]);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Entity/ShipSize.php:
--------------------------------------------------------------------------------
1 | size = $size;
22 | }
23 |
24 | public function getSize(): ?string
25 | {
26 | return $this->size;
27 | }
28 |
29 | public static function unknown(): self
30 | {
31 | return new self(null);
32 | }
33 |
34 | public static function __callStatic(string $name, array $arguments): self
35 | {
36 | if (!in_array($name, self::SIZES, true)) {
37 | throw new \RuntimeException(sprintf('static method %s does not exist.', $name));
38 | }
39 |
40 | return new self($name);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Domain/Exception/NotJoinedOrganizationMemberException.php:
--------------------------------------------------------------------------------
1 | pledge = $pledge !== null ? $pledge->getAmount() : null;
26 | $this->ingame = $ingame !== null ? $ingame->getAmount() : null;
27 | }
28 |
29 | public function getPledge(): ?Money
30 | {
31 | return $this->pledge !== null ? Money::USD($this->pledge) : null;
32 | }
33 |
34 | public function getIngame(): ?Money
35 | {
36 | return $this->ingame !== null ? Money::UEC($this->ingame) : null;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Domain/Exception/AlreadyMemberOfOrganizationException.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
22 | if ($user === null) {
23 | throw new NotFoundUserException($userId);
24 | }
25 |
26 | $patchNoteId = $this->patchNoteRepository->getOneRecentPatchNoteId($user->getLastPatchNoteReadAt());
27 |
28 | return new HasNewPatchNoteOutput($patchNoteId !== null);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/DeleteShipService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
27 | if ($fleet === null) {
28 | throw new NotFoundFleetByUserException($userId);
29 | }
30 |
31 | $fleet->deleteShip($shipId, $this->clock->now());
32 |
33 | $this->fleetRepository->save($fleet);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Domain/Exception/FullyJoinedMemberOfOrganizationException.php:
--------------------------------------------------------------------------------
1 | profilesService->handle($memberIds);
23 |
24 | $result = [];
25 | foreach ($profiles as $profile) {
26 | $result[(string) $profile->id] = new MemberProfile(
27 | MemberId::fromString((string) $profile->id),
28 | $profile->nickname,
29 | $profile->handle,
30 | );
31 | }
32 |
33 | return $result;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/config/services_test.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | _defaults:
3 | autowire: true
4 | autoconfigure: true
5 | public: true
6 |
7 | App\Application\:
8 | resource: '../src/Application'
9 | exclude:
10 | - '../src/Application/**/*/Input'
11 | - '../src/Application/**/*/Output'
12 | - '../src/Application/Exception'
13 | - '../src/Infrastructure/**/*/Input'
14 |
15 | App\Tests\Service\PayPal\MockPayPalHttpClient: ~
16 | App\Tests\Service\PayPal\MockVerifyWebhookSignatureFactory: ~
17 | App\Service\Funding\PaypalCheckout:
18 | arguments:
19 | $client: '@App\Tests\Service\PayPal\MockPayPalHttpClient'
20 | $verifyWebhookSignatureFactory: '@App\Tests\Service\PayPal\MockVerifyWebhookSignatureFactory'
21 |
22 | App\Infrastructure\Security\FakeAuth0Service:
23 | parent: 'jwt_auth.auth0_service'
24 | Auth0\JWTAuthBundle\Security\Auth0Service: '@App\Infrastructure\Security\FakeAuth0Service'
25 |
26 | App\Application\Repository\Auth0RepositoryInterface: '@App\Infrastructure\Repository\User\FakeAuth0Repository'
27 |
--------------------------------------------------------------------------------
/config/packages/dev/monolog.yaml:
--------------------------------------------------------------------------------
1 | parameters:
2 | env(MONOLOG_MAILER_TO_0): 'root@localhost'
3 |
4 | monolog:
5 | handlers:
6 | main:
7 | type: stream
8 | path: "php://stderr"
9 | level: debug
10 | channels: [ "!event" ]
11 | console:
12 | type: console
13 | process_psr_3_messages: false
14 | channels: ["!event", "!doctrine", "!console"]
15 | ##########################
16 | fingers:
17 | type: fingers_crossed
18 | action_level: error
19 | handler: dedup_mail
20 | buffer_size: 50
21 | dedup_mail:
22 | type: deduplication
23 | time: 5
24 | store: '/tmp/monolog_handler_deduplicated'
25 | handler: mailer
26 | mailer:
27 | type: symfony_mailer
28 | from_email: 'noreply@fleet-manager.space'
29 | to_email: '%env(MONOLOG_MAILER_TO_0)%'
30 | subject: '[FM API %kernel.environment%] Error : %%message%%'
31 | formatter: monolog.formatter.html
32 | content_type: text/html
33 |
--------------------------------------------------------------------------------
/migrations/Version20210413195714.php:
--------------------------------------------------------------------------------
1 | addSql('CREATE TABLE memberships (member_id UUID NOT NULL, organization_id UUID NOT NULL, joined BOOLEAN DEFAULT \'false\' NOT NULL, PRIMARY KEY(member_id, organization_id))');
13 | $this->addSql('CREATE INDEX IDX_865A477632C8A3DE ON memberships (organization_id)');
14 | $this->addSql('COMMENT ON COLUMN memberships.member_id IS \'(DC2Type:ulid)\'');
15 | $this->addSql('COMMENT ON COLUMN memberships.organization_id IS \'(DC2Type:ulid)\'');
16 | $this->addSql('ALTER TABLE memberships ADD CONSTRAINT FK_865A477632C8A3DE FOREIGN KEY (organization_id) REFERENCES organizations (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
17 | }
18 |
19 | public function down(Schema $schema): void
20 | {
21 | $this->addSql('CREATE SCHEMA public');
22 | $this->addSql('DROP TABLE memberships');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationsItemFleetShipsOutput.php:
--------------------------------------------------------------------------------
1 | getModel(),
30 | $ship->getImageUrl(),
31 | $ship->getQuantity(),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/MyOrganizationsItemOutput.php:
--------------------------------------------------------------------------------
1 | new feature.")
21 | */
22 | public string $body,
23 | /**
24 | * @OpenApi\Property(type="string", format="url", nullable=true, example="https://blog.fleet-manager.space/new-feature-released")
25 | */
26 | public ?string $link,
27 | /**
28 | * @OpenApi\Property(type="string", format="date-time")
29 | */
30 | public \DateTimeInterface $createdAt,
31 | ) {
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/config/packages/nyholm_psr7.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | # Register nyholm/psr7 services for autowiring with PSR-17 (HTTP factories)
3 | Psr\Http\Message\RequestFactoryInterface: '@nyholm.psr7.psr17_factory'
4 | Psr\Http\Message\ResponseFactoryInterface: '@nyholm.psr7.psr17_factory'
5 | Psr\Http\Message\ServerRequestFactoryInterface: '@nyholm.psr7.psr17_factory'
6 | Psr\Http\Message\StreamFactoryInterface: '@nyholm.psr7.psr17_factory'
7 | Psr\Http\Message\UploadedFileFactoryInterface: '@nyholm.psr7.psr17_factory'
8 | Psr\Http\Message\UriFactoryInterface: '@nyholm.psr7.psr17_factory'
9 |
10 | # Register nyholm/psr7 services for autowiring with HTTPlug factories
11 | Http\Message\MessageFactory: '@nyholm.psr7.httplug_factory'
12 | Http\Message\RequestFactory: '@nyholm.psr7.httplug_factory'
13 | Http\Message\ResponseFactory: '@nyholm.psr7.httplug_factory'
14 | Http\Message\StreamFactory: '@nyholm.psr7.httplug_factory'
15 | Http\Message\UriFactory: '@nyholm.psr7.httplug_factory'
16 |
17 | nyholm.psr7.psr17_factory:
18 | class: Nyholm\Psr7\Factory\Psr17Factory
19 |
20 | nyholm.psr7.httplug_factory:
21 | class: Nyholm\Psr7\Factory\HttplugFactory
22 |
--------------------------------------------------------------------------------
/src/Domain/Notification/FeedbackNotification.php:
--------------------------------------------------------------------------------
1 | format('Y-m-d');
21 | parent::__construct(<<setName('app:delete-old-created-funding');
22 | }
23 |
24 | protected function execute(InputInterface $input, OutputInterface $output): int
25 | {
26 | $io = new SymfonyStyle($input, $output);
27 |
28 | $answer = $io->askQuestion(new ConfirmationQuestion('Would you really want to delete old created fundings?', false));
29 | if ($answer) {
30 | $this->fundingRepository->deleteOldCreated(new \DateTimeImmutable('-1 week'));
31 | }
32 |
33 | return 0;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/Output/MyFleetShipOutput.php:
--------------------------------------------------------------------------------
1 | shipTemplateRepository->getTemplateById($templateId);
22 | if ($template !== null && $template->getAuthorId()->equals(TemplateAuthorId::fromString((string)$userId))) {
23 | return new UserShipTemplate(
24 | $template->getId(),
25 | $template->getModel(),
26 | $template->getPictureUrl(),
27 | );
28 | }
29 |
30 | return null;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Listener/Funding/UpdateSupporterAdvantagesListener.php:
--------------------------------------------------------------------------------
1 | getFunding();
21 |
22 | $user = $updatedFunding->getUser();
23 | if ($user === null) {
24 | return;
25 | }
26 |
27 | // recompute all FM Coins balance
28 | /** @var Funding[] $fundings */
29 | $fundings = $this->fundingRepository->findBy(['user' => $user, 'paypalStatus' => ['COMPLETED', 'PARTIALLY_REFUNDED']]);
30 | $balance = 0;
31 | foreach ($fundings as $funding) {
32 | $balance += $funding->getEffectiveAmount();
33 | }
34 | $user->setCoins($balance);
35 | $this->entityManager->flush();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/config/packages/messenger.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | messenger:
3 | serializer:
4 | default_serializer: messenger.transport.symfony_serializer
5 | symfony_serializer:
6 | format: json
7 | context: { }
8 | default_bus: event.bus
9 | buses:
10 | event.bus: ~
11 | # default_middleware: allow_no_handlers
12 | failure_transport: failed
13 | transports:
14 | failed: '%env(MESSENGER_TRANSPORT_FAILED_DSN)%'
15 | organizations_sub:
16 | dsn: '%env(MESSENGER_TRANSPORT_ORGANIZATIONS_SUB_DSN)%'
17 | retry_strategy:
18 | max_retries: 3
19 | delay: 1000
20 | multiplier: 2
21 | max_delay: 0
22 | my_fleet_internal: 'sync://'
23 | sync: 'sync://'
24 |
25 | routing:
26 | 'App\Message\Funding\SendOrderCaptureSummaryMail': sync
27 | 'App\Message\Funding\SendOrderRefundMail': sync
28 | 'App\Domain\Event\DeletedUserEvent': [ my_fleet_internal, organizations_sub ]
29 | 'App\Domain\Event\UpdatedFleetEvent': [ organizations_sub ]
30 |
--------------------------------------------------------------------------------
/docker/php/php-fpm-fcgi.prod.ini:
--------------------------------------------------------------------------------
1 | expose_php = Off
2 |
3 | max_execution_time = 30
4 | max_input_time = 60
5 | memory_limit = 1536M
6 | error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
7 | display_errors = Off
8 | display_startup_errors = Off
9 |
10 | post_max_size = 5M
11 | file_uploads = On
12 | upload_tmp_dir = /tmp
13 | upload_max_filesize = 5M
14 | max_file_uploads = 20
15 |
16 | date.timezone = UTC
17 |
18 | session.auto_start = Off
19 | session.name = PHPSESSID
20 | session.gc_probability = 1
21 | session.gc_divisor = 1000
22 |
23 | opcache.enable=1
24 | opcache.enable_cli=0
25 | opcache.memory_consumption=256
26 | opcache.interned_strings_buffer=32
27 | opcache.max_accelerated_files=16229
28 | opcache.validate_timestamps=0
29 | opcache.revalidate_path=1
30 | opcache.save_comments=1
31 | opcache.fast_shutdown=1
32 | opcache.max_wasted_percentage=5
33 | opcache.enable_file_override=1
34 | ;opcache.error_log=/var/log/php/opcache-error.log
35 | opcache.error_log=/proc/self/fd/2
36 | opcache.log_verbosity_level=2
37 | opcache.preload_user=www-data
38 | opcache.preload=/app/config/preload.php
39 |
40 | realpath_cache_size = 4096K
41 | realpath_cache_ttl = 600
42 |
43 | ;error_log = /var/log/php/error.log
44 | error_log = /proc/self/fd/2
45 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/Output/OrganizationsItemWithFleetOutput.php:
--------------------------------------------------------------------------------
1 | addSql('CREATE TABLE organizations (id UUID NOT NULL, founder_id UUID NOT NULL, name VARCHAR(32) NOT NULL, sid VARCHAR(15) NOT NULL, logo_url VARCHAR(1023) DEFAULT NULL, updated_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, version INT DEFAULT 1 NOT NULL, PRIMARY KEY(id))');
13 | $this->addSql('CREATE UNIQUE INDEX UNIQ_427C1C7F57167AB4 ON organizations (sid)');
14 | $this->addSql('CREATE INDEX founder_idx ON organizations (founder_id)');
15 | $this->addSql('COMMENT ON COLUMN organizations.id IS \'(DC2Type:ulid)\'');
16 | $this->addSql('COMMENT ON COLUMN organizations.founder_id IS \'(DC2Type:ulid)\'');
17 | $this->addSql('COMMENT ON COLUMN organizations.updated_at IS \'(DC2Type:datetimetz_immutable)\'');
18 | }
19 |
20 | public function down(Schema $schema): void
21 | {
22 | $this->addSql('CREATE SCHEMA public');
23 | $this->addSql('DROP TABLE organizations');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/UpdateShipService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
29 | if ($fleet === null) {
30 | throw new NotFoundFleetByUserException($userId);
31 | }
32 |
33 | $fleet->updateShip($shipId, $name, $imageUrl, $quantity, $this->clock->now());
34 |
35 | $this->fleetRepository->save($fleet);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Form/PatchNoteForm.php:
--------------------------------------------------------------------------------
1 | add('title', TextType::class, [
19 | 'required' => true,
20 | ])
21 | ->add('body', TextareaType::class, [
22 | 'required' => true,
23 | ])
24 | ->add('link', UrlType::class, [
25 | 'required' => false,
26 | ]);
27 | }
28 |
29 | public function configureOptions(OptionsResolver $resolver): void
30 | {
31 | $resolver->setDefaults([
32 | 'data_class' => PatchNote::class,
33 | 'allow_extra_fields' => true,
34 | 'csrf_protection' => true,
35 | ]);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/fixtures/monthly_cost_coverage.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\MonthlyCostCoverage:
2 | default:
3 | __construct:
4 | - '<(new \App\Domain\MonthlyCostCoverageId(\Symfony\Component\Uid\Ulid::fromString("01F17Y8TPE5JBC6RNM3DVVMD11")))>'
5 | - '<(new \DateTimeImmutable("1970-01-01 00:00:00"))>'
6 | target: 10000 # $100.00
7 | postpone: true
8 | last_month:
9 | __construct:
10 | - '<(new \App\Domain\MonthlyCostCoverageId(\Symfony\Component\Uid\Ulid::fromString("01F17YAEF6VZ9J951XCQTZRW2K")))>'
11 | - '<(new \DateTimeImmutable("first day of last month"))>'
12 | target: 20000
13 | postpone: false
14 | this_month:
15 | __construct:
16 | - '<(new \App\Domain\MonthlyCostCoverageId(\Symfony\Component\Uid\Ulid::fromString("01F17YAH6WGESK19R9CPG7Z4D0")))>'
17 | - '<(new \DateTimeImmutable("first day of"))>'
18 | target: 15000
19 | postpone: true
20 | next_month:
21 | __construct:
22 | - '<(new \App\Domain\MonthlyCostCoverageId(\Symfony\Component\Uid\Ulid::fromString("01F17YAMEJEDDMCE4R2NHZ5A34")))>'
23 | - '<(new \DateTimeImmutable("first day of next month"))>'
24 | target: 20000
25 | postpone: false
26 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/UpdateOrganizationService.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganization($orgaId);
23 | if ($organization === null) {
24 | throw new NotFoundOrganizationException($orgaId);
25 | }
26 | if (!$organization->isFounder($founderId)) {
27 | throw new NotFounderOfOrganizationException($orgaId, $founderId);
28 | }
29 |
30 | $organization->update($name, $logoUrl, $this->clock->now());
31 |
32 | $this->organizationRepository->save($organization);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/CreateTemplateService.php:
--------------------------------------------------------------------------------
1 | model,
26 | $input->pictureUrl,
27 | $input->chassis,
28 | $input->manufacturer,
29 | $input->size,
30 | $input->role,
31 | $input->cargoCapacity,
32 | $input->crew,
33 | $input->price,
34 | $this->clock->now(),
35 | );
36 |
37 | $this->shipTemplateRepository->save($template);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/docker/php/php-fpm-fcgi.dev.ini:
--------------------------------------------------------------------------------
1 | expose_php = Off
2 |
3 | max_execution_time = 30
4 | max_input_time = 60
5 | memory_limit = 1536M
6 | error_reporting = E_ALL
7 | display_errors = On
8 | display_startup_errors = On
9 |
10 | post_max_size = 5M
11 | file_uploads = On
12 | upload_tmp_dir = /tmp
13 | upload_max_filesize = 5M
14 | max_file_uploads = 20
15 |
16 | date.timezone = UTC
17 |
18 | session.auto_start = Off
19 | session.name = PHPSESSID
20 | session.gc_probability = 1
21 | session.gc_divisor = 1000
22 |
23 | opcache.enable=1
24 | opcache.enable_cli=0
25 | opcache.memory_consumption=256
26 | opcache.interned_strings_buffer=32
27 | opcache.max_accelerated_files=16229
28 | opcache.validate_timestamps=1
29 | opcache.revalidate_freq=0
30 | opcache.revalidate_path=1
31 | opcache.save_comments=1
32 | opcache.fast_shutdown=1
33 | opcache.max_wasted_percentage=5
34 | opcache.enable_file_override=1
35 | ;opcache.error_log=/var/log/php/opcache-error.log
36 | opcache.error_log=/proc/self/fd/2
37 | opcache.log_verbosity_level=2
38 | ;opcache.preload_user=www-data
39 | ;opcache.preload=/app/var/cache/dev/App_KernelDevDebugContainer.preload.php
40 |
41 | realpath_cache_size = 4096K
42 | realpath_cache_ttl = 600
43 |
44 | ;error_log = /var/log/php/error.log
45 | error_log = /proc/self/fd/2
46 |
--------------------------------------------------------------------------------
/src/Entity/Manufacturer.php:
--------------------------------------------------------------------------------
1 | name = $name;
33 | $this->code = $code;
34 | if ($this->code !== null) {
35 | $this->code = u($this->code)->upper();
36 | }
37 | }
38 |
39 | public function getName(): ?string
40 | {
41 | return $this->name;
42 | }
43 |
44 | public function getCode(): ?string
45 | {
46 | return $this->code;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Application/Support/GiveFeedbackService.php:
--------------------------------------------------------------------------------
1 | userRepository->getById($userId);
23 | if ($user === null) {
24 | throw new NotFoundUserException($userId);
25 | }
26 |
27 | $this->notifier->send(new FeedbackNotification(
28 | $description,
29 | $user->getNickname(),
30 | $user->getCoins(),
31 | $profile->getEmail(),
32 | $profile->getDiscordId(),
33 | $user->getCreatedAt(),
34 | $email,
35 | $discordId,
36 | ));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Service/Funding/VerifyWebhookSignatureFactory.php:
--------------------------------------------------------------------------------
1 | webhookId = $webhookId;
15 | }
16 |
17 | public function createVerifyWebhookSignature(Request $request): VerifyWebhookSignature
18 | {
19 | $signatureVerification = new VerifyWebhookSignature();
20 | $signatureVerification->setAuthAlgo($request->headers->get('paypal-auth-algo'));
21 | $signatureVerification->setTransmissionId($request->headers->get('paypal-transmission-id'));
22 | $signatureVerification->setCertUrl($request->headers->get('paypal-cert-url'));
23 | $signatureVerification->setWebhookId($this->webhookId);
24 | $signatureVerification->setTransmissionSig($request->headers->get('paypal-transmission-sig'));
25 | $signatureVerification->setTransmissionTime($request->headers->get('paypal-transmission-time'));
26 | $signatureVerification->setRequestBody($request->getContent());
27 |
28 | return $signatureVerification;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Infrastructure/Service/InMemoryEntityIdGenerator.php:
--------------------------------------------------------------------------------
1 | uid = '00000000-0000-0000-0000-000000000001';
17 | $this->callback = static function (string $oldUid): string {
18 | $n = hexdec(substr($oldUid, -12));
19 |
20 | return substr($oldUid, 0, -12).sprintf('%012s', dechex($n + 1));
21 | };
22 | }
23 |
24 | public function setUid(string $uid): void
25 | {
26 | Assert::uuid($uid);
27 | $this->uid = $uid;
28 | }
29 |
30 | public function setNextUidGenerator(callable $callback): void
31 | {
32 | $this->callback = $callback;
33 | }
34 |
35 | public function generateEntityId(string $class): EntityId
36 | {
37 | Assert::isAOf($class, EntityId::class);
38 |
39 | $id = $class::fromString($this->uid);
40 |
41 | $this->uid = ($this->callback)($this->uid);
42 |
43 | return $id;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/DisbandOrganizationService.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganization($orgaId);
23 | if ($organization === null) {
24 | throw new NotFoundOrganizationException($orgaId);
25 | }
26 | if (!$organization->isFounder($founderId)) {
27 | throw new NotFounderOfOrganizationException($orgaId, $founderId);
28 | }
29 |
30 | $this->organizationRepository->deleteAll([$orgaId]);
31 | $this->organizationFleetRepository->deleteAll([$orgaId]);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Infrastructure/Validator/UniqueOrganizationSidValidator.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganizationBySid($value);
27 | if ($orga === null) {
28 | return;
29 | }
30 | if ($constraint->excludeOrgaId !== null && $orga->getId()->equals($constraint->excludeOrgaId)) {
31 | // ignore if it's the excluded orgaId
32 | return;
33 | }
34 | $this->context->buildViolation($constraint->message)->addViolation();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/MyOrganizationsService.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganizationsByMember($memberId);
21 |
22 | return new MyOrganizationsOutput(
23 | array_map(static function (Organization $organization) use ($memberId): MyOrganizationsItemOutput {
24 | return new MyOrganizationsItemOutput(
25 | $organization->getId(),
26 | $organization->getName(),
27 | $organization->getSid(),
28 | $organization->getLogoUrl(),
29 | $organization->hasJoined($memberId),
30 | );
31 | }, $organizations),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Entity/Crew.php:
--------------------------------------------------------------------------------
1 | min = $min !== null ? (string) $min : null;
35 | $this->max = $max !== null ? (string) $max : null;
36 | }
37 |
38 | public function getMin(): ?int
39 | {
40 | return $this->min !== null ? (int) $this->min : null;
41 | }
42 |
43 | public function getMax(): ?int
44 | {
45 | return $this->max !== null ? (int) $this->max : null;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/migrations/Version20210522155300.php:
--------------------------------------------------------------------------------
1 | addSql('CREATE TABLE organization_fleet_member_versions (member_id UUID NOT NULL, organization_fleet_id UUID NOT NULL, version INT DEFAULT 1 NOT NULL, PRIMARY KEY(member_id, organization_fleet_id))');
13 | $this->addSql('CREATE INDEX IDX_BC393CAA41EDF5B ON organization_fleet_member_versions (organization_fleet_id)');
14 | $this->addSql('COMMENT ON COLUMN organization_fleet_member_versions.member_id IS \'(DC2Type:ulid)\'');
15 | $this->addSql('COMMENT ON COLUMN organization_fleet_member_versions.organization_fleet_id IS \'(DC2Type:ulid)\'');
16 | $this->addSql('ALTER TABLE organization_fleet_member_versions ADD CONSTRAINT FK_BC393CAA41EDF5B FOREIGN KEY (organization_fleet_id) REFERENCES organization_fleets (orga_id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
17 | }
18 |
19 | public function down(Schema $schema): void
20 | {
21 | $this->addSql('CREATE SCHEMA public');
22 | $this->addSql('DROP TABLE organization_fleet_member_versions');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/Home/NumbersController.php:
--------------------------------------------------------------------------------
1 | numbersService->handle();
32 |
33 | $json = $this->serializer->serialize($output, 'json');
34 |
35 | return (new JsonResponse($json, 200, [], true))->setSharedMaxAge(300);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/config/packages/jwt_auth.yaml:
--------------------------------------------------------------------------------
1 | jwt_auth:
2 | # The domain of your registered Auth0 tenant.
3 | domain: "%env(AUTH0_DOMAIN)%"
4 | # The client ID string of your registered Auth0 application.
5 | client_id: "%env(AUTH0_CLIENT_ID)%"
6 | # The audience/identifier string of your registered Auth0 API.
7 | audience: "%env(AUTH0_API_AUDIENCE)%"
8 |
9 | # Defaults to RS256. Supported options are RS256 or HS256.
10 | algorithm: "RS256"
11 | # If you're using HS256, you need to provide the client secret for your registered Auth0 application.
12 | # client_secret: "%env(AUTH0_CLIENT_SECRET)%"
13 |
14 | cache: "cache.app"
15 |
16 | # Token validations to run during JWT decoding:
17 | validations:
18 | # Validate AUD claim against a value, such as an API identifier. Set to false to skip. Defaults to jwt_auth.audience.
19 | aud: "%env(AUTH0_API_AUDIENCE)%"
20 | # Validate the AZP claim against a value, such as a client ID. Set to false to skip. Defaults to false.
21 | azp: "%env(AUTH0_CLIENT_ID)%"
22 | # Maximum age (in seconds) since the auth_time of the token. Set to false to skip. Defaults to false.
23 | max_age: 3600
24 | # Clock tolerance (in seconds) for token expiration checks. Requires an integer value. Defaults to 60 seconds.
25 | leeway: 60
26 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/MyFleetService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
22 | if ($fleet === null) {
23 | throw new NotFoundFleetByUserException($userId);
24 | }
25 |
26 | $shipOutputItems = [];
27 | foreach ($fleet->getShips() as $ship) {
28 | $shipOutputItems[] = new MyFleetShipOutput($ship->getId(), $ship->getModel(), $ship->getImageUrl(), $ship->getQuantity(), $ship->getTemplateId());
29 | }
30 |
31 | return new MyFleetOutput(
32 | ships: new MyFleetShipsCollectionOutput(items: $shipOutputItems, count: count($shipOutputItems)),
33 | updatedAt: $fleet->getUpdatedAt(),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Application/Repository/OrganizationRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | import('../config/{packages}/*.{yaml,php}');
17 | $container->import('../config/{packages}/'.$this->environment.'/*.{yaml,php}');
18 |
19 | $container->import('../config/services.yaml');
20 | $container->import('../config/{services}_'.$this->environment.'.yaml');
21 | }
22 |
23 | protected function configureRoutes(RoutingConfigurator $routes): void
24 | {
25 | $routes->import('../config/{routes}/'.$this->environment.'/*.yaml');
26 | $routes->import('../config/{routes}/*.yaml');
27 | }
28 |
29 | public function getBuildDir(): string
30 | {
31 | if (isset($_SERVER['APP_BUILD_DIR'])) {
32 | return $_SERVER['APP_BUILD_DIR'].'/'.$this->environment;
33 | }
34 |
35 | return $this->getProjectDir().'/var/build/'.$this->environment;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | tests/Unit
20 |
21 |
22 | tests/Acceptance
23 |
24 |
25 | tests/Integration
26 |
27 |
28 | tests/End2End
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/MyFleet/ClearMyFleetController.php:
--------------------------------------------------------------------------------
1 | security->isGranted('ROLE_USER')) {
30 | throw new AccessDeniedException();
31 | }
32 |
33 | /** @var User $user */
34 | $user = $this->security->getUser();
35 |
36 | $this->clearMyFleetService->handle($user->getId());
37 |
38 | return new Response(null, 204);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Application/ShipTemplate/Output/ListTemplatesItemOutput.php:
--------------------------------------------------------------------------------
1 | templates[(string) $templateId] ?? null;
18 | }
19 |
20 | public function save(ShipTemplate $template): void
21 | {
22 | $this->templates[(string) $template->getId()] = $template;
23 | }
24 |
25 | /**
26 | * {@inheritDoc}
27 | */
28 | public function getTemplatesOfAuthor(TemplateAuthorId $authorId): array
29 | {
30 | $templates = array_values(array_filter($this->templates, static function (ShipTemplate $template) use ($authorId): bool {
31 | return $template->getAuthorId()->equals($authorId);
32 | }));
33 | usort($templates, static function (ShipTemplate $template1, ShipTemplate $template2): int {
34 | return $template1->getModel() <=> $template2->getModel();
35 | });
36 |
37 | return $templates;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Infrastructure/Validator/CountOrganizationsLessThanValidator.php:
--------------------------------------------------------------------------------
1 | security->getUser();
31 | Assert::notNull($user);
32 |
33 | $orgas = $this->organizationRepository->getOrganizationsOfFounder(MemberId::fromString((string) $user->getId()));
34 | if (count($orgas) >= $constraint->max) {
35 | $this->context->buildViolation($constraint->message)->addViolation();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Entity/Membership.php:
--------------------------------------------------------------------------------
1 | memberId = $memberId->getId();
36 | $this->organization = $organization;
37 | $this->joined = $joined;
38 | }
39 |
40 | public function getMemberId(): MemberId
41 | {
42 | return new MemberId($this->memberId);
43 | }
44 |
45 | public function hasJoined(): bool
46 | {
47 | return $this->joined;
48 | }
49 |
50 | public function accept(): void
51 | {
52 | $this->joined = true;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/End2End/Controller/PatchNote/HasNewPatchNoteControllerTest.php:
--------------------------------------------------------------------------------
1 | executeStatement(<< 'application/json',
24 | 'HTTP_AUTHORIZATION' => 'Bearer '.static::generateToken('Ioni'),
25 | ]);
26 |
27 | static::assertSame(200, static::$client->getResponse()->getStatusCode());
28 | $json = static::json();
29 | static::assertSame([
30 | 'hasNewPatchNote' => true,
31 | ], $json);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/ImportFleetService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
28 | if ($fleet === null) {
29 | $fleet = new Fleet($userId, $this->clock->now());
30 | }
31 |
32 | $fleetShipImports = [];
33 | foreach ($importFleetShips as $importFleetShip) {
34 | $fleetShipImports[] = new FleetShipImport($importFleetShip->model);
35 | }
36 | $fleet->importShips($fleetShipImports, $onlyMissing, $this->clock->now(), $this->entityIdGenerator);
37 |
38 | $this->fleetRepository->save($fleet);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/Profile/Input/ChangeHandleInput.php:
--------------------------------------------------------------------------------
1 | handle = $data['handle'] ?? null;
31 | if ($this->handle !== null) {
32 | $this->handle = u($this->handle)->trim()->lower();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Serializer/EntityIdNormalizer.php:
--------------------------------------------------------------------------------
1 | symfony/framework-bundle ###
2 | APP_ENV=dev
3 | APP_SECRET=4b75b543292357158424363c5f2e8c6d
4 | ###< symfony/framework-bundle ###
5 |
6 | ###> sentry/sentry-symfony ###
7 | SENTRY_DSN=
8 | ###< sentry/sentry-symfony ###
9 |
10 | ###> symfony/mailer ###
11 | MAILER_DSN=smtp://smtp:25
12 | ###< symfony/mailer ###
13 |
14 | FUNDING_ORDER_CAPTURE_ADDRESSES=fleet-manager@protonmail.com
15 | MONOLOG_MAILER_TO_0=fleet-manager@protonmail.com
16 |
17 | ###> doctrine/doctrine-bundle ###
18 | DATABASE_URL="postgresql://postgres:root@postgres:5432/fleet_manager?serverVersion=13&charset=utf8"
19 | ###< doctrine/doctrine-bundle ###
20 |
21 | REDIS_DSN=redis://root@redis:6379
22 |
23 | PAYPAL_CHECKOUT_CLIENT_ID=
24 | PAYPAL_CHECKOUT_CLIENT_SECRET=
25 | PAYPAL_CHECKOUT_WEBHOOK_ID=
26 | PAYPAL_CHECKOUT_MODE=sandbox
27 |
28 | ###> symfony/messenger ###
29 | # MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
30 | MESSENGER_TRANSPORT_FAILED_DSN=doctrine://default?queue_name=failed
31 | MESSENGER_TRANSPORT_ORGANIZATIONS_SUB_DSN=doctrine://default?queue_name=organizations_events
32 | ###< symfony/messenger ###
33 |
34 | DEFAULT_URI=http://localhost:8000
35 |
36 | # Auth0 JWT
37 | AUTH0_DOMAIN=
38 | AUTH0_CLIENT_ID=
39 | AUTH0_API_AUDIENCE=
40 |
41 | AUTH0_CLIENT_ID_API=
42 | AUTH0_CLIENT_SECRET_API=
43 |
44 | ###> symfony/discord-notifier ###
45 | DISCORD_DSN=discord://TOKEN@default?webhook_id=ID
46 | ###< symfony/discord-notifier ###
47 |
--------------------------------------------------------------------------------
/migrations/Version20210506210323.php:
--------------------------------------------------------------------------------
1 | addSql('CREATE TABLE ship_templates (id UUID NOT NULL, author_id UUID NOT NULL, model VARCHAR(60) NOT NULL, image_url VARCHAR(1023) DEFAULT NULL, updated_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, version INT DEFAULT 1 NOT NULL, chassis_name VARCHAR(60) NOT NULL, manufacturer_name VARCHAR(50) DEFAULT NULL, manufacturer_code VARCHAR(5) DEFAULT NULL, ship_size_size VARCHAR(10) DEFAULT NULL, ship_role_role VARCHAR(30) DEFAULT NULL, cargo_capacity_capacity INT NOT NULL, crew_min NUMERIC(10, 0) DEFAULT NULL, crew_max NUMERIC(10, 0) DEFAULT NULL, price_pledge NUMERIC(12, 2) DEFAULT NULL, price_ingame NUMERIC(12, 2) DEFAULT NULL, PRIMARY KEY(id))');
13 | $this->addSql('COMMENT ON COLUMN ship_templates.id IS \'(DC2Type:ulid)\'');
14 | $this->addSql('COMMENT ON COLUMN ship_templates.author_id IS \'(DC2Type:ulid)\'');
15 | $this->addSql('COMMENT ON COLUMN ship_templates.updated_at IS \'(DC2Type:datetimetz_immutable)\'');
16 | }
17 |
18 | public function down(Schema $schema): void
19 | {
20 | $this->addSql('CREATE SCHEMA public');
21 | $this->addSql('DROP TABLE ship_templates');
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/Poubelle/BackOffice/PatchNote/PatchNoteCreateControllerTest.php:
--------------------------------------------------------------------------------
1 | client->request('GET', '/bo/patch-note/create');
17 |
18 | static::assertSame(403, $this->client->getResponse()->getStatusCode());
19 | }
20 |
21 | /**
22 | * @group functional
23 | * @group patch_note
24 | * @group bo
25 | */
26 | public function test_not_admin(): void
27 | {
28 | $this->client->request('GET', '/bo/patch-note/create', [], [], [
29 | 'HTTP_AUTHORIZATION' => 'Bearer '.static::generateToken('Gardien1'),
30 | ]);
31 |
32 | static::assertSame(403, $this->client->getResponse()->getStatusCode());
33 | }
34 |
35 | /**
36 | * @group functional
37 | * @group patch_note
38 | * @group bo
39 | */
40 | public function test_admin(): void
41 | {
42 | $this->client->request('GET', '/bo/patch-note/create', [], [], [
43 | 'HTTP_AUTHORIZATION' => 'Bearer '.static::generateToken('Ioni'),
44 | ]);
45 |
46 | static::assertSame(200, $this->client->getResponse()->getStatusCode());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
6 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
7 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
8 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
9 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
10 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true, 'test_acceptance' => true],
11 | Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true],
12 | Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['dev' => true],
13 | Hautelook\AliceBundle\HautelookAliceBundle::class => ['dev' => true],
14 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
15 | Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
16 | Sentry\SentryBundle\SentryBundle::class => ['prod' => true, 'beta' => true],
17 | Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
18 | Http\HttplugBundle\HttplugBundle::class => ['all' => true],
19 | Auth0\JWTAuthBundle\JWTAuthBundle::class => ['all' => true],
20 | Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['dev' => true],
21 | ];
22 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/ShipTemplate/Input/CreateTemplateManufacturerInput.php:
--------------------------------------------------------------------------------
1 | name = u($data['name'])->trim();
29 | }
30 | if (isset($data['code'])) {
31 | $this->code = u($data['code'])->trim()->upper();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/UnjoinOrganizationService.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganization($orgaId);
24 | if ($organization === null) {
25 | throw new NotFoundOrganizationException($orgaId);
26 | }
27 |
28 | if (!$organization->isMemberOf($memberId)) {
29 | throw new NotMemberOfOrganizationException($orgaId, $memberId);
30 | }
31 |
32 | if ($organization->hasJoined($memberId)) {
33 | throw new FullyJoinedMemberOfOrganizationException($orgaId, $memberId);
34 | }
35 |
36 | $organization->unjoinMember($memberId, $this->clock->now());
37 |
38 | $this->organizationRepository->save($organization);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/templates/back_office/funding/monthly_cost_coverage_create.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'back_office_layout.html.twig' %}
2 |
3 | {% block body %}
4 |
31 | {% endblock %}
32 |
33 | {% block javascripts %}
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], null, true)) {
24 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
25 | }
26 |
27 | if ($input->hasParameterOption('--no-debug', true)) {
28 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
29 | }
30 |
31 | (new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
32 |
33 | if ($_SERVER['APP_DEBUG']) {
34 | umask(0000);
35 |
36 | if (class_exists(Debug::class)) {
37 | Debug::enable();
38 | }
39 | }
40 |
41 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
42 | $application = new Application($kernel);
43 | $application->run($input);
44 |
--------------------------------------------------------------------------------
/src/Application/MyFleet/UpdateShipFromTemplateService.php:
--------------------------------------------------------------------------------
1 | fleetRepository->getFleetByUser($userId);
26 | if ($fleet === null) {
27 | $fleet = new Fleet($userId, $this->clock->now());
28 | }
29 |
30 | $template = $this->listTemplatesProvider->getShipTemplateOfUser($templateId, $userId);
31 | if ($template === null) {
32 | throw new NotFoundShipTemplateByUserException($userId, $templateId);
33 | }
34 |
35 | $fleet->updateShipFromTemplate($shipId, $template, $quantity ?? 1, $this->clock->now());
36 |
37 | $this->fleetRepository->save($fleet);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Application/MyOrganizations/OrganizationsService.php:
--------------------------------------------------------------------------------
1 | organizationRepository->getOrganizations($itemsPerPage, $sinceOrgaId, $searchQuery);
21 |
22 | return new OrganizationsCollectionOutput(
23 | array_map(static function (Organization $organization): OrganizationsItemOutput {
24 | return new OrganizationsItemOutput(
25 | $organization->getId(),
26 | $organization->getName(),
27 | $organization->getSid(),
28 | $organization->getLogoUrl(),
29 | );
30 | }, $organizations),
31 | count($organizations) === $itemsPerPage ? $baseUrl.'?sinceId='.end($organizations)->getId() : null,
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Infrastructure/Controller/Profile/DeleteAccountController.php:
--------------------------------------------------------------------------------
1 | security->isGranted('ROLE_USER')) {
32 | throw new AccessDeniedException();
33 | }
34 |
35 | /** @var User $user */
36 | $user = $this->security->getUser();
37 |
38 | $this->deleteAccount->handle($user->getId());
39 |
40 | return new Response(null, 204);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------