diff --git a/README.md b/README.md index 6220432d6181673b57046df2a4816cfb593950bf..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/README.md +++ b/README.md @@ -1,38 +0,0 @@ -Commands to set up Symfony with DB connection - -``` -php bin/console doctrine:database:create -php bin/console make:migration -php bin/console doctrine:migrations:migrate -``` - -Create an entity -``` -docker exec -it symfony_app php bin/console make:entity -``` -Update getters and setters in new properties where added manually -``` -docker exec -it symfony_app php bin/console make:entity --regenerate -``` - -Create migration file to apply in the dp -``` -docker exec -it symfony_app php bin/console make:migration -``` - -Apply the migration file in the db -``` -docker exec -it symfony_app php bin/console doctrine:migrations:migrate -``` - -Rollback to the previous migrate version -``` -php bin/console doctrine:migrations:migrate prev -``` - -To add sample data per dafault to the database (after finished editing DataFixtures/ files) -Note: Add the `--append` flag if you don't want to erase the records already created. -Also add `--group` to apply and specific file. -``` -php bin/console doctrine:fixtures:load -``` \ No newline at end of file diff --git a/server/.docker/nginx/default.conf b/server/.docker/nginx/default.conf new file mode 100644 index 0000000000000000000000000000000000000000..92f16aee22b560e3848da53e6d447bc7e755837a --- /dev/null +++ b/server/.docker/nginx/default.conf @@ -0,0 +1,20 @@ +server { + listen 80; + server_name localhost; + root /var/www/public; + + index index.php index.html; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php(/|$) { + fastcgi_pass app:9000; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } + + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; +} \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1842af95c8519e0cf8c9086b3a2f5e20c98ebb14 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,60 @@ +.DS_Store +Thumbs.db + +.env +.env.local +.env.*.local +/.vscode/ +/.idea/ +/nbproject/ + +/vendor/ +composer.lock + +# Caché y logs +/storage/logs/ +storage/framework/cache/ +storage/framework/sessions/ +storage/framework/views/ +bootstrap/cache/ + +*.log +*.cache +*.swp +*.bak +*.tmp + +Homestead.yaml +Homestead.json +Valet/ +.phpunit.result.cache + +public/uploads/ +storage/app/public/ + +*.sublime-project +*.sublime-workspace +/.vscode/ +/.idea/ +/nbproject/ + +node_modules/ +npm-debug.log +yarn-error.log + +phpunit.xml +phpunit.xml.dist +/tests/_output/ +tests/_support/_generated/ + +*.min.js +*.min.css +/build/ +dist/ + +.phpstorm.meta.php +/.phpunit.result.cache + +deploy/ + +mysql_data/ \ No newline at end of file diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6220432d6181673b57046df2a4816cfb593950bf --- /dev/null +++ b/server/README.md @@ -0,0 +1,38 @@ +Commands to set up Symfony with DB connection + +``` +php bin/console doctrine:database:create +php bin/console make:migration +php bin/console doctrine:migrations:migrate +``` + +Create an entity +``` +docker exec -it symfony_app php bin/console make:entity +``` +Update getters and setters in new properties where added manually +``` +docker exec -it symfony_app php bin/console make:entity --regenerate +``` + +Create migration file to apply in the dp +``` +docker exec -it symfony_app php bin/console make:migration +``` + +Apply the migration file in the db +``` +docker exec -it symfony_app php bin/console doctrine:migrations:migrate +``` + +Rollback to the previous migrate version +``` +php bin/console doctrine:migrations:migrate prev +``` + +To add sample data per dafault to the database (after finished editing DataFixtures/ files) +Note: Add the `--append` flag if you don't want to erase the records already created. +Also add `--group` to apply and specific file. +``` +php bin/console doctrine:fixtures:load +``` \ No newline at end of file diff --git a/server/compose.yaml b/server/compose.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0e9ab211d99bdc7649c1bff8484f4ac6dad2e5f2 --- /dev/null +++ b/server/compose.yaml @@ -0,0 +1,49 @@ +services: + web: + image: nginx:alpine + container_name: nginx_server + working_dir: /var/www + ports: + - "8080:80" + volumes: + - ./web_app:/var/www + - ./.docker/nginx/default.conf:/etc/nginx/conf.d/default.conf + depends_on: + - app + + app: + image: php_composer + build: + context: . + dockerfile: symfony.dockerfile + container_name: symfony_app + working_dir: /var/www + volumes: + - ./web_app:/var/www + environment: + - APP_ENV=dev + depends_on: + - db + + db: + image: mysql:9.2.0 + container_name: symfony_db + environment: + MYSQL_DATABASE: wishlist_db + MYSQL_ROOT_PASSWORD: password + MYSQL_USER: admin + MYSQL_PASSWORD: admin_password + ports: + - "3306:3306" + volumes: + - ./mysql_data:/var/lib/mysql + + phpMyAdmin: + image: phpmyadmin:5.2.2-apache + container_name: phpMyAdmin + ports: + - "8081:80" + environment: + - MYSQL_ROOT_PASSWORD=password + - MYSQL_USER=admin + - MYSQL_PASSWORD=admin_password \ No newline at end of file diff --git a/server/symfony.dockerfile b/server/symfony.dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a773a2d1fcae79f1c8dcd817ab6a3bd468ad9ffc --- /dev/null +++ b/server/symfony.dockerfile @@ -0,0 +1,29 @@ +# Use official PHP-FPM image +FROM php:8.2-fpm + +# Set working directory inside the container +WORKDIR /var/www + +# Install required system dependencies +RUN apt-get update && apt-get install -y \ + unzip \ + git \ + libpq-dev \ + libzip-dev \ + && docker-php-ext-install pdo pdo_mysql zip + +# Install Composer +RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \ + php composer-setup.php --install-dir=/usr/local/bin --filename=composer && \ + php -r "unlink('composer-setup.php');" + +# Copy existing application files to container +COPY ./web_app /var/www + +# Install Symfony dependencies +RUN composer install --no-scripts --no-autoloader && composer dump-autoload + +# Set permissions +RUN chown -R www-data:www-data /var/www + +CMD ["php-fpm"] \ No newline at end of file diff --git a/server/web_app/.env.dev b/server/web_app/.env.dev new file mode 100644 index 0000000000000000000000000000000000000000..98485ae45be61c173a3e6fda85046f1f1bf37ae6 --- /dev/null +++ b/server/web_app/.env.dev @@ -0,0 +1,4 @@ + +###> symfony/framework-bundle ### +APP_SECRET=5b91d9c00db21a1d640377b21cc0e39d +###< symfony/framework-bundle ### diff --git a/server/web_app/.gitignore b/server/web_app/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a67f91e25c268247e2034877873a2b27f37619f0 --- /dev/null +++ b/server/web_app/.gitignore @@ -0,0 +1,10 @@ + +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/prod/prod.decrypt.private.php +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### diff --git a/server/web_app/bin/console b/server/web_app/bin/console new file mode 100755 index 0000000000000000000000000000000000000000..d8d530e2c36a68f7916acdfa16c9afafcad06bf0 --- /dev/null +++ b/server/web_app/bin/console @@ -0,0 +1,21 @@ +#!/usr/bin/env php +<?php + +use App\Kernel; +use Symfony\Bundle\FrameworkBundle\Console\Application; + +if (!is_dir(dirname(__DIR__).'/vendor')) { + throw new LogicException('Dependencies are missing. Try running "composer install".'); +} + +if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { + throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); +} + +require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; + +return function (array $context) { + $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); + + return new Application($kernel); +}; diff --git a/server/web_app/composer.json b/server/web_app/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..8fc8bf22ac5af63af5a4d2ff39dc1a1e9bdb8ff8 --- /dev/null +++ b/server/web_app/composer.json @@ -0,0 +1,77 @@ +{ + "type": "project", + "license": "proprietary", + "minimum-stability": "stable", + "prefer-stable": true, + "require": { + "php": ">=8.2", + "ext-ctype": "*", + "ext-iconv": "*", + "doctrine/dbal": "^3", + "doctrine/doctrine-bundle": "^2.13", + "doctrine/doctrine-migrations-bundle": "^3.4", + "doctrine/orm": "^3.3", + "symfony/console": "7.2.*", + "symfony/dotenv": "7.2.*", + "symfony/flex": "^2", + "symfony/framework-bundle": "7.2.*", + "symfony/runtime": "7.2.*", + "symfony/security-bundle": "7.2.*", + "symfony/security-core": "7.2.*", + "symfony/yaml": "7.2.*" + }, + "config": { + "allow-plugins": { + "php-http/discovery": true, + "symfony/flex": true, + "symfony/runtime": true + }, + "bump-after-update": true, + "sort-packages": true + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" + } + }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*" + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + }, + "conflict": { + "symfony/symfony": "*" + }, + "extra": { + "symfony": { + "allow-contrib": false, + "require": "7.2.*" + } + }, + "require-dev": { + "doctrine/doctrine-fixtures-bundle": "^4.0", + "symfony/maker-bundle": "^1.62" + } +} diff --git a/server/web_app/config/bundles.php b/server/web_app/config/bundles.php new file mode 100644 index 0000000000000000000000000000000000000000..d1c745acc529dbea17aac1040902965183b399a1 --- /dev/null +++ b/server/web_app/config/bundles.php @@ -0,0 +1,10 @@ +<?php + +return [ + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], + Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], + Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], + Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], + Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], + Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], +]; diff --git a/server/web_app/config/packages/cache.yaml b/server/web_app/config/packages/cache.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6899b72003fca67f5a56b945cd3e07f5c8a33774 --- /dev/null +++ b/server/web_app/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Unique name of your app: used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The "app" cache stores to the filesystem by default. + # The data in this cache should persist between deploys. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: null diff --git a/server/web_app/config/packages/doctrine.yaml b/server/web_app/config/packages/doctrine.yaml new file mode 100644 index 0000000000000000000000000000000000000000..25138b979b685a90e7abcc8dbc563d5a5896683b --- /dev/null +++ b/server/web_app/config/packages/doctrine.yaml @@ -0,0 +1,54 @@ +doctrine: + dbal: + url: '%env(resolve:DATABASE_URL)%' + + # IMPORTANT: You MUST configure your server version, + # either here or in the DATABASE_URL env var (see .env file) + #server_version: '16' + + profiling_collect_backtrace: '%kernel.debug%' + use_savepoints: true + orm: + auto_generate_proxy_classes: true + enable_lazy_ghost_objects: true + report_fields_where_declared: true + validate_xml_mapping: true + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware + identity_generation_preferences: + Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity + auto_mapping: true + mappings: + App: + type: attribute + is_bundle: false + dir: '%kernel.project_dir%/src/Entity' + prefix: 'App\Entity' + alias: App + controller_resolver: + auto_mapping: false + +when@test: + doctrine: + dbal: + # "TEST_TOKEN" is typically set by ParaTest + dbname_suffix: '_test%env(default::TEST_TOKEN)%' + +when@prod: + doctrine: + orm: + auto_generate_proxy_classes: false + proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' + query_cache_driver: + type: pool + pool: doctrine.system_cache_pool + result_cache_driver: + type: pool + pool: doctrine.result_cache_pool + + framework: + cache: + pools: + doctrine.result_cache_pool: + adapter: cache.app + doctrine.system_cache_pool: + adapter: cache.system diff --git a/server/web_app/config/packages/doctrine_migrations.yaml b/server/web_app/config/packages/doctrine_migrations.yaml new file mode 100644 index 0000000000000000000000000000000000000000..29231d94bd1afd6f35b3c1e64687640d3f1e2f50 --- /dev/null +++ b/server/web_app/config/packages/doctrine_migrations.yaml @@ -0,0 +1,6 @@ +doctrine_migrations: + migrations_paths: + # namespace is arbitrary but should be different from App\Migrations + # as migrations classes should NOT be autoloaded + 'DoctrineMigrations': '%kernel.project_dir%/migrations' + enable_profiler: false diff --git a/server/web_app/config/packages/framework.yaml b/server/web_app/config/packages/framework.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7e1ee1f1e0d1183963de0d822c064178a2c4422c --- /dev/null +++ b/server/web_app/config/packages/framework.yaml @@ -0,0 +1,15 @@ +# see https://symfony.com/doc/current/reference/configuration/framework.html +framework: + secret: '%env(APP_SECRET)%' + + # Note that the session will be started ONLY if you read or write from it. + session: true + + #esi: true + #fragments: true + +when@test: + framework: + test: true + session: + storage_factory_id: session.storage.factory.mock_file diff --git a/server/web_app/config/packages/routing.yaml b/server/web_app/config/packages/routing.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8166181c68ab07bfac9aee6e482c7cc24031b8aa --- /dev/null +++ b/server/web_app/config/packages/routing.yaml @@ -0,0 +1,10 @@ +framework: + router: + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands + #default_uri: http://localhost + +when@prod: + framework: + router: + strict_requirements: null diff --git a/server/web_app/config/packages/security.yaml b/server/web_app/config/packages/security.yaml new file mode 100644 index 0000000000000000000000000000000000000000..367af25a56d2decba5041becc5770b16c91b60d4 --- /dev/null +++ b/server/web_app/config/packages/security.yaml @@ -0,0 +1,39 @@ +security: + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords + password_hashers: + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' + # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider + providers: + users_in_memory: { memory: null } + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + lazy: true + provider: users_in_memory + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#the-firewall + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } + +when@test: + security: + password_hashers: + # By default, password hashers are resource intensive and take time. This is + # important to generate secure password hashes. In tests however, secure hashes + # are not important, waste resources and increase test times. The following + # reduces the work factor to the lowest possible values. + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: + algorithm: auto + cost: 4 # Lowest possible value for bcrypt + time_cost: 3 # Lowest possible value for argon + memory_cost: 10 # Lowest possible value for argon diff --git a/server/web_app/config/preload.php b/server/web_app/config/preload.php new file mode 100644 index 0000000000000000000000000000000000000000..5ebcdb2153c870e7d915f3b3fcdd55821424284c --- /dev/null +++ b/server/web_app/config/preload.php @@ -0,0 +1,5 @@ +<?php + +if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) { + require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php'; +} diff --git a/server/web_app/config/routes.yaml b/server/web_app/config/routes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..41ef8140ba811c0da46ce1962ffa50d4c56b9840 --- /dev/null +++ b/server/web_app/config/routes.yaml @@ -0,0 +1,5 @@ +controllers: + resource: + path: ../src/Controller/ + namespace: App\Controller + type: attribute diff --git a/server/web_app/config/routes/framework.yaml b/server/web_app/config/routes/framework.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0fc74bbac4b757dd49782f0be496f6fd7e07e47c --- /dev/null +++ b/server/web_app/config/routes/framework.yaml @@ -0,0 +1,4 @@ +when@dev: + _errors: + resource: '@FrameworkBundle/Resources/config/routing/errors.xml' + prefix: /_error diff --git a/server/web_app/config/routes/security.yaml b/server/web_app/config/routes/security.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f853be15cf348ec1b6caaff738de0153eb9eeef0 --- /dev/null +++ b/server/web_app/config/routes/security.yaml @@ -0,0 +1,3 @@ +_security_logout: + resource: security.route_loader.logout + type: service diff --git a/server/web_app/config/services.yaml b/server/web_app/config/services.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2d6a76f94dce138741e2d63ae83a11c1879031d9 --- /dev/null +++ b/server/web_app/config/services.yaml @@ -0,0 +1,24 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration +parameters: + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\: + resource: '../src/' + exclude: + - '../src/DependencyInjection/' + - '../src/Entity/' + - '../src/Kernel.php' + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones diff --git a/server/web_app/migrations/.gitignore b/server/web_app/migrations/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/server/web_app/migrations/Version20250225195907.php b/server/web_app/migrations/Version20250225195907.php new file mode 100644 index 0000000000000000000000000000000000000000..967136ed04015b05e8c97cb6ff264ec0ba41992b --- /dev/null +++ b/server/web_app/migrations/Version20250225195907.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace DoctrineMigrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; + +/** + * Auto-generated Migration: Please modify to your needs! + */ +final class Version20250225195907 extends AbstractMigration +{ + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE TABLE item (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, price DOUBLE PRECISION NOT NULL, purchase_url VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE purchase (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, wish_list_id INT NOT NULL, item_id INT NOT NULL, url_proof VARCHAR(255) DEFAULT NULL, message VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_6117D13BA76ED395 (user_id), INDEX IDX_6117D13BD69F3311 (wish_list_id), INDEX IDX_6117D13B126F525E (item_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, user_name VARCHAR(255) DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, surname VARCHAR(255) DEFAULT NULL, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, is_blocked TINYINT(1) DEFAULT NULL, role VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE wish_list (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, name VARCHAR(255) NOT NULL, expiration_date DATETIME DEFAULT NULL, is_active TINYINT(1) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_5B8739BDA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE wishlist_item (wish_list_id INT NOT NULL, item_id INT NOT NULL, INDEX IDX_6424F4E8D69F3311 (wish_list_id), INDEX IDX_6424F4E8126F525E (item_id), PRIMARY KEY(wish_list_id, item_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE wish_list_member (id INT AUTO_INCREMENT NOT NULL, wish_list_id INT NOT NULL, user_id INT NOT NULL, can_edit TINYINT(1) NOT NULL, is_accepted TINYINT(1) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_F4CA81DFD69F3311 (wish_list_id), INDEX IDX_F4CA81DFA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13BA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)'); + $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13BD69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id)'); + $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13B126F525E FOREIGN KEY (item_id) REFERENCES item (id)'); + $this->addSql('ALTER TABLE wish_list ADD CONSTRAINT FK_5B8739BDA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)'); + $this->addSql('ALTER TABLE wishlist_item ADD CONSTRAINT FK_6424F4E8D69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE wishlist_item ADD CONSTRAINT FK_6424F4E8126F525E FOREIGN KEY (item_id) REFERENCES item (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFD69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id)'); + $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE purchase DROP FOREIGN KEY FK_6117D13BA76ED395'); + $this->addSql('ALTER TABLE purchase DROP FOREIGN KEY FK_6117D13BD69F3311'); + $this->addSql('ALTER TABLE purchase DROP FOREIGN KEY FK_6117D13B126F525E'); + $this->addSql('ALTER TABLE wish_list DROP FOREIGN KEY FK_5B8739BDA76ED395'); + $this->addSql('ALTER TABLE wishlist_item DROP FOREIGN KEY FK_6424F4E8D69F3311'); + $this->addSql('ALTER TABLE wishlist_item DROP FOREIGN KEY FK_6424F4E8126F525E'); + $this->addSql('ALTER TABLE wish_list_member DROP FOREIGN KEY FK_F4CA81DFD69F3311'); + $this->addSql('ALTER TABLE wish_list_member DROP FOREIGN KEY FK_F4CA81DFA76ED395'); + $this->addSql('DROP TABLE item'); + $this->addSql('DROP TABLE purchase'); + $this->addSql('DROP TABLE user'); + $this->addSql('DROP TABLE wish_list'); + $this->addSql('DROP TABLE wishlist_item'); + $this->addSql('DROP TABLE wish_list_member'); + } +} diff --git a/server/web_app/public/index.php b/server/web_app/public/index.php new file mode 100755 index 0000000000000000000000000000000000000000..9982c218d6969c72d4c91e3834e3f535e2dfe68b --- /dev/null +++ b/server/web_app/public/index.php @@ -0,0 +1,9 @@ +<?php + +use App\Kernel; + +require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; + +return function (array $context) { + return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); +}; diff --git a/server/web_app/src/Controller/.gitignore b/server/web_app/src/Controller/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/server/web_app/src/Controller/ItemController.php b/server/web_app/src/Controller/ItemController.php new file mode 100644 index 0000000000000000000000000000000000000000..ad855bfbfab543cfe3c7e9101da35ce4d5392a9d --- /dev/null +++ b/server/web_app/src/Controller/ItemController.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\Attribute\Route; + +final class ItemController extends AbstractController +{ + #[Route('/item', name: 'app_item')] + public function index(): JsonResponse + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/ItemController.php', + ]); + } +} diff --git a/server/web_app/src/Controller/PurchaseController.php b/server/web_app/src/Controller/PurchaseController.php new file mode 100644 index 0000000000000000000000000000000000000000..fa85a6e6e02de4b9adf5440e244ddecdba558192 --- /dev/null +++ b/server/web_app/src/Controller/PurchaseController.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\Attribute\Route; + +final class PurchaseController extends AbstractController +{ + #[Route('/purchase', name: 'app_purchase')] + public function index(): JsonResponse + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/PurchaseController.php', + ]); + } +} diff --git a/server/web_app/src/Controller/UserController.php b/server/web_app/src/Controller/UserController.php new file mode 100644 index 0000000000000000000000000000000000000000..b80a3e4f96e16261eaac20fac1009aaff66740a8 --- /dev/null +++ b/server/web_app/src/Controller/UserController.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\Attribute\Route; + +final class UserController extends AbstractController +{ + #[Route('/user', name: 'app_user')] + public function index(): JsonResponse + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/UserController.php', + ]); + } +} diff --git a/server/web_app/src/Controller/WishListController.php b/server/web_app/src/Controller/WishListController.php new file mode 100644 index 0000000000000000000000000000000000000000..e28a0e56eddadccc3968409c71860848a926e6f1 --- /dev/null +++ b/server/web_app/src/Controller/WishListController.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\Attribute\Route; + +final class WishListController extends AbstractController +{ + #[Route('/wish/list', name: 'app_wish_list')] + public function index(): JsonResponse + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/WishListController.php', + ]); + } +} diff --git a/server/web_app/src/Controller/WishListMemberController.php b/server/web_app/src/Controller/WishListMemberController.php new file mode 100644 index 0000000000000000000000000000000000000000..9ae805876796dca19e898f25837ac79d61651ed5 --- /dev/null +++ b/server/web_app/src/Controller/WishListMemberController.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Routing\Attribute\Route; + +final class WishListMemberController extends AbstractController +{ + #[Route('/wish/list/member', name: 'app_wish_list_member')] + public function index(): JsonResponse + { + return $this->json([ + 'message' => 'Welcome to your new controller!', + 'path' => 'src/Controller/WishListMemberController.php', + ]); + } +} diff --git a/server/web_app/src/DataFixtures/ItemFixtures.php b/server/web_app/src/DataFixtures/ItemFixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..a8dcc0cc5db53bdee8e0133ac7e78b9c6ee74c4c --- /dev/null +++ b/server/web_app/src/DataFixtures/ItemFixtures.php @@ -0,0 +1,59 @@ +<?php + +namespace App\DataFixtures; + +use App\Entity\Item; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Persistence\ObjectManager; + +class ItemFixtures extends Fixture +{ + public function load(ObjectManager $manager): void + { + $itemsData = [ + [ + 'title' => 'Smartphone', + 'description' => 'Latest model with high-end specs', + 'price' => 799.99, + 'purchase_url' => 'https://example.com/smartphone', + ], + [ + 'title' => 'Laptop', + 'description' => 'Powerful laptop for work and gaming', + 'price' => 1299.49, + 'purchase_url' => 'https://example.com/laptop', + ], + [ + 'title' => 'Wireless Headphones', + 'description' => 'Noise-canceling headphones with long battery life', + 'price' => 199.99, + 'purchase_url' => 'https://example.com/headphones', + ], + [ + 'title' => 'Coffee Maker', + 'description' => 'Automatic coffee maker with multiple settings', + 'price' => 89.99, + 'purchase_url' => 'https://example.com/coffee-maker', + ], + [ + 'title' => 'Gaming Chair', + 'description' => 'Ergonomic chair for long gaming sessions', + 'price' => 249.99, + 'purchase_url' => 'https://example.com/gaming-chair', + ] + ]; + + foreach ($itemsData as $itemData) { + $item = new Item(); + $item->setTitle($itemData['title']); + $item->setDescription($itemData['description']); + $item->setPrice($itemData['price']); + $item->setPurchaseUrl($itemData['purchase_url']); + $item->setCreatedAt(new \DateTimeImmutable()); + + $manager->persist($item); + } + + $manager->flush(); + } +} diff --git a/server/web_app/src/DataFixtures/PurchaseFixtures.php b/server/web_app/src/DataFixtures/PurchaseFixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..9b6140ae4946a969c557dfcf2f822d012a4e832d --- /dev/null +++ b/server/web_app/src/DataFixtures/PurchaseFixtures.php @@ -0,0 +1,17 @@ +<?php + +namespace App\DataFixtures; + +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Persistence\ObjectManager; + +class PurchaseFixtures extends Fixture +{ + public function load(ObjectManager $manager): void + { + // $product = new Product(); + // $manager->persist($product); + + $manager->flush(); + } +} diff --git a/server/web_app/src/DataFixtures/UserFixtures.php b/server/web_app/src/DataFixtures/UserFixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..fdb357ff333ff6fd83cd82a1693a670a6b596101 --- /dev/null +++ b/server/web_app/src/DataFixtures/UserFixtures.php @@ -0,0 +1,68 @@ +<?php + +namespace App\DataFixtures; + +use App\Entity\User; +use App\Enum\UserRole; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; + +class UserFixtures extends Fixture +{ + private UserPasswordHasherInterface $passwordHasher; + + public function __construct(UserPasswordHasherInterface $passwordHasher) + { + $this->passwordHasher = $passwordHasher; + } + + public function load(ObjectManager $manager): void + { + $usersData = [ + [ + 'user_name' => 'john_doe', + 'name' => 'John', + 'surname' => 'Doe', + 'email' => 'john.doe@example.com', + 'password' => 'password123', + 'is_blocked' => false, + 'role' => UserRole::ADMIN, + ], + [ + 'user_name' => 'jane_smith', + 'name' => 'Jane', + 'surname' => 'Smith', + 'email' => 'jane.smith@example.com', + 'password' => 'securepass', + 'is_blocked' => false, + 'role' => UserRole::USER, + ], + [ + 'user_name' => 'bob_martin', + 'name' => 'Bob', + 'surname' => 'Martin', + 'email' => 'bob.martin@example.com', + 'password' => 'test123', + 'is_blocked' => true, + 'role' => UserRole::USER, + ] + ]; + + foreach ($usersData as $userData) { + $user = new User(); + $user->setUserName($userData['user_name']); + $user->setName($userData['name']); + $user->setSurname($userData['surname']); + $user->setEmail($userData['email']); + $user->setPassword($this->passwordHasher->hashPassword($user, $userData['password'])); + $user->setIsBlocked($userData['is_blocked']); + $user->setRole($userData['role']); + $user->setCreatedAt(new \DateTimeImmutable()); + + $manager->persist($user); + } + + $manager->flush(); + } +} diff --git a/server/web_app/src/DataFixtures/WishListFixtures.php b/server/web_app/src/DataFixtures/WishListFixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..cd735e653e889aca768f0e5af011e72fd7b8da89 --- /dev/null +++ b/server/web_app/src/DataFixtures/WishListFixtures.php @@ -0,0 +1,74 @@ +<?php + +namespace App\DataFixtures; + +use App\Entity\User; +use App\Entity\Item; +use App\Entity\WishList; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Persistence\ObjectManager; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; + +class WishListFixtures extends Fixture implements DependentFixtureInterface +{ + public function load(ObjectManager $manager): void + { + // Retrieve all users + $users = $manager->getRepository(User::class)->findAll(); + // Retrieve all items + $items = $manager->getRepository(Item::class)->findAll(); + + if (empty($users) || empty($items)) { + throw new \Exception('No users or items found. Please load UserFixtures and ItemFixtures first.'); + } + + $wishListsData = [ + [ + 'name' => 'John\'s Birthday Wishlist', + 'user' => $users[0], // Assuming at least one user exists + 'items' => [$items[0], $items[1]], // Adding first two items + 'expiration_date' => new \DateTime('+30 days'), + 'is_active' => true, + ], + [ + 'name' => 'Tech Gadgets Wishlist', + 'user' => $users[1], // Use second user if available, else first user + 'items' => [$items[2], $items[3], $items[4]], // Adding three different items + 'expiration_date' => new \DateTime('+60 days'), + 'is_active' => true, + ], + [ + 'name' => 'Home Essentials Wishlist', + 'user' => $users[2], // Use third user if available, else first user + 'items' => [$items[1], $items[4]], // Adding two different items + 'expiration_date' => new \DateTime('+90 days'), + 'is_active' => false, + ], + ]; + + foreach ($wishListsData as $wishListData) { + $wishList = new WishList(); + $wishList->setName($wishListData['name']); + $wishList->setUser($wishListData['user']); + $wishList->setExpirationDate($wishListData['expiration_date']); + $wishList->setIsActive($wishListData['is_active']); + $wishList->setCreatedAt(new \DateTimeImmutable()); + + foreach ($wishListData['items'] as $item) { + $wishList->getItems()->add($item); + } + + $manager->persist($wishList); + } + + $manager->flush(); + } + + public function getDependencies(): array + { + return [ + UserFixtures::class, + ItemFixtures::class, + ]; + } +} diff --git a/server/web_app/src/DataFixtures/WishListMemberFixtures.php b/server/web_app/src/DataFixtures/WishListMemberFixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..b2100cd6040a69f6fdbf9d855a24c6bbd6aa37b6 --- /dev/null +++ b/server/web_app/src/DataFixtures/WishListMemberFixtures.php @@ -0,0 +1,66 @@ +<?php + +namespace App\DataFixtures; + +use App\Entity\WishListMember; +use App\Entity\User; +use App\Entity\WishList; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Persistence\ObjectManager; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; + +class WishListMemberFixtures extends Fixture implements DependentFixtureInterface +{ + public function load(ObjectManager $manager): void + { + // Fetch existing users and wishlists from the database + $users = $manager->getRepository(User::class)->findAll(); + $wishLists = $manager->getRepository(WishList::class)->findAll(); + + if (empty($users) || empty($wishLists)) { + throw new \Exception('Make sure you have users and wishlists in the database before running this fixture.'); + } + + $wishListMembersData = [ + [ + 'wishList' => $wishLists[0], + 'user' => $users[0], + 'can_edit' => true, + 'is_accepted' => true, + ], + [ + 'wishList' => $wishLists[0], + 'user' => $users[1], + 'can_edit' => false, + 'is_accepted' => true, + ], + [ + 'wishList' => $wishLists[1], + 'user' => $users[2], + 'can_edit' => true, + 'is_accepted' => false, + ] + ]; + + foreach ($wishListMembersData as $data) { + $wishListMember = new WishListMember(); + $wishListMember->setWishList($data['wishList']); + $wishListMember->setUser($data['user']); + $wishListMember->setCanEdit($data['can_edit']); + $wishListMember->setIsAccepted($data['is_accepted']); + $wishListMember->setCreatedAt(new \DateTimeImmutable()); + + $manager->persist($wishListMember); + } + + $manager->flush(); + } + + public function getDependencies(): array + { + return [ + UserFixtures::class, + WishListFixtures::class, + ]; + } +} \ No newline at end of file diff --git a/server/web_app/src/Entity/.gitignore b/server/web_app/src/Entity/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/server/web_app/src/Entity/Item.php b/server/web_app/src/Entity/Item.php new file mode 100644 index 0000000000000000000000000000000000000000..75a011f862125994f98e04a5600e5c8da8900348 --- /dev/null +++ b/server/web_app/src/Entity/Item.php @@ -0,0 +1,95 @@ +<?php + +namespace App\Entity; + +use App\Repository\ItemRepository; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity(repositoryClass: ItemRepository::class)] +class Item +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\Column(length: 255)] + private ?string $title = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $description = null; + + #[ORM\Column] + private ?float $price = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $purchase_url = null; + + #[ORM\Column] + private ?\DateTimeImmutable $created_at = null; + + public function getId(): ?int + { + return $this->id; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(string $title): static + { + $this->title = $title; + + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getPrice(): ?float + { + return $this->price; + } + + public function setPrice(float $price): static + { + $this->price = $price; + + return $this; + } + + public function getPurchaseUrl(): ?string + { + return $this->purchase_url; + } + + public function setPurchaseUrl(?string $purchase_url): static + { + $this->purchase_url = $purchase_url; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->created_at; + } + + public function setCreatedAt(\DateTimeImmutable $created_at): static + { + $this->created_at = $created_at; + + return $this; + } +} diff --git a/server/web_app/src/Entity/Purchase.php b/server/web_app/src/Entity/Purchase.php new file mode 100644 index 0000000000000000000000000000000000000000..7f65dc8013191702161543818529da19ce142c17 --- /dev/null +++ b/server/web_app/src/Entity/Purchase.php @@ -0,0 +1,113 @@ +<?php + +namespace App\Entity; + +use App\Repository\PurchaseRepository; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity(repositoryClass: PurchaseRepository::class)] +class Purchase +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\ManyToOne(targetEntity: User::class)] + #[ORM\JoinColumn(nullable: false)] + private ?int $user = null; + + #[ORM\ManyToOne(targetEntity: WishList::class)] + #[ORM\JoinColumn(nullable: false)] + private ?int $wishList = null; + + #[ORM\ManyToOne(targetEntity: Item::class)] + #[ORM\JoinColumn(nullable: false)] + private ?int $item = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $url_proof = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $message = null; + + #[ORM\Column] + private ?\DateTimeImmutable $created_at = null; + + public function getId(): ?int + { + return $this->id; + } + + public function getUser(): ?int + { + return $this->user; + } + + public function setUser(int $user): static + { + $this->user = $user; + + return $this; + } + + public function getWishList(): ?int + { + return $this->wishlist; + } + + public function setWishList(int $wishList): static + { + $this->wishList = $wishList; + + return $this; + } + + public function getItem(): ?int + { + return $this->item; + } + + public function setItem(int $item): static + { + $this->item = $item; + + return $this; + } + + public function getUrlProof(): ?string + { + return $this->url_proof; + } + + public function setUrlProof(?string $url_proof): static + { + $this->url_proof = $url_proof; + + return $this; + } + + public function getMessage(): ?string + { + return $this->message; + } + + public function setMessage(?string $message): static + { + $this->message = $message; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->created_at; + } + + public function setCreatedAt(\DateTimeImmutable $created_at): static + { + $this->created_at = $created_at; + + return $this; + } +} diff --git a/server/web_app/src/Entity/User.php b/server/web_app/src/Entity/User.php new file mode 100644 index 0000000000000000000000000000000000000000..b986c662e0168e100e2dadf512449741bc9a2a34 --- /dev/null +++ b/server/web_app/src/Entity/User.php @@ -0,0 +1,159 @@ +<?php + +namespace App\Entity; + +use App\Enum\UserRole; +use App\Repository\UserRepository; +use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; + +#[ORM\Entity(repositoryClass: UserRepository::class)] +class User implements UserInterface, PasswordAuthenticatedUserInterface +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $user_name = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $name = null; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $surname = null; + + #[ORM\Column(length: 255, unique: true)] + private ?string $email = null; + + #[ORM\Column(length: 255)] + private ?string $password = null; + + #[ORM\Column(nullable: true)] + private ?bool $is_blocked = null; + + #[ORM\Column(enumType: UserRole::class)] + private ?UserRole $role = null; + + #[ORM\Column] + private ?\DateTimeImmutable $created_at = null; + + public function getId(): ?int + { + return $this->id; + } + + public function getUserName(): ?string + { + return $this->user_name; + } + + public function setUserName(?string $user_name): static + { + $this->user_name = $user_name; + + return $this; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(?string $name): static + { + $this->name = $name; + + return $this; + } + + public function getSurname(): ?string + { + return $this->surname; + } + + public function setSurname(?string $surname): static + { + $this->surname = $surname; + + return $this; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(string $email): static + { + $this->email = $email; + + return $this; + } + + public function getPassword(): ?string + { + return $this->password; + } + + public function setPassword(string $password): static + { + $this->password = $password; + + return $this; + } + + public function isBlocked(): ?bool + { + return $this->is_blocked; + } + + public function setIsBlocked(?bool $is_blocked): static + { + $this->is_blocked = $is_blocked; + + return $this; + } + + public function getRole(): ?UserRole + { + return $this->role; + } + + public function setRole(UserRole $role): static + { + $this->role = $role; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->created_at; + } + + public function setCreatedAt(\DateTimeImmutable $created_at): static + { + $this->created_at = $created_at; + + return $this; + } + + //Methods neeeded to be implemented here because of the extension of UserInterface, PasswordAuthenticatedUserInterface + public function getRoles(): array + { + return [$this->role->value]; // Assuming UserRole is an enum with string values + } + + public function getUserIdentifier(): string + { + return $this->email; // Or another unique identifier like username + } + + public function eraseCredentials(): void + { + // If storing temporary sensitive data, clear it here + } +} diff --git a/server/web_app/src/Entity/WishList.php b/server/web_app/src/Entity/WishList.php new file mode 100644 index 0000000000000000000000000000000000000000..cb593dc9e5c773d0d995bb87dee502684fdfe5c9 --- /dev/null +++ b/server/web_app/src/Entity/WishList.php @@ -0,0 +1,132 @@ +<?php + +namespace App\Entity; + +use App\Repository\WishListRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity(repositoryClass: WishListRepository::class)] +class WishList +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\ManyToOne(targetEntity: User::class)] + #[ORM\JoinColumn(nullable: false)] + private ?User $user = null; + + #[ORM\Column(length: 255)] + private ?string $name = null; + + #[ORM\ManyToMany(targetEntity: Item::class)] + #[ORM\JoinTable(name: "wishlist_item")] + private Collection $items; + + #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] + private ?\DateTimeInterface $expiration_date = null; + + #[ORM\Column] + private ?bool $is_active = null; + + #[ORM\Column] + private ?\DateTimeImmutable $created_at = null; + + public function __construct() + { + $this->items = new ArrayCollection(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getUser(): ?User + { + return $this->user; + } + + public function setUser(User $user): static + { + $this->user = $user; + + return $this; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getExpirationDate(): ?\DateTimeInterface + { + return $this->expiration_date; + } + + public function setExpirationDate(?\DateTimeInterface $expiration_date): static + { + $this->expiration_date = $expiration_date; + + return $this; + } + + public function isActive(): ?bool + { + return $this->is_active; + } + + public function setIsActive(bool $is_active): static + { + $this->is_active = $is_active; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->created_at; + } + + public function setCreatedAt(\DateTimeImmutable $created_at): static + { + $this->created_at = $created_at; + + return $this; + } + + /** + * @return Collection<int, Item> + */ + public function getItems(): Collection + { + return $this->items; + } + + public function addItem(Item $item): static + { + if (!$this->items->contains($item)) { + $this->items->add($item); + } + + return $this; + } + + public function removeItem(Item $item): static + { + $this->items->removeElement($item); + + return $this; + } +} diff --git a/server/web_app/src/Entity/WishListMember.php b/server/web_app/src/Entity/WishListMember.php new file mode 100644 index 0000000000000000000000000000000000000000..5143481d7fd0aa9453e98027aaec09b4989c4331 --- /dev/null +++ b/server/web_app/src/Entity/WishListMember.php @@ -0,0 +1,97 @@ +<?php + +namespace App\Entity; + +use App\Repository\WishListMemberRepository; +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity(repositoryClass: WishListMemberRepository::class)] +class WishListMember +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\ManyToOne(targetEntity: WishList::class)] + #[ORM\JoinColumn(nullable: false)] + private ?WishList $wishList = null; + + #[ORM\ManyToOne(targetEntity: User::class)] + #[ORM\JoinColumn(nullable: false)] + private ?User $user = null; + + #[ORM\Column] + private ?bool $can_edit = null; + + #[ORM\Column(nullable: true)] + private ?bool $is_accepted = null; + + #[ORM\Column] + private ?\DateTimeImmutable $created_at = null; + + public function getId(): ?int + { + return $this->id; + } + + public function getWishList(): ?WishList + { + return $this->wishList; + } + + public function setWishList(WishList $wishList): static + { + $this->wishList = $wishList; + + return $this; + } + + public function getUser(): ?User + { + return $this->user; + } + + public function setUser(User $user): static + { + $this->user = $user; + + return $this; + } + + public function isCanEdit(): ?bool + { + return $this->can_edit; + } + + public function setCanEdit(bool $can_edit): static + { + $this->can_edit = $can_edit; + + return $this; + } + + public function isAccepted(): ?bool + { + return $this->is_accepted; + } + + public function setIsAccepted(?bool $is_accepted): static + { + $this->is_accepted = $is_accepted; + + return $this; + } + + public function getCreatedAt(): ?\DateTimeImmutable + { + return $this->created_at; + } + + public function setCreatedAt(\DateTimeImmutable $created_at): static + { + $this->created_at = $created_at; + + return $this; + } +} diff --git a/server/web_app/src/Enum/UserRole.php b/server/web_app/src/Enum/UserRole.php new file mode 100644 index 0000000000000000000000000000000000000000..4b040563c164cbd5def4c6c336cd5118aacda1dc --- /dev/null +++ b/server/web_app/src/Enum/UserRole.php @@ -0,0 +1,19 @@ +<?php + +namespace App\Enum; + +enum UserRole: string +{ + case ADMIN = 'admin'; + case USER = 'user'; + + public function label(): string + { + return match($this) { + self::ADMIN => 'Administrator', + self::USER => 'Regular User' + }; + } +} + +?> \ No newline at end of file diff --git a/server/web_app/src/Kernel.php b/server/web_app/src/Kernel.php new file mode 100644 index 0000000000000000000000000000000000000000..779cd1f2b12e0d30731787539ba67645b73ef796 --- /dev/null +++ b/server/web_app/src/Kernel.php @@ -0,0 +1,11 @@ +<?php + +namespace App; + +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Component\HttpKernel\Kernel as BaseKernel; + +class Kernel extends BaseKernel +{ + use MicroKernelTrait; +} diff --git a/server/web_app/src/Repository/.gitignore b/server/web_app/src/Repository/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/server/web_app/src/Repository/ItemRepository.php b/server/web_app/src/Repository/ItemRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..229f40652e92f36659747e345c2569cb626b2aa2 --- /dev/null +++ b/server/web_app/src/Repository/ItemRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\Item; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<Item> + */ +class ItemRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Item::class); + } + + // /** + // * @return Item[] Returns an array of Item objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('i') + // ->andWhere('i.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('i.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Item + // { + // return $this->createQueryBuilder('i') + // ->andWhere('i.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/src/Repository/PurchaseRepository.php b/server/web_app/src/Repository/PurchaseRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..6f189b3fc521a83374fbb6ac9a8c095988b3fb30 --- /dev/null +++ b/server/web_app/src/Repository/PurchaseRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\Purchase; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<Purchase> + */ +class PurchaseRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Purchase::class); + } + + // /** + // * @return Purchase[] Returns an array of Purchase objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('p') + // ->andWhere('p.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('p.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Purchase + // { + // return $this->createQueryBuilder('p') + // ->andWhere('p.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/src/Repository/UserRepository.php b/server/web_app/src/Repository/UserRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..b29153bdebc8c935907c000813740c61a20275d8 --- /dev/null +++ b/server/web_app/src/Repository/UserRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\User; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<User> + */ +class UserRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + + // /** + // * @return User[] Returns an array of User objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('u.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?User + // { + // return $this->createQueryBuilder('u') + // ->andWhere('u.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/src/Repository/WishListItemRepository.php b/server/web_app/src/Repository/WishListItemRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..1b7d0fffc63dca82dcc81dba03a1829e18a13157 --- /dev/null +++ b/server/web_app/src/Repository/WishListItemRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\WishListItem; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<WishListItem> + */ +class WishListItemRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, WishListItem::class); + } + + // /** + // * @return WishListItem[] Returns an array of WishListItem objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('w.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?WishListItem + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/src/Repository/WishListMemberRepository.php b/server/web_app/src/Repository/WishListMemberRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..cd0e76f9c204ce1ba6f816daef0b621cf99fe5d2 --- /dev/null +++ b/server/web_app/src/Repository/WishListMemberRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\WishListMember; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<WishListMember> + */ +class WishListMemberRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, WishListMember::class); + } + + // /** + // * @return WishListMember[] Returns an array of WishListMember objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('w.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?WishListMember + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/src/Repository/WishListRepository.php b/server/web_app/src/Repository/WishListRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..846c5434dc3c640090187cd19c0ffa15ceacf4dd --- /dev/null +++ b/server/web_app/src/Repository/WishListRepository.php @@ -0,0 +1,43 @@ +<?php + +namespace App\Repository; + +use App\Entity\WishList; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @extends ServiceEntityRepository<WishList> + */ +class WishListRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, WishList::class); + } + + // /** + // * @return WishList[] Returns an array of WishList objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('w.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?WishList + // { + // return $this->createQueryBuilder('w') + // ->andWhere('w.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/server/web_app/symfony.lock b/server/web_app/symfony.lock new file mode 100644 index 0000000000000000000000000000000000000000..65f77fc5c33ef2543d9284cf7230cb0d0ab7a0ab --- /dev/null +++ b/server/web_app/symfony.lock @@ -0,0 +1,120 @@ +{ + "doctrine/doctrine-bundle": { + "version": "2.13", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "8d96c0b51591ffc26794d865ba3ee7d193438a83" + }, + "files": [ + "config/packages/doctrine.yaml", + "src/Entity/.gitignore", + "src/Repository/.gitignore" + ] + }, + "doctrine/doctrine-fixtures-bundle": { + "version": "4.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "1f5514cfa15b947298df4d771e694e578d4c204d" + }, + "files": [ + "src/DataFixtures/AppFixtures.php" + ] + }, + "doctrine/doctrine-migrations-bundle": { + "version": "3.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.1", + "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" + }, + "files": [ + "config/packages/doctrine_migrations.yaml", + "migrations/.gitignore" + ] + }, + "symfony/console": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" + }, + "files": [ + "bin/console" + ] + }, + "symfony/flex": { + "version": "2.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.4", + "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" + }, + "files": [ + ".env", + ".env.dev" + ] + }, + "symfony/framework-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.2", + "ref": "87bcf6f7c55201f345d8895deda46d2adbdbaa89" + }, + "files": [ + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/preload.php", + "config/routes/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] + }, + "symfony/maker-bundle": { + "version": "1.62", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" + } + }, + "symfony/routing": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" + }, + "files": [ + "config/packages/routing.yaml", + "config/routes.yaml" + ] + }, + "symfony/security-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "2ae08430db28c8eb4476605894296c82a642028f" + }, + "files": [ + "config/packages/security.yaml", + "config/routes/security.yaml" + ] + } +}