add models, setup livewire, setup mongodb

This commit is contained in:
yuriko 🦊 2025-05-21 15:14:50 -04:00
parent c0590a3412
commit be4c848eee
Signed by: jaiden
SSH key fingerprint: SHA256:f8tvveBoXBrKZIQDWLLcpQrKbATUCGg98x2N4YzkDM8
27 changed files with 2508 additions and 0 deletions

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class AuthController extends Controller
{
public function handleRedirect()
{
return Socialite::driver('authentik')->redirect();
}
public function handleCallback()
{
$user = Socialite::driver('authentik')->user();
$authUser = User::updateOrCreate(
[ 'email' => $user->getEmail() ],
[ 'name' => $user->getName() ]
);
if ($authUser)
{
Auth::login($authUser);
return redirect('/');
}
abort(401);
}
public function handleLogout()
{
Auth::logout();
return redirect('/');
}
}

13
app/Livewire/App/Home.php Normal file
View file

@ -0,0 +1,13 @@
<?php
namespace App\Livewire\App;
use Livewire\Component;
class Home extends Component
{
public function render()
{
return view('livewire.app.home');
}
}

View file

@ -0,0 +1,13 @@
<?php
namespace App\Livewire\App;
use Livewire\Component;
class Navbar extends Component
{
public function render()
{
return view('livewire.app.navbar');
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace App\Livewire\Pages;
use App\Models\Post;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\Laravel\Facades\Image;
use Livewire\Attributes\Title;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\WithFileUploads;
class Upload extends Component
{
use WithFileUploads;
#[Validate('extensions:jpg,jpeg,bmp,gif,png,webp,apng,mp4,wmv,mkv|mimes:jpg,jpeg,bmp,gif,png,webp,apng,mp4,wmv,mkv|max:81920')]
public $file;
#[Validate('required|in:safe,suggestive,explicit')]
public $rating = 'safe';
#[Title('Upload')]
public function render()
{
return view('livewire.pages.upload');
}
public function createPost()
{
$this->validate();
$author = Auth::user();
if ($this->file)
{
$post = Post::create([
'extension' => $this->file->getClientOriginalExtension(),
'rating' => $this->rating,
]);
if ($post)
{
$author->posts()->save($post);
// Save the full image
$this->file->storeAs("posts/$post->id", 'full');
$fullImg = Storage::get("posts/$post->id/full");
// Create thumbnail preview
$thumb = Image::read($fullImg)->scaleDown(width: 512, height: 512);
Storage::put("posts/$post->id/thumb", $thumb->encodeByExtension($post->extension, quality: 70));
// Create smaller preview image
$preview = Image::read($fullImg)->scaleDown(width: 1280, height: 720);
Storage::put("posts/$post->id/preview", $preview->encodeByExtension($post->extension, quality: 70));
return $this->redirect('/');
}
}
return $this->redirect('/upload');
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace App\Livewire;
use App\Models\Post;
use Livewire\Component;
class PostFeature extends Component
{
public ?Post $post = null;
public function mount()
{
$this->post = Post::raw(function($collection)
{
return $collection->aggregate([
['$match' => ['featured' => 'on']],
['$sample' => ['size' => 1]]
]);
})->first();
}
public function render()
{
if ($this->post == null)
{
return <<<'HTML'
<div></div>
HTML;
}
return view('livewire.post-feature');
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace App\Livewire\Posts;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Attributes\Validate;
use Livewire\Component;
class Edit extends Component
{
public Post $post;
public Collection $tags;
public Collection $selectableTags;
#[Validate('exists:tags,id')]
public string $tag = '';
#[Validate('required|in:safe,suggestive,explicit')]
public string $rating = 'unknown';
public $featured = false;
public string $deleteTagId = '';
public function mount(Post $post)
{
$this->post = $post;
$this->tags = $post->tags;
$this->rating = $post->rating;
$this->featured = $post->featured;
$this->selectableTags = Tag::whereDoesntHave('posts', function ($query) {
$query->where('id', $this->post->id);
})->get();
}
public function render()
{
return view('livewire.posts.edit')->title("Edit post {$this->post->id}");
}
public function updated()
{
$this->validate();
if ($this->tag)
{
if ($tag = Tag::find($this->tag))
{
$this->post->tags()->attach($tag);
if ($tag->implies)
{
foreach ($tag->implies as $implied_id)
{
if ($impliedTag = Tag::find($implied_id))
{
$this->post->tags()->attach($impliedTag);
}
}
}
}
}
$this->post->rating = $this->rating;
if ($this->post->rating == 'safe')
{
$this->post->featured = $this->featured;
}
else
{
$this->post->featured = null;
}
$this->post->save();
$this->tags = $this->post->tags;
$this->selectableTags = Tag::whereDoesntHave('posts', function ($query) {
$query->where('id', $this->post->id);
})->get();
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\Livewire\Posts;
use App\Models\Post;
use Livewire\Component;
class Image extends Component
{
public Post $post;
public function placeholder()
{
return <<<'HTML'
<div class="wa-stack" style="display: flex; align-items: center; justify-content: center; max-height: 80vh;">
<div class="wa-frame wa-border-radius-l" style="max-inline-size: 100%;">
<wa-spinner></wa-spinner>
</div>
</div>
HTML;
}
public function render()
{
return view('livewire.posts.image');
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Livewire\Posts;
use App\Models\Post;
use Livewire\Attributes\Title;
use Livewire\Component;
use Livewire\WithPagination;
class Index extends Component
{
use WithPagination;
#[Title('Posts')]
public function render()
{
return view('livewire.posts.index', [
'posts' => Post::orderBy('created_at', 'desc')->paginate(25),
]);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace App\Livewire\Posts;
use App\Models\Post;
use Livewire\Component;
class Thumbnail extends Component
{
public Post $post;
public function placeholder()
{
return <<<'HTML'
<div style="display: flex; align-items: center; justify-content: center; width: 256px; height: 256px;">
<wa-spinner style="font-size: 4rem;"></wa-spinner>
</div>
HTML;
}
public function render()
{
return view('livewire.posts.thumbnail');
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace App\Livewire\Posts;
use App\Models\Post;
use Livewire\Attributes\Validate;
use Livewire\Component;
class View extends Component
{
public Post $post;
#[Validate('string|max:240')]
public $comment = '';
public function render()
{
return view('livewire.posts.view', [
// 'comments' => $this->post->comments
])->title("Post {$this->post->id}");
}
}

109
app/Models/Post.php Normal file
View file

@ -0,0 +1,109 @@
<?php
namespace App\Models;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Relations\BelongsTo;
use MongoDB\Laravel\Relations\BelongsToMany;
use Symfony\Component\HttpFoundation\StreamedResponse;
class Post extends Model
{
protected $fillable = [ 'rating', 'extension', 'featured' ];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
protected function toBase64(string $path): string
{
$ext = $this->extension;
$file = Storage::get($path);
$data = base64_encode($file);
return "data:image/$ext;base64,$data";
}
public function getThumbUrl(): ?string
{
if (Storage::has("posts/$this->id/thumb"))
{
return $this->toBase64("posts/$this->id/thumb");
}
return $this->getPreviewUrl();
}
public function getPreviewUrl(): ?string
{
if (Storage::has("posts/$this->id/preview"))
{
return $this->toBase64("posts/$this->id/preview");
}
return $this->getFullUrl();
}
public function getFullUrl(): ?string
{
if (Storage::has("posts/$this->id/full"))
{
return $this->toBase64("posts/$this->id/full");
}
abort(404);
}
public function getMimeType(): ?string
{
return Storage::mimeType("posts/$this->id/full");
}
public function getDimensions(): false|array
{
return getimagesize($this->getFullUrl());
}
public function getAspectRatio(): string
{
list($width, $height) = $this->getDimensions();
$divisor = gmp_intval(gmp_gcd($width, $height));
$w = $width / $divisor;
$h = $height / $divisor;
return "aspect-ratio: $w/$h;";
}
public function download(): StreamedResponse
{
return Storage::download("posts/$this->id/full");
}
public function getNextPost(): ?Post
{
return Post::where('created_at', '>', $this->created_at)
->orderBy('created_at', 'asc')
->first();
}
public function getPreviousPost(): ?Post
{
return Post::where('created_at', '<', $this->created_at)
->orderBy('created_at', 'desc')
->first();
}
public function getRatingColor(): string
{
return match ($this->rating)
{
'safe' => 'success',
'suggestive' => 'warning',
'explicit' => 'danger',
default => 'default',
};
}
}

16
app/Models/Tag.php Normal file
View file

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Relations\BelongsToMany;
class Tag extends Model
{
protected $fillable = [ 'name', 'slug', 'implies' ];
public function posts(): BelongsToMany
{
return $this->belongsToMany(Post::class);
}
}