فهرست منبع

added the second patch to i18n_access BUT WE WONT USE THIS MODULE!

Bachir Soussi Chiadmi 7 سال پیش
والد
کامیت
eba58a57bf

+ 288 - 0
sites/all/modules/contrib/localisation/i18n_access/entity_translation-2211649-5.patch

@@ -0,0 +1,288 @@
+diff --git a/i18n_access.module b/i18n_access.module
+index 5f4aa56..a76370d 100644
+--- a/i18n_access.module
++++ b/i18n_access.module
+@@ -105,18 +105,21 @@ function i18n_access_permission() {
+ function i18n_access_form_node_form_alter(&$form, &$form_state, $form_id) {
+ 
+   if (isset($form['language']['#options'])) {
+-  // Remove inaccessible languages from the select box
+-    // don't do it for  admininstrators
++    // Remove inaccessible languages from the select box
++    // don't do it for administrators
+     if (!user_access('administer nodes')) {
+       $perms = i18n_access_load_permissions();
+       foreach ($form['language']['#options'] as $key => $value) {
+         $perm_key = ($key == '') ? I18N_ACCESS_LANGUAGE_NEUTRAL : $key;
+-        if ($key!='en' && empty($perms[$perm_key])) {
++
++        // remove english from here, we treat english the same as any language
++        // if ($key!='en' && empty($perms[$perm_key])) {
++        if (empty($perms[$perm_key])) {
+           unset($form['language']['#options']["$key"]);
+         }
+       }
+     }
+-    unset($form['#after_build']['0']);
++    // unset($form['#after_build']['0']);
+   }
+ }
+ 
+@@ -125,7 +128,7 @@ function i18n_access_form_node_form_alter(&$form, &$form_state, $form_id) {
+  */
+ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
+ 
+-  //Configuring translation edit form to limit it to allowed language
++  // Configuring translation edit form to limit it to allowed language
+   if ($form_id == 'i18n_node_select_translation' && !user_access('administer nodes')) {
+ 
+     $perms = i18n_access_load_permissions();
+@@ -149,7 +152,7 @@ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
+   }
+ 
+   // Add i18n_access things to user/edit /user/add
+-  if ($form_id == 'user_register_form' || $form_id == 'user_profile_form' ) {
++  if ($form_id == 'user_register_form' || $form_id == 'user_profile_form') {
+ 
+     $form['i18n_access'] = array(
+       '#type' => 'fieldset',
+@@ -171,67 +174,100 @@ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
+  *
+  * @see node_access()
+  */
+-function i18n_access_node_access($node, $op, $account = NULL) {
++function i18n_access_node_access($node, $op, $account = NULL, $langcode = NULL) {
++  // big re-work here. discarded entire original function-- replaced with our own
+   if (is_object($node)) {
+-
+-    global $user;
+-
+-    // If no user object is supplied, the access check is for the current user.
+-    if (empty($account)) {
+-      $account = $user;
++    // make sure that site administrators always have access
++    $permissions = i18n_access_load_permissions($user);
++    if (user_access('site administrator', $account)) {
++      return TRUE;
+     }
++    // if langcode is null it means the user is not accessing by translation overview, we throw access deny and allow to hard deny sneaky people and keep unpermitted tabs out of the menu system for the user
++    elseif ($langcode == NULL) {
++      global $language;
++      $langcode = $language->language;
++
++      switch ($op) {
++        case 'view':
++          return NODE_ACCESS_ALLOW;
++          break;
++        case 'update':
++          if (empty($permissions[$langcode])) {
++            return NODE_ACCESS_DENY;
++          }
++          else {
++            return NODE_ACCESS_ALLOW;
++          }
++          break;
++        case 'create':
++          if (empty($permissions[$langcode])) {
++            return NODE_ACCESS_DENY;
++          }
++          else {
++            return NODE_ACCESS_ALLOW;
++          }
++          break;
+ 
+-    // Bypass completely if node_access returns false.
+-   //TODO $access = node_access($node, $op, $account);
+-
+-    /* TODO if (!$access) {
+-      return FALSE;
+-    } */
+-
+-    // This module doesn't deal with view permissions
+-    if ($op == 'view') {
+-      return NODE_ACCESS_IGNORE;
++      }
+     }
+-
+-    // make sure that administrators always have access
+-    if (user_access('administer nodes', $account)) {
+-      return TRUE;
++    //if they are accessing by translation overview, the language code gets passed by the translation overview, we send true or false here
++    else {
++      switch ($op) {
++        case 'view':
++          return TRUE;
++          break;
++        case 'update':
++          if (empty($permissions[$langcode])) {
++            return FALSE;
++          }
++          else {
++            return TRUE;
++          }
++          break;
++        case 'create':
++          if (empty($permissions[$langcode])) {
++            return FALSE;
++          }
++          else {
++            return TRUE;
++          }
++          break;
++      }
+     }
+-
+-    $perms = i18n_access_load_permissions($account->uid);
+-
+-    // Make sure to use the language neutral constant if node language is empty
+-    $langcode = $node->language ? $node->language : I18N_ACCESS_LANGUAGE_NEUTRAL;
+-
+-    //return isset($perms[$langcode]) ? (bool) $perms[$langcode] : NODE_ACCESS_DENY;
+-    return isset($perms[$langcode]) ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
+   }
+ }
+ 
+ /**
+  * Implements hook_menu_alter().
+  */
+-function i18n_access_menu_alter(&$items) {
++
++//make function name i18n_access_node_menu_alter
++function i18n_access_node_menu_alter(&$items) {
++
++  // due to hook_module_implementation_alter calling entity translation last, we can't change the callback here, i've done it in entity_translation.node.inc - consider calling it here?
+   // Replace the translation overview page since we can't hook it.
+   $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
++
+ }
+ 
+ function i18n_access_translation_node_overview($node) {
+ 
+   include_once DRUPAL_ROOT . '/includes/language.inc';
+ 
+-  if (!empty($node->tnid)) {
+-    // Already part of a set, grab that set.
+-    $tnid = $node->tnid;
+-    $translations = translation_node_get_translations($node->tnid);
+-  }
+-  else {
+-    // We have no translation source nid, this could be a new set, emulate that.
+-    $tnid = $node->nid;
+-    $translations = array($node->language => $node);
++  // include functions from i18n_node.pages.inc
++  include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'i18n_node') . '/i18n_node.pages.inc';
++
++  // this is the part where this thing sorts out how to build a list of existing translations for this node
++  // since we use entity translation, the tnid isn't what we're using to build the translation list. we're using node->translations->data[keys]
++  $available_translations = $node->translations->data;
++
++  // iterate over each available translation and add its key (which is the 2 letter language code) to the array we call $translations with the node object as the value
++  foreach ($available_translations as $key => $value) {
++    $translations[$key] = $node;
+   }
+ 
+   $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
++
+   $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));
+ 
+   //added from i18n/i18n_node/i18n_node.pages.inc function
+@@ -240,9 +276,9 @@ function i18n_access_translation_node_overview($node) {
+   $perms = i18n_access_load_permissions($account->uid);
+   //end
+ 
+-
+   // Modes have different allowed languages
+   foreach (i18n_node_language_list($node) as $langcode => $language_name) {
++
+     if ($langcode == LANGUAGE_NONE) {
+       // Never show language neutral on the overview.
+       continue;
+@@ -253,16 +289,24 @@ function i18n_access_translation_node_overview($node) {
+       // We load the full node to check whether the user can edit it.
+       $translation_node = node_load($translations[$langcode]->nid);
+       $path = 'node/' . $translation_node->nid;
+-      $title = i18n_node_translation_link($translation_node->title, $path, $langcode);
+-      if (node_access('update', $translation_node)) {
++
++      // Account for title field module:
++      if (isset($translation_node->title_field) && isset($translation_node->title_field[$langcode])) {
++        $title = i18n_node_translation_link($translation_node->title_field[$langcode][0]['value'], $path, $langcode);
++      }
++      else {
++        $title = i18n_node_translation_link($translation_node->title, $path, $langcode);
++      }
++
++      if (i18n_access_node_access($translation_node, 'update', $user, $langcode)) {
+         $text = t('edit');
+         $path = 'node/' . $translation_node->nid . '/edit';
+         $options[] = i18n_node_translation_link($text, $path, $langcode);
+       }
+       $status = $translation_node->status ? t('Published') : t('Not published');
+-      $status .= $translation_node->translate ? ' - <span class="marker">' . t('outdated') . '</span>' : '';
++      $status .= $translation_node->translate ? ' - ' . t('outdated') . '' : '';
+       if ($translation_node->nid == $tnid) {
+-        $language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
++        $language_name = t('@language_name (source)', array('@language_name' => $language_name));
+       }
+     }
+     else {
+@@ -316,6 +360,52 @@ function i18n_access_menu() {
+ }
+ 
+ /**
++ * Node-specific menu alterations.
++ */
++function i18n_access_menu_alter(&$items, $backup) {
++  if (isset($backup['node'])) {
++    $item = $backup['node'];
++    // Preserve the menu router item defined by other modules.
++    $callback['page callback'] = $item['page callback'];
++    $callback['file'] = $item['file'];
++    $callback['module'] = $item['module'];
++    $access_arguments = array_merge(array(1, $item['access callback']), $item['access arguments']);
++  }
++  else {
++    $access_arguments = array(1);
++  }
++
++  // Point the 'translate' tab to point to the i18n_access version of the translation overview page
++  $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
++
++  // There are 3 page arguments for the entity translation overview, only one for i18n_access:
++  $items['node/%node/translate']['page arguments'] = array(1);
++
++  // Pass in the i18n_access permissions
++  $items['node/%node/translate']['access arguments'] = $access_arguments;
++
++  // Point to i18n_access's include for the callback
++  $items['node/%node/translate']['file'] = 'i18n_access.module';
++
++  // Point to i18n_access module
++  $items['node/%node/translate']['module'] = 'i18n_access';
++}
++
++/**
++ * Implements hook_module_implements_alter().
++ */
++function i18n_access_module_implements_alter(&$implementations, $hook) {
++  switch ($hook) {
++    case 'menu_alter':
++      // Move our hook_menu_alter implementation to the end of the list.
++      $group = $implementations['i18n_access'];
++      unset($implementations['i18n_access']);
++      $implementations['i18n_access'] = $group;
++      break;
++  }
++}
++
++/**
+  * Admin settings form
+  */
+ function i18n_access_admin_settings() {
+@@ -330,4 +420,4 @@ function i18n_access_admin_settings() {
+   );
+ 
+   return system_settings_form($form);
+-}
+\ No newline at end of file
++}

+ 619 - 0
sites/all/modules/contrib/localisation/i18n_access/i18n_access.2298475-6.patch

@@ -0,0 +1,619 @@
+diff --git a/i18n_access.info b/i18n_access.info
+index e19050a..074cec2 100644
+--- a/i18n_access.info
++++ b/i18n_access.info
+@@ -2,6 +2,9 @@ name = Translation Access
+ description = Control access to creating content in different languages.
+ package = Multilanguage
+ core = 7.x
++configure = admin/config/regional/language/access
+ 
+ dependencies[] = locale
+ dependencies[] = translation
++dependencies[] = i18n_node
++files[] = i18n_access.test
+diff --git a/i18n_access.install b/i18n_access.install
+index 24aefb4..95c935c 100644
+--- a/i18n_access.install
++++ b/i18n_access.install
+@@ -42,4 +42,5 @@ function i18n_access_install() {
+  * Implements hook_uninstall().
+  */
+ function i18n_access_uninstall() {
++  variable_del('i18n_access_languages');
+ }
+diff --git a/i18n_access.module b/i18n_access.module
+index 5f4aa56..3b68458 100644
+--- a/i18n_access.module
++++ b/i18n_access.module
+@@ -2,32 +2,14 @@
+ 
+ /**
+  * @file
+- * file_description
++ * i18n_access.module
+  */
+ 
+-define('I18N_ACCESS_LANGUAGE_NEUTRAL', 'NEUTRAL');
+-
+ /**
+  * Implements hook_user_insert().
+  */
+ function i18n_access_user_insert(&$edit, &$account, $category = NULL) {
+-  if ($category == 'account') {
+-    // see user_admin_perm_submit()
+-    if (isset($edit['i18n_access'])) {
+-      db_delete('i18n_access')
+-        ->condition('uid', $account->uid)
+-        ->execute();
+-      $edit['i18n_access'] = array_filter($edit['i18n_access']);
+-      if (count($edit['i18n_access'])) {
+-        db_insert('i18n_access')
+-          ->fields(array(
+-            'uid' => $account->uid,
+-            'perm' => implode(', ', array_keys($edit['i18n_access'])),
+-        ))->execute();
+-      }
+-      unset($edit['i18n_access']);
+-    }
+-  }
++  i18n_access_user_update($edit, $account, $category);
+ }
+ 
+ /**
+@@ -54,10 +36,19 @@ function i18n_access_user_update(&$edit, &$account, $category = NULL) {
+ }
+ 
+ /**
++ * Implements hook_user_delete().
++ */
++function i18n_access_user_delete($account) {
++  db_delete('i18n_access')
++    ->condition('uid', $account->uid)
++    ->execute();
++}
++
++/**
+  * Load the language permissions for a given user
+  */
+ function i18n_access_load_permissions($uid = NULL) {
+-  static $perms = array();
++  $perms = &drupal_static(__FUNCTION__);
+ 
+   // use the global user id if none is passed
+   if (!isset($uid)) {
+@@ -94,7 +85,8 @@ function i18n_access_permission() {
+   return array(
+     'access selected languages' => array(
+       'title' => t('Access selected languages'),
+-      'description' => t('access selected languages.'),
++      'description' => t('This permission gives this role edit/delete access to all content which are in the <a href="!url" target="_blank">selected language</a>. View/create access needs a different access level.', array('!url' => url('admin/config/regional/language/access'))),
++      'restrict access' => TRUE,
+     ),
+   );
+ }
+@@ -102,34 +94,39 @@ function i18n_access_permission() {
+ /**
+  * Implements hook_form_node_form_alter().
+  */
+-function i18n_access_form_node_form_alter(&$form, &$form_state, $form_id) {
+-
+-  if (isset($form['language']['#options'])) {
+-  // Remove inaccessible languages from the select box
+-    // don't do it for  admininstrators
+-    if (!user_access('administer nodes')) {
+-      $perms = i18n_access_load_permissions();
+-      foreach ($form['language']['#options'] as $key => $value) {
+-        $perm_key = ($key == '') ? I18N_ACCESS_LANGUAGE_NEUTRAL : $key;
+-        if ($key!='en' && empty($perms[$perm_key])) {
+-          unset($form['language']['#options']["$key"]);
+-        }
++function i18n_access_form_node_form_alter(&$form) {
++  $form['#after_build'][] = '_i18n_access_form_node_form_alter';
++}
++
++/**
++ * Unset's languages from language options if user does not have permission to
++ * use.
++ *
++ * @param $form
++ * @param $form_state
++ * @return mixed
++ */
++function _i18n_access_form_node_form_alter($form, &$form_state) {
++  if (isset($form['language']['#options']) && !user_access('bypass node access')) {
++    $perms = i18n_access_load_permissions();
++    foreach ($form['language']['#options'] as $key => $value) {
++      if (empty($perms[$key])) {
++        unset($form['language']['#options'][$key]);
+       }
+     }
+-    unset($form['#after_build']['0']);
+   }
++
++  return $form;
+ }
+ 
+ /**
+  * Implements hook_form_alter().
+  */
+ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
+-
+   //Configuring translation edit form to limit it to allowed language
+-  if ($form_id == 'i18n_node_select_translation' && !user_access('administer nodes')) {
++  if ($form_id == 'i18n_node_select_translation' && !user_access('bypass node access')) {
+ 
+     $perms = i18n_access_load_permissions();
+-
+     foreach ($form['translations']['nid'] as $language => $translation) {
+       if (!isset($perms[$language]) && $language != '#tree') {
+         unset($form['translations']['nid'][$language]);
+@@ -159,17 +156,15 @@ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
+     );
+     $form['i18n_access']['i18n_access'] = array(
+       '#type' => 'checkboxes',
+-      '#options' => array(I18N_ACCESS_LANGUAGE_NEUTRAL => t('Language neutral')) + locale_language_list('name'),
++      '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
+       '#default_value' => i18n_access_load_permissions($form['#user']->uid),
+-      '#description' => t('Select the languages that this user should have permission to create and edit content for.'),
++      '#description' => t('The user get edit, delete access to all content which are in this enabled languages. Create, view access needs a different access level.'),
+     );
+   }
+ }
+ 
+ /**
+- * Wrapper around node_access() with additional checks for language permissions.
+- *
+- * @see node_access()
++ * Implements hook_node_access().
+  */
+ function i18n_access_node_access($node, $op, $account = NULL) {
+   if (is_object($node)) {
+@@ -181,29 +176,16 @@ function i18n_access_node_access($node, $op, $account = NULL) {
+       $account = $user;
+     }
+ 
+-    // Bypass completely if node_access returns false.
+-   //TODO $access = node_access($node, $op, $account);
+-
+-    /* TODO if (!$access) {
+-      return FALSE;
+-    } */
+-
+     // This module doesn't deal with view permissions
+     if ($op == 'view') {
+       return NODE_ACCESS_IGNORE;
+     }
+ 
+-    // make sure that administrators always have access
+-    if (user_access('administer nodes', $account)) {
+-      return TRUE;
+-    }
+-
+     $perms = i18n_access_load_permissions($account->uid);
+ 
+     // Make sure to use the language neutral constant if node language is empty
+-    $langcode = $node->language ? $node->language : I18N_ACCESS_LANGUAGE_NEUTRAL;
++    $langcode = $node->language ? $node->language : LANGUAGE_NONE;
+ 
+-    //return isset($perms[$langcode]) ? (bool) $perms[$langcode] : NODE_ACCESS_DENY;
+     return isset($perms[$langcode]) ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
+   }
+ }
+@@ -212,14 +194,26 @@ function i18n_access_node_access($node, $op, $account = NULL) {
+  * Implements hook_menu_alter().
+  */
+ function i18n_access_menu_alter(&$items) {
+-  // Replace the translation overview page since we can't hook it.
+-  $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
++  if (isset($items['node/%node/translate'])) {
++    $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
++  }
+ }
+ 
++/**
++ * Most logic comes from translation/i18n_node module.
++ *
++ * We removes here only the "add translation" links for languages which are not your selected language.
++ *
++ * @see translation_node_overview
++ * @see i18n_node_translation_overview
++ *
++ * @param object $node
++ *
++ * @return array.
++ */
+ function i18n_access_translation_node_overview($node) {
+ 
+   include_once DRUPAL_ROOT . '/includes/language.inc';
+-
+   if (!empty($node->tnid)) {
+     // Already part of a set, grab that set.
+     $tnid = $node->tnid;
+@@ -231,16 +225,12 @@ function i18n_access_translation_node_overview($node) {
+     $translations = array($node->language => $node);
+   }
+ 
+-  $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
+   $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));
+-
+-  //added from i18n/i18n_node/i18n_node.pages.inc function
++  $rows = array();
+   global $user;
+-  $account = $user;
+-  $perms = i18n_access_load_permissions($account->uid);
++  $perms = i18n_access_load_permissions($user->uid);
+   //end
+ 
+-
+   // Modes have different allowed languages
+   foreach (i18n_node_language_list($node) as $langcode => $language_name) {
+     if ($langcode == LANGUAGE_NONE) {
+@@ -268,15 +258,11 @@ function i18n_access_translation_node_overview($node) {
+     else {
+       // No such translation in the set yet: help user to create it.
+       $title = t('n/a');
+-      if (node_access('create', $node)) {
++      if (node_access('create', $node->type) && (!empty($perms[$langcode]) || user_access('bypass node access'))) {
+         $text = t('add translation');
+         $path = 'node/add/' . str_replace('_', '-', $node->type);
+         $query = array('query' => array('translation' => $node->nid, 'target' => $langcode));
+-
+-        //condition added from i18n/i18n_node/i18n_node.pages.inc
+-        if (in_array($langcode, $perms)) {
+-          $options[] = i18n_node_translation_link($text, $path, $langcode, $query);
+-        }
++        $options[] = i18n_node_translation_link($text, $path, $langcode, $query);
+       }
+       $status = t('Not translated');
+     }
+@@ -301,9 +287,7 @@ function i18n_access_translation_node_overview($node) {
+  * Implements hook_menu().
+  */
+ function i18n_access_menu() {
+-  $items = array();
+-
+-  $items['admin/settings/language/access'] = array(
++  $items['admin/config/regional/language/access'] = array(
+     'title' => 'Access',
+     'page callback' => 'drupal_get_form',
+     'page arguments' => array('i18n_access_admin_settings'),
+@@ -311,23 +295,20 @@ function i18n_access_menu() {
+     'type' => MENU_LOCAL_TASK,
+     'weight' => 10,
+   );
+-
+   return $items;
+ }
+ 
+ /**
+- * Admin settings form
++ * Admin settings form.
+  */
+-function i18n_access_admin_settings() {
+-
++function i18n_access_admin_settings($form) {
+   $form['i18n_access_languages'] = array(
+     '#title' => t('Select the default access languages'),
+     '#type' => 'select',
+-    '#multiple' => 'true',
+-    '#options' => array(I18N_ACCESS_LANGUAGE_NEUTRAL => t('Language neutral')) + locale_language_list('name'),
++    '#multiple' => TRUE,
++    '#options' => array(LANGUAGE_NONE => t('Language neutral')) + locale_language_list('name'),
+     '#default_value' => variable_get('i18n_access_languages', array()),
+     '#description' => t("This selection of languages will be connected with the 'access selected languages' permission which you can use to grant a role access to these languages at once.")
+   );
+-
+   return system_settings_form($form);
+-}
+\ No newline at end of file
++}
+diff --git a/i18n_access.test b/i18n_access.test
+index d32dbf4..5b2f443 100644
+--- a/i18n_access.test
++++ b/i18n_access.test
+@@ -6,10 +6,17 @@
+  */
+ 
+ class i18nAccessTestCase extends DrupalWebTestCase {
++
++  protected $admin_user;
++
++  protected $translator;
++
++  protected $visitor;
++
+   /**
+    * Implementation of getInfo().
+    */
+-  function getInfo() {
++  public static function getInfo() {
+     return array(
+       'name' => t('Translation Access'),
+       'description' => t('Test suite for the i18n_access module.'),
+@@ -20,22 +27,21 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+   /**
+    * Implementation of setUp().
+    */
+-  function setUp() {
+-    parent::setUp('locale', 'translation', 'i18n_access');
++  public function setUp() {
++    parent::setUp(array('locale', 'translation', 'i18n_access', 'i18n_node'));
+ 
+-    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'administer site configuration', 'access administration pages', 'administer content types', 'administer nodes', 'administer users'));
+-    $this->translator = $this->drupalCreateUser(array('create story content', 'edit own story content', 'translate content'));
++    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'administer site configuration', 'access administration pages', 'administer content types', 'administer users', 'bypass node access', 'translate content'));
++    $this->translator = $this->drupalCreateUser(array('create article content', 'edit own article content', 'translate content'));
+     $this->visitor = $this->drupalCreateUser(array('access content'));
+     $this->drupalLogin($this->admin_user);
++
+     $this->addLanguage('fr');
+     $this->addLanguage('de');
+-    $this->setLanguagePermissions($this->translator, array('en', 'fr'));
+ 
+     // Set Story content type to use multilingual support with translation.
+-    $edit = array();
+     $edit['language_content_type'] = 2;
+-    $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
+-    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Story')), t('Story content type has been updated.'));
++    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
++    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), 'Story content type has been updated.');
+ 
+   }
+ 
+@@ -47,26 +53,27 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+    */
+   function addLanguage($language_code) {
+     // Check to make sure that language has not already been installed.
+-    $this->drupalGet('admin/settings/language');
++    $this->drupalGet('admin/config/regional/language');
+ 
+     if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
+       // Doesn't have language installed so add it.
+       $edit = array();
+       $edit['langcode'] = $language_code;
+-      $this->drupalPost('admin/settings/language/add', $edit, t('Add language'));
++      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+ 
+-      $languages = language_list('language', TRUE); // Make sure not using cached version.
+-      $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
++      drupal_static_reset('language_list'); // Make sure not using cached version.
++      $languages = language_list('language');
++      $this->assertTrue(array_key_exists($language_code, $languages), 'Language was installed successfully.');
+ 
+       if (array_key_exists($language_code, $languages)) {
+-        $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => $languages[$language_code]->name)), t('Language has been created.'));
++        $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => $languages[$language_code]->name)), 'Language has been created.');
+       }
+     }
+     else {
+       // Ensure that it is enabled.
+       $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+ 
+-      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
++      $this->assertRaw(t('Configuration saved.'), 'Language successfully enabled.');
+     }
+   }
+ 
+@@ -80,8 +87,9 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+    *   An array of language codes to give permission for
+    */
+   function setLanguagePermissions($account, $languages = array()) {
+-    $this->assertTrue(user_access('administer users'), t('User has permission to administer users'));
+-
++    $this->assertTrue(user_access('administer users'), 'User has permission to administer users');
++    $expected = array();
++    $edit = array();
+     foreach ($languages as $langcode) {
+       $key = 'i18n_access[' . $langcode . ']';
+       $edit[$key] = $langcode;
+@@ -90,7 +98,31 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+     $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save'));
+ 
+     $actual = i18n_access_load_permissions($account->uid);
+-    $this->assertEqual($expected, $actual, t('Language permissions set correctly.'), 'i18n_access');
++    $this->assertEqual($expected, $actual, 'Language permissions set correctly.', 'i18n_access');
++  }
++
++  /**
++   * Unsets the language permission for the specified user. Must be logged in as
++   * an 'administer users' privileged user before calling this.
++   *
++   * @param $account
++   *   The user account to modify
++   * @param $languages
++   *   An array of language codes to remove permission for
++   */
++  function unsetLanguagePermissions($account, $languages = array()) {
++    $this->assertTrue(user_access('administer users'), 'User has permission to administer users');
++    $expected = array();
++    $edit = array();
++    foreach ($languages as $langcode) {
++      $key = 'i18n_access[' . $langcode . ']';
++      $edit[$key] = FALSE;
++    }
++    $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save'));
++    drupal_static_reset('i18n_access_load_permissions');
++    drupal_static_reset('node_access');
++    $actual = i18n_access_load_permissions($account->uid);
++    $this->assertEqual($expected, $actual, 'Language permissions unset correctly.', 'i18n_access');
+   }
+ 
+   /**
+@@ -109,7 +141,6 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+   function assertLanguageOption($langcode, $message, $group = 'Other') {
+     $xpath = '//select[@name="language"]/option';
+     $fields = $this->xpath($xpath);
+-
+     // If value specified then check array for match.
+     $found = TRUE;
+     if (isset($langcode)) {
+@@ -157,52 +188,145 @@ class i18nAccessTestCase extends DrupalWebTestCase {
+     return $this->assertFalse($fields && $found, $message, $group);
+   }
+ 
+-  function dsm($object) {
+-    $this->error('<pre>' . check_plain(print_r($object, 1)) . '</pre>');
+-  }
+-
+   /**
+-   * Test translator user.  User with 'create story content' and 'edit own story
+-   * content' permissions should be able to create and edit story nodes only in
++   * Test translator user. User with 'create article content' permission
++   * should be able to create and edit article nodes only in/for
+    * the languages that they have permissions for.
+    */
+   function testTranslatorUser() {
++    $this->_testTranslatorNodeAccess();
++    $this->_testTranslatorNodeAccess(TRUE);
++  }
++
++
++  function _testTranslatorNodeAccess($via_role = FALSE) {
++    $this->drupalLogin($this->admin_user);
++    if (!$via_role) {
++      $this->setLanguagePermissions($this->translator, array('en', 'fr'));
++    }
++    else{
++      $edit = array(
++        'i18n_access_languages[]' => array('en', 'fr'),
++      );
++      $this->drupalPost('admin/config/regional/language/access', $edit, t('Save configuration'));
++
++      $this->translator = $this->drupalCreateUser(array('create article content', 'edit own article content', 'translate content', 'access selected languages'));
++    }
++
+     $this->drupalLogin($this->translator);
+ 
+-    $this->drupalGet('node/add/story');
+-    $this->assertField('language', t('Found language selector.'));
++    $this->drupalGet('node/add/article');
++    $this->assertField('language', 'Found language selector.');
+ 
+     $perms = i18n_access_load_permissions($this->translator->uid);
+     $languages = language_list();
+-    $languages[I18N_ACCESS_LANGUAGE_NEUTRAL] = (object)array('language' => '', 'name' => 'Language Neutral');
++    $languages[LANGUAGE_NONE] = (object)array('language' => LANGUAGE_NONE, 'name' => 'Language Neutral');
+     foreach ($languages as $key => $language) {
+       // TODO: Add in check for language neutral
+       if (isset($perms[$key]) && $perms[$key]) {
+-        $this->assertLanguageOption($language->language, t('Option found for %language in language selector.', array('%language' => $language->name)));
++        $this->assertLanguageOption($language->language, format_string('Option found for %language in language selector.', array('%language' => $language->name)));
+       }
+       else {
+-        $this->assertNoLanguageOption($language->language, t('Option not found for %language in language selector.', array('%language' => $language->name)));
++        $this->assertNoLanguageOption($language->language, format_string('Option not found for %language in language selector.', array('%language' => $language->name)));
+       }
+     }
+-  }
++    $this->drupalLogin($this->admin_user);
++    $node = $this->drupalCreateNode(array('type' => 'article', 'language' => 'de', 'body' => array('de' => array(array()))));
++
++    $this->drupalLogin($this->translator);
++    $this->assertFalse(node_access('update', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/edit');
++    $this->assertResponse(403);
++
++    $this->assertFalse(node_access('delete', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/delete');
++    $this->assertResponse(403);
++
++    $this->drupalLogin($this->admin_user);
++    $node = $this->drupalCreateNode(array('type' => 'article', 'language' => 'fr', 'body' => array('fr' => array(array()))));
++
++    $this->drupalLogin($this->translator);
++    $this->assertTrue(node_access('update', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/edit');
++    $this->assertResponse(200);
++
++    $this->assertTrue(node_access('delete', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/delete');
++    $this->assertResponse(200);
++
++    $this->drupalGet('node/' . $node->nid . '/translate');
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'de'));
++    $this->assertNoRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'de', $query));
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'en'));
++    $this->assertRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'en', $query));
++    $this->assertRaw(i18n_node_translation_link(t('edit'), 'node/' . $node->nid . '/edit', 'fr'));
++
++    $this->drupalLogin($this->admin_user);
++    if (!$via_role) {
++      $this->unsetLanguagePermissions($this->translator, array('fr', 'en'));
++    }
++    else{
++      $edit = array(
++        'i18n_access_languages[]' => array(),
++      );
++      $this->drupalPost('admin/config/regional/language/access', $edit, t('Save configuration'));
++      $this->translator = $this->drupalCreateUser(array('create article content', 'edit own article content', 'translate content', 'access selected languages'));
++      drupal_static_reset('i18n_access_load_permissions');
++      drupal_static_reset('node_access');
++    }
++
++    $this->drupalLogin($this->translator);
++    $this->assertFalse(node_access('update', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/edit');
++    $this->assertResponse(403);
++
++    $this->assertFalse(node_access('delete', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/delete');
++    $this->assertResponse(403);
++
++    $this->drupalGet('node/' . $node->nid . '/translate');
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'de'));
++    $this->assertNoRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'de', $query));
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'en'));
++    $this->assertNoRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'en', $query));
++    $this->assertNoRaw(i18n_node_translation_link(t('edit'), 'node/' . $node->nid . '/edit', 'fr'));
++
++   }
+ 
+   /**
+-   * Test admin user.  User with 'administer nodes' permission should be able to
+-   * create and edit nodes regardless of the language
++   * Test admin user. User with 'bypass node access' permission should be able to
++   * update, delete nodes regardless of the language.
+    */
+   function testAdminUser() {
+     $this->drupalLogin($this->admin_user);
++    $this->drupalGet('node/add/article');
++    $this->assertField('language', 'Found language selector.');
+ 
+-    $this->drupalGet('node/add/story');
+-    $this->assertField('language', t('Found language selector.'));
+-
+-    $perms = i18n_access_load_permissions($this->admin_user->uid);
+     $languages = language_list();
+-    $languages[I18N_ACCESS_LANGUAGE_NEUTRAL] = (object)array('language' => '', 'name' => 'Language Neutral');
++    $languages[LANGUAGE_NONE] = (object)array('language' => LANGUAGE_NONE, 'name' => 'Language Neutral');
+     foreach ($languages as $language) {
+-      // TODO: Add in check for language neutral
+-      $this->assertLanguageOption($language->language, t('Option found for %language, regardless of permission, for administrator.', array('%language' => $language->name)));
++      $this->assertLanguageOption($language->language, format_string('Option found for %language, regardless of permission, for administrator.', array('%language' => $language->name)));
+     }
++    $this->drupalLogin($this->translator);
++    $node = $this->drupalCreateNode(array('type' => 'article', 'language' => 'de', 'body' => array('de' => array(array()))));
++
++    $this->drupalLogin($this->admin_user);
++
++    $this->assertTrue(node_access('update', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/edit');
++    $this->assertResponse(200);
++
++    $this->assertTrue(node_access('delete', $node, $this->loggedInUser));
++    $this->drupalGet('node/' . $node->nid . '/delete');
++    $this->assertResponse(200);
++
++    $this->drupalGet('node/' . $node->nid . '/translate');
++
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'fr'));
++    $this->assertRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'fr', $query));
++    $query = array('query' => array('translation' => $node->nid, 'target' => 'en'));
++    $this->assertRaw(i18n_node_translation_link(t('add translation'), 'node/add/article', 'en', $query));
++    $this->assertRaw(i18n_node_translation_link(t('edit'), 'node/' . $node->nid . '/edit', 'de'));
+   }
+ 
+-}
+\ No newline at end of file
++}

+ 14 - 0
sites/all/modules/contrib/localisation/i18n_access/i18n_access.info.orig

@@ -0,0 +1,14 @@
+name = Translation Access
+description = Control access to creating content in different languages.
+package = Multilanguage
+core = 7.x
+
+dependencies[] = locale
+dependencies[] = translation
+
+; Information added by drupal.org packaging script on 2013-09-30
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "i18n_access"
+datestamp = "1380582441"
+

+ 12 - 0
sites/all/modules/contrib/localisation/i18n_access/i18n_access.info.rej

@@ -0,0 +1,12 @@
+--- i18n_access.info
++++ i18n_access.info
+@@ -2,6 +2,9 @@ name = Translation Access
+ description = Control access to creating content in different languages.
+ package = Multilanguage
+ core = 7.x
++configure = admin/config/regional/language/access
+ 
+ dependencies[] = locale
+ dependencies[] = translation
++dependencies[] = i18n_node
++files[] = i18n_access.test

+ 126 - 35
sites/all/modules/contrib/localisation/i18n_access/i18n_access.module

@@ -166,37 +166,74 @@ function i18n_access_form_alter(&$form, &$form_state, $form_id) {
 /**
  * Implements hook_node_access().
  */
-function i18n_access_node_access($node, $op, $account = NULL) {
+function i18n_access_node_access($node, $op, $account = NULL, $langcode = NULL) {
+  // big re-work here. discarded entire original function-- replaced with our own
   if (is_object($node)) {
-
-    global $user;
-
-    // If no user object is supplied, the access check is for the current user.
-    if (empty($account)) {
-      $account = $user;
+    // make sure that site administrators always have access
+    $permissions = i18n_access_load_permissions($user);
+    if (user_access('site administrator', $account)) {
+      return TRUE;
     }
-
-    // This module doesn't deal with view permissions
-    if ($op == 'view') {
-      return NODE_ACCESS_IGNORE;
+    // if langcode is null it means the user is not accessing by translation overview, we throw access deny and allow to hard deny sneaky people and keep unpermitted tabs out of the menu system for the user
+    elseif ($langcode == NULL) {
+      global $language;
+      $langcode = $language->language;
+
+      switch ($op) {
+        case 'view':
+          return NODE_ACCESS_ALLOW;
+          break;
+        case 'update':
+          if (empty($permissions[$langcode])) {
+            return NODE_ACCESS_DENY;
+          }
+          else {
+            return NODE_ACCESS_ALLOW;
+          }
+          break;
+        case 'create':
+          if (empty($permissions[$langcode])) {
+            return NODE_ACCESS_DENY;
+          }
+          else {
+            return NODE_ACCESS_ALLOW;
+          }
+          break;
+      }
+    }
+    //if they are accessing by translation overview, the language code gets passed by the translation overview, we send true or false here
+    else {
+      switch ($op) {
+        case 'view':
+          return TRUE;
+          break;
+        case 'update':
+          if (empty($permissions[$langcode])) {
+            return FALSE;
+          }
+          else {
+            return TRUE;
+          }
+          break;
+        case 'create':
+          if (empty($permissions[$langcode])) {
+            return FALSE;
+          }
+          else {
+            return TRUE;
+          }
+          break;
+      }
     }
-
-    $perms = i18n_access_load_permissions($account->uid);
-
-    // Make sure to use the language neutral constant if node language is empty
-    $langcode = $node->language ? $node->language : LANGUAGE_NONE;
-
-    return isset($perms[$langcode]) ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
   }
 }
 
 /**
  * Implements hook_menu_alter().
  */
-function i18n_access_menu_alter(&$items) {
-  if (isset($items['node/%node/translate'])) {
-    $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
-  }
+function i18n_access_node_menu_alter(&$items) {
+  // due to hook_module_implementation_alter calling entity translation last, we can't change the callback here, i've done it in entity_translation.node.inc - consider calling it here?
+  $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
 }
 
 /**
@@ -214,15 +251,16 @@ function i18n_access_menu_alter(&$items) {
 function i18n_access_translation_node_overview($node) {
 
   include_once DRUPAL_ROOT . '/includes/language.inc';
-  if (!empty($node->tnid)) {
-    // Already part of a set, grab that set.
-    $tnid = $node->tnid;
-    $translations = translation_node_get_translations($node->tnid);
-  }
-  else {
-    // We have no translation source nid, this could be a new set, emulate that.
-    $tnid = $node->nid;
-    $translations = array($node->language => $node);
+
+  // include functions from i18n_node.pages.inc
+  include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'i18n_node') . '/i18n_node.pages.inc';
+
+  // this is the part where this thing sorts out how to build a list of existing translations for this node
+  // since we use entity translation, the tnid isn't what we're using to build the translation list. we're using node->translations->data[keys]
+  $available_translations = $node->translations->data;
+  // iterate over each available translation and add its key (which is the 2 letter language code) to the array we call $translations with the node object as the value
+  foreach ($available_translations as $key => $value) {
+    $translations[$key] = $node;
   }
 
   $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));
@@ -243,16 +281,23 @@ function i18n_access_translation_node_overview($node) {
       // We load the full node to check whether the user can edit it.
       $translation_node = node_load($translations[$langcode]->nid);
       $path = 'node/' . $translation_node->nid;
-      $title = i18n_node_translation_link($translation_node->title, $path, $langcode);
-      if (node_access('update', $translation_node)) {
+
+      // Account for title field module:
+      if (isset($translation_node->title_field) && isset($translation_node->title_field[$langcode])) {
+        $title = i18n_node_translation_link($translation_node->title_field[$langcode][0]['value'], $path, $langcode);
+      }
+      else {
+        $title = i18n_node_translation_link($translation_node->title, $path, $langcode);
+      }
+      if (i18n_access_node_access($translation_node, 'update', $user, $langcode)) {
         $text = t('edit');
         $path = 'node/' . $translation_node->nid . '/edit';
         $options[] = i18n_node_translation_link($text, $path, $langcode);
       }
       $status = $translation_node->status ? t('Published') : t('Not published');
-      $status .= $translation_node->translate ? ' - <span class="marker">' . t('outdated') . '</span>' : '';
+      $status .= $translation_node->translate ? ' - ' . t('outdated') . '' : '';
       if ($translation_node->nid == $tnid) {
-        $language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
+        $language_name = t('@language_name (source)', array('@language_name' => $language_name));
       }
     }
     else {
@@ -298,6 +343,52 @@ function i18n_access_menu() {
   return $items;
 }
 
+/**
+* Node-specific menu alterations.
+*/
+function i18n_access_menu_alter(&$items, $backup) {
+  if (isset($backup['node'])) {
+    $item = $backup['node'];
+    // Preserve the menu router item defined by other modules.
+    $callback['page callback'] = $item['page callback'];
+    $callback['file'] = $item['file'];
+    $callback['module'] = $item['module'];
+    $access_arguments = array_merge(array(1, $item['access callback']), $item['access arguments']);
+  }
+  else {
+    $access_arguments = array(1);
+  }
+
+  // Point the 'translate' tab to point to the i18n_access version of the translation overview page
+  $items['node/%node/translate']['page callback'] = 'i18n_access_translation_node_overview';
+
+  // There are 3 page arguments for the entity translation overview, only one for i18n_access:
+  $items['node/%node/translate']['page arguments'] = array(1);
+
+  // Pass in the i18n_access permissions
+  $items['node/%node/translate']['access arguments'] = $access_arguments;
+
+  // Point to i18n_access's include for the callback
+  $items['node/%node/translate']['file'] = 'i18n_access.module';
+
+  // Point to i18n_access module
+  $items['node/%node/translate']['module'] = 'i18n_access';
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function i18n_access_module_implements_alter(&$implementations, $hook) {
+  switch ($hook) {
+    case 'menu_alter':
+      // Move our hook_menu_alter implementation to the end of the list.
+      $group = $implementations['i18n_access'];
+      unset($implementations['i18n_access']);
+      $implementations['i18n_access'] = $group;
+      break;
+  }
+}
+
 /**
  * Admin settings form.
  */