/** * {@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(); $user_roles = $entity->getOwner()->getRoles(TRUE); if (!empty(array_filter($profile_roles)) && !array_intersect($user_roles, $profile_roles)) { return AccessResult::forbidden(); } } elseif ($entity->getEntityTypeId() == 'profile_type') { $profile_roles = $entity->getRoles(); $user_roles = User::load($user_page->id())->getRoles(TRUE); 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 { return AccessResult::forbidden()->cachePerPermissions(); } }
/** * 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), ], ]; }
/** * 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); }
/** * Tests tabs in profile UI. */ public function testProfileTabs() { $types_data = ['profile_type_0' => ['label' => $this->randomMachineName()], 'profile_type_1' => ['label' => $this->randomMachineName()]]; /** @var ProfileType[] $types */ $types = []; foreach ($types_data as $id => $values) { $types[$id] = ProfileType::create(['id' => $id] + $values); $types[$id]->save(); } $this->container->get('router.builder')->rebuild(); $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(); // 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_1']->id(), 'uid' => $this->user2->id()]); $profile2->save(); $this->drupalLogin($this->adminUser); $this->drupalGet('admin/config'); $this->clickLink('User profiles'); $this->assertResponse(200); $this->assertUrl('admin/config/people/profiles'); $this->assertLink($profile1->label()); $this->assertLinkByHref($profile2->toUrl('canonical')->toString()); $tasks = [['entity.profile.collection', []], ['entity.profile_type.collection', []]]; $this->assertLocalTasks($tasks, 0); }
/** * Creates a profile type for tests. * * @param string $id * The profile type machine name. * @param string $label * The profile type human display name. * @param bool|FALSE $registration * Boolean if profile type shows on registration form. * @param array $roles * Array of user role machine names. * * @return \Drupal\profile\Entity\ProfileTypeInterface * Returns a profile type entity. */ protected function createProfileType($id = NULL, $label = NULL, $registration = FALSE, $roles = []) { $id = !empty($id) ? $id : $this->randomMachineName(); $label = !empty($label) ? $label : $this->randomMachineName(); $type = ProfileType::create(['id' => $id, 'label' => $label, 'registration' => $registration, 'roles' => $roles]); $type->save(); return $type; }
/** * {@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', "view any {$id} profile", "add any {$id} profile", "edit any {$id} profile", "delete any {$id} profile"]); }
/** * {@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'], ['_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; }
/** * Tests CRUD operations. */ public function testCRUD() { $types_data = ['profile_type_0' => ['label' => $this->randomMachineName()], 'profile_type_1' => ['label' => $this->randomMachineName()]]; /** @var ProfileType[] $types */ $types = []; foreach ($types_data as $id => $values) { $types[$id] = ProfileType::create(['id' => $id] + $values); $types[$id]->save(); } $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(); $this->profileStorage = \Drupal::entityTypeManager()->getStorage('profile'); // Create a new profile. $profile = Profile::create($expected = ['type' => $types['profile_type_0']->id(), 'uid' => $this->user1->id()]); $this->assertIdentical($profile->id(), NULL); $this->assertTrue($profile->uuid()); $this->assertIdentical($profile->getType(), $expected['type']); $expected_label = t('@type profile of @username (uid: @uid)', ['@type' => $types['profile_type_0']->label(), '@username' => $this->user1->getDisplayName(), '@uid' => $this->user1->id()]); $this->assertEqual($profile->label(), $expected_label, new FormattableMarkup('Expected "%expected" but got "%got"', ['%expected' => $expected_label, '%got' => $profile->label()])); $this->assertIdentical($profile->getOwnerId(), $this->user1->id()); $this->assertIdentical($profile->getCreatedTime(), REQUEST_TIME); $this->assertIdentical($profile->getChangedTime(), REQUEST_TIME); // Save the profile. $status = $profile->save(); $this->assertIdentical($status, SAVED_NEW); $this->assertTrue($profile->id()); $this->assertIdentical($profile->getChangedTime(), REQUEST_TIME); // List profiles for the user and verify that the new profile appears. $list = $this->profileStorage->loadByProperties(['uid' => $this->user1->id()]); $list_ids = array_keys($list); $this->assertEqual($list_ids, [(int) $profile->id()]); // Reload and update the profile. /** @var Profile $profile */ $profile = Profile::load($profile->id()); $profile->setChangedTime($profile->getChangedTime() - 1000); $original = clone $profile; $status = $profile->save(); $this->assertIdentical($status, SAVED_UPDATED); $this->assertIdentical($profile->id(), $original->id()); $this->assertEqual($profile->getCreatedTime(), REQUEST_TIME); $this->assertEqual($original->getChangedTime(), REQUEST_TIME - 1000); // Changed time is only updated when saved through the UI form. // @see \Drupal\Core\Entity\ContentEntityForm::submitForm(). $this->assertEqual($profile->getChangedTime(), REQUEST_TIME - 1000); // Create a second profile. $user1_profile1 = $profile; $profile = Profile::create(['type' => $types['profile_type_0']->id(), 'uid' => $this->user1->id()]); $status = $profile->save(); $this->assertIdentical($status, SAVED_NEW); $user1_profile = $profile; // List profiles for the user and verify that both profiles appear. $list = $this->profileStorage->loadByProperties(['uid' => $this->user1->id()]); $list_ids = array_keys($list); $this->assertEqual($list_ids, [(int) $user1_profile1->id(), (int) $user1_profile->id()]); // Delete the second profile and verify that the first still exists. $user1_profile->delete(); $this->assertFalse(Profile::load($user1_profile->id())); $list = $this->profileStorage->loadByProperties(['uid' => $this->user1->id()]); $list_ids = array_keys($list); $this->assertEqual($list_ids, [(int) $user1_profile1->id()]); // Create a new second profile. $user1_profile = Profile::create(['type' => $types['profile_type_1']->id(), 'uid' => $this->user1->id()]); $status = $user1_profile->save(); $this->assertIdentical($status, SAVED_NEW); // Create a profile for the second user. $user2_profile1 = Profile::create(['type' => $types['profile_type_0']->id(), 'uid' => $this->user2->id()]); $status = $user2_profile1->save(); $this->assertIdentical($status, SAVED_NEW); // Delete the first user and verify that all of its profiles are deleted. $this->user1->delete(); $this->assertFalse(User::load($this->user1->id())); $list = $this->profileStorage->loadByProperties(['uid' => $this->user1->id()]); $list_ids = array_keys($list); $this->assertEqual($list_ids, []); // List profiles for the second user and verify that they still exist. $list = $this->profileStorage->loadByProperties(['uid' => $this->user2->id()]); $list_ids = array_keys($list); $this->assertEqual($list_ids, [(int) $user2_profile1->id()]); // @todo Rename a profile type; verify that existing profiles are updated. }
/** * {@inheritdoc} */ public function save(array $form, FormStateInterface $form_state) { $profile_type = ProfileType::load($this->entity->bundle()); // Active profile for non administers if profile is new. if (!\Drupal::currentUser()->hasPermission('administer profiles') && $this->entity->isNew()) { $this->entity->setActive(TRUE); } switch ($this->entity->save()) { case SAVED_NEW: drupal_set_message(t('%label profile has been created.', ['%label' => $profile_type->label()])); break; case SAVED_UPDATED: drupal_set_message(t('%label profile has been updated.', ['%label' => $profile_type->label()])); break; } $form_state->setRedirect('entity.user.canonical', [ 'user' => $this->entity->getOwnerId(), ]); }
/** * Creates a profile type for tests. * * @param string $id * The profile type machine name. * @param string $label * The profile type human display name. * @param bool|FALSE $registration * Boolean if profile type shows on registration form. * * @return \Drupal\profile\Entity\ProfileInterface * Returns a profile type entity. */ protected function createProfileType($id, $label, $registration = FALSE) { $type = ProfileType::create(['id' => $id, 'label' => $label, 'registration' => $registration]); $type->save(); $this->container->get('router.builder')->rebuild(); return $type; }
/** * Check whether the profile type exists. * * @param string $id * A string representing a profile type ID. * * @return bool * Returns bool if profile exists. */ public function exists($id) { $profile_type = ProfileType::load($id); return !empty($profile_type); }
/** * {@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()]); }