Backup of db before drupal security update
[yaffs-website] / web / core / modules / content_translation / src / Tests / ContentTranslationWorkflowsTest.php
1 <?php
2
3 namespace Drupal\content_translation\Tests;
4
5 use Drupal\Component\Utility\SafeMarkup;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\Core\Url;
8 use Drupal\user\UserInterface;
9
10 /**
11  * Tests the content translation workflows for the test entity.
12  *
13  * @group content_translation
14  */
15 class ContentTranslationWorkflowsTest extends ContentTranslationTestBase {
16
17   /**
18    * The entity used for testing.
19    *
20    * @var \Drupal\Core\Entity\EntityInterface
21    */
22   protected $entity;
23
24   /**
25    * Modules to enable.
26    *
27    * @var array
28    */
29   public static $modules = ['language', 'content_translation', 'entity_test'];
30
31   protected function setUp() {
32     parent::setUp();
33     $this->setupEntity();
34   }
35
36   /**
37    * {@inheritdoc}
38    */
39   protected function getTranslatorPermissions() {
40     $permissions = parent::getTranslatorPermissions();
41     $permissions[] = 'view test entity';
42
43     return $permissions;
44   }
45
46   /**
47    * {@inheritdoc}
48    */
49   protected function getEditorPermissions() {
50     return ['administer entity_test content'];
51   }
52
53   /**
54    * Creates a test entity and translate it.
55    */
56   protected function setupEntity() {
57     $default_langcode = $this->langcodes[0];
58
59     // Create a test entity.
60     $user = $this->drupalCreateUser();
61     $values = [
62       'name' => $this->randomMachineName(),
63       'user_id' => $user->id(),
64       $this->fieldName => [['value' => $this->randomMachineName(16)]],
65     ];
66     $id = $this->createEntity($values, $default_langcode);
67     $storage = $this->container->get('entity_type.manager')
68       ->getStorage($this->entityTypeId);
69     $storage->resetCache([$id]);
70     $this->entity = $storage->load($id);
71
72     // Create a translation.
73     $this->drupalLogin($this->translator);
74     $add_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_add", [$this->entityTypeId => $this->entity->id(), 'source' => $default_langcode, 'target' => $this->langcodes[2]]);
75     $this->drupalPostForm($add_translation_url, [], t('Save'));
76     $this->rebuildContainer();
77   }
78
79   /**
80    * Test simple and editorial translation workflows.
81    */
82   public function testWorkflows() {
83     // Test workflows for the editor.
84     $expected_status = [
85       'edit' => 200,
86       'delete' => 200,
87       'overview' => 403,
88       'add_translation' => 403,
89       'edit_translation' => 403,
90       'delete_translation' => 403,
91     ];
92     $this->doTestWorkflows($this->editor, $expected_status);
93
94     // Test workflows for the translator.
95     $expected_status = [
96       'edit' => 403,
97       'delete' => 403,
98       'overview' => 200,
99       'add_translation' => 200,
100       'edit_translation' => 200,
101       'delete_translation' => 200,
102     ];
103     $this->doTestWorkflows($this->translator, $expected_status);
104
105     // Test workflows for the admin.
106     $expected_status = [
107       'edit' => 200,
108       'delete' => 200,
109       'overview' => 200,
110       'add_translation' => 200,
111       'edit_translation' => 403,
112       'delete_translation' => 403,
113     ];
114     $this->doTestWorkflows($this->administrator, $expected_status);
115
116     // Check that translation permissions allow the associated operations.
117     $ops = ['create' => t('Add'), 'update' => t('Edit'), 'delete' => t('Delete')];
118     $translations_url = $this->entity->urlInfo('drupal:content-translation-overview');
119     foreach ($ops as $current_op => $item) {
120       $user = $this->drupalCreateUser([$this->getTranslatePermission(), "$current_op content translations", 'view test entity']);
121       $this->drupalLogin($user);
122       $this->drupalGet($translations_url);
123
124       // Make sure that the user.permissions cache context and the cache tags
125       // for the entity are present.
126       $this->assertCacheContext('user.permissions');
127       foreach ($this->entity->getCacheTags() as $cache_tag) {
128         $this->assertCacheTag($cache_tag);
129       }
130
131       foreach ($ops as $op => $label) {
132         if ($op != $current_op) {
133           $this->assertNoLink($label, format_string('No %op link found.', ['%op' => $label]));
134         }
135         else {
136           $this->assertLink($label, 0, format_string('%op link found.', ['%op' => $label]));
137         }
138       }
139     }
140   }
141
142   /**
143    * Checks that workflows have the expected behaviors for the given user.
144    *
145    * @param \Drupal\user\UserInterface $user
146    *   The user to test the workflow behavior against.
147    * @param array $expected_status
148    *   The an associative array with the operation name as key and the expected
149    *   status as value.
150    */
151   protected function doTestWorkflows(UserInterface $user, $expected_status) {
152     $default_langcode = $this->langcodes[0];
153     $languages = $this->container->get('language_manager')->getLanguages();
154     $args = ['@user_label' => $user->getUsername()];
155     $options = ['language' => $languages[$default_langcode], 'absolute' => TRUE];
156     $this->drupalLogin($user);
157
158     // Check whether the user is allowed to access the entity form in edit mode.
159     $edit_url = $this->entity->urlInfo('edit-form', $options);
160     $this->drupalGet($edit_url, $options);
161     $this->assertResponse($expected_status['edit'], SafeMarkup::format('The @user_label has the expected edit access.', $args));
162
163     // Check whether the user is allowed to access the entity delete form.
164     $delete_url = $this->entity->urlInfo('delete-form', $options);
165     $this->drupalGet($delete_url, $options);
166     $this->assertResponse($expected_status['delete'], SafeMarkup::format('The @user_label has the expected delete access.', $args));
167
168     // Check whether the user is allowed to access the translation overview.
169     $langcode = $this->langcodes[1];
170     $options['language'] = $languages[$langcode];
171     $translations_url = $this->entity->url('drupal:content-translation-overview', $options);
172     $this->drupalGet($translations_url);
173     $this->assertResponse($expected_status['overview'], SafeMarkup::format('The @user_label has the expected translation overview access.', $args));
174
175     // Check whether the user is allowed to create a translation.
176     $add_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_add", [$this->entityTypeId => $this->entity->id(), 'source' => $default_langcode, 'target' => $langcode], $options);
177     if ($expected_status['add_translation'] == 200) {
178       $this->clickLink('Add');
179       $this->assertUrl($add_translation_url->toString(), [], 'The translation overview points to the translation form when creating translations.');
180       // Check that the translation form does not contain shared elements for
181       // translators.
182       if ($expected_status['edit'] == 403) {
183         $this->assertNoSharedElements();
184       }
185     }
186     else {
187       $this->drupalGet($add_translation_url);
188     }
189     $this->assertResponse($expected_status['add_translation'], SafeMarkup::format('The @user_label has the expected translation creation access.', $args));
190
191     // Check whether the user is allowed to edit a translation.
192     $langcode = $this->langcodes[2];
193     $options['language'] = $languages[$langcode];
194     $edit_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_edit", [$this->entityTypeId => $this->entity->id(), 'language' => $langcode], $options);
195     if ($expected_status['edit_translation'] == 200) {
196       $this->drupalGet($translations_url);
197       $editor = $expected_status['edit'] == 200;
198
199       if ($editor) {
200         $this->clickLink('Edit', 2);
201         // An editor should be pointed to the entity form in multilingual mode.
202         // We need a new expected edit path with a new language.
203         $expected_edit_path = $this->entity->url('edit-form', $options);
204         $this->assertUrl($expected_edit_path, [], 'The translation overview points to the edit form for editors when editing translations.');
205       }
206       else {
207         $this->clickLink('Edit');
208         // While a translator should be pointed to the translation form.
209         $this->assertUrl($edit_translation_url->toString(), [], 'The translation overview points to the translation form for translators when editing translations.');
210         // Check that the translation form does not contain shared elements.
211         $this->assertNoSharedElements();
212       }
213     }
214     else {
215       $this->drupalGet($edit_translation_url);
216     }
217     $this->assertResponse($expected_status['edit_translation'], SafeMarkup::format('The @user_label has the expected translation edit access.', $args));
218
219     // Check whether the user is allowed to delete a translation.
220     $langcode = $this->langcodes[2];
221     $options['language'] = $languages[$langcode];
222     $delete_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_delete", [$this->entityTypeId => $this->entity->id(), 'language' => $langcode], $options);
223     if ($expected_status['delete_translation'] == 200) {
224       $this->drupalGet($translations_url);
225       $editor = $expected_status['delete'] == 200;
226
227       if ($editor) {
228         $this->clickLink('Delete', 2);
229         // An editor should be pointed to the entity deletion form in
230         // multilingual mode. We need a new expected delete path with a new
231         // language.
232         $expected_delete_path = $this->entity->url('delete-form', $options);
233         $this->assertUrl($expected_delete_path, [], 'The translation overview points to the delete form for editors when deleting translations.');
234       }
235       else {
236         $this->clickLink('Delete');
237         // While a translator should be pointed to the translation deletion
238         // form.
239         $this->assertUrl($delete_translation_url->toString(), [], 'The translation overview points to the translation deletion form for translators when deleting translations.');
240       }
241     }
242     else {
243       $this->drupalGet($delete_translation_url);
244     }
245     $this->assertResponse($expected_status['delete_translation'], SafeMarkup::format('The @user_label has the expected translation deletion access.', $args));
246   }
247
248   /**
249    * Assert that the current page does not contain shared form elements.
250    */
251   protected function assertNoSharedElements() {
252     $language_none = LanguageInterface::LANGCODE_NOT_SPECIFIED;
253     return $this->assertNoFieldByXPath("//input[@name='field_test_text[$language_none][0][value]']", NULL, 'Shared elements are not available on the translation form.');
254   }
255
256 }