"multipart/form-data"); for ($i = 0; $i < 10; ++$i) { $form['upload'. $i] = array('#type' => 'file'); } $form['submit_same'] = array('#type' => 'submit', '#value' => t('Upload more')); $form['submit_next'] = array('#type' => 'submit', '#value' => t('Next')); break; case 2: // create release $form['name'] = array( '#type' => 'textfield', '#title' => t('Name'), '#required' => TRUE, '#size' => 30, '#maxlength' => 255, '#description' => t('Name of the release') ); $form['version'] = array( '#type' => 'textfield', '#title' => t('Version'), '#required' => TRUE, '#size' => 30, '#maxlength' => 255, '#description' => t('Version of the release') ); $form['description'] = array( '#type' => 'textarea', '#title' => t('Description'), '#required' => TRUE, '#cols' => 60, '#rows' => 5, '#description' => t('Description of the release') ); // create form elements for file selection $pass = origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'user.my_password'); $files = get_files_from_ftp(variable_get('origo_ftp', ''), $user->name, $pass); $i = 0; $platform_values = drupal_map_assoc(array_merge(array('ignore', 'remove'), variable_get('origo_release_platforms', array()))); foreach ($files as $file) { $form['file'. $i] = array( '#type' => 'value', '#value' => $file); $form['platform'. $i] = array( '#type' => 'select', '#options' => $platform_values, '#default_value' => 'ignore' ); ++$i; } $form['count'] = array('#type' => 'value', '#value' => $i); $form['submit'] = array('#type' => 'submit', '#value' => t('Create Release')); break; default: ///blah blah, really you should never get here break; } return $form; } /** * Special theme function for our wizard form. * @param $form the form elements to template * @return the string of the themed form */ function theme_origo_home_create_release_form($form) { $output = ''; // Unfortunately we don't have access to $form_state in the theming function, // thus we switch between the pages according to the button that was clicked: // - we only render the second page, if either "next" was clicked (in this case // the user wants to advance), or the "Create Release" button (in case the user // made an error, and the 2nd form is re-displayed. if ($form['#parameters'][1]['values']['op'] != t('Next') && $form['#parameters'][1]['values']['op'] != t('Create Release')) { // first page $output .= drupal_render($form); $output .= t('

