diff --git a/translators/tmgmt_local/includes/tmgmt_local.entity.inc b/translators/tmgmt_local/includes/tmgmt_local.entity.inc index 639b98a..a6701f8 100644 --- a/translators/tmgmt_local/includes/tmgmt_local.entity.inc +++ b/translators/tmgmt_local/includes/tmgmt_local.entity.inc @@ -93,7 +93,24 @@ class TMGMTLocalTask extends Entity { * Overrides Entity::defaultLabel(). */ protected function defaultLabel() { - return t('Task for @job assigned to @translator', array('@job' => $this->getJob()->label(), '@translator' => entity_label('user', user_load($this->tuid)))); + if (empty($this->tuid)) { + if (empty($this->title)) { + return t('Task for @job', array('@job' => $this->getJob()->label())); + } + else { + return $this->title; + } + } + else { + if (empty($this->title)) { + return t('Task for @job assigned to @translator', array('@job' => $this->getJob()->label(), '@translator' => entity_label('user', user_load($this->tuid)))); + } + else { + return t('@title assigned to @translator', array('@title' => $this->title, '@translator' => entity_label('user', user_load($this->tuid)))); + } + } + + } /** @@ -461,4 +478,62 @@ class TMGMTLocalTaskItem extends Entity { public function completed() { $this->status = TMGMT_LOCAL_TASK_ITEM_STATUS_COMPLETED; } -} \ No newline at end of file + + /** + * Updates the values for a specific substructure in the data array. + * + * The values are either set or updated but never deleted. + * + * @param $key + * Key pointing to the item the values should be applied. + * The key can be either be an array containing the keys of a nested array + * hierarchy path or a string with '][' or '|' as delimiter. + * @param $values + * Nested array of values to set. + */ + public function updateData($key, $values = array()) { + foreach ($values as $index => $value) { + // In order to preserve existing values, we can not aplly the values array + // at once. We need to apply each containing value on its own. + // If $value is an array we need to advance the hierarchy level. + if (is_array($value)) { + $this->updateData(array_merge(tmgmt_ensure_keys_array($key), array($index)), $value); + } + // Apply the value. + else { + drupal_array_set_nested_value($this->data, array_merge(tmgmt_ensure_keys_array($key), array($index)), $value); + } + } + } + + /** + * Array of translations. + * + * The structure is similar to the form API in the way that it is a possibly + * nested array with the following properties whose presence indicate that the + * current element is a text that might need to be translated. + * + * - #text: The translated text of the corresponding entry in the job item. + * - #status: The status of the translation. + * + * The key can be an alphanumeric string. + * + * @param array $key + * If present, only the subarray identified by key is returned. + * @param string $index + * Optional index of an attribute below $key. + * + * @return array + * A structured data array. + */ + public function getData(array $key = array(), $index = null) { + if (empty($key)) { + return $this->data; + } + if ($index) { + $key = array_merge($key, array($index)); + } + return drupal_array_get_nested_value($this->data, $key); + } + +} diff --git a/translators/tmgmt_local/includes/tmgmt_local.pages.inc b/translators/tmgmt_local/includes/tmgmt_local.pages.inc index 78df224..310fff4 100644 --- a/translators/tmgmt_local/includes/tmgmt_local.pages.inc +++ b/translators/tmgmt_local/includes/tmgmt_local.pages.inc @@ -34,6 +34,7 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = '#type' => 'textfield', '#title' => t('Title'), '#default_value' => $task->title, + '#access' => user_access('administer tmgmt') || user_access('administer translation tasks'), ); $form['status'] = array( @@ -41,6 +42,7 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = '#title' => t('Status'), '#options' => tmgmt_local_task_statuses(), '#default_value' => $wrapper->status->value(), + '#access' => user_access('administer tmgmt') || user_access('administer translation tasks'), ); $translators = tmgmt_local_translators($task->getJob()->source_language, $task->getJob()->target_language); @@ -50,6 +52,7 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = '#options' => $translators, '#empty_option' => t('- Select user -'), '#default_value' => $task->tuid, + '#access' => user_access('administer tmgmt') || user_access('administer translation tasks'), ); if ($view = views_get_view('tmgmt_local_task_items')) { @@ -57,7 +60,7 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = '#type' => 'item', '#title' => $view->get_title(), '#prefix' => '
', - '#markup' => $view->preview('block'), + '#markup' => $view->preview('block', $task->tltid), '#attributes' => array('class' => array('tmgmt-local-task-items')), '#suffix' => '
', '#weight' => 10, @@ -66,6 +69,7 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = // Add the buttons and action links. $form['actions']['#type'] = 'actions'; + $form['actions']['#access'] = user_access('administer tmgmt') || user_access('administer translation tasks'); $form['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Save task'), @@ -89,6 +93,11 @@ function tmgmt_local_task_form($form, &$form_state, TMGMTLocalTask $task, $op = */ function tmgmt_local_task_form_submit($form, &$form_state) { $task = entity_ui_form_submit_build_entity($form, $form_state); + // If the task isn't assigned to anyone but doesn't have the unassigned status + // update it. + if ($task->tuid == 0 && !$task->isUnassigned()) { + $task->unassign(); + } $task->save(); } @@ -149,7 +158,7 @@ function tmgmt_local_translation_form($form, &$form_state, TMGMTLocalTaskItem $t // Reverse the order to get the correct order. foreach (array_reverse(element_children($data)) as $key) { $flattened = tmgmt_flatten_data($data[$key], $key); - $form['translation'][$key] = tmgmt_local_translation_form_element($flattened, $job_item, $zebra); + $form['translation'][$key] = tmgmt_local_translation_form_element($flattened, $task_item, $zebra); } // Add the form actions as well. @@ -197,19 +206,19 @@ function tmgmt_local_translation_form_save_as_completed_submit($form, &$form_sta $task = $form_state['task']; /** - * @var TMGMTLocalTaskItem $item. + * @var TMGMTLocalTaskItem $task_item. */ $task_item = $form_state['task_item']; $task_item->translated(); $task_item->save(); /** - * @var TMGMTJobItem $item. + * @var TMGMTJobItem $job_item. */ $job_item = $form_state['job_item']; - // Set the job item to 'needs review' and task to finished states. - $job_item->needsReview(); + // Add the translations to the job item. + $job_item->addTranslatedData($task_item->getData()); // Mark the task as completed if all assigned job items are at needs done. $all_done = TRUE; @@ -235,27 +244,25 @@ function tmgmt_local_translation_form_save_as_completed_submit($form, &$form_sta */ function tmgmt_local_translation_form_save_submit($form, &$form_state) { /** - * @var TMGMTJobItem $item. + * @var TMGMTTaskItem $task_item. */ - $job_item = $form_state['job_item']; + $task_item = $form_state['task_item']; // Write the translated data into the task item. $values = $form_state['values']; foreach ($values as $key => $value) { if (isset($value['translation'])) { - $update['#translation'] = array( - '#text' => $value['translation'], - ); - $job_item->updateData($key, $update); + $update['#text'] = $value['translation']; + $task_item->updateData($key, $update); } } - $job_item->save(); + $task_item->save(); } /** * Builds a translation form element. */ -function tmgmt_local_translation_form_element($data, TMGMTJobItem $item, &$zebra) { +function tmgmt_local_translation_form_element($data, TMGMTLocalTaskItem $item, &$zebra) { static $flip = array( 'even' => 'odd', 'odd' => 'even', @@ -263,7 +270,7 @@ function tmgmt_local_translation_form_element($data, TMGMTJobItem $item, &$zebra $form = array(); - $job = $item->getJob(); + $job = $item->getJobItem()->getJob(); $language_list = language_list(); foreach (element_children($data) as $key) { @@ -292,14 +299,15 @@ function tmgmt_local_translation_form_element($data, TMGMTJobItem $item, &$zebra $form[$target_key]['translation'] = array( '#type' => 'textarea', '#title' => $target_language->name, - '#default_value' => isset($data[$key]['#translation']['#text']) ? $data[$key]['#translation']['#text'] : '', + '#default_value' => $item->getData(tmgmt_ensure_keys_array($key), '#text'), //'#required' => TRUE, ); $form[$target_key]['actions'] = array( '#type' => 'container', ); - $completed = !empty($data[$key]['#status']) && $data[$key]['#status'] == TMGMT_DATA_ITEM_STATE_TRANSLATED; + $status = $item->getData(tmgmt_ensure_keys_array($key), '#status'); + $completed = $status == TMGMT_DATA_ITEM_STATE_TRANSLATED; if ($completed) { $form[$target_key]['actions']['reject-' . $target_key] = array( '#type' => 'submit', @@ -345,9 +353,9 @@ function tmgmt_local_translation_form_update_state_submit($form, &$form_state) { $values = $form_state['values']; /** - * @var TMGMTJobItem $item. + * @var TMGMTLocalTaskItem $item. */ - $item = $form_state['item']; + $item = $form_state['task_item']; $action = $form_state['triggering_element']['#tmgmt_local_action']; $key = $form_state['triggering_element']['#tmgmt_local_key']; @@ -355,10 +363,7 @@ function tmgmt_local_translation_form_update_state_submit($form, &$form_state) { // Write the translated data into the job item. if (isset($values[$key]) && is_array($values[$key]) && isset($values[$key]['translation'])) { $update['#status'] = $action == 'finish' ? TMGMT_DATA_ITEM_STATE_TRANSLATED : TMGMT_DATA_ITEM_STATE_PENDING; - $update['#translation'] = array( - '#text' => $values[$key]['translation'], - ); - + $update['#text'] = $values[$key]['translation']; $item->updateData($key, $update); $item->save(); @@ -375,7 +380,7 @@ function tmgmt_local_translation_form_update_state_ajax($form, &$form_state) { $commands = array(); $render_data = drupal_array_get_nested_value($form, $key); $commands[] = ajax_command_replace(NULL, drupal_render($render_data)); - tmgmt_ui_write_request_messages($form_state['item']->getJob()); + tmgmt_ui_write_request_messages($form_state['job_item']->getJob()); $commands[] = ajax_command_html('#tmgmt-status-messages-' . strtolower($render_data['#parent_label'][0]), theme('status_messages')); return array('#type' => 'ajax', '#commands' => $commands); } diff --git a/translators/tmgmt_local/includes/tmgmt_local_ui.controller.inc b/translators/tmgmt_local/includes/tmgmt_local_ui.controller.inc index bdb9079..d22c790 100644 --- a/translators/tmgmt_local/includes/tmgmt_local_ui.controller.inc +++ b/translators/tmgmt_local/includes/tmgmt_local_ui.controller.inc @@ -30,6 +30,14 @@ class TMGMTLocalTaskUIController extends EntityDefaultUIController { 'access arguments' => array('delete', $this->entityType, $id_count), 'type' => MENU_CALLBACK, ); + $items[$this->path . '/' . $wildcard . '/unassign'] = array( + 'page callback' => 'drupal_get_form', + 'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $id_count, $id_count + 1), + 'load arguments' => array($this->entityType), + 'access callback' => 'entity_access', + 'access arguments' => array('unassign', $this->entityType, $id_count), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -41,6 +49,9 @@ class TMGMTLocalTaskUIController extends EntityDefaultUIController { case 'delete': $confirm_question = t('Are you sure you want to delete the translation task %label?', array('%label' => $entity->label())); return confirm_form($form, $confirm_question, $this->path); + case 'unassign': + $confirm_question = t('Are you sure you want to unassign from the translation task %label?', array('%label' => $entity->label())); + return confirm_form($form, $confirm_question, $this->path); } drupal_not_found(); exit; @@ -54,6 +65,10 @@ class TMGMTLocalTaskUIController extends EntityDefaultUIController { case 'delete': $entity->delete(); return t('Deleted the translation local task %label.', array('%label' => $entity->label())); + case 'unassign': + $entity->unassign(); + $entity->save(); + return t('Unassigned from translation local task %label.', array('%label' => $entity->label())); } return FALSE; } diff --git a/translators/tmgmt_local/tmgmt_local.install b/translators/tmgmt_local/tmgmt_local.install index 247a28c..36ade11 100644 --- a/translators/tmgmt_local/tmgmt_local.install +++ b/translators/tmgmt_local/tmgmt_local.install @@ -191,7 +191,7 @@ function tmgmt_local_update_7000() { * Create local task items. */ function tmgmt_local_update_7001() { - $result = db_query('SELECT lt.tltid, ji.tjiid, ji.state from {tmgmt_local_task} lt INNER JOIN {tmgmt_job} j ON j.tjid = lt.tjid INNER JOIN {tmgmt_job_item} ji ON ji.tjid = j.tjid'); + $result = db_query('SELECT lt.tltid, ji.tjiid, ji.state, ji.data from {tmgmt_local_task} lt INNER JOIN {tmgmt_job} j ON j.tjid = lt.tjid INNER JOIN {tmgmt_job_item} ji ON ji.tjid = j.tjid'); $insert = db_insert('tmgmt_local_task_item') ->fields(array('tltid', 'tjiid', 'status', 'data')); foreach ($result as $row) { @@ -210,12 +210,46 @@ function tmgmt_local_update_7001() { $status = 0; break; } + $translation = (array)_tmgmt_local_translated_data_7001(unserialize($row->data)); $insert->values(array( 'tltid' => $row->tltid, 'tjiid' => $row->tjiid, 'status' => $status, - 'data' => serialize(array()), + 'data' => serialize($translation), )); } $insert->execute(); } + +/** + * Data parsing helper function for tmgmt_local_update_7001(). + * + * Copies #translation texts from the source data array to the translation + * data array. + * + * @param array $source + * The original source data array of the job item. + * + * @return array + * The filled translation data array. + */ +function _tmgmt_local_translated_data_7001($source) { + if (!empty($source['#translation']['#text'])) { + $translation['#text'] = $source['#translation']['#text']; + if ((!empty($source['#status']))) { + $translation['#status'] = $source['#status']; + } + return $translation; + } + else { + $translation = array(); + foreach (element_children($source) as $key) { + if ($return = _tmgmt_local_translated_data_7001($source[$key])) { + $translation[$key] = $return; + } + } + if (!empty($translation)) { + return $translation; + } + } +} diff --git a/translators/tmgmt_local/tmgmt_local.module b/translators/tmgmt_local/tmgmt_local.module index d3e349e..9821059 100644 --- a/translators/tmgmt_local/tmgmt_local.module +++ b/translators/tmgmt_local/tmgmt_local.module @@ -466,12 +466,19 @@ function tmgmt_local_task_access($op, $task = NULL, $account = NULL) { return TRUE; } + if (!$account) { + global $user; + $account = $user; + } + // @todo - probably need refinement when we introduce more module permissions. switch ($op) { case 'view': case 'update': return user_access('provide translation services', $account); break; + case 'unassign': + return !empty($task->tuid) && $task->tuid == $account->uid && user_access('provide translation services', $account); } } diff --git a/translators/tmgmt_local/tmgmt_local.test b/translators/tmgmt_local/tmgmt_local.test index 78d0594..3c3517d 100644 --- a/translators/tmgmt_local/tmgmt_local.test +++ b/translators/tmgmt_local/tmgmt_local.test @@ -280,6 +280,16 @@ class TMGMTLocalTestCase extends TMGMTBaseTestCase { $this->assertText(t('Completed')); $this->assertText(t('Untranslated')); + // Check the job data, which should not yet contain the translation. + entity_get_controller('tmgmt_job')->resetCache(array($job->tjid)); + entity_get_controller('tmgmt_job_item')->resetCache(); + $job = tmgmt_job_load($job->tjid); + list($item1, $item2) = array_values($job->getItems()); + // The text in the first item should be available for review, the + // translation of the second item not. + $this->assertEqual($item1->getData(array('dummy', 'deep_nesting', '#translation', '#text')), $translation1); + $this->assertEqual($item2->getData(array('dummy', 'deep_nesting', '#translation', '#text')), ''); + // Check the overview page, the task should still show in progress. $this->drupalGet('translate'); $this->assertText(t('Pending')); diff --git a/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_item_operations.inc b/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_item_operations.inc index 9bbeba4..5fbd0d6 100644 --- a/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_item_operations.inc +++ b/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_item_operations.inc @@ -8,6 +8,7 @@ class tmgmt_local_task_handler_field_item_operations extends views_handler_field_entity { function render($values) { + global $user; /** * @var TMGMTLocalTaskItem $item */ @@ -15,15 +16,16 @@ class tmgmt_local_task_handler_field_item_operations extends views_handler_field $element = array(); $element['#theme'] = 'links'; - $element['#attributes'] = array('class' => array('inline')); - if ($item->isUntranslated() && entity_access('view', 'tmgmt_local_task_item', $item)) { + $element['#attributes'] = array('class' => array('links', 'inline')); + // Only allow to translate if the job is assigned to this user. + if (entity_access('view', 'tmgmt_local_task_item', $item) && $item->getTask()->tuid == $user->uid) { $element['#links']['translate'] = array( 'href' => 'translate/' . $item->tltid . '/item/' . $item->tltiid, 'query' => array('destination' => current_path()), 'attributes' => array( - 'title' => t('Translate'), + 'title' => $item->isUntranslated() ? t('Translate') : t('View'), ), - 'title' => t('translate'), + 'title' => $item->isUntranslated() ? t('translate') : t('view'), ); } return drupal_render($element); diff --git a/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_operations.inc b/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_operations.inc index 48bc58c..1fae5a9 100644 --- a/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_operations.inc +++ b/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_operations.inc @@ -17,7 +17,7 @@ class tmgmt_local_task_handler_field_operations extends views_handler_field_enti $element = array(); $element['#theme'] = 'links'; - $element['#attributes'] = array('class' => array('inline')); + $element['#attributes'] = array('class' => array('links', 'inline')); $uri = $task->uri(); if (entity_access('view', 'tmgmt_local_task', $task)) { $element['#links']['view'] = array( @@ -26,13 +26,6 @@ class tmgmt_local_task_handler_field_operations extends views_handler_field_enti 'title' => t('view'), ); } - if (entity_access('delete', 'tmgmt_local_task', $task)) { - $element['#links']['delete'] = array( - 'href' => $uri['path'] . '/delete', - 'query' => array('destination' => current_path()), - 'title' => t('delete'), - ); - } if (user_access('administer translation tasks') && tmgmt_local_translation_access($task) && empty($task->tuid)) { $element['#links']['assign'] = array( 'href' => 'manage-translate/assign-tasks/' . $task->tltid, @@ -63,7 +56,7 @@ class tmgmt_local_task_handler_field_operations extends views_handler_field_enti 'title' => t('assign'), ); } - if (tmgmt_local_translation_access($task) && !empty($task->tuid)) { + if (!empty($task->tuid) && entity_access('unassign', 'tmgmt_local_task', $task)) { $element['#links']['unassign'] = array( 'href' => 'translate/' . $task->tltid . '/unassign', 'query' => array('destination' => current_path()), @@ -73,6 +66,13 @@ class tmgmt_local_task_handler_field_operations extends views_handler_field_enti 'title' => t('unassign'), ); } + if (entity_access('delete', 'tmgmt_local_task', $task)) { + $element['#links']['delete'] = array( + 'href' => $uri['path'] . '/delete', + 'query' => array('destination' => current_path()), + 'title' => t('delete'), + ); + } return drupal_render($element); } diff --git a/translators/tmgmt_local/views/tmgmt_local_task_items.view.inc b/translators/tmgmt_local/views/tmgmt_local_task_items.view.inc index fa238b8..18feb5a 100644 --- a/translators/tmgmt_local/views/tmgmt_local_task_items.view.inc +++ b/translators/tmgmt_local/views/tmgmt_local_task_items.view.inc @@ -42,6 +42,15 @@ $handler->display->display_options['fields']['status']['field'] = 'status'; $handler->display->display_options['fields']['operations']['id'] = 'operations'; $handler->display->display_options['fields']['operations']['table'] = 'tmgmt_local_task_item'; $handler->display->display_options['fields']['operations']['field'] = 'operations'; +/* Contextual filter: Translation Task Item: Tltid */ +$handler->display->display_options['arguments']['tltid']['id'] = 'tltid'; +$handler->display->display_options['arguments']['tltid']['table'] = 'tmgmt_local_task_item'; +$handler->display->display_options['arguments']['tltid']['field'] = 'tltid'; +$handler->display->display_options['arguments']['tltid']['default_action'] = 'empty'; +$handler->display->display_options['arguments']['tltid']['default_argument_type'] = 'fixed'; +$handler->display->display_options['arguments']['tltid']['summary']['number_of_records'] = '0'; +$handler->display->display_options['arguments']['tltid']['summary']['format'] = 'default_summary'; +$handler->display->display_options['arguments']['tltid']['summary_options']['items_per_page'] = '25'; /* Display: Block */ $handler = $view->new_display('block', 'Block', 'block'); @@ -64,11 +73,10 @@ $translatables['tmgmt_local_task_items'] = array( t('last ยป'), t('Translation Task'), t('Translation Management Job Item'), - t('Translation task item ID'), - t('.'), - t(','), + t('Label'), t('Status'), t('Operations'), - t('Label'), + t('All'), t('Block'), ); +