From 573054e7d8dc09f9452c9500db4db1c9ed23d7cb Mon Sep 17 00:00:00 2001 From: ro Date: Thu, 15 Feb 2024 15:00:03 -0600 Subject: [PATCH] Cleaned up location controller, responsive fix The Location Controller was getting too heavy so an Update and Maintenance service class was created to offload most of it's functionality. Location upating was moved to LocationRepository There was also a small issue with responsive list links not adapting properly in Safari that was fixed --- app/Http/Controllers/LocationController.php | 261 +------------------- app/Providers/AppServiceProvider.php | 10 + app/Repositories/LocationRepository.php | 39 +++ app/Services/MaintenanceService.php | 41 +++ app/Services/UpdateService.php | 198 +++++++++++++++ public/assets/css/front/listing.css | 2 +- 6 files changed, 302 insertions(+), 249 deletions(-) create mode 100644 app/Services/MaintenanceService.php create mode 100644 app/Services/UpdateService.php diff --git a/app/Http/Controllers/LocationController.php b/app/Http/Controllers/LocationController.php index 1e87e74..a2fc4cc 100644 --- a/app/Http/Controllers/LocationController.php +++ b/app/Http/Controllers/LocationController.php @@ -2,262 +2,27 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; -use App\Models\Location; -use Ramsey\Uuid\Uuid; -use Illuminate\Support\Facades\Auth; -use App\Models\Source; +use App\Services\UpdateService; class LocationController extends Controller { - public function addLocation(Request $request) - { - $fields = $request->validate([ - 'name' => ['required'], - 'url' => ['required'], - 'description' => ['required'], - 'tags' => ['required'], - ]); + protected $update; - if ($fields) { - $examples = []; - $files = $request->files->get("loc_examples"); - if ($request->hasfile('loc_examples')) { - foreach ($request->file('loc_examples') as $file) { - $path = $file->store('reference'); - array_push($examples, ["path" => $path]); - } - } - $request->merge(['active' => true]); - $request->merge(['uuid' => Uuid::uuid4()]); - $request->merge(['images' => json_encode($examples)]); - $request->merge(['added_by' => Auth::user()->id]); - //NOTE: Laravel gets funky if sequencing isn't explicitly set - $new = Location::create($request->all()); - if ($new) { - return back()->with('message', 'New Location Added. Take a break!'); - } else { - return back()->withErrors([ - 'error' => 'Uh oh. There was an inssue', - ]); - } - } else { - return back()->withErrors([ - 'error' => 'All fields are required', - ]); - } + public function __construct(UpdateService $updateService) + { + $this->update = $updateService; } public function updateLocations() { - $duplicates = 0; - $fresh = 0; - $missing = []; + $result = $this->update->locations(); - $unified = []; - $cleanSources = []; - $sources = Source::where("active", true)->get(); - - //checks source url to make sure they valid - foreach ($sources as $source) { - if ($source->type == 'mastodon') { - $url = 'https://' . $source->url; - } else { - $url = $source->url; - } - - if ($this->urlExists($url)) { - array_push($cleanSources, [ - 'url' => $source->url, - 'token' => $source->token, - 'type' => $source->type, - 'format' => $source->format]); - } else { - var_dump($url); - array_push($missing, ['source' => $url]); - } - } - - //valid source url get compiled for unified - foreach ($cleanSources as $source) { - //check url to make sure it's cool - - //parsing for mastodon - if ($source['type'] == 'mastodon') { - $result = []; - if ($source['token'] == null) { - $result = \Mastodon::domain('https://' . $source['url']) - ->get('/instance/domain_blocks'); - } else { - $result = \Mastodon::domain('https://' . $source['url']) - ->token($source['token']) - ->get('/instance/domain_blocks'); - } - - foreach ($result as $item) { - $index = array_search($item['domain'], array_column($unified, 'url')); - if ($index) { - //if there is a match, update the count - if ($item['severity'] == "suspend" || $item['severity'] == "defederate") { - ++$unified[$index]['block_count']; - } else { - ++$unified[$index]['silence_count']; - } - } else { - $silence = 0; - $suspend = 0; - if ($item['severity'] == "suspend" || $item['severity'] == "defederate") { - ++$suspend; - } else { - ++$silence; - } - array_push($unified, [ - 'name' => $item['domain'], - 'url' => $item['domain'], - 'rating' => $item['severity'], - 'comment' => $item['comment'], - 'block_count' => $suspend, - 'silence_count' => $silence, - ]); - } - } - } - //parsing for custom csv - if ($source['type'] == 'custom' && $source['format'] == 'csv') { - $denylist = array_map('str_getcsv', file($source['url'])); - foreach ($denylist as $item) { - $index = array_search($item[0], array_column($unified, 'url')); - if ($index) { - //if there is a match, update the count - if ($item[1] == "suspend" || $item['severity'] == "defederate") { - ++$unified[$index]['block_count']; - } else { - ++$unified[$index]['silence_count']; - } - } else { - $silence = 0; - $suspend = 0; - if ($item[1] == "suspend" || $item[1] == "defederate") { - ++$suspend; - } else { - ++$silence; - } - array_push($unified, [ - 'name' => $item[0], - 'url' => $item[0], - 'rating' => $item[1], - 'comment' => $item[2], - 'block_count' => $suspend, - 'silence_count' => $silence, - ]); - } - } - } - } - - //TODO: maintenance script to set locations to inactive if they haven't been updated - // over 90 days - - //$diff=date_diff($location->updated_at, new DateTime()); - //$days = $diff->format("%R%a days") - - //$interval = $location->updated_at->diff(new DateTime()); - //$days = $interval->format("%a"); - - //get all locations and sort which are present in unified or not - /* - $sorted = []; - $listed = 0; - $notlisted = 0; - foreach (Location::all() as $location) { - if (array_search($location->url, array_column($unified, 'url'))) { - ++$listed; - // locations present in unfied, so updated - array_push($sorted, [ - 'location' => $location, - 'listed' => true - ]); - } else { - ++$notlisted; - //locations not present - array_push($sorted, [ - 'location' => $location, - 'listed' => false - ]); - } - }; - */ - - //once the unified list is created, update current entries or create fresh ones - - foreach ($unified as $item) { - $location = Location::where("url", $item['url'])->first(); - if ($location) { - ++$duplicates; - //update block count for existing item - - $location->block_count = $item['block_count']; - $location->silence_count = $item['silence_count']; - - $location->actions_count = $item['block_count'] + $item['silence_count']; - - if (($item['block_count'] + $item['silence_count']) < 2) { - $location->active = false; - } - - //replace null with empty array - if ($location->images == null) { - $location->images = []; - }; - $location->save(); - } else { - // make new entries for instances not present - ++$fresh; - $images = []; - $rating = ($item['rating'] == 'defederate') ? 'suspend' : $item['rating']; - - $status = true; - if (($item['block_count'] + $item['silence_count']) < 2) { - $status = false; - } - - $new = Location::create([ - 'uuid' => Uuid::uuid4(), - 'name' => $item['url'], - 'url' => $item['url'], - 'description' => ($item['comment'] != null) ? $item['comment'] : "no description", - 'active' => $status, - 'rating' => $rating, - 'added_by' => 1, - 'tags' => 'poor moderation, hate speech', - 'images' => json_encode($images), - 'block_count' => $item['block_count'], - 'silence_count' => $item['silence_count'], - 'actions_cont' => $item['block_count'] + $item['silence_count'] - ]); - } - } - //TODO: Send update post to TBS social account - - return back()->with('message', $duplicates . ' UPDATED - ' . $fresh . ' CREATED - ' . count($missing) . ' SOURCE(S) NOT CHECKED'); - } - - public function urlExists($url) - { - // Remove all illegal characters from a url - $url = filter_var($url, FILTER_SANITIZE_URL); - // Validate URI - if ( - filter_var($url, FILTER_VALIDATE_URL) === false || // check only for http/https schemes. - !in_array( - strtolower(parse_url($url, PHP_URL_SCHEME)), - ["http", "https"], - true - ) - ) { - return false; - } // Check that URL exists - $file_headers = @get_headers($url); - return !(!$file_headers || $file_headers[0] === "HTTP/1.1 404 Not Found"); + return back()->with( + 'message', + $result['duplicates'] . + ' UPDATED - ' . $result['fresh'] . + ' CREATED - ' . count($result['missing']) . + ' SOURCE(S) NOT CHECKED' + ); } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 6b854fa..6e4f77f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,8 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Repositories\LocationRepository; +use App\Services\UpdateService; +use App\Services\MaintenanceService; use App\Models\Location; class AppServiceProvider extends ServiceProvider @@ -16,6 +18,14 @@ class AppServiceProvider extends ServiceProvider $this->app->bind(LocationRepository::class, function ($app) { return new LocationRepository(new Location()); }); + + $this->app->bind(UpdateService::class, function ($app) { + return new UpdateService(new Location()); + }); + + $this->app->bind(MaintenanceService::class, function ($app) { + return new MaintenanceService(new Location()); + }); } /** diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index 05d3ca7..6d846c3 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -4,6 +4,7 @@ namespace App\Repositories; use App\Models\Location; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Auth; class LocationRepository { @@ -70,4 +71,42 @@ class LocationRepository return $result = [$locations, $pageCount, $prev, $next]; } + + public function addLocation(Request $request) + { + $fields = $request->validate([ + 'name' => ['required'], + 'url' => ['required'], + 'description' => ['required'], + 'tags' => ['required'], + ]); + + if ($fields) { + $examples = []; + $files = $request->files->get("loc_examples"); + if ($request->hasfile('loc_examples')) { + foreach ($request->file('loc_examples') as $file) { + $path = $file->store('reference'); + array_push($examples, ["path" => $path]); + } + } + $request->merge(['active' => true]); + $request->merge(['uuid' => Uuid::uuid4()]); + $request->merge(['images' => json_encode($examples)]); + $request->merge(['added_by' => Auth::user()->id]); + //NOTE: Laravel gets funky if sequencing isn't explicitly set + $new = Location::create($request->all()); + if ($new) { + return back()->with('message', 'New Location Added. Take a break!'); + } else { + return back()->withErrors([ + 'error' => 'Uh oh. There was an inssue', + ]); + } + } else { + return back()->withErrors([ + 'error' => 'All fields are required', + ]); + } + } } diff --git a/app/Services/MaintenanceService.php b/app/Services/MaintenanceService.php new file mode 100644 index 0000000..1d68207 --- /dev/null +++ b/app/Services/MaintenanceService.php @@ -0,0 +1,41 @@ +updated_at, new DateTime()); + //$days = $diff->format("%R%a days") + + //$interval = $location->updated_at->diff(new DateTime()); + //$days = $interval->format("%a"); + + //get all locations and sort which are present in unified or not + /* + $sorted = []; + $listed = 0; + $notlisted = 0; + foreach (Location::all() as $location) { + if (array_search($location->url, array_column($unified, 'url'))) { + ++$listed; + // locations present in unfied, so updated + array_push($sorted, [ + 'location' => $location, + 'listed' => true + ]); + } else { + ++$notlisted; + //locations not present + array_push($sorted, [ + 'location' => $location, + 'listed' => false + ]); + } + }; + */ +} diff --git a/app/Services/UpdateService.php b/app/Services/UpdateService.php new file mode 100644 index 0000000..3072753 --- /dev/null +++ b/app/Services/UpdateService.php @@ -0,0 +1,198 @@ +model = $model; + } + + public function locations() + { + $duplicates = 0; + $fresh = 0; + $missing = []; + + $unified = []; + $cleanSources = []; + $sources = Source::where("active", true)->get(); + + //checks source url to make sure they valid + foreach ($sources as $source) { + if ($source->type == 'mastodon') { + $url = 'https://' . $source->url; + } else { + $url = $source->url; + } + + if ($this->urlExists($url)) { + array_push($cleanSources, [ + 'url' => $source->url, + 'token' => $source->token, + 'type' => $source->type, + 'format' => $source->format]); + } else { + var_dump($url); + array_push($missing, ['source' => $url]); + } + } + + //valid source url get compiled for unified + foreach ($cleanSources as $source) { + //check url to make sure it's cool + + //parsing for mastodon + if ($source['type'] == 'mastodon') { + $result = []; + if ($source['token'] == null) { + $result = \Mastodon::domain('https://' . $source['url']) + ->get('/instance/domain_blocks'); + } else { + $result = \Mastodon::domain('https://' . $source['url']) + ->token($source['token']) + ->get('/instance/domain_blocks'); + } + + foreach ($result as $item) { + $index = array_search($item['domain'], array_column($unified, 'url')); + if ($index) { + //if there is a match, update the count + if ($item['severity'] == "suspend" || $item['severity'] == "defederate") { + ++$unified[$index]['block_count']; + } else { + ++$unified[$index]['silence_count']; + } + } else { + $silence = 0; + $suspend = 0; + if ($item['severity'] == "suspend" || $item['severity'] == "defederate") { + ++$suspend; + } else { + ++$silence; + } + array_push($unified, [ + 'name' => $item['domain'], + 'url' => $item['domain'], + 'rating' => $item['severity'], + 'comment' => $item['comment'], + 'block_count' => $suspend, + 'silence_count' => $silence, + ]); + } + } + } + //parsing for custom csv + if ($source['type'] == 'custom' && $source['format'] == 'csv') { + $denylist = array_map('str_getcsv', file($source['url'])); + foreach ($denylist as $item) { + $index = array_search($item[0], array_column($unified, 'url')); + if ($index) { + //if there is a match, update the count + if ($item[1] == "suspend" || $item['severity'] == "defederate") { + ++$unified[$index]['block_count']; + } else { + ++$unified[$index]['silence_count']; + } + } else { + $silence = 0; + $suspend = 0; + if ($item[1] == "suspend" || $item[1] == "defederate") { + ++$suspend; + } else { + ++$silence; + } + array_push($unified, [ + 'name' => $item[0], + 'url' => $item[0], + 'rating' => $item[1], + 'comment' => $item[2], + 'block_count' => $suspend, + 'silence_count' => $silence, + ]); + } + } + } + } + + //once the unified list is created, update current entries or create fresh ones + + foreach ($unified as $item) { + $location = Location::where("url", $item['url'])->first(); + if ($location) { + ++$duplicates; + //update block count for existing item + + $location->block_count = $item['block_count']; + $location->silence_count = $item['silence_count']; + + $location->actions_count = $item['block_count'] + $item['silence_count']; + + if (($item['block_count'] + $item['silence_count']) < 2) { + $location->active = false; + } + + //replace null with empty array + if ($location->images == null) { + $location->images = []; + }; + $location->save(); + } else { + // make new entries for instances not present + ++$fresh; + $images = []; + $rating = ($item['rating'] == 'defederate') ? 'suspend' : $item['rating']; + + $status = true; + if (($item['block_count'] + $item['silence_count']) < 2) { + $status = false; + } + + $new = Location::create([ + 'uuid' => Uuid::uuid4(), + 'name' => $item['url'], + 'url' => $item['url'], + 'description' => ($item['comment'] != null) ? $item['comment'] : "no description", + 'active' => $status, + 'rating' => $rating, + 'added_by' => 1, + 'tags' => 'poor moderation, hate speech', + 'images' => json_encode($images), + 'block_count' => $item['block_count'], + 'silence_count' => $item['silence_count'], + 'actions_cont' => $item['block_count'] + $item['silence_count'] + ]); + } + } + //TODO: Send update post to TBS social account + + return ['duplicates' => $duplicates, 'fresh' => $fresh, 'missing' => $missing]; + } + + public function urlExists($url) + { + // Remove all illegal characters from a url + $url = filter_var($url, FILTER_SANITIZE_URL); + // Validate URI + if ( + filter_var($url, FILTER_VALIDATE_URL) === false || // check only for http/https schemes. + !in_array( + strtolower(parse_url($url, PHP_URL_SCHEME)), + ["http", "https"], + true + ) + ) { + return false; + } // Check that URL exists + $file_headers = @get_headers($url); + return !(!$file_headers || $file_headers[0] === "HTTP/1.1 404 Not Found"); + } +} diff --git a/public/assets/css/front/listing.css b/public/assets/css/front/listing.css index 3fdcf2f..bf36469 100644 --- a/public/assets/css/front/listing.css +++ b/public/assets/css/front/listing.css @@ -128,7 +128,7 @@ a.list-link > .item-block > .item-icon { a.list-link { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr; - grid-template-rows: 100% auto 30px 30px; + grid-template-rows: auto auto 30px 30px; gap: 5px; height: auto; padding-bottom: 20px;