taxonomy_access.test 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620
  1. <?php
  2. /**
  3. * @file
  4. * Automated tests for the Taxonomy Access Control module.
  5. */
  6. /**
  7. * Provides a base test class and helper methods for automated tests.
  8. */
  9. class TaxonomyAccessTestCase extends DrupalWebTestCase {
  10. // There are four types of users:
  11. // site admins, taxonomy admins, content editors, and regular users.
  12. protected $users = array();
  13. protected $user_roles = array();
  14. protected $user_config = array(
  15. 'site_admin' => array(
  16. 'access content',
  17. 'access site reports',
  18. 'access administration pages',
  19. 'administer permissions',
  20. 'create article content',
  21. 'edit any article content',
  22. 'create page content',
  23. 'edit any page content',
  24. ),
  25. 'tax_admin' => array(
  26. 'access content',
  27. 'administer taxonomy',
  28. ),
  29. 'editor' => array(
  30. 'access content',
  31. 'create article content',
  32. 'create page content',
  33. ),
  34. 'regular_user' =>
  35. array(
  36. 'access content',
  37. ),
  38. );
  39. public function setUp() {
  40. // Enable module and dependencies.
  41. parent::setUp('taxonomy_access');
  42. // Rebuild node access on installation.
  43. node_access_rebuild();
  44. // Configure users with base permission patterns.
  45. foreach ($this->user_config as $user => $permissions) {
  46. $this->users[$user] = $this->drupalCreateUser($permissions);
  47. // Save the role ID separately so it's easy to retrieve.
  48. foreach ($this->users[$user]->roles as $rid => $role) {
  49. if ($rid != DRUPAL_AUTHENTICATED_RID) {
  50. $this->user_roles[$user] = user_role_load($rid);
  51. }
  52. }
  53. }
  54. // Give the anonymous and authenticated roles ignore grants.
  55. $rows = array();
  56. foreach (array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) as $rid) {
  57. $ignore = array(
  58. 'view' => TAXONOMY_ACCESS_NODE_IGNORE,
  59. 'update' => TAXONOMY_ACCESS_NODE_IGNORE,
  60. 'delete' => TAXONOMY_ACCESS_NODE_IGNORE,
  61. );
  62. $rows[] = _taxonomy_access_format_grant_record(TAXONOMY_ACCESS_GLOBAL_DEFAULT, $rid, $ignore, TRUE);
  63. }
  64. taxonomy_access_set_default_grants($rows);
  65. foreach (array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) as $rid) {
  66. $r =
  67. db_query(
  68. 'SELECT grant_view FROM {taxonomy_access_default}
  69. WHERE vid = :vid AND rid = :rid',
  70. array(':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT, ':rid' => $rid)
  71. )
  72. ->fetchField();
  73. $this->assertTrue(is_numeric($r) && $r == 0, t("Set global default for role %rid to <em>Ignore</em>", array('%rid' => $rid)));
  74. }
  75. }
  76. /**
  77. * Creates a vocabulary with a certain name.
  78. *
  79. * @param string $machine_name
  80. * A machine-safe name.
  81. *
  82. * @return object
  83. * The vocabulary object.
  84. */
  85. function createVocab($machine_name) {
  86. $vocabulary = new stdClass();
  87. $vocabulary->name = $machine_name;
  88. $vocabulary->description = $this->randomName();
  89. $vocabulary->machine_name = $machine_name;
  90. $vocabulary->help = '';
  91. $vocabulary->weight = mt_rand(0, 10);
  92. taxonomy_vocabulary_save($vocabulary);
  93. return $vocabulary;
  94. }
  95. /**
  96. * Creates a new term in the specified vocabulary.
  97. *
  98. * @param string $machine_name
  99. * A machine-safe name.
  100. * @param object $vocab
  101. * A vocabulary object.
  102. * @param int|null $parent
  103. * (optional) The tid of the parent term, if any. Defaults to NULL.
  104. *
  105. * @return object
  106. * The taxonomy term object.
  107. */
  108. function createTerm($machine_name, $vocab, $parent = NULL) {
  109. $term = new stdClass();
  110. $term->name = $machine_name;
  111. $term->description = $machine_name;
  112. // Use the first available text format.
  113. $term->format =
  114. db_query_range('SELECT format FROM {filter_format}', 0, 1)->fetchField();
  115. $term->vid = $vocab->vid;
  116. $term->vocabulary_machine_name = $vocab->machine_name;
  117. if (!is_null($parent)) {
  118. $term->parent = $parent;
  119. }
  120. taxonomy_term_save($term);
  121. return $term;
  122. }
  123. /**
  124. * Creates a taxonomy field and adds it to the page content type.
  125. *
  126. * @param string $machine_name
  127. * The machine name of the vocabulary to use.
  128. * @param string $widget
  129. * (optional) The name of the widget to use. Defaults to 'options_select'.
  130. * @param int $count
  131. * (optional) The allowed number of values. Defaults to unlimited.
  132. *
  133. * @return array
  134. * Array of instance data.
  135. */
  136. function createField($machine_name, $widget = 'options_select', $count = FIELD_CARDINALITY_UNLIMITED) {
  137. $field = array(
  138. 'field_name' => $machine_name,
  139. 'type' => 'taxonomy_term_reference',
  140. 'cardinality' => $count,
  141. 'settings' => array(
  142. 'allowed_values' => array(
  143. array(
  144. 'vocabulary' => $machine_name,
  145. 'parent' => 0,
  146. ),
  147. ),
  148. ),
  149. );
  150. $field = field_create_field($field);
  151. $instance = array(
  152. 'field_name' => $machine_name,
  153. 'bundle' => 'page',
  154. 'entity_type' => 'node',
  155. 'widget' => array(
  156. 'type' => $widget,
  157. ),
  158. 'display' => array(
  159. 'default' => array(
  160. 'type' => 'taxonomy_term_reference_link',
  161. ),
  162. ),
  163. );
  164. return field_create_instance($instance);
  165. }
  166. /**
  167. * Creates an article with the specified terms.
  168. *
  169. * @param array $autocreate
  170. * (optional) An array of term names to autocreate. Defaults to array().
  171. * @param array $existing
  172. * (optional) An array of existing term IDs to add.
  173. *
  174. * @return object
  175. * The node object.
  176. */
  177. function createArticle($autocreate = array(), $existing = array()) {
  178. $values = array();
  179. foreach ($autocreate as $name) {
  180. $values[] = array('tid' => 'autocreate', 'vid' => 1, 'name' => $name, 'vocabulary_machine_name' => 'tags');
  181. }
  182. foreach ($existing as $tid) {
  183. $values[] = array('tid' => $tid, 'vid' => 1, 'vocabulary_machine_name' => 'tags');
  184. }
  185. // Bloody $langcodes.
  186. $values = array(LANGUAGE_NONE => $values);
  187. $settings = array(
  188. 'type' => 'article',
  189. 'field_tags' => $values,
  190. );
  191. return $this->drupalCreateNode($settings);
  192. }
  193. /**
  194. * Submits the node access rebuild form.
  195. */
  196. function rebuild() {
  197. $this->drupalPost('admin/reports/status/rebuild', array(), t('Rebuild permissions'));
  198. $this->assertText(t('The content access permissions have been rebuilt.'));
  199. }
  200. /**
  201. * Asserts that a status column and "Configure" link is found for the role.
  202. *
  203. * @param array $statuses
  204. * An associative array of role statuses, keyed by role ID. Each item
  205. * should be TRUE if the role is enabled, and FALSE otherwise.
  206. */
  207. function checkRoleConfig(array $statuses) {
  208. $roles = _taxonomy_access_user_roles();
  209. // Log in as the administrator.
  210. $this->drupalLogout();
  211. $this->drupalLogin($this->users['site_admin']);
  212. $this->drupalGet(TAXONOMY_ACCESS_CONFIG);
  213. foreach ($statuses as $rid => $status) {
  214. // Assert that a "Configure" link is available for the role.
  215. $this->assertLinkByHref(
  216. TAXONOMY_ACCESS_CONFIG . "/role/$rid/edit",
  217. 0,
  218. t('"Configure" link is available for role %rid.', array('%rid' => $rid)));
  219. }
  220. // Retrieve the grant status table.
  221. $shown = array();
  222. $table = $this->xpath('//table/tbody');
  223. $table = reset($table);
  224. // SimpleXML has fake arrays so we have to do this to get the data out.
  225. foreach ($table->tr as $row) {
  226. $tds = array();
  227. foreach ($row->td as $value) {
  228. $tds[] = (string) $value;
  229. }
  230. $shown[$tds[0]] = $tds[1];
  231. }
  232. foreach ($statuses as $rid => $status) {
  233. // Assert that the form shows the passed status.
  234. if ($status) {
  235. $this->assertTrue(
  236. $shown[$roles[$rid]] == t('Enabled'),
  237. format_string('Role %role is enabled.', array('%role' => $rid)));
  238. }
  239. else {
  240. $this->assertTrue(
  241. $shown[$roles[$rid]] == t('Disabled'),
  242. format_string('Role %role is disabled.', array('%role' => $rid)));
  243. }
  244. // Assert that a "Configure" link is available for the role.
  245. $this->assertLinkByHref(
  246. TAXONOMY_ACCESS_CONFIG . "/role/$rid/edit",
  247. 0,
  248. t('"Configure" link is available for role %rid.',
  249. array('%rid' => $rid)));
  250. }
  251. }
  252. /**
  253. * Asserts that an enable link is or is not found for the role.
  254. *
  255. * @param int $rid
  256. * The role ID to check.
  257. * @param bool $found
  258. * Whether the link should be found, or not.
  259. */
  260. function checkRoleEnableLink($rid, $found) {
  261. if ($found) {
  262. $this->assertLinkByHref(
  263. TAXONOMY_ACCESS_CONFIG . "/role/$rid/enable",
  264. 0,
  265. t('Enable link is available for role %rid.', array('%rid' => $rid))
  266. );
  267. }
  268. else {
  269. $this->assertNoLinkByHref(
  270. TAXONOMY_ACCESS_CONFIG . "/role/$rid/enable",
  271. t('Enable link is not available for role %rid.', array('%rid' => $rid))
  272. );
  273. }
  274. }
  275. /**
  276. * Asserts that a disable link is or is not found for the role.
  277. *
  278. * @param int $rid
  279. * The role ID to check.
  280. * @param bool $found
  281. * Whether the link should be found, or not.
  282. */
  283. function checkRoleDisableLink($rid, $found) {
  284. if ($found) {
  285. $this->assertLinkByHref(
  286. TAXONOMY_ACCESS_CONFIG . "/role/$rid/delete",
  287. 0,
  288. t('Disable link is available for role %rid.', array('%rid' => $rid))
  289. );
  290. }
  291. else {
  292. $this->assertNoLinkByHref(
  293. TAXONOMY_ACCESS_CONFIG . "/role/$rid/delete",
  294. t('Disable link is not available for role %rid.', array('%rid' => $rid))
  295. );
  296. }
  297. }
  298. /**
  299. * Adds a term row on the role configuration form.
  300. *
  301. * @param array &$edit
  302. * The form data to post.
  303. * @param int $vid
  304. * (optional) The vocabulary ID. Defaults to
  305. * TAXONOMY_ACCESS_GLOBAL_DEFAULT.
  306. * @param $int tid
  307. * (optional) The term ID. Defaults to TAXONOMY_ACCESS_VOCABULARY_DEFAULT.
  308. * @param int $view
  309. * (optional) The view grant value. Defaults to
  310. * TAXONOMY_ACCESS_NODE_IGNORE.
  311. * @param int $update
  312. * (optional) The update grant value. Defaults to
  313. * @param int $delete
  314. * (optional) The delete grant value. Defaults to
  315. * TAXONOMY_ACCESS_NODE_IGNORE.
  316. * @param int $create
  317. * (optional) The create grant value. Defaults to
  318. * TAXONOMY_ACCESS_TERM_DENY.
  319. * @param int $list
  320. * (optional) The list grant value. Defaults to TAXONOMY_ACCESS_TERM_DENY.
  321. */
  322. function addFormRow(&$edit, $vid = TAXONOMY_ACCESS_GLOBAL_DEFAULT, $tid = TAXONOMY_ACCESS_VOCABULARY_DEFAULT, $view = TAXONOMY_ACCESS_NODE_IGNORE, $update = TAXONOMY_ACCESS_NODE_IGNORE, $delete = TAXONOMY_ACCESS_NODE_IGNORE, $create = TAXONOMY_ACCESS_TERM_DENY, $list = TAXONOMY_ACCESS_TERM_DENY) {
  323. $new_value = $tid ? "term $tid" : "default $vid";
  324. $edit["new[$vid][item]"] = $new_value;
  325. $edit["new[$vid][grants][$vid][0][view]"] = $view;
  326. $edit["new[$vid][grants][$vid][0][update]"] = $update;
  327. $edit["new[$vid][grants][$vid][0][delete]"] = $delete;
  328. $edit["new[$vid][grants][$vid][0][create]"] = $create;
  329. $edit["new[$vid][grants][$vid][0][list]"] = $list;
  330. }
  331. /**
  332. * Configures a row on the TAC configuration form.
  333. *
  334. * @param array &$edit
  335. * The form data to post.
  336. * @param int $vid
  337. * (optional) The vocabulary ID. Defaults to
  338. * TAXONOMY_ACCESS_GLOBAL_DEFAULT.
  339. * @param $int tid
  340. * (optional) The term ID. Defaults to TAXONOMY_ACCESS_VOCABULARY_DEFAULT.
  341. * @param int $view
  342. * (optional) The view grant value. Defaults to
  343. * TAXONOMY_ACCESS_NODE_IGNORE.
  344. * @param int $update
  345. * (optional) The update grant value. Defaults to
  346. * @param int $delete
  347. * (optional) The delete grant value. Defaults to
  348. * TAXONOMY_ACCESS_NODE_IGNORE.
  349. * @param int $create
  350. * (optional) The create grant value. Defaults to
  351. * TAXONOMY_ACCESS_TERM_DENY.
  352. * @param int $list
  353. * (optional) The list grant value. Defaults to TAXONOMY_ACCESS_TERM_DENY.
  354. */
  355. function configureFormRow(&$edit, $vid = TAXONOMY_ACCESS_GLOBAL_DEFAULT, $tid = TAXONOMY_ACCESS_VOCABULARY_DEFAULT, $view = TAXONOMY_ACCESS_NODE_IGNORE, $update = TAXONOMY_ACCESS_NODE_IGNORE, $delete = TAXONOMY_ACCESS_NODE_IGNORE, $create = TAXONOMY_ACCESS_TERM_DENY, $list = TAXONOMY_ACCESS_TERM_DENY) {
  356. $edit["grants[$vid][$tid][view]"] = $view;
  357. $edit["grants[$vid][$tid][update]"] = $update;
  358. $edit["grants[$vid][$tid][delete]"] = $delete;
  359. $edit["grants[$vid][$tid][create]"] = $create;
  360. $edit["grants[$vid][$tid][list]"] = $list;
  361. }
  362. }
  363. /**
  364. * Tests the module's response to changes from other modules.
  365. */
  366. class TaxonomyAccessExternalChanges extends TaxonomyAccessTestCase {
  367. public static function getInfo() {
  368. return array(
  369. 'name' => 'External changes',
  370. 'description' => "Test the module's response to changes from other modules.",
  371. 'group' => 'Taxonomy Access Control',
  372. );
  373. }
  374. public function setUp() {
  375. parent::setUp();
  376. }
  377. /*
  378. 1. delete a term
  379. 2. delete a role
  380. 3. delete a field attachment
  381. 4. modify a field attachment
  382. 5. delete a vocabulary
  383. 6. add terms to node
  384. 7. remove terms from node
  385. */
  386. }
  387. /**
  388. * Tests the module's configuration forms.
  389. */
  390. class TaxonomyAccessConfigTest extends TaxonomyAccessTestCase {
  391. protected $articles = array();
  392. protected $pages = array();
  393. protected $vocabs = array();
  394. protected $terms = array();
  395. public static function getInfo() {
  396. return array(
  397. 'name' => 'Configuration forms',
  398. 'description' => 'Test module configuration forms.',
  399. 'group' => 'Taxonomy Access Control',
  400. );
  401. }
  402. public function setUp() {
  403. parent::setUp();
  404. // Add two taxonomy fields to pages.
  405. foreach (array('v1', 'v2') as $vocab) {
  406. $this->vocabs[$vocab] = $this->createVocab($vocab);
  407. $this->createField($vocab);
  408. $this->terms[$vocab . 't1'] =
  409. $this->createTerm($vocab . 't1', $this->vocabs[$vocab]);
  410. $this->terms[$vocab . 't2'] =
  411. $this->createTerm($vocab . 't2', $this->vocabs[$vocab]);
  412. }
  413. // Set up a variety of nodes with different term combinations.
  414. $this->articles['no_tags'] = $this->createArticle();
  415. $this->articles['one_tag'] =
  416. $this->createArticle(array($this->randomName()));
  417. $this->articles['two_tags'] =
  418. $this->createArticle(array($this->randomName(), $this->randomName()));
  419. $this->pages['no_tags'] = $this->createPage();
  420. foreach ($this->terms as $t1) {
  421. $this->pages[$t1->name] = $this->createPage(array($t1->name));
  422. foreach ($this->terms as $t2) {
  423. $this->pages[$t1->name . '_' . $t2->name] =
  424. $this->createPage(array($t1->name, $t2->name));
  425. }
  426. }
  427. }
  428. /**
  429. * Creates a page with the specified terms.
  430. *
  431. * @param array $terms
  432. * (optional) An array of term names to tag the page. Defaults to array().
  433. *
  434. * @return object
  435. * The node object.
  436. */
  437. function createPage($tags = array()) {
  438. $v1 = array();
  439. $v2 = array();
  440. foreach ($tags as $name) {
  441. switch ($this->terms[$name]->vid) {
  442. case ($this->vocabs['v1']->vid):
  443. $v1[] = array('tid' => $this->terms[$name]->tid);
  444. break;
  445. case ($this->vocabs['v2']->vid):
  446. $v2[] = array('tid' => $this->terms[$name]->tid);
  447. break;
  448. }
  449. }
  450. // Bloody $langcodes.
  451. $v1 = array(LANGUAGE_NONE => $v1);
  452. $v2 = array(LANGUAGE_NONE => $v2);
  453. $settings = array(
  454. 'type' => 'page',
  455. 'v1' => $v1,
  456. 'v2' => $v2,
  457. );
  458. return $this->drupalCreateNode($settings);
  459. }
  460. /*
  461. @todo
  462. - check anon and auth forms
  463. - add recursive for vocab and for term
  464. - change multiple
  465. - delete multiple
  466. - configure create and list
  467. */
  468. /**
  469. * Tests the initial state of the test environment.
  470. *
  471. * Verifies that:
  472. * - Access to all nodes is denied for anonymous users.
  473. * - The main admin page provides the correct configuration links.
  474. */
  475. public function testSetUpCheck() {
  476. // Visit all nodes as anonymous and verify that access is denied.
  477. foreach ($this->articles as $key => $article) {
  478. $this->drupalGet('node/' . $article->nid);
  479. $this->assertResponse(403, t("Access to %name article (nid %nid) is denied.", array('%name' => $key, '%nid' => $article->nid)));
  480. }
  481. foreach ($this->pages as $key => $page) {
  482. $this->drupalGet('node/' . $page->nid);
  483. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  484. }
  485. // Log in as the regular_user.
  486. $this->drupalLogin($this->users['regular_user']);
  487. // Visit all nodes and verify that access is denied.
  488. foreach ($this->articles as $key => $article) {
  489. $this->drupalGet('node/' . $article->nid);
  490. $this->assertResponse(403, t("Access to %name article (nid %nid) is denied.", array('%name' => $key, '%nid' => $article->nid)));
  491. }
  492. foreach ($this->pages as $key => $page) {
  493. $this->drupalGet('node/' . $page->nid);
  494. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  495. }
  496. // Log in as the administrator.
  497. $this->drupalLogin($this->users['site_admin']);
  498. // Confirm that only edit links are available for anon. and auth.
  499. $this->checkRoleConfig(array(
  500. DRUPAL_ANONYMOUS_RID => TRUE,
  501. DRUPAL_AUTHENTICATED_RID => TRUE,
  502. ));
  503. }
  504. /**
  505. * Tests configuring a global default.
  506. *
  507. * Verifies that:
  508. * - Access is updated for all nodes when there are no other configurations.
  509. * - Access is updated for the correct nodes when there are specific term
  510. * and vocabulary configurations.
  511. */
  512. public function testGlobalDefaultConfig() {
  513. // Log in as the administrator.
  514. $this->drupalLogin($this->users['site_admin']);
  515. // Use the admin form to give anonymous view allow in the global default.
  516. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  517. $edit = array();
  518. $this->configureFormRow($edit, TAXONOMY_ACCESS_GLOBAL_DEFAULT, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_ALLOW);
  519. $this->drupalPost(NULL, $edit, 'Save all');
  520. // Log out.
  521. $this->drupalLogout();
  522. // Visit each node and verify that access is allowed.
  523. foreach ($this->articles as $key => $article) {
  524. $this->drupalGet('node/' . $article->nid);
  525. $this->assertResponse(200, t("Access to %name article (nid %nid) is allowed.", array('%name' => $key, '%nid' => $article->nid)));
  526. }
  527. foreach ($this->pages as $key => $page) {
  528. $this->drupalGet('node/' . $page->nid);
  529. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  530. }
  531. // Add some specific configurations programmatically.
  532. // Set the v1 default to view allow.
  533. $default_config = _taxonomy_access_format_grant_record(
  534. $this->vocabs['v1']->vid, DRUPAL_ANONYMOUS_RID, array('view' => TAXONOMY_ACCESS_NODE_ALLOW), TRUE
  535. );
  536. taxonomy_access_set_default_grants(array($default_config));
  537. // Set v1t1 and v2t1 to view allow.
  538. $term_configs = array();
  539. foreach (array('v1t1', 'v2t1') as $name) {
  540. $term_configs[] = _taxonomy_access_format_grant_record(
  541. $this->terms[$name]->vid, DRUPAL_ANONYMOUS_RID, array('view' => TAXONOMY_ACCESS_NODE_ALLOW)
  542. );
  543. }
  544. taxonomy_access_set_term_grants($term_configs);
  545. // This leaves articles and the v2t2 page controlled by the global default.
  546. // Log in as the administrator.
  547. $this->drupalLogin($this->users['site_admin']);
  548. // Use the admin form to give anonymous view deny in the global default.
  549. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  550. $edit = array();
  551. $this->configureFormRow($edit, TAXONOMY_ACCESS_GLOBAL_DEFAULT, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_DENY);
  552. $this->drupalPost(NULL, $edit, 'Save all');
  553. // Log out.
  554. $this->drupalLogout();
  555. // Visit each artile and verify that access is denied.
  556. foreach ($this->articles as $key => $article) {
  557. $this->drupalGet('node/' . $article->nid);
  558. $this->assertResponse(403, t("Access to %name article (nid %nid) is denied.", array('%name' => $key, '%nid' => $article->nid)));
  559. }
  560. // Visit each page.
  561. foreach ($this->pages as $key => $page) {
  562. $this->drupalGet('node/' . $page->nid);
  563. switch (TRUE) {
  564. // If the page has no tags, access should be denied.
  565. case ($key == 'no_tags'):
  566. // If the page is tagged with v2t2, access should be denied.
  567. case (strpos($key, 'v2t2') !== FALSE):
  568. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  569. break;
  570. // Otherwise, access should be allowed.
  571. default:
  572. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  573. break;
  574. }
  575. }
  576. }
  577. /**
  578. * Tests configuring vocabulary defaults.
  579. *
  580. * Verifies that:
  581. * - Access is updated correctly when the vocabulary default is added and
  582. * configured.
  583. * - Access is updated correctly when there is a specific term configuration
  584. * in the vocabulary.
  585. * - Access is updated correctly when multiple defaults are changed.
  586. * - Access is updated correctly when the vocabulary default is deleted.
  587. */
  588. public function testVocabularyDefaultConfig() {
  589. // Log in as the administrator.
  590. $this->drupalLogin($this->users['site_admin']);
  591. // Enable the vocabulary.
  592. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  593. // @todo
  594. // - Ensure that all vocabularies are options in the "Add" fieldset.
  595. $edit = array();
  596. $edit['enable_vocab'] = $this->vocabs['v1']->vid;
  597. $this->drupalPost(NULL, $edit, t('Add'));
  598. // @todo
  599. // - Ensure that the vocabulary is removed from the "Add" fieldset.
  600. // - Ensure that the fieldset for the vocabulary appears.
  601. // - Ensure that no other fieldsets or rows appear.
  602. // Give anonymous view allow for the v1 default.
  603. $edit = array();
  604. $this->configureFormRow($edit, $this->vocabs['v1']->vid, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_ALLOW);
  605. $this->drupalPost(NULL, $edit, 'Save all');
  606. // Log out.
  607. $this->drupalLogout();
  608. // Visit each page and verify whether access is allowed or denied.
  609. foreach ($this->pages as $key => $page) {
  610. $this->drupalGet('node/' . $page->nid);
  611. // If the page is tagged with a v1 term, access should be allowed.
  612. if (strpos($key, 'v1') !== FALSE) {
  613. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  614. }
  615. // Otherwise, access should be denied.
  616. else {
  617. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  618. }
  619. }
  620. // Programmatically enable v2 and add a specific configuration for v2t1.
  621. taxonomy_access_enable_vocab($this->vocabs['v2']->vid, DRUPAL_ANONYMOUS_RID);
  622. $term_config = _taxonomy_access_format_grant_record(
  623. $this->terms['v2t1']->tid, DRUPAL_ANONYMOUS_RID, array('view' => TAXONOMY_ACCESS_NODE_IGNORE)
  624. );
  625. taxonomy_access_set_term_grants(array($term_config));
  626. // Log in as the administrator.
  627. $this->drupalLogin($this->users['site_admin']);
  628. // Use the admin form to give anonymous view deny for the v2 default.
  629. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  630. $edit = array();
  631. $this->configureFormRow($edit, $this->vocabs['v2']->vid, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_DENY);
  632. $this->drupalPost(NULL, $edit, 'Save all');
  633. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  634. // Log out.
  635. $this->drupalLogout();
  636. // Visit each page and verify whether access is allowed or denied.
  637. foreach ($this->pages as $key => $page) {
  638. $this->drupalGet('node/' . $page->nid);
  639. switch (TRUE) {
  640. // If the page is tagged with v2t2, the v2 default is inherited: Deny.
  641. case (strpos($key, 'v2t2') !== FALSE):
  642. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  643. break;
  644. // Otherwise, if the page is tagged with v1, it's allowed.
  645. case (strpos($key, 'v1') !== FALSE):
  646. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  647. break;
  648. // Access should be denied by default.
  649. default:
  650. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  651. break;
  652. }
  653. }
  654. // Log in as the administrator.
  655. $this->drupalLogin($this->users['site_admin']);
  656. // Use the form to change the configuration: Allow for v2; Deny for v1.
  657. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  658. $edit = array();
  659. $this->configureFormRow($edit, $this->vocabs['v2']->vid, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_ALLOW);
  660. $this->configureFormRow($edit, $this->vocabs['v1']->vid, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_DENY);
  661. $this->drupalPost(NULL, $edit, 'Save all');
  662. // Log out.
  663. $this->drupalLogout();
  664. // Visit each page and verify whether access is allowed or denied.
  665. foreach ($this->pages as $key => $page) {
  666. $this->drupalGet('node/' . $page->nid);
  667. switch (TRUE) {
  668. // If the page is tagged with a v1 term, access should be denied.
  669. case (strpos($key, 'v1') !== FALSE):
  670. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  671. break;
  672. // Otherwise, if the page is tagged with v2t2, the default is
  673. // inherited and access should be allowed.
  674. case (strpos($key, 'v2t2') !== FALSE):
  675. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  676. break;
  677. // Access should be denied by default.
  678. default:
  679. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  680. break;
  681. }
  682. }
  683. // Log in as the administrator.
  684. $this->drupalLogin($this->users['site_admin']);
  685. // Use the admin form to disable v1.
  686. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  687. $this->clickLink(t('delete all v1 access rules'));
  688. $this->assertText("Are you sure you want to delete all Taxonomy access rules for v1", t('Disable form for vocabulary loaded.'));
  689. $this->drupalPost(NULL, array(), 'Delete all');
  690. // Log out.
  691. $this->drupalLogout();
  692. // Visit each page and verify whether access is allowed or denied.
  693. foreach ($this->pages as $key => $page) {
  694. $this->drupalGet('node/' . $page->nid);
  695. // If the page is tagged with v2t2, access should be allowed.
  696. if (strpos($key, 'v2t2') !== FALSE) {
  697. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  698. }
  699. // Otherwise, access should be denied.
  700. else {
  701. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  702. }
  703. }
  704. }
  705. /**
  706. * Tests configuring specific terms.
  707. *
  708. * Verifies that:
  709. * - Access is updated correctly when the term configuration is added.
  710. * - Access is updated correctly when there is a vocabulary default.
  711. * - Access is updated correctly when multiple configurations are changed.
  712. * - Access is updated correctly when the term configuration is deleted.
  713. */
  714. public function testTermConfig() {
  715. // Log in as the administrator.
  716. $this->drupalLogin($this->users['site_admin']);
  717. // Use the admin form to enable v1 and give anonymous view allow for v1t1.
  718. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  719. $edit = array();
  720. $edit['enable_vocab'] = $this->vocabs['v1']->vid;
  721. $this->drupalPost(NULL, $edit, t('Add'));
  722. $edit = array();
  723. $this->addFormRow($edit, $this->vocabs['v1']->vid, $this->terms['v1t1']->tid, TAXONOMY_ACCESS_NODE_ALLOW);
  724. $this->drupalPost(NULL, $edit, 'Add');
  725. // Log out.
  726. $this->drupalLogout();
  727. // Visit each page and verify whether access is allowed or denied.
  728. foreach ($this->pages as $key => $page) {
  729. $this->drupalGet('node/' . $page->nid);
  730. // If the page is tagged with v1t1, access should be allowed.
  731. if (strpos($key, 'v1t1') !== FALSE) {
  732. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  733. }
  734. // Otherwise, access should be denied.
  735. else {
  736. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  737. }
  738. }
  739. // Enable v2 programmatically.
  740. taxonomy_access_enable_vocab($this->vocabs['v2']->vid, DRUPAL_ANONYMOUS_RID);
  741. // Log in as the administrator.
  742. $this->drupalLogin($this->users['site_admin']);
  743. // Use the admin form to give anonymous view deny for v2t1.
  744. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  745. $edit = array();
  746. $this->addFormRow($edit, $this->vocabs['v2']->vid, $this->terms['v2t1']->tid, TAXONOMY_ACCESS_NODE_DENY);
  747. $this->drupalPost(NULL, $edit, 'Add');
  748. // Log out.
  749. $this->drupalLogout();
  750. // Visit each page and verify whether access is allowed or denied.
  751. foreach ($this->pages as $key => $page) {
  752. $this->drupalGet('node/' . $page->nid);
  753. switch (TRUE) {
  754. // If the page is tagged with v2t1, access should be denied.
  755. case (strpos($key, 'v2t1') !== FALSE):
  756. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  757. break;
  758. // Otherwise, if the page is tagged with v1t1, it's allowed.
  759. case (strpos($key, 'v1t1') !== FALSE):
  760. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  761. break;
  762. // Access should be denied by default.
  763. default:
  764. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  765. break;
  766. }
  767. }
  768. // Log in as the administrator.
  769. $this->drupalLogin($this->users['site_admin']);
  770. // Use the form to change the configuration: Allow for v2t1; Deny for v1t1.
  771. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  772. $edit = array();
  773. $this->configureFormRow(
  774. $edit, $this->vocabs['v2']->vid, $this->terms['v2t1']->tid, TAXONOMY_ACCESS_NODE_ALLOW
  775. );
  776. $this->configureFormRow(
  777. $edit, $this->vocabs['v1']->vid, $this->terms['v1t1']->tid, TAXONOMY_ACCESS_NODE_DENY
  778. );
  779. $this->drupalPost(NULL, $edit, 'Save all');
  780. // Log out.
  781. $this->drupalLogout();
  782. // Visit each page and verify whether access is allowed or denied.
  783. foreach ($this->pages as $key => $page) {
  784. $this->drupalGet('node/' . $page->nid);
  785. switch (TRUE) {
  786. // If the page is tagged with v1t1, access should be denied.
  787. case (strpos($key, 'v1t1') !== FALSE):
  788. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  789. break;
  790. // Otherwise, if the page is tagged with v2t1, it's allowed.
  791. case (strpos($key, 'v2t1') !== FALSE):
  792. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  793. break;
  794. // Access should be denied by default.
  795. default:
  796. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  797. break;
  798. }
  799. }
  800. // Log in as the administrator.
  801. $this->drupalLogin($this->users['site_admin']);
  802. // Use the form to delete the v2t1 configuration.
  803. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  804. $edit = array();
  805. $edit["grants[{$this->vocabs['v2']->vid}][{$this->terms['v2t1']->tid}][remove]"] = 1;
  806. $this->drupalPost(NULL, $edit, 'Delete selected');
  807. // Log out.
  808. $this->drupalLogout();
  809. // Visit each page and verify whether access is allowed or denied.
  810. foreach ($this->pages as $key => $page) {
  811. $this->drupalGet('node/' . $page->nid);
  812. // Access to all pages should be denied.
  813. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  814. }
  815. }
  816. /**
  817. * Tests adding a term configuration with children.
  818. *
  819. * @todo
  820. * Check that node access is updated for these as well.
  821. */
  822. public function testTermWithChildren() {
  823. // Create some additional taxonomy terms in a hierarchy:
  824. // v1
  825. // - v1t1
  826. // - - v1t1c1
  827. // - - - v1t1c1g1
  828. // - - - v1t1c1g2
  829. // - - v1t1c2
  830. // - - v1t2
  831. $this->terms['v1t1c1'] = $this->createTerm(
  832. 'v1t1c1',
  833. $this->vocabs['v1'],
  834. $this->terms['v1t1']->tid
  835. );
  836. $this->terms['v1t1c2'] = $this->createTerm(
  837. 'v1t1c2',
  838. $this->vocabs['v1'],
  839. $this->terms['v1t1']->tid
  840. );
  841. $this->terms['v1t1c1g1'] = $this->createTerm(
  842. 'v1t1c1g1',
  843. $this->vocabs['v1'],
  844. $this->terms['v1t1c1']->tid
  845. );
  846. $this->terms['v1t1c1g2'] = $this->createTerm(
  847. 'v1t1c1g2',
  848. $this->vocabs['v1'],
  849. $this->terms['v1t1c1']->tid
  850. );
  851. // Add pages tagged with each.
  852. foreach (array('v1t1c1', 'v1t1c2', 'v1t1c1g1', 'v1t1c1g2') as $name) {
  853. $this->pages[$name] = $this->createPage(array($name));
  854. }
  855. // Log in as the administrator.
  856. $this->drupalLogin($this->users['site_admin']);
  857. // Enable v1 programmatically.
  858. taxonomy_access_enable_vocab($this->vocabs['v1']->vid, DRUPAL_ANONYMOUS_RID);
  859. // Use the admin form to give anonymous view allow for v1t1 and children.
  860. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . '/role/' . DRUPAL_ANONYMOUS_RID . '/edit');
  861. $edit = array();
  862. $edit["new[{$this->vocabs['v1']->vid}][recursive]"] = 1;
  863. $this->addFormRow($edit, $this->vocabs['v1']->vid, $this->terms['v1t1']->tid, TAXONOMY_ACCESS_NODE_ALLOW);
  864. $this->drupalPost(NULL, $edit, 'Add');
  865. }
  866. /**
  867. * Tests enabling and disabling TAC for a custom role.
  868. */
  869. public function testRoleEnableDisable() {
  870. // Save some typing.
  871. $rid = $this->user_roles['regular_user']->rid;
  872. $name = $this->user_roles['regular_user']->name;
  873. // Check that the role is disabled by default.
  874. $this->checkRoleConfig(array(
  875. DRUPAL_ANONYMOUS_RID => TRUE,
  876. DRUPAL_AUTHENTICATED_RID => TRUE,
  877. $rid => FALSE,
  878. ));
  879. // Test enabling the role.
  880. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . "/role/$rid/edit");
  881. // Check that there is:
  882. // - An enable link
  883. // - No disable link
  884. // @todo
  885. // - No grant tables.
  886. $this->checkRoleEnableLink($rid, TRUE);
  887. $this->checkRoleDisableLink($rid, FALSE);
  888. // Enable the role and check that there is:
  889. // - A disable link
  890. // - No enable link
  891. // @todo
  892. // - A global default table (with correct values?)
  893. // - An "Add vocabulary" fieldset.
  894. // - No vocabulary fieldsets or term data.
  895. $this->clickLink(format_string('Enable @name', array('@name' => $name)));
  896. $this->checkRoleEnableLink($rid, FALSE);
  897. $this->checkRoleDisableLink($rid, TRUE);
  898. // Update the global default to allow view.
  899. $edit = array();
  900. $this->configureFormRow($edit, TAXONOMY_ACCESS_GLOBAL_DEFAULT, TAXONOMY_ACCESS_VOCABULARY_DEFAULT, TAXONOMY_ACCESS_NODE_ALLOW);
  901. $this->drupalPost(NULL, $edit, 'Save all');
  902. // Confirm that all three roles are enabled.
  903. $this->checkRoleConfig(array(
  904. DRUPAL_ANONYMOUS_RID => TRUE,
  905. DRUPAL_AUTHENTICATED_RID => TRUE,
  906. $rid => TRUE,
  907. ));
  908. // Check that the role is configured.
  909. $r =
  910. db_query(
  911. 'SELECT grant_view FROM {taxonomy_access_default}
  912. WHERE vid = :vid AND rid = :rid',
  913. array(':vid' => TAXONOMY_ACCESS_GLOBAL_DEFAULT, ':rid' => $rid)
  914. )
  915. ->fetchField();
  916. $this->assertTrue($r == TAXONOMY_ACCESS_NODE_ALLOW, t('Used form to grant the role %role view in the global default.', array('%role' => $name)));
  917. // Log in as the regular_user.
  918. $this->drupalLogout();
  919. $this->drupalLogin($this->users['regular_user']);
  920. // Visit each node and verify that access is allowed.
  921. foreach ($this->articles as $key => $article) {
  922. $this->drupalGet('node/' . $article->nid);
  923. $this->assertResponse(200, t("Access to %name article (nid %nid) is allowed.", array('%name' => $key, '%nid' => $article->nid)));
  924. }
  925. foreach ($this->pages as $key => $page) {
  926. $this->drupalGet('node/' . $page->nid);
  927. $this->assertResponse(200, t("Access to %name page (nid %nid) is allowed.", array('%name' => $key, '%nid' => $page->nid)));
  928. }
  929. // Log in as the administrator.
  930. $this->drupalLogout();
  931. $this->drupalLogin($this->users['site_admin']);
  932. // Test disabling the role.
  933. $this->drupalGet(TAXONOMY_ACCESS_CONFIG . "/role/$rid/edit");
  934. $this->clickLink(t('Disable @name', array('@name' => $name)));
  935. $this->assertText("Are you sure you want to delete all taxonomy access rules for the role $name", t('Disable form for role loaded.'));
  936. $this->drupalPost(NULL, array(), 'Delete all');
  937. // Confirm that a confirmation message appears.
  938. $this->assertText("All taxonomy access rules deleted for role $name", t('Confirmation message found.'));
  939. // Check that there is:
  940. // - An enable link
  941. // - No disable link
  942. // @todo
  943. // - No grant tables.
  944. $this->checkRoleEnableLink($rid, TRUE);
  945. $this->checkRoleDisableLink($rid, FALSE);
  946. // Confirm edit/enable/disable links are in their original state.
  947. $this->checkRoleConfig(array(
  948. DRUPAL_ANONYMOUS_RID => TRUE,
  949. DRUPAL_AUTHENTICATED_RID => TRUE,
  950. $rid => FALSE,
  951. ));
  952. // Check that the role is no longer configured.
  953. $r =
  954. db_query(
  955. 'SELECT grant_view FROM {taxonomy_access_default}
  956. WHERE rid = :rid',
  957. array(':rid' => $rid)
  958. )
  959. ->fetchAll();
  960. $this->assertTrue(empty($r), t('All records removed for role %role.', array('%role' => $name)));
  961. // @todo
  962. // - Add a term configuration and make sure that gets deleted too.
  963. // Log in as the regular_user.
  964. $this->drupalLogout();
  965. $this->drupalLogin($this->users['regular_user']);
  966. // Visit all nodes and verify that access is again denied.
  967. foreach ($this->articles as $key => $article) {
  968. $this->drupalGet('node/' . $article->nid);
  969. $this->assertResponse(403, t("Access to %name article (nid %nid) is denied.", array('%name' => $key, '%nid' => $article->nid)));
  970. }
  971. foreach ($this->pages as $key => $page) {
  972. $this->drupalGet('node/' . $page->nid);
  973. $this->assertResponse(403, t("Access to %name page (nid %nid) is denied.", array('%name' => $key, '%nid' => $page->nid)));
  974. }
  975. }
  976. }
  977. /**
  978. * Tests node access for all possible grant combinations.
  979. */
  980. class TaxonomyAccessNodeGrantTest extends TaxonomyAccessTestCase {
  981. // There are three roles for node access testing:
  982. // global_allow Receives "Allow" in the global default.
  983. // global_ignore Receives "Ignore" in the global default.
  984. // global_deny Receives "Deny" in the global default.
  985. // All roles receive the same permissions for terms and vocab defaults.
  986. protected $roles = array();
  987. protected $role_config = array(
  988. 'global_allow' => array(),
  989. 'global_ignore' => array(),
  990. 'global_deny' => array(),
  991. );
  992. protected $vocabs = array();
  993. public static function getInfo() {
  994. return array(
  995. 'name' => 'Node access',
  996. 'description' => 'Test node access for various grant configurations.',
  997. 'group' => 'Taxonomy Access Control',
  998. );
  999. }
  1000. public function setUp() {
  1001. parent::setUp();
  1002. // Configure roles with no additional permissions.
  1003. foreach ($this->role_config as $role_name => $permissions) {
  1004. $this->roles[$role_name] = $this->drupalCreateRole(array(), $role_name);
  1005. }
  1006. $node_grants = array('view', 'update', 'delete');
  1007. // Set up our testing taxonomy.
  1008. // We will create 4 vocabularies: a, i, d, and nc
  1009. // These names indicate what grant the vocab. default will have for view.
  1010. // (NC means the vocab default is not configured.)
  1011. $grant_types = array(
  1012. 'a' => array(),
  1013. 'i' => array(),
  1014. 'd' => array(),
  1015. 'nc' => array(),
  1016. );
  1017. // View alone can be used to test V/U/D because the logic is identical.
  1018. foreach ($node_grants as $grant) {
  1019. $grant_types['a'][$grant] = TAXONOMY_ACCESS_NODE_ALLOW;
  1020. $grant_types['i'][$grant] = TAXONOMY_ACCESS_NODE_IGNORE;
  1021. $grant_types['d'][$grant] = TAXONOMY_ACCESS_NODE_DENY;
  1022. }
  1023. // Each vocabulary will have four parent terms in the same fashion:
  1024. // a_parent, i_parent, d_parent, and nc_parent.
  1025. // Each of these_parent terms will have children in each class, as well:
  1026. // a_child, i_child, d_child, and nc_child.
  1027. // So, each vocab looks something like:
  1028. // - a_parent
  1029. // - - a_child
  1030. // - - i_child
  1031. // - - d_child
  1032. // - - nc_child
  1033. // - i_parent
  1034. // - - a_child
  1035. // - - i_child
  1036. // - - d_child
  1037. // - - nc_child
  1038. // - d_parent
  1039. // - - a_child
  1040. // - - i_child
  1041. // - - d_child
  1042. // - - nc_child
  1043. // - nc_parent
  1044. // - - a_child
  1045. // - - i_child
  1046. // - - d_child
  1047. // - - nc_child
  1048. $term_rows = array();
  1049. $default_rows = array();
  1050. $this->setUpAssertions = array();
  1051. // Configure terms, vocabularies, and grants.
  1052. foreach ($grant_types as $vocab_name => $default_grants) {
  1053. // Create the vocabulary.
  1054. $vocab_name = "v" . $vocab_name;
  1055. $this->vocabs[$vocab_name] = array();
  1056. $this->vocabs[$vocab_name]['vocab'] = parent::createVocab($vocab_name);
  1057. $this->vocabs[$vocab_name]['terms'] = array();
  1058. $vocab = $this->vocabs[$vocab_name]['vocab'];
  1059. // Add a field for the vocabulary to pages.
  1060. $this->createField($vocab_name);
  1061. // Configure default grants for the vocabulary for each role.
  1062. if (!empty($default_grants)) {
  1063. foreach ($this->roles as $name => $role) {
  1064. $default_rows[] = _taxonomy_access_format_grant_record($vocab->vid, $role, $default_grants, TRUE);
  1065. $this->setUpAssertions[] = array(
  1066. 'grant' => $default_grants['view'],
  1067. 'query' => 'SELECT grant_view FROM {taxonomy_access_default} WHERE vid = :vid AND rid = :rid',
  1068. 'args' => array(':vid' => $vocab->vid, ':rid' => $role),
  1069. 'message' => t('Configured default grants for vocab %vocab, role %role', array('%vocab' => $vocab->machine_name, '%role' => $name)),
  1070. );
  1071. }
  1072. }
  1073. // Create terms.
  1074. foreach ($grant_types as $parent_name => $parent_grants) {
  1075. // Create parent term.
  1076. $parent_name = $vocab_name . "__" . $parent_name . "_parent";
  1077. $this->vocabs[$vocab_name]['terms'][$parent_name] =
  1078. parent::createTerm($parent_name, $vocab);
  1079. $parent_id = $this->vocabs[$vocab_name]['terms'][$parent_name]->tid;
  1080. // Configure grants for the parent term for each role.
  1081. if (!empty($parent_grants)) {
  1082. foreach ($this->roles as $name => $role) {
  1083. $term_rows[] = _taxonomy_access_format_grant_record($parent_id, $role, $parent_grants);
  1084. $this->setUpAssertions[] = array(
  1085. 'grant' => $parent_grants['view'],
  1086. 'query' => 'SELECT grant_view FROM {taxonomy_access_term} WHERE tid = :tid AND rid = :rid',
  1087. 'args' => array(':tid' => $parent_id, ':rid' => $role),
  1088. 'message' => t('Configured grants for term %term, role %role', array('%term' => $parent_name, '%role' => $name)),
  1089. );
  1090. }
  1091. }
  1092. // Create child terms.
  1093. foreach ($grant_types as $child_name => $child_grants) {
  1094. $child_name = $parent_name . "__" . $child_name . "_child";
  1095. $this->vocabs[$vocab_name]['terms'][$child_name] =
  1096. parent::createTerm($child_name, $vocab, $parent_id);
  1097. $child_id = $this->vocabs[$vocab_name]['terms'][$child_name]->tid;
  1098. // Configure grants for the child term for each role.
  1099. if (!empty($child_grants)) {
  1100. foreach ($this->roles as $name => $role) {
  1101. $term_rows[] = _taxonomy_access_format_grant_record($child_id, $role, $child_grants);
  1102. $this->setUpAssertions[] = array(
  1103. 'grant' => $child_grants['view'],
  1104. 'query' => 'SELECT grant_view FROM {taxonomy_access_term} WHERE tid = :tid AND rid = :rid',
  1105. 'args' => array(':tid' => $child_id, ':rid' => $role),
  1106. 'message' => t('Configured grants for term %term, role %role', array('%term' => $child_name, '%role' => $name)),
  1107. );
  1108. }
  1109. }
  1110. }
  1111. }
  1112. }
  1113. // Set the grants.
  1114. taxonomy_access_set_default_grants($default_rows);
  1115. taxonomy_access_set_term_grants($term_rows);
  1116. }
  1117. /**
  1118. * Verifies that all grants were properly stored during setup.
  1119. */
  1120. public function testSetUpCheck() {
  1121. // Check that all records were properly stored.
  1122. foreach ($this->setUpAssertions as $assertion) {
  1123. $r = db_query($assertion['query'], $assertion['args'])->fetchField();
  1124. $this->assertTrue(
  1125. (is_numeric($r) && $r == $assertion['grant']),
  1126. $assertion['message']
  1127. );
  1128. }
  1129. }
  1130. // Role config tests:
  1131. // Create a role
  1132. // Create a user with the role
  1133. // Configure role grants via form
  1134. // Add, with children, delete
  1135. // Confirm records stored
  1136. // Confirm node access properly updated
  1137. // Go back and edit, repeat.
  1138. // Disable role.
  1139. // Confirm form.
  1140. // Update node access if prompted.
  1141. // Confirm records deleted.
  1142. // Confirm node access updated.
  1143. // 1. delete a term
  1144. // 2. change a grant config
  1145. // 3. delete a grant config
  1146. // 4. change a vocab default
  1147. // 5. delete a voacb default
  1148. // 6. disable a role
  1149. // 7. delete a role
  1150. // 8. delete a field attachment
  1151. // 9. delete a vocabulary
  1152. }
  1153. /**
  1154. * Tests term grants for all possible grant combinations.
  1155. */
  1156. class TaxonomyAccessTermGrantTest extends TaxonomyAccessTestCase {
  1157. // There are four roles for term access testing:
  1158. // ctlt Receives both "Create" and "List" in the global default.
  1159. // ctlf Receives "Create" but not "List" in the global default.
  1160. // cflt Receives "List" but not "Create" in the global default.
  1161. // cflf Receives neither "Create" nor "List" in the global default.
  1162. // All roles receive the same permissions for terms and vocab defaults.
  1163. protected $roles = array();
  1164. protected $role_config = array(
  1165. 'ctlt' => array(),
  1166. 'ctlf' => array(),
  1167. 'cflt' => array(),
  1168. 'cflf' => array(),
  1169. );
  1170. protected $vocabs = array();
  1171. public static function getInfo() {
  1172. return array(
  1173. 'name' => 'Term grants',
  1174. 'description' => 'Test node access for View tag (create) and Add tag (list) grants.',
  1175. 'group' => 'Taxonomy Access Control',
  1176. );
  1177. }
  1178. public function setUp() {
  1179. parent::setUp();
  1180. // Configure roles with no additional permissions.
  1181. foreach ($this->role_config as $role_name => $permissions) {
  1182. $this->roles[$role_name] = $this->drupalCreateRole(array(), $role_name);
  1183. }
  1184. // Set up our testing taxonomy.
  1185. // We will create four vocabularies:
  1186. // vctlt Receives both "Create" and "List" in the vocabulary default.
  1187. // vctlf Receives "Create" but not "List" in the vocabulary default.
  1188. // vcflt Receives "List" but not "Create" in the vocabulary default.
  1189. // vcflf Receives neither "Create" nor "List" in the vocabulary default.
  1190. $grant_combos = array(
  1191. 'ctlt' => array('create' => TAXONOMY_ACCESS_TERM_ALLOW, 'list' => TAXONOMY_ACCESS_TERM_ALLOW),
  1192. 'ctlf' => array('create' => TAXONOMY_ACCESS_TERM_ALLOW, 'list' => TAXONOMY_ACCESS_TERM_DENY),
  1193. 'cflt' => array('create' => TAXONOMY_ACCESS_TERM_DENY, 'list' => TAXONOMY_ACCESS_TERM_ALLOW),
  1194. 'cflf' => array('create' => TAXONOMY_ACCESS_TERM_DENY, 'list' => TAXONOMY_ACCESS_TERM_DENY),
  1195. );
  1196. // Grant all rows view, update, and delete.
  1197. foreach ($grant_combos as $combo) {
  1198. $combo['view'] = TAXONOMY_ACCESS_NODE_ALLOW;
  1199. $combo['update'] = TAXONOMY_ACCESS_NODE_ALLOW;
  1200. $combo['delete'] = TAXONOMY_ACCESS_NODE_ALLOW;
  1201. }
  1202. // Each vocabulary will have four parent terms in the same fashion:
  1203. // ctlt_parent, ctlf_parent, cflt_parent, and cflf_parent.
  1204. // Each of these_parent terms will have children in each class, as well:
  1205. // ctlt_child, ctlf_child, cflt_child, and cflf_child.
  1206. // So, each vocab looks something like:
  1207. // - ctlt_parent
  1208. // - - ctlt_child
  1209. // - - ctlf_child
  1210. // - - cflt_child
  1211. // - - cflf_child
  1212. // - ctlf_parent
  1213. // - - ctlt_child
  1214. // - - ctlf_child
  1215. // - - cflt_child
  1216. // - - cfl_fchild
  1217. // - cflt_parent
  1218. // - - ctlt_child
  1219. // - - ctlf_child
  1220. // - - cflt_child
  1221. // - - cflf_child
  1222. // - cflf_parent
  1223. // - - ctlt_child
  1224. // - - ctlf_child
  1225. // - - cflt_child
  1226. // - - cflf_child
  1227. // Configure terms, vocabularies, and grants.
  1228. foreach ($grant_combos as $vocab_name => $default_grants) {
  1229. // Create the vocabulary.
  1230. $vocab_name = "v" . $vocab_name;
  1231. $this->vocabs[$vocab_name] = array();
  1232. $this->vocabs[$vocab_name]['vocab'] = parent::createVocab($vocab_name);
  1233. $this->vocabs[$vocab_name]['terms'] = array();
  1234. $vocab = $this->vocabs[$vocab_name]['vocab'];
  1235. // Add a field for the vocabulary to pages.
  1236. $this->createField($vocab_name);
  1237. // Configure default grants for the vocabulary for each role.
  1238. if (!empty($default_grants)) {
  1239. foreach ($this->roles as $name => $role) {
  1240. $default_rows[] = _taxonomy_access_format_grant_record($vocab->vid, $role, $default_grants, TRUE);
  1241. $this->setUpAssertions[] = array(
  1242. 'create' => $default_grants['create'],
  1243. 'list' => $default_grants['list'],
  1244. 'query' => 'SELECT grant_create, grant_list FROM {taxonomy_access_default} WHERE vid = :vid AND rid = :rid',
  1245. 'args' => array(':vid' => $vocab->vid, ':rid' => $role),
  1246. 'message' => t('Configured default grants for vocab %vocab, role %role', array('%vocab' => $vocab->machine_name, '%role' => $name)),
  1247. );
  1248. }
  1249. }
  1250. // Create terms.
  1251. foreach ($grant_combos as $parent_name => $parent_grants) {
  1252. // Create parent term.
  1253. $parent_name = $vocab_name . "__" . $parent_name . "_parent";
  1254. $this->vocabs[$vocab_name]['terms'][$parent_name] =
  1255. parent::createTerm($parent_name, $vocab);
  1256. $parent_id = $this->vocabs[$vocab_name]['terms'][$parent_name]->tid;
  1257. // Configure grants for the parent term for each role.
  1258. if (!empty($parent_grants)) {
  1259. foreach ($this->roles as $name => $role) {
  1260. $term_rows[] = _taxonomy_access_format_grant_record($parent_id, $role, $parent_grants);
  1261. $this->setUpAssertions[] = array(
  1262. 'create' => $parent_grants['create'],
  1263. 'list' => $parent_grants['list'],
  1264. 'query' => 'SELECT grant_create, grant_list FROM {taxonomy_access_term} WHERE tid = :tid AND rid = :rid',
  1265. 'args' => array(':tid' => $parent_id, ':rid' => $role),
  1266. 'message' => t('Configured grants for term %term, role %role', array('%term' => $parent_name, '%role' => $name)),
  1267. );
  1268. }
  1269. }
  1270. // Create child terms.
  1271. foreach ($grant_combos as $child_name => $child_grants) {
  1272. $child_name = $parent_name . "__" . $child_name . "_child";
  1273. $this->vocabs[$vocab_name]['terms'][$child_name] =
  1274. parent::createTerm($child_name, $vocab, $parent_id);
  1275. $child_id = $this->vocabs[$vocab_name]['terms'][$child_name]->tid;
  1276. // Configure grants for the child term for each role.
  1277. if (!empty($child_grants)) {
  1278. foreach ($this->roles as $name => $role) {
  1279. $term_rows[] = _taxonomy_access_format_grant_record($child_id, $role, $child_grants);
  1280. $this->setUpAssertions[] = array(
  1281. 'create' => $child_grants['create'],
  1282. 'list' => $child_grants['list'],
  1283. 'query' => 'SELECT grant_create, grant_list FROM {taxonomy_access_term} WHERE tid = :tid AND rid = :rid',
  1284. 'args' => array(':tid' => $child_id, ':rid' => $role),
  1285. 'message' => t('Configured grants for term %term, role %role', array('%term' => $child_name, '%role' => $name)),
  1286. );
  1287. }
  1288. }
  1289. }
  1290. }
  1291. }
  1292. // Set the grants.
  1293. taxonomy_access_set_default_grants($default_rows);
  1294. taxonomy_access_set_term_grants($term_rows);
  1295. }
  1296. /**
  1297. * Verifies that all grants were properly stored during setup.
  1298. */
  1299. public function testSetUpCheck() {
  1300. // Check that all records were properly stored.
  1301. foreach ($this->setUpAssertions as $assertion) {
  1302. $r = db_query($assertion['query'], $assertion['args'])->fetchAssoc();
  1303. $this->assertTrue(
  1304. (is_array($r)
  1305. && $r['grant_create'] == $assertion['create']
  1306. && $r['grant_list'] == $assertion['list']),
  1307. $assertion['message']
  1308. );
  1309. }
  1310. }
  1311. }
  1312. class TaxonomyAccessWeightTest extends DrupalWebTestCase {
  1313. public static function getInfo() {
  1314. return array(
  1315. 'name' => 'Weight',
  1316. 'description' => 'Test module weight.',
  1317. 'group' => 'Taxonomy Access Control',
  1318. );
  1319. }
  1320. public function setUp() {
  1321. parent::setUp('taxonomy_access');
  1322. }
  1323. /**
  1324. * Verifies that this module is weighted below the Taxonomy module.
  1325. */
  1326. public function testWeight() {
  1327. // Verify weight.
  1328. $tax_weight =
  1329. db_query(
  1330. "SELECT weight FROM {system}
  1331. WHERE name = 'taxonomy'")
  1332. ->fetchField();
  1333. $tax_access_weight =
  1334. db_query(
  1335. "SELECT weight FROM {system}
  1336. WHERE name = 'taxonomy_access'")
  1337. ->fetchField();
  1338. $this->assertTrue(
  1339. $tax_access_weight > $tax_weight,
  1340. t("Weight of this module is @tax_access_weight. Weight of the Taxonomy module is @tax_weight.",
  1341. array('@tax_access_weight' => $tax_access_weight, '@tax_weight' => $tax_weight))
  1342. );
  1343. // Disable module and set weight of the Taxonomy module to a high number.
  1344. module_disable(array('taxonomy_access'), TRUE);
  1345. db_update('system')
  1346. ->fields(array('weight' => rand(5000, 9000)))
  1347. ->condition('name', 'taxonomy')
  1348. ->execute();
  1349. // Re-enable module and re-verify weight.
  1350. module_enable(array('taxonomy_access'), TRUE);
  1351. $tax_weight =
  1352. db_query(
  1353. "SELECT weight FROM {system}
  1354. WHERE name = 'taxonomy'")
  1355. ->fetchField();
  1356. $tax_access_weight =
  1357. db_query(
  1358. "SELECT weight FROM {system}
  1359. WHERE name = 'taxonomy_access'")
  1360. ->fetchField();
  1361. $this->assertTrue(
  1362. $tax_access_weight > $tax_weight,
  1363. t("Weight of this module is @tax_access_weight. Weight of the Taxonomy module is @tax_weight.",
  1364. array('@tax_access_weight' => $tax_access_weight, '@tax_weight' => $tax_weight))
  1365. );
  1366. }
  1367. }
  1368. /**
  1369. * Tests that callbacks are cleaned up when the module is disabled.
  1370. */
  1371. class TaxonomyAccessCallbackCleanupTest extends DrupalWebTestCase {
  1372. public static function getInfo() {
  1373. return array(
  1374. 'name' => 'Callback Cleanup',
  1375. 'description' => 'Test callback cleanup during disabling of module works.',
  1376. 'group' => 'Taxonomy Access Control',
  1377. );
  1378. }
  1379. public function setUp() {
  1380. parent::setUp('taxonomy_access');
  1381. }
  1382. /**
  1383. * Verifies that the module's callbacks are cleaned up during disable.
  1384. */
  1385. public function testCallbackCleanup() {
  1386. // The problem only happens on new fields after the module is installed.
  1387. $content_type = $this->drupalCreateContentType();
  1388. // Create a new field with type taxonomy_term_reference.
  1389. $field_name = drupal_strtolower($this->randomName() . '_field_name');
  1390. $field_type = array(
  1391. 'field_name' => $field_name,
  1392. 'type' => 'taxonomy_term_reference',
  1393. 'cardinality' => 1,
  1394. );
  1395. $field_type = field_create_field($field_type);
  1396. // Add an instance of the field to content type.
  1397. $field_instance = array(
  1398. 'field_name' => $field_name,
  1399. 'entity_type' => 'node',
  1400. 'bundle' => $content_type->name
  1401. );
  1402. $field_instance = field_create_instance($field_instance);
  1403. // Trigger hook_disable to see if the callbacks are cleaned up.
  1404. module_disable(array('taxonomy_access'), TRUE);
  1405. // Create a user so that we can check if we can access the node add pages.
  1406. $this->privileged_user = $this->drupalCreateUser(array('bypass node access'));
  1407. $this->drupalLogin($this->privileged_user);
  1408. // If the callbacks are not cleaned up we would get a fatal error.
  1409. $this->drupalGet('node/add/' . $content_type->name);
  1410. $this->assertText(t('Create @name', array('@name' => $content_type->name)), t('New content can be added'));
  1411. }
  1412. }