* Copyright 2003-2010, Roland Mas, Franck Villaume
* Copyright 2004, GForge, LLC
* Copyright 2010, Alain Peyrat <aljeux@free.fr>
- * Copyright 2012-2014,2016-2018, Franck Villaume - TrivialDev
+ * Copyright 2012-2014,2016-2018,2021-2022, Franck Villaume - TrivialDev
* Copyright 2013, French Ministry of National Education
*
* This file is part of FusionForge.
forge_define_config_item('default_server', 'scmsvn', forge_get_config('scm_host'));
forge_define_config_item('repos_path', 'scmsvn', forge_get_config('chroot').'/scmrepos/svn');
forge_define_config_item('serve_path', 'scmsvn', forge_get_config('repos_path'));
-forge_define_config_item('use_ssh', 'scmsvn', false);
-forge_set_config_item_bool('use_ssh', 'scmsvn');
-forge_define_config_item('use_dav', 'scmsvn', true);
-forge_set_config_item_bool('use_dav', 'scmsvn');
-forge_define_config_item('use_ssl', 'scmsvn', true);
-forge_set_config_item_bool('use_ssl', 'scmsvn');
+forge_define_config_item_bool('use_ssh', 'scmsvn', false);
+forge_define_config_item_bool('use_dav', 'scmsvn', true);
+forge_define_config_item_bool('use_ssl', 'scmsvn', true);
forge_define_config_item('ssh_port', 'core', 22);
class SVNPlugin extends SCMPlugin {
+
+ var $svn_root_dav;
+ var $svn_root_fs;
+ var $web_port;
+
function __construct() {
parent::__construct();
$this->name = 'scmsvn';
$this->_addHook('activity');
$this->provides['svn'] = true;
-
+ $this->web_port = util_url_port(forge_get_config('use_ssl', 'scmsvn'));
$this->register();
}
foreach ($repo_list as $repo_name) {
$modules = $this->topModule($project, $repo_name);
foreach ($modules as $module) {
- $b .= html_e('kbd', array(), 'svn checkout http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. $this->getBoxForProject($project). '/anonscm/svn/'.$repo_name.$module).html_e('br');
+ $b .= html_e('kbd', array(), 'svn checkout http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'. $this->getBoxForProject($project).$this->web_port.'/anonscm/svn/'.$repo_name.$module).html_e('br');
}
}
}
foreach ($repo_list as $repo_name) {
$modules = $this->topModule($project, $repo_name);
foreach ($modules as $module) {
- $b .= html_e('kbd', array(), 'svn checkout --username '.$d.' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).'/authscm/'.$d.'/svn/'.$repo_name.$module).html_e('br');
+ $b .= html_e('kbd', array(), 'svn checkout --username '.$d.' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.$d.'/svn/'.$repo_name.$module).html_e('br');
}
}
$b .= '</div>';
} else {
if (forge_get_config('use_ssh', 'scmsvn')) {
$b .= '<div id="tabber-svnssh" class="tabbertab" >';
- $b .= '<p>';
- $b .= _('SSH must be installed on your client machine.');
- $b .= ' ';
- $b .= _('Substitute <em>developername</em> with the proper value.');
- $b .= ' ';
- $b .= _('Enter your site password when prompted.');
- $b .= '</p><p>';
+ $b .= html_e('p', array(),
+ ngettext('Only project developers can access the SVN repository via this method.',
+ 'Only project developers can access the SVN repositories via this method.',
+ count($repo_list)).
+ ' '. _('SSH must be installed on your client machine.').
+ ' '. _('Additionally, a public ssh key must be available in the FusionForge settings of the respective user.').
+ ' '. _('Substitute <em>developername</em> with the proper value.')).'<p>';
$ssh_port = '';
if (forge_get_config('ssh_port') != 22) {
$ssh_port = '--config-option="config:tunnels:ssh=ssh -p '.forge_get_config('ssh_port').'" ';
$modules = $this->topModule($project, $repo_name);
foreach ($modules as $module) {
if (forge_get_config('use_shell_limited')) {
- $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://<i>'._('developername').'</i>@'.$this->getBoxForProject($project).'/'.$repo_name.$module).html_e('br');
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.html_e('em', array(), _('developername'), true, false).'@'.$this->getBoxForProject($project).'/'.$repo_name.$module).html_e('br');
} else {
- $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://<i>'._('developername').'</i>@'.$this->getBoxForProject($project).$this->svn_root_fs .'/'.$repo_name.$module).html_e('br');
+ $b .= html_e('kbd', array(), 'svn '.$ssh_port.'checkout svn+ssh://'.html_e('em', array(), _('developername'), true, false).'@'.$this->getBoxForProject($project).$this->svn_root_fs .'/'.$repo_name.$module).html_e('br');
}
}
}
foreach ($repo_list as $repo_name) {
$modules = $this->topModule($project, $repo_name);
foreach ($modules as $module) {
- $b .= html_e('kbd', array(), 'svn checkout --username <i>'._('developername').'</i> http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).'/authscm/<i>'._('developername').'</i>/svn/'.$repo_name.$module).html_e('br');
+ $b .= html_e('kbd', array(), 'svn checkout --username '.html_e('em', array(), _('developername'),true, false).' http'.((forge_get_config('use_ssl', 'scmsvn')) ? 's' : '').'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.html_e('em', array(), _('developername'),true, false).'/svn/'.$repo_name.$module).html_e('br');
}
}
$b .= '</div>';
if ($params['scm_plugin'] != $this->name) {
return;
}
- global $HTML;
- $useautoheight = 0;
$project = $this->checkParams($params);
if (!$project) {
return;
function createOrUpdateRepo($params) {
$project = $this->checkParams($params);
- if (!$project) return false;
- if (!$project->isActive()) return false;
-
+ if (!$project) {
+ return false;
+ }
$repo_prefix = forge_get_config('repos_path', 'scmsvn');
if (!is_dir($repo_prefix) && !mkdir($repo_prefix, 0755, true)) {
return false;
$start_time = $params['begin'];
$end_time = $params['end'];
- $xml_parser = xml_parser_create();
- xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
- xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
-
- // Grab&parse commit log
- $protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
if ($project->enableAnonSCM()) {
$server_script = '/anonscm/svnlog';
} else {
return false;
}
}
- $script_url = $protocol.$this->getBoxForProject($project)
- . $server_script
- .'?unix_group_name='.$project->getUnixName()
- .'&mode=date_range'
- .'&begin='.$params['begin']
- .'&end='.$params['end'];
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $script_url);
- curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- curl_setopt($ch, CURLOPT_COOKIE, @$_SERVER['HTTP_COOKIE']); // for session validation
- curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
- curl_setopt($ch, CURLOPT_HTTPHEADER,
- array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
- $body = curl_exec($ch);
- if ($body === false) {
- $this->setError(curl_error($ch));
- }
- curl_close($ch);
- // final checks
- if (!xml_parse($xml_parser, '', true))
- $this->setError('Unable to parse XML with error '
- . xml_error_string(xml_get_error_code($xml_parser))
- . ' on line ' . xml_get_current_line_number($xml_parser));
- xml_parser_free($xml_parser);
+ $repo_list = $this->getRepositories($project);
+ $protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
+ foreach ($repo_list as $repo_name) {
+ $xml_parser = xml_parser_create();
+ xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
+ xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
+
+ // Grab & parse commit log
+ $script_url = $protocol.$this->getBoxForProject($project)
+ . $this->web_port
+ . $server_script
+ .'?unix_group_name='.$project->getUnixName()
+ .'&repo_name='.$repo_name
+ .'&mode=date_range'
+ .'&begin='.$params['begin']
+ .'&end='.$params['end'];
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $script_url);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_COOKIE, @$_SERVER['HTTP_COOKIE']); // for session validation
+ curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
+ curl_setopt($ch, CURLOPT_HTTPHEADER,
+ array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
+ $body = curl_exec($ch);
+ if ($body === false) {
+ $this->setError(curl_error($ch));
+ }
+ curl_close($ch);
- if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
- $i = 0;
- foreach ($messages as $message) {
- $result = array();
- $result['section'] = 'scm';
- $result['group_id'] = $project->getID();
- $result['ref_id'] = 'browser.php?group_id='.$project->getID().'&scm_plugin='.$this->name;
- $result['description'] = htmlspecialchars($message).' (r'.$revisions[$i].')';
- $userObject = user_get_object_by_name($users[$i]);
- if (is_a($userObject, 'FFUser')) {
- $result['realname'] = util_display_user($userObject->getUnixName(), $userObject->getID(), $userObject->getRealName());
- } else {
- $result['realname'] = '';
+ // final checks
+ if (!xml_parse($xml_parser, '', true)) {
+ $this->setError('Unable to parse XML with error '
+ . xml_error_string(xml_get_error_code($xml_parser))
+ . ' on line ' . xml_get_current_line_number($xml_parser));
+ }
+ xml_parser_free($xml_parser);
+
+ if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
+ $i = 0;
+ foreach ($messages as $message) {
+ $result = array();
+ $result['section'] = 'scm';
+ $result['group_id'] = $project->getID();
+ $result['ref_id'] = 'browser.php?group_id='.$project->getID().'&scm_plugin='.$this->name.'&repo_name='.$repo_name;
+ $result['description'] = htmlspecialchars($message).' (repository: '.$repo_name.' r'.$revisions[$i].')';
+ $userObject = user_get_object_by_name($users[$i]);
+ if (is_a($userObject, 'FFUser')) {
+ $result['realname'] = util_display_user($userObject->getUnixName(), $userObject->getID(), $userObject->getRealName());
+ } else {
+ $result['realname'] = '';
+ }
+ $result['activity_date'] = $times[$i];
+ $result['subref_id'] = '&commit='.$revisions[$i];
+ $params['results'][] = $result;
+ $i++;
}
- $result['activity_date'] = $times[$i];
- $result['subref_id'] = '&commit='.$revisions[$i];
- $params['results'][] = $result;
- $i++;
}
}
}
$notimecheck = true;
$revisionsArr = array();
if ($project->usesPlugin($this->name) && forge_check_perm('scm', $project->getID(), 'read')) {
- $xml_parser = xml_parser_create();
- xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
- xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
-
// Grab&parse commit log
$protocol = forge_get_config('use_ssl', 'scmsvn') ? 'https://' : 'http://';
$u = session_get_user();
- if ($project->enableAnonSCM())
+ if ($project->enableAnonSCM()) {
$server_script = '/anonscm/svnlog';
- else
+ } else {
$server_script = '/authscm/'.$u->getUnixName().'/svnlog';
+ }
if ($user) {
$userunixname = $user->getUnixName();
$params = '&mode=latest_user&user_name='.$userunixname;
} else {
$params = '&mode=latest';
}
- $script_url = $protocol.$this->getBoxForProject($project)
- . $server_script
- .'?unix_group_name='.$project->getUnixName()
- . $params
- .'&limit='.$nbCommits;
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $script_url);
- curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
- curl_setopt($ch, CURLOPT_COOKIE, $_SERVER['HTTP_COOKIE']); // for session validation
- curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
- curl_setopt($ch, CURLOPT_HTTPHEADER,
- array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
- $body = curl_exec($ch);
- if ($body === false) {
- $this->setError(curl_error($ch));
- }
- curl_close($ch);
-
- // final checks
- if (!xml_parse($xml_parser, '', true))
- $this->setError('Unable to parse XML with error '
+ $repo_list = $this->getRepositories($project);
+ $i = 0;
+ foreach ($repo_list as $repo_name) {
+ $script_url = $protocol.$this->getBoxForProject($project)
+ . $this->web_port
+ . $server_script
+ .'?unix_group_name='.$project->getUnixName()
+ .'&repo_name='.$repo_name
+ . $params
+ .'&limit='.$nbCommits;
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $script_url);
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl2xml');
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, forge_get_config('use_ssl_verification'));
+ curl_setopt($ch, CURLOPT_COOKIE, $_SERVER['HTTP_COOKIE']); // for session validation
+ curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // for session validation
+ curl_setopt($ch, CURLOPT_HTTPHEADER,
+ array('X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'])); // for session validation
+ $body = curl_exec($ch);
+ if ($body === false) {
+ $this->setError(curl_error($ch));
+ }
+ curl_close($ch);
+
+ $xml_parser = xml_parser_create();
+ xml_set_element_handler($xml_parser, "SVNPluginStartElement", "SVNPluginEndElement");
+ xml_set_character_data_handler($xml_parser, "SVNPluginCharData");
+ // final checks
+ if (!xml_parse($xml_parser, '', true)) {
+ $this->setError('Unable to parse XML with error '
. xml_error_string(xml_get_error_code($xml_parser))
. ' on line ' . xml_get_current_line_number($xml_parser));
- xml_parser_free($xml_parser);
-
- if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
- $i = 0;
- foreach ($messages as $message) {
- $revisionsArr[$i]['pluginName'] = 'scmsvn';
- $revisionsArr[$i]['description'] = htmlspecialchars($message);
- $revisionsArr[$i]['commit_id'] = $revisions[$i];
- $revisionsArr[$i]['repo_name'] = $project->getUnixName();
- $revisionsArr[$i]['date'] = $times[$i];
- $i++;
+ }
+ xml_parser_free($xml_parser);
+
+ if ($adds > 0 || $updates > 0 || $commits > 0 || $deletes > 0) {
+ foreach ($messages as $message) {
+ $revisionsArr[$i]['pluginName'] = 'scmsvn';
+ $revisionsArr[$i]['description'] = htmlspecialchars($message);
+ $revisionsArr[$i]['commit_id'] = $revisions[$i];
+ $revisionsArr[$i]['repo_name'] = $repo_name;
+ $revisionsArr[$i]['date'] = $times[$i];
+ $i++;
+ }
}
}
}
return false;
}
if (db_result($result, 0, 'count')) {
- $params['error_msg'] = sprintf(_('A repository %s already exists'), $params['repo_name']);
+ $params['error_msg'] = sprintf(_('%s as repository name cannot be used'), $params['repo_name']);
+ return false;
+ }
+
+ // do to current implementation of multiple repositories in SVN : we need to check repo_name against project names and forbid it
+ $result = db_query_params('SELECT count(*) as count FROM groups WHERE unix_group_name = $1',
+ array($params['repo_name']));
+ if (!$result) {
+ $params['error_msg'] = db_error();
+ return false;
+ }
+ if (db_result($result, 0, 'count')) {
+ $params['error_msg'] = sprintf(_('%s as repository name cannot be used'), $params['repo_name']);
return false;
}
+
$description = '';
$clone = '';
if (isset($params['description'])) {
continue;
}
$urls = array();
+ $project = group_get_object($arr['group_id']);
if (forge_get_config('use_dav', 'scmsvn')) {
- $urls[] = $protocol.'://'.$this->getBoxForProject($project).'/anonscm/svn/'.$arr['unix_group_name'];
+ $urls[] = $protocol.'://'.$this->getBoxForProject($project).$this->web_port.'/anonscm/svn/'.$arr['unix_group_name'];
}
if (forge_get_config('use_ssh', 'scmsvn')) {
$urls[] = 'svn://'.$this->getBoxForProject($project).$this->svn_root_fs.'/'.$arr['unix_group_name'];
}
if (session_loggedin()) {
if (forge_get_config('use_dav', 'scmsvn')) {
- $urls[] = $protocol.'://'.$this->getBoxForProject($project).'/authscm/'.$d.'/svn/'.$arr['unix_group_name'];
+ $urls[] = $protocol.'://'.$this->getBoxForProject($project).$this->web_port.'/authscm/'.$d.'/svn/'.$arr['unix_group_name'];
}
if (forge_get_config('use_ssh', 'scmsvn')) {
$urls[] = 'svn+ssh://'.$d.'@'.$this->getBoxForProject($project).$this->svn_root_fs .'/'. $arr['unix_group_name'];
}
}
foreach ($tstamps as $t => $v) {
- $res = db_query_params("INSERT INTO scm_activities (group_id, plugin_id, repository_id, tstamp) VALUES ($1,$2,$3,$4)",
+ db_query_params("INSERT INTO scm_activities (group_id, plugin_id, repository_id, tstamp) VALUES ($1,$2,$3,$4)",
array($rdata['gid'],
$this->getID(),
$rdata['rid'],
count($existing_repos)), $project_name));
$titleArr = array(_('Repository name'), ('Initial repository description'), _('Delete'));
echo $HTML->listTableTop($titleArr);
- foreach ($existing_repos as $key => $repo) {
+ foreach ($existing_repos as $repo) {
$cells = array();
$cells[][] = html_e('kbd', array(), $repo['repo_name']);
$cells[][] = $repo['description'];
} else {
$time_ok = false;
if (!isset($notimecheck)) {
- if ($last_user !== '') // empty in e.g. tags from cvs2svn
+ if ($last_user !== '') { // empty in e.g. tags from cvs2svn
$usr_commits[$last_user]--;
+ }
$commits--;
}
}
function curl2xml($ch, $data) {
global $xml_parser;
- if (!xml_parse($xml_parser, $data, false))
+ if (!xml_parse($xml_parser, $data, false)) {
exit_error('Unable to parse XML with error '
. xml_error_string(xml_get_error_code($xml_parser))
. ' on line ' . xml_get_current_line_number($xml_parser),
'activity');
+ }
return strlen($data);
}
// Local Variables: