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.
This commit is contained in:
parent
b9298451b7
commit
245531faf6
10 changed files with 234 additions and 21 deletions
2
.gitignore
vendored
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
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
134
src/Service/HandleImports.php
Normal file
134
src/Service/HandleImports.php
Normal file
|
@ -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>
|
||||
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 %}
|
||||
|
||||
|
||||
|
||||
</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…
Reference in a new issue