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;