Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/backend_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Run Laravel API Feature Tests

on:
pull_request:
branches:
- development
paths:
- 'API/**'

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2' # the PHP version this project requires
extensions: mbstring, pdo_sqlite
ini-values: |
memory_limit=-1
coverage: none

- name: Install dependencies
run: |
cd API
composer install --prefer-dist --no-interaction
cp .env.test .env

- name: Configure environment for SQLite in-memory database
run: |
cd API
echo "DB_CONNECTION=sqlite" >> .env
echo "DB_DATABASE=:memory:" >> .env
php artisan key:generate

- name: Run migrations
run: |
cd API
php artisan migrate --force

- name: Run tests
run: |
cd API
php artisan test --testsuite=Feature
3 changes: 2 additions & 1 deletion API/.env.example → API/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
FRONTEND_BASE_URL=www.speedcartapp.com

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
Expand All @@ -19,7 +20,7 @@ LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=sqlite
# DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
Expand Down
31 changes: 13 additions & 18 deletions API/app/Http/Controllers/Api/GroceryItemController.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,27 +99,22 @@ public function update(Request $request, $id)

public function destroy(Request $request, $id)
{
try {
$groceryItem = GroceryItem::findOrFail($id);

$shoppingList = ShoppingList::findOrFail($groceryItem->shopping_list_id);
$groceryItem = GroceryItem::findOrFail($id);

$shoppingList = ShoppingList::findOrFail($groceryItem->shopping_list_id);

// This will automatically call the `update` method in the ShoppingListPolicy
$this->authorize('update', $shoppingList); // Throws a 403 if not authorized
// This will automatically call the `update` method in the ShoppingListPolicy
$this->authorize('update', $shoppingList); // Throws a 403 if not authorized

Log::info("Deleting item: " . print_r($groceryItem, true));
$groceryItem->delete();
Log::info("Deleting item: " . print_r($groceryItem, true));
$groceryItem->delete();

// Also update shopping list name "updated_at" field (users should know the shopping list has been
// modified without having to see the individual items; this is done via this functionality and shown
// for the Dashboard front end component list items)
$shoppingList->updated_at = now(); // Update the timestamp
$shoppingList->save();
// Also update shopping list name "updated_at" field (users should know the shopping list has been
// modified without having to see the individual items; this is done via this functionality and shown
// for the Dashboard front end component list items)
$shoppingList->updated_at = now(); // Update the timestamp
$shoppingList->save();

return response()->json(['message' => 'Grocery item deleted successfully'], 200);
} catch (\Exception $e) {
Log::error('Error deleting grocery item: ' . $e->getMessage());
return response()->json(['error' => 'Could not delete grocery item'], 500);
}
return response()->json(['message' => 'Grocery item deleted successfully'], 200);
}
}
19 changes: 6 additions & 13 deletions API/app/Http/Controllers/Api/ShoppingListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

define('DEBUG_MODE', 0);


class ShoppingListController extends Controller
{
Expand Down Expand Up @@ -157,18 +155,13 @@ public function update(Request $request, $id)

public function destroy(Request $request, $id)
{
try {
$shoppingList = ShoppingList::findOrFail($id);
$shoppingList = ShoppingList::findOrFail($id);

// This will automatically call the `delete` method in the ShoppingListPolicy
$this->authorize('delete', $shoppingList); // Throws a 403 if not authorized
$shoppingList->delete();
// This will automatically call the `delete` method in the ShoppingListPolicy
$this->authorize('delete', $shoppingList); // Throws a 403 if not authorized

$shoppingList->delete();

return response()->json(['message' => 'Shopping list deleted successfully'], 200);
} catch (\Exception $e) {
Log::error('Error deleting shopping list: ' . $e->getMessage());
return response()->json(['error' => 'Could not delete shopping list'], 500);
}
return response()->json(['message' => 'Shopping list deleted successfully'], 200);
}
}
5 changes: 0 additions & 5 deletions API/app/Http/Controllers/GoogleAuthenticationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;


define('DEBUG_MODE', 0);
// Fetch the client ID from the environment variable
define('GOOGLE_CLIENT_ID', env('GOOGLE_CLIENT_ID'));

class GoogleAuthenticationController extends Controller
{
/**
Expand Down
9 changes: 7 additions & 2 deletions API/app/Http/Controllers/ListPermissionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;

define('DEBUG_MODE', 0);

class ListPermissionsController extends BaseController
{

Expand All @@ -38,6 +36,13 @@ public function createShareLink($id, Request $request)
{
$shoppingList = ShoppingList::findOrFail($id);
Log::info("Shopping list id: " . $shoppingList->list_id . " and we started with id: " . $id);

// Grab user from sanctum
$user = Auth::user();

if ($shoppingList->user_id != $user->user_id) {
abort(403);
}

$maxRetries = 10; // Maximum number of retries
$retryCount = 0;
Expand Down
3 changes: 3 additions & 0 deletions API/app/Models/SharedLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class SharedLink extends Model
{
use HasFactory;

protected $table = 'shared_links';

// Fillable properties, allowing mass assignment
Expand Down
7 changes: 7 additions & 0 deletions API/app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,12 @@ public function register(): void
public function boot(): void
{
//
if (!defined('DEBUG_MODE')) {
define('DEBUG_MODE', 1);
}
if (!defined('GOOGLE_CLIENT_ID')) {
// Fetch the client ID from the environment variable
define('GOOGLE_CLIENT_ID', env('GOOGLE_CLIENT_ID'));
}
}
}
35 changes: 35 additions & 0 deletions API/database/factories/GroceryItemFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Database\Factories;

use App\Models\GroceryItem;
use App\Models\ShoppingList;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class GroceryItemFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = GroceryItem::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
// Get a random user from the database (can be adjusted based on your needs)
$user = User::inRandomOrder()->first();
$list = ShoppingList::inRandomOrder()->first();
return [
'name' => $this->faker->word(), // Random name for the grocery item
'is_food' => false,
'shopping_list_id' => $list->list_id,
];
}
}
26 changes: 26 additions & 0 deletions API/database/factories/SharedLinkFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Database\Factories;

use App\Models\SharedLink;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use Carbon\Carbon;

class SharedLinkFactory extends Factory
{
protected $model = SharedLink::class;

public function definition()
{
return [
'token' => (string) Str::uuid(),
'expires_at' => Carbon::now()->addDays(7),
'can_update' => false,
'can_delete' => false,
'shopping_list_id' => function () {
return \App\Models\ShoppingList::factory()->create()->list_id;
}
];
}
}
34 changes: 34 additions & 0 deletions API/database/factories/ShoppingListFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Database\Factories;

use App\Models\ShoppingList;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class ShoppingListFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = ShoppingList::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
// Get a random user from the database (can be adjusted based on your needs)
$user = User::inRandomOrder()->first();

return [
'name' => $this->faker->word(), // Random name for the shopping list
'user_id' => $user ? $user->user_id : null, // Assign a user_id from an existing user
'route_id' => null, // Set to null if you don't want to assign a route by default
];
}
}
37 changes: 7 additions & 30 deletions API/database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,19 @@
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
use App\Models\User;

class UserFactory extends Factory
{
/**
* The current password being used by the factory.
*/
protected static ?string $password;
protected $model = User::class;

/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
'user_id' => $this->faker->uuid(),
'username' => $this->faker->userName(),
// Add any other necessary fields here
];
}

/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
2 changes: 1 addition & 1 deletion API/phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
Expand Down
19 changes: 0 additions & 19 deletions API/tests/Feature/ExampleTest.php

This file was deleted.

Loading