* added 'force_project_delete'.

* added the pre-revprop-change hook and the post-revprop-change hook.
This commit is contained in:
hyung-hwan 2010-04-18 12:43:37 +00:00
parent b4fdd8f888
commit c02b59a9ca
16 changed files with 220 additions and 95 deletions

View File

@ -169,7 +169,7 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
wwwdir = @wwwdir@ wwwdir = @wwwdir@
cfg_DATA = codepot.ini codepot.sql codepot.a2ldap cfg_DATA = codepot.ini codepot.sql codepot.a2ldap
cfg_SCRIPTS = start-commit pre-commit post-commit cfg_SCRIPTS = start-commit pre-commit post-commit pre-revprop-change post-revprop-change
EXTRA_DIST = $(cfg_DATA) $(cfg_SCRIPTS) EXTRA_DIST = $(cfg_DATA) $(cfg_SCRIPTS)
all: all-am all: all-am

View File

@ -136,6 +136,14 @@ file_dir = "@DEPOTDIR@/files"
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
log_threshold = 0 log_threshold = 0
;------------------------------------------------------------------------------
; When yes, a project member can delete a non-empty project containing
; wiki pages, file uploads, etc. An empty project can be deleted any time
; regardless of this option. A system administrator(sysadmin_userids) is
; allowed to delete a non-empty project also regardless of this option.
;------------------------------------------------------------------------------
force_project_delete = "no"
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; customized footer ; customized footer
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
REPOBASE="`basename "${1}"`" REPOBASE="`basename "${1}"`"
REV="${2}" REVISION="${2}"
USER="${3}" USER="${3}"
PROPNAME="${4}" PROPNAME="${4}"
ACTION="${5}" ACTION="${5}"
@ -9,5 +9,5 @@ ACTION="${5}"
# [STDIN] PROPVAL ** the old property value is passed via STDIN. # [STDIN] PROPVAL ** the old property value is passed via STDIN.
# does not care if logging has failed. # does not care if logging has failed.
wget -q -O- "%API%/logRevpropChange/svn/${REPOBASE}/${REV}" 2>/dev/null wget -q -O- "%API%/logCodeRevpropChange/svn/${REPOBASE}/${REVISION}/${USER}/${PROPNAME}/${ACTION}" 2>/dev/null
exit 0 exit 0

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
REPOBASE="`basename "${1}"`" REPOBASE="`basename "${1}"`"
USER="${2}" REVISION="${2}"
USER="${3}" USER="${3}"
PROPNAME="${4}" PROPNAME="${4}"
ACTION="${5}" ACTION="${5}"

View File

@ -54,15 +54,14 @@ class API extends Controller
*/ */
} }
function logCodeRevpropChange ($type, $repo, $rev, $propname) function logCodeRevpropChange ($type, $repo, $rev, $userid, $propname, $action)
{ {
$this->check_access (); $this->check_access ();
if (!isset($repo) || !isset($rev) || !isset($propname)) return; if (!isset($repo) || !isset($rev) || !isset($propname) || !isset($action)) return;
$this->load->model ('LogModel', 'logs'); $this->load->model ('LogModel', 'logs');
// TODO: $this->logs->writeCodeRevpropChange ($type, $repo, $rev, $userid, $propname, $action);
//$this->logs->writeCodeRevpropChange ($type, $repo, $rev, '');
} }
} }

View File

