[wip] mastodon integration
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Simon Vieille 2023-07-27 18:28:25 +02:00
parent 2cd8d7fcca
commit 9dc3272d40
Signed by: deblan
GPG key ID: 579388D585F70417
11 changed files with 260 additions and 1 deletions

4
.env
View file

@ -35,3 +35,7 @@ MAILER_SENDER=example@localhost
ASSET_BASE_URL=null
UMAMI_URL=null
MASTODON_HOST=
MASTODON_CLIENT_ID=
MASTODON_CLIENT_SECRET=
MASTODON_CLIENT_ACCESS_TOKEN=

View file

@ -7,6 +7,7 @@
"php": ">=8.0.0",
"beberlei/doctrineextensions": "^1.3",
"friendsofsymfony/jsrouting-bundle": "^2.7",
"fundevogel/php-mastodon": "^0.6.0",
"gregwar/captcha-bundle": "^2.2",
"knplabs/knp-markdown-bundle": "^1.9",
"knplabs/knp-menu-bundle": "^3.1",

View file

@ -4,6 +4,10 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
mastodon_host: '%env(MASTODON_HOST)%'
mastodon_client_id: '%env(MASTODON_CLIENT_ID)%'
mastodon_client_secret: '%env(MASTODON_CLIENT_SECRET)%'
mastodon_client_access_token: '%env(MASTODON_CLIENT_ACCESS_TOKEN)%'
services:
# default configuration for services in *this* file
@ -47,6 +51,13 @@ services:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
App\Api\MastodonClient:
arguments:
$host: '%mastodon_host%'
$clientId: '%mastodon_client_id%'
$clientSecret: '%mastodon_client_secret%'
$clientAccessToken: '%mastodon_client_access_token%'
site.route_loader:
class: App\Core\Router\SiteRouteLoader
tags: [routing.loader]

View file

@ -0,0 +1,60 @@
<?php
namespace App\Api;
use Fundevogel\Mastodon\Api as Client;
/**
* class MastodonClient.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class MastodonClient
{
protected ?Client $client = null;
public function __construct(
protected ?string $host,
protected ?string $clientId,
protected ?string $clientSecret,
protected ?string $clientAccessToken
) {
}
public function __call(string $name, array $arguments)
{
if (!$this->client) {
$this->createClient();
}
return call_user_func_array([$this->client, $name], $arguments);
}
protected function createClient(): self
{
$this->client = new Client($this->host);
$this->client->accessToken = $this->clientAccessToken;
return $this;
}
public function extractId(string $url): string
{
return basename($url);
}
public function getTree(string $postId, array &$tree = []): array
{
$tree['id'] = $postId;
$tree = array_merge($tree, $this->statuses()->get($postId)->data);
$tree = array_merge($tree, $this->statuses()->context($postId)->data);
foreach ($tree['descendants'] as $key => $descendant) {
if ($descendant['in_reply_to_id'] === $postId) {
$descendants['descendants'][$key] = $this->getTree($descendant['id'], $descendants['descendants'][$key]);
}
}
return $tree;
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use App\Api\MastodonClient;
use App\Core\Manager\EntityManager;
use App\Repository\Blog\PostRepositoryQuery;
#[AsCommand(
name: 'app:mastodon:comments-sync',
description: 'Add a short description for your command',
)]
class MastodonCommentsSyncCommand extends Command
{
public function __construct(
protected MastodonClient $client,
protected PostRepositoryQuery $query,
protected EntityManager $manager
)
{
parent::__construct();
}
protected function configure(): void
{
// $this
// ->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
// ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
// ;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
foreach ($this->query->create()->where('.mastodonUrl is not null')->find() as $post) {
dump($this->client->getTree($this->client->extractId($post->getMastodonUrl())));
}
return Command::SUCCESS;
}
}

View file

@ -90,6 +90,12 @@ class Post implements EntityInterface
#[ORM\Column(type: 'array')]
private $parameters = [];
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $mastodonUrl;
#[ORM\Column(type: 'json')]
private $mastodonComments = [];
public function __construct()
{
$this->categories = new ArrayCollection();
@ -475,4 +481,28 @@ class Post implements EntityInterface
}
)[0]['value'] ?? null;
}
public function getMastodonUrl(): ?string
{
return $this->mastodonUrl;
}
public function setMastodonUrl(?string $mastodonUrl): self
{
$this->mastodonUrl = $mastodonUrl;
return $this;
}
public function getMastodonComments(): ?array
{
return $this->mastodonComments;
}
public function setMastodonComments(array $mastodonComments): self
{
$this->mastodonComments = $mastodonComments;
return $this;
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace App\Entity;
use App\Repository\ExportQueueRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ExportQueueRepository::class)]
class ExportQueue
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
public function getId(): ?int
{
return $this->id;
}
}

View file

@ -202,6 +202,19 @@ class PostType extends AbstractType
]
);
$builder->add(
'mastodonUrl',
TextType::class,
[
'label' => 'URL Mastodon',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'quickUrl',
TextType::class,

View file

@ -0,0 +1,66 @@
<?php
namespace App\Repository;
use App\Entity\ExportQueue;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<ExportQueue>
*
* @method ExportQueue|null find($id, $lockMode = null, $lockVersion = null)
* @method ExportQueue|null findOneBy(array $criteria, array $orderBy = null)
* @method ExportQueue[] findAll()
* @method ExportQueue[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ExportQueueRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ExportQueue::class);
}
public function add(ExportQueue $entity, bool $flush = false): void
{
$this->getEntityManager()->persist($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function remove(ExportQueue $entity, bool $flush = false): void
{
$this->getEntityManager()->remove($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
// /**
// * @return ExportQueue[] Returns an array of ExportQueue objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('e')
// ->andWhere('e.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('e.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?ExportQueue
// {
// return $this->createQueryBuilder('e')
// ->andWhere('e.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View file

@ -38,7 +38,7 @@
</span>
</div>
{% for item in ['image', 'image2', 'parameters', 'status', 'contentFormat', 'publishedAt'] %}
{% for item in ['image', 'image2', 'parameters', 'status', 'contentFormat', 'publishedAt', 'mastodonUrl'] %}
<div class="col-md-12">
{{ form_row(form[item]) }}
</div>

View file

@ -125,6 +125,11 @@
{{ entity.publishedAt ? entity.publishedAt|date('d/m/Y H:i') : '-' }}
</li>
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">URL Mastodon</span>
{{ entity.mastodonUrl|default('-') }}
</li>
</ul>
</div>
</div>