Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
a21d45f
Add route definitions and Group access check service
damiankloip Dec 2, 2015
d0ce8cb
Start on SubscriptionController
damiankloip Dec 2, 2015
590639a
More conversion in SubscriptionController
damiankloip Dec 4, 2015
0f64119
Add initial subscription confirm form
damiankloip Dec 4, 2015
954df49
Convert user access checking and form builder usage
damiankloip Dec 7, 2015
cf801aa
Use OgAccess in GroupCheck access
damiankloip Dec 7, 2015
6e47f3a
Update cardinality and account usage in SubscriptionController::subsc…
damiankloip Dec 8, 2015
2e8448b
Use optional feild_name parameter in subscribe route
damiankloip Dec 9, 2015
a2a545e
Add a GroupUnsubscribeConfirmForm
damiankloip Dec 9, 2015
96edcc6
Use correct classes to build forms
damiankloip Dec 9, 2015
438a8d7
Update OgMembershipInterface constants, misc tidyiny
damiankloip Dec 30, 2015
5b9b1dc
Merge 8.x-1.x
amitaibu Jul 26, 2016
06ac92b
Start moving classes around [skip ci]
amitaibu Jul 26, 2016
065fdd6
Remove duplicate route [skip ci]
amitaibu Jul 26, 2016
c537f56
Move more classes [skip ci]
amitaibu Jul 26, 2016
e963011
Start adapting controller [skip ci]
amitaibu Jul 26, 2016
01dcc87
Fix wrong negate [skip ci]
amitaibu Jul 26, 2016
c2fd194
Auto sniffer fixes [skip ci]
amitaibu Jul 26, 2016
d03412a
namespace fix [skip ci]
amitaibu Jul 26, 2016
1bfc4dd
Fix subscribe route access [skip ci]
amitaibu Jul 26, 2016
925dc81
Use correct t() method [skip ci]
amitaibu Jul 26, 2016
06e3b28
More cleanup [skip ci]
amitaibu Jul 26, 2016
03423f6
Add default form [skip ci]
amitaibu Jul 27, 2016
0b904e6
Remove debug and add todo [skip ci]
amitaibu Jul 27, 2016
1e40e8b
Rename membership type config [skip ci]
amitaibu Jul 27, 2016
889a12d
Fix default value
amitaibu Jul 27, 2016
b5853cc
Back to confirm form.
amitaibu Jul 27, 2016
340c9c7
Set state
amitaibu Jul 27, 2016
322e2eb
Back to ContentEntityForm
amitaibu Jul 27, 2016
96cf2ff
Keep confirm form
amitaibu Jul 27, 2016
0d4fb12
Save the membership
amitaibu Jul 27, 2016
078635b
Implement cancel
amitaibu Jul 27, 2016
0969a91
Improve syntax
amitaibu Jul 27, 2016
56cf2d8
getConfirmText
amitaibu Jul 27, 2016
a82a894
Cleanups
amitaibu Jul 27, 2016
38e9ce5
Merge branch '8.x-1.x' into og-ui-subscribe-routes
amitaibu Jul 28, 2016
1a56acf
Add docs [skip ci]
amitaibu Jul 28, 2016
3e60d6e
Work in unsubscribe [skip ci]
amitaibu Jul 28, 2016
d4e007a
Add PHPdocs [skip ci]
amitaibu Jul 28, 2016
53eaa1c
Sniffer fixes
amitaibu Jul 28, 2016
1ed5855
Add membership request field
amitaibu Jul 28, 2016
f2226f0
Fix redirectReposnse [skip ci]
amitaibu Jul 28, 2016
57e9a8b
Use ContentEntityForm instead of EntityConfirmFormBase
amitaibu Jul 28, 2016
ba626c9
Hide request field
amitaibu Jul 28, 2016
9a6503d
Change field type
amitaibu Jul 28, 2016
890d538
Revert "Change field type"
amitaibu Jul 28, 2016
73793d4
Change fields to be string [skip ci]
amitaibu Jul 28, 2016
27e93c9
Try to fix fields
amitaibu Jul 28, 2016
c531391
Fix file name
amitaibu Jul 28, 2016
be9cdf6
Allow passing multiple permissions
amitaibu Jul 28, 2016
df26bb5
Change Og::getMembership arguments order
amitaibu Jul 28, 2016
ff22372
Start worknig on unsubscribe
amitaibu Jul 28, 2016
c292fff
Define form name [skip ci]
amitaibu Jul 28, 2016
9b242bb
Fix unsubscribe
amitaibu Jul 28, 2016
d80991b
Fix unsubscribe labelg
amitaibu Jul 28, 2016
ea02311
Use methods
amitaibu Jul 28, 2016
2da713d
Swap arguments
amitaibu Jul 28, 2016
81117db
Sniffer fixes
amitaibu Jul 28, 2016
3737496
Fix failing tests due to scehma changes
amitaibu Jul 29, 2016
59ed119
Set correct default state
amitaibu Jul 29, 2016
de6c792
Start adding tests
amitaibu Jul 29, 2016
6656d9d
Cleanup
amitaibu Jul 29, 2016
36918dd
Fix wrong indentation
amitaibu Jul 29, 2016
ba831fc
Sniffer fixes
amitaibu Jul 29, 2016
5a586b2
Add Og::getRole
amitaibu Jul 29, 2016
1f7027e
Use Og::getRole in test [skip ci]
amitaibu Jul 29, 2016
6e575e4
Merge 8.x-1.x
amitaibu Jul 29, 2016
a9d331f
Merge branch 'resave-og-role' into og-ui-subscribe-routes
amitaibu Jul 29, 2016
8e3e628
Add Og::getRole helper
amitaibu Jul 29, 2016
9ae099f
Check ifAllowed correctly
amitaibu Jul 29, 2016
026b261
Use correct state variable [skip ci]
amitaibu Jul 29, 2016
22583aa
Check non-members access
amitaibu Jul 29, 2016
61bb77a
Improve test
amitaibu Jul 29, 2016
c86f6f7
Sniffer fixes
amitaibu Jul 29, 2016
5d4f732
Merge branch '8.x-1.x' into og-ui-subscribe-routes
amitaibu Jul 30, 2016
ce2fe35
Merge branch '279-non-member-access' into og-ui-subscribe-routes
amitaibu Jul 30, 2016
740268c
Improve tests
amitaibu Jul 31, 2016
f16805e
Complete form test
amitaibu Jul 31, 2016
d0e8747
Improve comments [skip ci]
amitaibu Jul 31, 2016
914ed02
Start adding unit tests
amitaibu Jul 31, 2016
82e8f05
Add ::testNoGroup
amitaibu Jul 31, 2016
ba0d34b
Use isAllowed [skip ci]
amitaibu Jul 31, 2016
a7f22cd
Add more tests
amitaibu Jul 31, 2016
53ae973
Add data provider
amitaibu Jul 31, 2016
449a7d9
Add data provider to tests
amitaibu Jul 31, 2016
022a645
Merge branch '8.x-1.x' into og-ui-subscribe-routes
amitaibu Aug 1, 2016
b626f0c
Merge branch '8.x-1.x' into og-ui-subscribe-routes
amitaibu Aug 1, 2016
4e8212a
Add functional test
amitaibu Aug 1, 2016
2bfcd9a
Debug test
amitaibu Aug 1, 2016
6747f9f
Sniffer fixes
amitaibu Aug 1, 2016
4975d04
Import classes
amitaibu Aug 1, 2016
e3bad9b
Test fixes
amitaibu Aug 2, 2016
c444279
Start fixing tests
amitaibu Aug 2, 2016
707f249
Fix test
amitaibu Aug 2, 2016
85059d7
Sniffer fixes
amitaibu Aug 2, 2016
86c47a8
Confirm group label doesn't appear
amitaibu Aug 2, 2016
17d375b
Add membership type interface
amitaibu Aug 2, 2016
1845490
Merge branch '8.x-1.x' into og-ui-subscribe-routes
amitaibu Aug 2, 2016
08b1a29
Use Og::createMembership
amitaibu Aug 2, 2016
1962a35
Sniffer fixes
amitaibu Aug 2, 2016
c2a86dd
Improve docs
amitaibu Aug 2, 2016
c4cf934
Expand code coverage
amitaibu Aug 2, 2016
42908bb
Reorganize code
amitaibu Aug 2, 2016
abd1bb2
Fix wrong assertion
amitaibu Aug 2, 2016
3c08670
Improve scnearios
amitaibu Aug 2, 2016
d95dddd
Remove unused use
amitaibu Aug 2, 2016
a4d1ab9
Add comment about why not using provider [skip ci]
amitaibu Aug 3, 2016
e0bd094
Validate membership types
amitaibu Aug 3, 2016
991e0b3
Start adding unsubscribe tests
amitaibu Aug 3, 2016
9aae51a
Add member role
amitaibu Aug 3, 2016
a47fbc2
Fix tests
amitaibu Aug 3, 2016
202b26a
Move permissions to Og core
amitaibu Aug 3, 2016
cce0e73
Remove service
amitaibu Aug 3, 2016
3272a69
Remove module from test
amitaibu Aug 3, 2016
eba37fa
Prevent WSOD on wrong entity type
amitaibu Aug 4, 2016
9b0511e
Add more test cases
amitaibu Aug 4, 2016
c950965
Fix notice
amitaibu Aug 4, 2016
50e6891
Fix another notice
amitaibu Aug 4, 2016
a803648
Use valid random strings
amitaibu Aug 4, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions og_ui/og_ui.routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ og_ui.settings:
requirements:
_permission: 'administer group'

og_ui.subscribe:

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as @dawehner and @damiankloip suggested in #59 (comment) , I'll move those routes and the access services to OG core.

path: 'group/{entity_type_id}/{entity_id}/subscribe/{field_name}'
defaults:
_controller: '\Drupal\og_ui\Controller\SubscriptionController::subscribe'
_title: 'Join Group'
field_name: null
requirements:
_user_is_logged_in: 'TRUE'

og_ui.unsubscribe:
path: 'group/{entity_type_id}/{entity_id}/unsubscribe'
defaults:
_controller: '\Drupal\og_ui\Controller\SubscriptionController::unsubscribe'
_title: 'Leave Group'
requirements:
_og_ui_user_access_group: 'unsubscribe'

og_ui.roles_permissions_overview:
path: 'admin/config/group/{type}'
defaults:
Expand Down
6 changes: 6 additions & 0 deletions og_ui/og_ui.services.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
services:
access_check.og.user_access_group:
class: Drupal\og_ui\Access\GroupCheck
arguments: ['@entity_type.manager']
tags:
- { name: access_check, applies_to: _og_ui_user_access_group }

og_ui.event_subscriber:
class: Drupal\og_ui\EventSubscriber\OgUiEventSubscriber
tags:
Expand Down
76 changes: 76 additions & 0 deletions og_ui/src/Access/GroupCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

