added a new feature that allows you to create files by uploading files. this also allows creation of directories.

added new configuration items: commit_notification and commit_review_notification
This commit is contained in:
hyung-hwan 2015-08-16 11:06:39 +00:00
parent 0986be08db
commit cf532ebaf9
11 changed files with 481 additions and 90 deletions

View File

@ -257,6 +257,16 @@ code_folder_readme = "README.wiki,README.txt,README"
;------------------------------------------------------------------------------
email_sender = ""
;------------------------------------------------------------------------------
; Send notification upon a new commit if yes
;------------------------------------------------------------------------------
commit_notification = "yes"
;------------------------------------------------------------------------------
; Send commit review notification if yes
;------------------------------------------------------------------------------
commit_review_notification = "yes"
;------------------------------------------------------------------------------
; URL to include when sending a commit notification message.
; You can specify multiple urls. in fact, it's a free text.

View File

@ -55,6 +55,7 @@ sub get_config
database_prefix => $cfg->param ("database_prefix"),
email_sender => $cfg->param ("email_sender"),
commit_notification => $cfg->param ("commit_notification"),
commit_notification_url => $cfg->param ("commit_notification_url")
};
@ -340,6 +341,11 @@ sub email_message_to_project_members
Message => $message
);
if (length($cfg->{email_sender}) > 0)
{
$mail{From} .= $cfg->{email_sender};
}
Mail::Sendmail::sendmail (%mail);
return (1, undef);
}
@ -383,6 +389,8 @@ if (!defined($dbh))
write_commit_log ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $AUTHOR);
if (lc($cfg->{commit_notification}) eq 'yes')
{
my $commit_subject = "Commit r$REV by $AUTHOR in $REPOBASE";
my $commit_message = '';
@ -396,6 +404,7 @@ else
}
email_message_to_project_members ($cfg, $dbh, $cfg->{database_prefix}, $REPOBASE, $commit_subject, $commit_message);
}
close_database ($dbh);

View File

@ -35,6 +35,7 @@ class Code extends Controller
{
$this->load->model ('ProjectModel', 'projects');
$this->load->model ('SubversionModel', 'subversion');
$this->load->library ('upload');
$login = $this->login->getUser ();
if (CODEPOT_SIGNIN_COMPULSORY && $login['id'] == '')
@ -73,7 +74,53 @@ class Code extends Controller
$data['message'] = 'Failed to get file';
$this->load->view ($this->VIEW_ERROR, $data);
}
else if ($file['type'] == 'file')
else
{
$popup_error_message = '';
$post_new_message = $this->input->post('code_folder_new_message');
$post_max_item_no = $this->input->post('code_folder_new_item_count');
$post_unzip = $this->input->post('code_folder_new_item_unzip');
if ($post_new_message !== FALSE && $post_max_item_no !== FALSE)
{
$import_files = array ();
for ($i = 0; $i < $post_max_item_no; $i++)
{
$d = $this->input->post("code_folder_new_item_dir_$i");
if (strlen($d) > 0)
{
array_push ($import_files, array ('type' => 'dir', 'name' => $d));
}
$fid = "code_folder_new_item_file_$i";
if (array_key_exists($fid, $_FILES) && $_FILES[$fid]['name'] != '')
{
array_push ($import_files, array ('type' => 'file', 'name' => $_FILES[$fid]['name'], 'fid' => $fid, 'unzip' => $post_unzip));
}
}
if (count($import_files) > 0 && $this->subversion->importFiles ($projectid, $path, $login['id'], $post_new_message, $import_files, $this->upload) === FALSE)
{
$popup_error_message = '<pre>' . $this->subversion->import_files_errmsg . '</pre>';
}
else
{
$refreshed_file = $this->subversion->getFile ($projectid, $path, $rev);
if ($refreshed_file === FALSE)
{
$data['project'] = $project;
$data['message'] = 'Failed to get file';
$this->load->view ($this->VIEW_ERROR, $data);
return; /* EXIT HERE */
}
$file = $refreshed_file;
}
}
$data['popup_error_message'] = $popup_error_message;
if ($file['type'] == 'file')
{
$head_rev = $this->subversion->getHeadRev ($projectid, $path, $rev);
if ($head_rev === FALSE)
@ -142,6 +189,7 @@ class Code extends Controller
}
}
}
}
function blame ($projectid = '', $path = '', $rev = SVN_REVISION_HEAD)
{
@ -430,7 +478,6 @@ class Code extends Controller
}
}
$data['project'] = $project;
$data['fullpath'] = $path;
$data['file'] = $file;
@ -568,6 +615,8 @@ class Code extends Controller
// this is a hack to clear form data upon success
$this->form_validation->_field_data = array();
if (CODEPOT_COMMIT_REVIEW_NOTIFICATION)
{
// TODO: message localization
$email_subject = sprintf (
'New review message #%d for r%d by %s in %s',
@ -579,6 +628,7 @@ class Code extends Controller
);
}
}
}
else
{
$data['popup_error_message'] = 'Invalid review comment';

View File

@ -219,6 +219,33 @@ if ( !function_exists ('codepot_zip_dir'))
}
}
if ( !function_exists ('codepot_unzip_file'))
{
function codepot_unzip_file ($output_dir, $path)
{
$zip = new ZipArchive();
if ($zip->open ($path) === FALSE) return FALSE;
if ($zip->extractTo ($output_dir) === FALSE)
{
$zip->close ();
return FALSE;
}
$names = array();
for ($i = 0; $i < $zip->numFiles; $i++)
{
array_push ($names, $zip->getNameIndex($i));
}
$zip->close ();
return $names;
}
}
if ( !function_exists ('codepot_find_longest_matching_sequence'))
{
function codepot_find_longest_matching_sequence ($old, $old_start, $old_len, $new, $new_start, $new_len)

View File

@ -64,6 +64,8 @@ $lang['My issues'] = 'My issues';
$lang['My projects'] = 'My projects';
$lang['Name'] = 'Name';
$lang['New'] = 'New';
$lang['New directory'] = 'New directory';
$lang['New file'] = 'New file';
$lang['OK'] = 'OK';
$lang['Open issues'] = 'Open issues';
$lang['Other projects'] = 'Other projects';
@ -100,6 +102,7 @@ $lang['Text'] = 'Text';
$lang['Time'] = 'Time';
$lang['Type'] = 'Type';
$lang['Undo'] = 'Undo';
$lang['Unzip a zip file'] = 'Unzip a zip file';
$lang['Update'] = 'Update';
$lang['Username'] = 'Username';
$lang['Wiki'] = 'Wiki';

View File

@ -1,13 +1,13 @@
<?php
$lang['Administration'] = 'Administration';
$lang['All'] = 'Semua';
$lang['Apply'] = 'Apply';
$lang['Apply'] = 'Menterapkan';
$lang['Attachment'] = 'Attachment';
$lang['Attachments'] = 'Attachments';
$lang['Blame'] = 'Menyalahkan';
$lang['Blank'] = 'Blank';
$lang['Cancel'] = 'Cancel';
$lang['Change'] = 'Change';
$lang['Blank'] = 'Kosong';
$lang['Cancel'] = 'Membatalkan';
$lang['Change'] = 'Perubahan';
$lang['Change log'] = 'Change log';
$lang['Close'] = 'Close';
$lang['Code'] = 'Kode';
@ -41,7 +41,7 @@ $lang['Full Difference'] = 'FullDiff';
$lang['Graph'] = 'Graph';
$lang['Graphs'] = 'Graphs';
$lang['Head revision'] = 'Kepala revisi';
$lang['Hide metadata'] = 'Hide metadata';
$lang['Hide metadata'] = 'Menyembunyikan metadata';
$lang['History'] = 'Sejarah';
$lang['Home'] = 'Beranda';
$lang['Icon'] = 'Icon';
@ -64,6 +64,8 @@ $lang['My issues'] = 'Issue saya';
$lang['My projects'] = 'Proyek saya';
$lang['Name'] = 'Nama';
$lang['New'] = 'Baru';
$lang['New directory'] = 'Direktori baru';
$lang['New file'] = 'File baru';
$lang['OK'] = 'OK';
$lang['Open issues'] = 'Open issues';
$lang['Other projects'] = 'Proyek lain';
@ -99,6 +101,7 @@ $lang['Text'] = 'Teks';
$lang['Time'] = 'Waktu';
$lang['Type'] = 'Type';
$lang['Undo'] = 'Undo';
$lang['Unzip a zip file'] = 'Unzip a zip file';
$lang['Update'] = 'Memperbaharui';
$lang['Username'] = 'Nama pemakai';
$lang['Wiki'] = 'Wiki';

View File

@ -64,6 +64,8 @@ $lang['My issues'] = '내 이슈';
$lang['My projects'] = '내 프로젝트';
$lang['Name'] = '이름';
$lang['New'] = '신규';
$lang['New directory'] = 'New directory';
$lang['New file'] = 'New file';
$lang['OK'] = '확인';
$lang['Open issues'] = '미처리이슈';
$lang['Other projects'] = '다른 프로젝트';
@ -100,6 +102,7 @@ $lang['Text'] = '본문';
$lang['Time'] = '시간';
$lang['Type'] = '종류';
$lang['Undo'] = '되돌림';
$lang['Unzip a zip file'] = 'zip파일 풀기';
$lang['Update'] = '수정';
$lang['Username'] = '사용자명';
$lang['Wiki'] = '위키';

View File

@ -584,7 +584,7 @@ class ProjectModel extends Model
if (CODEPOT_EMAIL_SENDER != '') $additional_headers .= 'From: ' . CODEPOT_EMAIL_SENDER . "\r\n";
if (empty($recipients)) return FALSE;
mail ($recipients, $subject, wordwrap($message, 70, "\r\n"), $additional_headers);
mail ($recipients, $subject, $message, $additional_headers);
return TRUE;
}
}

