cvs diff: Diffing modules/project
Index: modules/project/CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/CHANGELOG.txt,v
retrieving revision 1.5.2.1
diff -u -F^f -r1.5.2.1 CHANGELOG.txt
--- modules/project/CHANGELOG.txt 25 Jul 2006 00:12:26 -0000 1.5.2.1
+++ modules/project/CHANGELOG.txt 10 Sep 2006 19:51:02 -0000
@@ -1,3 +1,8 @@
+XX. September 2006
+-----------------
+- Split out releases into project_release.module and made them real nodes
+ (dww and merlinofchaos)
+
21. July 2006
-----------------
- Split out issue tracking to project_issue.module (dww)
Index: modules/project/project.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.inc,v
retrieving revision 1.75.2.16
diff -u -F^f -r1.75.2.16 project.inc
--- modules/project/project.inc 26 Jul 2006 07:18:01 -0000 1.75.2.16
+++ modules/project/project.inc 10 Sep 2006 19:51:03 -0000
@@ -173,7 +173,7 @@ function project_project_form(&$node) {
'#description' => t('Link to a live demo.'),
);
- if ($releases = project_release_load($node)) {
+ if ($releases = project_release_get_releases($node, false)) {
$form['project']['version'] = array(
'#type' => 'select',
'#title' => t('Default version'),
@@ -303,31 +303,34 @@ function project_project_view(&$node, $t
$breadcrumb = project_project_set_location($node, $breadcrumb);
menu_set_location($breadcrumb);
- if ($releases = project_release_load($node)) {
+ $releases = project_release_get_releases($node);
+ if ($releases) {
// Determine most suitable release
$overview = variable_get('project_release_overview', -1);
- foreach ($releases as $rid => $version) {
+ foreach ($releases as $rid => $release) {
// If the project has a preferred release, choose that.
+ $version = theme('project_release_version', $release);
if ($rid == $node->version) {
- $release = $rid;
+ $latest_release = $release;
break;
}
// If the version matches the default on the overview, prefer the first.
if (!isset($release) && strpos($version, $overview) === 0) {
- $release = $rid;
+ $latest_release = $release;
}
}
// Fallback to the latest
- if (!isset($release)) {
+ if (!isset($latest_release)) {
reset($releases);
- list($release) = each($releases);
+ $latest_release = current($releases);
}
- $release = project_release_load($release);
+ $release = $latest_release;
+ $version = theme('project_release_version', $release);
// Download section
$links = array();
- $links[] = '' . t('Download latest release (%version, %date, %size)', array('%version' => $release->version, '%date' => format_date($release->changed, 'small'), '%size' => format_size(filesize($release->path)))) . '';
+ $links[] = '' . t('Download latest release (%version, %date, %size)', array('%version' => $version, '%date' => format_date($release->changed, 'small'), '%size' => format_size(filesize($release->file_path)))) . '';
if ($release->changes) {
$links[] = l(t('Read release notes'), 'node/'. $node->nid .'/release', null, null, 'version-'. $release->version);
@@ -337,7 +340,7 @@ function project_project_view(&$node, $t
}
}
if (node_access('update', $node) && !variable_get('project_release_directory', '')) {
- $links[] = l(t('Add new release'), 'node/'. $node->nid .'/release/add');
+ $links[] = l(t('Add new release'), 'node/add/project_release/'. $node->nid);
}
if ($links) {
$output .= theme('item_list', $links, t('Releases'));
@@ -402,22 +405,6 @@ function project_project_view(&$node, $t
}
}
-function project_project_releases() {
- $node = node_load(arg(1));
-
- // Breadcrumb navigation
- $breadcrumb[] = array('path' => 'node/'. $node->nid .'/', 'title' => $node->title);
- $breadcrumb[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('Releases'));
- $breadcrumb = project_project_set_location($node, $breadcrumb);
-
- menu_set_location($breadcrumb);
-
- $output = project_release_list($node);
-
- drupal_set_title(check_plain($node->title));
- return $output;
-}
-
function project_project_load($node) {
$project = db_fetch_object(db_query('SELECT * FROM {project_projects} WHERE nid = %d', $node->nid));
Index: modules/project/project.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.install,v
retrieving revision 1.2.2.6
diff -u -F^f -r1.2.2.6 project.install
--- modules/project/project.install 10 Sep 2006 06:37:17 -0000 1.2.2.6
+++ modules/project/project.install 10 Sep 2006 19:51:03 -0000
@@ -22,25 +22,7 @@ function project_install() {
KEY project_projects_uri (uri(8))
) TYPE=MyISAM
/*!40100 DEFAULT CHARACTER SET utf8 */;");
- db_query("CREATE TABLE {project_releases} (
- rid int(10) unsigned NOT NULL default '0',
- nid int(10) unsigned NOT NULL default '0',
- fid int(10) unsigned NOT NULL default '0',
- path varchar(255) NOT NULL default '',
- created int(10) unsigned NOT NULL default '0',
- version varchar(255) NOT NULL default '',
- status tinyint(1) unsigned NOT NULL default '1',
- changes text,
- weight tinyint(3) unsigned NOT NULL default '0',
- changed int(10) unsigned NOT NULL default '0',
- hash varchar(32) NOT NULL default '',
- UNIQUE(path),
- PRIMARY KEY (`rid`),
- KEY project_releases_nid (nid)
- ) TYPE=MyISAM
- /*!40100 DEFAULT CHARACTER SET utf8 */;");
- break;
-
+
case 'pgsql':
db_query("CREATE TABLE {project_projects} (
nid int NOT NULL default '0',
@@ -57,20 +39,6 @@ function project_install() {
license varchar(255) default '' not null,
PRIMARY KEY (nid)
);");
- db_query("CREATE TABLE {project_releases} (
- rid int NOT NULL default '0',
- nid int NOT NULL default '0',
- fid int NOT NULL default '0',
- path varchar(255) NOT NULL default '',
- created int NOT NULL default '0',
- hash varchar(32) NOT NULL default '',
- version varchar(255) NOT NULL default '',
- changes text,
- weight smallint NOT NULL default '0',
- changed int NOT NULL default '0',
- status smallint default '1' not null,
- PRIMARY KEY (rid)
- );");
break;
}
@@ -230,6 +198,60 @@ function project_update_4() {
return $ret;
}
+/**
+ * Create the {project_release_nodes} table and transfer data into it.
+ */
+function project_update_5() {
+ $ret = array();
+
+ // First, create the new table.
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ $ret[] = update_sql("CREATE TABLE IF NOT EXISTS {project_release_nodes} (
+ nid int(10) unsigned NOT NULL default '0',
+ pid int(10) unsigned NOT NULL default '0',
+ tag varchar(255) NOT NULL default '0',
+ file_path varchar(255) NOT NULL default '',
+ file_date int(10) unsigned NOT NULL default '0',
+ file_hash varchar(32) NOT NULL default '',
+ rebuild tinyint(1) default '0',
+ version_super_major int(10) NOT NULL default 0,
+ version_super_minor int(10) NOT NULL default 0,
+ version_major int(10) NOT NULL default 0,
+ version_minor int(10) NOT NULL default 0,
+ version_extra varchar(255) NOT NULL default '',
+ PRIMARY KEY (`nid`),
+ KEY project_releases_pid (pid)
+ ) TYPE=MyISAM
+ /*!40100 DEFAULT CHARACTER SET utf8 */;");
+ break;
+
+ case 'pgsql':
+ if (!project_db_table_exists('project_release_nodes')) {
+ $ret[] = update_sql("CREATE TABLE {project_release_nodes} (
+ nid int NOT NULL default '0',
+ pid int NOT NULL default '0',
+ tag varchar(255) NOT NULL default '0',
+ file_path varchar(255) NOT NULL default '',
+ file_date int NOT NULL default '0',
+ file_hash varchar(32) NOT NULL default '',
+ rebuild smallint default '0',
+ version_super_major int NOT NULL default 0,
+ version_super_minor int NOT NULL default 0,
+ version_major int NOT NULL default 0,
+ version_minor int NOT NULL default 0,
+ version_extra varchar(255) NOT NULL default '',
+ PRIMARY KEY (nid),
+ KEY project_releases_pid (pid)
+ );");
+ }
+ break;
+ }
+ // TODO: migrate data from old {project_releases} table
+ // TODO: drop old {project_releases} table
+}
+
function project_db_table_exists($table) {
switch ($GLOBALS['db_type']) {
case 'mysql':
Index: modules/project/project.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.module,v
retrieving revision 1.239.2.13
diff -u -F^f -r1.239.2.13 project.module
--- modules/project/project.module 7 Sep 2006 19:25:39 -0000 1.239.2.13
+++ modules/project/project.module 10 Sep 2006 19:51:04 -0000
@@ -1,21 +1,17 @@
project_projects
-// project releases -> project_releases
-
$path = drupal_get_path('module', 'project');
if (file_exists("$path/project.inc")) {
require_once "$path/project.inc";
- require_once "$path/release.inc";
}
function project_help($section) {
switch ($section) {
case 'admin/modules#description':
- return t('Provides a project node type and manages downloads of project releases.');
+ return t('Provides a project node type and browsing of projects.');
case 'node/add#project_project':
- return t('A project is anything that has releases which can be downloaded');
+ return t('A project is something a group is working on. It can optionally have issue tracking, integration with revision control systems, releases, and so on.' );
case 'node/add/project_project':
if (project_use_taxonomy()) {
$tree = taxonomy_get_tree(_project_get_vid());
@@ -89,69 +85,27 @@ function project_perm() {
* Callback for the main settings page.
*/
function project_settings() {
- $versions = array(-1 => t('all')) + project_releases_list();
$sort_methods = drupal_map_assoc(array_keys(module_invoke_all('project_sort_methods', 'methods')));
- $form['releases'] = array('#type' => 'fieldset',
- '#title' => t('Releases'),
- '#collapsible' => TRUE,
- );
- $form['releases']['project_release_directory'] = array(
- '#type' => 'textfield',
- '#title' => t('Release directory'),
- '#default_value' => variable_get('project_release_directory', ''),
- '#size' => 50,
- '#maxlength' => 255,
- '#description' => t('Leave this blank if project maintainers are to create their own release packages. This is useful if releases are generated by an external tool.'),
- );
-
- $form['releases']['project_release_unmoderate'] = array(
- '#type' => 'radios',
- '#title' => t('Unmoderate projects with releases'),
- '#default_value' => variable_get('project_release_unmoderate', 0),
- '#options' => array('Disabled', 'Enabled'),
- );
-
- $form['releases']['project_browse_releases'] = array(
- '#type' => 'checkbox',
- '#title' => t('Browse projects by releases'),
- '#default_value' => variable_get('project_browse_releases', 0),
- '#description' => t('Checking this box will cause the project browsing page to have a version select.'),
- );
-
- $form['releases']['project_release_overview'] = array(
- '#type' => 'radios',
- '#title' => t('Default release overview'),
- '#default_value' => variable_get('project_release_overview', -1),
- '#options' => $versions,
- '#description' => t('Default release version to list on the overview page'),
- );
-
- $form['browsing'] = array(
- '#type' => 'fieldset',
- '#title' => t('Browsing options'),
- '#collapsible' => TRUE,
- );
-
if (project_use_taxonomy()) {
// For now, date-based browsing doesn't work once you disable
// taxonomy (only because the code involved is rather complicated
// and needs to be majorly refactored and cleaned up).
- $form['browsing']['project_sort_method'] = array(
+ $form['project_sort_method'] = array(
'#type' => 'radios',
'#title' => t('Default sort option'),
'#default_value' => variable_get('project_sort_method', 'category'),
'#options' => $sort_methods,
'#description' => t('Default sorting option to use on the overview page'),
);
- $form['browsing']['sort_methods'] = array(
+ $form['sort_methods'] = array(
'#type' => 'fieldset',
'#title' => t('Enabled sorting options'),
);
$tree = taxonomy_get_tree(_project_get_vid(), 0 , -1, 1);
foreach ($tree as $term) {
- $form['browsing']['sort_methods']['project_sort_method_used_' . $term->tid] = array(
+ $form['sort_methods']['project_sort_method_used_' . $term->tid] = array(
'#type' => 'checkboxes',
'#title' => $term->name,
'#default_value' => variable_get('project_sort_method_used_' . $term->tid, array_keys($sort_methods)),
@@ -160,12 +114,18 @@ function project_settings() {
);
}
}
- $form['browsing']['project_browse_nodes'] = array(
+ $form['project_browse_nodes'] = array(
'#type' => 'select', '#title' => t('Number of projects to list in paged browsing'),
'#default_value' => variable_get('project_browse_nodes', 30),
'#options' => drupal_map_assoc(array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50)),
'#description' => t('The default maximum number of projects to list when browsing lists, e.g., by category.')
);
+ $form['project_browse_releases'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Browse projects by releases'),
+ '#default_value' => variable_get('project_browse_releases', 0),
+ '#description' => t('Checking this box will cause the project browsing page to have a version select.'),
+ );
if (module_exist('forum') && project_use_taxonomy()) {
$form['project_support_forum'] = taxonomy_form(_forum_get_vid(), variable_get('project_support_forum', ''), t('Select the support forum for projects'), 'project_support_forum');
@@ -176,13 +136,6 @@ function project_settings() {
return $form;
}
-function project_cron() {
- if (variable_get('project_release_directory', '') && time() - variable_get('project_release_directory_last', 0) > variable_get('project_release_directory_interval', 6 * 60 * 60)) {
- variable_set('project_release_directory_last', time());
- project_release_cron();
- }
-}
-
function project_link($type, $node = 0, $main = 0) {
$links = array();
switch ($type) {
@@ -319,32 +272,9 @@ function project_menu($may_cache) {
$access = project_project_access('create', NULL);
$items[] = array('path' => 'node/add/project_project', 'title' => t('project'), 'callback' => 'node_page', 'access' => $access, 'type' => MENU_NORMAL_ITEM);
- // Releases
- if (variable_get('project_release_directory', '')) {
- $access = user_access('administer projects');
- $items[] = array('path' => 'admin/settings/project/reload', 'title' => t('scan for releases'), 'callback' => 'project_release_scan', 'access' => $access, 'type' => MENU_NORMAL_ITEM);
- }
}
else {
theme_add_style(drupal_get_path('module', 'project') .'/project.css');
- if (arg(0) == 'node' && is_numeric(arg(1))) {
- $node = node_load(arg(1));
- if ($node->type == 'project_project') {
- $items[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('releases'), 'callback' => 'project_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK);
-
- if (node_access('update', $node)) {
- $items[] = array('path' => 'node/'. arg(1) .'/release/overview', 'title' => t('overview'), 'callback' => 'project_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK);
- }
-
- if (!variable_get('project_release_directory', '')) {
- $items[] = array('path' => 'node/'. arg(1) .'/release/add', 'title' => t('add'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK);
- }
- if (arg(2) == 'release' && is_numeric(arg(4))) {
- $items[] = array('path' => 'node/'. arg(1) .'/release/edit/'. arg(4), 'title' => t('edit'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK);
- $items[] = array('path' => 'node/'. arg(1) .'/release/delete/'. arg(4), 'title' => t('edit'), 'callback' => 'project_release_submit', 'access' => node_access('update', $node), 'weight' => 1, 'type' => MENU_CALLBACK);
- }
- }
- }
}
return $items;
@@ -733,9 +663,10 @@ function project_project_sort_methods($o
'order_bys' => array('n.sticky DESC', 'n.title ASC')
);
case 'date':
+ // TODO: this should all be conditional on project_release.module
return array(
'fields' => array('MAX(pr.changed) AS changed'),
- 'joins' => array('INNER JOIN {project_releases} pr ON n.nid = pr.nid'),
+ 'joins' => array('INNER JOIN {project_release_nodes} pr ON n.nid = pr.nid'),
'group_bys' => array('n.nid'),
'order_bys' => array('pr.changed DESC', 'n.sticky DESC', 'n.title ASC')
);
@@ -779,6 +710,7 @@ function project_project_sort_methods($o
return;
}
+// TODO: refactor for project_release.module? Need {project_release_nodes}
function project_default_tid() {
static $tid;
if ($tid === NULL) {
Index: modules/project/project_release.install
===================================================================
RCS file: modules/project/project_release.install
diff -N modules/project/project_release.install
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/project/project_release.install 10 Sep 2006 19:51:04 -0000
@@ -0,0 +1,62 @@
+ array('name' => t('project release'), 'base' => 'project_release'),
+ );
+}
+
+function project_release_menu($may_cache) {
+ $items = array();
+ global $user;
+
+ if ($may_cache) {
+ // Releases
+ if (variable_get('project_release_directory', '')) {
+ $access = user_access('administer projects');
+ $items[] = array('path' => 'admin/settings/project/reload', 'title' => t('scan for releases'), 'callback' => 'project_release_scan', 'access' => $access, 'type' => MENU_NORMAL_ITEM);
+ }
+ }
+ else {
+ if (arg(0) == 'node' && is_numeric(arg(1))) {
+ $node = node_load(arg(1));
+ if ($node->type == 'project_project') {
+ $items[] = array('path' => 'node/'. arg(1) .'/release', 'title' => t('releases'), 'callback' => 'project_release_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK);
+ if (node_access('update', $node)) {
+ $items[] = array('path' => 'node/'. arg(1) .'/release/overview', 'title' => t('overview'), 'callback' => 'project_release_project_releases', 'access' => node_access('view', $node), 'weight' => 0, 'type' => MENU_CALLBACK);
+ }
+ }
+ }
+ }
+ return $items;
+}
+
+
+/**
+ * Callback for the main settings page.
+ */
+function project_release_settings() {
+ $versions = array(-1 => t('all')) + project_releases_list();
+ $form['project_release_directory'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Release directory'),
+ '#default_value' => variable_get('project_release_directory', ''),
+ '#size' => 50,
+ '#maxlength' => 255,
+ '#description' => t('Leave this blank if project maintainers are to create their own release packages. This is useful if releases are generated by an external tool.'),
+ );
+
+ $form['project_release_unmoderate'] = array(
+ '#type' => 'radios',
+ '#title' => t('Unmoderate projects with releases'),
+ '#default_value' => variable_get('project_release_unmoderate', 0),
+ '#options' => array('Disabled', 'Enabled'),
+ );
+
+ $form['project_release_overview'] = array(
+ '#type' => 'radios',
+ '#title' => t('Default release overview'),
+ '#default_value' => variable_get('project_release_overview', -1),
+ '#options' => $versions,
+ '#description' => t('Default release version to list on the overview page'),
+ );
+ return $form;
+}
+
+function project_release_cron() {
+ if (variable_get('project_release_directory', '') && time() - variable_get('project_release_directory_last', 0) > variable_get('project_release_directory_interval', 6 * 60 * 60)) {
+ variable_set('project_release_directory_last', time());
+ // TODO: should be able to optimize this to use less file system calls.
+ // TODO: commented out until implemented with the new system.
+ // project_release_scan_directory();
+ }
+}
+
+
+/**
+ * -- commented out; needs to be re-implemented using new system, but
+ * we need to be sure we understand what this is doing, how and why.
+
+function project_release_scan() {
+ project_release_scan_directory();
+ drupal_set_title(t('Release directory scan'));
+ foreach (project_release_scan_directory_results() as $type => $count) {
+ drupal_set_message(t('Releases %type: %count.', array('%type' => $type, '%count' => $count)));
+ }
+ return t('Scan completed.');
+}
+
+function project_release_scan_directory($project = NULL) {
+ if ($dir = file_create_path(variable_get('project_release_directory', ''))) {
+ if ($project) {
+ $regexp = "($project)" .'-(.+)\.(tar.gz|zip)';
+ }
+ else {
+ $regexp = '(.+)-(.+)\.(tar.gz|zip)';
+ }
+
+ file_scan_directory($dir, $regexp, array('.', '..', 'CVS'), 'project_release_scan_parse');
+
+ // If any releases were previously present but are no longer, unpublish them.
+ foreach (project_release_scan_parse() as $project) {
+ if ($project->releases) {
+ foreach ($project->releases as $rid) {
+ project_release_delete($rid);
+ project_release_scan_directory_results(t('unpublished'));
+ }
+ }
+ }
+ }
+ project_releases_list(TRUE);
+}
+
+function project_release_scan_directory_results($type = NULL) {
+ static $results;
+ if ($type) {
+ if (!$results[$type]) {
+ $results[$type] = 1;
+ }
+ else {
+ $results[$type]++;
+ }
+ }
+ return $results;
+}
+
+function project_release_scan_parse($path = NULL) {
+ static $projects = array();
+
+ if (is_null($path)) {
+ return $projects;
+ }
+ else {
+ $dir = dirname($path);
+ $file = basename($path);
+ //preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar\.gz|zip)$/', $file, $matches);
+ preg_match('/^(.+?)-([0-9.]+(?:-.*)|[^-]+)\.(tar.gz$|zip$)/', $file, $matches);
+ list($filename, $name, $version) = $matches;
+
+ // If the project was not previously loaded, load its data, including previous releases.
+ if (!$projects[$name]) {
+ if ($project = db_fetch_object(db_query(db_rewrite_sql("SELECT n.nid, n.type, n.moderate FROM {node} n INNER JOIN {project_projects} p ON n.nid = p.nid WHERE p.uri = '%s'"), $name))) {
+ if ($releases = project_release_load($project, 0)) {
+ // Releases are loaded in an array where the key is the rid and the value the version.
+ // We flip the array to more readily test for releases.
+ $project->releases = array_flip($releases);
+ }
+ // Unmoderate nodes that have gotten releases
+ if (variable_get('project_release_unmoderate', 0) && $project->moderate) {
+ db_query("UPDATE {node} SET moderate = 0, status = 1 WHERE nid = %d", $project->nid);
+ }
+ }
+ else {
+ // No project found for this id.
+ return;
+ }
+ $projects[$name] = & $project;
+ }
+ else {
+ $project = & $projects[$name];
+ }
+
+ $release->scan = 1;
+ $release->nid = $project->nid;
+ // If the current version was previously released, add its rid value, so that
+ // it will be updated rather than inserted by project_release_save();
+ if (is_array($project->releases) && array_key_exists($version, $project->releases)) {
+ $release->rid = $project->releases[$version];
+ project_release_scan_directory_results(t('updated'));
+ }
+ else {
+ project_release_scan_directory_results(t('created'));
+ }
+ $release->version = $version;
+ $release->path = $path;
+ project_release_save($release);
+ // This release version has been resaved, so take it out of the array.
+ // That way, any releases no longer present can be unpublished in project_release_scan_directory().
+ if ($project->releases[$version]) {
+ unset($project->releases[$version]);
+ }
+ }
+}
+*/
+
+/**
+ * Implementation of hook_form().
+ */
+function project_release_form(&$release, &$param) {
+ if (arg(1) == 'add') {
+ if (!is_numeric(arg(3))) {
+ $form['markup'] = array(
+ '#value' => t('You must add releases only from projects.')
+ );
+ return $form;
+ }
+ $release->pid = arg(3);
+ $project = node_load($release->pid);
+ if (!$project) {
+ return drupal_not_found();
+ }
+ $form['project'] = array(
+ '#type' => 'value',
+ '#value' => $project,
+ );
+ }
+ else {
+ $edit = true;
+ }
+ $form['#attributes'] = array("enctype" => "multipart/form-data");
+
+ $form['title'] = array(
+ '#type' => 'value',
+ '#default_value' => $release->title,
+ );
+
+ $form['version_major'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Major version number'),
+ '#default_value' => $release->version_major,
+ '#size' => 20,
+ '#maxlength' => 10,
+ '#required' => TRUE,
+ );
+ if ($edit) {
+ $form['version_major']['#attributes'] = array('disabled' => $edit);
+ }
+
+ $form['version_minor'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Minor version number'),
+ '#default_value' => $release->version_minor,
+ '#size' => 20,
+ '#maxlength' => 10,
+ '#required' => TRUE,
+ );
+ if ($edit) {
+ $form['version_minor']['#attributes'] = array('disabled' => $edit);
+ }
+
+ $form['version_extra'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Extra version identifier'),
+ '#default_value' => $release->version_extra,
+ '#size' => 20,
+ '#maxlength' => 10,
+ '#description' => t('Optionally specify other identifying information for this version, for example "rc1" or "dev". In most cases, this should be left blank.'),
+ );
+ if ($edit) {
+ $form['version_minor']['#attributes'] = array('disabled' => $edit);
+ }
+
+ if (!variable_get('project_release_directory', '')) {
+ $form['file'] = array(
+ '#type' => 'file',
+ '#title' => t('File'),
+ '#size' => 40,
+ '#description' => ($release->fid) ?
+ t('A file already exists, if you upload another file the current file will be replaced.') :
+ 'Choose the file that will be associated with this release.',
+ );
+ }
+
+ $form['body'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Changes'),
+ '#default_value' => $release->body,
+ '#rows' => 10,
+ '#cols' => 40,
+ '#required' => TRUE,
+ '#description' => t('Enter a description of this version, such as a list of the major changes or updates.'),
+ );
+ $form['format'] = filter_form($node->format);
+
+ $form['pid'] = array(
+ '#type' => 'value',
+ '#value' => $release->pid,
+ );
+ $form['tag'] = array(
+ '#type' => 'value',
+ '#value' => $release->tag,
+ );
+ $form['rebuild'] = array(
+ '#type' => 'value',
+ '#value' => $release->rebuild,
+ );
+ $form['file_hash'] = array(
+ '#type' => 'value',
+ '#value' => $release->file_hash,
+ );
+ $form['file_date'] = array(
+ '#type' => 'value',
+ '#value' => $release->file_date,
+ );
+ $form['file_path'] = array(
+ '#type' => 'value',
+ '#value' => $release->file_path,
+ );
+ $form['version_super_major'] = array(
+ '#type' => 'value',
+ '#value' => $release->version_super_major,
+ );
+ $form['version_super_minor'] = array(
+ '#type' => 'value',
+ '#value' => $release->version_super_minor,
+ );
+ return $form;
+}
+
+/**
+ * Implementation of hook_validate().
+ */
+function project_release_validate(&$edit, $form) {
+ $result = db_query("SELECT * FROM {project_release_nodes} WHERE pid = %d AND version_major = %d AND version_minor = %d AND version_extra = '%s' AND version_super_major = %d AND version_super_minor = %d AND nid != %d", $edit->pid, $edit->version_major, $edit->version_minor, $edit->version_extra, $edit->version_super_major, $edit->super_version_minor, $edit->nid);
+
+ if ($release = db_fetch_object($result)) {
+ form_set_error('version_minor', t('This version already exists for this project.'));
+ }
+
+ if ($file = file_check_upload('file')) {
+ $file = file_save_upload('file', file_directory_path());
+ if ($file) {
+ $filepath = file_create_path($file->filepath);
+ form_set_value($form['file_path'], $file->filepath);
+ form_set_value($form['file_date'], filemtime($filepath));
+ form_set_value($form['file_hash'], md5_file($filepath));
+ }
+ else {
+ form_set_error('file', t('There was a problem uploading the specified file.'));
+ }
+ }
+ if ($edit->project) {
+ form_set_value($form['title'], t('%project %version', array('%project' => $edit->project->title, '%version' => theme('project_release_version', (object) $edit))));
+ }
+}
+
+/**
+ * Implementation of hook_load().
+ */
+function project_release_load($node) {
+ $additions = db_fetch_object(db_query("SELECT * FROM {project_release_nodes} WHERE nid = %d", $node->nid));
+ return $additions;
+}
+
+/**
+ * Implementation of hook_insert().
+ */
+function project_release_insert($node) {
+ db_query("INSERT INTO {project_release_nodes} (nid, pid, tag, file_path, file_date, file_hash, rebuild, version_super_major, version_super_minor, version_major, version_minor, version_extra) VALUES (%d, %d, '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, '%s')", $node->nid, $node->pid, $node->tag, $node->file_path, $node->file_date, $node->file_hash, $node->rebuild, $node->version_super_major, $node->version_super_minor, $node->version_major, $node->version_minor, $node->version_extra);
+}
+
+/**
+ * Implementation of hook_update().
+ */
+function project_release_update($node) {
+ db_query("UPDATE {project_release_nodes} SET pid = %d, tag = '%s', file_path = '%s', file_date = %d, file_hash = '%s', rebuild = %d, version_super_major = %d, version_super_minor = %d, version_major = %d, version_minor = %d, version_extra = '%s' WHERE nid = %d", $node->pid, $node->tag, $node->file_path, $node->file_date, $node->file_hash, $node->rebuild, $node->version_super_major, $node->version_super_minor, $node->version_major, $node->version_minor, $node->version_extra, $node->nid);
+}
+
+/**
+ * Implementation of hook_delete().
+ */
+function project_release_delete($node) {
+ if ($node->file_path) {
+ file_delete(file_create_path($node->file_path));
+ }
+ db_query("DELETE FROM {project_release_nodes} WHERE nid = %d", $node->nid);
+}
+
+
+/**
+ * @themeable
+ * Provide a proper full version name of a file.
+ */
+function theme_project_release_version($release) {
+ $version = '';
+ if ($release->version_super_major) {
+ $version .= $release->version_super_major .'.'. $release->version_super_minor .'-';
+ }
+ $version .= $release->version_major .'.'. $release->version_minor;
+ if ($release->version_extra) {
+ $version .= '-' . $release->version_extra;
+ }
+ return $version;
+}
+
+/**
+ * Implementation of hook_view().
+ */
+function project_release_view(&$release, $teaser = FALSE, $page = FALSE) {
+ $project = node_load($release->pid);
+
+ if ($page) {
+ // Breadcrumb navigation
+ $breadcrumb[] = array('path' => 'node/'. $project->nid, 'title' => $project->title);
+ $breadcrumb[] = array('path' => 'node/'. $node->nid, 'title' => $node->title);
+ $breadcrumb = project_project_set_location($project, $breadcrumb);
+ menu_set_location($breadcrumb);
+ }
+
+ $links = array();
+ if ($release->file_path) {
+ $output .= '' . t('Download: %file', array('%file' => l(basename($release->file_path), file_create_url($release->file_path)))) . '
';
+ $output .= '' . t('Size: %size', array('%size' => format_size(filesize(file_create_path($release->file_path))))) . '
';
+ $output .= '' . t('md5_file file_hash: %file_hash', array('%file_hash' => $release->file_hash)) . '
';
+ }
+ if ($release->created) {
+ $output .= '' . t('First released: %created', array('%created' => format_date($release->created))) . '
';
+ }
+ if ($release->changed && ($release->changed != $release->created)) {
+ $output .= '' . t('Last updated: %changed', array('%changed' => format_date($release->changed))) . '
';
+ }
+
+ $output .= $release->changes;
+ $output .= theme('links', $links);
+
+ $release->body .= '