/**
* @file
* Contains \Drupal\og_ui\Access\GroupCheck.
*/

namespace Drupal\og_ui\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\og\Og;
use Drupal\og\OgAccess;
use Symfony\Component\Routing\Route;

/**
* Determines access to routes based on group access for the current user.
*/
class GroupCheck implements AccessInterface {

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

/**
* Constructs a GroupCheck object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}

/**
* Checks access.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The currently logged in account.
* @param \Symfony\Component\Routing\Route $route
* The route to check against.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(AccountInterface $account, Route $route, $entity_type_id, $entity_id) {
// No access if the entity type doesn't exist.
if (!$this->entityTypeManager->getDefinition($entity_type_id, FALSE)) {
return AccessResult::forbidden();
}

$entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$group = $entity_storage->load($entity_id);

// No access if no entity was loaded or it's not a group.
if (!$group || !Og::isGroup($entity_type_id, $group->bundle())) {
return AccessResult::forbidden();
}

// @todo Convert when Role checking is added and has API to use.
// Verify the bundle has roles
// if (!og_roles($group_type, $bundle, $gid)) {
// return AccessResult::forbidden();
// }

$permission = $permission = $route->getRequirement('_og_ui_user_access_group');

return OgAccess::userAccess($group, $permission);
}

}

164 changes: 164 additions & 0 deletions og_ui/src/Controller/SubscriptionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php

/**
* @file
* Contains \Drupal\og_ui\Controller\SubscriptionController.
*/

namespace Drupal\og_ui\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\og\OgMembershipInterface;
use Drupal\user\Entity\User;
use Drupal\user\EntityOwnerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\og\Og;
use Drupal\og\OgAccess;

/**
* Controller for OG subscription routes.
*/
class SubscriptionController extends ControllerBase {

/**
* @param string $entity_type_id
* @param string|int $entity_id
* @param NULL|string $field_name
*
* @return mixed
*/
public function subscribe(Request $request, $entity_type_id, $entity_id, $field_name) {
// @todo We don't need to re-validate the entity type and entity group here,
// as it's already been done in the access check?
$entity_storage = $this->entityTypeManager()->getStorage($entity_type_id);
$entity_access = $this->entityTypeManager()->getAccessControlHandler($entity_type_id);
$group = $entity_storage->load($entity_id);

$account = User::load($this->currentUser()->id());

if (empty($field_name)) {
$field_name = og_get_best_group_audience_field('user', $account, $entity_type_id, $group->bundle());
if (empty($field_name)) {
throw new NotFoundHttpException();
}
}

// @todo Requires FieldableEntityInterface/ContentEntityInterface
$field = $group->getFieldDefinition($field_name);

if (empty($instance) || !$entity_access->fieldAccess('view', $field, $account)) {
// Field name given is incorrect, or user doesn't have access to the field.
throw new NotFoundHttpException();
}

if ($account->isAnonymous()) {
// Anonymous user can't request membership.
$destination = $this->getDestinationArray();

$user_login_url = Url::fromRoute('user.login', [], $destination)->toString();

// @todo I think this is correct? Other options are visitors or require
// approval both of which apply to the else instead of here.
if ($this->config('user.settings')->get('register') === USER_REGISTER_ADMINISTRATORS_ONLY) {
drupal_set_message($this->t('In order to join any group, you must <a href=":login">login</a>. After you have successfully done so, you will need to request membership again.', [':login' => $user_login_url]));
}
else {
$user_register_url = Url::fromRoute('user.register', [], $destination)->toString();
drupal_set_message($this->t('In order to join any group, you must <a href=":login">login</a> or <a href=":register">register</a> a new account. After you have successfully done so, you will need to request membership again.', [':register' => $user_register_url, ':login' => $user_login_url]));
}

return new RedirectResponse(Url::fromRoute('user.page')->setAbsolute(TRUE)->toString());
}

$redirect = FALSE;
$message = '';
$params = [
'@user' => $account->getDisplayName(),
];

// Show the group name only if user has access to it.
$params['@group'] = $group->access('view', $account) ? $group->label() : $this->t('Private group');

if (Og::isMemberBlocked($group, $account)) {
// User is blocked, access denied.
throw new AccessDeniedHttpException();
}

if (Og::isMemberPending($group, $account)) {
// User is pending, return them back.
$message = $this->t('@user already has a pending membership for the the group @group.', $params);
$redirect = TRUE;
}

if (Og::isMember($group, $account)) {
// User is already a member, return them back.
$message = $this->t('You are already a member of the group @group.', $params);
$redirect = TRUE;
}

$cardinality = $field->getStorageDefinition()->getCardinality();

if (!$message && ($cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)) {
// Check if user is already registered as active or pending in the maximum
// allowed values.
if ($cardinality === 1) {
$count = $account->get($field_name)->value ? 1 : 0;
}
else {
$count = $account->get($field_name)->count();
}

if ($count >= $cardinality) {
$message = $this->t('You cannot register to this group, as you have reached your maximum allowed subscriptions.');
$redirect = TRUE;
}
}

if ($redirect) {
drupal_set_message($message, 'warning');
return new RedirectResponse($group->toUrl()->setAbsolute(TRUE)->toString());
}

if (OgAccess::userAccess($group, 'subscribe', $account) || OgAccess::userAccess($group, 'subscribe without approval', $account)) {
// Show the user a subscription confirmation.
// @todo Use buildForm() create our own form state object and attach
// field_name etc..?
return $this->formBuilder()->getForm('\Drupal\og_ui\Form\GroupSubscribeConfirmForm', $group, $account, $field_name);
}

throw new AccessDeniedHttpException();
}

/**
* @param string $entity_type_id
* @param string|int $entity_id
*/
public function unsubscribe($entity_type_id, $entity_id) {
// @todo We don't need to re-validate the entity type and entity group here,
// as it's already been done in the access check?
$entity_storage = $this->entityTypeManager()->getStorage($entity_type_id);
$group = $entity_storage->load($entity_id);

$account = $this->currentUser();

// Check the user isn't the manager of the group.
if (($group instanceof EntityOwnerInterface) && ($group->getOwnerId() !== $account->id())) {
if (Og::isMember($group, $account, [OgMembershipInterface::STATE_ACTIVE, OgMembershipInterface::STATE_PENDING])) {
// Show the user a subscription confirmation.
return $this->formBuilder()->getForm('\Drupal\og_ui\Form\GroupUnsubscribeConfirmForm', $group);
}

throw new AccessDeniedHttpException();
}

drupal_set_message(t('As the manager of %group, you can not leave the group.', array('%group' => $group->label())));

return new RedirectResponse($group->toUrl()->setAbsolute(TRUE)->toString());
}

}
116 changes: 116 additions & 0 deletions og_ui/src/Form/GroupSubscribeConfirmForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

/**
* @file
* Contains \Drupal\og_ui\Form\GroupSubscribeConfirmForm.
*/

namespace Drupal\og_ui\Form;

use Drupal\Core\Entity\EntityConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\og\OgAccess;
use Drupal\og\OgMembershipInterface;

/**
* Provides a confirmation form for subscribing form a group.
*/
class GroupSubscribeConfirmForm extends EntityConfirmFormBase {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'og_ui_subscribe_confirm_form';
}

/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to join the group %title?', ['%title' => $this->entity->label()]);
}