@ -304,10 +304,13 @@ class Project extends Controller
{ {
if ($data['project_confirm'] == 'yes') if ($data['project_confirm'] == 'yes')
{ {
$result = $this->projects->delete ($login['id'], $project); $result = $this->projects->delete (
$login['id'], $project,
($login['sysadmin?'] || CODEPOT_FORCE_PROJECT_DELETE));
if ($result === FALSE) if ($result === FALSE)
{ {
$data['message'] = 'DATABASE ERROR'; $data['message'] = 'DATABASE ERROR';
$data['project'] = $project;
$this->load->view ($this->VIEW_DELETE, $data); $this->load->view ($this->VIEW_DELETE, $data);
} }
else else

View File

@ -429,7 +429,7 @@ class Site extends Controller
$this->load->view ($this->VIEW_LOG, $data); $this->load->view ($this->VIEW_LOG, $data);
} }
function wiki ($xlink) function wiki ($xlink = '')
{ {
$login = $this->login->getUser (); $login = $this->login->getUser ();
if (CODEPOT_SIGNIN_COMPULSORY && $login['id'] == '') if (CODEPOT_SIGNIN_COMPULSORY && $login['id'] == '')

View File

@ -84,6 +84,7 @@ $lang['MSG_LOG_CHANGE_BY'] = 'Changed by %s';
$lang['MSG_LOG_CREATE_BY'] = 'Created by %s'; $lang['MSG_LOG_CREATE_BY'] = 'Created by %s';
$lang['MSG_LOG_DELETE_BY'] = 'Deleted by %s'; $lang['MSG_LOG_DELETE_BY'] = 'Deleted by %s';
$lang['MSG_LOG_UPDATE_BY'] = 'Updated by %s'; $lang['MSG_LOG_UPDATE_BY'] = 'Updated by %s';
$lang['MSG_LOG_REVPROP_CHANGE_BY'] = 'Revision property %s changed by %s';
$lang['MSG_NO_DIFF'] = 'No difference found'; $lang['MSG_NO_DIFF'] = 'No difference found';
$lang['MSG_NO_CODE_AVAIL'] = 'No source code available'; $lang['MSG_NO_CODE_AVAIL'] = 'No source code available';

View File

@ -78,11 +78,13 @@ $lang['Username'] = '사용자명';
$lang['Wiki'] = '위키'; $lang['Wiki'] = '위키';
$lang['Wikis'] = '위키'; $lang['Wikis'] = '위키';
$lang['MSG_LOG_COMMIT_BY'] = '%s에 의해 커밋되었습니다'; $lang['MSG_LOG_COMMIT_BY'] = '%s이(가) 커밋했습니다';
$lang['MSG_LOG_CHANGE_BY'] = '%s에 의해 변경되었습니다'; $lang['MSG_LOG_CHANGE_BY'] = '%s이(가) 변경했습니다';
$lang['MSG_LOG_CREATE_BY'] = '%s에 의해 생성되었습니다'; $lang['MSG_LOG_CREATE_BY'] = '%s이(가) 생성했습니다';
$lang['MSG_LOG_DELETE_BY'] = '%s에 의해 삭제되었습니다'; $lang['MSG_LOG_DELETE_BY'] = '%s이(가) 삭제했습니다';
$lang['MSG_LOG_UPDATE_BY'] = '%s에 의해 갱신되었습니다'; $lang['MSG_LOG_UPDATE_BY'] = '%s이(가) 갱신했습니다';
$lang['MSG_LOG_REVPROP_CHANGE_BY'] = '리비전 속성 %s을(를) %s이(가) 변경했습니다';
$lang['MSG_NO_DIFF'] = '차이점이 없습니다'; $lang['MSG_NO_DIFF'] = '차이점이 없습니다';
$lang['MSG_NO_CODE_AVAIL'] = '소스코드가 없습니다'; $lang['MSG_NO_CODE_AVAIL'] = '소스코드가 없습니다';

View File

@ -53,6 +53,12 @@ class IssueModel extends Model
if ($search->summary != '') $this->db->like ('summary', $search->summary); if ($search->summary != '') $this->db->like ('summary', $search->summary);
$this->db->select ('count(id) as count'); $this->db->select ('count(id) as count');
$query = $this->db->get ('issue'); $query = $this->db->get ('issue');
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_complete ();
return FALSE;
}
$result = $query->result(); $result = $query->result();
$num = empty($result)? 0: $result[0]->count; $num = empty($result)? 0: $result[0]->count;

View File

@ -23,6 +23,12 @@ class LogModel extends Model
$this->db->select ('count(id) as count'); $this->db->select ('count(id) as count');
$query = $this->db->get ('log'); $query = $this->db->get ('log');
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_complete ();
return FALSE;
}
$result = $query->result(); $result = $query->result();
$num = empty($result)? 0: $result[0]->count; $num = empty($result)? 0: $result[0]->count;
@ -65,8 +71,12 @@ class LogModel extends Model
$commits[$count]['userid'] = $row->userid; $commits[$count]['userid'] = $row->userid;
if ($row->type == 'code') if ($row->type == 'code')
{
if ($row->action == 'commit')
{ {
list($type,$repo,$rev) = split('[,]', $row->message); list($type,$repo,$rev) = split('[,]', $row->message);
$tmp['type'] = $type; $tmp['type'] = $type;
$tmp['repo'] = $repo; $tmp['repo'] = $repo;
$tmp['rev'] = $rev; $tmp['rev'] = $rev;
@ -86,6 +96,21 @@ class LogModel extends Model
$tmp['author'] = $log[0]['author']; $tmp['author'] = $log[0]['author'];
$tmp['message'] = $log[0]['msg']; $tmp['message'] = $log[0]['msg'];
} }
}
else
{
list($type,$repo,$rev,$propname,$action) = split('[,]', $row->message);
$tmp['type'] = $type;
$tmp['repo'] = $repo;
$tmp['rev'] = $rev;
$tmp['propname'] = $propname;
$tmp['action'] = $action;
$tmp['time'] = $row->createdon;
$tmp['author'] = $row->userid;
}
$commits[$count]['message'] = $tmp; $commits[$count]['message'] = $tmp;
} }
@ -110,6 +135,16 @@ class LogModel extends Model
$this->write ($log); $this->write ($log);
} }
function writeCodeRevpropChange ($type, $repo, $rev, $userid, $propname, $action)
{
$log->type = 'code';
$log->action = 'revpropchange';
$log->projectid = $repo;
$log->userid = $userid;
$log->message = "{$type},{$repo},{$rev},{$propname},{$action}";
$this->write ($log);
}
function write ($log) function write ($log)
{ {
$this->db->trans_begin (); $this->db->trans_begin ();
@ -119,6 +154,7 @@ class LogModel extends Model
$this->db->set ('projectid', $log->projectid); $this->db->set ('projectid', $log->projectid);
$this->db->set ('message', $log->message); $this->db->set ('message', $log->message);
$this->db->set ('createdon', date('Y-m-d H:i:s')); $this->db->set ('createdon', date('Y-m-d H:i:s'));
$this->db->set ('userid', $log->userid);
$this->db->insert ('log'); $this->db->insert ('log');
if ($this->db->trans_status() === FALSE) if ($this->db->trans_status() === FALSE)

View File

@ -57,7 +57,14 @@ class ProjectModel extends Model
if ($search->id != '') $this->db->like ('id', $search->id); if ($search->id != '') $this->db->like ('id', $search->id);
if ($search->name != '') $this->db->like ('name', $search->name); if ($search->name != '') $this->db->like ('name', $search->name);
if ($search->summary != '') $this->db->like ('summary', $search->summary); if ($search->summary != '') $this->db->like ('summary', $search->summary);
$query = $this->db->get ('project'); $query = $this->db->get ('project');
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_complete ();
return FALSE;
}
$result = $query->result(); $result = $query->result();
$num = empty($result)? 0: $result[0]->count; $num = empty($result)? 0: $result[0]->count;
@ -146,10 +153,19 @@ class ProjectModel extends Model
return FALSE; return FALSE;
} }
$hooks = array (
"start-commit",
"post-commit",
"pre-revprop-change",
"post-revprop-change"
);
foreach ($hooks as $hook)
{
// copy hook scripts to the top repository directory // copy hook scripts to the top repository directory
// overwriting existing scripts are ok as they are // overwriting existing scripts are ok as they are
// just updated to the latest scripts anyway. // just updated to the latest scripts anyway.
$contents = @file_get_contents("{$cfgdir}/start-commit"); $contents = @file_get_contents("{$cfgdir}/${hook}");
if ($contents === FALSE) if ($contents === FALSE)
{ {
$this->deleteDirectory ("{$repodir}/{$project->id}"); $this->deleteDirectory ("{$repodir}/{$project->id}");
@ -158,7 +174,7 @@ class ProjectModel extends Model
} }
if (@file_put_contents ( if (@file_put_contents (
"{$repodir}/start-commit", "{$repodir}/${hook}",
str_replace('%API%', $api, $contents)) === FALSE) str_replace('%API%', $api, $contents)) === FALSE)
{ {
$this->deleteDirectory ("{$repodir}/{$project->id}"); $this->deleteDirectory ("{$repodir}/{$project->id}");
@ -166,35 +182,14 @@ class ProjectModel extends Model
return FALSE; return FALSE;
} }
$contents = @file_get_contents("{$cfgdir}/post-commit"); // install the hook script to the new project repository
if ($contents === FALSE) if (@chmod ("{$repodir}/{$hook}", 0755) === FALSE ||
@symlink ("../../{$hook}", "{$repodir}/{$project->id}/hooks/${hook}") === FALSE)
{ {
$this->deleteDirectory ("{$repodir}/{$project->id}"); $this->deleteDirectory ("{$repodir}/{$project->id}");
$this->db->trans_rollback (); $this->db->trans_rollback ();
return FALSE; return FALSE;
} }
if (@file_put_contents(
"{$repodir}/post-commit",
str_replace('%API%', $api, $contents)) === FALSE)
{
$this->deleteDirectory ("{$repodir}/{$project->id}");
$this->db->trans_rollback ();
return FALSE;
}
// install hook scripts to the new project repository
if (@chmod ("{$repodir}/start-commit", 0755) === FALSE ||
@chmod ("{$repodir}/post-commit", 0755) === FALSE ||
@symlink ("../../start-commit", "{$repodir}/{$project->id}/hooks/start-commit") === FALSE ||
@symlink ("../../post-commit", "{$repodir}/{$project->id}/hooks/post-commit") === FALSE)
{
// keep {$repodir}/start-commit, {$repodir}/post-commit
// to minimize impact on other projects. just delete the attempted
// project repository directory.
$this->deleteDirectory ("{$repodir}/{$project->id}");
$this->db->trans_rollback ();
return FALSE;
} }
$this->db->trans_commit (); $this->db->trans_commit ();
@ -257,11 +252,36 @@ class ProjectModel extends Model
} }
} }
function delete ($userid, $project) function delete ($userid, $project, $force = FALSE)
{ {
// TODO: check if userid can do this.. // TODO: check if userid can do this..
$this->db->trans_begin (); $this->db->trans_begin ();
if ($force)
{
$this->db->where ('projectid', $project->id);
$this->db->delete ('wiki');
$this->db->where ('projectid', $project->id);
$this->db->delete ('issue_change');
$this->db->where ('projectid', $project->id);
$this->db->delete ('issue');
$this->db->where ('projectid', $project->id);
$query = $this->db->get ('file');
if ($this->db->trans_status() === FALSE)
{
$this->db->trans_rollback ();
return FALSE;
}
$result = $query->result ();
$this->db->where ('projectid', $project->id);
$this->db->delete ('file');
}
$this->db->where ('id', $project->id); $this->db->where ('id', $project->id);
$this->db->delete ('project'); $this->db->delete ('project');
@ -288,6 +308,13 @@ class ProjectModel extends Model
} }
else else
{ {
if ($force && count($result) > 0)
{
// no way to roll back file delete.
// so deletion is done here.
$this->_delete_files_uploaded ($result);
}
$this->db->trans_commit (); $this->db->trans_commit ();
return TRUE; return TRUE;
} }
@ -394,6 +421,13 @@ class ProjectModel extends Model
if ($this->db->trans_status() === FALSE) return FALSE; if ($this->db->trans_status() === FALSE) return FALSE;
return ($count == 1)? TRUE: FALSE; return ($count == 1)? TRUE: FALSE;
} }
function _delete_files_uploaded ($files)
{
foreach ($files as $file)
@unlink (CODEPOT_FILE_DIR . "/{$file->encname}");
}
} }
?> ?>