View File

@ -250,14 +250,22 @@ class SubversionModel extends Model
}
public $store_file_errmsg = '';
public $import_files_errmsg = '';
function capture_save_error ($errno, $errmsg)
{
$this->store_file_errmsg = $errmsg;
}
function capture_import_error ($errno, $errmsg)
{
$this->import_files_errmsg = $errmsg;
}
function storeFile ($projectid, $path, $committer, $commit_message, $text)
{
$store_file_errmsg = '';
//$url = 'file://'.CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}";
$canon_path = $this->_canonical_path(CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}");
$canon_dir = dirname($canon_path);
@ -293,6 +301,143 @@ class SubversionModel extends Model
return TRUE;
}
function importFiles ($projectid, $path, $committer, $commit_message, $files, $uploader)
{
$import_files_errmsg = '';
//$url = 'file://'.CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}";
$full_path = CODEPOT_SVNREPO_DIR."/{$projectid}";
if (strlen($path) > 0) $full_path .= "/{$path}";
$canon_path = $this->_canonical_path($full_path);
$dirurl = 'file://' . $canon_path;
set_error_handler (array ($this, 'capture_import_error'));
$tfname = @tempnam(__FILE__, 'codepot-import-files-');
restore_error_handler ();
if ($tfname === FALSE)
{
return FALSE;
}
$actual_tfname = $tfname . '.d';
codepot_delete_files ($actual_tfname, TRUE); // delete the directory in case it exists
mkdir ($actual_tfname);
set_error_handler (array ($this, 'capture_import_error'));
if (@svn_auth_set_parameter (SVN_AUTH_PARAM_DEFAULT_USERNAME, $committer) === FALSE ||
@svn_checkout ($dirurl, $actual_tfname, SVN_REVISION_HEAD, SVN_NON_RECURSIVE) === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
foreach ($files as $f)
{
$xname = $actual_tfname . '/' . $f['name'];
if ($f['type'] == 'dir')
{
if (@mkdir($xname) === FALSE ||
@svn_add ($xname, TRUE, TRUE) === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
}
else if ($f['type'] == 'file')
{
$config['allowed_types'] = '*';
$config['max_size'] = 0;
$config['overwrite'] = FALSE;
$config['remove_spaces'] = FALSE;
$config['encrypt_name'] = TRUE;
if (strcasecmp($f['unzip'], 'yes') == 0 &&
strcasecmp(substr($f['name'], -4), '.zip') == 0)
{
$unzip = TRUE;
if (function_exists('sys_get_temp_dir'))
$config['upload_path'] = sys_get_temp_dir();
else
$config['upload_path'] = '/tmp';
}
else
{
$unzip = FALSE;
$config['upload_path'] = $actual_tfname;
}
$uploader->initialize ($config);
if (!$uploader->do_upload($f['fid']))
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
$ud = $uploader->data();
if ($unzip)
{
$x = codepot_unzip_file ($actual_tfname, $ud['full_path']);
@unlink ($ud['full_path']);
if ($x === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
foreach ($x as $y)
{
if (@svn_add ($actual_tfname . '/' . $y, TRUE, TRUE) === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
}
}
else
{
@rename ($ud['full_path'], $xname);
if (@svn_add ($xname, TRUE, TRUE) === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
}
}
// ignore other types
}
if (($result = @svn_commit ($commit_message, $actual_tfname)) === FALSE)
{
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE);
@unlink ($tfname);
return FALSE;
}
restore_error_handler ();
codepot_delete_files ($actual_tfname, TRUE); // delete the directory in case it exists
@unlink ($tfname);
return TRUE;
}
function getRevHistory ($projectid, $path, $rev)
{
//$url = 'file:///'.CODEPOT_SVNREPO_DIR."/{$projectid}/{$path}";

View File

@ -180,8 +180,81 @@ function render_readme()
}
var new_file_item_no = 0;
var new_dir_item_no = 0;
function get_new_item_html(no, type, name)
{
return codepot_sprintf ('<li><input type="%s" name="code_folder_new_item_%s_%d" /></li>', type, name, no);
}
$(function () {
<?php if (isset($login['id']) && $login['id'] != ''): ?>
new_file_item_no = 0;
new_dir_item_no = 0;
$('#code_folder_mainarea_new_file_form_item_list').append (get_new_item_html(new_file_item_no, 'file', 'file'));
$('#code_folder_mainarea_new_dir_form_item_list').append (get_new_item_html(new_dir_item_no, 'text', 'dir'));
$("#code_folder_mainarea_new_file_form_div").dialog (
{
title: '<?php print $this->lang->line('File');?>',
resizable: true,
autoOpen: false,
modal: true,
buttons: {
'More': function () {
++new_file_item_no;
$('#code_folder_mainarea_new_file_form_item_list').append (get_new_item_html(new_file_item_no, 'file', 'file'));
},
'<?php print $this->lang->line('OK')?>': function () {
$('#code_folder_mainarea_new_file_item_count').val (new_file_item_no + 1);
$('#code_folder_mainarea_new_file_form').submit();
$(this).dialog('close');
},
'<?php print $this->lang->line('Cancel')?>': function () {
$(this).dialog('close');
}
},
clsoe: function() {}
}
);
$("#code_folder_mainarea_new_dir_form_div").dialog (
{
title: '<?php print $this->lang->line('Directory');?>',
resizable: true,
autoOpen: false,
modal: true,
buttons: {
'More': function () {
++new_dir_item_no;
$('#code_folder_mainarea_new_dir_form_item_list').append (get_new_item_html(new_dir_item_no, 'text', 'dir'));
},
'<?php print $this->lang->line('OK')?>': function () {
$('#code_folder_mainarea_new_dir_item_count').val (new_dir_item_no + 1);
$('#code_folder_mainarea_new_dir_form').submit();
$(this).dialog('close');
},
'<?php print $this->lang->line('Cancel')?>': function () {
$(this).dialog('close');
}
},
clsoe: function() {}
}
);
$("#code_folder_mainarea_new_file_button").button().click (function() {
$("#code_folder_mainarea_new_file_form_div").dialog('open');
});
$("#code_folder_mainarea_new_dir_button").button().click (function() {
$("#code_folder_mainarea_new_dir_form_div").dialog('open');
});
<?php endif; ?>
<?php if ($file_count > 0): ?>
<?php
if ($login['settings'] != NULL && $login['settings']->code_hide_metadata == 'Y')
@ -194,7 +267,6 @@ $(function () {
btn_label = "<?php print $this->lang->line('Show metadata')?>";
btn = $("#code_folder_mainarea_metadata_button").button({"label": btn_label}).click (function () {
if ($("#code_folder_mainarea_result_info").is(":visible"))
{
$("#code_folder_mainarea_result_info").hide("blind",{},200);
@ -271,6 +343,23 @@ $(function () {
});
render_readme ();
<?php if (strlen($popup_error_message) > 0): ?>
$("#code_folder_popup_error_div").dialog( {
title: '<?php print $this->lang->line('Error')?>',
width: 'auto',
height: 'auto',
modal: true,
autoOpen: true,
buttons: {
"<?php print $this->lang->line('OK')?>": function() {
$( this ).dialog( "close" );
}
}
});
<?php endif; ?>
});
</script>
@ -451,11 +540,22 @@ $this->load->view (
print ' ';
print anchor ("code/file/{$project->id}/${xpar}/{$next_revision}", '<i class="fa fa-arrow-circle-right"></i>');
if ($file_count > 0)
if ((isset($login['id']) && $login['id'] != '') || $file_count > 0)
{
print ' | ';
if (isset($login['id']) && $login['id'] != '')
{
printf ('<a id="code_folder_mainarea_new_file_button" href="#">%s</a>', $this->lang->line('New file'));
printf ('<a id="code_folder_mainarea_new_dir_button" href="#">%s</a>', $this->lang->line('New directory'));
}
if ($file_count > 0)
{
printf ('<a id="code_folder_mainarea_metadata_button" href="#">%s</a>', $this->lang->line('Metadata'));
}
}
print form_close();
?>
@ -677,6 +777,38 @@ $this->load->view (
</div> <!-- code_folder_mainarea_result -->
<?php if (isset($login['id']) && $login['id'] != ''): ?>
<div id="code_folder_mainarea_new_file_form_div">
<?php
$attrs = array ('id' => 'code_folder_mainarea_new_file_form');
// this posts to the head revision regardless of the revision being shown
print form_open_multipart("code/file/{$project->id}/".$this->converter->AsciiToHex($headpath), $attrs);
?>
<input type='hidden' name='code_folder_new_item_count' id='code_folder_mainarea_new_file_item_count' />
<div><?php print $this->lang->line('Message'); ?>:</div>
<div><textarea type='textarea' name='code_folder_new_message' style='width:100%;'></textarea></div>
<div><input type='checkbox' name='code_folder_new_item_unzip' value='yes'/><?php print $this->lang->line('Unzip a zip file'); ?></div>
<div><ul id='code_folder_mainarea_new_file_form_item_list'></ul></div>
<?php print form_close();?>
</div>
<div id="code_folder_mainarea_new_dir_form_div">
<?php
$attrs = array ('id' => 'code_folder_mainarea_new_dir_form');
// this posts to the head revision regardless of the revision being shown
print form_open_multipart("code/file/{$project->id}/".$this->converter->AsciiToHex($headpath), $attrs);
?>
<input type='hidden' name='code_folder_new_item_count' id='code_folder_mainarea_new_dir_item_count' />
<div><?php print $this->lang->line('Message'); ?>:</div>
<div><textarea type='textarea' name='code_folder_new_message' style='width:100%;'></textarea></div>
<div><ul id='code_folder_mainarea_new_dir_form_item_list'></ul></div>
<?php print form_close();?>
</div>
<?php endif; ?>
</div> <!-- code_folder_mainarea -->
<div class='footer-pusher'></div> <!-- for sticky footer -->
@ -689,6 +821,12 @@ $this->load->view (
<!-- ================================================================== -->
<?php if (strlen($popup_error_message) > 0): ?>
<div id="code_folder_popup_error_div">
<?php print $popup_error_message?>
</div>
<?php endif; ?>
</body>
</html>

View File

@ -84,7 +84,10 @@ function load_ini ($file)
array ('footer', 'string', ''),
array ('cloc_command_path', 'string', CODEPOT_CFG_DIR.'/cloc.pl'),
array ('code_folder_readme', 'string', 'README'),
array ('email_sender', 'string', ''),
array ('commit_notification', 'boolean', TRUE),
array ('commit_review_notification', 'boolean', TRUE),
array ('commit_notification_url', 'string', ''),
array ('svn_tag_property', 'string', 'codepot:tag'),