Added support of fedifence CSV and pagination

Populated the DB with entries from a fedifence export provided by
@Oliphant (https://codeberg.org/oliphant/blocklists).

As such also updated the appropriate templates with pagination to be
able to peruse through the location directory.

Also added an edit link on the location template front end to make
finding and updating instance info easy.
symfony-version
Ro 2 years ago
parent b9298451b7
commit 245531faf6

2
.gitignore vendored

@ -1,4 +1,4 @@
/files
###> symfony/framework-bundle ###
.env.local
/.env.local.php

@ -9,8 +9,19 @@ section[role="listings"] {
section[role="listings"] a {
color: var(--highlight);
font-size: 2.5em;
font-size: 2em;
font-weight: bold;
border: 0;
display: block;
}
section[role="listings"] a label {
color: var(--secondary);
font-size: 0.3em;
text-decoration: underline;
font-family: var(--mono-type);
}
section[role="listings"] a:hover {
color: var(--white);
}

@ -12,6 +12,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RequestStack;
use Doctrine\Persistence\ManagerRegistry;
use App\Service\HandleLocations;
use App\Service\HandleImports;
use App\Service\Auth;
use App\Service\FileUploader;
use App\Service\Render;
@ -45,8 +46,27 @@ class Locations extends AbstractController
$member = $session->get("member");
$list = $locations->getLocationsPage($pageNum);
//$search = $connection->fetchAllAssociative("SELECT * FROM searchlocations('agenda')");
return $render->page(["list" => $list, "mode" => "index"], "Bad Space | Locations", "back/locations.twig");
$next = $pageNum + 1;
if ($next > $list["total"]) {
$next = 1;
}
$prev = $pageNum - 1;
if ($prev <= 0) {
$prev = $list["total"];
}
return $render->page(
[
"list" => $list,
"mode" => "index",
"curentPage" => $pageNum,
"nextPage" => $next,
"prevPage" => $prev
],
"Bad Space | Locations",
"back/locations.twig"
);
} else {
return $render->page([], "The Bad Space | Den", "back/index.twig");
}
@ -164,6 +184,7 @@ class Locations extends AbstractController
Request $request,
Auth $auth,
HandleLocations $locations,
HandleImports $imports,
ManagerRegistry $doctrine,
FileUploader $uploader,
Render $render
@ -181,7 +202,7 @@ class Locations extends AbstractController
$token = $request->get("token");
$entityManager = $doctrine->getManager();
$notice = '';
$type = $request->get("input_type");
if (!$this->isCsrfTokenValid("upload", $token)) {
$logger->info("CSRF failure");
return new Response(
@ -217,7 +238,12 @@ class Locations extends AbstractController
]);
}
//if it's cool, send it to be processed
$response = $locations->addMultipleLocations($file, $result["id"]);
if ($type == "tbs" || $type == "") {
$response = $locations->addMultipleLocations($file, $result["id"]);
} else {
$response = $imports->importLocations($file, $result["id"]);
}
if ($response["status"]) {
$notice = "New locations added! Take a break.";
return $render->page(

@ -73,9 +73,26 @@ class Index extends AbstractController
Auth $auth,
Render $render,
HandleLocations $locations,
string $pageNum
int $pageNum = 1
): Response {
$list = $locations->getLocationsPage($pageNum, "true");
return $render->page(["list" => $list, "page" => $pageNum], "About The Bad Space", "front/listing.twig");
$next = $pageNum + 1;
if ($next > $list["total"]) {
$next = 1;
}
$prev = $pageNum - 1;
if ($prev <= 0) {
$prev = $list["total"];
}
return $render->page([
"list" => $list,
"currentPage" => $pageNum,
"nextPage" => $next,
"prevPage" => $prev
], "About The Bad Space", "front/listing.twig");
}
}

