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
4 changes: 4 additions & 0 deletions app/Filament/Admin/Resources/ComputerScienceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public static function form(Form $form): Form
Forms\Components\TextInput::make('slug')
->maxLength(255),

Forms\Components\TextInput::make('page_url')
->maxLength(255),

Forms\Components\Select::make('user_id')
->relationship('user', 'name')
->required(),
Expand Down Expand Up @@ -84,6 +87,7 @@ public static function table(Table $table): Table
->description(fn (ModelsComputerScienceResource $resource): string => $resource->user->id)->wrap(),
TextColumn::make('name')->searchable()
->description(fn (ModelsComputerScienceResource $resource): string => $resource->description)->wrap(),
TextColumn::make('page_url')->searchable()->wrap()->copyable(),
TextColumn::make('topic_tags')
->label('topics_tags')
->badge()
Expand Down
24 changes: 2 additions & 22 deletions app/Http/Controllers/ResourceEditsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use App\Http\Requests\StoreResourceEdit;
use App\Models\ComputerScienceResource;
use App\Models\ResourceEdits;
use App\Services\DataNormalizationService;
use App\Services\ResourceEditsService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
Expand All @@ -18,7 +17,7 @@
class ResourceEditsController extends Controller
{
public function __construct(
private DataNormalizationService $dataNormalizationService
protected ResourceEditsService $resourceEditsService
) {}

/**
Expand All @@ -42,7 +41,7 @@ public function store(ComputerScienceResource $computerScienceResource, StoreRes
$validatedData = $request->validated();
$proposedChanges = $validatedData['proposed_changes'] ?? [];

$actualChanges = $this->calculateChanges($computerScienceResource, $proposedChanges);
$actualChanges = $this->resourceEditsService->calculateChanges($computerScienceResource, $proposedChanges);

// Add image path to the actual changes
if (array_key_exists('image_file', $proposedChanges)) {
Expand Down Expand Up @@ -72,25 +71,6 @@ public function store(ComputerScienceResource $computerScienceResource, StoreRes
->with('success', 'Edits Created!');
}

/**
* Calculate the actual differences between the proposed changes and the original resource.
*/
private function calculateChanges(ComputerScienceResource $resource, array $proposedChanges): array
{
$actualChanges = [];
$normalizedProposed = $this->dataNormalizationService->normalize($proposedChanges);
$normalizedOriginal = $this->dataNormalizationService->normalize($resource->toArray());

foreach ($normalizedProposed as $key => $value) {
if (! array_key_exists($key, $normalizedOriginal) || $normalizedOriginal[$key] !== $value) {
// Use the original value from the request, not the normalized one, for file uploads.
$actualChanges[$key] = $proposedChanges[$key];
}
}

return $actualChanges;
}

public function show(string $slug)
{
$resourceEdits = ResourceEdits::where('slug', $slug)->firstOrFail();
Expand Down
8 changes: 8 additions & 0 deletions app/Models/ComputerScienceResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Observers\ComputerScienceResourceObserver;
use App\Traits\HasComments;
use App\Traits\HasVotes;
use App\Utilities\UrlUtilities;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute;
Expand Down Expand Up @@ -89,6 +90,13 @@ protected function imageUrl(): Attribute
);
}

protected function pageUrl(): Attribute
{
return Attribute::make(
set: fn ($value) => UrlUtilities::normalize($value)
);
}

/**
* Get the review summary relationship.
*/
Expand Down
8 changes: 8 additions & 0 deletions app/Models/ResourceEdits.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Services\ResourceEditsService;
use App\Traits\HasComments;
use App\Traits\HasVotes;
use App\Utilities\UrlUtilities;
use Cviebrock\EloquentSluggable\Sluggable;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute;
Expand Down Expand Up @@ -89,6 +90,13 @@ protected function proposedChanges(): Attribute

return $changes;
},
set: function ($value) {
if (array_key_exists('page_url', $value) && is_string($value['page_url'])) {
$value['page_url'] = UrlUtilities::normalize($value['page_url']);
}

return json_encode($value);
}
);
}

Expand Down
6 changes: 5 additions & 1 deletion app/Services/ComputerScienceResourceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Models\ResourceEdits;
use App\Models\ResourceReview;
use App\Services\SortingManagers\ResourceSortingManager;
use App\Utilities\UrlUtilities;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
Expand Down Expand Up @@ -157,6 +158,9 @@ function () use ($computerScienceResource, $sortBy, $request) {
*/
private function existingConflictingResource(array $data): ?ComputerScienceResource
{
return ComputerScienceResource::where('page_url', $data['page_url'])->first();
return ComputerScienceResource::where(
'page_url',
UrlUtilities::normalize($data['page_url']),
)->first();
}
}
30 changes: 0 additions & 30 deletions app/Services/DataNormalizationService.php

This file was deleted.

42 changes: 42 additions & 0 deletions app/Services/ResourceEditsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace App\Services;

use App\Models\ComputerScienceResource;
use App\Models\ResourceEdits;
use App\Utilities\UrlUtilities;

class ResourceEditsService
{
Expand Down Expand Up @@ -42,4 +44,44 @@ public function canMergeEdits(ResourceEdits $edits): bool

return $approvals >= $neededApprovals;
}

/**
* Calculate the actual differences between the proposed changes and the original resource.
*/
public function calculateChanges(ComputerScienceResource $resource, array $proposedChanges): array
{
$actualChanges = [];
$normalizedProposed = $this->normalize($proposedChanges);
$normalizedOriginal = $this->normalize($resource->toArray());

foreach ($normalizedProposed as $key => $value) {
if (! array_key_exists($key, $normalizedOriginal) || $normalizedOriginal[$key] !== $value) {
// Use the original value from the request, not the normalized one, for file uploads.
$actualChanges[$key] = $proposedChanges[$key];
}
}

return $actualChanges;
}

/**
* Normalize an array by sorting keys and values for consistent comparison, including page_url normalization.
*/
public function normalize(array $array): array
{
ksort($array);

// Normalize page_url if present
if (array_key_exists('page_url', $array) && is_string($array['page_url'])) {
$array['page_url'] = UrlUtilities::normalize($array['page_url']);
}

foreach ($array as &$value) {
if (is_array($value)) {
sort($value);
}
}

return $array;
}
}
14 changes: 14 additions & 0 deletions app/Utilities/UrlUtilities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace App\Utilities;

class UrlUtilities
{
/**
* Normalize a URL: trim, lowercase, remove trailing slashes.
*/
public static function normalize(string $url): string
{
return rtrim(strtolower(trim($url)), '/');
}
}
3 changes: 2 additions & 1 deletion tests/Feature/ComputerScienceResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ public function test_posting_duplicate_resource_returns_existing_resource()
$formData = StoreResourceRequestFactory::new()->create();
$this->postJson(route('resources.store'), $formData);

// Try to create the same resource again
// Try to create the same resource again, with a slightly different URL
$formData['page_url'] = $formData['page_url'].' ';
$response = $this->postJson(route('resources.store'), $formData);

$response->assertStatus(200);
Expand Down