tapis_job-1.4.1-alpha1/src/Controller/TapisWebhooksController.php
src/Controller/TapisWebhooksController.php
<?php
namespace Drupal\tapis_job\Controller;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\jwt\Transcoder\JwtTranscoderInterface;
use Drupal\node\Entity\Node;
use Drupal\tapis_job\Entity\TapisJob;
use Drupal\tapis_tenant\DrupalIds as TenantDrupalIds;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* Class TapisWebhooksController.
*
* This class is used to create a controller that processes Tapis webhooks.
*
* @package Drupal\tapis_job\Controller
*/
class TapisWebhooksController extends ControllerBase {
/**
* The JWT transcoder service.
*
* @var \Drupal\jwt\Transcoder\JwtTranscoderInterface
*/
protected JwtTranscoderInterface $jwtTranscoder;
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface|\Drupal\Core\Config\ImmutableConfig
*/
protected ConfigFactoryInterface|ImmutableConfig $config;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* TapisWebhooksController constructor.
*
* @param \Drupal\jwt\Transcoder\JwtTranscoderInterface $jwt_transcoder
* The JWT transcoder service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
*/
public function __construct(JwtTranscoderInterface $jwt_transcoder,
ConfigFactoryInterface $config_factory,
EntityTypeManagerInterface $entityTypeManager) {
$this->jwtTranscoder = $jwt_transcoder;
$this->config = $config_factory->get('tapis_job.config');
$this->entityTypeManager = $entityTypeManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('jwt.transcoder'),
$container->get('config.factory'),
$container->get('entity_type.manager')
);
}
/**
* Process a Tapis webhook.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The HTTP request.
*
* @return \Symfony\Component\HttpFoundation\Response
* Returns the job status
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
* @throws \Drupal\jwt\Transcoder\JwtDecodeException
*/
public function processWebhook(Request $request): Response {
$params = json_decode($request->getContent(), TRUE);
if ($request->getMethod() !== "POST") {
return new Response('', 405);
}
$jwt_token = $request->query->get('token');
// $config = \Drupal::config('tapis_job.config');
$jwt_secret_key_id = $this->config->get("webhook_jwt_secret_key_id");
$params = json_decode($request->getContent(), TRUE);
$event = $params['event'];
$jobUUID = $event['subject'];
$raw_data = $event['data'];
if ($jwt_secret_key_id) {
// A JWT secret key has been configured,
// so use it to verify the JWT token.
if (!$jwt_token) {
return new Response('', 401);
}
// $jwt_secret_key = \Drupal::entityTypeManager()->getStorage('key')->load($jwt_secret_key_id);
/** @var \Drupal\key\KeyInterface $jwt_secret_key */
$jwt_secret_key = $this->entityTypeManager->getStorage('key')->load($jwt_secret_key_id);
if (!$jwt_secret_key) {
return new Response('', 401);
}
// Verify the JWT token.
// $jwt_transcoder = \Drupal::service('jwt.transcoder');.
$this->jwtTranscoder->setKey($jwt_secret_key);
// This will throw an exception if the token is invalid.
$jwt = $this->jwtTranscoder->decode($jwt_token);
// Verify that the subject of the JWT token matches the jobUUID.
if ($jwt->getClaim('sub') !== $jobUUID) {
return new Response('', 401);
}
}
// Check if raw_data is a stringified json object,
// and if so, parse it into an array.
if (is_string($raw_data)) {
$raw_data = json_decode($raw_data, TRUE);
}
$newJobStatus = $raw_data['newJobStatus'];
$tenantTapisId = $event['tenant'];
// Get the tapis_tenant node from the database by filtering
// on the tenantId field.
// $tapis_tenant_ids = \Drupal::entityQuery('node')
$tapis_tenant_ids = $this->entityTypeManager->getStorage('node')->getQuery()
->condition('type', 'tapis_tenant')
->condition(TenantDrupalIds::TENANT_TAPIS_ID, $tenantTapisId)
->accessCheck(FALSE)
->execute();
$tenant = Node::load(reset($tapis_tenant_ids));
// Get the job from the database by filtering
// on the jobUUID field and the tenantId field.
// $tapis_job_ids = \Drupal::entityQuery('tapis_job')
$tapis_job_ids = $this->entityTypeManager->getStorage('tapis_job')->getQuery()
->condition('tapisUUID', $jobUUID)
->condition('tenant', $tenant->id())
->accessCheck(FALSE)
->execute();
$job = TapisJob::load(reset($tapis_job_ids));
// If the job is not found, return a 404.
if (empty($job)) {
return new Response('', 404);
}
// If the job is found, update the job status.
$job->setStatus($newJobStatus);
$job->save();
return new Response('', 200);
}
}
