diff --git a/codepot/etc/Makefile.in b/codepot/etc/Makefile.in index 2f82c638..d1ae9224 100644 --- a/codepot/etc/Makefile.in +++ b/codepot/etc/Makefile.in @@ -169,7 +169,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ wwwdir = @wwwdir@ 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) all: all-am diff --git a/codepot/etc/codepot.ini.in b/codepot/etc/codepot.ini.in index f1aefeb5..ce8a5d8c 100644 --- a/codepot/etc/codepot.ini.in +++ b/codepot/etc/codepot.ini.in @@ -136,6 +136,14 @@ file_dir = "@DEPOTDIR@/files" ;------------------------------------------------------------------------------ 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 ;------------------------------------------------------------------------------ diff --git a/codepot/etc/post-revprop-change b/codepot/etc/post-revprop-change index 791bcdeb..535985e3 100755 --- a/codepot/etc/post-revprop-change +++ b/codepot/etc/post-revprop-change @@ -1,7 +1,7 @@ #!/bin/sh REPOBASE="`basename "${1}"`" -REV="${2}" +REVISION="${2}" USER="${3}" PROPNAME="${4}" ACTION="${5}" @@ -9,5 +9,5 @@ ACTION="${5}" # [STDIN] PROPVAL ** the old property value is passed via STDIN. # 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 diff --git a/codepot/etc/pre-revprop-change b/codepot/etc/pre-revprop-change index e59c0f38..263da313 100755 --- a/codepot/etc/pre-revprop-change +++ b/codepot/etc/pre-revprop-change @@ -1,7 +1,7 @@ #!/bin/sh REPOBASE="`basename "${1}"`" -USER="${2}" +REVISION="${2}" USER="${3}" PROPNAME="${4}" ACTION="${5}" diff --git a/codepot/src/codepot/controllers/api.php b/codepot/src/codepot/controllers/api.php index da92dd0f..b9a84d6a 100644 --- a/codepot/src/codepot/controllers/api.php +++ b/codepot/src/codepot/controllers/api.php @@ -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 (); - if (!isset($repo) || !isset($rev) || !isset($propname)) return; + if (!isset($repo) || !isset($rev) || !isset($propname) || !isset($action)) return; $this->load->model ('LogModel', 'logs'); - // TODO: - //$this->logs->writeCodeRevpropChange ($type, $repo, $rev, ''); + $this->logs->writeCodeRevpropChange ($type, $repo, $rev, $userid, $propname, $action); } } diff --git a/codepot/src/codepot/controllers/project.php b/codepot/src/codepot/controllers/project.php index efad7a5f..7f6dde29 100644 --- a/codepot/src/codepot/controllers/project.php +++ b/codepot/src/codepot/controllers/project.php @@ -304,10 +304,13 @@ class Project extends Controller { 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) { $data['message'] = 'DATABASE ERROR'; + $data['project'] = $project; $this->load->view ($this->VIEW_DELETE, $data); } else diff --git a/codepot/src/codepot/controllers/site.php b/codepot/src/codepot/controllers/site.php index e69ce43e..1eb5e240 100644 --- a/codepot/src/codepot/controllers/site.php +++ b/codepot/src/codepot/controllers/site.php @@ -429,7 +429,7 @@ class Site extends Controller $this->load->view ($this->VIEW_LOG, $data); } - function wiki ($xlink) + function wiki ($xlink = '') { $login = $this->login->getUser (); if (CODEPOT_SIGNIN_COMPULSORY && $login['id'] == '') diff --git a/codepot/src/codepot/language/english/common_lang.php b/codepot/src/codepot/language/english/common_lang.php index 4c7eebe1..02d169fb 100644 --- a/codepot/src/codepot/language/english/common_lang.php +++ b/codepot/src/codepot/language/english/common_lang.php @@ -84,6 +84,7 @@ $lang['MSG_LOG_CHANGE_BY'] = 'Changed by %s'; $lang['MSG_LOG_CREATE_BY'] = 'Created by %s'; $lang['MSG_LOG_DELETE_BY'] = 'Deleted 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_CODE_AVAIL'] = 'No source code available'; diff --git a/codepot/src/codepot/language/korean/common_lang.php b/codepot/src/codepot/language/korean/common_lang.php index 8bb96272..1b74d30f 100644 --- a/codepot/src/codepot/language/korean/common_lang.php +++ b/codepot/src/codepot/language/korean/common_lang.php @@ -78,11 +78,13 @@ $lang['Username'] = '사용자명'; $lang['Wiki'] = '위키'; $lang['Wikis'] = '위키'; -$lang['MSG_LOG_COMMIT_BY'] = '%s에 의해 커밋되었습니다'; -$lang['MSG_LOG_CHANGE_BY'] = '%s에 의해 변경되었습니다'; -$lang['MSG_LOG_CREATE_BY'] = '%s에 의해 생성되었습니다'; -$lang['MSG_LOG_DELETE_BY'] = '%s에 의해 삭제되었습니다'; -$lang['MSG_LOG_UPDATE_BY'] = '%s에 의해 갱신되었습니다'; +$lang['MSG_LOG_COMMIT_BY'] = '%s이(가) 커밋했습니다'; +$lang['MSG_LOG_CHANGE_BY'] = '%s이(가) 변경했습니다'; +$lang['MSG_LOG_CREATE_BY'] = '%s이(가) 생성했습니다'; +$lang['MSG_LOG_DELETE_BY'] = '%s이(가) 삭제했습니다'; +$lang['MSG_LOG_UPDATE_BY'] = '%s이(가) 갱신했습니다'; +$lang['MSG_LOG_REVPROP_CHANGE_BY'] = '리비전 속성 %s을(를) %s이(가) 변경했습니다'; + $lang['MSG_NO_DIFF'] = '차이점이 없습니다'; $lang['MSG_NO_CODE_AVAIL'] = '소스코드가 없습니다'; diff --git a/codepot/src/codepot/models/issuemodel.php b/codepot/src/codepot/models/issuemodel.php index 1b7a97ae..3446314e 100644 --- a/codepot/src/codepot/models/issuemodel.php +++ b/codepot/src/codepot/models/issuemodel.php @@ -53,6 +53,12 @@ class IssueModel extends Model if ($search->summary != '') $this->db->like ('summary', $search->summary); $this->db->select ('count(id) as count'); $query = $this->db->get ('issue'); + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_complete (); + return FALSE; + } + $result = $query->result(); $num = empty($result)? 0: $result[0]->count; diff --git a/codepot/src/codepot/models/logmodel.php b/codepot/src/codepot/models/logmodel.php index 33259466..c26ac259 100644 --- a/codepot/src/codepot/models/logmodel.php +++ b/codepot/src/codepot/models/logmodel.php @@ -23,6 +23,12 @@ class LogModel extends Model $this->db->select ('count(id) as count'); $query = $this->db->get ('log'); + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_complete (); + return FALSE; + } + $result = $query->result(); $num = empty($result)? 0: $result[0]->count; @@ -66,25 +72,44 @@ class LogModel extends Model if ($row->type == 'code') { - list($type,$repo,$rev) = split('[,]', $row->message); - $tmp['type'] = $type; - $tmp['repo'] = $repo; - $tmp['rev'] = $rev; - $log = @svn_log ( - 'file:///'.CODEPOT_SVNREPO_DIR."/{$repo}", - $rev, $rev, 1,SVN_DISCOVER_CHANGED_PATHS); - if ($log === FALSE || count($log) < 1) + if ($row->action == 'commit') { - $tmp['time'] = ''; - $tmp['author'] = ''; - $tmp['message'] = ''; + list($type,$repo,$rev) = split('[,]', $row->message); + + $tmp['type'] = $type; + $tmp['repo'] = $repo; + $tmp['rev'] = $rev; + + $log = @svn_log ( + 'file:///'.CODEPOT_SVNREPO_DIR."/{$repo}", + $rev, $rev, 1,SVN_DISCOVER_CHANGED_PATHS); + if ($log === FALSE || count($log) < 1) + { + $tmp['time'] = ''; + $tmp['author'] = ''; + $tmp['message'] = ''; + } + else + { + $tmp['time'] = $log[0]['date']; + $tmp['author'] = $log[0]['author']; + $tmp['message'] = $log[0]['msg']; + } } else { - $tmp['time'] = $log[0]['date']; - $tmp['author'] = $log[0]['author']; - $tmp['message'] = $log[0]['msg']; + 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; @@ -110,6 +135,16 @@ class LogModel extends Model $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) { $this->db->trans_begin (); @@ -119,6 +154,7 @@ class LogModel extends Model $this->db->set ('projectid', $log->projectid); $this->db->set ('message', $log->message); $this->db->set ('createdon', date('Y-m-d H:i:s')); + $this->db->set ('userid', $log->userid); $this->db->insert ('log'); if ($this->db->trans_status() === FALSE) diff --git a/codepot/src/codepot/models/projectmodel.php b/codepot/src/codepot/models/projectmodel.php index 9c3577ee..7b4b8739 100644 --- a/codepot/src/codepot/models/projectmodel.php +++ b/codepot/src/codepot/models/projectmodel.php @@ -57,7 +57,14 @@ class ProjectModel extends Model if ($search->id != '') $this->db->like ('id', $search->id); if ($search->name != '') $this->db->like ('name', $search->name); if ($search->summary != '') $this->db->like ('summary', $search->summary); + $query = $this->db->get ('project'); + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_complete (); + return FALSE; + } + $result = $query->result(); $num = empty($result)? 0: $result[0]->count; @@ -146,55 +153,43 @@ class ProjectModel extends Model return FALSE; } - // copy hook scripts to the top repository directory - // overwriting existing scripts are ok as they are - // just updated to the latest scripts anyway. - $contents = @file_get_contents("{$cfgdir}/start-commit"); - if ($contents === FALSE) - { - $this->deleteDirectory ("{$repodir}/{$project->id}"); - $this->db->trans_rollback (); - return FALSE; - } + $hooks = array ( + "start-commit", + "post-commit", + "pre-revprop-change", + "post-revprop-change" + ); - if (@file_put_contents ( - "{$repodir}/start-commit", - str_replace('%API%', $api, $contents)) === FALSE) + foreach ($hooks as $hook) { - $this->deleteDirectory ("{$repodir}/{$project->id}"); - $this->db->trans_rollback (); - return FALSE; - } + // copy hook scripts to the top repository directory + // overwriting existing scripts are ok as they are + // just updated to the latest scripts anyway. + $contents = @file_get_contents("{$cfgdir}/${hook}"); + if ($contents === FALSE) + { + $this->deleteDirectory ("{$repodir}/{$project->id}"); + $this->db->trans_rollback (); + return FALSE; + } - $contents = @file_get_contents("{$cfgdir}/post-commit"); - if ($contents === FALSE) - { - $this->deleteDirectory ("{$repodir}/{$project->id}"); - $this->db->trans_rollback (); - return FALSE; - } + if (@file_put_contents ( + "{$repodir}/${hook}", + str_replace('%API%', $api, $contents)) === FALSE) + { + $this->deleteDirectory ("{$repodir}/{$project->id}"); + $this->db->trans_rollback (); + 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; + // install the hook script to the new project repository + if (@chmod ("{$repodir}/{$hook}", 0755) === FALSE || + @symlink ("../../{$hook}", "{$repodir}/{$project->id}/hooks/${hook}") === FALSE) + { + $this->deleteDirectory ("{$repodir}/{$project->id}"); + $this->db->trans_rollback (); + return FALSE; + } } $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.. $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->delete ('project'); @@ -288,6 +308,13 @@ class ProjectModel extends Model } 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 (); return TRUE; } @@ -394,6 +421,13 @@ class ProjectModel extends Model if ($this->db->trans_status() === FALSE) return FALSE; return ($count == 1)? TRUE: FALSE; } + + + function _delete_files_uploaded ($files) + { + foreach ($files as $file) + @unlink (CODEPOT_FILE_DIR . "/{$file->encname}"); + } } ?> diff --git a/codepot/src/codepot/views/log.php b/codepot/src/codepot/views/log.php index b7c727a4..a28f43bf 100644 --- a/codepot/src/codepot/views/log.php +++ b/codepot/src/codepot/views/log.php @@ -200,14 +200,26 @@ $this->load->view ( print ''; print ''; - $fmt = $this->lang->line ( - 'MSG_LOG_'.strtoupper($log['action']).'_BY'); - print htmlspecialchars (sprintf($fmt, $code['author'])); + 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 ( + 'MSG_LOG_'.strtoupper($log['action']).'_BY'); + print htmlspecialchars (sprintf($fmt, $code['author'])); + } print ''; - print '
';
-			print htmlspecialchars ($code['message']);
-			print '
'; + if ($log['action'] != 'revpropchange') + { + print '
';
+				print htmlspecialchars ($code['message']);
+				print '
'; + } } else { diff --git a/codepot/src/codepot/views/project_home.php b/codepot/src/codepot/views/project_home.php index 368270ed..f3d3fed5 100644 --- a/codepot/src/codepot/views/project_home.php +++ b/codepot/src/codepot/views/project_home.php @@ -118,15 +118,26 @@ $this->load->view ( print ''; print ''; print ''; - $fmt = $this->lang->line ( - 'MSG_LOG_'.strtoupper($log['action']).'_BY'); - print htmlspecialchars (sprintf($fmt, $x['author'])); + 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 ( + 'MSG_LOG_'.strtoupper($log['action']).'_BY'); + print htmlspecialchars (sprintf($fmt, $x['author'])); + } print ''; - print '
';
-			$sm = strtok (trim ($x['message']), "\r\n");
-			print htmlspecialchars ($sm);
-			print '
'; + if ($log['action'] != 'revpropchange') + { + print '
';
+				$sm = strtok (trim ($x['message']), "\r\n");
+				print htmlspecialchars ($sm);
+				print '
'; + } print ''; print ''; } diff --git a/codepot/src/codepot/views/site_home.php b/codepot/src/codepot/views/site_home.php index 9c086fa6..9d6d142f 100644 --- a/codepot/src/codepot/views/site_home.php +++ b/codepot/src/codepot/views/site_home.php @@ -116,15 +116,27 @@ foreach ($latest_projects as $project) print ''; print ''; print ''; - $fmt = $this->lang->line ( - 'MSG_LOG_'.strtoupper($log['action']).'_BY'); - print htmlspecialchars (sprintf($fmt, $x['author'])); + + 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 ( + 'MSG_LOG_'.strtoupper($log['action']).'_BY'); + print htmlspecialchars (sprintf($fmt, $x['author'])); + } print ''; - print '
';
-			$sm = strtok (trim ($x['message']), "\r\n");
-			print htmlspecialchars ($sm);
-			print '
'; + if ($log['action'] != 'revpropchange') + { + print '
';
+				$sm = strtok (trim ($x['message']), "\r\n");
+				print htmlspecialchars ($sm);
+				print '
'; + } print ''; print ''; } diff --git a/codepot/src/config.php.in b/codepot/src/config.php.in index 75697906..1eb45da3 100644 --- a/codepot/src/config.php.in +++ b/codepot/src/config.php.in @@ -61,6 +61,7 @@ function load_ini ($file) array ('log_threshold', 'integer', 0), + array ('force_project_delete', 'boolean', FALSE), array ('footer', 'string', '') );