From e2d639c7e4ecde07027b6410d65ea334a8eb9f8b Mon Sep 17 00:00:00 2001 From: YUE YU Date: Sat, 24 Aug 2024 04:19:42 +0800 Subject: [PATCH 1/4] option added --- relis_app/controllers/Screening.php | 1 + relis_app/helpers/bm_helper.php | 1 + relis_app/helpers/tests/element_ut_helper.php | 1 + .../inclusion_mode_conflict_ut_helper.php | 7 ++++++ relis_app/helpers/tests/manager_ut_helper.php | 1 + .../libraries/entity_config/config_config.php | 14 +++++++++++ .../entity_config/config_configuration.php | 25 +++++++++++++++---- .../screen_phase_custom_configuration.php | 19 +++++++++++--- .../init_sql/project_initial_query.sql | 5 ++-- .../init_sql/project_initial_query.sql | 5 ++-- relis_app/models/Screening_dataAccess.php | 2 ++ 11 files changed, 69 insertions(+), 12 deletions(-) diff --git a/relis_app/controllers/Screening.php b/relis_app/controllers/Screening.php index d7c63c23..4be5b610 100644 --- a/relis_app/controllers/Screening.php +++ b/relis_app/controllers/Screening.php @@ -2878,6 +2878,7 @@ public function toggle_phase_config($phase_id) { 'use_kappa' => $config['use_kappa'], 'screening_validation_on' => $config['screening_validation_on'], 'screening_validator_assignment_type' => $config['screening_validator_assignment_type'], + 'assign_to_non_screened_validator_on' => $config['assign_to_non_screened_validator_on'], 'validation_default_percentage' => $config['validation_default_percentage'] ); $this->db2->where('screen_phase_id', $phase_id); diff --git a/relis_app/helpers/bm_helper.php b/relis_app/helpers/bm_helper.php index 11226d3b..1bb3db47 100755 --- a/relis_app/helpers/bm_helper.php +++ b/relis_app/helpers/bm_helper.php @@ -857,6 +857,7 @@ function is_screening_config_element($element) { 'screening_status_to_validate', 'screening_validator_assignment_type', 'use_kappa', + 'assign_to_non_screened_validator_on', 'validation_default_percentage' )); } diff --git a/relis_app/helpers/tests/element_ut_helper.php b/relis_app/helpers/tests/element_ut_helper.php index 41b7cb09..3e357347 100755 --- a/relis_app/helpers/tests/element_ut_helper.php +++ b/relis_app/helpers/tests/element_ut_helper.php @@ -3083,6 +3083,7 @@ private function update_screening_config() 'screening_validation_on' => array(0, 1), 'screening_validator_assignment_type' => 'Normal', 'screening_status_to_validate' => 'Excluded', + 'assign_to_non_screened_validator_on' => array(0, 1), 'validation_default_percentage' => 50 ); diff --git a/relis_app/helpers/tests/inclusion_mode_conflict_ut_helper.php b/relis_app/helpers/tests/inclusion_mode_conflict_ut_helper.php index 990bb7c0..4626e01d 100644 --- a/relis_app/helpers/tests/inclusion_mode_conflict_ut_helper.php +++ b/relis_app/helpers/tests/inclusion_mode_conflict_ut_helper.php @@ -57,6 +57,7 @@ private function changeModeWhenNoInclusionCriteria() { 'use_kappa' => true, 'screening_validation_on' => true, 'screening_validator_assignment_type' => "Normal", + 'assign_to_non_screened_validator_on' => false, 'validation_default_percentage' => 20 ); @@ -120,6 +121,7 @@ private function defaultCriteria_one() { 'use_kappa' => '1', 'screening_validation_on' => '0', 'screening_validator_assignment_type' => 'Normal', + 'assign_to_non_screened_validator_on' => '0', 'validation_default_percentage' => '10', )), 'affected_phases' => serialize(array( @@ -186,6 +188,7 @@ private function keepOneFromAny() { 'use_kappa' => '1', 'screening_validation_on' => '0', 'screening_validator_assignment_type' => 'Normal', + 'assign_to_non_screened_validator_on' => '0', 'validation_default_percentage' => '10', )), 'affected_phases' => serialize(array( @@ -226,6 +229,7 @@ private function keepOneFromAll() { 'use_kappa' => true, 'screening_validation_on' => true, 'screening_validator_assignment_type' => "Normal", + 'assign_to_non_screened_validator_on' => false, 'validation_default_percentage' => 20 ); @@ -258,6 +262,7 @@ private function keepOneFromAll() { 'use_kappa' => '1', 'screening_validation_on' => '0', 'screening_validator_assignment_type' => 'Normal', + 'assign_to_non_screened_validator_on' => '0', 'validation_default_percentage' => '10', )), 'affected_phases' => serialize(array( @@ -301,6 +306,7 @@ private function resetScreening() { 'use_kappa' => true, 'screening_validation_on' => true, 'screening_validator_assignment_type' => "Normal", + 'assign_to_non_screened_validator_on' => false, 'validation_default_percentage' => 20 ); @@ -333,6 +339,7 @@ private function resetScreening() { 'use_kappa' => '1', 'screening_validation_on' => '0', 'screening_validator_assignment_type' => 'Normal', + 'assign_to_non_screened_validator_on' => '0', 'validation_default_percentage' => '10', )), 'affected_phases' => serialize(array( diff --git a/relis_app/helpers/tests/manager_ut_helper.php b/relis_app/helpers/tests/manager_ut_helper.php index 6a5b1d6f..136f0c50 100755 --- a/relis_app/helpers/tests/manager_ut_helper.php +++ b/relis_app/helpers/tests/manager_ut_helper.php @@ -1133,6 +1133,7 @@ private function update_screening_config() 'screening_validation_on' => array(0, 1), 'screening_validator_assignment_type' => 'Normal', 'screening_status_to_validate' => 'Excluded', + 'assign_to_non_screened_validator_on' => array(0, 1), 'validation_default_percentage' => 50 ); diff --git a/relis_app/libraries/entity_config/config_config.php b/relis_app/libraries/entity_config/config_config.php index f07488c7..26b8f152 100755 --- a/relis_app/libraries/entity_config/config_config.php +++ b/relis_app/libraries/entity_config/config_config.php @@ -241,6 +241,20 @@ function get_configuration() 'on_list' => 'show' ); + $fields['assign_to_non_screened_validator_on'] = array( + 'field_title' => 'Assign to non-screened validator', + 'field_type' => 'text', + 'field_value' => '0_1', + 'field_size' => 1, + 'input_type' => 'select', + 'input_select_source' => 'yes_no', + 'input_select_values' => '', + 'initial_value' => 1, + 'on_add' => 'enabled', + 'on_edit' => 'enabled', + 'on_list' => 'show' + ); + $fields['classification_on'] = array( 'field_title' => 'Classification activated', 'field_type' => 'text', diff --git a/relis_app/libraries/entity_config/config_configuration.php b/relis_app/libraries/entity_config/config_configuration.php index bb8a0eb6..f5b5f210 100755 --- a/relis_app/libraries/entity_config/config_configuration.php +++ b/relis_app/libraries/entity_config/config_configuration.php @@ -255,7 +255,18 @@ function get_configuration() 'mandatory' => ' mandatory ' ); - $fields['validation_default_percentage'] = array( + $fields['assign_to_non_screened_validator_on'] = array( + 'field_title' => 'Assign to non-screened validator', + 'field_type' => 'int', + 'field_size' => '1', + 'field_value' => '1', + 'default_value' => '0', + 'input_type' => 'select', + 'input_select_source' => 'yes_no', + 'input_select_values' => '', + ); + + $fields['validation_default_percentage'] = array( 'field_title' => 'Default percentage of papers to validate', 'field_type' => 'int', 'field_value' => '20', @@ -450,7 +461,8 @@ function get_configuration() 'screening_validation_on' => array('group' => 'screen'), 'screening_validator_assignment_type' => array('group' => 'screen'), 'screening_status_to_validate' => array('group' => 'screen'), - 'validation_default_percentage' => array('group' => 'screen'), + 'assign_to_non_screened_validator_on' => array('group' => 'screen'), + 'validation_default_percentage' => array('group' => 'screen'), 'qa_on' => array('group' => 'qa'), 'qa_cutt_off_score' => array('group' => 'qa'), @@ -669,7 +681,8 @@ function get_configuration() 'use_kappa' => array(), 'validation_default_percentage' => array(), 'screening_status_to_validate' => array(), - 'screening_validator_assignment_type' => array(), + 'assign_to_non_screened_validator_on' => array(), + 'screening_validator_assignment_type' => array(), ), @@ -727,7 +740,8 @@ function get_configuration() 'key_paper_serial' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), 'validation_default_percentage' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), 'screening_status_to_validate' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), - 'screening_validator_assignment_type' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), + 'assign_to_non_screened_validator_on' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), + 'screening_validator_assignment_type' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), ), @@ -812,7 +826,8 @@ function get_configuration() 'screening_validation_on' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), 'screening_validator_assignment_type' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), 'screening_status_to_validate' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), - 'validation_default_percentage' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), + 'assign_to_non_screened_validator_on' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), + 'validation_default_percentage' => array('mandatory' => 'mandatory', 'field_state' => 'enabled'), ), 'top_links' => array( diff --git a/relis_app/libraries/screening/screen_phase_custom_configuration.php b/relis_app/libraries/screening/screen_phase_custom_configuration.php index cc2ec57d..33c5d1aa 100644 --- a/relis_app/libraries/screening/screen_phase_custom_configuration.php +++ b/relis_app/libraries/screening/screen_phase_custom_configuration.php @@ -166,7 +166,18 @@ function get_screening_phase_config() ); - $fields['screening_validator_assignment_type'] = array( + $fields['assign_to_non_screened_validator_on'] = array( + 'field_title' => 'Assign to non-screened validator', + 'field_type' => 'int', + 'field_size' => '1', + 'field_value' => '1', + 'default_value' => '0', + 'input_type' => 'select', + 'input_select_source' => 'yes_no', + 'input_select_values' => '', + ); + + $fields['screening_validator_assignment_type'] = array( 'field_title' => 'Validation mode', 'field_type' => 'text', 'field_value' => 'Normal', @@ -240,7 +251,8 @@ function get_screening_phase_config() 'use_kappa' => array(), 'screening_validation_on' => array(), 'screening_validator_assignment_type' => array(), - 'validation_default_percentage' => array(), + 'assign_to_non_screened_validator_on' => array(), + 'validation_default_percentage' => array(), ), @@ -285,7 +297,8 @@ function get_screening_phase_config() 'use_kappa' => array('mandatory' => '', 'field_state' => 'enabled'), 'screening_validation_on' => array('mandatory' => '', 'field_state' => 'enabled'), 'screening_validator_assignment_type' => array('mandatory' => '', 'field_state' => 'enabled'), - 'validation_default_percentage' => array('mandatory' => '', 'field_state' => 'enabled'), + 'assign_to_non_screened_validator_on' => array('mandatory' => '', 'field_state' => 'enabled'), + 'validation_default_percentage' => array('mandatory' => '', 'field_state' => 'enabled'), ), diff --git a/relis_app/libraries/table_config/init_sql/project_initial_query.sql b/relis_app/libraries/table_config/init_sql/project_initial_query.sql index 9f883cbb..a0bbc310 100755 --- a/relis_app/libraries/table_config/init_sql/project_initial_query.sql +++ b/relis_app/libraries/table_config/init_sql/project_initial_query.sql @@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS `config` ( `validation_default_percentage` int(3) NOT NULL DEFAULT '20', `screening_reviewer_number` int(3) NOT NULL DEFAULT '2', `screening_status_to_validate` enum('IncludedExcluded','Excluded','Included') NOT NULL DEFAULT 'Excluded', + `assign_to_non_screened_validator_on` int(2) NOT NULL DEFAULT '0', `screening_validator_assignment_type` enum('Normal','Veto','Info') NOT NULL DEFAULT 'Normal', `qa_on` int(2) NOT NULL DEFAULT '0', `qa_open` int(2) NOT NULL DEFAULT '0', @@ -72,8 +73,8 @@ CREATE TABLE IF NOT EXISTS `config` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1;;;; -INSERT INTO `config` (`config_id`, `config_type`, `editor_url`, `editor_generated_path`, `csv_field_separator`, `csv_field_separator_export`, `screening_screening_conflict_resolution`, `screening_conflict_type`, `import_papers_on`, `assign_papers_on`, `screening_validation_on`, `screening_result_on`, `source_papers_on`, `search_strategy_on`,`key_paper_prefix`,`key_paper_serial`, `screening_status_to_validate`, `config_active`) VALUES -(1, 'default', 'http://127.0.0.1:8080/relis/texteditor', 'C:/dslforge_workspace', ';', ',', 'Unanimity', 'IncludeExclude', 1, 1, 1, 1, 1, 1,'Paper_',1, 'Excluded', 1);;;; +INSERT INTO `config` (`config_id`, `config_type`, `editor_url`, `editor_generated_path`, `csv_field_separator`, `csv_field_separator_export`, `screening_screening_conflict_resolution`, `screening_conflict_type`, `import_papers_on`, `assign_papers_on`, `screening_validation_on`, `screening_result_on`, `source_papers_on`, `search_strategy_on`,`key_paper_prefix`,`key_paper_serial`, `screening_status_to_validate`, `assign_to_non_screened_validator_on`, `config_active`) VALUES +(1, 'default', 'http://127.0.0.1:8080/relis/texteditor', 'C:/dslforge_workspace', ';', ',', 'Unanimity', 'IncludeExclude', 1, 1, 1, 1, 1, 1,'Paper_',1, 'Excluded', 0, 1);;;; DROP TABLE IF EXISTS `exclusion`;;;; CREATE TABLE IF NOT EXISTS `exclusion` ( diff --git a/relis_app/libraries/table_config/project/init_sql/project_initial_query.sql b/relis_app/libraries/table_config/project/init_sql/project_initial_query.sql index e08071ec..357062b1 100755 --- a/relis_app/libraries/table_config/project/init_sql/project_initial_query.sql +++ b/relis_app/libraries/table_config/project/init_sql/project_initial_query.sql @@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS `config` ( `validation_default_percentage` int(3) NOT NULL DEFAULT '20', `screening_reviewer_number` int(3) NOT NULL DEFAULT '2', `screening_status_to_validate` enum('IncludedExcluded','Excluded','Included') NOT NULL DEFAULT 'Excluded', + `assign_to_non_screened_validator_on` int(2) NOT NULL DEFAULT '0', `screening_validator_assignment_type` enum('Normal','Veto','Info') NOT NULL DEFAULT 'Normal', `qa_on` int(2) NOT NULL DEFAULT '0', `qa_open` int(2) NOT NULL DEFAULT '0', @@ -72,8 +73,8 @@ CREATE TABLE IF NOT EXISTS `config` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1;;;; -INSERT INTO `config` (`config_id`, `config_type`, `editor_url`, `editor_generated_path`, `csv_field_separator`, `csv_field_separator_export`, `screening_screening_conflict_resolution`, `screening_conflict_type`, `import_papers_on`, `assign_papers_on`, `screening_validation_on`, `screening_result_on`, `source_papers_on`, `search_strategy_on`,`key_paper_prefix`,`key_paper_serial`, `screening_status_to_validate`, `config_active`) VALUES -(1, 'default', 'http://127.0.0.1:8080/relis/texteditor', 'C:/dslforge_workspace', ';', ',', 'Unanimity', 'IncludeExclude', 1, 1, 1, 1, 1, 1,'Paper_',1,'Excluded', 1);;;; +INSERT INTO `config` (`config_id`, `config_type`, `editor_url`, `editor_generated_path`, `csv_field_separator`, `csv_field_separator_export`, `screening_screening_conflict_resolution`, `screening_conflict_type`, `import_papers_on`, `assign_papers_on`, `screening_validation_on`, `screening_result_on`, `source_papers_on`, `search_strategy_on`,`key_paper_prefix`,`key_paper_serial`, `screening_status_to_validate`, `assign_to_non_screened_validator_on`, `config_active`) VALUES +(1, 'default', 'http://127.0.0.1:8080/relis/texteditor', 'C:/dslforge_workspace', ';', ',', 'Unanimity', 'IncludeExclude', 1, 1, 1, 1, 1, 1,'Paper_',1,'Excluded', 0, 1);;;; DROP TABLE IF EXISTS `exclusion`;;;; CREATE TABLE IF NOT EXISTS `exclusion` ( diff --git a/relis_app/models/Screening_dataAccess.php b/relis_app/models/Screening_dataAccess.php index b03aa89c..89bf9c02 100755 --- a/relis_app/models/Screening_dataAccess.php +++ b/relis_app/models/Screening_dataAccess.php @@ -145,6 +145,7 @@ function edit_screening_config($config, $phase_id, $affected_phases) { 'use_kappa' => $config['use_kappa'], 'screening_validation_on' => $config['screening_validation_on'], 'screening_validator_assignment_type' => $config['screening_validator_assignment_type'], + 'assign_to_non_screened_validator_on' => $config['assign_to_non_screened_validator_on'], 'validation_default_percentage' => $config['validation_default_percentage'] ); if (!$phase_id) $config_save['screening_on'] = $config['screening_on']; @@ -386,6 +387,7 @@ private function add_phase_config($phase_id) { 'use_kappa' => $config['use_kappa'], 'screening_validation_on' => $config['screening_validation_on'], 'screening_validator_assignment_type' => $config['screening_validator_assignment_type'], + 'assign_to_non_screened_validator_on' => $config['assign_to_non_screened_validator_on'], 'validation_default_percentage' => $config['validation_default_percentage'] ); $this->db_current->where('screen_phase_id', $phase_id); From 8618595898f637d2c37781e19b7713262942e8c9 Mon Sep 17 00:00:00 2001 From: YUE YU Date: Tue, 27 Aug 2024 09:19:32 +0800 Subject: [PATCH 2/4] Validation assigned to other reviewer --- relis_app/controllers/Screening.php | 186 +++++++++++++++--- relis_app/models/Screening_dataAccess.php | 8 + .../assign_papers_screen_validation.php | 8 +- 3 files changed, 174 insertions(+), 28 deletions(-) diff --git a/relis_app/controllers/Screening.php b/relis_app/controllers/Screening.php index 4be5b610..e5e7f43e 100644 --- a/relis_app/controllers/Screening.php +++ b/relis_app/controllers/Screening.php @@ -2104,6 +2104,14 @@ public function validate_screen_set($data = array()) } } // print_test($users); + if (get_appconfig_element('assign_to_non_screened_validator_on')){ + // Get assignable papers + $user_papers_map = array(); + foreach ($_assign_user as $user_id => $user_name) { + $user_papers_map[$user_id] = $this->get_assignable_papers($user_id, $screening_phase_id, $papers['to_assign']); + } + $data['user_papers_map'] = $user_papers_map; + } $data['users'] = $_assign_user; $data['number_papers'] = count($papers['to_assign']); $data['number_papers_assigned'] = count($papers['assigned']); @@ -2123,6 +2131,22 @@ public function validate_screen_set($data = array()) $this->load->view('shared/body', $data); } + function get_assignable_papers($user_id, $screen_phase_id, $papers) { + // Gets a list of papers that the user has screened + $screened_papers = $this->Screening_dataAccess->get_user_screened_papers($user_id, $screen_phase_id); + $screened_paper_ids = array_column($screened_papers, 'paper_id'); + + // Filter out papers that the user has not screened + $assignable_papers = array(); + foreach ($papers as $paper) { + if (!in_array($paper['id'], $screened_paper_ids)) { + $assignable_papers[] = $paper; + } + } + + return $assignable_papers; + } + public function get_papers_by_criteria($data = array()) { header('Content-Type: application/json'); $validation_by_criteria = $this->input->post('validation_by_criteria'); @@ -2288,6 +2312,7 @@ function save_assign_screen_validation() $papers_sources = $post_arr['papers_sources']; $paper_source_status = $post_arr['paper_source_status']; $screening_phase_info = active_screening_phase_info(); + $screen_phase_id = $screening_phase_info['screen_phase_id']; $phase_title = $screening_phase_info['phase_title']; $reviews_per_paper = 1; if ($validation_by_exclusion_criteria_toggle == 'on'){ @@ -2303,39 +2328,148 @@ function save_assign_screen_validation() $papers = $papers_all['to_assign']; } $papers_to_validate_nbr = round(count($papers) * $percentage / 100); + if ($papers_to_validate_nbr <= 0) { + $data['err_msg'] = " No papers selected for assignment. Please increase the percentage of papers to be assigned."; + $this->validate_screen_set($data); + return; + } $operation_description = "Assign $percentage % ($papers_to_validate_nbr) of " . $paper_source_status . " papers for $phase_title"; // print_test($papers); shuffle($papers); // randomize the list $assign_papers = array(); $this->db2 = $this->load->database(project_db(), TRUE); $operation_code = active_user_id() . "_" . time(); - foreach ($papers as $key => $value) { - if ($key < $papers_to_validate_nbr) { - $assign_papers[$key]['paper'] = $value['id']; - $assign_papers[$key]['users'] = array(); - $assignment_save = array( - 'paper_id' => $value['id'], - 'user_id' => '', - 'assignment_note' => '', - 'assignment_type' => screening_validator_assignment_type(), - 'operation_code' => $operation_code, - 'assignment_mode' => 'auto', - 'assignment_role' => 'Validation', - 'screening_phase' => $currect_screening_phase, - 'assigned_by' => $this->session->userdata('user_id') - ); - $j = 1; - //the table to save assignments + if (get_appconfig_element('assign_to_non_screened_validator_on')){ + // Get assignable papers for each user + $user_papers_map = array(); + foreach ($users as $user) { + $user_papers_map[$user] = $this->get_assignable_papers($user, $screen_phase_id, $papers); + + } + + // Sort users by the number of assignable papers from low to high + uasort($user_papers_map, function($a, $b) { + return count($a) > count($b); + }); + + // Get all assignable papers + $all_assignable_papers = array(); + foreach ($user_papers_map as $user_papers) { + foreach ($user_papers as $paper) { + $all_assignable_papers[$paper['id']] = $paper; + } + } + $all_assignable_papers = array_values($all_assignable_papers); + +// print_test('papers_to_validate_nbr: '.$papers_to_validate_nbr); + + if (count($all_assignable_papers) < $papers_to_validate_nbr) { + $data['err_msg'] = " Selected users cannot be assigned the required number of papers. Please select more users or reduce the percentage of papers to be assigned."; + $this->validate_screen_set($data); + return; + } + + // The number of papers each user has been assigned + $assigned_papers = array(); + foreach ($users as $user) { + $assigned_papers[$user] = 0; + } + + foreach ($all_assignable_papers as $paper) { + // Get validators who can be assigned this paper + $eligible_users = array(); + foreach ($user_papers_map as $user => $user_papers) { + if (in_array($paper, $user_papers)) { + if (!isset($assign_papers[$user])) { + $assign_papers[$user] = []; + } + $eligible_users[$user] = count($assign_papers[$user]); + } + } + + // Sort in ascending order according to the number of papers assigned + asort($eligible_users); + + $final_user = null; + foreach ($eligible_users as $user => $assigned_count) { + if (is_null($final_user)) { + $final_user = $user; + } elseif ($assigned_count == $assigned_papers[$final_user]) { + // If the number of assigned papers is the same, select validators with fewer papers to be assigned + if (count($user_papers_map[$user]) < count($user_papers_map[$final_user])) { + $final_user = $user; + } + } else { + break; + } + } + + $assign_papers[$final_user][] = $paper; // papers assigned under best average + $assigned_papers[$final_user]++; // number of papers assigned + + } + + // Assign papers as expected number + for ($i = 0, $j =0; $j < $papers_to_validate_nbr; $i++){ + foreach ($users as $user){ + if ($j >= $papers_to_validate_nbr){ + break; + } + if ($assigned_papers[$user] > 0) { + $assignments_to_save[] = array( + 'paper_id' => $assign_papers[$user][$i]['id'], + 'user_id' => $user, + 'assignment_note' => '', + 'assignment_type' => screening_validator_assignment_type(), + 'operation_code' => $operation_code, + 'assignment_mode' => 'auto', + 'assignment_role' => 'Validation', + 'screening_phase' => $currect_screening_phase, + 'assigned_by' => $this->session->userdata('user_id') + ); + $assigned_papers[$user]--; + $j++; + } + } + } + +// print_test($assignments_to_save);exit(); + + if (!empty($assignments_to_save)) { $table_name = get_table_configuration('screening', 'current', 'table_name'); - while ($j <= $reviews_per_paper) { - $temp_user = ($key % count($users)) + $j; - if ($temp_user >= count($users)) - $temp_user = $temp_user - count($users); - array_push($assign_papers[$key]['users'], $users[$temp_user]); - $assignment_save['user_id'] = $users[$temp_user]; - //print_test($assignment_save); - $this->db2->insert($table_name, $assignment_save); - $j++; + $this->db2->insert_batch($table_name, $assignments_to_save); + } + + } + else { + foreach ($papers as $key => $value) { + if ($key < $papers_to_validate_nbr) { + $assign_papers[$key]['paper'] = $value['id']; + $assign_papers[$key]['users'] = array(); + $assignment_save = array( + 'paper_id' => $value['id'], + 'user_id' => '', + 'assignment_note' => '', + 'assignment_type' => screening_validator_assignment_type(), + 'operation_code' => $operation_code, + 'assignment_mode' => 'auto', + 'assignment_role' => 'Validation', + 'screening_phase' => $currect_screening_phase, + 'assigned_by' => $this->session->userdata('user_id') + ); + $j = 1; + //the table to save assignments + $table_name = get_table_configuration('screening', 'current', 'table_name'); + while ($j <= $reviews_per_paper) { + $temp_user = ($key % count($users)) + $j; + if ($temp_user >= count($users)) + $temp_user = $temp_user - count($users); + array_push($assign_papers[$key]['users'], $users[$temp_user]); + $assignment_save['user_id'] = $users[$temp_user]; + //print_test($assignment_save); + $this->db2->insert($table_name, $assignment_save); + $j++; + } } } } diff --git a/relis_app/models/Screening_dataAccess.php b/relis_app/models/Screening_dataAccess.php index 89bf9c02..e2c359a6 100755 --- a/relis_app/models/Screening_dataAccess.php +++ b/relis_app/models/Screening_dataAccess.php @@ -81,6 +81,14 @@ function select_screening_paper_by_criteria($source_status, $exclusion_criteria_ return $all_papers; } + function get_user_screened_papers($user_id, $screening_phase) { + $sql = "SELECT paper_id FROM screening_paper WHERE assignment_role='Screening' AND screening_phase = $screening_phase AND screening_status='Done' AND screening_active=1 + AND user_id = ? AND screening_phase = ? "; + + $user_screenings = $this->db_current->query($sql, array($user_id, $screening_phase))->result_array(); + return $user_screenings; + } + function get_all_screenings($screening_phase) { $sql = "select * from screening_paper where assignment_role='Screening' AND screening_phase = $screening_phase AND screening_status='Done' AND screening_active=1 "; diff --git a/relis_app/views/screening/assign_papers_screen_validation.php b/relis_app/views/screening/assign_papers_screen_validation.php index 57d11b0d..4a4028bf 100755 --- a/relis_app/views/screening/assign_papers_screen_validation.php +++ b/relis_app/views/screening/assign_papers_screen_validation.php @@ -64,8 +64,12 @@ echo '

Select validator(s)

'; $i=1; foreach ($users as $user_id => $user_name) { - echo checkbox_form_bm($user_name,'user_'.$i,'user_'.$user_id,$user_id); - $i++; + if (get_appconfig_element('assign_to_non_screened_validator_on')){ + echo checkbox_form_bm($user_name.' (papers available to assign: ' . count($user_papers_map[$user_id]) . ')','user_'.$i,'user_'.$user_id,$user_id); + }else { + echo checkbox_form_bm($user_name, 'user_' . $i, 'user_' . $user_id, $user_id); + } + $i++; } From 8bb37f2d6bc1a1dd2a000ca7fe9099b89b7fecdf Mon Sep 17 00:00:00 2001 From: YUE YU Date: Tue, 3 Sep 2024 04:51:02 +0800 Subject: [PATCH 3/4] option name changed to 'Assign papers to validators who have not screened them' --- relis_app/libraries/entity_config/config_config.php | 2 +- relis_app/libraries/entity_config/config_configuration.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/relis_app/libraries/entity_config/config_config.php b/relis_app/libraries/entity_config/config_config.php index 26b8f152..40591ffe 100755 --- a/relis_app/libraries/entity_config/config_config.php +++ b/relis_app/libraries/entity_config/config_config.php @@ -242,7 +242,7 @@ function get_configuration() ); $fields['assign_to_non_screened_validator_on'] = array( - 'field_title' => 'Assign to non-screened validator', + 'field_title' => 'Assign papers to validators who have not screened them', 'field_type' => 'text', 'field_value' => '0_1', 'field_size' => 1, diff --git a/relis_app/libraries/entity_config/config_configuration.php b/relis_app/libraries/entity_config/config_configuration.php index f5b5f210..d66a31b8 100755 --- a/relis_app/libraries/entity_config/config_configuration.php +++ b/relis_app/libraries/entity_config/config_configuration.php @@ -256,7 +256,7 @@ function get_configuration() ); $fields['assign_to_non_screened_validator_on'] = array( - 'field_title' => 'Assign to non-screened validator', + 'field_title' => 'Assign papers to validators who have not screened them', 'field_type' => 'int', 'field_size' => '1', 'field_value' => '1', From 95fdb3c76bfb61eb63af3b443aa945b70ed63ccd Mon Sep 17 00:00:00 2001 From: YUE YU Date: Tue, 3 Sep 2024 16:35:43 +0800 Subject: [PATCH 4/4] testfile added for feature-80 --- .../tests/helpers/functions_helper.php | 25 +++ .../helpers/tests/screening_ut_helper.php | 185 ++++++++++++++++-- .../tests/testFiles/paper/1_bibPaper_b.bib | 7 + .../tests/testFiles/paper/1_bibPaper_c.bib | 7 + .../tests/testFiles/paper/2_bibPapers.bib | 21 ++ 5 files changed, 233 insertions(+), 12 deletions(-) create mode 100644 relis_app/helpers/tests/testFiles/paper/1_bibPaper_b.bib create mode 100644 relis_app/helpers/tests/testFiles/paper/1_bibPaper_c.bib create mode 100644 relis_app/helpers/tests/testFiles/paper/2_bibPapers.bib diff --git a/relis_app/helpers/tests/helpers/functions_helper.php b/relis_app/helpers/tests/helpers/functions_helper.php index 027ed187..9aeb1cc4 100755 --- a/relis_app/helpers/tests/helpers/functions_helper.php +++ b/relis_app/helpers/tests/helpers/functions_helper.php @@ -678,6 +678,31 @@ function save_assignment_screen($data) } } +//The purpose of this function is to handle the remove of screening entry from the database +function remove_screening($screen_id) +{ + $ci = get_instance(); + + $ci->db2 = $ci->load->database(project_db(), TRUE); + $config = "screen"; + $screen_detail = $ci->DBConnection_mdl->get_row_details($config, $screen_id); + $ci->db2->update('screening_paper', array('screening_active' => 0), array('screening_id' => $screen_id)); + $ci->db2->update('screening_paper', array('screening_status' => 'Pending'), array('screening_id' => $screen_id)); + update_paper_status_status($screen_detail['paper_id']); +} + +//The purpose of this function is to handle the removal of screening validation entries from the database +function remove_screening_validation($screen_id) +{ + $ci = get_instance(); + + $ci->db2 = $ci->load->database(project_db(), TRUE); + $config = "screen"; + $screen_detail = $ci->DBConnection_mdl->get_row_details($config, $screen_id); + $ci->db2->update('screening_paper', array('screening_active' => 0), array('screening_id' => $screen_id)); + $ci->db2->update('screening_paper', array('screening_status' => 'Pending'), array('screening_id' => $screen_id)); +} + /** * The purpose of this function is to retrieve and organize papers for screening based on the provided source, * source status, current phase, and assignment role diff --git a/relis_app/helpers/tests/screening_ut_helper.php b/relis_app/helpers/tests/screening_ut_helper.php index 639cb25b..0874b213 100755 --- a/relis_app/helpers/tests/screening_ut_helper.php +++ b/relis_app/helpers/tests/screening_ut_helper.php @@ -50,6 +50,7 @@ function run_tests() $this->displayPaperScreen(); $this->listScreen(); $this->validateScreenSet(); + $this->saveAssignmentValidation_assignToNotScreenedUser(); $this->saveAssignmentValidation_emptyPercentage(); $this->saveAssignmentValidation_invalidPercentage(); $this->saveAssignmentValidation_emptyUsers(); @@ -1538,6 +1539,166 @@ private function validateScreenSet() /* * Test 34 * Action : save_assign_screen_validation + * Description : save the assignments of papers for screening validation to whom have not screened them. + * Expected Paper assignements : + * - The numbers of papers each user are assigned all between 1 and 2. (5 papers for 3 user) + * - assign_papers_valida operation inserted in operations table in the project DB + */ + private function saveAssignmentValidation_assignToNotScreenedUser() + { + $action = "save_assign_screen_validation"; + $test_name = "Save the assignments of papers for screening validation to whom have not screened them"; + + $test_assignement = "Paper assignements"; + $expected_assignement = "Assigned"; + + //activate assign_to_non_screened_validator_on + $this->ci->db->query("UPDATE relis_dev_correct_" . getProjectShortName() . ".config SET assign_to_non_screened_validator_on = 1"); + + //initialise the Database + $this->TestInitialize(); + //select screening phase as active phase + $screenPhaseID = getScreeningPhaseId("Title"); + $this->http_client->response("screening", "select_screen_phase" . "/" . $screenPhaseID); + + $AdminUserId = getAdminUserId(); + $TestUserId = getTestUserId(); + $DemoUserId = getDemoUserId(); + + //add 1 paper & screening paper for admin and test user + addBibtextPapersToProject("relis_app/helpers/tests/testFiles/paper/1_bibPaper.bib"); + $data = [ + "number_of_users" => 2, + "screening_phase" => $screenPhaseID, + "papers_sources" => "all", + "paper_source_status" => "all", + "user_1" => $AdminUserId, + "user_2" => $TestUserId, + "reviews_per_paper" => 2 + ]; + save_assignment_screen($data); + for ($i = 1; $i <= 2; $i++) { + $screening_paper = $this->ci->db->query("SELECT * FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE screening_decision IS NULL AND assignment_role = 'Screening'")->row_array(); + $data = ["criteria_ex" => 1, "criteria_in" => "", "note" => "", "screening_id" => $screening_paper['screening_id'], "decision" => "excluded", "operation_type" => "new", "screening_phase" => $screening_paper['screening_phase'], "operation_source" => "list_screen/mine_screen", "paper_id" => $screening_paper['paper_id'], "assignment_id" => $screening_paper['screening_id'], "screen_type" => "simple_screen"]; + save_screening($data); + } + + //add 2 papers & screening papers for admin user + addBibtextPapersToProject("relis_app/helpers/tests/testFiles/paper/2_bibPapers.bib"); + $data = [ + "number_of_users" => 1, + "screening_phase" => $screenPhaseID, + "papers_sources" => "all", + "paper_source_status" => "all", + "user_1" => $AdminUserId, + "reviews_per_paper" => 1 + ]; + save_assignment_screen($data); + for ($i = 1; $i <= 2; $i++) { + $screening_paper = $this->ci->db->query("SELECT * FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE screening_decision IS NULL AND assignment_role = 'Screening'")->row_array(); + $data = ["criteria_ex" => 1, "criteria_in" => "", "note" => "", "screening_id" => $screening_paper['screening_id'], "decision" => "excluded", "operation_type" => "new", "screening_phase" => $screening_paper['screening_phase'], "operation_source" => "list_screen/mine_screen", "paper_id" => $screening_paper['paper_id'], "assignment_id" => $screening_paper['screening_id'], "screen_type" => "simple_screen"]; + save_screening($data); + } + + //add 1 paper & screening paper for test user + addBibtextPapersToProject("relis_app/helpers/tests/testFiles/paper/1_bibPaper_b.bib"); + $data = [ + "number_of_users" => 1, + "screening_phase" => $screenPhaseID, + "papers_sources" => "all", + "paper_source_status" => "all", + "user_1" => $TestUserId, + "reviews_per_paper" => 1 + ]; + save_assignment_screen($data); + $screening_paper = $this->ci->db->query("SELECT * FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE screening_decision IS NULL AND assignment_role = 'Screening'")->row_array(); + $data = ["criteria_ex" => 1, "criteria_in" => "", "note" => "", "screening_id" => $screening_paper['screening_id'], "decision" => "excluded", "operation_type" => "new", "screening_phase" => $screening_paper['screening_phase'], "operation_source" => "list_screen/mine_screen", "paper_id" => $screening_paper['paper_id'], "assignment_id" => $screening_paper['screening_id'], "screen_type" => "simple_screen"]; + save_screening($data); + + //add 1 paper & screening paper for demo user + addBibtextPapersToProject("relis_app/helpers/tests/testFiles/paper/1_bibPaper_c.bib"); + $data = [ + "number_of_users" => 1, + "screening_phase" => $screenPhaseID, + "papers_sources" => "all", + "paper_source_status" => "all", + "user_1" => $DemoUserId, + "reviews_per_paper" => 1 + ]; + save_assignment_screen($data); + $screening_paper = $this->ci->db->query("SELECT * FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE screening_decision IS NULL AND assignment_role = 'Screening'")->row_array(); + $data = ["criteria_ex" => 1, "criteria_in" => "", "note" => "", "screening_id" => $screening_paper['screening_id'], "decision" => "excluded", "operation_type" => "new", "screening_phase" => $screening_paper['screening_phase'], "operation_source" => "list_screen/mine_screen", "paper_id" => $screening_paper['paper_id'], "assignment_id" => $screening_paper['screening_id'], "screen_type" => "simple_screen"]; + save_screening($data); + + $postData = [ + "number_of_users" => 3, + "screening_phase" => getScreeningPhaseId("Title"), + "papers_sources" => 1, + "paper_source_status" => "Excluded", + "user_1" => getAdminUserId(), + "user_2" => getTestUserId(), + "user_3" => getDemoUserId(), + "percentage" => 100, + ]; + $response = $this->http_client->response($this->controller, $action, $postData, "POST"); + + if ($response['status_code'] >= 400) { + $actual_assignement = "" . $response['content'] . ""; + } else { + $actual_assignement = "Not assigned"; + + // Check if all the papers have been assigned as expected + $excludedPaperIds = $this->ci->db->query("SELECT paper_id FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE screening_decision='Excluded'")->result_array(); + $excludedPaperIdList = array(); + foreach ($excludedPaperIds as $paperId) { + $excludedPaperIdList[] = $paperId['paper_id']; + } + $excludedPaperIdList = array_unique($excludedPaperIdList); + $excludedPaperIdList = implode(',', $excludedPaperIdList); + + $users = [getAdminUserId(), getTestUserId(), getDemoUserId()]; + + $flag = 0;//Check if the number is as expected + foreach ($users as $user) { + $nbrOfAssignment = $this->ci->db->query("SELECT COUNT(*) AS row_count FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE user_id = $user AND paper_id IN (" . $excludedPaperIdList . ") AND assignment_role = 'validation'")->row_array()['row_count']; + if ($nbrOfAssignment == 1 or $nbrOfAssignment == 2){ + $flag = 1; + } + else{ + $flag = 0; + break; + } + } + + //Check if the assign_papers_valida operation is inserted in operations table in the project DB + $operation = $this->ci->db->query("SELECT * FROM relis_dev_correct_" . getProjectShortName() . ".operations WHERE operation_type = 'assign_papers_valida' AND operation_state = 'Active' AND operation_active = 1")->row_array(); + + if ($flag == 1 && !empty($operation)) { + $actual_assignement = "Assigned"; + } + + //deactivate assign_to_non_screened_validator_on + $this->ci->db->query("UPDATE relis_dev_correct_" . getProjectShortName() . ".config SET assign_to_non_screened_validator_on = 0"); + + // Remove screenings + $screening_ids = $this->ci->db->query("SELECT screening_id FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE user_id IN ('" . $TestUserId . "', '" . $DemoUserId . "', '" . $AdminUserId . "') AND assignment_role='Screening'")->result_array(); + foreach ($screening_ids as $id) { + remove_screening($id['screening_id']); + } + + // Remove screening validations + $validation_ids = $this->ci->db->query("SELECT screening_id FROM relis_dev_correct_" . getProjectShortName() . ".screening_paper WHERE user_id IN ('" . $TestUserId . "', '" . $DemoUserId . "', '" . $AdminUserId . "') AND assignment_role='Validation'")->result_array(); + foreach ($validation_ids as $id) { + remove_screening_validation($id['screening_id']); + } + } + + run_test($this->controller, $action, $test_name, $test_assignement, $expected_assignement, $actual_assignement); + } + + /* + * Test 35 + * Action : save_assign_screen_validation * Description : Handle the saving of paper assignments for screening validation with empty percentage in POST request. * Expected Paper assignements : * - No papers are added in the project DB in screening_paper table @@ -1581,7 +1742,7 @@ private function saveAssignmentValidation_emptyPercentage() } /* - * Test 35 + * Test 36 * Action : save_assign_screen_validation * Description : Handle the saving of paper assignments for screening validation with invalid percentage (>100) in POST request. * Expected Paper assignements : @@ -1626,7 +1787,7 @@ private function saveAssignmentValidation_invalidPercentage() } /* - * Test 36 + * Test 37 * Action : save_assign_screen_validation * Description : Handle the saving of paper assignments for screening validation with empty users in POST request. * Expected Paper assignements : @@ -1670,7 +1831,7 @@ private function saveAssignmentValidation_emptyUsers() } /* - * Test 37 + * Test 38 * Action : save_assign_screen_validation * Description : save the assignments of papers for screening validation with 50% of paper assignement. * Expected Paper assignements : @@ -1721,7 +1882,7 @@ private function saveAssignmentValidation_50percent() } /* - * Test 38 + * Test 39 * Action : save_assign_screen_validation * Description : save the assignments of papers for screening validation with 100% of paper assignement. * Expected Paper assignements : @@ -1781,7 +1942,7 @@ private function saveAssignmentValidation_100percent() } /* - * Test 39 + * Test 40 * Action : save_assign_screen_validation * Description : save the assignments of papers for screening validation by exclusion criteria EC1 with 100%. * Expected Paper assignements : @@ -1843,7 +2004,7 @@ private function saveAssignmentValidation_by1criteria() } /* - * Test 40 + * Test 41 * Action : screen_paper_validation * Description : handle the display of a paper for screening validation * Expected HTTP Response Code : 200 OK (indicating a successful response from the server). @@ -1870,7 +2031,7 @@ private function screenPaperValidation() } /* - * Test 41 + * Test 42 * Action : screen_completion * Description : calculate and display the completion progress of screening validation for users. * Expected HTTP Response Code : 200 OK (indicating a successful response from the server). @@ -1897,7 +2058,7 @@ private function screenValidationCompletion() } /* - * Test 42 + * Test 43 * Action : screen_validation_result * Description : Display screening validation statistics and results. * Expected HTTP Response Code : 200 OK (indicating a successful response from the server). @@ -1924,7 +2085,7 @@ private function screenValidationResult() } /* - * Test 43 + * Test 44 * Action : remove_screening * Description : Remove a screening entry from the database. * Expected update in DB @@ -1954,7 +2115,7 @@ private function removeScreening() } /* - * Test 44 + * Test 45 * Action : remove_screening_validation * Description : Handle the removal of screening validation entries from the database. * Expected update in DB @@ -1984,7 +2145,7 @@ private function removeScreeningValidation() } /* - * Test 45 + * Test 46 * Action : screening * Description : Display screening home page with 4 papers screened. * Expected result: check if displayed data is correct @@ -2015,7 +2176,7 @@ private function screening_4papersScreened() } /* - * Test 46 + * Test 47 * Action : screening * Description : Display screening home page with 0 paper screened. * Expected result: check if displayed data is correct diff --git a/relis_app/helpers/tests/testFiles/paper/1_bibPaper_b.bib b/relis_app/helpers/tests/testFiles/paper/1_bibPaper_b.bib new file mode 100644 index 00000000..a2ce16c9 --- /dev/null +++ b/relis_app/helpers/tests/testFiles/paper/1_bibPaper_b.bib @@ -0,0 +1,7 @@ +@ARTICLE{Abouzahra2018, + author = {Abouzahra, Anas and Sabraoui, Ayoub and Afdel, Karim}, + journal = {Advances in Science, Technology and Engineering Systems Journal3}, + title = {A Practical Approach for Extending DSMLs by Composing their Meta -models}, + year = {2018}, + volume = {6} +} \ No newline at end of file diff --git a/relis_app/helpers/tests/testFiles/paper/1_bibPaper_c.bib b/relis_app/helpers/tests/testFiles/paper/1_bibPaper_c.bib new file mode 100644 index 00000000..d13a9340 --- /dev/null +++ b/relis_app/helpers/tests/testFiles/paper/1_bibPaper_c.bib @@ -0,0 +1,7 @@ +@MISC{Adam2016, + author = {Adam, Kai and Butting, Arvid and Heim, Robert and Kautz, Oliver and Rumpe, Bernhard and Wortmann, Andreas}, + title = {Model-driven separation of concerns for service robotics}, + year = {2016}, + doi = {10.1145/3023147.3023151}, + paper = {https://dx.doi.org/10.1145/3023147.3023151} +} \ No newline at end of file diff --git a/relis_app/helpers/tests/testFiles/paper/2_bibPapers.bib b/relis_app/helpers/tests/testFiles/paper/2_bibPapers.bib new file mode 100644 index 00000000..224bb4a1 --- /dev/null +++ b/relis_app/helpers/tests/testFiles/paper/2_bibPapers.bib @@ -0,0 +1,21 @@ +@ARTICLE{Ahmad2020, + author = {Ahmad, Muhammad Waqas and Anwar, Muhammad Waseem and Azam, Farooque and Rasheed, Yawar and Ghani, Usman and Ahmad, Mukhtar}, + journal = {Lecture Notes in Computer Science}, + title = {AutoNet: Meta-model for Seamless Integration of Timed Automata and Colored Petri Nets}, + year = {2020}, + pages = {307--319}, + volume = {12133}, + doi = {10.1007/978-3-030-47679-3\_26}, + paper = {http://dx.doi.org/10.1007/978-3-030-47679-3\_26} +} +@INBOOK{Alexander2007, + author = {Alexander, Perry}, + pages = {263--276}, + publisher = {Morgan Kaufmann}, + title = {15 - Domain Interactions}, + year = {2007}, + address = {Burlington}, + series = {Systems on Silicon}, + type = {Book Section}, + abstract = {It is noted that the decisions made locally in one domain can have impacts on system-level requirements and other domain specific requirements. Rosetta defines an interaction as a collection of mechanisms for describing how information flows between modeling domains. Each interaction defines three kinds of information transfer. Translators define how information is transformed as it flows through a parameter shared by two facets. Translators handle both information translation and coordination of the communication process. Functors define transformations of facets from one domain to another. Because facets are simply Rosetta values, these transformations take the form of functions whose domain and range include facet types. Furthermore, algebra combinators, or simply combinators define mechanisms for combining two facets to produce a new facet. The primary use for combinator is to provide a capability for composing and refining or abstracting two facets in a single step. Moreover, combinators are like functors, except that the domain of a combinator must include two facets that can be composed into a single facet.} +} \ No newline at end of file