View File

@ -200,15 +200,27 @@ $this->load->view (
print '<td class="details">'; print '<td class="details">';
print '<span class="description">'; print '<span class="description">';
if ($log['action'] == 'revpropchange')
{
$fmt = $this->lang->line ('MSG_LOG_REVPROP_CHANGE_BY');
print htmlspecialchars (sprintf($fmt, $code['propname'], $code['author']));
//$code['action']
}
else
{
$fmt = $this->lang->line ( $fmt = $this->lang->line (
'MSG_LOG_'.strtoupper($log['action']).'_BY'); 'MSG_LOG_'.strtoupper($log['action']).'_BY');
print htmlspecialchars (sprintf($fmt, $code['author'])); print htmlspecialchars (sprintf($fmt, $code['author']));
}
print '</span>'; print '</span>';
if ($log['action'] != 'revpropchange')
{
print '<pre class="message">'; print '<pre class="message">';
print htmlspecialchars ($code['message']); print htmlspecialchars ($code['message']);
print '</pre>'; print '</pre>';
} }
}
else else
{ {
print '<td class="object">'; print '<td class="object">';

View File

@ -118,15 +118,26 @@ $this->load->view (
print '<td></td>'; print '<td></td>';
print '<td colspan=1 class="details">'; print '<td colspan=1 class="details">';
print '<span class="description">'; print '<span class="description">';
if ($log['action'] == 'revpropchange')
{
$fmt = $this->lang->line ('MSG_LOG_REVPROP_CHANGE_BY');
print htmlspecialchars (sprintf($fmt, $x['propname'], $x['author']));
}
else
{
$fmt = $this->lang->line ( $fmt = $this->lang->line (
'MSG_LOG_'.strtoupper($log['action']).'_BY'); 'MSG_LOG_'.strtoupper($log['action']).'_BY');
print htmlspecialchars (sprintf($fmt, $x['author'])); print htmlspecialchars (sprintf($fmt, $x['author']));
}
print '</span>'; print '</span>';
if ($log['action'] != 'revpropchange')
{
print '<pre class="message">'; print '<pre class="message">';
$sm = strtok (trim ($x['message']), "\r\n"); $sm = strtok (trim ($x['message']), "\r\n");
print htmlspecialchars ($sm); print htmlspecialchars ($sm);
print '</pre>'; print '</pre>';
}
print '</td>'; print '</td>';
print '</tr>'; print '</tr>';
} }

View File

@ -116,15 +116,27 @@ foreach ($latest_projects as $project)
print '<td></td>'; print '<td></td>';
print '<td colspan=2 class="details">'; print '<td colspan=2 class="details">';
print '<span class="description">'; print '<span class="description">';
if ($log['action'] == 'revpropchange')
{
$fmt = $this->lang->line ('MSG_LOG_REVPROP_CHANGE_BY');
print htmlspecialchars (sprintf($fmt, $x['propname'], $x['author']));
}
else
{
$fmt = $this->lang->line ( $fmt = $this->lang->line (
'MSG_LOG_'.strtoupper($log['action']).'_BY'); 'MSG_LOG_'.strtoupper($log['action']).'_BY');
print htmlspecialchars (sprintf($fmt, $x['author'])); print htmlspecialchars (sprintf($fmt, $x['author']));
}
print '</span>'; print '</span>';
if ($log['action'] != 'revpropchange')
{
print '<pre class="message">'; print '<pre class="message">';
$sm = strtok (trim ($x['message']), "\r\n"); $sm = strtok (trim ($x['message']), "\r\n");
print htmlspecialchars ($sm); print htmlspecialchars ($sm);
print '</pre>'; print '</pre>';
}
print '</td>'; print '</td>';
print '</tr>'; print '</tr>';
} }

View File

@ -61,6 +61,7 @@ function load_ini ($file)
array ('log_threshold', 'integer', 0), array ('log_threshold', 'integer', 0),
array ('force_project_delete', 'boolean', FALSE),
array ('footer', 'string', '') array ('footer', 'string', '')
); );