@ -0,0 +1,134 @@
<?php
// src/Controller/ProductController.php
namespace App\Service;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\ORMException;
use PDOException;
use Exception;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Uid\Uuid;
use Doctrine\DBAL\Connection;
use App\Entity\Location;
use League\Csv\Reader;
//use App\Utils\StringTools;
/**
* Members
*
* Data class for importing external CVS blocklists
*/
class HandleImports
{
private $session;
private $entityManager;
private $conn;
private $limit = 4;
public function __construct(
Connection $connection,
EntityManagerInterface $entityManager,
RequestStack $requestStack
) {
$this->connection = $connection;
$this->entityManager = $entityManager;
$this->session = $requestStack->getSession();
}
/**
* Add new Locations to db from fedifence file
* provided by Oliphant
*
* @param string $path location of file
* @param int $memberID member adding locations
* @return Object
*/
public function importLocations($file, $memberId)
{
//read csv
$csv = Reader::createFromPath($file, "r");
$csv->setHeaderOffset(0);
$records = $csv->getRecords();
$recordCount = count($csv);
$duplicates = 0;
$errorMessage = null;
//extract data row by row
//TODO: set name to lowercase for comparison
foreach ($records as $offset => $row) {
$url = $row["domain"];
//$images = $row["Images"];
$desc = $row["public_comment"];
$ratings = $row["severity"];
//check to see if location already exists
$list = $this->entityManager->getRepository(Location::class);
$entry = $list->findOneBy(["url" => trim($url)]);
if ($entry) {
++$duplicates;
} else {
$errorMessage = null;
$location = new Location();
$location->setName($url);
$location->setUrl($url);
$location->setTags("bigotry, hate speech, poor moderation");
if ($ratings == "suspend") {
$location->setRating("defederate");
} else {
$location->setRating("silence");
}
//set defaults
$location->setUuid(Uuid::v4());
if ($desc == "") {
$location->setDescription("needs description");
$location->setActive(false);
} else {
$location->setActive(true);
$location->setDescription($desc);
}
$location->setCreatedAt(new \DateTimeImmutable());
$location->setUpdatedAt(new \DateTimeImmutable());
$location->setAddedBy($memberId);
$this->entityManager->persist($location);
}
}
try {
$this->entityManager->flush();
} catch (PDOException $error) {
$errorMessage = $error->getMessage();
} catch (DBALException $error) {
$errorMessage = $error->getMessage();
} catch (ORMException $error) {
$errorMessage = $error->getMessage();
} catch (Exception $error) {
$errorMessage = $error->getMessage();
} catch (SyntaxErrorException $e) {
$errorMessage = $error->getMessage();
}
if ($duplicates > 0) {
$message = $duplicates . " of " . $recordCount . " location entries were duplicates";
} else {
$message = "Locations Added. Nice Job!";
}
// return result status
if ($errorMessage == null) {
return $response = [
"status" => true,
"message" => $message,
];
} else {
return $response = ["status" => false, "message" => $errorMessage];
}
}
}

@ -27,7 +27,7 @@ class HandleLocations
private $session;
private $entityManager;
private $conn;
private $limit = 4;
private $limit = 9;
public function __construct(
Connection $connection,

@ -30,13 +30,20 @@
<a href="/den/locations/bulk-add">Add Multiple Locations</a>
<br>
<h3>Bad Spaces</h3>
{% for location in options.list.locations %}
<sup>ID:{{ location.id }}</sup>
<a href="/den/locations/modify/edit/{{ location.uuid }}">
Page
{{ options.curentPage }}
of
{{ options.list.total }}<br>
{% for location in options.list.locations %}
<sup>ID:{{ location.id }}</sup>
<a href="/den/locations/modify/edit/{{ location.uuid }}">
{{ location.name }}</a><br/>
{% endfor %}
<a href="/den/locations/page/{{ options.prevPage }}">Previous</a>
<a href="/den/locations/page/{{ options.nextPage }}">Next</a>
{% endif %}
{{ location.name }}</a><br/>
{% endfor %}
{% endif %}
</section>
{% endblock %}
</section>
{% endblock %}

@ -3,6 +3,14 @@
<br>
<input type="file" name="myfile" id="myfile"></div>
<br/>
<label>Input Type</label><br/>
<select name="input_type">
<option value="" disabled selected>Choose Upload Type
</option>
<option value="tbs">The Bad Space Custom</option>
<option value="fedifence">Fedifence</option>
</select>
<br/>
<input type="hidden" name="token" value="{{ csrf_token('upload') }}"/>
<button type="submit">Upload Locations</button>
</form>

@ -7,12 +7,17 @@
<section role="listings">
<h1>The Bad Space Listings</h1>
<h2>Page
{{ options.page }}</h2>
{{ options.currentPage }}
of
{{ options.list.total }}</h2>
{% for location in options.list.locations %}
<sup>ID:{{ location.id }}</sup>
<a href="/location/{{ location.uuid }}">
{{ location.name }}</a><br/>
<a href="/location/{{ location.uuid }}">
<label>{{ location.id }}</label>
{{ location.name }}</a>
<br/>
{% endfor %}
<a href="/listings/page/{{ options.prevPage }}">Previous</a>
<a href="/listings/page/{{ options.nextPage }}">Next</a>
</section>
{% endblock %}

@ -17,5 +17,10 @@
<br/>
<strong>TAGS:</strong>
{{ options.location.tags }}
<br/>
{% if loggedIn %}
<a href="/den/locations/modify/edit/{{ options.location.uuid }}">EDIT
{{ options.location.name }}</a>
{% endif %}
</section>
{% endblock %}

Loading…
Cancel
Save