| 1 |
<?php |
<?php |
| 2 |
// $Id: versioncontrol_project.module,v 1.75 2009/05/29 16:22:23 jpetso Exp $ |
// $Id: versioncontrol_project.module,v 1.76 2009/05/31 17:32:33 jpetso Exp $ |
| 3 |
/** |
/** |
| 4 |
* @file |
* @file |
| 5 |
* Version Control / Project Node integration - Integrates project nodes |
* Version Control / Project Node integration - Integrates project nodes |
| 6 |
* (provided by the Project module) with version control systems supported |
* (provided by the Project module) with version control systems supported |
| 7 |
* by the Version Control API. |
* by the Version Control API. |
| 8 |
* |
* |
| 9 |
* Copyright 2006, 2007 by Derek Wright ("dww", http://drupal.org/user/46549) |
* Copyright 2006, 2007, 2009 by Derek Wright ("dww", http://drupal.org/user/46549) |
| 10 |
* Copyright 2007, 2008, 2009 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020) |
* Copyright 2007, 2008, 2009 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020) |
| 11 |
*/ |
*/ |
| 12 |
|
|
| 146 |
} |
} |
| 147 |
|
|
| 148 |
/** |
/** |
| 149 |
|
* Get the version-control-integrated project node from the currently active |
| 150 |
|
* menu context, if possible. |
| 151 |
|
* |
| 152 |
|
* @return |
| 153 |
|
* A fully loaded project $node object if the currently active menu has a |
| 154 |
|
* project node context, or FALSE if the menu isn't pointing to a |
| 155 |
|
* project node or the node does not use version control functionality. |
| 156 |
|
*/ |
| 157 |
|
function versioncontrol_project_node_from_menu() { |
| 158 |
|
if ($node = menu_get_object('versioncontrol_project_node')) { |
| 159 |
|
return $node; |
| 160 |
|
} |
| 161 |
|
$node = menu_get_object(); |
| 162 |
|
if (is_object($node) && versioncontrol_project_node_uses_versioncontrol($node)) { |
| 163 |
|
return $node; |
| 164 |
|
} |
| 165 |
|
return FALSE; |
| 166 |
|
} |
| 167 |
|
|
| 168 |
|
/** |
| 169 |
* Custom access callback, ensuring that the current user (or the one given |
* Custom access callback, ensuring that the current user (or the one given |
| 170 |
* in @p $account, if set) is permitted to view and edit the list of people |
* in @p $account, if set) is permitted to view and edit the list of people |
| 171 |
* with commit access for a given project node. |
* with commit access for a given project node. |
| 771 |
'types' => array(VERSIONCONTROL_OPERATION_COMMIT), |
'types' => array(VERSIONCONTROL_OPERATION_COMMIT), |
| 772 |
'nids' => array($project['nid']), |
'nids' => array($project['nid']), |
| 773 |
); |
); |
| 774 |
return theme('versioncontrol_user_statistics', $constraints, array( |
$statistics = versioncontrol_get_operation_statistics($constraints, array( |
| 775 |
'order_by' => array('date'), |
'group_by' => array('uid', 'repo_id', 'username'), |
| 776 |
|
'order_by' => array('last_operation_date'), |
| 777 |
|
)); |
| 778 |
|
|
| 779 |
|
return theme('versioncontrol_user_statistics_table', $statistics, array( |
| 780 |
|
'constraints' => $constraints, |
| 781 |
)); |
)); |
| 782 |
} |
} |
| 783 |
|
|
| 832 |
/** |
/** |
| 833 |
* Implementation of hook_block(): Present a list of the most active projects. |
* Implementation of hook_block(): Present a list of the most active projects. |
| 834 |
*/ |
*/ |
| 835 |
function versioncontrol_project_block($op = 'list', $delta = 0) { |
function versioncontrol_project_block($op = 'list', $delta = 0, $edit = array()) { |
| 836 |
if ($op == 'list') { |
if ($op == 'list') { |
| 837 |
$blocks = array(); |
$blocks = array(); |
| 838 |
$blocks['site_active_projects'] = array( |
$blocks['site_active_projects'] = array( |
| 839 |
'info' => t('Version Control API: Most active projects'), |
'info' => t('Version Control API: Most active projects'), |
| 840 |
'cache' => BLOCK_CACHE_GLOBAL, |
'cache' => BLOCK_CACHE_GLOBAL, |
| 841 |
); |
); |
| 842 |
|
// We roll our own caching for these blocks, since the existing block cache |
| 843 |
|
// is cleared on every comment or node added on the site, which isn't at |
| 844 |
|
// all what we need for this. There are expensive queries for this block, |
| 845 |
|
// and it only changes when an operation is made to a given project. |
| 846 |
|
$blocks['project_developers'] = array( |
| 847 |
|
'info' => t('Version Control API: Project developers'), |
| 848 |
|
'cache' => BLOCK_NO_CACHE, |
| 849 |
|
); |
| 850 |
|
$blocks['project_maintainers'] = array( |
| 851 |
|
'info' => t('Version Control API: Project maintainers'), |
| 852 |
|
'cache' => BLOCK_NO_CACHE, |
| 853 |
|
); |
| 854 |
return $blocks; |
return $blocks; |
| 855 |
} |
} |
| 856 |
else if ($op == 'view') { |
else if ($op == 'view') { |
| 857 |
if ($delta == 'site_active_projects') { |
if ($delta == 'site_active_projects') { |
| 858 |
return versioncontrol_project_block_site_active_projects(); |
return versioncontrol_project_block_site_active_projects(); |
| 859 |
} |
} |
| 860 |
|
if ($delta == 'project_developers' || $delta == 'project_maintainers') { |
| 861 |
|
return versioncontrol_project_block_project_committers($delta); |
| 862 |
|
} |
| 863 |
|
} |
| 864 |
|
else if ($op == 'configure') { |
| 865 |
|
if ($delta == 'project_developers' || $delta == 'project_maintainers') { |
| 866 |
|
return versioncontrol_project_block_project_committers_configure($delta); |
| 867 |
|
} |
| 868 |
|
} |
| 869 |
|
else if ($op == 'save') { |
| 870 |
|
if ($delta == 'project_developers' || $delta == 'project_maintainers') { |
| 871 |
|
return versioncontrol_project_block_project_committers_save($delta, $edit); |
| 872 |
|
} |
| 873 |
} |
} |
| 874 |
} |
} |
| 875 |
|
|
| 910 |
} |
} |
| 911 |
|
|
| 912 |
/** |
/** |
| 913 |
|
* Implementation of hook_block($op='configure') for the project developers |
| 914 |
|
* or maintainers block. |
| 915 |
|
* |
| 916 |
|
* @param $delta |
| 917 |
|
* The block delta: either 'project_developers' or 'project_maintainers'. |
| 918 |
|
*/ |
| 919 |
|
function versioncontrol_project_block_project_committers_configure($delta) { |
| 920 |
|
$options = array(); |
| 921 |
|
for ($i = 1; $i <= 10; $i++) { |
| 922 |
|
$options[$i] = $i; |
| 923 |
|
} |
| 924 |
|
$options['all'] = t('Unlimited'); |
| 925 |
|
|
| 926 |
|
$form = array(); |
| 927 |
|
$form['versioncontrol_'. $delta .'_block_length'] = array( |
| 928 |
|
'#type' => 'select', |
| 929 |
|
'#options' => $options, |
| 930 |
|
'#title' => t('Number of developers to display'), |
| 931 |
|
'#default_value' => variable_get('versioncontrol_'. $delta .'_block_length', 5), |
| 932 |
|
); |
| 933 |
|
return $form; |
| 934 |
|
} |
| 935 |
|
|
| 936 |
|
/** |
| 937 |
|
* Implementation of hook_block($op='save') for the project developers or |
| 938 |
|
* maintainers block. |
| 939 |
|
* |
| 940 |
|
* @param $delta |
| 941 |
|
* The block delta: either 'project_developers' or 'project_maintainers'. |
| 942 |
|
*/ |
| 943 |
|
function versioncontrol_project_block_project_committers_save($delta, $edit) { |
| 944 |
|
variable_set('versioncontrol_'. $delta .'_block_length', |
| 945 |
|
$edit['versioncontrol_'. $delta .'_block_length'] |
| 946 |
|
); |
| 947 |
|
// Clear the cache because it might now contain statistics for a too limited |
| 948 |
|
// set of committers, and as an overall easy way to regenerate the values. |
| 949 |
|
_versioncontrol_project_block_cache_clear(); |
| 950 |
|
} |
| 951 |
|
|
| 952 |
|
/** |
| 953 |
|
* Implementation of hook_block($op='view') for the project developers or |
| 954 |
|
* maintainers block. |
| 955 |
|
* |
| 956 |
|
* @param $delta |
| 957 |
|
* The block delta: either 'project_developers' or 'project_maintainers'. |
| 958 |
|
*/ |
| 959 |
|
function versioncontrol_project_block_project_committers($delta) { |
| 960 |
|
$block = array(); |
| 961 |
|
$project_node = versioncontrol_project_node_from_menu(); |
| 962 |
|
|
| 963 |
|
if (!$project_node) { |
| 964 |
|
return $block; |
| 965 |
|
} |
| 966 |
|
if (!user_access('access commit messages') || !node_access('view', $project_node)) { |
| 967 |
|
return $block; |
| 968 |
|
} |
| 969 |
|
$cid = 'versioncontrol_'. $delta .'_statistics:'. $project_node->nid; |
| 970 |
|
$statistics = _versioncontrol_project_block_cache_get($cid); |
| 971 |
|
|
| 972 |
|
if (empty($statistics)) { |
| 973 |
|
$constraints = array( |
| 974 |
|
'types' => array(VERSIONCONTROL_OPERATION_COMMIT), |
| 975 |
|
'nids' => array($project_node->nid), |
| 976 |
|
); |
| 977 |
|
if ($delta == 'project_maintainers') { |
| 978 |
|
$constraints['uids'] = $project_node->versioncontrol_project['maintainer_uids']; |
| 979 |
|
$group_by = array('uid'); // per Drupal user |
| 980 |
|
} |
| 981 |
|
else { // $delta == 'project_developers' |
| 982 |
|
// Group per account, because no associated Drupal user might be involved. |
| 983 |
|
$group_by = array('uid', 'repo_id', 'username'); |
| 984 |
|
} |
| 985 |
|
$statistics = versioncontrol_get_operation_statistics($constraints, array( |
| 986 |
|
'group_by' => $group_by, |
| 987 |
|
'order_by' => array('last_operation_date'), |
| 988 |
|
'query_type' => 'range', |
| 989 |
|
'count' => variable_get('versioncontrol_'. $delta .'_block_length', 5), |
| 990 |
|
'from' => 0, |
| 991 |
|
)); |
| 992 |
|
_versioncontrol_project_block_cache_set($cid, $statistics); |
| 993 |
|
} |
| 994 |
|
|
| 995 |
|
$title = ($delta == 'project_maintainers') |
| 996 |
|
? t('Maintainers for @project', array('@project' => $project_node->title)) |
| 997 |
|
: t('Developers for @project', array('@project' => $project_node->title)); |
| 998 |
|
$more_link = l(t('View all developers'), 'node/'. $project_node->nid .'/developers'); |
| 999 |
|
|
| 1000 |
|
$block = array( |
| 1001 |
|
'subject' => $title, |
| 1002 |
|
'content' => theme('versioncontrol_user_statistics_item_list', $statistics, $more_link), |
| 1003 |
|
); |
| 1004 |
|
return $block; |
| 1005 |
|
} |
| 1006 |
|
|
| 1007 |
|
function _versioncontrol_project_block_cache_get($cid) { |
| 1008 |
|
$data = db_result(db_query("SELECT data FROM {versioncontrol_project_cache_block} |
| 1009 |
|
WHERE cid = '%s'", $cid)); |
| 1010 |
|
if (!empty($data)) { |
| 1011 |
|
return unserialize($data); |
| 1012 |
|
} |
| 1013 |
|
} |
| 1014 |
|
|
| 1015 |
|
function _versioncontrol_project_block_cache_set($cid, $data) { |
| 1016 |
|
if (empty($data)) { |
| 1017 |
|
db_query("DELETE FROM {versioncontrol_project_cache_block} |
| 1018 |
|
WHERE cid = '%s'", $cid); |
| 1019 |
|
} |
| 1020 |
|
else { |
| 1021 |
|
$serialized = serialize($data); |
| 1022 |
|
db_query("UPDATE {versioncontrol_project_cache_block} |
| 1023 |
|
SET data = '%s' WHERE cid = '%s'", $serialized, $cid); |
| 1024 |
|
if (!db_affected_rows()) { |
| 1025 |
|
db_query("INSERT INTO {versioncontrol_project_cache_block} (cid, data) |
| 1026 |
|
VALUES ('%s', '%s')", $cid, $serialized); |
| 1027 |
|
} |
| 1028 |
|
} |
| 1029 |
|
} |
| 1030 |
|
|
| 1031 |
|
function _versioncontrol_project_block_cache_clear() { |
| 1032 |
|
db_query("DELETE FROM {versioncontrol_project_cache_block}"); |
| 1033 |
|
} |
| 1034 |
|
|
| 1035 |
|
|
| 1036 |
|
/** |
| 1037 |
* Implementation of hook_commitlog_constraints(): |
* Implementation of hook_commitlog_constraints(): |
| 1038 |
* Provide a list of supported constraints and corresponding request attributes. |
* Provide a list of supported constraints and corresponding request attributes. |
| 1039 |
*/ |
*/ |
| 1740 |
else { |
else { |
| 1741 |
$project['comaintainer_uids'] = array(); |
$project['comaintainer_uids'] = array(); |
| 1742 |
} |
} |
| 1743 |
|
// The list of maintainers has potentially changed, clear the block cache. |
| 1744 |
|
$cid = 'versioncontrol_project_maintainers_statistics:'. $project['nid']; |
| 1745 |
|
_versioncontrol_project_block_cache_set($cid, NULL); |
| 1746 |
|
|
| 1747 |
$project['maintainer_uids'] = array($project['owner_uid']); |
$project['maintainer_uids'] = array($project['owner_uid']); |
| 1748 |
foreach ($project['comaintainer_uids'] as $comaintainer_uid) { |
foreach ($project['comaintainer_uids'] as $comaintainer_uid) { |
| 1926 |
function versioncontrol_project_versioncontrol_operation($op, $operation, $operation_items) { |
function versioncontrol_project_versioncontrol_operation($op, $operation, $operation_items) { |
| 1927 |
switch ($op) { |
switch ($op) { |
| 1928 |
case 'insert': |
case 'insert': |
| 1929 |
|
$project = NULL; |
| 1930 |
|
|
| 1931 |
// Update the project/item associations with the new operation items. |
// Update the project/item associations with the new operation items. |
| 1932 |
foreach ($operation_items as $path => $item) { |
foreach ($operation_items as $path => $item) { |
| 1933 |
$project = versioncontrol_project_get_project_for_item( |
$project = versioncontrol_project_get_project_for_item( |
| 1937 |
(empty($project) ? VERSIONCONTROL_PROJECT_NID_NONE : $project['nid']) |
(empty($project) ? VERSIONCONTROL_PROJECT_NID_NONE : $project['nid']) |
| 1938 |
); |
); |
| 1939 |
} |
} |
| 1940 |
|
// A new operation (probably a commit) has been registered, so clear the |
| 1941 |
|
// block cache with project commit statistics. |
| 1942 |
|
if (isset($project)) { |
| 1943 |
|
$cid = 'versioncontrol_project_developers_statistics:'. $project['nid']; |
| 1944 |
|
_versioncontrol_project_block_cache_set($cid, NULL); |
| 1945 |
|
$cid = 'versioncontrol_project_maintainers_statistics:'. $project['nid']; |
| 1946 |
|
_versioncontrol_project_block_cache_set($cid, NULL); |
| 1947 |
|
} |
| 1948 |
break; |
break; |
| 1949 |
|
|
| 1950 |
case 'delete': |
case 'delete': |