Skip to content

Commit

Permalink
Merge branch 'main' into refactor/auth-revamp
Browse files Browse the repository at this point in the history
  • Loading branch information
axelrindle committed Sep 29, 2024
2 parents c85a49e + 4ba8a43 commit 214f3f5
Show file tree
Hide file tree
Showing 123 changed files with 4,478 additions and 1,438 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

[package.json]
indent_size = 2
17 changes: 15 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"redhat.vscode-yaml",
"axelrindle.duplicate-file",
"axelrindle.task-explorer",
"actboy168.tasks",
"mikestead.dotenv",
"phpactor.vscode-phpactor",
"ctf0.php-class-imports-folding",
"oven.bun-vscode",
"dbaeumer.vscode-eslint",
"herrmannplatz.npm-dependency-links",
"bradlc.vscode-tailwindcss",
"GitHub.vscode-github-actions",
"GitHub.vscode-pull-request-github",
],
"unwantedRecommendations": [
"esbenp.prettier-vscode"
]
}
31 changes: 3 additions & 28 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,43 +1,18 @@
{
"files.associations": {
"artisan": "php",
"composer": "shellscript"
},

"explorer.autoRevealExclude": {
"**/node_modules": true,
"**/vendor": true
},

"editor.foldingImportsByDefault": true,
"editor.defaultFormatter": null,
"editor.linkedEditing": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.preferences.quoteStyle": "single",
"typescript.format.semicolons": "remove",

"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
},

"i18n-ally.localesPaths": [
"frontend/messages"
],

"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[yaml]": {
"editor.defaultFormatter": "redhat.vscode-yaml"
},
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
}
}
71 changes: 64 additions & 7 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,22 @@
"focus": false,
"panel": "dedicated"
},
"group": "none"
"group": "none",
"options": {
"statusbar": {
"hide": true
}
}
},
{
"label": "Frontend",
"type": "shell",
"command": "bun run dev",
"options": {
"cwd": "frontend"
"cwd": "frontend",
"statusbar": {
"hide": true
}
},
"problemMatcher": [],
"presentation": {
Expand All @@ -44,7 +52,12 @@
"focus": false,
"panel": "dedicated"
},
"group": "none"
"group": "none",
"options": {
"statusbar": {
"hide": true
}
}
},
{
"label": "Queue",
Expand All @@ -59,7 +72,12 @@
"focus": false,
"panel": "dedicated"
},
"group": "none"
"group": "none",
"options": {
"statusbar": {
"hide": true
}
}
},
{
"label": "Dev",
Expand All @@ -79,7 +97,12 @@
"Backend",
"Scheduler",
"Queue"
]
],
"options": {
"statusbar": {
"hide": true
}
}
},
{
"label": "Open Browser",
Expand All @@ -97,6 +120,25 @@
"panel": "shared",
},
"group": "none",
"options": {
"statusbar": {
"hide": true
}
}
},
{
"label": "Migrate",
"type": "shell",
"command": "./artisan migrate",
"osx": {
"command": "php artisan migrate"
},
"problemMatcher": [],
"group": "none",
"presentation": {
"reveal": "always",
"panel": "shared",
}
},
{
"label": "Reset database",
Expand All @@ -110,7 +152,8 @@
"presentation": {
"reveal": "always",
"panel": "shared",
}
"focus": true,
},
},
{
"label": "Clear Cache",
Expand All @@ -126,5 +169,19 @@
"panel": "shared",
}
},
]
{
"label": "Gen API Client",
"type": "shell",
"command": "bash gen-api-client.sh",
"options": {
"cwd": "${workspaceFolder}/frontend"
},
"problemMatcher": [],
"group": "none",
"presentation": {
"reveal": "always",
"panel": "shared",
},
},
],
}
10 changes: 10 additions & 0 deletions app/Enum/UploadType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Enum;

enum UploadType: string
{
case ATTACHMENT = 'attachment';
case HEADER = 'header';
case CONTENT = 'content';
}
90 changes: 61 additions & 29 deletions app/Http/Controllers/NewsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Http\Requests\News\NewsStoreRequest;
use App\Http\Requests\News\NewsUpdateRequest;
use App\Http\Requests\News\UploadImageRequest;
use App\Http\Resources\AttachmentResource;
use App\Http\Resources\NewsResource;
use App\Models\Attachment;
use App\Models\News;
Expand All @@ -19,6 +20,7 @@
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class NewsController extends Controller implements HasMiddleware
{
Expand All @@ -28,7 +30,7 @@ class NewsController extends Controller implements HasMiddleware
public static function middleware(): array
{
return [
new Middleware('auth:api', except: ['index', 'show']),
new Middleware('auth:api', except: ['index', 'show', 'listAttachments']),
];
}

Expand All @@ -44,10 +46,15 @@ public function index(NewsListRequest $request): AnonymousResourceCollection
{
$query = News::query()
->orderByDesc('published_at')
->orderByDesc('created_at')
->with('attachments');

if (Gate::check('news.viewall')) {
$query = $query->withTrashed();
if ($request->has('status')) {
$query = $query->whereStatus($request->input('status'));
} else {
$query = $query->withTrashed();
}
} else {
$query = $query->whereStatus(NewsStatus::ACTIVE);
}
Expand Down Expand Up @@ -98,12 +105,12 @@ public function show(string $id): NewsResource
/**
* Update the specified resource in storage.
*/
public function update(NewsUpdateRequest $request, string $id): Response|JsonResponse
public function update(NewsUpdateRequest $request, $id): JsonResponse
{
$news = $this->find($id, 'update');

if ($news->trashed()) {
return response()->json(['message' => 'You cannot update trashed news.'], status: 403);
abort(403, 'You cannot update trashed news.');
}

$news->fill($request->validated());
Expand All @@ -118,20 +125,20 @@ public function update(NewsUpdateRequest $request, string $id): Response|JsonRes

$news->save();

return response()->noContent();
return response()->json($news);
}

/**
* Delete the specified resource from storage.
*/
public function destroy(Request $request, string $id): Response|JsonResponse
public function destroy(Request $request, $id): Response
{
$force = $request->boolean('force', false);

$news = $this->find($id, $force ? 'forceDelete' : 'delete');

if ($news->trashed()) {
return response()->json(['message' => 'You cannot deleted trashed news.'], status: 403);
abort(403, 'You cannot delete trashed news.');
}

$force ? $news->forceDeleteQuietly() : $news->delete();
Expand All @@ -152,7 +159,9 @@ public function restore(string $id): Response
}

/**
* Uploads a file to the scope of a news article.
* Attach a file to the specified resource.
*
* @param int $id
*/
public function upload(UploadImageRequest $request, string $id): JsonResponse
{
Expand All @@ -161,41 +170,64 @@ public function upload(UploadImageRequest $request, string $id): JsonResponse
$type = $request->input('type');
$file = $request->file('file');

if ($type == 'attachment') {
$path = $file->store('news/' . $id, 'public');

/** @var Attachment */
$attachment = Attachment::create([
'name' => $file->getClientOriginalName(),
'type' => $file->getMimeType(),
'path' => $path,
]);
$attachment->attach($news);
} elseif ($type == 'header') {
$oldImage = $news->getRawOriginal('header_image');
if ($oldImage != null) {
Storage::disk('public')->delete($oldImage);
}
$path = $file->store('news/' . $id . '/' . $type, 'public');

$path = $file->store('news/' . $id, 'public');
$news->header_image = $path;
$news->save();
}
/** @var Attachment */
$attachment = Attachment::create([
'name' => $file->getClientOriginalName(),
'type' => $file->getMimeType(),
'path' => $path,
'metadata' => [
'type' => $type,
],
]);
$attachment->attach($news);

return response()->json(['url' => url(Storage::url($path))]);
}

/**
* Remove an attachment.
* Delete an attachment from the specified resource.
*
* Deletes the specified attachment associated to the given News entity.
* If both are not related to each other or one is not found, a HTTP 404 error is
* returned.
*/
public function detach(News $news, Attachment $attachment)
public function detach(News $news, Attachment $attachment): Response
{
$belongs = $news->attachments()->where('id', $attachment->id)->exists();
if (! $belongs) {
abort(404, 'No matching attachment could be found!');
}

$attachment->detach($news);
$attachment->delete();

return response()->noContent();
}

/**
* List all uploads of the specified resource.
*
* Returns a list of all files associated to a News entity, including the upload types:
* - attachment
* - header
* - content
*
* @param int $id
* @return AnonymousResourceCollection<AttachmentResource>
*/
public function listAttachments(Request $request, $id)
{
$news = $this->find($id, allowGuest: true);

$query = collect(Validator::make($request->query(), [
'type' => 'nullable|string|in:content,header,attachment',
])->validated());

return AttachmentResource::collection($news->attachments);
}

private function find(string $id, ?string $action = null, bool $allowGuest = false): News
{
$query = News::query()
Expand Down
Loading

0 comments on commit 214f3f5

Please sign in to comment.