feat/factory_creation (#1)

Prepping for launch.

Reviewed-on: #1
Co-authored-by: Paul Couture <paul@paulcouture.com>
Co-committed-by: Paul Couture <paul@paulcouture.com>
This commit was merged in pull request #1.
This commit is contained in:
2023-12-14 11:33:03 -06:00
committed by Paul Couture
parent 8eb4d14909
commit c4398c641e
342 changed files with 60893 additions and 2557 deletions

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Artwork;
use App\Models\Episode;
use Illuminate\Support\Facades\DB;
class AddMissingArtworkIdsToEpisodes extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'naart:artwork-to-episodes';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
$oldEpisodes = DB::connection('legacy')->select('SELECT * FROM episodes WHERE artwork_id IS NOT NULL AND published = 1');
foreach($oldEpisodes as $oldEpisode) {
$this->info('Checking old episode ' . $oldEpisode->show_date);
$episode = Episode::where('legacy_id', $oldEpisode->id)->first();
$artwork = Artwork::where('legacy_id', $oldEpisode->artwork_id)->first();
if ($episode && $artwork) {
$this->line('Have artwork ' . $artwork->title . ' for episode ' . $episode->title);
$episode->artwork_id = $artwork->id;
$episode->timestamps = false;
if ($episode->isDirty()) {
$this->info('I need to update this.');
//$episode->save();
} else {
$this->line('No Change Needed.');
}
} else {
$this->error('I am lost.');
}
}
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;
use App\Models\User;
use App\Models\Artist;
use App\Models\Podcast;
use App\Models\Episode;
use App\Models\Artwork;
use ImageOptimizer;
class GetMissingArtworkMovedCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'naart:wrapup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
$missingArtworks = DB::connection('legacy')->select('SELECT * FROM artworks WHERE id > 30835 AND approved_by IS NOT NULL');
foreach ($missingArtworks as $missingArtwork) {
$localPath = '/legacypublic' . $missingArtwork->path . '/' . $missingArtwork->filename;
$user = User::where('legacy_id', $missingArtwork->user_id)->with('artists')->first();
$artwork = Artwork::where('legacy_id', $missingArtwork->id)->first();
$episode = Episode::where('legacy_id', $missingArtwork->episode_id)->first();
$approver = User::where('legacy_id', $missingArtwork->approved_by)->with('artists')->first();
if ($artwork) {
$this->line('Artwork ID: ' . $artwork->id);
}
if ($episode) {
$this->line('Episode: ' . $episode->episode_number . ' "' . $episode->title . '"');
}
if (!$artwork) {
$newFilename = $this->uniqueName($episode, $user, $missingArtwork);
$state = [
'title' => $missingArtwork->title,
'description' => '',
'artist_id' => $user->artists->first()->id,
'episode_id' => $episode->id,
'podcast_id' => 1,
'overlay_id' => null,
'filename' => $newFilename . '.jpg',
'created_at' => Carbon::parse($missingArtwork->created_at),
'updated_at' => Carbon::parse($missingArtwork->updated_at),
'legacy_id' => $missingArtwork->id,
'approved_by' => $approver->artists->first()->id,
];
$artwork = Artwork::factory()->state($state)->create();
}
$this->line('Artist: ' . $user->artists->first()->name);
$this->line($localPath);
$filename = 'artworks/' . $artwork->filename;
$thumbnailName = 'thumbnails/' . $artwork->filename;
if (Storage::disk('static')->exists($filename)) {
$this->error($filename . ' already exists. ' . Storage::disk('static')->size($filename));
}
if (Storage::disk('static')->exists($thumbnailName)) {
$this->error($thumbnailName . ' already exists. ' . Storage::disk('static')->size($thumbnailName));
}
$img = Image::make($localPath)
->resize(3000, null, function ($constraint) {
$constraint->aspectRatio();
})
->encode('jpg', 100);
$thumbImg = Image::make($localPath)
->resize(512, null, function ($constraint) {
$constraint->aspectRatio();
})
->encode('jpg', 100);
$imgLocation = Storage::disk('static')->put($filename, $img);
$thumbLocation = Storage::disk('static')->put($thumbnailName, $thumbImg);
$size_before = Storage::disk('static')->size($filename);
$thumb_size_before = Storage::disk('static')->size($thumbnailName);
ImageOptimizer::optimize(Storage::disk('static')->path($filename));
ImageOptimizer::optimize(Storage::disk('static')->path($thumbnailName));
$size_after = Storage::disk('static')->size($filename);
$thumb_size_after = Storage::disk('static')->size($thumbnailName);
$diff = $size_before - $size_after;
$thumbDiff = $thumb_size_before - $thumb_size_after;
$this->line('Filesize before: ' . $size_before);
$this->line('Filesize after: ' . $size_after);
$this->line('Thumb Filesize before: ' . $thumb_size_before);
$this->line('Thumb Filesize after: ' . $thumb_size_after);
}
}
private function checkExistingFilename($name) {
$checkArtwork = Artwork::where('filename', $name . '.jpg')->count();
return $checkArtwork;
}
private function uniqueName($episode, $user, $missingArtwork) {
$i = 0;
$uniqueFilename = $episode->episode_date->format('Y/m/') . Str::slug($user->artists->first()->name . '-' . $missingArtwork->title) . '_' . $missingArtwork->id;
$exists = $this->checkExistingFilename($uniqueFilename);
if (!$exists) {
return $uniqueFilename;
}
while(!$exists) {
$i++;
$uniqueFilename = $uniqueFilename . '_v' . $i;
$exists = $this->checkExistingFilename($uniqueFilename);
}
return $uniqueFilename;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Artwork;
class LegacyNginxMappingCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'naart:legacy-nginx-mapping';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
$oldLocations = [];
$newLocations = [];
$this->line('# legacy_mappings.conf');
$this->line('');
$this->line('map $uri $new_location {');
$artworks = Artwork::whereNotNull('legacy_filename')->get();
foreach ($artworks as $artwork) {
if (!in_array($artwork->legacy_filename, $oldLocations) && !in_array($artwork->legacy_filename, $newLocations)) {
$oldLocations[] = $artwork->legacy_filename;
$newLocations[] = $artwork->legacy_filename;
$this->line(' "' . $artwork->legacy_filename . '" "/legacy-asset/?legacy_filename=' . urlencode($artwork->legacy_filename) . '";');
}
}
$this->line(' default $uri;');
$this->line('}');
$this->line('');
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use App\Models\Artwork;
use App\Models\Episode;
class MapLegacyArtworkToLegacyEpisodeCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'naart:map-legacy';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Maps legacy artwork to the legacy episode it related to.';
/**
* Execute the console command.
*/
public function handle()
{
$artworks = Artwork::whereNotNull('legacy_id')->get();
foreach ($artworks as $artwork) {
if ($artwork->id > 76200) {
$legacyDetailResponse = $this->getArtworkInfoFromApi($artwork->legacy_id);
$response = $legacyDetailResponse->object();
if ($response->artwork->episode_id) {
$episode = Episode::where('legacy_id', $response->artwork->episode_id)->first();
if ($episode) {
$artwork->episode_id = $episode->id;
$this->line('Artwork ID ' . $artwork->id . ' is mapped to Episode ID ' . $episode->id);
if ($artwork->isDirty()) {
$this->line('This is a new mapping.');
$artwork->save();
}
}
}
}
}
}
private function getArtworkInfoFromApi($artwork_legacy_id) {
$response = Http::timeout(180)
->get('https://noagendaartgenerator.com/artworkapi/' . $artwork_legacy_id,
[
'p' => '7476',
]
);
return $response;
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use App\Models\Artwork;
use App\Models\Episode;
class MapSelectedLegacyArtworkToEpisode extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'naart:map-selected';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Maps the correct artwork selected to the legacy episodes';
/**
* Execute the console command.
*/
public function handle()
{
$episodes = Episode::all();
foreach ($episodes as $episode) {
$this->line('Checking episode ' . $episode->episode_number);
$legacyEpisodeResponse = $this->getEpisodeFromApi($episode->episode_number);
$response = $legacyEpisodeResponse->object();
if ($response->episode->artwork_id && $response->episode->artwork_id + 0 > 0) {
$selectedArtwork = Artwork::where('legacy_id', $response->episode->artwork_id)->first();
if ($selectedArtwork) {
$episode->artwork_id = $selectedArtwork->id;
$this->line('Artwork ID ' . $selectedArtwork->id . ' marked as episode artwork for episode ' . $episode->episode_number);
if ($episode->isDirty()) {
$this->line('This is a new mapping.');
$episode->save();
}
}
}
}
}
private function getEpisodeFromApi($episode_legacy_id) {
$response = Http::timeout(180)
->get('https://noagendaartgenerator.com/episodeapi/' . $episode_legacy_id,
[
'p' => '7476',
]
);
return $response;
}
}

View File

@@ -0,0 +1,27 @@
<?php
if (!function_exists('numberSuffix')) {
function numberSuffix($number) {
if (!is_int($number) || $number < 1) {
return $number;
}
$lastDigit = $number % 10;
$secondLastDigit = ($number / 10) % 10;
if ($secondLastDigit == 1) {
return 'th';
}
switch ($lastDigit) {
case 1:
return 'st';
case 2:
return 'nd';
case 3:
return 'rd';
default:
return 'th';
}
}
}

View File

@@ -3,6 +3,9 @@
namespace App\Http\Controllers;
use App\Models\Artist;
use App\Models\Artwork;
use App\Models\Podcast;
use App\Models\Episode;
use Illuminate\Http\Request;
class ArtistController extends Controller
@@ -14,7 +17,18 @@ class ArtistController extends Controller
*/
public function index()
{
//
$user = auth()->user();
$artists = Artist::whereHas('artworks')
->withCount('artworks')
->orderBy('artworks_count', 'desc')
->paginate(100);
$podcasts = Podcast::where('published', true)->with('episodes')->get();
return view('profile.artists', [
'user' => $user,
'pageTitle' => 'Artists',
'podcasts' => $podcasts,
'artists' => $artists,
]);
}
/**
@@ -44,9 +58,23 @@ class ArtistController extends Controller
* @param \App\Models\Artist $artist
* @return \Illuminate\Http\Response
*/
public function show(Artist $artist)
public function show(Request $request, $slug)
{
//
$user = auth()->user();
$artist = Artist::where('slug', $slug)
->firstOrFail();
$artworks = Artwork::where('artist_id', $artist->id)
->with('episode')
->with('podcast')
->orderBy('artworks.created_at', 'desc')
->paginate($perPage = 92, $columns = ['*'], $pageName = 'artworks');
$podcasts = Podcast::where('published', true)->with('episodes')->get();
return view('profile.artist', [
'user' => $user,
'artist' => $artist,
'artworks' => $artworks,
'podcasts' => $podcasts,
]);
}
/**

View File

@@ -3,7 +3,18 @@
namespace App\Http\Controllers;
use App\Models\Artwork;
use App\Models\Podcast;
use App\Models\Episode;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;
use ImageOptimizer;
class ArtworkController extends Controller
{
@@ -14,7 +25,19 @@ class ArtworkController extends Controller
*/
public function index()
{
//
$user = auth()->user();
$artworks = Artwork::whereNotNull('approved_by')
->with('artist')
->orderBy('episode_id', 'desc')
->orderBy('created_at', 'desc')
->paginate($perPage = 3, $columns = ['*'], $pageName = 'artworks');
$podcasts = Podcast::where('published', true)->with('episodes')->get();
return view('explore.artworks', [
'user' => $user,
'pageTitle' => 'Explore',
'artworks' => $artworks,
'podcasts' => $podcasts,
]);
}
/**
@@ -24,7 +47,13 @@ class ArtworkController extends Controller
*/
public function create()
{
//
$user = auth()->user();
$podcasts = Podcast::where('published', true)->with('episodes')->get();
return view('artworks.submit', [
'user' => $user,
'pageTitle' => 'Submit New Artwork',
'podcasts' => $podcasts,
]);
}
/**
@@ -33,20 +62,79 @@ class ArtworkController extends Controller
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
public function store(Request $request): RedirectResponse
{
//
$validator = Validator::make($request->all(), [
'title' => ['required', 'max:255',],
'podcast' => ['required', 'exists:podcasts,id',],
'description' => ['nullable',],
'file' => ['required', 'image', Rule::dimensions()->ratio(1)->minWidth(512),],
]);
if ($validator->fails()) {
return back()
->withErrors($validator)
->withInput();
}
Log::channel('artwork_import')->info('making new artwork model.');
$podcast = Podcast::where('id', $request->podcast)->with(['episodes' => function($query) {
$query->orderBy('episode_number', 'desc')->limit(1);
}])->first();
$episode = $podcast->episodes->first();
$artist = auth()->user()->artists()->first();
$rawFile = $request->file('file');
$filename = now()->format('Y')
. '/'
. now()->format('m')
. '/'
. Str::slug($artist->name)
. '-'
. Str::slug($request->title)
. '_'
. Str::random(8)
. '.jpg';
$artwork = Artwork::factory()->state([
'title' => $request->title,
'artist_id' => $artist->id,
'description' => $request->description,
'overlay_id' => null,
'podcast_id' => $podcast->id,
'episode_id' => $episode->id,
'filename' => $filename,
])->create();
$img = Image::make($rawFile)->resize(3000, null, function($constraint){
$constraint->aspectRatio();
})
->encode('jpg', 100)
->save(Storage::disk('static')->path('/artworks') . '/' . $artwork->filename);
$thumbImg = Image::make($request->file('file'))->resize(512, null, function($constraint){
$constraint->aspectRatio();
})
->encode('jpg', 100)
->save(Storage::disk('static')->path('/thumbnails') . '/' . $artwork->filename);
ImageOptimizer::optimize(Storage::disk('static')->path('/artworks/' . $artwork->filename));
ImageOptimizer::optimize(Storage::disk('static')->path('/thumbnails/' . $artwork->filename));
return redirect('/artworks/' . $artwork->id);
}
/**
* Display the specified resource.
*
* @param \App\Models\Artwork $artwork
* @param \Illuminate\Http\Request $request
* @param the id of the \App\Models\Artwork $id
* @return \Illuminate\Http\Response
*/
public function show(Artwork $artwork)
public function show(Request $request, $id)
{
//
$user = auth()->user();
$artwork = Artwork::where('id', $id)
->with('podcast')
->with('episode')
->with('artist')
->first();
return view('artworks.artwork', [
'artwork' => $artwork,
'user' => $user,
]);
}
/**
@@ -82,4 +170,11 @@ class ArtworkController extends Controller
{
//
}
public function legacyArtLink(Request $request, $any = null)
{
phpinfo();
dd($request->path());
//$artwork = Artwork::where('legacy_filename', '/assets/artwork/')
}
}

View File

@@ -4,10 +4,12 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Artist;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
@@ -31,17 +33,24 @@ class RegisteredUserController extends Controller
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'name' => ['unique:artists,name', 'required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'name' => trim($request->name),
'email' => trim(strtolower($request->email)),
'password' => Hash::make($request->password),
]);
$artist = Artist::create([
'user_id' => $user->id,
'name' => trim($request->name),
'slug' => Str::slug(trim($request->name)),
'location' => 'No Agenda Nation',
]);
event(new Registered($user));
Auth::login($user);

View File

@@ -2,8 +2,12 @@
namespace App\Http\Controllers;
use App\Models\Episode;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\Models\Podcast;
use App\Models\Artworks;
use App\Models\Episode;
class EpisodeController extends Controller
{
@@ -44,9 +48,26 @@ class EpisodeController extends Controller
* @param \App\Models\Episode $episode
* @return \Illuminate\Http\Response
*/
public function show(Episode $episode)
public function show(Request $request, $podcast_slug, $slug)
{
//
$user = auth()->user();
$episode = Episode::where('slug', $slug)
->with('artworks')
->with('artwork')
->with('podcast')
->firstOrFail();
$podcasts = Podcast::where('published', true)->with('episodes', function ($query) {
$query->orderBy('episode_number', 'desc');
$query->where('published', true);
$query->take(10);
})->get();
return view('episodes.episode', [
'user' => $user,
'pageTitle' => '"' . $episode->title . '" ' . $episode->podcast->name . ' Episode ' . number_format($episode->episode_number + 0),
'podcast' => $episode->podcast,
'episode' => $episode,
'podcasts' => $podcasts,
]);
}
/**

View File

@@ -0,0 +1,144 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\Models\Artwork;
use App\Models\Artist;
use App\Models\Episode;
class PageController extends Controller
{
public function landing(Request $request)
{
$user = auth()->user();
$headerCounters = $this->getHeaderCounters();
$recentEpisodes = $this->mostRecentEpisodes();
$recentSubmissions = $this->mostRecentSubmissions();
$leaderboard = $this->leaderboardTwelveMonths();
return view('home.page', [
'user' => $user,
'pageTitle' => 'Home',
'headerCounters' => $headerCounters,
'recentEpisodes' => $recentEpisodes,
'recentSubmissions' => $recentSubmissions,
'leaderboard' => $leaderboard,
'preferredTheme' => $request->session()->get('preferred_theme') ?? 'dark',
]);
}
private function mostRecentSubmissions() {
$artworks = Cache::remember('latestSubmissions', 30, function() {
return Artwork::whereNotNull('approved_by')
->with('artist')
->with('episode')
->with('podcast')
->orderBy('created_at', 'desc')
->limit(50)
->get();
});
return $artworks;
}
private function mostRecentEpisodes()
{
$episodes = Cache::remember('latestEpisodes', 30, function() {
return Episode::where('published', true)
->whereHas('artwork')
->with('podcast')
->with('artwork')
->with('artwork.artist')
->orderBy('episode_date', 'desc')
->limit(10)
->get();
});
return $episodes;
}
private function getHeaderCounters()
{
$headerCounters = [];
$artworkCountNumber = Cache::remember('artworkCountNumber', 10, function() {
return Artwork::all()->count();
});
$artistCountNumber = Cache::remember('artistCountNumber', 10, function() {
return Artist::all()->count();
});
$episodeCountNumber = Cache::remember('episodeCountNumber', 10, function() {
return Episode::all()->count();
});
$headerCounters['Artworks'] = $this->shortNumberCount($artworkCountNumber);
$headerCounters['Artists'] = $this->shortNumberCount($artistCountNumber);
$headerCounters['Episodes'] = $this->shortNumberCount($episodeCountNumber);
return $headerCounters;
}
private function shortNumberCount($number)
{
$units = ['', 'K', 'M', 'B', 'T'];
for ($i = 0; $number >= 1000; $i++) {
$number /= 1000;
}
return [
'number' => $this->numberFormatPrecision($number, 1), //number_format(floatval($number), 1),
'unit' => $units[$i],
];
}
private function numberFormatPrecision($number, $precision = 2, $separator = '.')
{
$numberParts = explode($separator, $number);
$response = $numberParts[0];
if (count($numberParts)>1 && $precision > 0) {
$response .= $separator;
$response .= substr($numberParts[1], 0, $precision);
}
return $response;
}
private function leaderboardTwelveMonths() {
$endDate = now()->endOfDay()->subYear()->format('Y-m-d');
$leaderboard = DB::table('episodes')
->join('artworks', 'artworks.id', '=', 'episodes.artwork_id')
->join('artists', 'artists.id', '=', 'artworks.artist_id')
->select([
DB::raw('artists.id as artistId'),
DB::raw('artists.name as artistName'),
DB::raw('count(artworks.id) as artworkCount')
])
->where('episodes.published', 1)
->where('episodes.episode_date', '>=', $endDate)
->groupBy('artistId')
->orderByDesc('artworkCount')
->limit(10)
->get();
$leaderboard = $this->addArtistModelToLeaderboard($leaderboard);
return $leaderboard;
}
private function addArtistModelToLeaderboard($leaderboard) {
$artistIds = [];
foreach ($leaderboard as $lb) {
$artistIds[] = $lb->artistId;
}
$artists = Artist::whereIn('id', $artistIds)->get();
foreach ($leaderboard as $lb) {
$lb->artist = $artists->where('id', $lb->artistId)->first();
}
$p = 0;
foreach ($leaderboard as $lb) {
$p++;
$lb->position = $p;
}
return $leaderboard;
}
public function setSessionTheme(Request $request) {
}
}

View File

@@ -3,8 +3,34 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\Models\Podcast;
use App\Models\Artworks;
use App\Models\Episode;
class PodcastController extends Controller
{
//
public function show(Request $request, $slug)
{
$user = auth()->user();
$podcast = Podcast::where('slug', $slug)
->where('published', true)
->firstOrFail();
$episodes = Episode::where('published', true)
->whereNotNull('artwork_id')
->with('artwork')
->with('artworks')
->where('podcast_id', $podcast->id)
->orderBy('episode_number', 'desc')->paginate(100);
$podcasts = Podcast::where('published', true)->with('episodes')->get();
return view('podcasts.podcast', [
'user' => $user,
'pageTitle' => $podcast->name,
'podcast' => $podcast,
'episodes' => $episodes,
'podcasts' => $podcasts,
]);
}
}

View File

@@ -39,7 +39,7 @@ class Kernel extends HttpKernel
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Models\Artist;
use Carbon\Carbon;
use App\Jobs\StashAndOptimizeLegacyArtworkJob;
class ImportLegacyUserJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
/**
* Create a new job instance.
*/
public function __construct($user)
{
$this->user = $user;
}
/**
* Execute the job.
*/
public function handle(): void
{
$name = str_replace(' ', '', $this->user->username);
$email = strtolower(trim($this->user->email));
$email_verified_at = Carbon::parse($this->user->created_at);
$this->createUser($name, $email, $email_verified_at);
}
private function createUser($name, $email, $email_verified_at)
{
$user = User::where('name', $name)->first();
if (!$user) {
$user = User::factory()->state([
'name' => $name,
'email' => $email,
'email_verified_at' => $email_verified_at,
'remember_token' => null,
])->create();
}
$artist = Artist::where('user_id', $user->id)->first();
if (!$artist) {
$artist = Artist::factory()->state([
'user_id' => $user->id,
'name' => $this->user->profile->name,
'avatar' => null,
'header' => null,
'location' => $this->user->profile->location ?? 'No Agenda Art Generator',
'website' => $this->user->profile->website ?? null,
'bio' => null,
])->create();
}
foreach ($this->user->artworks as $artwork) {
StashAndOptimizeLegacyArtworkJob::dispatch($artist, $artwork);
}
}
}

View File

@@ -0,0 +1,125 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Models\Artist;
use App\Models\Artwork;
use App\Models\Episode;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;
use Carbon\Carbon;
use ImageOptimizer;
class StashAndOptimizeLegacyArtworkJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $artist;
protected $artwork;
public $tries = 2;
/**
* Create a new job instance.
*/
public function __construct($artist, $artwork)
{
$this->artist = $artist;
$this->artwork = $artwork;
}
/**
* Execute the job.
*/
public function handle(): void
{
$date = Carbon::parse($this->artwork->created_at);
$basename = $date->format('Y')
. '/' . $date->format('m')
. '/' . Str::slug($this->artist->name)
. '-' . Str::slug($this->artwork->title)
. '_' . $this->artwork->id . '.jpg';
$filename = 'artworks/' . $basename;
$thumbnailName = 'thumbnails/' . $basename;
if (Storage::disk('static')->exists($filename)) {
Log::channel('artwork_import')->error($filename . ' already exists. Filesize: ' . Storage::disk('static')->size($filename));
$this->createArtwork($basename);
return;
}
$img = Image::make('/legacypublic' . $this->artwork->path . '/' . $this->artwork->filename)
->resize(3000, null, function ($constraint) {
$constraint->aspectRatio();
})
->encode('jpg', 100);
$thumbImg = Image::make('/legacypublic' . $this->artwork->path . '/' . $this->artwork->filename)
->resize(512, null, function ($constraint) {
$constraint->aspectRatio();
})
->encode('jpg', 100);
$imgLocation = Storage::disk('static')->put($filename, $img);
$thumbLocation = Storage::disk('static')->put($thumbnailName, $thumbImg);
$size_before = Storage::disk('static')->size($filename);
$thumb_size_before = Storage::disk('static')->size($thumbnailName);
ImageOptimizer::optimize(Storage::disk('static')->path($filename));
ImageOptimizer::optimize(Storage::disk('static')->path($thumbnailName));
$size_after = Storage::disk('static')->size($filename);
$thumb_size_after = Storage::disk('static')->size($thumbnailName);
$diff = $size_before - $size_after;
$thumbDiff = $thumb_size_before - $thumb_size_after;
Log::channel('artwork_import')->info('Filesize Before: ' . $size_before);
Log::channel('artwork_import')->info('Filesize After: ' . $size_after);
$perc_smaller = ($diff / $size_before) * 100;
$thumb_perc_smaller = ($thumbDiff / $thumb_size_before) * 100;
Log::channel('artwork_import')->info(number_format($perc_smaller, 2) . '% smaller.');
Log::channel('artwork_import')->info(number_format($thumb_perc_smaller, 2) . '% smaller thumbnail - ' . $thumb_size_after);
Log::channel('artwork_import')->info('Saved and resized ' . $filename);
$this->createArtwork($basename);
}
private function createArtwork($basename) {
$artwork = Artwork::where('legacy_id', $this->artwork->id)->first();
if (!$this->artwork->episode_id) {
$episode = Episode::where('episode_date', '>=', Carbon::parse($this->artwork->created_at)->startOfDay())
->orderBy('episode_date', 'asc')
->first();
} else {
$episode = Episode::where('legacy_id', $this->artwork->episode_id)->first();
}
if (!$artwork) {
$artwork = Artwork::where('filename', $basename)->first();
if ($artwork) {
$artwork->legacy_id = $this->artwork->id;
$artwork->episode_id = $episode->id ?? null;
$artwork->save();
return;
}
}
if (!$artwork) {
Log::channel('artwork_import')->info('making new artwork model for ' . $basename);
Artwork::factory()->state([
'title' => $this->artwork->title,
'artist_id' => $this->artist->id,
'description' => '',
'podcast_id' => 1,
'overlay_id' => $this->artwork->overlay_id,
'episode_id' => $episode->id ?? null,
'filename' => $basename ?? null,
'created_at' => Carbon::parse($this->artwork->created_at),
'updated_at' => Carbon::parse($this->artwork->updated_at),
'legacy_id' => $this->artwork->id,
])->create();
} else {
Log::channel('artwork_import')->info($artwork->id . ' has a model it exists with ' . $artwork->filename);
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Counter extends Component
{
public $count = 1;
public function increment()
{
$this->count++;
}
public function decrement()
{
$this->count--;
}
public function render()
{
return view('livewire.counter');
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Livewire;
use Livewire\Component;
class Themeswitch extends Component
{
public function light()
{
session()->put('preferred_theme', 'light');
}
public function dark()
{
session()->put('preferred_theme', 'dark');
}
public function render()
{
return view('livewire.themeswitch');
}
}

View File

@@ -16,9 +16,29 @@ class Artist extends Model
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
protected $fillable = [
'user_id',
'name',
'slug',
'avatar',
'header',
'location',
'website',
'bio',
'created_at',
'updated_at',
'deleted_at',
];
public function user()
{
return $this->belongs_to(User::class);
return $this->belongsTo(User::class);
}
public function artworks()

View File

@@ -16,6 +16,12 @@ class Artwork extends Model
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
public function podcast()
{
return $this->belongsTo(Podcast::class);

View File

@@ -14,6 +14,13 @@ class Episode extends Model
protected $dates = ['episode_date', 'created_at', 'updated_at', 'deleted_at'];
protected $casts = [
'episode_date' => 'date',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
public function podcast()
{
return $this->belongsTo(Podcast::class);
@@ -21,7 +28,12 @@ class Episode extends Model
public function artwork()
{
return $this->hasOne(Artwork::class);
return $this->hasOne(Artwork::class, 'id', 'artwork_id');
}
public function artworks()
{
return $this->hasMany(Artwork::class);
}
public function artist()

View File

@@ -16,6 +16,12 @@ class Overlay extends Model
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
];
public function artist()
{
return $this->belongsTo(Artist::class);

View File

@@ -16,6 +16,13 @@ class Podcast extends Model
protected $dates = ['created_at', 'updated_at', 'deleted_at', 'added_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'added_at' => 'datetime',
];
public function episodes()
{
return $this->hasMany(Episode::class);

View File

@@ -14,8 +14,6 @@ class User extends Authenticatable
protected $table = 'users';
protected $dates = ['created_at', 'updated_at'];
/**
* The attributes that are mass assignable.
*
@@ -44,6 +42,17 @@ class User extends Authenticatable
*/
protected $casts = [
'email_verified_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* The attributes that should be appended.
*
* @var array<string, string>
*/
protected $appends = [
];
public function artists()

View File

@@ -13,6 +13,11 @@ class Wallet extends Model
protected $dates = ['created_at', 'updated_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public function walletType()
{
return $this->hasOne(WalletType::class);

View File

@@ -13,6 +13,11 @@ class WalletType extends Model
protected $dates = ['created_at', 'updated_at'];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public function wallets()
{
return $this->hasMany(Wallet::class);

View File

@@ -3,6 +3,9 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\View;
use App\Models\Podcast;
class AppServiceProvider extends ServiceProvider
{
@@ -19,6 +22,8 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
//
Paginator::useBootstrapFive();
$publishedPodcasts = Podcast::where('published', true)->select(['name', 'slug'])->get();
View::share(['navPodcasts' => $publishedPodcasts]);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace App\Providers\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}

View File

@@ -17,7 +17,7 @@ class RouteServiceProvider extends ServiceProvider
*
* @var string
*/
public const HOME = '/dashboard';
public const HOME = '/';
/**
* Define your route model bindings, pattern filters, and other route configuration.