diff --git a/.github/workflows/backend_test.yml b/.github/workflows/backend_test.yml index e38875b..484d99f 100644 --- a/.github/workflows/backend_test.yml +++ b/.github/workflows/backend_test.yml @@ -3,6 +3,7 @@ name: Run Laravel API Feature Tests on: pull_request: branches: + - deployment - development paths: - 'API/**' diff --git a/API/.env.example b/API/.env.example new file mode 100644 index 0000000..5aa1feb --- /dev/null +++ b/API/.env.example @@ -0,0 +1,71 @@ +# Be sure to copy this into your .env file and ask for any necessary keys to test +APP_NAME=API +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_TIMEZONE=UTC +APP_URL=localhost:8000 +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +GOOGLE_REDIRECT_URI=localhost:3000 +SANCTUM_STATEFUL_DOMAINS=localhost,localhost:3000,localhost:8000 +SESSION_DOMAIN=localhost +FRONTEND_BASE_URL=localhost:3000 +SESSION_SECURE_COOKIE=false +DEBUGBAR_ENABLED=false + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +APP_MAINTENANCE_STORE=database + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stderr +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=mysql +DB_HOST=db +DB_DATABASE=laravel +DB_USERNAME=root +DB_PASSWORD=root +DB_PORT=3306 + +SESSION_DRIVER=cookie +SESSION_LIFETIME=43200 +SESSION_ENCRYPT=false +SESSION_PATH=/ + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false +VITE_APP_NAME=${APP_NAME} diff --git a/API/app/Http/Controllers/Api/ShoppingListController.php b/API/app/Http/Controllers/Api/ShoppingListController.php index 63a7d30..a3cc138 100644 --- a/API/app/Http/Controllers/Api/ShoppingListController.php +++ b/API/app/Http/Controllers/Api/ShoppingListController.php @@ -129,7 +129,7 @@ public function getSharedShoppingLists(Request $request) $shoppingListIds = $sharedPermissionEntries->pluck('shopping_list_id'); // Step 3: Retrieve shopping lists based on the IDs - $shoppingLists = ShoppingList::whereIn('id', $shoppingListIds)->get(); + $shoppingLists = ShoppingList::whereIn('list_id', $shoppingListIds)->get(); return response()->json($shoppingLists, 200); } diff --git a/API/docker/development/Dockerfile b/API/docker/development/Dockerfile index 0cb0b48..a212f12 100644 --- a/API/docker/development/Dockerfile +++ b/API/docker/development/Dockerfile @@ -1,37 +1,28 @@ -# Use the official PHP 8.2 CLI image -FROM php:8.2-cli-alpine - -# Set working directory -WORKDIR /var/www/html +# Use official PHP image with necessary extensions +FROM php:8.2-fpm # Install system dependencies -RUN apk add --no-cache \ +RUN apt-get update && apt-get install -y \ libpng-dev \ - libjpeg-turbo-dev \ - freetype-dev \ + libjpeg-dev \ + libfreetype6-dev \ libxml2-dev \ - oniguruma-dev \ + libonig-dev \ + unzip \ + zip \ + git \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install gd pdo pdo_mysql mbstring xml -# Install PHP extensions -RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ - && docker-php-ext-install gd pdo pdo_mysql mbstring xml - # Install Composer globally COPY --from=composer:2.6 /usr/bin/composer /usr/bin/composer -# Copy application source -COPY . /var/www/html - -# Install dependencies -RUN composer install +# Set working directory +WORKDIR /var/www -# Set correct permissions -RUN chmod -R 777 storage bootstrap/cache +# Set permissions +RUN chown -R www-data:www-data /var/www && chmod -R 755 /var/www -# Expose port 8000 for Laravel's dev server +# Expose port 8000 for Laravel's dev server and start development server EXPOSE 8000 - -# Start Laravel development server -CMD ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8000"] +CMD ["php-fpm"] \ No newline at end of file diff --git a/API/docker/development/docker-compose.yml b/API/docker/development/docker-compose.yml index 5116f40..009165f 100644 --- a/API/docker/development/docker-compose.yml +++ b/API/docker/development/docker-compose.yml @@ -1,17 +1,18 @@ -version: '3.8' services: app: build: context: ../../ dockerfile: ./docker/development/Dockerfile - container_name: laravel_dev + container_name: speedcart_laravel_dev ports: - - "8000:8000" + - "9000:9000" depends_on: - db env_file: - ../../.env + volumes: + - ../../:/var/www # Make sure the following variables are set in .env # for the db connection to function properly: # APP_ENV=local @@ -26,15 +27,30 @@ services: db: image: mysql:8.0 - container_name: laravel_db - restart: always + container_name: speedcart_laravel_mysql + restart: unless-stopped environment: MYSQL_DATABASE: laravel MYSQL_ROOT_PASSWORD: root + MYSQL_USER: laravel + MYSQL_PASSWORD: secret volumes: - db_data:/var/lib/mysql ports: - - "127.0.0.1:3306:3306" + - "3306:3306" + networks: + - laravel_network + + nginx: + image: nginx:alpine + container_name: speedcart_nginx + ports: + - "8000:80" # 8000 on host → 80 on container + volumes: + - ../../:/var/www + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf + depends_on: + - app networks: - laravel_network diff --git a/API/docker/development/nginx/default.conf b/API/docker/development/nginx/default.conf new file mode 100644 index 0000000..c091d7f --- /dev/null +++ b/API/docker/development/nginx/default.conf @@ -0,0 +1,19 @@ +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$ { + include fastcgi_params; + fastcgi_pass app:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME /var/www/public$fastcgi_script_name; + } +} diff --git a/API/docker/production/Dockerfile b/API/docker/production/Dockerfile index 34354b5..0124eaf 100644 --- a/API/docker/production/Dockerfile +++ b/API/docker/production/Dockerfile @@ -20,7 +20,10 @@ RUN apt-get update && apt-get install -y \ && apt-get clean && rm -rf /var/lib/apt/lists/* # Install PHP extensions -RUN docker-php-ext-install pdo pdo_mysql mbstring exif pcntl bcmath gd intl zip soap +RUN docker-php-ext-install pdo pdo_mysql mbstring exif pcntl bcmath gd intl zip soap opcache + +# Copy custom opcache configuration +COPY ./opcache.ini /usr/local/etc/php/conf.d/opcache.ini # Enable Apache Rewrite module (required by Laravel) RUN a2enmod rewrite @@ -28,6 +31,15 @@ RUN a2enmod rewrite # Copy existing application directory contents COPY . /var/www/html +# Set Apache to serve the Laravel "public" directory +RUN sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public|' /etc/apache2/sites-available/000-default.conf + +# Also allow .htaccess overrides in public directory +RUN echo '\n\ + AllowOverride All\n\ + Require all granted\n\ +' >> /etc/apache2/apache2.conf + # Copy existing application directory permissions RUN chown -R www-data:www-data /var/www/html \ && chmod -R 755 /var/www/html diff --git a/API/opcache.ini b/API/opcache.ini new file mode 100644 index 0000000..b193c20 --- /dev/null +++ b/API/opcache.ini @@ -0,0 +1,9 @@ +; Enable OPcache +zend_extension=opcache +opcache.enable=1 +opcache.enable_cli=1 +opcache.memory_consumption=128 +opcache.interned_strings_buffer=8 +opcache.max_accelerated_files=10000 +opcache.revalidate_freq=2 +opcache.validate_timestamps=1 diff --git a/Frontend/shared/.env b/Frontend/shared/.env index 83bf5b5..5494f0f 100644 --- a/Frontend/shared/.env +++ b/Frontend/shared/.env @@ -1,3 +1,2 @@ API_DOMAIN=api.speedcartapp.com -API_PORT=80 TESTING_MODE=false \ No newline at end of file diff --git a/Frontend/shared/src/constants/BaseUrl.ts b/Frontend/shared/src/constants/BaseUrl.ts index 0d2bf7d..d73b5d6 100644 --- a/Frontend/shared/src/constants/BaseUrl.ts +++ b/Frontend/shared/src/constants/BaseUrl.ts @@ -2,11 +2,10 @@ import config from './config.json'; const API_DOMAIN = config.API_DOMAIN; -const API_PORT = config.API_PORT; // Protocol depends on if we're using dev or production const API_PROTOCOL = API_DOMAIN === 'localhost' ? 'http' : 'https'; // This can be reused for all backend interactions -export const BASE_URL: string = `${API_PROTOCOL}://${API_DOMAIN}:${API_PORT}`; +export const BASE_URL: string = `${API_PROTOCOL}://${API_DOMAIN}`; export const TESTING_MODE: boolean = config.TESTING_MODE === 'true'; \ No newline at end of file diff --git a/tests/CrudOpsTest.php b/tests/CrudOpsTest.php deleted file mode 100755 index c86f4f2..0000000 --- a/tests/CrudOpsTest.php +++ /dev/null @@ -1,88 +0,0 @@ -assertInstanceOf(Database::class, self::$db); - } - - public function testInsertAndSelect() - { - $userId = self::$db->insert("users", ["username" => "test_user", "email" => "test@example.com"]); - - $this->assertGreaterThan(0, $userId); - - $tblName = 'users'; - - $result = self::$db->select("SELECT * FROM `{$tblName}` WHERE id = :searchValue", [':searchValue' => $userId]); - - //print_r($result); - - $this->assertCount(1, $result); - $this->assertEquals("test_user", $result[0][1]); - } - - public function testUpdate() - { - self::$db->update("users", ["username" => "updated_user"], "id = 1"); - - $result = self::$db->select("SELECT * FROM users WHERE id = 1"); - - //print_r($result); - $this->assertEquals("updated_user", $result[0][1]); - } - - public function testDelete() - { - self::$db->delete("users", "id = :num", [':num' => 1]); - - $result = self::$db->select("SELECT * FROM users WHERE id = 1"); - - $this->assertCount(0, $result); - } - - public function testInvalidConnection() - { - try { - $db = new Database('invalid_dsn'); - $this->fail('Expected PDOException, but no exception was thrown.'); - } catch (PDOException $e) { - $this->assertInstanceOf(PDOException::class, $e); - } - } - - - - private static function createUsersTable() - { - $createTableSql = " - CREATE TABLE users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username VARCHAR(255) NOT NULL, - email VARCHAR(255) NOT NULL - ) - "; - - self::$db->query($createTableSql); - } -} -?> \ No newline at end of file diff --git a/tests/RESTAPITests.py b/tests/RESTAPITests.py deleted file mode 100644 index 574a34a..0000000 --- a/tests/RESTAPITests.py +++ /dev/null @@ -1,71 +0,0 @@ -import requests -import json -from bson import json_util - -def read_binary_file(file_path, encoding='utf-8'): - try: - # Open the binary file in read mode - with open(file_path, "rb") as f: - # Read the binary data - binary_data = f.read() - - # Decode the binary data into a string using the specified encoding - decoded_data = binary_data.decode(encoding) - - # Load the decoded JSON string into a Python object - json_data = json_util.loads(decoded_data) - - # Process the JSON data as needed - # For example, you can print it or perform further processing - print("Decoded JSON data read from file:") - print(json_data) - - except FileNotFoundError: - print(f"File not found: {file_path}") - except json.JSONDecodeError as e: - print(f"Error decoding JSON: {e}") - -def send_get_request(search_value): - # Replace 'your_server_ip' with the actual IP address of your server - base_url = 'http://139.144.239.217' - endpoint = '/api/ShopFastDataManager.php' - - # Construct the URL - url = f'{base_url}{endpoint}' - - # Specify the search parameters as a dictionary - params = { - 'database': 'movies', - 'tblName': 'movies', - 'condition': 'name LIKE :searchValue', - 'params' : { - ':searchValue' : search_value - } - } - - print(search_value) - - # Convert params to JSON - json_params = json.dumps(params) - - # Send the GET request with JSON payload - response = requests.get(url, data=json_params, headers={'Content-Type': 'application/json'}) - - # Check the status code - if response.status_code == 200: - # Access the binary data - binary_data = response.content - - # Save the binary data to a file - with open("output_file.bin","wb") as f: - f.write(binary_data) - - print("Octet-stream data successfully saved to output_file.bin") - - # Read and process the binary data from the file - read_binary_file("output_file.bin") - else: - print(f'Request failed with status code {response.status_code}') - -# Example: Sending a request with search value 'home' -send_get_request('%opp%') \ No newline at end of file