Skip to content
Snippets Groups Projects
Commit 52853f57 authored by Claudiu Cristea's avatar Claudiu Cristea
Browse files

Merge remote-tracking branch 'origin/release/2.1.0' into EPIC-9212

parents 0be4ff8a 7fcf9a7c
No related branches found
Tags 2.1.0
2 merge requests!205Update ephemeral with develop,!204Release 2.1.0
Showing
with 286 additions and 25 deletions
uuid: b0ee2373-73db-4139-a440-2eb485189783
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.message.mail_body
- message.template.col_membership_block_coc
module:
- layout_builder
third_party_settings:
layout_builder:
enabled: false
allow_custom: false
id: message.col_membership_block_coc.mail_body
targetEntityType: message
bundle: col_membership_block_coc
mode: mail_body
content:
partial_1:
weight: 0
region: content
hidden:
partial_0: true
search_api_excerpt: true
uuid: 42c50eb6-ef62-4d05-9a19-8997ef88289c
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.message.mail_subject
- message.template.col_membership_block_coc
module:
- layout_builder
third_party_settings:
layout_builder:
enabled: false
allow_custom: false
id: message.col_membership_block_coc.mail_subject
targetEntityType: message
bundle: col_membership_block_coc
mode: mail_subject
content:
partial_0:
weight: 0
region: content
hidden:
partial_1: true
search_api_excerpt: true
uuid: 236fc087-2ffb-4f51-a201-1cb87448f171
langcode: en
status: true
dependencies:
config:
- filter.format.full_html
template: col_membership_block_coc
label: 'Collection block membership (CoC violation)'
description: 'An active membership was blocked due to CoC violation.'
text:
-
value: '<p>Interoperable Europe Portal: Membership status update for @entity:title</p>'
format: full_html
-
value: "<p>We regret to inform you that your membership in <a href=\"@entity:url\">@entity:title</a> has been revoked due to a violation of the <a href=\"@entity:code_of_conduct:url\">Code of Conduct</a>.</p>\r\n<p>If you think this action is not clear, please contact the owner of @entity:title.</p>\r\n<p><a href=\"@entity:contact:url\">@entity:contact:url</a></p>"
format: full_html
settings:
'token options':
clear: false
'token replace': true
purge_override: false
purge_methods: { }
......@@ -20,6 +20,8 @@ Feature: Collection membership administration
| Donald Duck | | donald_duck@example.com | Donald | Duck |
| Turkey Ham | | turkey_ham@example.com | Turkey | Ham |
| Cam Bridge | | cambridge@example.com | Cam | Bridge |
| Justin Times | | justintimes@example.com | Justin | Times |
| Ben Dover | | bendover@example.com | Ben | Dover |
# Moderator.
| Daniel Moder | moderator | daniel_moder@example.com | Daniel | Moder |
And collection content:
......@@ -31,6 +33,8 @@ Feature: Collection membership administration
| Medical diagnosis | Turkey Ham | facilitator | active |
| Medical diagnosis | Gregory House | | active |
| Medical diagnosis | Kathie Cumbershot | | pending |
| Medical diagnosis | Justin Times | | active |
| Medical diagnosis | Ben Dover | | active |
Scenario: Only one instance of the "Apply to selected items" should exist.
Given I am logged in as a moderator
......@@ -189,6 +193,40 @@ Feature: Collection membership administration
Then I should not see the plus button menu
And I should see the button "Join this collection"
Scenario: Block a membership
# With CoC, an email should be sent.
Given custom_page content:
| title | collection | state |
| Medical diagnosis CoC | Medical diagnosis | published |
And the "code of conduct" setting of the "Medical diagnosis" collection is set to "Medical diagnosis CoC" "custom page"
Given I am logged in as "Lisa Cuddy"
When I am on the members page of "Medical diagnosis"
And I check the box "Update the member Ben Dover"
Then I select "Block the selected membership(s)" from "Action"
And I press "Apply to selected items"
Then I should see the success message "Block the selected membership(s) was applied to 1 item."
And the email sent to "Ben Dover" with subject "Interoperable Europe Portal: Membership status update for Medical diagnosis" contains the following lines of text:
| We regret to inform you that your membership in Medical diagnosis has been revoked due to a violation of the Code of Conduct. |
| If you think this action is not clear, please contact the owner of Medical diagnosis. |
When I am logged in as "Ben Dover"
And I go to the "Medical diagnosis" collection
Then I should not see the plus button menu
# Without CoC, no email should be sent.
And the "code of conduct" setting of the "Medical diagnosis" collection is unset
Given I am logged in as "Lisa Cuddy"
When I am on the members page of "Medical diagnosis"
And I check the box "Update the member Justin Times"
Then I select "Block the selected membership(s)" from "Action"
And I press "Apply to selected items"
Then I should see the success message "Block the selected membership(s) was applied to 1 item."
And no email has been sent to "Justin Times"
When I am logged in as "Justin Times"
And I go to the "Medical diagnosis" collection
Then I should not see the plus button menu
Scenario: Assign a new role to a member
# Check that Dr House can't edit the collection.
When I am logged in as "Gregory House"
......
......@@ -19,3 +19,9 @@ Feature: Minimal install clone testing.
And "Solutions" should be the active item in the "Navigation bar" region
Then I visit "/collection/portal"
And no menu items should be active in the "Navigation bar" region
@javascript
Scenario: Assert publiccode.yml page.
Given I am an anonymous user
When I visit "/publiccode-editor"
And I should see "publiccode.yml Editor"
......@@ -401,7 +401,7 @@ protected function getAnnouncementBySubject(string $subject): AnnouncementInterf
}
/**
* Sets a group settings (meta entity) field to the given value.
* Sets or unset a group settings (meta entity) field to the given value.
*
* @param string $config
* The configuration (field name) of the collection's settings meta entity.
......@@ -409,12 +409,13 @@ protected function getAnnouncementBySubject(string $subject): AnnouncementInterf
* The label of the collection or solution.
* @param string $group
* The type of the group ("collection" or "solution").
* @param string $value
* @param string|null $value
* The new value of the meta entity field. This should be an entity label if
* the field is an entity reference field.
* @param string|null $entityTypeId
* The entity type ID (or alias) if the value is an entity reference.
*
* @Given the :config setting of the :collectionLabel :group is unset
* @Given the :config setting of the :collectionLabel :group is set to :value
* @Given the :config setting of the :collectionLabel :group is set to :value :entityTypeId
*/
......@@ -422,11 +423,11 @@ public function givenCollectionSetting(
string $config,
string $groupLabel,
string $group,
string $value,
?string $value = NULL,
?string $entityTypeId = NULL,
): void {
Assert::assertTrue(in_array($group, ['collection', 'solution']));
$groupEntity = $this->getEntityByLabel('node', $groupLabel, $group);
Assert::assertContains($group, ['collection', 'solution']);
$groupEntity = static::getEntityByLabel('node', $groupLabel, $group);
Assert::assertInstanceOf(GroupInterface::class, $groupEntity);
$fieldName = preg_replace('/\s+/', '_', mb_strtolower($config));
......@@ -441,22 +442,26 @@ public function givenCollectionSetting(
));
}
// Assume entity reference field and an entity label in the $value variable.
if (is_string($entityTypeId)) {
$value = $this->getEntityByLabel($this->translateEntityTypeAlias($entityTypeId), $labelToSearchFor = $value);
Assert::assertNotEmpty(
$value,
sprintf(
"Cannot find '%s' entity with label '%s'.",
$entityTypeId,
$labelToSearchFor
),
);
}
if (isset($value)) {
// Assume entity reference field and an entity label in $value.
$newValue = is_string($entityTypeId)
? static::getEntityByLabel($this->translateEntityTypeAlias($entityTypeId), $value)
: $value;
MetaEntity::loadOrCreate("{$group}_settings", $groupEntity)
->set($fieldName, $value)
->save();
MetaEntity::loadOrCreate("{$group}_settings", $groupEntity)
->set($fieldName, $newValue)
->save();
}
else {
$metaEntities = \Drupal::entityTypeManager()->getStorage('meta_entity')
->loadByProperties([
'type' => "{$group}_settings",
'target.target_type' => $groupEntity->getEntityTypeId(),
'target.target_id' => $groupEntity->id(),
]);
$metaEntity = $metaEntities ? reset($metaEntities) : NULL;
$metaEntity?->delete();
}
}
/**
......
......@@ -20,8 +20,8 @@
*
* @EuOssCatalogueProvider(
* id = "dutch_catalogue",
* label = @Translation("Dutch catalogue"),
* description = @Translation("Dutch open source software solutions for the public administrations."),
* label = @Translation("Developer Overheid"),
* description = @Translation("Dutch National OSS Catalogue, by https://developer.overheid.nl website."),
* parser = "publiccode_yml",
* )
*/
......
......@@ -7,4 +7,5 @@ package: Joinup communities
dependencies:
- og:og
- drupal:filter
- joinup_notification:joinup_notification
- rdf_sync:rdf_sync
......@@ -3,3 +3,8 @@ services:
class: Drupal\joinup_collection\Routing\RouteSubscriber
tags:
- { name: event_subscriber }
joinup_collection.membership_notification.subscriber:
class: Drupal\joinup_collection\EventSubscriber\MembershipNotificationSubscriber
parent: joinup_notification.notification_subscriber_base
tags:
- { name: event_subscriber }
<?php
declare(strict_types=1);
namespace Drupal\joinup_collection\EventSubscriber;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;
use Drupal\collection\Entity\CollectionInterface;
use Drupal\joinup_notification\Event\NotificationEvent;
use Drupal\joinup_notification\EventSubscriber\NotificationSubscriberBase;
use Drupal\joinup_notification\NotificationEvents;
use Drupal\og\OgMembershipInterface;
/**
* Handles notifications related to changes in collection memberships.
*/
class MembershipNotificationSubscriber extends NotificationSubscriberBase {
const TEMPLATE_REVOKE_MEMBERSHIP_COC = 'col_membership_block_coc';
/**
* The membership object.
*
* @var \Drupal\og\Entity\OgMembership
*/
protected $membership;
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events[NotificationEvents::OG_MEMBERSHIP_MANAGEMENT] = [
['onUpdate'],
];
return $events;
}
/**
* {@inheritdoc}
*/
protected function initialize(NotificationEvent $event): void {
/** @var \Drupal\og\Entity\OgMembership $membership */
$this->membership = $event->getEntity();
try {
$this->entity = $this->membership->getGroup();
}
catch (\TypeError $exception) {
// The group might have been deleted.
}
$this->operation = $event->getOperation();
}
/**
* Sends notifications when a membership is updated.
*
* Notifications handled: All.
*
* @param \Drupal\joinup_notification\Event\NotificationEvent $event
* The notification event.
*/
public function onUpdate(NotificationEvent $event): void {
$this->initialize($event);
if (!$this->appliesOnUpdate()) {
return;
}
// Act on specific membership state transitions.
/** @var \Drupal\og\Entity\OgMembership $original_membership */
$original_membership = $this->membership->original;
match ([$original_membership->getState(), $this->membership->getState()]) {
[OgMembershipInterface::STATE_ACTIVE, OgMembershipInterface::STATE_BLOCKED] => $this->onUpdateMembershipBlocked(),
default => NULL,
};
}
/**
* Sends notifications when a membership is blocked.
*/
protected function onUpdateMembershipBlocked(): void {
if (!$this->entity instanceof CollectionInterface || !$this->entity->hasCodeOfConductToAccept()) {
return;
}
$recipient_id = $this->membership->getOwnerId();
$user_data = [
self::TEMPLATE_REVOKE_MEMBERSHIP_COC => [
$recipient_id => $recipient_id,
],
];
$this->sendUserDataMessages($user_data);
}
/**
* Checks if the conditions apply for the onUpdate method.
*
* @return bool
* Whether the conditions apply.
*/
protected function appliesOnUpdate(): bool {
if ($this->operation !== 'update') {
return FALSE;
}
if (!$this->membership->getGroup()) {
return FALSE;
}
if (empty($this->membership->original)) {
return FALSE;
}
return TRUE;
}
/**
* {@inheritdoc}
*/
protected function generateArguments(EntityInterface $entity): array {
$arguments = parent::generateArguments($entity);
\assert($this->entity instanceof CollectionInterface);
if ($this->entity->hasCodeOfConductToAccept()) {
$arguments['@entity:code_of_conduct:url'] = $this->entity->getCodeOfConduct()->toUrl()->setAbsolute()->toString();
}
if ($this->entity->getValidatedContactInformationEmails()) {
$arguments['@entity:contact:url'] = Url::fromRoute('entity.node.contact', ['node' => $this->entity->id()])->setAbsolute()->toString();
}
return $arguments;
}
}
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment