activitypub-1.0.x-dev/src/Form/ActivitypubInteractForm.php
src/Form/ActivitypubInteractForm.php
<?php
namespace Drupal\activitypub\Form;
use Drupal\activitypub\Services\ActivityPubUtilityInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
/**
* The ActivityPub content interaction form.
*/
class ActivitypubInteractForm extends FormBase {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The ActivityPub utility service.
*
* @var \Drupal\activitypub\Services\ActivityPubUtilityInterface
*/
protected $activityPubUtility;
/**
* FollowForm constructor.
*
* @param \Drupal\activitypub\Services\ActivityPubUtilityInterface $activitypub_utility
* The ActivityPub utility service.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(ActivityPubUtilityInterface $activitypub_utility, EntityTypeManagerInterface $entity_type_manager) {
$this->activityPubUtility = $activitypub_utility;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('activitypub.utility'),
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'activitypub_interact_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $node = NULL, $interact_type = NULL) {
$actorStorage = $this->entityTypeManager->getStorage('activitypub_actor');
$actor = $actorStorage->loadActorByEntityIdAndType($node->getOwnerId(), 'person');
$url = $node->toUrl('canonical', ['absolute' => TRUE])->toString();
if ($actor) {
$entity_type = $node->getEntityType()->id();
$view_builder = $this->entityTypeManager->getViewBuilder($entity_type);
$entity_storage = $this->entityTypeManager->getstorage($entity_type);
$node_build = $view_builder->view($node, 'teaser');
$form['content'] = $node_build;
$form['handle'] = [
'#type' => 'textfield',
'#title' => $this->t('Username'),
'#placeholder' => $this->t('Enter your username@domain to interact from'),
'#description' => $this->t('<strong>Why is this step necessary?</strong> <code>%domain</code> might not be the server where you are registered, so we need to redirect you to your home server first.<br/><small>You can interact with me from Mastodon or any other similar application that uses ActivityPub. If you prefer, you can try to search this status ( %url ) from your instance and interact there.</small>', ["%domain" => \Drupal::request()->getHost(), "%url" => $url]),
'#required' => TRUE,
];
$form['status'] = [
'#type' => 'hidden',
'#title' => $this->t('Link title'),
'#value' => $url,
];
$form['follow'] = [
'#type' => 'submit',
'#value' => $this->t('Proceed to %interact', ["%interact" => $interact_type]),
];
}
else {
$form['info'] = ['#markup' => $this->t('No ActivityPub actor found')];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$endpoint = '';
$handle = $form_state->getValue('handle');
try {
$webfinger = $this->activityPubUtility->getServer()->actor($handle)->webfinger();
$links = $webfinger->getLinks();
foreach ($links as $link) {
if ($link['rel'] == 'http://ostatus.org/schema/1.0/subscribe') {
$endpoint = $link['template'];
}
}
}
catch (\Exception $e) {
$this->logger('activitypub')->error('Error getting subscribe endpoint: @message', ['@message' => $e->getMessage()]);
}
if (empty($endpoint)) {
$form_state->setErrorByName('handle', $this->t('Could not find your subscription endpoint.'));
}
else {
$form_state->setValue('endpoint', $endpoint);
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$handle = $form_state->getValue('handle');
$endpoint = $form_state->getValue('endpoint');
$status = $form_state->getValue('status');
$redirect = str_replace('{uri}', $status, $endpoint);
$response = new TrustedRedirectResponse($redirect);
$form_state->setResponse($response);
}
/**
* Checks access to interact with content.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
* @param \Drupal\Core\Entity\EntityInterface $node
* The entity that the interaction is for.
* @param string $interact_type
* The wanted interaction.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(AccountInterface $account, EntityInterface $node = NULL, $interact_type = NULL) {
$activitypub_type_query = $this->entityTypeManager->getStorage('activitypub_type')->getQuery()->accessCheck();
$activitypub_type_query
->condition('status', 1)
->condition('plugin.configuration.target_entity_type_id', $node->getEntityType()->id())
->condition('plugin.configuration.target_bundle', $node->bundle());
$enabled_activitypub_types = $activitypub_type_query->execute();
return AccessResult::allowedIf($enabled_activitypub_types);
}
/**
* Cook the title to interact with content.
*
* @param \Drupal\Core\Entity\EntityInterface $node
* The entity that the interaction is for.
* @param string $interact_type
* The wanted interaction.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function title(EntityInterface $node = NULL, $interact_type = NULL) {
switch ($interact_type) {
case "favourite":
$title = $this->t("Mark %node as favourite", ["%node" => $node->label()]);
break;
case "announce":
$title = $this->t("Announce %node", ["%node" => $node->label()]);
break;
default:
$title = $this->t("Interact with %node", ["%node" => $node->label()]);
}
return $title;
}
}
