Skip to content

Commit

Permalink
Merge pull request #419 from itk-dev/feature/delete-hearing-tickets-b…
Browse files Browse the repository at this point in the history
…y-date-do-it

2288: Deleted hearing replies after delete_date is passed
  • Loading branch information
rimi-itk authored Oct 8, 2024
2 parents 6ac636a + 158647d commit a4ecbe2
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 87 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

* [PR-419](https://github.com/itk-dev/hoeringsportal/pull/419)
Added Drush command to delete hearing replies
* [PR-418](https://github.com/itk-dev/hoeringsportal/pull/418)
Add message when hearing tickets is deleted.
Add message when hearing replies are deleted
* [PR-417](https://github.com/itk-dev/hoeringsportal/pull/417)
Added more test setup stuff

Expand Down
4 changes: 2 additions & 2 deletions config/sync/field.field.node.hearing.field_delete_date.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ id: node.hearing.field_delete_date
field_name: field_delete_date
entity_type: node
bundle: hearing
label: 'Slette dato'
description: 'Bruges til at sætte dato for sletning af høringssvar.'
label: 'Dato for sletning af høringssvar'
description: 'Vælg hvornår høringssvar skal slettes fra høringen.'
required: true
translatable: false
default_value: { }
Expand Down
2 changes: 1 addition & 1 deletion documentation/localDevelopment.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ docker compose exec phpfpm vendor/bin/drush --yes --uri="http://hoeringsportal.l

Add all fixtures

```sh
```sh name=load-fixtures
docker compose exec phpfpm vendor/bin/drush --yes pm:enable hoeringsportal_base_fixtures $(find web/modules/custom -type f -name 'hoeringsportal_*_fixtures.info.yml' -exec basename -s .info.yml {} \;)
docker compose exec phpfpm vendor/bin/drush --yes content-fixtures:load
docker compose exec phpfpm vendor/bin/drush --yes pm:uninstall content_fixtures
Expand Down
13 changes: 13 additions & 0 deletions web/modules/custom/hoeringsportal_data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ e.g. every minute
*/5 * * * * drush hoeringsportal:data:hearing-state-update
```

Delete replies on hearings by running

```sh
drush hoeringsportal:data:delete-replies
```

This should be done regularly by `cron` or other similar means,
e.g. daily at 03:00

```sh
0 3 * * * drush hoeringsportal:data:delete-replies
```

## Building assets

First, install tools and requirements:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
services:
logger.channel.hoeringsportal_data:
parent: logger.channel_base
arguments: [ 'hoeringsportal_data' ]

hoeringsportal_data.plandata:
class: Drupal\hoeringsportal_data\Service\Plandata
arguments: ['@settings']
Expand All @@ -8,7 +12,7 @@ services:

hoeringsportal_data.hearing_helper:
class: Drupal\hoeringsportal_data\Helper\HearingHelper
arguments: ['@entity_type.manager']
arguments: ['@entity_type.manager', '@logger.channel.hoeringsportal_data']

hoeringsportal_data.map_item_helper:
class: Drupal\hoeringsportal_data\Helper\MapItemHelper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace Drupal\hoeringsportal_data\Drush\Commands;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\State\StateInterface;
use Drupal\hoeringsportal_data\Helper\HearingHelper;
use Drupal\hoeringsportal_deskpro\Service\HearingHelper as DeskproHearingHelper;
use Drush\Attributes as CLI;
use Drush\Commands\DrushCommands as BaseDrushCommands;
use Symfony\Component\DependencyInjection\ContainerInterface;
Expand All @@ -17,6 +22,9 @@ final class DrushCommands extends BaseDrushCommands {
*/
public function __construct(
private readonly HearingHelper $helper,
private readonly DeskproHearingHelper $deskproHelper,
private readonly TimeInterface $time,
private readonly StateInterface $state,
) {
parent::__construct();
}
Expand All @@ -27,6 +35,9 @@ public function __construct(
public static function create(ContainerInterface $container) {
return new static(
$container->get('hoeringsportal_data.hearing_helper'),
$container->get('hoeringsportal_deskpro.helper'),
$container->get('datetime.time'),
$container->get('state')
);
}

Expand Down Expand Up @@ -66,4 +77,84 @@ public function showHearingState() {
}
}

/**
* A drush command for deleting replies from hearings.
*/
#[CLI\Command(name: 'hoeringsportal:data:delete-replies')]
#[CLI\Option(name: 'ids', description: 'Comma separated list of ids')]
public function processDeleteHearingReplies(
array $options = [
'ids' => NULL,
'last-run-at' => NULL,
],
): void {
if (!empty($options['ids'])) {
$hearingIds = preg_split('/\s*,\s*/', $options['ids'] ?? '', PREG_SPLIT_NO_EMPTY);
}
else {
$lastRunAt = $options['last-run-at'] ? new DrupalDateTime($options['last-run-at']) : $this->getLastRunAt(__METHOD__);
$requestTime = $this->getRequestTime();

if ($this->io()->isVerbose()) {
$this->io()->info(sprintf('Finding hearings with delete replies date between %s and %s', $lastRunAt->format('Y-m-d'), $requestTime->format('Y-m-d')));
}

$hearingIds = $options['ids'] ?? $this->helper->findHearingWhoseRepliesMustBeDeleted($lastRunAt, $requestTime);
}

if (empty($hearingIds)) {
$this->io()->info('No hearings found');
return;
}

if ($options['yes'] || $this->confirm(sprintf('Delete replies on hearings %s', implode(', ', $hearingIds)))) {
$hearings = $this->helper->loadHearings([['nid', $hearingIds, 'IN']]);
foreach ($hearings as $hearing) {
$hearingRepliesDeletedOn = $this->deskproHelper->getHearingRepliesDeletedOn($hearing);
if (NULL !== $hearingRepliesDeletedOn) {
$this->deskproHelper->deleteHearingReplies([$hearing->id()]);
Cache::invalidateTags($hearing->getCacheTags());

$this->io()->success(sprintf('Replies deleted from hearing %s',
$hearing->id()));
}
else {
$this->io()->warning(sprintf('Replies on hearing %s must not yet be deleted', $hearing->id()));
}
}

$this->setLastRunAt(__METHOD__);
}
}

/**
* Get request time.
*/
private function getRequestTime(): DrupalDateTime {
return DrupalDateTime::createFromTimestamp($this->time->getRequestTime());
}

/**
* Get time of last run.
*/
private function getLastRunAt(string $method): DrupalDateTime {
$time = $this->state->get($this->getLastRunKey($method));

return DrupalDateTime::createFromTimestamp($time ?? 0);
}

/**
* Set time of last run.
*/
private function setLastRunAt(string $method) {
$this->state->set($this->getLastRunKey($method), $this->time->getRequestTime());
}

/**
* Get last run key.
*/
private function getLastRunKey(string $method): string {
return $method . '_last_run_at';
}

}
52 changes: 41 additions & 11 deletions web/modules/custom/hoeringsportal_data/src/Helper/HearingHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,32 @@

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;

/**
* Hearing helper.
*/
class HearingHelper {
class HearingHelper implements LoggerAwareInterface {
use LoggerAwareTrait;

const NODE_TYPE_HEARING = 'hearing';
const STATE_UPCOMING = 'upcoming';
const STATE_ACTIVE = 'active';
const STATE_FINISHED = 'finished';

/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private $entityTypeManager;

/**
* Constructor.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
$this->entityTypeManager = $entityTypeManager;
public function __construct(
private readonly EntityTypeManagerInterface $entityTypeManager,
LoggerChannelInterface $logger,
) {
$this->setLogger($logger);
}

/**
Expand Down Expand Up @@ -90,6 +92,34 @@ public function isDeadlinePassed(NodeInterface $node) {
return $this->getDateTime() > new DrupalDateTime($deadline);
}

/**
* Find hearings whose replies must be deleted.
*
* @return array
* A list of hearing ids.
*/
public function findHearingWhoseRepliesMustBeDeleted(DrupalDateTime $from, DrupalDateTime $to): array {
try {
return $this->entityTypeManager
->getStorage('node')
->getQuery()
->condition('type', 'hearing')
->condition('field_delete_date', [
$from->format(DateTimeItemInterface::DATE_STORAGE_FORMAT),
$to->format(DateTimeItemInterface::DATE_STORAGE_FORMAT),
], 'BETWEEN')
->accessCheck(FALSE)
->execute();
}
catch (\Exception $exception) {
$this->logger->error('Error finding hearing whose replies must be deleted: @message', [
'@message' => $exception->getMessage(),
]);

return [];
}
}

/**
* A list of conditions.
*
Expand Down Expand Up @@ -125,7 +155,7 @@ public function isHearing($node) {
/**
* Get a date time object.
*/
private function getDateTime($time = 'now', $timezone = 'UTC') {
private function getDateTime($time = 'now', $timezone = 'UTC'): DrupalDateTime {
return new DrupalDateTime($time, $timezone);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,6 @@ use Drupal\node\Entity\Node;
*/
function hoeringsportal_deskpro_schema() {
return [
'hoeringsportal_deskpro_deskpro_data' => [
'description' => 'Table to hold information about Deskpro data for nodes.',
'fields' => [
'entity_type' => [
'description' => 'The entity type',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
],
'entity_id' => [
'description' => 'The entity id',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
'bundle' => [
'description' => 'The entity bundle',
'type' => 'varchar',
'length' => 128,
'not null' => TRUE,
'default' => '',
],
'data' => [
'description' => 'Deskpro data (JSON)',
'type' => 'text',
'size' => 'big',
'not null' => TRUE,
'default' => '{}',
],
],
'primary key' => [
'entity_type',
'entity_id',
'bundle',
],
],

'hoeringsportal_deskpro_deskpro_tickets' => [
'description' => 'Table to hold information about Deskpro tickets for nodes.',
'fields' => [
Expand Down Expand Up @@ -391,3 +353,13 @@ function hoeringsportal_deskpro_update_8004(&$sandbox) {
return t('Batch finished');
}
}

/**
* Drop hoeringsportal_deskpro_deskpro_data table.
*/
function hoeringsportal_deskpro_update_8005(&$sandbox) {
/** @var \Drupal\Core\Database\Connection $connection */
$connection = \Drupal::service('database');
$schema = $connection->schema();
$schema->dropTable('hoeringsportal_deskpro_deskpro_data');
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\node\NodeInterface;

/**
* Implements hook_help().
Expand Down Expand Up @@ -37,6 +38,7 @@ function hoeringsportal_deskpro_theme() {
'is_deadline_passed' => NULL,
'tickets' => NULL,
'is_hearing_started' => NULL,
'hearing_replies_deleted_on' => NULL,
],
],
'hoeringsportal_hearing_ticket' => [
Expand Down Expand Up @@ -111,3 +113,14 @@ function hoeringsportal_deskpro_entity_bundle_field_info_alter(&$fields, EntityT
$fields['field_deskpro_agent_email']->addConstraint('AgentEmail');
}
}

/**
* Implements hook_node_update().
*
* @see \Drupal\hoeringsportal_data\Helper\HearingHelper::nodeUpdate();
*/
function hoeringsportal_deskpro_node_update(NodeInterface $node) {
/** @var \Drupal\hoeringsportal_deskpro\Service\HearingHelper $helper */
$helper = \Drupal::service('hoeringsportal_deskpro.helper');
$helper->nodeUpdate($node);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public function build() {
'#is_deadline_passed' => $this->helper->isDeadlinePassed($node),
'#tickets' => $this->helper->getHearingTickets($node),
'#is_hearing_started' => $is_hearing_started,
'#hearing_replies_deleted_on' => $this->helper->getHearingRepliesDeletedOn($node),
];
}

Expand Down
Loading

0 comments on commit a4ecbe2

Please sign in to comment.