It is also possible to use FTP to upload files, connect to '. variable_get('origo_ftp', '') .' using your Origo user name and password. Don\'t upload whole directories because only files will be processed and added to your release.'); } else { // second page $output .= drupal_render($form['name']); $output .= drupal_render($form['version']); $output .= drupal_render($form['description']); // add button for setting all platforms $platforms = array_diff( variable_get('origo_release_platforms', Array()), array('other', 'all', 'source') ); $js = << 0) { $js = drupal_substr($js, 0, -2); } $js .= << longestMatch) { defaultPlatform = parseInt(platform) + 4; // + 4 is added because 'ignore', 'other', 'all', 'source' are not added longestMatch = platforms[platform].length; } } document.getElementById('edit-platform'+i).selectedIndex = defaultPlatform; // get next file i++; file = $("#uploadFileName"+i).html(); } }); $(".showOnLoad").css("display", "block"); }); EOF; drupal_add_js($js, 'inline'); $output .= t('
'); // Format file selection table $header = array( array('data' => t('File')), array('data' => t('Action/Platform')) ); $data = array(); for ( $i = 0; $i < $form['count']['#value']; ++$i ) { $row = array( array('data' => $form['file'. $i]['#value'], 'id' => 'uploadFileName'. $i), array('data' => drupal_render($form['platform'. $i])) ); $data[] = $row; } $output .= theme('table', $header, $data); $output .= '
'; $output .= t('It is also possible to use the various IDE integrations to create a release. ' .'If your desired platform is not listed, please report an issue and it will be added.

'); } $output .= drupal_render($form); return $output; } /** * Additional validation for our wizard form. * @param $form_id id of the submited form * @param $form_values values of the submited form */ function origo_home_create_release_form_validate($form, &$form_state) { switch ($form_state['storage']['step']) { // file upload case 1: break; // create release case 2: $any_file_included = False; for ($i = 0; !$any_file_included && $i < $form_state['values']['count']; ++$i) { $current_value = $form_state['values']['platform'. $i]; $any_file_included = ($current_value != 'ignore') && ($current_value != 'remove'); } if (!$any_file_included) { form_set_error('', t('At least one file has to be included in a release, select an appropriate platform for each file that should be included')); } break; } } /** * Handle the form submit * @param $form_id id of the submited form * @param $form_values values of the submited form */ function origo_home_create_release_form_submit($form, &$form_state) { global $user; switch ($form_state['storage']['step']) { case 1: // file upload $connection_id = ftp_connect(variable_get('origo_ftp', '')); $pass = origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'user.my_password'); if ( ftp_login($connection_id, $user->name, $pass) ) { $uploaded = False; for ($i = 0; $i < 10; ++$i) { if ($source = file_save_upload('upload'. $i)) { if (ftp_put($connection_id, $source->filename, $source->filepath, FTP_BINARY)) { $uploaded = True; } } } if ($uploaded) { drupal_set_message(t('File uploaded')); } ftp_close($connection_id); } //tell Drupal we are redrawing the same form $form_state['rebuild'] = TRUE; break; case 2: // create release $files_remove = array(); $files_release = array(); for ($i = 0; $i < $form_state['values']['count']; ++$i) { $cur_file = $form_state['values']['file'. $i]; $current_platform = $form_state['values']['platform'. $i]; if ($current_platform == 'remove') { $files_remove[] = $cur_file; } elseif ($current_platform != 'ignore') { $files_release[] = array('name' => $cur_file, 'platform' => $current_platform); } } // remove files selected to be removed if (!empty($files_remove)) { $connection_id = ftp_connect(variable_get('origo_ftp', '')); $pass = origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'user.my_password'); if (ftp_login($connection_id, $user->name, $pass)) { foreach ($files_remove as $file) { ftp_delete($connection_id, $file); } ftp_close($connection_id); } } // execute the api call origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'release.add', (int)variable_get('origo_project_id', 0), $form_state['values']['name'], $form_state['values']['description'], $form_state['values']['version'], $files_release); drupal_set_message(t('Your release has been created.')); drupal_goto('download'); break; } } // Returns a human readable size function _origo_home_size_hum_read($size) { $i=0; $iec = array("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); if (is_numeric($size) && $size > 0) { while (($size/1024)>1) { $size=$size/1024; $i++; } if ($i == 0) { return sprintf('%d ', $size) . $iec[$i]; } else { return sprintf('%0.2f ', $size) . $iec[$i]; } } else { return "0 B"; } } /** * Show releases for project */ function origo_home_release_page() { global $pager_total; drupal_add_js(drupal_get_path('module', 'origo_home') .'/projects.js', 'module', 'header', FALSE, FALSE); drupal_add_css(drupal_get_path('module', 'origo_home') .'/projects.css', 'module', 'all', FALSE, FALSE); return _origo_xmlrpc_table_get_page('_releases_dataprovider'); } /** * This dataprovider feeds the data for the xmlrpc-table for releases. */ function _releases_dataprovider($page, $pagesize, $order, $direction) { $header = array( "", array('data' => t('Date'), 'width' => '15%', 'field' => 'date', 'sort' => 'asc'), array('data' => t('Version'), 'width' => '10%', 'field' => 'version'), array('data' => t('Name'), 'width' => '55%', 'colspan' => '2', 'field' => 'Name'), array('data' => t('Platform'), 'width' => '10%'), array('data' => t('Size'), 'width' => '10%'), ); // Some small helper functions: function cmp_release_date($a, $b) { return $a['creation_time'] - $b['creation_time']; } function cmp_release_version($a, $b) { // Split both version $sa = explode('.', $a['version']); $sb = explode('.', $b['version']); for ($i = 0; $i < count($sb); $i++) { if (is_numeric($sa[$i]) && is_numeric($sb[$i]) && $sa[$i] != $sb[$i]) { return $sa[$i] - $sb[$i]; } elseif ($sa[$i] != $sb[$i]) { return strcasecmp($sa[$i], $sb[$i]); } } } function cmp_release_name($a, $b) { return strcasecmp($a['name'], $b['name']); } // Retrieve the stuff $releases = origo_auth_xml_rpc(variable_get('origo_api_internal', ''), 'internal_release.list', (int)variable_get('origo_project_id', 1)); if ((int)xmlrpc_errno() > 0) { $rows[] = array(array('data' => t('An internal error occured: the download list is currently not available.'), 'colspan' => '7', 'class' => 'message')); return array( 'header' => $header, 'rows' => $rows, 'options' => array('style' => 'width: 100%', 'id' => 'releases') ); } if (count($releases) < 1) return array( 'header' => $header, 'rows' => array(array(array('data' => t('This project has not released anything, yet.'), 'colspan' => '7', 'class' => 'message'))), 'total_size' => 0, 'options' => array('style' => 'width: 100%', 'id' => 'releases') ); // Get filesizes: foreach ($releases as $k => $release) { for ($i = 1; $i <= $release['file_count']; $i++) { $escaped = rawurlencode($release['file_name_'. $i]); $headers = get_headers('http://'. variable_get('origo_internal_file_server_ip', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $escaped, 1); $releases[$k]['file_size_'. $i] = $headers['Content-Length'] > 0 ? $headers['Content-Length'] : "-"; } } if (empty($order)) $order = 'Date'; if (empty($direction)) $direction = 'asc'; // Order it switch ($order) { case 'Date': usort($releases, 'cmp_release_date'); break; case 'Name': usort($releases, 'cmp_release_name'); break; case 'Version': usort($releases, 'cmp_release_version'); break; } // Invert the order if we are actually ascending: $releases = $direction == "asc" ? array_reverse($releases) : $releases; // Mark the first release to be expanded (will later be replaced with result) $releases[0]['expanded'] = TRUE; // Create the rows foreach ($releases as $release) { // Build the switcher imgs $img = drupal_get_path('module', 'origo_home') . ($release['expanded'] ? "/img/checkbox_minus.gif" : "/img/checkbox_plus.gif"); $alt = drupal_get_path('module', 'origo_home') . ($release['expanded'] ? "/img/checkbox_plus.gif" : "/img/checkbox_minus.gif"); // Add the release row: $rows[] = array( array('data' => "". $alt ."", 'class' => "release_description"), array('data' => date('Y-m-d H:i', $release['creation_time']), 'width' => '15%', 'class' => 'release_description'), array('data' => check_plain($release['version']), 'width' => '10%', 'class' => 'release_description'), array('data' => l($release['name'], 'download/'. $release['release_id']), 'width' => '55%', 'colspan' => '2', 'class' => 'release_description'), ); // the last col is only shown if we have the right to edit the releases: if (user_access('origo delete release')) { $rows[count($rows)-1][] = array( 'data' => l('[remove]', 'download/delete/'. $release['release_id']), 'width' => '20%', 'colspan' => '2', 'class' => 'release_description' ); } else { $rows[count($rows)-1][] = array('data' => "", 'colspan' => 4, 'class' => 'release_description'); } // Build the files for this release $base_path = drupal_get_path('module', 'origo_home'); for ($i = 1; $i <= $release['file_count']; $i++) { $metalink = l( "metalink ", variable_get('origo_download_path', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $release['file_name_'. $i] .'.metalink', array( 'html' => True ) ); $rows[]['data'] = array( "", array('data' => "", 'colspan' => '3', 'class' => 'release_file'), array('data' => l($release['file_name_'. $i], variable_get('origo_download_path', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $release['file_name_'. $i]) .' ('. $metalink .')', 'width' => '53%', 'class' => 'release_file'), array('data' => t($release['file_platform_'. $i]), 'width' => '10%', 'class' => 'release_file'), array('data' => t(_origo_home_size_hum_read($release['file_size_'. $i])), 'width' => '10%', 'class' => 'release_file') ); $rows[count($rows)-1]['class'] = ($release['expanded'] ? "" : "collapsed ") ."release". $release['release_id']; } } // If we have no release just return a message: if (empty($rows)) { $rows[] = array(array('data' => t('No downloads available.'), 'colspan' => '6', 'class' => 'message')); } return array( 'header' => $header, 'rows' => $rows, 'total_size' => $total_size, 'options' => array('style' => 'width: 100%', 'id' => 'releases') ); } /** * Show release for project */ function origo_home_release_detail_page($release_id) { $output = ''; // get release $release = origo_auth_xml_rpc(variable_get('origo_api_internal', ''), 'internal_release.retrieve', (int)$release_id); $output .= '

'. check_plain($release['name']) .' - '. check_plain($release['version']) .' ('. date('Y-m-d H:i', $release['creation_time']) .')

'; $description= $release['description']; $output .= check_markup($description, FILTER_FORMAT_DEFAULT, False) .'

'; $header = array( array('data' => t('File'), 'width' => '80%'), array('data' => t('Platform'), 'width' => '10%'), array('data' => t('Size'), 'width' => '10%'), ); $rows = array(); $color = '#EEEEEE'; for ($i = 1; $i <= $release['file_count']; $i++) { $size = '-'; $headers = get_headers('http://'. variable_get('origo_internal_file_server_ip', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $release['file_name_'. $i], 1); $filesize = $headers['Content-Length']; if ($filesize > 0) { $size = _origo_home_size_hum_read($filesize); } $rows[] = array( array('data' => l($release['file_name_'. $i], variable_get('origo_download_path', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $release['file_name_'. $i]) .' ('. l('metalink', variable_get('origo_download_path', '') .'/'. variable_get('origo_project_name', '') .'/'. $release['release_id'] .'/'. $release['file_name_'. $i] .'.metalink') .')', 'width' => '80%', 'style' => 'background-color:'. $color), array('data' => t($release['file_platform_'. $i]), 'width' => '10%', 'style' => 'background-color:'. $color), array('data' => t($size), 'width' => '10%', 'style' => 'background-color:'. $color), ); } if (empty($rows)) { $rows[] = array(array('data' => t('No files available.'), 'colspan' => '3', 'class' => 'message')); } $output .= theme('table', $header, $rows, array('style' => 'width:100%')); return $output; } /** * Page to delete a release. * * @param release_id Release ID */ function origo_home_release_delete_page($release_id) { $output = ''; // get release $release = origo_auth_xml_rpc(variable_get('origo_api_internal', ''), 'internal_release.retrieve', (int)$release_id); $output .= '

'. check_plain($release['name']) .' - '. check_plain($release['version']) .' ('. date('Y-m-d H:i', $release['creation_time']) .')

'; $description= $release['description']; $output .= check_markup($description, FILTER_FORMAT_DEFAULT, False) .'

'; $output .= '

'; $output .= t('Do you really want to delete this release?') .'

'; $output .= drupal_get_form('origo_home_release_delete_form', $release_id); return $output; } /** * Form to delete a release. * * @param $release_id Release ID */ function origo_home_release_delete_form(&$form_state, $release_id) { // store the id of the current release $form['release_id'] = array( '#type' => 'hidden', '#value' => $release_id ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Delete'), ); return $form; } /** * Submit form handler to delete a release. * * @param $release_id Release ID */ function origo_home_release_delete_form_submit($form, &$form_state) { $project_id = variable_get('origo_project_id', 0); origo_auth_xmlrpc_session(variable_get('origo_api', ''), 'release.delete', (int)$project_id, (int)$form_state['values']['release_id']); if ((int)xmlrpc_errno() > 0) { form_set_error(NULL, t('Error: '. xmlrpc_error_msg())); } else { drupal_set_message('Release has been deleted.'); drupal_goto('download'); } }