/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Join');
}

/**
* {@inheritdoc}
*/
public function getCancelUrl() {
// TODO: Implement getCancelUrl() method.
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Indicate the OG membership state (active or pending).
$state = OgAccess::userAccess($this->entity, 'subscribe without approval') ? OgMembershipInterface::STATE_ACTIVE : OgMembershipInterface::STATE_PENDING;

if ($this->entity->access('view')) {
$label = $this->entity->label();
}
else {
$label = $this->t('Private group');

if ($state === OgMembershipInterface::STATE_ACTIVE) {
// Determine if a user can subscribe to a private group, when OG-access
// module is enabled, and the group is set to private.
$state = $this->config('og_ui.settings')->get('deny_subscribe_without_approval') ? OgMembershipInterface::STATE_PENDING : OgMembershipInterface::STATE_ACTIVE;
}
}

// // Add group membership form.
// $og_membership = og_membership_create($group_type, $gid, 'user', $account->uid, $field_name, array('state' => $state));
// $form_state['og_membership'] = $og_membership;
// field_attach_form('og_membership', $og_membership, $form, $form_state);
//
// if ($state == OG_STATE_ACTIVE && !empty($form[OG_MEMBERSHIP_REQUEST_FIELD])) {
// // Hide the user request field.
// $form[OG_MEMBERSHIP_REQUEST_FIELD]['#access'] = FALSE;
// }
// $form['group_type'] = array('#type' => 'value', '#value' => $group_type);
// $form['gid'] = array('#type' => 'value', '#value' => $gid);
// $form['field_name'] = array('#type' => 'value', '#value' => $field_name);

return parent::buildForm($form, $form_state);
}

/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);

// @see entity_form_field_validate().
$og_membership = $form_state['og_membership'];
field_attach_form_validate('og_membership', $og_membership, $form, $form_state);
}


/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$og_membership = $form_state['og_membership'];
field_attach_submit('og_membership', $og_membership, $form, $form_state);

$og_membership->save();

if ($this->entity->access('view')) {
$form_state->setRedirectUrl($this->entity->toUrl());
}
else {
// User doesn't have access to the group entity, so redirect to front page,
// with a message.
drupal_set_message($this->t('Your subscription request was sent.'));
}
}

}

Loading