... | ... |
@@ -116,7 +116,15 @@ sub startup { |
116 | 116 |
|
117 | 117 |
# Helper |
118 | 118 |
$self->helper(gitprep_api => sub { Gitprep::API->new(shift) }); |
119 |
- |
|
119 |
+ $self->helper(finish_rendering => sub { |
|
120 |
+ my $self = shift; |
|
121 |
+ |
|
122 |
+ $self->stash->{'mojo.routed'} = 1; |
|
123 |
+ $self->rendered; |
|
124 |
+ |
|
125 |
+ return $self; |
|
126 |
+ }); |
|
127 |
+ |
|
120 | 128 |
# Routes |
121 | 129 |
my $r = $self->routes; |
122 | 130 |
|
... | ... |
@@ -179,7 +187,7 @@ sub startup { |
179 | 187 |
$r->get('/commits/#rev/(*blob)')->name('commits'); |
180 | 188 |
|
181 | 189 |
# Branches |
182 |
- $r->get('/branches')->name('branches'); |
|
190 |
+ $r->any('/branches')->name('branches'); |
|
183 | 191 |
|
184 | 192 |
# Tags |
185 | 193 |
$r->get('/tags')->name('tags'); |
... | ... |
@@ -87,21 +87,30 @@ sub logined_admin { |
87 | 87 |
} |
88 | 88 |
|
89 | 89 |
sub logined { |
90 |
- my $self = shift; |
|
90 |
+ my ($self, $user) = @_; |
|
91 | 91 |
|
92 | 92 |
my $c = $self->cntl; |
93 | 93 |
|
94 | 94 |
my $dbi = $c->app->dbi; |
95 | 95 |
|
96 |
- my $user = $c->session('user'); |
|
96 |
+ my $current_user = $c->session('user'); |
|
97 | 97 |
my $password = $c->session('password'); |
98 | 98 |
return unless defined $password; |
99 | 99 |
|
100 | 100 |
my $correct_password |
101 |
- = $dbi->model('user')->select('password', id => $user)->value; |
|
101 |
+ = $dbi->model('user')->select('password', id => $current_user)->value; |
|
102 | 102 |
return unless defined $correct_password; |
103 | 103 |
|
104 |
- return $password eq $correct_password; |
|
104 |
+ my $logined; |
|
105 |
+ |
|
106 |
+ if (defined $user) { |
|
107 |
+ $logined = $user eq $current_user && $password eq $correct_password; |
|
108 |
+ } |
|
109 |
+ else { |
|
110 |
+ $logined = $password eq $correct_password |
|
111 |
+ } |
|
112 |
+ |
|
113 |
+ return $logined; |
|
105 | 114 |
} |
106 | 115 |
|
107 | 116 |
sub users { |
... | ... |
@@ -172,21 +172,6 @@ sub blob_plain { |
172 | 172 |
return $content; |
173 | 173 |
} |
174 | 174 |
|
175 |
-sub blob_raw { |
|
176 |
- my ($self, $user, $project, $rev, $path) = @_; |
|
177 |
- |
|
178 |
- # Get blob raw |
|
179 |
- my @cmd = $self->cmd($user, $project, 'cat-file', 'blob', "$rev:$path"); |
|
180 |
- open my $fh, "-|", @cmd |
|
181 |
- or croak 500, "Open git-cat-file failed"; |
|
182 |
- local $/; |
|
183 |
- my $blob_raw = scalar <$fh>; |
|
184 |
- |
|
185 |
- close $fh or croak 'Reading git-shortlog failed'; |
|
186 |
- |
|
187 |
- return $blob_raw; |
|
188 |
-} |
|
189 |
- |
|
190 | 175 |
sub blob_mimetype { |
191 | 176 |
my ($self, $user, $project, $rev, $file) = @_; |
192 | 177 |
|
... | ... |
@@ -233,6 +218,43 @@ sub blob_contenttype { |
233 | 218 |
return $type; |
234 | 219 |
} |
235 | 220 |
|
221 |
+sub blob_mode { |
|
222 |
+ my ($self, $user, $project, $rev, $file) = @_; |
|
223 |
+ |
|
224 |
+ # Mode |
|
225 |
+ $file =~ s#/+$##; |
|
226 |
+ my @cmd = $self->cmd( |
|
227 |
+ $user, |
|
228 |
+ $project, |
|
229 |
+ 'ls-tree', |
|
230 |
+ $rev, |
|
231 |
+ '--', |
|
232 |
+ $file |
|
233 |
+ ); |
|
234 |
+ open my $fh, '-|', @cmd |
|
235 |
+ or croak 'Open git-ls-tree failed'; |
|
236 |
+ my $line = $self->_dec(scalar <$fh>); |
|
237 |
+ close $fh or return; |
|
238 |
+ my ($mode) = ($line || '') =~ m/^([0-9]+) /; |
|
239 |
+ |
|
240 |
+ return $mode; |
|
241 |
+} |
|
242 |
+ |
|
243 |
+sub blob_raw { |
|
244 |
+ my ($self, $user, $project, $rev, $path) = @_; |
|
245 |
+ |
|
246 |
+ # Get blob raw |
|
247 |
+ my @cmd = $self->cmd($user, $project, 'cat-file', 'blob', "$rev:$path"); |
|
248 |
+ open my $fh, "-|", @cmd |
|
249 |
+ or croak 500, "Open git-cat-file failed"; |
|
250 |
+ local $/; |
|
251 |
+ my $blob_raw = scalar <$fh>; |
|
252 |
+ |
|
253 |
+ close $fh or croak 'Reading git-shortlog failed'; |
|
254 |
+ |
|
255 |
+ return $blob_raw; |
|
256 |
+} |
|
257 |
+ |
|
236 | 258 |
sub blob_size_kb { |
237 | 259 |
my ($self, $user, $project, $rev, $file) = @_; |
238 | 260 |
|
... | ... |
@@ -341,6 +363,28 @@ sub commits_number { |
341 | 363 |
return $commits_num; |
342 | 364 |
} |
343 | 365 |
|
366 |
+sub delete_branch { |
|
367 |
+ my ($self, $user, $project, $branch) = @_; |
|
368 |
+ |
|
369 |
+ my $branches = $self->branches($user, $project); |
|
370 |
+ my $exists; |
|
371 |
+ for my $b (@$branches) { |
|
372 |
+ if ($branch eq $b->{name}) { |
|
373 |
+ $exists = 1; |
|
374 |
+ next; |
|
375 |
+ } |
|
376 |
+ } |
|
377 |
+ |
|
378 |
+ if ($exists) { |
|
379 |
+ my @cmd = $self->cmd($user, $project, 'branch', '-D', $branch); |
|
380 |
+ system(@cmd) == 0 |
|
381 |
+ or croak "Branch deleting failed. Can't delete branch $branch"; |
|
382 |
+ } |
|
383 |
+ else { |
|
384 |
+ croak "Branch deleteting failed.. branchg $branch is not exists"; |
|
385 |
+ } |
|
386 |
+} |
|
387 |
+ |
|
344 | 388 |
sub description { |
345 | 389 |
my ($self, $user, $project, $description) = @_; |
346 | 390 |
|
... | ... |
@@ -362,77 +406,6 @@ sub description { |
362 | 406 |
} |
363 | 407 |
} |
364 | 408 |
|
365 |
-sub blob_mode { |
|
366 |
- my ($self, $user, $project, $rev, $file) = @_; |
|
367 |
- |
|
368 |
- # Mode |
|
369 |
- $file =~ s#/+$##; |
|
370 |
- my @cmd = $self->cmd( |
|
371 |
- $user, |
|
372 |
- $project, |
|
373 |
- 'ls-tree', |
|
374 |
- $rev, |
|
375 |
- '--', |
|
376 |
- $file |
|
377 |
- ); |
|
378 |
- open my $fh, '-|', @cmd |
|
379 |
- or croak 'Open git-ls-tree failed'; |
|
380 |
- my $line = $self->_dec(scalar <$fh>); |
|
381 |
- close $fh or return; |
|
382 |
- my ($mode) = ($line || '') =~ m/^([0-9]+) /; |
|
383 |
- |
|
384 |
- return $mode; |
|
385 |
-} |
|
386 |
- |
|
387 |
-sub file_type { |
|
388 |
- my ($self, $mode) = @_; |
|
389 |
- |
|
390 |
- # File type |
|
391 |
- if ($mode !~ m/^[0-7]+$/) { return $mode } |
|
392 |
- else { $mode = oct $mode } |
|
393 |
- if ($self->_s_isgitlink($mode)) { return 'submodule' } |
|
394 |
- elsif (S_ISDIR($mode & S_IFMT)) { return 'directory' } |
|
395 |
- elsif (S_ISLNK($mode)) { return 'symlink' } |
|
396 |
- elsif (S_ISREG($mode)) { return 'file' } |
|
397 |
- else { return 'unknown' } |
|
398 |
- |
|
399 |
- return |
|
400 |
-} |
|
401 |
- |
|
402 |
-sub file_type_long { |
|
403 |
- my ($self, $mode) = @_; |
|
404 |
- |
|
405 |
- # File type |
|
406 |
- if ($mode !~ m/^[0-7]+$/) { return $mode } |
|
407 |
- else { $mode = oct $mode } |
|
408 |
- if ($self->_s_isgitlink($mode)) { return 'submodule' } |
|
409 |
- elsif (S_ISDIR($mode & S_IFMT)) { return 'directory' } |
|
410 |
- elsif (S_ISLNK($mode)) { return 'symlink' } |
|
411 |
- elsif (S_ISREG($mode)) { |
|
412 |
- if ($mode & S_IXUSR) { return 'executable file' } |
|
413 |
- else { return 'file' } |
|
414 |
- } |
|
415 |
- else { return 'unknown' } |
|
416 |
- |
|
417 |
- return; |
|
418 |
-} |
|
419 |
- |
|
420 |
-sub fill_from_file_info { |
|
421 |
- my ($self, $user, $project, $diff, $parents) = @_; |
|
422 |
- |
|
423 |
- # Fill file info |
|
424 |
- $diff->{from_file} = []; |
|
425 |
- $diff->{from_file}[$diff->{nparents} - 1] = undef; |
|
426 |
- for (my $i = 0; $i < $diff->{nparents}; $i++) { |
|
427 |
- if ($diff->{status}[$i] eq 'R' || $diff->{status}[$i] eq 'C') { |
|
428 |
- $diff->{from_file}[$i] = |
|
429 |
- $self->path_by_id($user, $project, $parents->[$i], $diff->{from_id}[$i]); |
|
430 |
- } |
|
431 |
- } |
|
432 |
- |
|
433 |
- return $diff; |
|
434 |
-} |
|
435 |
- |
|
436 | 409 |
sub difftree { |
437 | 410 |
my ($self, $user, $project, $cid, $parent, $parents) = @_; |
438 | 411 |
|
... | ... |
@@ -504,6 +477,55 @@ sub difftree { |
504 | 477 |
return $diffs; |
505 | 478 |
} |
506 | 479 |
|
480 |
+sub file_type { |
|
481 |
+ my ($self, $mode) = @_; |
|
482 |
+ |
|
483 |
+ # File type |
|
484 |
+ if ($mode !~ m/^[0-7]+$/) { return $mode } |
|
485 |
+ else { $mode = oct $mode } |
|
486 |
+ if ($self->_s_isgitlink($mode)) { return 'submodule' } |
|
487 |
+ elsif (S_ISDIR($mode & S_IFMT)) { return 'directory' } |
|
488 |
+ elsif (S_ISLNK($mode)) { return 'symlink' } |
|
489 |
+ elsif (S_ISREG($mode)) { return 'file' } |
|
490 |
+ else { return 'unknown' } |
|
491 |
+ |
|
492 |
+ return |
|
493 |
+} |
|
494 |
+ |
|
495 |
+sub file_type_long { |
|
496 |
+ my ($self, $mode) = @_; |
|
497 |
+ |
|
498 |
+ # File type |
|
499 |
+ if ($mode !~ m/^[0-7]+$/) { return $mode } |
|
500 |
+ else { $mode = oct $mode } |
|
501 |
+ if ($self->_s_isgitlink($mode)) { return 'submodule' } |
|
502 |
+ elsif (S_ISDIR($mode & S_IFMT)) { return 'directory' } |
|
503 |
+ elsif (S_ISLNK($mode)) { return 'symlink' } |
|
504 |
+ elsif (S_ISREG($mode)) { |
|
505 |
+ if ($mode & S_IXUSR) { return 'executable file' } |
|
506 |
+ else { return 'file' } |
|
507 |
+ } |
|
508 |
+ else { return 'unknown' } |
|
509 |
+ |
|
510 |
+ return; |
|
511 |
+} |
|
512 |
+ |
|
513 |
+sub fill_from_file_info { |
|
514 |
+ my ($self, $user, $project, $diff, $parents) = @_; |
|
515 |
+ |
|
516 |
+ # Fill file info |
|
517 |
+ $diff->{from_file} = []; |
|
518 |
+ $diff->{from_file}[$diff->{nparents} - 1] = undef; |
|
519 |
+ for (my $i = 0; $i < $diff->{nparents}; $i++) { |
|
520 |
+ if ($diff->{status}[$i] eq 'R' || $diff->{status}[$i] eq 'C') { |
|
521 |
+ $diff->{from_file}[$i] = |
|
522 |
+ $self->path_by_id($user, $project, $parents->[$i], $diff->{from_id}[$i]); |
|
523 |
+ } |
|
524 |
+ } |
|
525 |
+ |
|
526 |
+ return $diff; |
|
527 |
+} |
|
528 |
+ |
|
507 | 529 |
sub branches { |
508 | 530 |
my ($self, $user, $project, $opts) = @_; |
509 | 531 |
|
... | ... |
@@ -68,7 +68,7 @@ |
68 | 68 |
% } |
69 | 69 |
|
70 | 70 |
% if ($errors) { |
71 |
- <div class="alert"> |
|
71 |
+ <div class="alert alert-error"> |
|
72 | 72 |
<button type="button" class="close" data-dismiss="alert">×</button> |
73 | 73 |
% for my $error (@$errors) { |
74 | 74 |
<p><%= $error %></p> |
... | ... |
@@ -7,6 +7,10 @@ |
7 | 7 |
my $errors; |
8 | 8 |
if ($op eq 'delete') { |
9 | 9 |
|
10 |
+ unless ($api->logined) { |
|
11 |
+ return $self->render_exception; |
|
12 |
+ } |
|
13 |
+ |
|
10 | 14 |
# Validation |
11 | 15 |
my $params = $api->params; |
12 | 16 |
my $validator = $self->app->validator; |
... | ... |
@@ -1,8 +0,0 @@ |
1 |
- <% |
|
2 |
- use Encode 'encode'; |
|
3 |
- |
|
4 |
- $self->res->headers->content_type('text/plain;charset=UTF-8'); |
|
5 |
- $self->res->body(encode('UTF-8', 'あ')); |
|
6 |
- $self->rendered; |
|
7 |
- return; |
|
8 |
- %> |
... | ... |
@@ -5,20 +5,86 @@ |
5 | 5 |
# Parameters |
6 | 6 |
my $user = param('user'); |
7 | 7 |
my $project = param('project'); |
8 |
+ my $op = param('op'); |
|
8 | 9 |
|
9 | 10 |
# Git |
10 | 11 |
my $git = $self->app->git; |
11 |
- |
|
12 |
+ |
|
12 | 13 |
# Default branch |
13 | 14 |
my $default_branch = {}; |
14 |
- $default_branch->{name} = app->manager->default_branch($user, $project); |
|
15 |
- $default_branch->{commit} = $git->get_commit($user, $project, $default_branch->{name}); |
|
16 | 15 |
|
17 |
- # No merged branches |
|
18 |
- my $branches = $git->branches($user, $project); |
|
19 |
- my $branches_count = $git->branches_count($user, $project); |
|
20 |
- my $no_merged_branches_count = $git->no_merged_branches_count($user, $project); |
|
21 |
- my $merged_branches_count = $branches_count - $no_merged_branches_count - 1; |
|
16 |
+ # Branch |
|
17 |
+ my $branches; |
|
18 |
+ my $branches_count; |
|
19 |
+ my $no_merged_branches_count; |
|
20 |
+ my $merged_branches_count; |
|
21 |
+ |
|
22 |
+ # Delete |
|
23 |
+ my $errors; |
|
24 |
+ if ($op eq 'delete') { |
|
25 |
+ |
|
26 |
+ # Validation |
|
27 |
+ my $params = $api->params; |
|
28 |
+ my $validator = $self->app->validator; |
|
29 |
+ my $rule = [ |
|
30 |
+ user => [ |
|
31 |
+ ['not_blank' => 'User name is empty.'] |
|
32 |
+ ], |
|
33 |
+ project => [ |
|
34 |
+ ['not_blank' => 'Repository name is empty'] |
|
35 |
+ ], |
|
36 |
+ branch => [ |
|
37 |
+ ['not_blank' => 'Branch name is empty'] |
|
38 |
+ ] |
|
39 |
+ ]; |
|
40 |
+ my $vresult = $validator->validate($params, $rule); |
|
41 |
+ |
|
42 |
+ if ($vresult->is_ok) { |
|
43 |
+ |
|
44 |
+ # Valid parameters |
|
45 |
+ my $params = $vresult->data; |
|
46 |
+ my $user = $params->{user}; |
|
47 |
+ my $project = $params->{project}; |
|
48 |
+ my $branch = $params->{branch}; |
|
49 |
+ |
|
50 |
+ # Delete branch |
|
51 |
+ if ($api->logined($user)) { |
|
52 |
+ |
|
53 |
+ # Delete user |
|
54 |
+ eval { $git->delete_branch($user, $project, $branch) }; |
|
55 |
+ if ($@) { |
|
56 |
+ app->log->error($@); |
|
57 |
+ $errors = ['Internal Error']; |
|
58 |
+ } |
|
59 |
+ else { |
|
60 |
+ $self->flash(branch_deleted => 1); |
|
61 |
+ $self->flash(branch => $branch); |
|
62 |
+ $self->redirect_to; |
|
63 |
+ $self->finish_rendering; |
|
64 |
+ return; |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ # Forbidden |
|
68 |
+ else { |
|
69 |
+ $self->res->code('403'); |
|
70 |
+ $self->finish_rendering; |
|
71 |
+ return; |
|
72 |
+ } |
|
73 |
+ } |
|
74 |
+ else { $errors = $vresult->messages } |
|
75 |
+ } |
|
76 |
+ # List |
|
77 |
+ else { |
|
78 |
+ # Default branch |
|
79 |
+ $default_branch->{name} = app->manager->default_branch($user, $project); |
|
80 |
+ $default_branch->{commit} = $git->get_commit($user, $project, $default_branch->{name}); |
|
81 |
+ |
|
82 |
+ # No merged branches |
|
83 |
+ $branches = $git->branches($user, $project); |
|
84 |
+ $branches_count = $git->branches_count($user, $project); |
|
85 |
+ $no_merged_branches_count = $git->no_merged_branches_count($user, $project); |
|
86 |
+ $merged_branches_count = $branches_count - $no_merged_branches_count - 1; |
|
87 |
+ } |
|
22 | 88 |
%> |
23 | 89 |
|
24 | 90 |
% layout 'common'; |
... | ... |
@@ -45,12 +111,32 @@ |
45 | 111 |
} |
46 | 112 |
display_no_merged = !display_no_merged; |
47 | 113 |
}); |
114 |
+ |
|
115 |
+ // Click delete button |
|
116 |
+ $('.delete-branch').on('click', function () { |
|
117 |
+ if (window.confirm('Are you sure you want to remove this branch?')) { |
|
118 |
+ return true; |
|
119 |
+ } |
|
120 |
+ else { |
|
121 |
+ return false; |
|
122 |
+ } |
|
123 |
+ }); |
|
48 | 124 |
}); |
49 | 125 |
% end |
50 | 126 |
|
51 | 127 |
%= include '/include/header'; |
52 | 128 |
|
53 |
- <div class="container"> |
|
129 |
+ <div class="container" style="padding-bottom:30px"> |
|
130 |
+ |
|
131 |
+ % if ($errors) { |
|
132 |
+ <div class="alert alert-error"> |
|
133 |
+ <button type="button" class="close" data-dismiss="alert">×</button> |
|
134 |
+ % for my $error (@$errors) { |
|
135 |
+ <p><%= $error %></p> |
|
136 |
+ % } |
|
137 |
+ </div> |
|
138 |
+ % } |
|
139 |
+ |
|
54 | 140 |
%= include '/include/project_header'; |
55 | 141 |
%= include '/include/code_menu', display => 'branches'; |
56 | 142 |
|
... | ... |
@@ -113,6 +199,12 @@ |
113 | 199 |
</div> |
114 | 200 |
</div> |
115 | 201 |
<div class="text-right" style="padding-top:5px"> |
202 |
+ % if ($api->logined($user)) { |
|
203 |
+ <form action="<%= url_for->query(op => 'delete') %>" method="post" style="display:inline-block"> |
|
204 |
+ <input type="submit" class="btn delete-branch" style="color:#900;" value="Delete branch"> |
|
205 |
+ %= hidden_field branch => $bname; |
|
206 |
+ </form> |
|
207 |
+ % } |
|
116 | 208 |
<a class="btn" href="<%= url_for("/$user/$project/compare/$default_branch->{name}...$bname") %>"> |
117 | 209 |
Compare |
118 | 210 |
</a> |
... | ... |
@@ -36,12 +36,10 @@ |
36 | 36 |
$content_disposition .= "; filename=$file_name"; |
37 | 37 |
|
38 | 38 |
# Response |
39 |
- $self->res->code(200); |
|
40 | 39 |
$self->res->headers->content_disposition($content_disposition); |
41 | 40 |
$self->res->headers->content_type($type); |
42 |
- $self->res->body($blob_raw); |
|
43 |
- $self->rendered; |
|
44 |
- $self->stash->{'mojo.routed'} = 1; |
|
41 |
+ $self->render(data => $blob_raw); |
|
42 |
+ $self->finish_rendering; |
|
45 | 43 |
|
46 | 44 |
return; |
47 |
-%> |
|
45 |
+%> |