updated core and modules

This commit is contained in:
Bachir Soussi Chiadmi
2017-09-09 16:27:51 +02:00
parent 027aa99b32
commit 41863f872c
7810 changed files with 318922 additions and 83631 deletions
@@ -31,6 +31,9 @@ profile.type.*:
langcode:
type: string
label: 'Default language'
use_revisions:
type: boolean
label: 'User revisions'
field.field.*.*.*.third_party.profile:
type: mapping
@@ -1,51 +0,0 @@
<?php
/**
* @file
* Hooks provided by profile module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Control access to a user profile.
*
* Modules may implement this hook to control whether a user has access to
* perform a certain operation on a profile.
*
* @param string $op
* The operation being performed. One of 'view', 'edit' (being the same as
* 'create' or 'update'), or 'delete'.
* @param Drupal\profile\Entity\Profile $profile
* A profile to check access for.
* @param Drupal\user\Entity\User $account
* The user performing the operation; the currently logged in user by default.
*
* @return bool
* Either a Boolean or NULL:
* - FALSE to explicitly deny access. If a module denies access, no other
* module is able to grant access and access is denied.
* - TRUE to grant access. Access is only granted if at least one module
* grants access and no module denies access.
* - NULL or nothing to not affect the operation. If no module explicitly
* grants access, access is denied.
*/
function hook_profile_access($op, Drupal\profile\Entity\Profile $profile, Drupal\user\Entity\User $account) {
// Explicitly deny access for a 'secret' profile type.
if ($profile->getType() == 'secret' && !\Drupal::currentUser()->hasPermission('custom permission')) {
return FALSE;
}
// For profiles other than the default profile grant access.
if ($profile->getType() != 'main' && \Drupal::currentUser()->hasPermission('custom permission')) {
return TRUE;
}
// In other cases do not alter access.
return NULL;
}
/**
* @}
*/
@@ -10,8 +10,8 @@ dependencies:
- views
- system (>=8.1.0)
# Information added by Drupal.org packaging script on 2016-08-31
version: '8.x-1.0-alpha5+4-dev'
# Information added by Drupal.org packaging script on 2017-06-12
version: '8.x-1.0-beta1'
core: '8.x'
project: 'profile'
datestamp: 1472611474
datestamp: 1497287652
@@ -0,0 +1,36 @@
<?php
/**
* @file
* Install, update and uninstall functions for the profile module.
*/
/**
* Uninstalls the langcode field from the profile entity.
*/
function profile_update_8001() {
$definition = \Drupal::entityTypeManager()->getDefinition('profile');
// Allow langcode field to be null.
$schema = \Drupal::database()->schema();
if ($schema->fieldExists($definition->getBaseTable(), 'langcode')) {
$schema->changeField($definition->getBaseTable(), 'langcode', 'langcode', [
'type' => 'varchar',
'length' => 12,
'not null' => FALSE,
]);
// Set langcode field to null so it can be deleted.
\Drupal::database()
->update($definition->getBaseTable())
->fields(['langcode' => NULL])
->execute();
}
$entity_definition_update = \Drupal::entityDefinitionUpdateManager();
if ($storage_definition = $entity_definition_update->getFieldStorageDefinition('langcode', 'profile')) {
$entity_definition_update->uninstallFieldStorageDefinition($storage_definition);
}
return t('Language code field uninstalled from profile entity.');
}
@@ -5,6 +5,11 @@
* Support for configurable user profiles.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\UserInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -16,26 +21,6 @@ use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Denotes that the profile is not active.
*/
const PROFILE_NOT_ACTIVE = 0;
/**
* Denotes that the profile is active.
*/
const PROFILE_ACTIVE = 1;
/**
* Denotes that the profile is not default.
*/
const PROFILE_NOT_DEFAULT = 0;
/**
* Denotes that the profile is default.
*/
const PROFILE_DEFAULT = 1;
/**
* Implements hook_help().
*/
@@ -43,10 +28,10 @@ function profile_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.profile':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Profile module provides a fieldable entity, that allows administrators to define different sets of fields for user profiles, which are then displayed in the <a href="!user">My Account</a> section. This permits users of a site to share more information about themselves, and can help community-based sites organize users around specific information.', ['!user' => Url::fromRoute('user.page')]) . '</p>';
$output .= '<p>' . t('The Profile module provides a fieldable entity, that allows administrators to define different sets of fields for user profiles, which are then displayed in the <a href="@user">My Account</a> section. This permits users of a site to share more information about themselves, and can help community-based sites organize users around specific information.', ['@user' => Url::fromRoute('user.page')->toString()]) . '</p>';
$output .= '<dl>';
$output .= '<dt>' . t('Types of profiles') . '</dt>';
$output .= '<dd>' . t('Profile types provide a way of grouping similar data for user profiles e.g. Personal information, Work etc. A default "Personal information type is provided. You may create more types and manage fields for each type from the <a href="!profile-types">Profile types</a> admin page. When creating a new profile type, you will be able to specify whether a user may create multiple profiles or make the profile form available when registering a new user.', ['!profile-types' => Url::fromRoute('entity.profile_type.collection')]) . '</dd>';
$output .= '<dd>' . t('Profile types provide a way of grouping similar data for user profiles e.g. Personal information, Work etc. A default "Personal information type is provided. You may create more types and manage fields for each type from the <a href="@profile-types">Profile types</a> admin page. When creating a new profile type, you will be able to specify whether a user may create multiple profiles or make the profile form available when registering a new user.', ['@profile-types' => Url::fromRoute('entity.profile_type.collection')->toString()]) . '</dd>';
$output .= '<dt>' . t('Creating profiles') . '</dt>';
$output .= '<dd>' . t('A user will see tabs they have access to, when editing their main user account e.g. "Add personal information profile". The visibility of a tab depends on whether they can create multiple profiles or if they haven\'t created a profile of the type that doesn\'t allow multiple instances.') . '</dd>';
$output .= '</dl>';
@@ -54,6 +39,29 @@ function profile_help($route_name, RouteMatchInterface $route_match) {
}
}
/**
* Implements hook_entity_field_access().
*/
function profile_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
if ($operation == 'view' && $items && $field_definition->getTargetEntityTypeId() == 'profile') {
if ($field_definition instanceof FieldConfigInterface) {
$is_private = $field_definition->getThirdPartySetting('profile', 'profile_private', FALSE);
if ($is_private) {
// Users may see their own private profile fields by default, so this
// requires user granularity for caching.
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
$profile = $items->getEntity();
if ($account->id() === $profile->getOwnerId()) {
return AccessResult::neutral();
}
return AccessResult::forbiddenIf(!$account->hasPermission('administer profile'));
}
}
}
return AccessResult::neutral();
}
/**
* Implements hook_theme().
*/
@@ -83,7 +91,7 @@ function template_preprocess_profile(array &$variables) {
$variables['url'] = $profile->toUrl();
// Helpful $content variable for templates.
$variables['content'] = [];
foreach (\Drupal\Core\Render\Element::children($variables['elements']) as $key) {
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
@@ -120,13 +128,16 @@ function profile_user_view(array &$build, UserInterface $account, EntityViewDisp
function profile_entity_extra_field_info() {
$extra = [];
// Add each profile type as an extra field for display. Enabled by default.
// Add each profile type as an extra field for display. Not enabled by default
// as many sites will not need this and it otherwise also gets added
// automatically to other view modes.
/** @var \Drupal\profile\Entity\ProfileType $bundle */
foreach (ProfileType::loadMultiple() as $bundle) {
$extra['user']['user']['display']['profile_' . $bundle->id()] = array(
'label' => $bundle->label(),
'description' => t('Display @type profiles', ['@type' => $bundle->label()]),
'weight' => 10,
'visible' => TRUE,
'visible' => FALSE,
);
}
return $extra;
@@ -140,7 +151,7 @@ function profile_user_delete(EntityInterface $entity) {
->getStorage('profile')
->loadByProperties([
'uid' => $entity->id(),
]);
]);
foreach ($list as $profile) {
$profile->delete();
@@ -209,8 +220,7 @@ function profile_form_user_register_form_alter(&$form, FormStateInterface $form_
if (empty($profile)) {
$profile = Profile::create([
'type' => $profile_type->id(),
'langcode' => $profile_type->language() ?
$profile_type->language() : \Drupal::languageManager()->getDefaultLanguage()->getId(),
'langcode' => $profile_type->language() ? $profile_type->language() : \Drupal::languageManager()->getDefaultLanguage()->getId(),
]);
// Attach profile entity form.
@@ -225,6 +235,22 @@ function profile_form_user_register_form_alter(&$form, FormStateInterface $form_
'#weight' => ++$weight,
'#open' => TRUE,
];
// @see https://www.drupal.org/node/2871480.
if (\Drupal::moduleHandler()->moduleExists('field_group')) {
$context = [
'entity_type' => $profile->getEntityTypeId(),
'bundle' => $profile->bundle(),
'entity' => $profile,
'context' => 'form',
'display_context' => 'form',
'mode' => 'default',
];
field_group_attach_groups($form['entity_' . $profile_type->id()], $context);
$form['entity_' . $profile_type->id()]['#pre_render'][] = 'field_group_form_pre_render';
}
$form_state
->get('form_display_' . $profile_type->id())
->buildForm($profile, $form['entity_' . $profile_type->id()], $form_state);
@@ -248,13 +274,15 @@ function profile_form_user_register_form_validate(array &$form, FormStateInterfa
foreach ($profiles as $bundle => $entity) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$form_display = $form_state->get('form_display_' . $bundle);
$form_display->extractFormValues($entity, $form['entity_' . $bundle], $form_state);
$form_display->validateFormValues($entity, $form['entity_' . $bundle], $form_state);
if (isset($form['entity_' . $bundle])) {
$form_display->extractFormValues($entity, $form['entity_' . $bundle], $form_state);
$form_display->validateFormValues($entity, $form['entity_' . $bundle], $form_state);
}
}
}
// Entity was validated in entityFormValidate(). This will prevent validation
// exception from being thrown.
$form_state->getFormObject()->getEntity()->validate();
$form_state->getFormObject()->validateForm($form, $form_state);
}
/**
@@ -1,13 +1,3 @@
administer profile types:
title: 'Administer profile types'
restrict access: true
administer profiles:
title: 'Administer profiles'
restrict access: true
bypass profile access:
title: 'Bypass profile access control'
description: 'View, edit and delete all user profiles, including private field values, regardless of permission restrictions.'
restrict access: true
permission_callbacks:
- \Drupal\profile\ProfilePermissions::profileTypePermissions
@@ -5,7 +5,7 @@ entity.profile.collection:
_entity_list: 'profile'
_title: 'Profiles'
requirements:
_permission: 'administer profiles'
_permission: 'administer profile'
entity.profile_type.collection:
path: '/admin/config/people/profiles/types'
@@ -23,14 +23,21 @@ entity.profile_type.add_form:
requirements:
_permission: 'administer profile types'
entity.profile.add_form:
path: '/user/{user}/profile/{profile_type}'
entity.profile.type.user_profile_form:
path: '/user/{user}/{profile_type}'
defaults:
_controller: '\Drupal\profile\Controller\ProfileController::userProfileForm'
_title_callback: '\Drupal\profile\Controller\ProfileController::addPageTitle'
requirements:
_profile_access_check: 'add'
entity.profile.type.user_profile_form.add:
path: '/user/{user}/{profile_type}/add'
defaults:
_controller: '\Drupal\profile\Controller\ProfileController::addProfile'
_title: 'Add new profile'
operation: 'add'
_title_callback: '\Drupal\profile\Controller\ProfileController::addPageTitle'
requirements:
_profile_access_check: 'profile:{profile_type}'
_profile_access_check: 'add'
entity.profile.canonical:
path: '/profile/{profile}'
@@ -45,7 +52,7 @@ entity.profile.multiple_delete_confirm:
defaults:
_form: '\Drupal\profile\Form\DeleteMultiple'
requirements:
_permission: 'administer profiles'
_permission: 'administer profile'
entity.profile.set_default:
path: '/profile/{profile}/set-default'
@@ -56,5 +63,5 @@ entity.profile.set_default:
profile:
type: entity:profile
requirements:
_entity_access: 'profile.edit'
_entity_access: 'profile.update'
_csrf_token: 'TRUE'
@@ -38,35 +38,22 @@ class ProfileAccessCheck implements AccessInterface {
* The route to check against.
* @param \Drupal\Core\Session\AccountInterface $account
* The currently logged in account.
* @param \Drupal\Core\Session\AccountInterface $user
* The user entity.
* @param \Drupal\profile\Entity\ProfileTypeInterface $profile_type
* The profile type entity.
*
* @return bool|\Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(Route $route, AccountInterface $account, ProfileTypeInterface $profile_type = NULL) {
$access_control_handler = $this->entityTypeManager->getAccessControlHandler('profile');
public function access(Route $route, AccountInterface $account, AccountInterface $user, ProfileTypeInterface $profile_type) {
if ($account->hasPermission('administer profile types')) {
return AccessResult::allowed()->cachePerPermissions();
}
$operation = $route->getRequirement('_profile_access_check');
if ($operation == 'add') {
return $access_control_handler->access($profile_type, $operation, $account, TRUE);
}
$own_any = ($account->id() == $user->id()) ? 'own' : 'any';
$operation = ($profile_type->getMultiple()) ? 'view' : 'update';
if ($profile_type) {
return $access_control_handler->createAccess($profile_type->id(), $account, [], TRUE);
}
// If checking whether a profile of any type may be created.
foreach ($this->entityTypeManager->getStorage('profile_type')->loadMultiple() as $profile_type) {
if (($access = $access_control_handler->createAccess($profile_type->id(), $account, [], TRUE)) && $access->isAllowed()) {
return $access;
}
}
// No opinion.
return AccessResult::neutral();
return AccessResult::allowedIfHasPermission($account, "$operation $own_any {$profile_type->id()} profile");
}
}
@@ -76,7 +76,7 @@ class ProfileController extends ControllerBase implements ContainerInjectionInte
}
/**
* The _title_callback for the entity.profile.add_form route.
* The _title_callback for the add profile form route.
*
* @param \Drupal\profile\Entity\ProfileTypeInterface $profile_type
* The current profile type.
@@ -106,8 +106,9 @@ class ProfileController extends ControllerBase implements ContainerInjectionInte
/** @var \Drupal\profile\Entity\ProfileType $profile_type */
/** @var \Drupal\profile\Entity\ProfileInterface|bool $active_profile */
$active_profile = $this->entityTypeManager()->getStorage('profile')
->loadByUser($user, $profile_type->id());
$active_profile = $this->entityTypeManager()
->getStorage('profile')
->loadByUser($user, $profile_type->id());
// If the profile type does not support multiple, only display an add form
// if there are no entities, or an edit for the current.
@@ -132,8 +133,8 @@ class ProfileController extends ControllerBase implements ContainerInjectionInte
$build['add_profile'] = Link::createFromRoute(
$this->t('Add new @type', ['@type' => $profile_type->label()]),
"entity.profile.type.{$profile_type->id()}.user_profile_form.add",
['user' => \Drupal::currentUser()->id(), 'profile_type' => $profile_type->id()])
'entity.profile.type.user_profile_form.add',
['user' => $this->currentUser()->id(), 'profile_type' => $profile_type->id()])
->toRenderable();
// Render the active profiles.
@@ -164,13 +165,14 @@ class ProfileController extends ControllerBase implements ContainerInjectionInte
* A redirect back to the currency listing.
*/
public function setDefault(RouteMatchInterface $routeMatch) {
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
$profile = $routeMatch->getParameter('profile');
$profile->setDefault(TRUE);
$profile->save();
drupal_set_message($this->t('The %label profile has been marked as default.', ['%label' => $profile->label()]));
$url = $profile->urlInfo('collection');
$url = $profile->toUrl('collection');
return $this->redirect($url->getRouteName(), $url->getRouteParameters(), $url->getOptions());
}
@@ -8,9 +8,11 @@ use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\profile\Event\ProfileEvents;
use Drupal\profile\Event\ProfileLabelEvent;
use Drupal\user\UserInterface;
/**
* Defines the profile entity class.
*
@@ -23,6 +25,7 @@ use Drupal\user\UserInterface;
* "view_builder" = "Drupal\profile\ProfileViewBuilder",
* "views_data" = "Drupal\profile\ProfileViewsData",
* "access" = "Drupal\profile\ProfileAccessControlHandler",
* "permission_provider" = "Drupal\profile\ProfilePermissionProvider",
* "list_builder" = "Drupal\profile\ProfileListBuilder",
* "form" = {
* "default" = "Drupal\profile\Form\ProfileForm",
@@ -31,12 +34,13 @@ use Drupal\user\UserInterface;
* "delete" = "Drupal\profile\Form\ProfileDeleteForm",
* },
* "route_provider" = {
* "html" = "Drupal\profile\ProfileHtmlRouteProvider",
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* },
* },
* bundle_entity_type = "profile_type",
* field_ui_base_route = "entity.profile_type.edit_form",
* admin_permission = "administer profiles",
* admin_permission = "administer profile",
* permission_granularity = "bundle",
* base_table = "profile",
* revision_table = "profile_revision",
* fieldable = TRUE,
@@ -44,7 +48,6 @@ use Drupal\user\UserInterface;
* "id" = "profile_id",
* "revision" = "revision_id",
* "bundle" = "type",
* "langcode" = "langcode",
* "uuid" = "uuid"
* },
* links = {
@@ -60,78 +63,24 @@ use Drupal\user\UserInterface;
class Profile extends ContentEntityBase implements ProfileInterface {
use EntityChangedTrait;
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Owner'))
->setDescription(t('The user that owns this profile.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default');
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Active status'))
->setDescription(t('A boolean indicating whether the profile is active.'))
->setDefaultValue(TRUE)
->setRevisionable(TRUE);
$fields['is_default'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Default'))
->setDescription(t('A boolean indicating whether the profile is the default one.'))
->setRevisionable(TRUE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time that the profile was created.'))
->setRevisionable(TRUE);
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setDescription(t('The time that the profile was last edited.'))
->setRevisionable(TRUE);
return $fields;
}
/**
* Overrides Entity::id().
*/
public function id() {
return $this->get('profile_id')->value;
}
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function label() {
$profile_type = ProfileType::load($this->bundle());
return
t('@type profile of @username (uid: @uid)',
[
'@type' => $profile_type->label(),
'@username' => $this->getOwner()->getDisplayName(),
'@uid' => $this->getOwnerId(),
]);
}
$label = $this->t('@type profile #@id', [
'@type' => $profile_type->label(),
'@id' => $this->id(),
]);
// Allow the label to be overridden.
$event = new ProfileLabelEvent($this, $label);
$event_dispatcher = \Drupal::service('event_dispatcher');
$event_dispatcher->dispatch(ProfileEvents::PROFILE_LABEL, $event);
$label = $event->getLabel();
/**
* {@inheritdoc}
*/
public function getType() {
return $this->bundle();
}
/**
* {@inheritdoc}
*/
public function setType($type) {
$this->set('type', $this->bundle());
return $this;
return $label;
}
/**
@@ -164,6 +113,36 @@ class Profile extends ContentEntityBase implements ProfileInterface {
return $this;
}
/**
* {@inheritdoc}
*/
public function isActive() {
return (bool) $this->get('status')->value;
}
/**
* {@inheritdoc}
*/
public function setActive($active) {
$this->set('status', (bool) $active);
return $this;
}
/**
* {@inheritdoc}
*/
public function isDefault() {
return (bool) $this->get('is_default')->value;
}
/**
* {@inheritdoc}
*/
public function setDefault($is_default) {
$this->set('is_default', (bool) $is_default);
return $this;
}
/**
* {@inheritdoc}
*/
@@ -209,36 +188,6 @@ class Profile extends ContentEntityBase implements ProfileInterface {
return $this;
}
/**
* {@inheritdoc}
*/
public function isActive() {
return (bool) $this->get('status')->value;
}
/**
* {@inheritdoc}
*/
public function setActive($active) {
$this->set('status', $active ? PROFILE_ACTIVE : PROFILE_NOT_ACTIVE);
return $this;
}
/**
* {@inheritdoc}
*/
public function isDefault() {
return (bool) $this->get('is_default')->value;
}
/**
* {@inheritdoc}
*/
public function setDefault($is_default) {
$this->set('is_default', $is_default ? PROFILE_DEFAULT : PROFILE_NOT_DEFAULT);
return $this;
}
/**
* {@inheritdoc}
*/
@@ -250,6 +199,37 @@ class Profile extends ContentEntityBase implements ProfileInterface {
]);
}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage) {
/** @var \Drupal\profile\ProfileStorage $storage */
parent::preSave($storage);
// If this profile is active and the owner has no current default profile
// of this type, set this as the default.
if ($this->getOwner()) {
if ($this->isActive() && !$this->isDefault()) {
if (!$storage->loadDefaultByUser($this->getOwner(), $this->bundle())) {
$this->setDefault(TRUE);
}
}
// Only active profiles can be default.
elseif (!$this->isActive()) {
$this->setDefault(FALSE);
}
}
// Mark a new revision if the profile type supports revisions, and if there
// has been field data changes.
if ($this->hasTranslationChanges()) {
/** @var \Drupal\profile\Entity\ProfileTypeInterface $profile_type */
$profile_type = \Drupal::entityTypeManager()->getStorage('profile_type')->load($this->bundle());
$this->setNewRevision($profile_type->shouldCreateNewRevision());
}
}
/**
* {@inheritdoc}
*/
@@ -258,18 +238,65 @@ class Profile extends ContentEntityBase implements ProfileInterface {
parent::postSave($storage, $update);
// Check if this profile is, or became the default.
if ($this->isDefault()) {
/** @var \Drupal\profile\Entity\ProfileInterface[] $profiles */
$profiles = $storage->loadMultipleByUser($this->getOwner(), $this->getType());
if ($this->getOwner()) {
if ($this->isDefault()) {
/** @var \Drupal\profile\Entity\ProfileInterface[] $profiles */
$profiles = $storage->loadMultipleByUser($this->getOwner(), $this->bundle());
// Ensure that all other profiles are set to not default.
foreach ($profiles as $profile) {
if ($profile->id() != $this->id() && $profile->isDefault()) {
$profile->setDefault(FALSE);
// Ensure that all other profiles are set to not default.
foreach ($profiles as $profile) {
if ($profile->id() != $this->id() && $profile->isDefault()) {
$profile->setDefault(FALSE);
$profile->save();
}
}
}
// If this isn't the default, try to set a new one.
elseif (!$storage->loadDefaultByUser($this->getOwner(), $this->bundle())) {
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
if ($profile = $storage->loadByUser($this->getOwner(), $this->bundle())) {
$profile->setDefault(TRUE);
$profile->save();
}
}
}
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Owner'))
->setDescription(t('The user that owns this profile.'))
->setRevisionable(TRUE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default');
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Active'))
->setDescription(t('Whether the profile is active.'))
->setDefaultValue(TRUE)
->setRevisionable(TRUE);
$fields['is_default'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Default'))
->setDescription(t('Whether this is the default profile.'))
->setRevisionable(TRUE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time when the profile was created.'))
->setRevisionable(TRUE);
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setDescription(t('The time when the profile was last edited.'))
->setRevisionable(TRUE);
return $fields;
}
}
@@ -7,30 +7,55 @@ use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\user\EntityOwnerInterface;
/**
* Provides an interface defining a profile entity.
* Provides an interface for profiles.
*/
interface ProfileInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface {
/**
* Returns the profile type.
* Gets whether the profile is active.
*
* @return string
* The profile type name.
* Unpublished profiles are only visible to their authors and administrators.
*
* @return bool
* TRUE if the profile is active, FALSE otherwise.
*/
public function getType();
public function isActive();
/**
* Sets the profile type.
* Sets whether the profile is active.
*
* @param string $type
* The profile type.
* @param bool $active
* Whether the profile is active.
*
* @return $this
*/
public function setType($type);
public function setActive($active);
/**
* Returns the profile creation timestamp.
* Gets whether this is the user's default profile.
*
* A user can have a default profile of each type.
*
* @return bool
* TRUE if this is the user's default profile, FALSE otherwise.
*/
public function isDefault();
/**
* Sets whether this is the user's default profile.
*
* @param bool $is_default
* Whether this is the user's default profile.
*
* @return $this
*/
public function setDefault($is_default);
/**
* Gets the profile creation timestamp.
*
* @return int
* The profile creation timestamp.
*/
public function getCreatedTime();
@@ -45,7 +70,7 @@ interface ProfileInterface extends ContentEntityInterface, EntityChangedInterfac
public function setCreatedTime($timestamp);
/**
* Returns the profile revision creation timestamp.
* Gets the profile revision creation timestamp.
*
* @return int
* The UNIX timestamp of when this revision was created.
@@ -63,7 +88,7 @@ interface ProfileInterface extends ContentEntityInterface, EntityChangedInterfac
public function setRevisionCreationTime($timestamp);
/**
* Returns the profile revision author.
* Gets the profile revision author.
*
* @return \Drupal\user\UserInterface
* The user entity for the revision author.
@@ -80,47 +105,4 @@ interface ProfileInterface extends ContentEntityInterface, EntityChangedInterfac
*/
public function setRevisionAuthorId($uid);
/**
* Returns a label for the profile.
*/
public function label();
/**
* Returns the node published status indicator.
*
* Unpublished profiles are only visible to their authors and administrators.
*
* @return bool
* TRUE if the profile is active.
*/
public function isActive();
/**
* Sets the published status of a profile.
*
* @param bool $active
* TRUE to set this profile to active, FALSE to set it to inactive.
*
* @return $this
*/
public function setActive($active);
/**
* Returns the profile default status indicator.
*
* @return bool
* TRUE if the profile is default.
*/
public function isDefault();
/**
* Sets the default status of a profile.
*
* @param bool $is_default
* TRUE to set this profile to default, FALSE to set it to not default.
*
* @return $this
*/
public function setDefault($is_default);
}
@@ -38,7 +38,8 @@ use Drupal\Core\Entity\EntityStorageInterface;
* "roles",
* "weight",
* "status",
* "langcode"
* "langcode",
* "use_revisions"
* },
* links = {
* "add-form" = "/admin/config/people/profiles/types/add",
@@ -54,7 +55,7 @@ class ProfileType extends ConfigEntityBundleBase implements ProfileTypeInterface
/**
* The primary identifier of the profile type.
*
* @var integer
* @var int
*/
protected $id;
@@ -75,14 +76,14 @@ class ProfileType extends ConfigEntityBundleBase implements ProfileTypeInterface
/**
* Whether the profile type is shown during registration.
*
* @var boolean
* @var bool
*/
protected $registration = FALSE;
/**
* Whether the profile type allows multiple profiles.
*
* @var boolean
* @var bool
*/
protected $multiple = FALSE;
@@ -96,10 +97,17 @@ class ProfileType extends ConfigEntityBundleBase implements ProfileTypeInterface
/**
* The weight of the profile type compared to others.
*
* @var integer
* @var int
*/
protected $weight = 0;
/**
* Should profiles of this type always generate revisions.
*
* @var bool
*/
protected $use_revisions = FALSE;
/**
* {@inheritdoc}
*/
@@ -140,7 +148,7 @@ class ProfileType extends ConfigEntityBundleBase implements ProfileTypeInterface
/**
* {@inheritdoc}
*/
public function setRoles($roles) {
public function setRoles(array $roles) {
$this->roles = $roles;
return $this;
}
@@ -160,15 +168,23 @@ class ProfileType extends ConfigEntityBundleBase implements ProfileTypeInterface
return $this;
}
/**
* {@inheritdoc}
*/
public function shouldCreateNewRevision() {
return $this->use_revisions;
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
// @todo Setting ->setRebuildNeeded isn't enough. Investigate.
\Drupal::service('router.builder')->rebuild();
// Rebuild module data to generate bundle permissions and link tasks.
if (!$update) {
system_rebuild_module_data();
}
}
}
@@ -3,11 +3,12 @@
namespace Drupal\profile\Entity;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\RevisionableEntityBundleInterface;
/**
* Provides an interface defining a profile type entity.
*/
interface ProfileTypeInterface extends ConfigEntityInterface {
interface ProfileTypeInterface extends ConfigEntityInterface, RevisionableEntityBundleInterface {
/**
* Return the registration form flag.
@@ -50,7 +51,7 @@ interface ProfileTypeInterface extends ConfigEntityInterface {
*
* @return $this
*/
public function setRoles($roles);
public function setRoles(array $roles);
/**
* Returns the profile type's weight.
@@ -0,0 +1,19 @@
<?php
namespace Drupal\profile\Event;
/**
* Defines events for the profile module.
*/
final class ProfileEvents {
/**
* Name of the event fired when altering a profile label.
*
* @Event
*
* @see \Drupal\Profile\Event\ProfileFormatEvent
*/
const PROFILE_LABEL = 'profile.label';
}
@@ -0,0 +1,75 @@
<?php
namespace Drupal\profile\Event;
use Drupal\profile\Entity\ProfileInterface;
use Symfony\Component\EventDispatcher\Event;
/**
* Defines the profile label event.
*
* @see \Drupal\address\Event\AddressEvents
*/
class ProfileLabelEvent extends Event {
/**
* The profile.
*
* @var \Drupal\profile\Entity\ProfileInterface
*/
protected $profile;
/**
* The label.
*
* @var string
*/
protected $label;
/**
* Constructs a new ProfileLabelEvent object.
*
* @param \Drupal\profile\Entity\ProfileInterface $profile
* The profile.
* @param string $label
* The profile label.
*/
public function __construct(ProfileInterface $profile, $label) {
$this->profile = $profile;
$this->label = $label;
}
/**
* Gets the profile.
*
* @return \Drupal\profile\Entity\ProfileInterface
* The profile.
*/
public function getProfile() {
return $this->profile;
}
/**
* Gets the profile label.
*
* @return string
* The profile label.
*/
public function getLabel() {
return $this->label;
}
/**
* Sets the profile label.
*
* @param string $label
* The profile label.
*
* @return $this
*/
public function setLabel($label) {
$this->label = $label;
return $this;
}
}
@@ -84,7 +84,7 @@ class DeleteMultiple extends ConfirmFormBase {
* {@inheritdoc}
*/
public function getConfirmText() {
return t('Delete');
return $this->t('Delete');
}
/**
@@ -93,7 +93,7 @@ class DeleteMultiple extends ConfirmFormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$this->profiles = $this->privateTempStoreFactory->get('profile_multiple_delete_confirm')->get(\Drupal::currentUser()->id());
if (empty($this->profiles)) {
return new RedirectResponse(\Drupal::url('entity.profile.collection', [], ['absolute' => TRUE]));
return new RedirectResponse(Url::fromRoute('entity.profile.collection', [], ['absolute' => TRUE]));
}
$form['profiles'] = [
@@ -13,12 +13,36 @@ class ProfileDeleteForm extends ContentEntityDeleteForm {
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('entity.user.canonical', [
'user' => $this->entity->getOwnerId(),
public function getQuestion() {
return $this->t('Are you sure you want to delete %label?', [
'%label' => $this->getEntity()->label(),
]);
}
/**
* {@inheritdoc}
*/
protected function getDeletionMessage() {
$entity = $this->getEntity();
return $this->t('%label has been deleted.', [
'%label' => $entity->label(),
]);
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
/** @var \Drupal\profile\Entity\ProfileInterface $entity */
$entity = $this->entity;
if ($entity->getOwnerId()) {
return Url::fromRoute('entity.user.canonical', [
'user' => $entity->getOwnerId(),
]);
}
return Url::fromRoute('entity.profile.collection');
}
/**
* {@inheritdoc}
*/
@@ -3,25 +3,14 @@
namespace Drupal\profile\Form;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\RevisionableEntityBundleInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\profile\Entity\ProfileType;
/**
* Form controller for profile forms.
*/
class ProfileForm extends ContentEntityForm {
/**
* {@inheritdoc}
*/
public function buildEntity(array $form, FormStateInterface $form_state) {
$entity = parent::buildEntity($form, $form_state);
if ($entity->isNew()) {
$entity->setCreatedTime(REQUEST_TIME);
}
return $entity;
}
/**
* {@inheritdoc}
*/
@@ -30,12 +19,18 @@ class ProfileForm extends ContentEntityForm {
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
$profile = $this->entity;
// Add an "Activate" button.
$element['set_default'] = $element['submit'];
$element['set_default']['#value'] = t('Save and make default');
$element['set_default']['#weight'] = 10;
$element['set_default']['#access'] = !$profile->isDefault();
array_unshift($element['set_default']['#submit'], [$this, 'setDefault']);
$profile_type_storage = $this->entityTypeManager->getStorage('profile_type');
/** @var \Drupal\profile\Entity\ProfileTypeInterface $profile_type */
$profile_type = $profile_type_storage->load($profile->bundle());
// Allow the profile to be saved as default if type supports multiple.
if ($profile_type->getMultiple() && !$profile->isDefault()) {
// Add a "make default" button.
$element['set_default'] = $element['submit'];
$element['set_default']['#value'] = $this->t('Save and make default');
$element['set_default']['#weight'] = 10;
array_unshift($element['set_default']['#submit'], [$this, 'setDefault']);
}
return $element;
}
@@ -62,28 +57,31 @@ class ProfileForm extends ContentEntityForm {
*/
public function deactivate(array $form, FormStateInterface $form_state) {
$form_state->setValue('status', FALSE);
$form_state->setValue('is_default', TRUE);
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$profile_type = ProfileType::load($this->entity->bundle());
switch ($this->entity->save()) {
case SAVED_NEW:
drupal_set_message($this->t('%label profile has been created.', ['%label' => $profile_type->label()]));
drupal_set_message($this->t('%label has been created.', ['%label' => $this->entity->label()]));
break;
case SAVED_UPDATED:
drupal_set_message($this->t('%label profile has been updated.', ['%label' => $profile_type->label()]));
drupal_set_message($this->t('%label has been updated.', ['%label' => $this->entity->label()]));
break;
}
$form_state->setRedirect('entity.user.canonical', [
'user' => $this->entity->getOwnerId(),
]);
if ($this->entity->getOwnerId()) {
$form_state->setRedirect('entity.user.canonical', [
'user' => $this->entity->getOwnerId(),
]);
}
else {
$form_state->setRedirect('entity.profile.collection');
}
}
}
@@ -48,7 +48,7 @@ class ProfileTypeDeleteForm extends EntityDeleteForm {
->execute();
if ($num_profiles) {
$caption = '<p>' . \Drupal::translation()
->formatPlural($num_profiles, '%type is used by 1 profile on your site. You can not remove this profile type until you have removed all of the %type profiles.', '%type is used by @count profiles on your site. You may not remove %type until you have removed all of the %type profiles.', ['%type' => $this->entity->label()]) . '</p>';
->formatPlural($num_profiles, '%type is used by 1 profile on your site. You can not remove this profile type until you have removed all of the %type profiles.', '%type is used by @count profiles on your site. You may not remove %type until you have removed all of the %type profiles.', ['%type' => $this->entity->label()]) . '</p>';
$form['#title'] = $this->entity->label();
$form['description'] = ['#markup' => $caption];
return $form;
@@ -8,7 +8,6 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\field_ui\FieldUI;
use Drupal\user\Entity\Role;
/**
* Form controller for profile type forms.
*/
@@ -19,6 +18,7 @@ class ProfileTypeForm extends BundleEntityFormBase {
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
/** @var \Drupal\profile\Entity\ProfileTypeInterface $type */
$type = $this->entity;
if ($this->operation == 'add') {
@@ -71,6 +71,12 @@ class ProfileTypeForm extends BundleEntityFormBase {
}
}
$form['use_revisions'] = [
'#type' => 'checkbox',
'#title' => $this->t('Create a new revision when a profile is modified'),
'#default_value' => $type->shouldCreateNewRevision(),
];
return $this->protectBundleIdElement($form);
}
@@ -83,8 +89,8 @@ class ProfileTypeForm extends BundleEntityFormBase {
$this->getEntity()->isNew()
) {
$actions['save_continue'] = $actions['submit'];
$actions['save_continue']['#value'] = t('Save and manage fields');
$actions['save_continue']['#submit'][] = [$this, 'redirectToFieldUI'];
$actions['save_continue']['#value'] = $this->t('Save and manage fields');
$actions['save_continue']['#submit'][] = [$this, 'redirectToFieldUi'];
}
return $actions;
}
@@ -97,10 +103,10 @@ class ProfileTypeForm extends BundleEntityFormBase {
$status = $type->save();
if ($status == SAVED_UPDATED) {
drupal_set_message(t('%label profile type has been updated.', ['%label' => $type->label()]));
drupal_set_message($this->t('%label profile type has been updated.', ['%label' => $type->label()]));
}
else {
drupal_set_message(t('%label profile type has been created.', ['%label' => $type->label()]));
drupal_set_message($this->t('%label profile type has been created.', ['%label' => $type->label()]));
}
$form_state->setRedirect('entity.profile_type.collection');
}
@@ -108,7 +114,7 @@ class ProfileTypeForm extends BundleEntityFormBase {
/**
* Form submission handler to redirect to Manage fields page of Field UI.
*/
public function redirectToFieldUI(array $form, FormStateInterface $form_state) {
public function redirectToFieldUi(array $form, FormStateInterface $form_state) {
if ($form_state->getTriggeringElement()['#parents'][0] === 'save_continue' && $route_info = FieldUI::getOverviewRouteInfo('profile', $this->entity->id())) {
$form_state->setRedirectUrl($route_info);
}
@@ -53,7 +53,7 @@ class ProfileLocalTask extends DeriverBase implements ContainerDeriverInterface
foreach ($this->entityTypeManager->getStorage('profile_type')->loadMultiple() as $profile_type_id => $profile_type) {
$this->derivatives["profile.type.$profile_type_id"] = [
'title' => $profile_type->label(),
'route_name' => "entity.profile.type.$profile_type_id.user_profile_form",
'route_name' => 'entity.profile.type.user_profile_form',
'base_route' => 'entity.user.canonical',
'route_parameters' => ['profile_type' => $profile_type_id],
'weight' => ++$weight,
@@ -26,4 +26,5 @@ class ProfileSelection extends DefaultSelection {
$form['target_bundles']['#title'] = $this->t('Profile types');
return $form;
}
}
@@ -15,7 +15,7 @@ class ProfileBulkForm extends BulkForm {
* {@inheritdoc}
*/
protected function emptySelectedMessage() {
return t('No profile selected.');
return $this->t('No profile selected.');
}
}
@@ -3,10 +3,8 @@
namespace Drupal\profile;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\Entity\User;
use Drupal\entity\EntityAccessControlHandler as EntityApiAccessControlHandler;
use Drupal\profile\Entity\ProfileType;
/**
@@ -14,99 +12,23 @@ use Drupal\profile\Entity\ProfileType;
*
* @see \Drupal\profile\Entity\Profile
*/
class ProfileAccessControlHandler extends EntityAccessControlHandler {
/**
* {@inheritdoc}
*/
public function createAccess($entity_bundle = NULL, AccountInterface $account = NULL, array $context = [], $return_as_object = FALSE) {
$account = $this->prepareUser($account);
if ($account->hasPermission('bypass profile access')) {
$result = AccessResult::allowed()->cachePerPermissions();
return $return_as_object ? $result : $result->isAllowed();
}
$result = parent::createAccess($entity_bundle, $account, $context, TRUE)->cachePerPermissions();
return $return_as_object ? $result : $result->isAllowed();
}
/**
* {@inheritdoc}
*
* When the $operation is 'add' then the $entity is of type 'profile_type',
* otherwise $entity is of type 'profile'.
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
$account = $this->prepareUser($account);
$user_page = \Drupal::request()->attributes->get('user');
// Some times, operation edit is called update.
// Use edit in any case.
if ($operation == 'update') {
$operation = 'edit';
}
// Check that if profile type has require roles, the user the profile is
// being added to has any of the required roles.
if ($entity->getEntityTypeId() == 'profile') {
$profile_roles = ProfileType::load($entity->bundle())->getRoles();
// Retrieve all user roles including locked roles.
$user_roles = $entity->getOwner()->getRoles();
if (!empty(array_filter($profile_roles)) && !array_intersect($user_roles, $profile_roles)) {
return AccessResult::forbidden();
}
}
elseif ($entity->getEntityTypeId() == 'profile_type') {
$profile_roles = $entity->getRoles();
// Retrieve all user roles including locked roles.
$user_roles = User::load($user_page->id())->getRoles();
if (!empty(array_filter($profile_roles)) && !array_intersect($user_roles, $profile_roles)) {
return AccessResult::forbidden();
}
}
if ($account->hasPermission('bypass profile access')) {
return AccessResult::allowed()->cachePerPermissions();
}
elseif (
(
$operation == 'add'
&& (
(
$user_page->id() == $account->id()
&& $account->hasPermission($operation . ' own ' . $entity->id() . ' profile')
)
|| $account->hasPermission($operation . ' any ' . $entity->id() . ' profile')
)
) || (
$operation != 'add'
&& (
(
$entity->getOwnerId() == $account->id()
&& $account->hasPermission($operation . ' own ' . $entity->getType() . ' profile')
)
|| $account->hasPermission($operation . ' any ' . $entity->getType() . ' profile')
)
)
){
return AccessResult::allowed()->cachePerPermissions();
}
else {
// No opinion.
return AccessResult::neutral()->cachePerPermissions();
}
}
class ProfileAccessControlHandler extends EntityApiAccessControlHandler {
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
return AccessResult::allowedIfHasPermissions($account, [
'add any ' . $entity_bundle . ' profile',
'add own ' . $entity_bundle . ' profile',
], 'OR');
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
// If access is allowed, check role restriction.
if ($result->isAllowed()) {
$bundle = ProfileType::load($entity_bundle);
if (!empty(array_filter($bundle->getRoles()))) {
$result = AccessResult::allowedIf(!empty(array_intersect($account->getRoles(), $bundle->getRoles())));
}
}
return $result;
}
}
@@ -1,59 +0,0 @@
<?php
namespace Drupal\profile;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
use Drupal\profile\Entity\ProfileType;
use Symfony\Component\Routing\Route;
/**
* Provides HTML routes for the profile entity type.
*/
class ProfileHtmlRouteProvider extends DefaultHtmlRouteProvider {
/**
* {@inheritdoc}
*/
public function getRoutes(EntityTypeInterface $entity_type) {
$collection = parent::getRoutes($entity_type);
/** @var \Drupal\profile\Entity\ProfileTypeInterface $profile_type */
foreach (ProfileType::loadMultiple() as $profile_type) {
$route = (new Route(
"/user/{user}/{profile_type}",
['_controller' => '\Drupal\profile\Controller\ProfileController::userProfileForm',
'_title_callback' => '\Drupal\profile\Controller\ProfileController::addPageTitle'
],
['_profile_access_check' => 'add'],
[
'parameters' => [
'user' => ['type' => 'entity:user'],
'profile_type' => ['type' => 'entity:profile_type'],
],
])
);
$collection->add("entity.profile.type.{$profile_type->id()}.user_profile_form", $route);
// If the profile type supports multiple, we need an additional route for
// adding new profiles.
if ($profile_type->getMultiple()) {
$route = (new Route(
"/user/{user}/{profile_type}/add",
['_controller' => '\Drupal\profile\Controller\ProfileController::addProfile'],
['_profile_access_check' => 'add'],
[
'parameters' => [
'user' => ['type' => 'entity:user'],
'profile_type' => ['type' => 'entity:profile_type'],
],
])
);
$collection->add("entity.profile.type.{$profile_type->id()}.user_profile_form.add", $route);
}
}
return $collection;
}
}
@@ -104,7 +104,7 @@ class ProfileListBuilder extends EntityListBuilder {
$options += ($langcode != LanguageInterface::LANGCODE_NOT_SPECIFIED && isset($languages[$langcode]) ? ['language' => $languages[$langcode]] : []);
$uri->setOptions($options);
$row['label'] = $entity->toLink();
$row['type'] = $entity->getType();
$row['type'] = $entity->bundle();
$row['owner']['data'] = [
'#theme' => 'username',
'#account' => $entity->getOwner(),
@@ -126,7 +126,7 @@ class ProfileListBuilder extends EntityListBuilder {
public function getOperations(EntityInterface $entity) {
$operations = parent::getOperations($entity);
if (!$entity->isDefault()) {
if ($entity->isActive() && !$entity->isDefault()) {
$operations['set_default'] = [
'title' => $this->t('Mark as default'),
'url' => $entity->toUrl('set-default'),
@@ -0,0 +1,43 @@
<?php
namespace Drupal\profile;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\entity\EntityPermissionProvider;
/**
* Providers Profile entity permissions.
*
* Extends the Entity API permission provider to support bundle based view
* permissions.
*/
class ProfilePermissionProvider extends EntityPermissionProvider {
/**
* {@inheritdoc}
*/
protected function buildBundlePermissions(EntityTypeInterface $entity_type) {
$permissions = parent::buildBundlePermissions($entity_type);
$singular_label = $entity_type->getSingularLabel();
$entity_type_id = $entity_type->id();
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
foreach ($bundles as $bundle_name => $bundle_info) {
$permissions["view any {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: View any @type', [
'@bundle' => $bundle_info['label'],
'@type' => $singular_label,
]),
];
$permissions["view own {$bundle_name} {$entity_type_id}"] = [
'title' => $this->t('@bundle: View own @type', [
'@bundle' => $bundle_info['label'],
'@type' => $singular_label,
]),
];
}
return $permissions;
}
}
@@ -1,72 +0,0 @@
<?php
namespace Drupal\profile;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\profile\Entity\ProfileType;
/**
* Defines a class containing permission callbacks.
*/
class ProfilePermissions {
use StringTranslationTrait;
/**
* Returns an array of profile type permissions.
*
* @return array
* Returns an array of permissions.
*/
public function profileTypePermissions() {
$perms = [];
// Generate profile permissions for all profile types.
foreach (ProfileType::loadMultiple() as $type) {
$perms += $this->buildPermissions($type);
}
return $perms;
}
/**
* Builds a standard list of permissions for a given profile type.
*
* @param \Drupal\profile\Entity\ProfileType $profile_type
* The machine name of the profile type.
*
* @return array
* An array of permission names and descriptions.
*/
protected function buildPermissions(ProfileType $profile_type) {
$type_id = $profile_type->id();
$type_params = ['%type' => $profile_type->label()];
return [
"add own $type_id profile" => [
'title' => $this->t('%type: Add own profile', $type_params),
],
"add any $type_id profile" => [
'title' => $this->t('%type: Add any profile', $type_params),
],
"view own $type_id profile" => [
'title' => $this->t('%type: View own profile', $type_params),
],
"view any $type_id profile" => [
'title' => $this->t('%type: View any profile', $type_params),
],
"edit own $type_id profile" => [
'title' => $this->t('%type: Edit own profile', $type_params),
],
"edit any $type_id profile" => [
'title' => $this->t('%type: Edit any profile', $type_params),
],
"delete own $type_id profile" => [
'title' => $this->t('%type: Delete own profile', $type_params),
],
"delete any $type_id profile" => [
'title' => $this->t('%type: Delete any profile', $type_params),
],
];
}
}
@@ -13,7 +13,7 @@ class ProfileStorage extends SqlContentEntityStorage implements ProfileStorageIn
/**
* {@inheritdoc}
*/
public function loadByUser(AccountInterface $account, $profile_type, $active = PROFILE_ACTIVE) {
public function loadByUser(AccountInterface $account, $profile_type, $active = TRUE) {
$result = $this->loadByProperties([
'uid' => $account->id(),
'type' => $profile_type,
@@ -26,12 +26,12 @@ class ProfileStorage extends SqlContentEntityStorage implements ProfileStorageIn
/**
* {@inheritdoc}
*/
public function loadMultipleByUser(AccountInterface $account, $profile_type, $active = PROFILE_ACTIVE) {
public function loadMultipleByUser(AccountInterface $account, $profile_type, $active = TRUE) {
return $this->loadByProperties([
'uid' => $account->id(),
'type' => $profile_type,
'status' => $active,
]);
'uid' => $account->id(),
'type' => $profile_type,
'status' => $active,
]);
}
/**
@@ -41,7 +41,7 @@ class ProfileStorage extends SqlContentEntityStorage implements ProfileStorageIn
$result = $this->loadByProperties([
'uid' => $account->id(),
'type' => $profile_type,
'status' => PROFILE_ACTIVE,
'status' => TRUE,
'is_default' => TRUE,
]);
@@ -21,7 +21,7 @@ trait ProfileTestTrait {
* The profile type machine name.
* @param string $label
* The profile type human display name.
* @param bool|FALSE $registration
* @param bool $registration
* Boolean if profile type shows on registration form.
* @param array $roles
* Array of user role machine names.
@@ -29,7 +29,7 @@ trait ProfileTestTrait {
* @return \Drupal\profile\Entity\ProfileTypeInterface
* Returns a profile type entity.
*/
protected function createProfileType($id = NULL, $label = NULL, $registration = FALSE, $roles = []) {
protected function createProfileType($id = NULL, $label = NULL, $registration = FALSE, array $roles = []) {
$id = !empty($id) ? $id : $this->randomMachineName();
$label = !empty($label) ? $label : $this->randomMachineName();
@@ -14,9 +14,9 @@ class ProfileTypeListBuilder extends ConfigEntityListBuilder {
* {@inheritdoc}
*/
public function buildHeader() {
$header['type'] = t('Profile type');
$header['registration'] = t('Registration');
$header['multiple'] = t('Allow multiple profiles');
$header['type'] = $this->t('Profile type');
$header['registration'] = $this->t('Registration');
$header['multiple'] = $this->t('Allow multiple profiles');
return $header + parent::buildHeader();
}
@@ -25,8 +25,8 @@ class ProfileTypeListBuilder extends ConfigEntityListBuilder {
*/
public function buildRow(EntityInterface $entity) {
$row['type'] = $entity->toLink(NULL, 'edit-form');
$row['registration'] = $entity->getRegistration() ? t('Yes') : t('No');
$row['multiple'] = $entity->getMultiple() ? t('Yes') : t('No');
$row['registration'] = $entity->getRegistration() ? $this->t('Yes') : $this->t('No');
$row['multiple'] = $entity->getMultiple() ? $this->t('Yes') : $this->t('No');
return $row + parent::buildRow($entity);
}
@@ -39,14 +39,14 @@ class ProfileTypeListBuilder extends ConfigEntityListBuilder {
// which have the weights 15, 20, 25.
if (isset($operations['edit'])) {
$operations['edit'] = [
'title' => t('Edit'),
'title' => $this->t('Edit'),
'weight' => 30,
'url' => $entity->toUrl('edit-form'),
];
}
if (isset($operations['delete'])) {
$operations['delete'] = [
'title' => t('Delete'),
'title' => $this->t('Delete'),
'weight' => 35,
'url' => $entity->toUrl('delete-form'),
];
@@ -14,10 +14,10 @@ class ProfileViewsData extends EntityViewsData {
*/
public function getViewsData() {
$data = parent::getViewsData();
$data['profile']['type']['title'] = t('Profile type');
$data['profile']['profile_bulk_form'] = [
'title' => t('Profile operations bulk form'),
'help' => t('Add a form element that lets you run operations on multiple profiles.'),
'title' => $this->t('Profile operations bulk form'),
'help' => $this->t('Add a form element that lets you run operations on multiple profiles.'),
'field' => [
'id' => 'profile_bulk_form',
],
@@ -1,411 +0,0 @@
<?php
namespace Drupal\profile\Tests;
use Drupal\profile\Entity\Profile;
use Drupal\user\Entity\User;
/**
* Tests basic CRUD functionality of profiles.
*
* @group profile
*/
class ProfileDefaultTest extends ProfileTestBase {
/**
* Testing demo user 1.
*
* @var \Drupal\user\UserInterface
*/
public $user1;
/**
* Testing demo user 2.
*
* @var \Drupal\user\UserInterface;
*/
public $user2;
/**
* Profile entity storage.
*
* @var \Drupal\profile\ProfileStorageInterface
*/
public $profileStorage;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser([
'access user profiles',
'administer profiles',
'administer profile types',
'bypass profile access',
'access administration pages',
]);
$this->user1 = User::create([
'name' => $this->randomMachineName(),
'mail' => $this->randomMachineName() . '@example.com',
]);
$this->user1->save();
$this->user2 = User::create([
'name' => $this->randomMachineName(),
'mail' => $this->randomMachineName() . '@example.com',
]);
$this->user2->save();
}
/**
* Tests profiles are active by default.
*/
public function testProfileActive() {
$profile_type = $this->createProfileType('test_defaults', 'test_defaults');
// Create new profiles.
$profile1 = Profile::create($expected = [
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
$this->assertTrue($profile1->isActive());
$profile1->setActive(PROFILE_NOT_ACTIVE);
$profile1->save();
$this->assertFalse($profile1->isActive());
}
/**
* Tests default profile functionality.
*/
public function testDefaultProfile() {
$profile_type = $this->createProfileType('test_defaults', 'test_defaults');
// Create new profiles.
$profile1 = Profile::create($expected = [
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
$profile2 = Profile::create($expected = [
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile2->setDefault(TRUE);
$profile2->save();
$this->assertFalse($profile1->isDefault());
$this->assertTrue($profile2->isDefault());
$profile1->setDefault(TRUE)->save();
$this->assertFalse(Profile::load($profile2->id())->isDefault());
$this->assertTrue(Profile::load($profile1->id())->isDefault());
}
/**
* Tests loading default from storage handler.
*/
public function testLoadDefaultProfile() {
$profile_type = $this->createProfileType('test_defaults', 'test_defaults');
// Create new profiles.
$profile1 = Profile::create($expected = [
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->setActive(TRUE);
$profile1->save();
$profile2 = Profile::create($expected = [
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile2->setActive(TRUE);
$profile2->setDefault(TRUE);
$profile2->save();
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = \Drupal::entityTypeManager()->getStorage('profile');
$default_profile = $storage->loadDefaultByUser($this->user1, $profile_type->id());
$this->assertEqual($profile2->id(), $default_profile->id());
}
/**
* Tests mark as default action.
*/
public function testDefaultAction() {
$types_data = [
'profile_type_0' => [
'label' => $this->randomMachineName(),
'multiple' => TRUE,
],
'profile_type_1' => [
'label' => $this->randomMachineName(),
'multiple' => TRUE,
],
];
/** @var ProfileType[] $types */
$types = [];
foreach ($types_data as $id => $values) {
$types[$id] = $this->createProfileType($id, $values['label']);
}
$restricted_user = $this->drupalCreateUser([
'administer profiles',
'edit own ' . $types['profile_type_0']->id() . ' profile',
'edit own ' . $types['profile_type_1']->id() . ' profile',
]);
$admin_user = $this->drupalCreateUser([
'administer profiles',
'edit any ' . $types['profile_type_0']->id() . ' profile',
'edit any ' . $types['profile_type_1']->id() . ' profile',
]);
// Create new profiles.
$profile_profile_type_0_restricted_user = Profile::create($expected = [
'type' => $types['profile_type_0']->id(),
'uid' => $restricted_user->id(),
]);
$profile_profile_type_0_restricted_user->setActive(TRUE);
$profile_profile_type_0_restricted_user->save();
$profile_profile_type_0_user1_1 = Profile::create($expected = [
'type' => $types['profile_type_0']->id(),
'uid' => $this->user1->id(),
]);
$profile_profile_type_0_user1_1->setActive(TRUE);
$profile_profile_type_0_user1_1->save();
$profile_profile_type_0_user1_2 = Profile::create($expected = [
'type' => $types['profile_type_0']->id(),
'uid' => $this->user1->id(),
]);
$profile_profile_type_0_user1_2->setActive(TRUE);
$profile_profile_type_0_user1_2->save();
$profile_profile_type_1_user1 = Profile::create($expected = [
'type' => $types['profile_type_1']->id(),
'uid' => $this->user1->id(),
]);
$profile_profile_type_1_user1->setActive(TRUE);
$profile_profile_type_1_user1->save();
$profile_profile_type_1_user2 = Profile::create($expected = [
'type' => $types['profile_type_1']->id(),
'uid' => $this->user2->id(),
]);
$profile_profile_type_1_user2->setActive(TRUE);
$profile_profile_type_1_user2->save();
$profile_profile_type_1_user1_inactive = Profile::create($expected = [
'type' => $types['profile_type_1']->id(),
'uid' => $this->user1->id(),
]);
$profile_profile_type_1_user1_inactive->setActive(FALSE);
$profile_profile_type_1_user1_inactive->save();
$profile_profile_type_1_user1_active = Profile::create($expected = [
'type' => $types['profile_type_1']->id(),
'uid' => $this->user1->id(),
]);
$profile_profile_type_1_user1_active->isActive(TRUE);
$profile_profile_type_1_user1_active->save();
// Make sure that $restricted_user is allowed to set default his own profile
// and not others'.
$this->drupalLogin($restricted_user);
$this->drupalGet('admin/config/people/profiles');
$this->clickLink('Mark as default', 0);
$this->assertTrue(Profile::load($profile_profile_type_0_restricted_user->id())->isDefault());
$this->clickLink('Mark as default', 1);
$this->assertResponse(403);
$this->drupalLogout();
$this->drupalLogin($admin_user);
$this->drupalGet('admin/config/people/profiles');
// Mark $profile_profile_type_0_user1_1 as default
// $profile_profile_type_0_user1_2 should stay not default.
$this->clickLink('Mark as default', 0);
$this->assertTrue(Profile::load($profile_profile_type_0_user1_1->id())->isDefault());
$this->assertFalse($profile_profile_type_0_user1_2->isDefault());
// Mark $profile_profile_type_0_user1_2 as default
// $profile_profile_type_0_user1_1 should become not default.
$profile_profile_type_0_user1_2->setDefault(TRUE);
$profile_profile_type_0_user1_2->save();
$this->assertTrue($profile_profile_type_0_user1_2->isDefault());
$this->assertFalse($profile_profile_type_0_user1_1->isDefault());
// Mark $profile_profile_type_1_user1 as default
// $profile_profile_type_1_user2 should stay not default.
$this->clickLink('Mark as default', 1);
$this->assertTrue(Profile::load($profile_profile_type_1_user1->id())->isDefault());
$this->assertFalse($profile_profile_type_1_user2->isDefault());
// Mark $profile_profile_type_1_user2 as default
// $profile_profile_type_1_user1 should stay default.
$profile_profile_type_1_user2->setDefault(TRUE);
$profile_profile_type_1_user2->save();
$this->assertTrue($profile_profile_type_1_user2->isDefault());
$this->assertTrue(Profile::load($profile_profile_type_1_user1->id())->isDefault());
// Mark $profile_profile_type_1_user1_inactive as default
// $profile_profile_type_1_user1_active should stay not default.
$this->clickLink('Mark as default', 2);
$this->assertTrue(Profile::load($profile_profile_type_1_user1_inactive->id())->isDefault());
$this->assertFalse($profile_profile_type_1_user1_active->isDefault());
// Mark $profile_profile_type_1_user1_active as default
// $profile_profile_type_1_user1_inactive should stay default.
$profile_profile_type_1_user1_active->setDefault(TRUE);
$profile_profile_type_1_user1_active->save();
$this->assertTrue($profile_profile_type_1_user1_active->isDefault());
$this->assertTrue(Profile::load($profile_profile_type_1_user1_inactive->id())->isDefault());
}
/**
* Tests whether profile default on edit is working.
*/
public function testProfileEdit() {
$types_data = [
'profile_type_0' => [
'label' => $this->randomMachineName(),
'multiple' => TRUE,
],
];
/** @var \Drupal\profile\Entity\ProfileTypeInterface[] $types */
$types = [];
foreach ($types_data as $id => $values) {
$types[$id] = $this->createProfileType($id, $values['label']);
}
$admin_user = $this->drupalCreateUser([
'administer profiles',
'administer users',
'edit any ' . $types['profile_type_0']->id() . ' profile',
]);
// Create new profiles.
$profile1 = Profile::create($expected = [
'type' => $types['profile_type_0']->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
$profile2 = Profile::create($expected = [
'type' => $types['profile_type_0']->id(),
'uid' => $this->user1->id(),
]);
$profile2->setDefault(TRUE);
$profile2->save();
$this->assertFalse($profile1->isDefault());
$this->assertTrue($profile2->isDefault());
$this->drupalLogin($admin_user);
$this->drupalPostForm("profile/{$profile1->id()}/edit", [], 'Save and make default');
\Drupal::entityTypeManager()->getStorage('profile')->resetCache([$profile1->id(), $profile2->id()]);
$this->assertTrue(Profile::load($profile1->id())->isDefault());
$this->assertFalse(Profile::load($profile2->id())->isDefault());
}
/**
* Tests administrative-only profiles.
*/
public function testAdminOnlyProfiles() {
$id = $this->type->id();
$field_name = $this->field->getName();
// Create a test user account.
$web_user = $this->drupalCreateUser(['access user profiles']);
$uid = $web_user->id();
$value = $this->randomMachineName();
// Administratively enter profile field values for the new account.
$this->drupalLogin($this->adminUser);
$edit = [
"{$this->field->getName()}[0][value]" => $value,
];
$this->drupalPostForm("user/$uid/$id", $edit, 'Save and make default');
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
$profile = \Drupal::entityTypeManager()
->getStorage('profile')
->loadByUser($web_user, $this->type->id());
$profile_id = $profile->id();
$this->assertEqual($profile->getType(), $this->type->id());
/*
// Verify that the administrator can see the profile.
$this->drupalGet("user/$uid");
$this->assertText($this->type->label());
$this->assertText($value);
$this->drupalLogout();
// Verify that the user can not access, create or edit the profile.
$this->drupalLogin($web_user);
$this->drupalGet("user/$uid");
$this->assertNoText($this->type->label());
$this->assertNoText($value);
$this->drupalGet("user/$uid/edit/profile/$id/$profile_id");
$this->assertResponse(403);
// Check edit link isn't displayed.
$this->assertNoLinkByHref("user/$uid/edit/profile/$id/$profile_id");
// Check delete link isn't displayed.
$this->assertNoLinkByHref("user/$uid/delete/profile/$id/$profile_id");
// Allow users to edit own profiles.
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ["edit own $id profile"]);
// Verify that the user is able to edit the own profile.
$value = $this->randomMachineName();
$edit = [
"{$field_name}[0][value]" => $value,
];
$this->drupalPostForm("user/$uid/edit/profile/$id/$profile_id", $edit, t('Save'));
$this->assertText(new FormattableMarkup('profile has been updated.', []));
// Verify that the own profile is still not visible on the account page.
$this->drupalGet("user/$uid");
$this->assertNoText($this->type->label());
$this->assertNoText($value);
// Allow users to view own profiles.
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ["view own $id profile"]);
// Verify that the own profile is visible on the account page.
$this->drupalGet("user/$uid");
$this->assertText($this->type->label());
$this->assertText($value);
// Allow users to delete own profiles.
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ["delete own $id profile"]);
// Verify that the user can delete the own profile.
$this->drupalGet("user/$uid/edit/profile/$id/$profile_id");
$this->clickLink(t('Delete'));
$this->drupalPostForm(NULL, [], t('Delete'));
$this->assertRaw(new FormattableMarkup('@label profile deleted.', ['@label' => $this->type->label()]));
$this->assertUrl("user/$uid");
// Verify that the profile is gone.
$this->drupalGet("user/$uid");
$this->assertNoText($this->type->label());
$this->assertNoText($value);
$this->drupalGet("user/$uid/edit/profile/$id");
$this->assertNoText($value);
*/
}
}
@@ -1,91 +0,0 @@
<?php
namespace Drupal\profile\Tests;
use Drupal\Core\Cache\Cache;
/**
* Tests profile field access functionality.
*
* @group profile
*/
class ProfileFieldAccessTest extends ProfileTestBase {
private $webUser;
private $otherUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser([
'access user profiles',
'administer profile types',
'administer profile fields',
'administer profile display',
'bypass profile access',
]);
$user_permissions = [
'access user profiles',
"add own {$this->type->id()} profile",
"edit own {$this->type->id()} profile",
"view own {$this->type->id()} profile",
];
$this->webUser = $this->drupalCreateUser($user_permissions);
$this->otherUser = $this->drupalCreateUser($user_permissions);
}
/**
* Tests private profile field access.
*/
public function testPrivateField() {
$this->drupalLogin($this->adminUser);
// Create a private profile field.
$edit = [
'new_storage_type' => 'string',
'label' => 'Secret',
'field_name' => 'secret',
];
$this->drupalPostForm("admin/config/people/profiles/types/manage/{$this->type->id()}/fields/add-field", $edit, t('Save and continue'));
$this->drupalPostForm(NULL, [], t('Save field settings'));
$edit = [
'profile_private' => 1,
];
$this->drupalPostForm(NULL, $edit, t('Save settings'));
// Fill in a field value.
$this->drupalLogin($this->webUser);
$uid = $this->webUser->id();
$secret = $this->randomMachineName();
$edit = [
'field_secret[0][value]' => $secret,
];
$this->drupalPostForm("user/$uid/{$this->type->id()}", $edit, t('Save'));
// User cache page need to be cleared to see new profile.
Cache::invalidateTags([
'user:' . $uid,
'user_view',
]);
// Verify that the private field value appears for the profile owner.
$this->drupalGet("user/$uid");
$this->assertText($secret);
// Verify that the private field value appears for the administrator.
$this->drupalLogin($this->adminUser);
$this->drupalGet("user/$uid");
$this->assertText($secret);
// Verify that the private field value does not appear for other users.
$this->drupalLogin($this->otherUser);
$this->drupalGet("user/$uid");
$this->assertNoText($secret);
}
}
@@ -1,165 +0,0 @@
<?php
namespace Drupal\profile\Tests;
use Drupal\Core\Session\AccountInterface;
/**
* Tests profile role access handling.
*
* @group profile
*/
class ProfileRoleAccessTest extends ProfileTestBase {
/**
* Randomly generated profile type entity.
*
* Requires some, but not all roles.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type2;
/**
* Randomly generated profile type entity.
*
* Requires all profile roles.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type3;
/**
* Randomly generated user role entity.
*
* @var \Drupal\user\Entity\Role
*/
protected $role1;
/**
* Randomly generated user role entity.
*
* @var \Drupal\user\Entity\Role
*/
protected $role2;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->role1 = $this->drupalCreateRole([]);
$this->role2 = $this->drupalCreateRole([]);
$this->type2 = $this->createProfileType(NULL, NULL, FALSE, [$this->role2]);
$this->type3 = $this->createProfileType(NULL, NULL, FALSE, [$this->role1, $this->role2]);
}
/**
* Tests add profile form access for a profile type that does not require
* users to have a role.
*/
public function testProfileWithNoRoles() {
// Create user with add own profile permissions.
$web_user1 = $this->drupalCreateUser(["add own {$this->type->id()} profile"]);
$this->drupalLogin($web_user1);
// Test user without role can access add profile form.
// Expected: User can access form.
$this->drupalGet("user/{$web_user1->id()}/{$this->type->id()}");
$this->assertResponse(200);
}
public function testLockedRoles() {
$locked_role_type = $this->createProfileType(NULL, NULL, FALSE, [AccountInterface::AUTHENTICATED_ROLE]);
// Create user with add own profile permissions.
$web_user1 = $this->drupalCreateUser(["add own {$locked_role_type->id()} profile"]);
$this->drupalLogin($web_user1);
// Test user without role can access add profile form.
// Expected: User can access form.
$this->drupalGet("user/{$web_user1->id()}/{$locked_role_type->id()}");
$this->assertResponse(200);
}
/**
* Tests add profile form access for a profile type that requires users to
* have a single role.
*/
public function testProfileWithSingleRole() {
// Create user with add own profile permissions.
$web_user1 = $this->drupalCreateUser(["add own {$this->type2->id()} profile"]);
$this->drupalLogin($web_user1);
// Test user without role can access add profile form.
// Expected: User cannot access form.
$this->drupalGet("user/{$web_user1->id()}/{$this->type2->id()}");
$this->assertResponse(403);
// Test user with wrong role can access add profile form.
// Expected: User cannot access form.
$web_user1->addRole($this->role1);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type2->id()}");
$this->assertResponse(403);
// Test user with correct role can access add profile form.
// Expected: User can access form.
$web_user1->removeRole($this->role1);
$web_user1->addRole($this->role2);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type2->id()}");
$this->assertResponse(200);
}
/**
* Tests add profile form access for a profile type that requires users to
* have one of multiple roles.
*/
public function testProfileWithAllRoles() {
// Create user with add own profile permissions.
$web_user1 = $this->drupalCreateUser(["add own {$this->type3->id()} profile"]);
$this->drupalLogin($web_user1);
// Test user without role can access add profile form.
// Expected: User cannot access form.
$this->drupalGet("user/{$web_user1->id()}/{$this->type3->id()}");
$this->assertResponse(403);
// Test user with role 1 can access add profile form.
// Expected: User can access form.
$web_user1->addRole($this->role1);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type3->id()}");
$this->assertResponse(200);
// Test user with both roles can access add profile form.
// Expected: User can access form.
$web_user1->addRole($this->role2);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type3->id()}");
$this->assertResponse(200);
// Test user with role 2 can access add profile form.
// Expected: User can access form.
$web_user1->removeRole($this->role1);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type3->id()}");
$this->assertResponse(200);
// Test user without role can access add profile form.
// Expected: User cannot access form.
$web_user1->removeRole($this->role2);
$web_user1->save();
$this->drupalGet("user/{$web_user1->id()}/{$this->type3->id()}");
$this->assertResponse(403);
}
}
@@ -1,139 +0,0 @@
<?php
namespace Drupal\profile\Tests;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Session\AccountInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\profile\ProfileTestTrait;
use Drupal\simpletest\WebTestBase;
/**
* Tests profile access handling.
*/
abstract class ProfileTestBase extends WebTestBase {
use ProfileTestTrait;
public static $modules = ['profile', 'field_ui', 'text', 'block'];
/**
* Testing profile type entity.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type;
/**
* Testing profile type entity view display.
*
* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
*/
protected $display;
/**
* Testing profile type entity form display.
*
* @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form
*/
protected $form;
/**
* Testing field on profile type.
*
* @var \Drupal\Core\Field\FieldConfigInterface
*/
protected $field;
/**
* Testing admin user.
*
* @var \Drupal\user\Entity\User
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('local_actions_block');
$this->drupalPlaceBlock('page_title_block');
$this->type = $this->createProfileType('test', 'Test profile', TRUE);
$id = $this->type->id();
$field_storage = FieldStorageConfig::create([
'field_name' => 'profile_fullname',
'entity_type' => 'profile',
'type' => 'text',
]);
$field_storage->save();
$this->field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $this->type->id(),
'label' => 'Full name',
]);
$this->field->save();
// Configure the default display.
$this->display = EntityViewDisplay::load("profile.{$this->type->id()}.default");
if (!$this->display) {
$this->display = EntityViewDisplay::create([
'targetEntityType' => 'profile',
'bundle' => $this->type->id(),
'mode' => 'default',
'status' => TRUE,
]);
$this->display->save();
}
$this->display
->setComponent($this->field->getName(), ['type' => 'string'])
->save();
// Configure rhe default form.
$this->form = EntityFormDisplay::load("profile.{$this->type->id()}.default");
if (!$this->form) {
$this->form = EntityFormDisplay::create([
'targetEntityType' => 'profile',
'bundle' => $this->type->id(),
'mode' => 'default',
'status' => TRUE,
]);
$this->form->save();
}
$this->form
->setComponent($this->field->getName(), [
'type' => 'string_textfield',
])->save();
$this->checkPermissions([
'administer profile types',
"view own $id profile",
"view any $id profile",
"add own $id profile",
"add any $id profile",
"edit own $id profile",
"edit any $id profile",
"delete own $id profile",
"delete any $id profile",
]);
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ['access user profiles']);
$this->adminUser = $this->drupalCreateUser([
'administer profile types',
'administer profiles',
"view any $id profile",
"add any $id profile",
"edit any $id profile",
"delete any $id profile",
]);
}
}
@@ -1,95 +0,0 @@
<?php
namespace Drupal\profile\Tests;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Cache\Cache;
/**
* Tests multiple enabled profile types.
*
* @group profile
*/
class ProfileTypeMultipleTest extends ProfileTestBase {
/**
* Tests the flow of a profile type that has multiple enabled.
*/
public function testMultipleProfileType() {
$this->drupalLogin($this->adminUser);
$edit = [
'multiple' => 1,
];
$this->drupalPostForm("admin/config/people/profiles/types/manage/{$this->type->id()}", $edit, t('Save'));
$this->assertRaw(new FormattableMarkup('%type profile type has been updated.', [
'%type' => $this->type->label(),
]));
$web_user1 = $this->drupalCreateUser(
[
"view own {$this->type->id()} profile",
"add own {$this->type->id()} profile",
"edit own {$this->type->id()} profile",
]
);
$this->drupalLogin($web_user1);
$value = $this->randomMachineName();
$edit = [
"{$this->field->getName()}[0][value]" => $value,
];
$this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}", $edit, t('Save'));
$this->assertRaw(new FormattableMarkup('%type profile has been created.', [
'%type' => $this->type->label(),
]));
$this->drupalGet("user/{$web_user1->id()}/{$this->type->id()}");
$this->assertLinkByHref("user/{$web_user1->id()}/{$this->type->id()}/add");
$this->assertText($value);
$value2 = $this->randomMachineName();
$edit = [
"{$this->field->getName()}[0][value]" => $value2,
];
$this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}/add", $edit, t('Save'));
$this->assertRaw(new FormattableMarkup('%type profile has been created.', [
'%type' => $this->type->label(),
]));
Cache::invalidateTags(['profile_view']);
$this->drupalGet("user/{$web_user1->id()}/{$this->type->id()}");
$this->assertText($value2);
}
/**
* Tests the non-multiple profile type create and edit flow.
*/
public function testProfileNotMultipleFlow() {
$web_user1 = $this->createUser([
"add own {$this->type->id()} profile",
"edit own {$this->type->id()} profile",
]);
$this->drupalLogin($web_user1);
// Create the profile.
$edit = [
"{$this->field->getName()}[0][value]" => $this->randomString(),
];
$this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}", $edit, 'Save and make default');
$this->assertRaw(new FormattableMarkup('%type profile has been created.', [
'%type' => $this->type->label(),
]));
// Update the profile.
$edit = [
"{$this->field->getName()}[0][value]" => $this->randomString(),
];
$this->drupalPostForm("user/{$web_user1->id()}/{$this->type->id()}", $edit, t('Save'));
$this->assertRaw(new FormattableMarkup('%type profile has been updated.', [
'%type' => $this->type->label(),
]));
}
}
@@ -5,8 +5,8 @@ description: 'Test module for Profile.'
dependencies:
- profile
# Information added by Drupal.org packaging script on 2016-08-31
version: '8.x-1.0-alpha5+4-dev'
# Information added by Drupal.org packaging script on 2017-06-12
version: '8.x-1.0-beta1'
core: '8.x'
project: 'profile'
datestamp: 1472611474
datestamp: 1497287652
@@ -0,0 +1,148 @@
<?php
namespace Drupal\Tests\profile\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
use Drupal\profile\Entity\Profile;
use Drupal\profile\Entity\ProfileType;
use Drupal\user\Entity\User;
/**
* Tests "default" functionality via the UI.
*
* @group profile
*/
class ProfileDefaultTest extends ProfileTestBase {
/**
* Testing demo user 1.
*
* @var \Drupal\user\UserInterface
*/
public $user1;
/**
* Testing demo user 2.
*
* @var \Drupal\user\UserInterface
*/
public $user2;
/**
* Profile entity storage.
*
* @var \Drupal\profile\ProfileStorageInterface
*/
public $profileStorage;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser([
'access user profiles',
'administer profile',
'administer profile types',
'access administration pages',
]);
$this->user1 = User::create([
'name' => $this->randomMachineName(),
'mail' => $this->randomMachineName() . '@example.com',
]);
$this->user1->save();
$this->user2 = User::create([
'name' => $this->randomMachineName(),
'mail' => $this->randomMachineName() . '@example.com',
]);
$this->user2->save();
}
/**
* Tests whether profile default on edit is working.
*/
public function testProfileEdit() {
$type = ProfileType::create([
'id' => $this->randomMachineName(),
'label' => $this->randomMachineName(),
'registration' => FALSE,
'roles' => [],
'multiple' => TRUE,
]);
$type->save();
$admin_user = $this->drupalCreateUser([
'administer profile',
'administer users',
]);
// Create new profiles.
$profile1 = Profile::create([
'type' => $type->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
$profile2 = Profile::create([
'type' => $type->id(),
'uid' => $this->user1->id(),
]);
$profile2->save();
// Verify that the first profile of this type is default.
$this->assertTrue($profile1->isDefault());
$this->assertFalse($profile2->isDefault());
$this->drupalLogin($admin_user);
$this->drupalGet($profile1->toUrl('edit-form')->toString());
$this->assertSession()->buttonNotExists('Save and make default');
$this->assertSession()->buttonExists('Save');
$this->drupalGet($profile2->toUrl('edit-form')->toString());
$this->assertSession()->buttonExists('Save');
$this->assertSession()->buttonExists('Save and make default');
$this->submitForm([], 'Save and make default');
\Drupal::entityTypeManager()->getStorage('profile')->resetCache([$profile1->id(), $profile2->id()]);
$this->assertFalse(Profile::load($profile1->id())->isDefault());
$this->assertTrue(Profile::load($profile2->id())->isDefault());
}
/**
* Tests the entity.profile.set_default route.
*/
public function testSetDefaultRoute() {
$this->type->setMultiple(TRUE)->save();
$id = $this->type->id();
$test_user = $this->drupalCreateUser([
"view own $id profile",
"create $id profile",
"update own $id profile",
"delete own $id profile",
]);
$profile1 = Profile::create([
'type' => $id,
'uid' => $test_user->id(),
'profile_fullname' => 'Frederick Pabst',
]);
$profile1->save();
$profile2 = Profile::create([
'type' => $id,
'uid' => $test_user->id(),
'profile_fullname' => 'Frederick Miller',
]);
$profile2->save();
$this->drupalLogin($test_user);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user->id(), 'profile_type' => $id]));
$this->assertSession()->pageTextContains('Frederick Pabst');
$this->assertSession()->pageTextContains('Frederick Miller');
$this->assertSession()->linkExists('Mark as default');
$this->getSession()->getPage()->clickLink('Mark as default');
$this->assertSession()->responseContains(new FormattableMarkup('The %label profile has been marked as default.', ['%label' => $profile2->label()]));
}
}
@@ -0,0 +1,121 @@
<?php
namespace Drupal\Tests\profile\Functional;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Tests profile field access functionality.
*
* @group profile
*/
class ProfileFieldAccessTest extends ProfileTestBase {
/**
* A test user.
*
* @var \Drupal\user\Entity\User
*/
protected $webUser;
/**
* A test user.
*
* @var \Drupal\user\Entity\User
*/
protected $otherUser;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser([
'access user profiles',
'administer profile',
'administer profile types',
'administer profile fields',
'administer profile display',
]);
$user_permissions = [
'access user profiles',
"create {$this->type->id()} profile",
"update own {$this->type->id()} profile",
"view any {$this->type->id()} profile",
];
$this->webUser = $this->drupalCreateUser($user_permissions);
$this->otherUser = $this->drupalCreateUser($user_permissions);
}
/**
* Tests private profile field access.
*/
public function testPrivateField() {
$this->field->setThirdPartySetting('profile', 'profile_private', TRUE);
$this->field->save();
$field_storage = FieldStorageConfig::create([
'field_name' => 'profile_bio',
'entity_type' => 'profile',
'type' => 'text',
]);
$field_storage->save();
$bio_field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $this->type->id(),
'label' => 'Bio',
]);
$bio_field->save();
$this->display
->setComponent($bio_field->getName(), [
'type' => 'string',
'label' => 'above',
])
->save();
$this->form
->setComponent($bio_field->getName(), [
'type' => 'text_default',
'settings' => [],
])->save();
// Fill in a field value.
$this->drupalLogin($this->webUser);
$secret = $this->randomMachineName();
$not_secret = $this->randomMachineName();
$this->drupalGet("user/{$this->webUser->id()}/{$this->type->id()}");
$edit = [
'profile_fullname[0][value]' => $secret,
'profile_bio[0][value]' => $not_secret,
];
$this->assertSession()->buttonNotExists('Save and make default');
$this->submitForm($edit, 'Save');
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')->getStorage('profile');
$web_user_profile = $storage->loadDefaultByUser($this->webUser, $this->type->id());
// Verify that the private field value appears for the profile owner.
$this->drupalGet($web_user_profile->toUrl());
$this->assertSession()->pageTextContains($secret);
$this->assertSession()->pageTextContains($not_secret);
// Verify that the private field value does not appear for other users.
$this->drupalLogin($this->otherUser);
$this->drupalGet($web_user_profile->toUrl());
$this->assertSession()->pageTextNotContains($secret);
$this->assertSession()->pageTextContains($not_secret);
// Verify that the private field value appears for the administrator.
$this->drupalLogin($this->adminUser);
$this->drupalGet($web_user_profile->toUrl());
$this->assertSession()->pageTextContains($secret);
$this->assertSession()->pageTextContains($not_secret);
}
}
@@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\profile\Functional;
use Drupal\Core\Url;
/**
* Tests that the help page for the module is available.
*
* @group profile
*/
class ProfileHelpTest extends ProfileTestBase {
public static $modules = ['help'];
/**
* Tests that the help page loads.
*/
public function testHelpPage() {
$user = $this->createUser(['access administration pages']);
$this->drupalLogin($user);
$this->drupalGet(Url::fromRoute('help.page', ['name' => 'profile'])->toString());
$this->assertSession()->pageTextContains('Types of profiles');
$this->assertSession()->pageTextContains('Creating profiles');
}
}
@@ -30,36 +30,44 @@ class ProfileRegisterFormTest extends ProfileTestBase {
->save();
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ['view own test profile']);
$this->drupalGet('user/register');
// Verify that the additional profile field is attached and required.
$name = $this->randomMachineName();
$pass_raw = $this->randomMachineName();
// Use existing email to verify normal validation happens.
$edit = [
'name' => $name,
'mail' => $this->randomMachineName() . '@example.com',
'mail' => $this->adminUser->getEmail(),
'pass[pass1]' => $pass_raw,
'pass[pass2]' => $pass_raw,
];
$this->drupalPostForm('user/register', $edit, t('Create new account'));
$this->submitForm($edit, t('Create new account'));
$this->assertSession()->pageTextContains(new FormattableMarkup('@name field is required.', ['@name' => $this->field->getLabel()]));
$this->assertSession()->pageTextContains(new FormattableMarkup('The email address @email is already taken.', ['@email' => $this->adminUser->getEmail()]));
// Verify that we can register.
$edit['mail'] = $this->randomMachineName() . '@example.com';
$edit["entity_" . $id . "[$field_name][0][value]"] = $this->randomMachineName();
$this->drupalPostForm(NULL, $edit, t('Create new account'));
$this->submitForm($edit, t('Create new account'));
$this->assertSession()->pageTextContains(new FormattableMarkup('Registration successful. You are now logged in.', []));
$new_user = user_load_by_name($name);
$this->assertTrue($new_user->isActive(), 'New account is active after registration.');
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')->getStorage('profile');
// Verify that a new profile was created for the new user ID.
$profile = $this->container->get('entity_type.manager')
->getStorage('profile')
->loadByUser($new_user, $this->type->id());
$profile = $storage->loadDefaultByUser($new_user, $this->type->id());
$this->assertEquals($profile->get($field_name)->value, $edit["entity_" . $id . "[$field_name][0][value]"], 'Field value found in loaded profile.');
// Verify that, as the first profile of this type for the user, it was set
// as default.
$this->assertTrue($profile->isDefault());
// Verify that the profile field value appears on the user account page.
$this->drupalGet('user');
$this->drupalGet($profile->toUrl()->toString());
$this->assertSession()->pageTextContains($edit["entity_" . $id . "[$field_name][0][value]"]);
}
@@ -0,0 +1,160 @@
<?php
namespace Drupal\Tests\profile\Functional;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\profile\Entity\ProfileType;
/**
* Tests using revisions with profiles.
*
* @group profile
*/
class ProfileRevisionTest extends ProfileTestBase {
/**
* Testing profile type, with use_revisions.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $useRevisionsType;
/**
* @inheritDoc
*/
protected function setUp() {
parent::setUp();
$use_revisions_type = ProfileType::create([
'id' => $this->randomMachineName(),
'label' => $this->randomMachineName(),
'use_revisions' => TRUE,
]);
$use_revisions_type->save();
$this->useRevisionsType = $use_revisions_type;
$use_revisions_fullname_field = FieldConfig::create([
'field_storage' => $this->field->getFieldStorageDefinition(),
'bundle' => $this->useRevisionsType->id(),
'label' => 'Full name',
]);
$use_revisions_fullname_field->save();
// Configure the default display.
$use_revisions_display = EntityViewDisplay::load("profile.{$this->useRevisionsType->id()}.default");
if (!$use_revisions_display) {
$use_revisions_display = EntityViewDisplay::create([
'targetEntityType' => 'profile',
'bundle' => $this->useRevisionsType->id(),
'mode' => 'default',
'status' => TRUE,
]);
$use_revisions_display->save();
}
$use_revisions_display
->setComponent($this->field->getName(), ['type' => 'string'])
->save();
// Configure the default form.
$use_revisions_form = EntityFormDisplay::load("profile.{$this->useRevisionsType->id()}.default");
if (!$use_revisions_form) {
$use_revisions_form = EntityFormDisplay::create([
'targetEntityType' => 'profile',
'bundle' => $this->useRevisionsType->id(),
'mode' => 'default',
'status' => TRUE,
]);
$this->form->save();
}
$use_revisions_form
->setComponent($this->field->getName(), [
'type' => 'string_textfield',
])->save();
}
/**
* Tests revision handling.
*/
public function testProfileRevisions() {
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')->getStorage('profile');
$user = $this->createUser([
"create {$this->type->id()} profile",
"view own {$this->type->id()} profile",
"update own {$this->type->id()} profile",
]);
$this->drupalLogin($user);
$create_url = Url::fromRoute('entity.profile.type.user_profile_form', [
'user' => $this->loggedInUser->id(),
'profile_type' => $this->type->id(),
]);
$this->drupalGet($create_url);
$edit = [
'profile_fullname[0][value]' => $this->getRandomGenerator()->word(10),
];
$this->submitForm($edit, 'Save');
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->type->id());
$existing_profile_id = $profile->id();
$existing_revision_id = $profile->getRevisionId();
$create_url = Url::fromRoute('entity.profile.type.user_profile_form', [
'user' => $this->loggedInUser->id(),
'profile_type' => $this->type->id(),
]);
$this->drupalGet($create_url);
$edit = [
'profile_fullname[0][value]' => $this->getRandomGenerator()->word(10),
];
$this->submitForm($edit, 'Save');
$storage->resetCache([$profile->id()]);
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->type->id());
$this->assertEquals($existing_profile_id, $profile->id());
$this->assertEquals($existing_revision_id, $profile->getRevisionId());
$user = $this->createUser([
"create {$this->useRevisionsType->id()} profile",
"view own {$this->useRevisionsType->id()} profile",
"update own {$this->useRevisionsType->id()} profile",
]);
$this->drupalLogin($user);
$create_url = Url::fromRoute('entity.profile.type.user_profile_form', [
'user' => $this->loggedInUser->id(),
'profile_type' => $this->useRevisionsType->id(),
]);
$this->drupalGet($create_url);
$edit = [
'profile_fullname[0][value]' => $this->getRandomGenerator()->word(10),
];
$this->submitForm($edit, 'Save');
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->useRevisionsType->id());
$existing_profile_id = $profile->id();
$existing_revision_id = $profile->getRevisionId();
$create_url = Url::fromRoute('entity.profile.type.user_profile_form', [
'user' => $this->loggedInUser->id(),
'profile_type' => $this->useRevisionsType->id(),
]);
$this->drupalGet($create_url);
$edit = [
'profile_fullname[0][value]' => $this->getRandomGenerator()->word(10),
];
$this->submitForm($edit, 'Save');
$storage->resetCache([$profile->id()]);
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->useRevisionsType->id());
$this->assertEquals($existing_profile_id, $profile->id());
$this->assertNotEquals($existing_revision_id, $profile->getRevisionId());
}
}
@@ -1,6 +1,6 @@
<?php
namespace Drupal\profile\Tests;
namespace Drupal\Tests\profile\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
@@ -27,7 +27,7 @@ class ProfileTabTest extends ProfileTestBase {
/**
* Testing demo user 2.
*
* @var \Drupal\user\UserInterface;
* @var \Drupal\user\UserInterface
*/
public $user2;
@@ -39,9 +39,8 @@ class ProfileTabTest extends ProfileTestBase {
$this->adminUser = $this->drupalCreateUser([
'access user profiles',
'administer profiles',
'administer profile',
'administer profile types',
'bypass profile access',
'access administration pages',
]);
}
@@ -116,17 +115,17 @@ class ProfileTabTest extends ProfileTestBase {
* secondary. Defaults to 0.
*/
protected function assertLocalTasks(array $routes, $level = 0) {
$elements = $this->xpath('//*[contains(@class, :class)]//a', array(
$elements = $this->xpath('//*[contains(@class, :class)]//a', [
':class' => $level == 0 ? 'tabs primary' : 'tabs secondary',
));
]);
$this->assertTrue(count($elements), 'Local tasks found.');
foreach ($routes as $index => $route_info) {
list($route_name, $route_parameters) = $route_info;
$expected = Url::fromRoute($route_name, $route_parameters)->toString();
$method = ($elements[$index]['href'] == $expected ? 'pass' : 'fail');
$method = ($elements[$index]->getAttribute('href') == $expected ? 'pass' : 'fail');
$this->{$method}(new FormattableMarkup('Task @number href @value equals @expected.', [
'@number' => $index + 1,
'@value' => (string) $elements[$index]['href'],
'@value' => (string) $elements[$index]->getAttribute('href'),
'@expected' => $expected,
]));
}
@@ -0,0 +1,127 @@
<?php
namespace Drupal\Tests\profile\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
use Drupal\profile\Entity\Profile;
use Drupal\user\Entity\User;
/**
* Tests various CRUD for Profile entity in browser.
*
* @group profile
*/
class ProfileTest extends ProfileTestBase {
/**
* Tests creating and editing a profile.
*/
public function testCreateEditProfile() {
$this->drupalLogin($this->adminUser);
$profile_fullname = $this->randomString();
$create_url = Url::fromRoute('entity.profile.type.user_profile_form', [
'user' => $this->loggedInUser->id(),
'profile_type' => $this->type->id(),
]);
$this->drupalGet($create_url->toString());
$this->assertSession()->titleEquals("Create {$this->type->label()} | Drupal");
$this->assertSession()->buttonNotExists('Save and make default');
$edit = [
'profile_fullname[0][value]' => $profile_fullname,
];
$this->submitForm($edit, 'Save');
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')->getStorage('profile');
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->type->id());
$this->assertEquals($profile_fullname, $profile->get('profile_fullname')->value);
$this->drupalGet($profile->toUrl('edit-form')->toString());
$this->assertSession()->titleEquals("Edit {$this->type->label()} profile #{$profile->id()} | Drupal");
$profile_fullname = $this->randomString();
$edit = [
'profile_fullname[0][value]' => $profile_fullname,
];
$this->submitForm($edit, 'Save');
$storage->resetCache([$profile->id()]);
$profile = $storage->loadDefaultByUser($this->loggedInUser, $this->type->id());
$this->assertEquals($profile_fullname, $profile->get('profile_fullname')->value);
}
/**
* Tests that a profile belonging to an anonymous user can be edited.
*/
public function testAnonymousProfileEdit() {
$profile = $this->createProfile($this->type, User::getAnonymousUser());
$this->drupalLogin($this->adminUser);
$this->drupalGet($profile->toUrl('edit-form')->toString());
$profile_fullname = $this->randomString();
$edit = [
'profile_fullname[0][value]' => $profile_fullname,
];
$this->submitForm($edit, 'Save');
$this->assertSession()->addressEquals($profile->toUrl('collection')->toString());
}
/**
* Tests entity.profile.type.user_profile_form route access.
*/
public function testUserProfileFormAccess() {
$id = $this->type->id();
$test_user1 = $this->drupalCreateUser([
"view own $id profile",
"create $id profile",
"update own $id profile",
"delete own $id profile",
]);
$test_user2 = $this->drupalCreateUser([
"view own $id profile",
"create $id profile",
"update own $id profile",
"delete own $id profile",
]);
$this->drupalLogin($this->adminUser);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user1->id(), 'profile_type' => $id]));
$this->assertSession()->statusCodeEquals(200);
$this->drupalLogin($test_user1);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user1->id(), 'profile_type' => $id]));
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user2->id(), 'profile_type' => $id]));
$this->assertSession()->statusCodeEquals(403);
$this->type->setMultiple(TRUE)->save();
// Add link only appears if there are existing profiles.
Profile::create([
'type' => $this->type->id(),
'uid' => $test_user1->id(),
'profile_fullname' => $this->randomMachineName(),
])->save();
Profile::create([
'type' => $this->type->id(),
'uid' => $test_user2->id(),
'profile_fullname' => $this->randomMachineName(),
])->save();
$this->drupalLogin($this->adminUser);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user1->id(), 'profile_type' => $id]));
$this->assertSession()->linkExists(new FormattableMarkup('Add new @type', ['@type' => $this->type->label()]));
$this->assertSession()->statusCodeEquals(200);
$this->drupalLogin($test_user1);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user1->id(), 'profile_type' => $id]));
$this->assertSession()->linkExists(new FormattableMarkup('Add new @type', ['@type' => $this->type->label()]));
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet(Url::fromRoute('entity.profile.type.user_profile_form', ['user' => $test_user2->id(), 'profile_type' => $id]));
$this->assertSession()->linkNotExists(new FormattableMarkup('Add new @type', ['@type' => $this->type->label()]));
$this->assertSession()->statusCodeEquals(403);
}
}
@@ -8,7 +8,6 @@ use Drupal\Core\Session\AccountInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\profile\ProfileTestTrait;
use Drupal\simpletest\WebTestBase;
use Drupal\Tests\BrowserTestBase;
/**
@@ -30,14 +29,14 @@ abstract class ProfileTestBase extends BrowserTestBase {
/**
* Testing profile type entity view display.
*
* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface
*/
protected $display;
/**
* Testing profile type entity form display.
*
* @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form
* @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface
*/
protected $form;
@@ -98,7 +97,7 @@ abstract class ProfileTestBase extends BrowserTestBase {
->setComponent($this->field->getName(), ['type' => 'string'])
->save();
// Configure rhe default form.
// Configure the default form.
$this->form = EntityFormDisplay::load("profile.{$this->type->id()}.default");
if (!$this->form) {
$this->form = EntityFormDisplay::create([
@@ -116,12 +115,11 @@ abstract class ProfileTestBase extends BrowserTestBase {
$this->checkPermissions([
'administer profile types',
"create $id profile",
"view own $id profile",
"view any $id profile",
"add own $id profile",
"add any $id profile",
"edit own $id profile",
"edit any $id profile",
"update own $id profile",
"update any $id profile",
"delete own $id profile",
"delete any $id profile",
]);
@@ -129,10 +127,10 @@ abstract class ProfileTestBase extends BrowserTestBase {
user_role_grant_permissions(AccountInterface::AUTHENTICATED_ROLE, ['access user profiles']);
$this->adminUser = $this->drupalCreateUser([
'administer profile types',
'administer profiles',
'administer profile',
"view any $id profile",
"add any $id profile",
"edit any $id profile",
"create $id profile",
"update any $id profile",
"delete any $id profile",
]);
}
@@ -1,9 +1,10 @@
<?php
namespace Drupal\profile\Tests;
namespace Drupal\Tests\profile\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Unicode;
use Drupal\profile\Entity\ProfileType;
/**
* Tests basic CRUD functionality of profile types.
@@ -23,7 +24,6 @@ class ProfileTypeCRUDTest extends ProfileTestBase {
'administer profile types',
'administer profile fields',
'administer profile display',
'bypass profile access',
]);
}
@@ -41,7 +41,7 @@ class ProfileTypeCRUDTest extends ProfileTestBase {
/**
* Tests CRUD operations for profile types through the UI.
*/
public function testCRUDUI() {
public function testUi() {
$this->drupalLogin($this->adminUser);
// Create a new profile type.
@@ -51,7 +51,7 @@ class ProfileTypeCRUDTest extends ProfileTestBase {
$this->assertUrl('admin/config/people/profiles/types/add');
$id = Unicode::strtolower($this->randomMachineName());
$label = $this->randomString();
$label = $this->getRandomGenerator()->word(10);
$edit = [
'id' => $id,
'label' => $label,
@@ -67,37 +67,16 @@ class ProfileTypeCRUDTest extends ProfileTestBase {
// Edit the new profile type.
$this->drupalGet("admin/config/people/profiles/types/manage/$id");
$this->assertRaw(new FormattableMarkup('Edit %label profile type', ['%label' => $label]));
$edit = [
'registration' => 1,
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->getSession()->getPage()->checkField('Include in user registration form');
$this->getSession()->getPage()->checkField('Create a new revision when a profile is modified');
$this->submitForm([], 'Save');
$this->assertUrl('admin/config/people/profiles/types');
$this->assertRaw(new FormattableMarkup('%label profile type has been updated.', ['%label' => $label]));
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
// Add a field to the profile type.
$this->drupalGet("admin/config/people/profiles/types/manage/$id/fields/add-field");
$field_name = Unicode::strtolower($this->randomMachineName());
$field_label = $this->randomString();
$edit = [
'new_storage_type' => 'string',
'label' => $field_label,
'field_name' => $field_name,
];
$this->drupalPostForm(NULL, $edit, t('Save and continue'));
$this->drupalPostForm(NULL, [], t('Save field settings'));
$this->drupalPostForm(NULL, [], t('Save settings'));
$this->assertRaw(new FormattableMarkup('Saved %label configuration.', ['%label' => $field_label]));
// Verify that the field is still associated with it.
$this->drupalGet("admin/config/people/profiles/types/manage/$id/fields");
// @todo D8 core: This assertion fails for an unknown reason. Database
// contains the right values, so field_attach_rename_bundle() works
// correctly. The pre-existing field does not appear on the Manage
// fields page of the renamed bundle. Not even flushing all caches
// helps. Can be reproduced manually.
// $this->assertText(check_plain($field_label));
$profile_type = ProfileType::load($id);
$this->assertEquals($label, $profile_type->label());
$this->assertTrue($profile_type->getRegistration());
$this->assertTrue($profile_type->shouldCreateNewRevision());
}
}
@@ -1,10 +1,12 @@
<?php
namespace Drupal\profile\Tests;
namespace Drupal\Tests\profile\Kernel;
use Drupal\Core\Session\AccountInterface;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\profile\Entity\Profile;
use Drupal\profile\ProfileTestTrait;
use Drupal\user\Entity\User;
/**
* Tests profile access handling.
@@ -20,7 +22,11 @@ class ProfileAccessTest extends EntityKernelTestBase {
*
* @var array
*/
public static $modules = ['user', 'system', 'field', 'text', 'profile', 'views'];
public static $modules = [
'entity',
'profile',
'views',
];
/**
* The access control handler.
@@ -52,7 +58,8 @@ class ProfileAccessTest extends EntityKernelTestBase {
$this->installEntitySchema('profile');
$this->installEntitySchema('view');
$this->installConfig(['profile']);
$this->accessControlHandler = $this->container->get('entity_type.manager')->getAccessControlHandler('profile');
$this->accessControlHandler = $this->container->get('entity_type.manager')
->getAccessControlHandler('profile');
$this->accessManager = $this->container->get('access_manager');
$this->type = $this->createProfileType('test', 'Test profile', TRUE);
$this->createUser();
@@ -71,14 +78,16 @@ class ProfileAccessTest extends EntityKernelTestBase {
// Verify access through route.
$this->assertFalse($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
'entity.profile.type.user_profile_form.add',
['user' => $web_user1->id(), 'profile_type' => $this->type->id()],
$web_user1
));
// Test user with permission to only add own profile.
$web_user2 = $this->createUser([], ["add own {$this->type->id()} profile"]);
// Test user with permission to only add a profile.
$web_user2 = $this->createUser([], [
"create {$this->type->id()} profile",
"update own {$this->type->id()} profile",
]);
$web_user1->addRole($web_user2->get('roles')->first()->target_id);
$web_user1->save();
@@ -86,15 +95,15 @@ class ProfileAccessTest extends EntityKernelTestBase {
$access = $this->accessControlHandler->createAccess($this->type->id(), $web_user2);
$this->assertTrue($access);
// User 2 can create own profile of type.
// User 2 can create profile of type.
$this->assertTrue($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
'entity.profile.type.user_profile_form.add',
['user' => $web_user2->id(), 'profile_type' => $this->type->id()],
$web_user2
));
// User 1 cannot create a profile for User 2.
$this->assertFalse($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
'entity.profile.type.user_profile_form.add',
['user' => $web_user2->id(), 'profile_type' => $this->type->id()],
$web_user1
));
@@ -103,23 +112,26 @@ class ProfileAccessTest extends EntityKernelTestBase {
$second_type = $this->createProfileType('test2', 'Test2 profile', TRUE);
$this->assertFalse($this->accessControlHandler->createAccess('test2', $web_user2));
$this->assertFalse($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
'entity.profile.type.user_profile_form.add',
['user' => $web_user2->id(), 'profile_type' => $second_type->id()],
$web_user2
));
// Test user with permission to only add any profile.
$web_user3 = $this->createUser([], ["add any {$this->type->id()} profile"]);
$web_user3 = $this->createUser([], [
"create {$this->type->id()} profile",
"update own {$this->type->id()} profile",
]);
$this->assertTrue($this->accessControlHandler->createAccess($this->type->id(), $web_user3));
// Verify access through route.
$this->assertTrue($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
'entity.profile.type.user_profile_form.add',
['user' => $web_user3->id(), 'profile_type' => $this->type->id()],
$web_user3
));
$this->assertTrue($this->accessManager->checkNamedRoute(
'entity.profile.add_form',
$this->assertFalse($this->accessManager->checkNamedRoute(
'entity.profile.type.user_profile_form.add',
['user' => $web_user2->id(), 'profile_type' => $this->type->id()],
$web_user3
));
@@ -159,17 +171,14 @@ class ProfileAccessTest extends EntityKernelTestBase {
$this->assertTrue($profile1->access('view', $web_user2));
$this->assertTrue($profile2->access('view', $web_user2));
$user_view_builder = $this->container->get('entity_type.manager')->getViewBuilder('user');
user_role_grant_permissions(AccountInterface::ANONYMOUS_ROLE, ["view own {$this->type->id()} profile"]);
$this->assertFalse($profile1->access('view', User::getAnonymousUser()));
$this->assertFalse($profile2->access('view', User::getAnonymousUser()));
$this->container->get('current_user')->setAccount($web_user1);
$user2_view = $user_view_builder->view($web_user2);
$this->render($user2_view);
$this->assertNoText($this->type->label());
$this->container->get('current_user')->setAccount($web_user2);
$user1_view = $user_view_builder->view($web_user1);
$this->render($user1_view);
$this->assertText($this->type->label());
// @todo Fix in https://www.drupal.org/node/2820209
user_role_grant_permissions(AccountInterface::ANONYMOUS_ROLE, ["view any {$this->type->id()} profile"]);
// $this->assertTrue($profile1->access('view', User::getAnonymousUser()));
// $this->assertTrue($profile2->access('view', User::getAnonymousUser()));
}
/**
@@ -178,12 +187,12 @@ class ProfileAccessTest extends EntityKernelTestBase {
public function testProfileEditAccess() {
// Setup users.
$web_user1 = $this->createUser([], [
"add own {$this->type->id()} profile",
"edit own {$this->type->id()} profile",
"create {$this->type->id()} profile",
"update own {$this->type->id()} profile",
]);
$web_user2 = $this->createUser([], [
"add any {$this->type->id()} profile",
"edit any {$this->type->id()} profile",
"create {$this->type->id()} profile",
"update any {$this->type->id()} profile",
]);
// Setup profiles.
@@ -199,12 +208,12 @@ class ProfileAccessTest extends EntityKernelTestBase {
$profile2->save();
// Test user1 can only edit own profiles.
$this->assertTrue($profile1->access('edit', $web_user1));
$this->assertFalse($profile2->access('edit', $web_user1));
$this->assertTrue($profile1->access('update', $web_user1));
$this->assertFalse($profile2->access('update', $web_user1));
// Test user2 can edit any profiles.
$this->assertTrue($profile1->access('edit', $web_user2));
$this->assertTrue($profile2->access('edit', $web_user2));
$this->assertTrue($profile1->access('update', $web_user2));
$this->assertTrue($profile2->access('update', $web_user2));
}
}
@@ -0,0 +1,201 @@
<?php
namespace Drupal\Tests\profile\Kernel;
use Drupal\Core\Session\AccountInterface;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\profile\ProfileTestTrait;
use Drupal\user\Entity\Role;
/**
* Tests profile role access handling.
*
* @group profile
*/
class ProfileRoleAccessTest extends EntityKernelTestBase {
use ProfileTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'entity',
'profile',
'views',
];
/**
* Randomly generated profile type entity.
*
* No roles.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type1;
/**
* Randomly generated profile type entity.
*
* Requires some, but not all roles.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type2;
/**
* Randomly generated profile type entity.
*
* Requires all profile roles.
*
* @var \Drupal\profile\Entity\ProfileType
*/
protected $type3;
/**
* Randomly generated user role entity.
*
* @var \Drupal\user\Entity\Role
*/
protected $role1;
/**
* Randomly generated user role entity.
*
* @var \Drupal\user\Entity\Role
*/
protected $role2;
/**
* The profile access handler.
*
* @var \Drupal\profile\ProfileAccessControlHandler
*/
protected $accessHandler;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->role1 = Role::create([
'id' => strtolower($this->randomMachineName(8)),
'label' => $this->randomMachineName(8),
]);
$this->role1->save();
$this->role2 = Role::create([
'id' => strtolower($this->randomMachineName(8)),
'label' => $this->randomMachineName(8),
]);
$this->role2->save();
$this->type1 = $this->createProfileType(NULL, NULL, FALSE, []);
$this->type2 = $this->createProfileType(NULL, NULL, FALSE, [$this->role2->id()]);
$this->type3 = $this->createProfileType(NULL, NULL, FALSE, [
$this->role1->id(),
$this->role2->id(),
]);
$this->accessHandler = $this->container->get('entity_type.manager')
->getAccessControlHandler('profile');
// Do not allow uid == 1 to skew tests.
$this->createUser();
}
/**
* Tests profile form access for a type that has no role requirement.
*/
public function testProfileWithNoRoles() {
// Create user with add profile permissions.
$web_user1 = $this->createUser([], ["create {$this->type1->id()} profile"]);
$this->assertTrue($this->accessHandler->createAccess($this->type1->id(), $web_user1));
}
/**
* Tests profile form access for a type that has the locked role requirement.
*/
public function testLockedRoles() {
$locked_role_type = $this->createProfileType(NULL, NULL, FALSE, [AccountInterface::AUTHENTICATED_ROLE]);
// Create user with add profile permissions.
$web_user1 = $this->createUser([], ["create {$locked_role_type->id()} profile"]);
$this->assertTrue($this->accessHandler->createAccess($locked_role_type->id(), $web_user1));
}
/**
* Tests profile form access for a type that requires a role.
*/
public function testProfileWithSingleRole() {
// Create user with add own profile permissions.
$web_user1 = $this->createUser([], ["create {$this->type2->id()} profile"]);
// Test user without role can access add profile form.
// Expected: User cannot access form.
$this->assertFalse($this->accessHandler->createAccess($this->type2->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user with wrong role can access add profile form.
// Expected: User cannot access form.
$web_user1->addRole($this->role1->id());
$web_user1->save();
$this->assertFalse($this->accessHandler->createAccess($this->type2->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user with correct role can access add profile form.
// Expected: User can access form.
$web_user1->removeRole($this->role1->id());
$web_user1->addRole($this->role2->id());
$web_user1->save();
$this->reloadEntity($web_user1);
$this->assertTrue($this->accessHandler->createAccess($this->type2->id(), $web_user1));
}
/**
* Tests profile form access for a type that requires multiple roles.
*/
public function testProfileWithAllRoles() {
// Create user with add own profile permissions.
$web_user1 = $this->createUser([], ["create {$this->type3->id()} profile"]);
// Test user without role can access add profile form.
// Expected: User cannot access form.
$this->assertFalse($this->accessHandler->createAccess($this->type3->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user with role 1 can access add profile form.
// Expected: User can access form.
$web_user1->addRole($this->role1->id());
$web_user1->save();
$this->assertTrue($this->accessHandler->createAccess($this->type3->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user with both roles can access add profile form.
// Expected: User can access form.
$web_user1->addRole($this->role2->id());
$web_user1->save();
$this->assertTrue($this->accessHandler->createAccess($this->type3->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user with role 2 can access add profile form.
// Expected: User can access form.
$web_user1->removeRole($this->role1->id());
$web_user1->save();
$this->assertTrue($this->accessHandler->createAccess($this->type3->id(), $web_user1));
$this->accessHandler->resetCache();
// Test user without role can access add profile form.
// Expected: User cannot access form.
$web_user1->removeRole($this->role2->id());
$web_user1->save();
$this->assertFalse($this->accessHandler->createAccess($this->type3->id(), $web_user1));
}
}
@@ -3,9 +3,11 @@
namespace Drupal\Tests\profile\Kernel;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\profile\Entity\Profile;
use Drupal\profile\Entity\ProfileType;
use Drupal\profile\ProfileTestTrait;
/**
* Tests basic functionality of profiles.
@@ -20,10 +22,7 @@ class ProfileTest extends EntityKernelTestBase {
* @var array
*/
public static $modules = [
'user',
'system',
'field',
'text',
'entity',
'profile',
'views',
];
@@ -38,7 +37,7 @@ class ProfileTest extends EntityKernelTestBase {
/**
* Testing demo user 2.
*
* @var \Drupal\user\UserInterface;
* @var \Drupal\user\UserInterface
*/
public $user2;
@@ -80,21 +79,13 @@ class ProfileTest extends EntityKernelTestBase {
$types[$id]->save();
}
// Create a new profile.
/** @var \Drupal\profile\Entity\ProfileInterface $profile */
$profile = $this->profileStorage->create($expected = [
$profile = $this->profileStorage->create([
'type' => $types['profile_type_0']->id(),
'uid' => $this->user1->id(),
]);
$expected_label = new TranslatableMarkup('@type profile of @username (uid: @uid)', [
'@type' => $types['profile_type_0']->label(),
'@username' => $this->user1->getDisplayName(),
'@uid' => $this->user1->id(),
]);
$this->assertEquals($expected_label, $profile->label());
$this->assertEquals($profile->getOwnerId(), $this->user1->id());
$this->assertEquals($profile->getCreatedTime(), REQUEST_TIME);
$this->assertEquals($profile->getChangedTime(), REQUEST_TIME);
@@ -102,6 +93,11 @@ class ProfileTest extends EntityKernelTestBase {
// Save the profile.
$profile->save();
$this->assertEquals(REQUEST_TIME, $profile->getChangedTime());
$expected_label = new TranslatableMarkup('@type profile #@id', [
'@type' => $types['profile_type_0']->label(),
'@id' => $profile->id(),
]);
$this->assertEquals($expected_label, $profile->label());
// List profiles for the user and verify that the new profile appears.
$list = $this->profileStorage->loadByProperties(['uid' => $this->user1->id()]);
@@ -146,4 +142,190 @@ class ProfileTest extends EntityKernelTestBase {
$this->assertEquals($list_ids, [$user2_profile1->id()]);
}
/**
* Tests profiles are active by default.
*/
public function testProfileActive() {
$profile_type = ProfileType::create([
'id' => 'test_defaults',
'label' => 'test_defaults',
]);
$profile_type->save();
// Create new profiles.
$profile1 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
$this->assertTrue($profile1->isActive());
$profile1->setActive(FALSE);
$profile1->save();
$this->assertFalse($profile1->isActive());
}
/**
* Tests default profile functionality.
*/
public function testDefaultProfile() {
$profile_type = ProfileType::create([
'id' => 'test_defaults',
'label' => 'test_defaults',
]);
$profile_type->save();
// Create a new profile.
$profile1 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->save();
// Verify that the first profile of this type is default.
$this->assertTrue($profile1->isDefault());
// Create a second new profile.
$profile2 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile2->setDefault(TRUE);
$profile2->save();
$this->assertFalse($this->reloadEntity($profile1)->isDefault());
$this->assertTrue($this->reloadEntity($profile2)->isDefault());
$profile1->setDefault(TRUE)->save();
$this->assertFalse($this->reloadEntity($profile2)->isDefault());
$this->assertTrue($this->reloadEntity($profile1)->isDefault());
// Verify that a deactivated profile cannot be the default and that if the
// current default is disactivated another default is set.
$profile2->setActive(FALSE);
$profile2->save();
$this->assertFalse($this->reloadEntity($profile2)->isDefault());
$this->assertTrue($this->reloadEntity($profile1)->isDefault());
}
/**
* Tests loading default from storage handler.
*/
public function testLoadDefaultProfile() {
$profile_type = ProfileType::create([
'id' => 'test_defaults',
'label' => 'test_defaults',
]);
$profile_type->save();
// Create new profiles.
$profile1 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile1->setActive(TRUE);
$profile1->save();
$profile2 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
]);
$profile2->setActive(TRUE);
$profile2->setDefault(TRUE);
$profile2->save();
/** @var \Drupal\profile\ProfileStorageInterface $storage */
$storage = \Drupal::entityTypeManager()->getStorage('profile');
$default_profile = $storage->loadDefaultByUser($this->user1, $profile_type->id());
$this->assertEquals($profile2->id(), $default_profile->id());
// Ensure that \Drupal\profile\Entity\Profile::preSave doesn't crash.
$anonymous_profile = Profile::create(['type' => $profile_type->id()]);
$anonymous_profile->save();
$this->assertTrue(empty($anonymous_profile->getOwner()));
}
/**
* Tests revisions.
*/
public function testProfileRevisions() {
$profile_type = ProfileType::create([
'id' => 'test_defaults',
'label' => 'test_defaults',
]);
$profile_type->save();
$field_storage = FieldStorageConfig::create([
'field_name' => 'profile_fullname',
'entity_type' => 'profile',
'type' => 'text',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $profile_type->id(),
'label' => 'Full name',
]);
$field->save();
// Create new profiles.
/** @var \Drupal\profile\Entity\Profile $profile1 */
$profile1 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
'profile_fullname' => $this->randomMachineName(),
]);
$profile1->save();
$profile1 = $this->reloadEntity($profile1);
$existing_profile_id = $profile1->id();
$existing_revision_id = $profile1->getRevisionId();
$profile1->get('profile_fullname')->setValue($this->randomMachineName());
$profile1->save();
$profile1 = $this->reloadEntity($profile1);
$this->assertEquals($existing_profile_id, $profile1->id());
$this->assertEquals($existing_revision_id, $profile1->getRevisionId());
$profile_type->set('use_revisions', TRUE);
$profile_type->save();
// Create new profiles.
/** @var \Drupal\profile\Entity\Profile $profile2 */
$profile2 = Profile::create([
'type' => $profile_type->id(),
'uid' => $this->user1->id(),
'profile_fullname' => $this->randomMachineName(),
]);
$profile2->setDefault(TRUE);
$profile2->save();
$profile2 = $this->reloadEntity($profile2);
$existing_profile_id = $profile2->id();
$existing_revision_id = $profile2->getRevisionId();
// Changing field creates revision.
$profile2->get('profile_fullname')->setValue($this->randomMachineName());
$profile2->save();
$profile2 = $this->reloadEntity($profile2);
$this->assertEquals($existing_profile_id, $profile2->id());
$this->assertNotEquals($existing_revision_id, $profile2->getRevisionId());
$existing_profile_id = $profile2->id();
$existing_revision_id = $profile2->getRevisionId();
// Random save does not create a revision.
$profile2->save();
$profile2 = $this->reloadEntity($profile2);
$this->assertEquals($existing_profile_id, $profile2->id());
$this->assertEquals($existing_revision_id, $profile2->getRevisionId());
}
}
@@ -29,6 +29,9 @@ class ProfileViewTest extends ViewsKernelTestBase {
'users',
];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);