... | ... |
@@ -146,13 +146,34 @@ EOS |
146 | 146 |
); |
147 | 147 |
}; |
148 | 148 |
} |
149 |
- |
|
149 |
+ |
|
150 |
+ # Routes |
|
151 |
+ my $r = $self->routes; |
|
152 |
+ |
|
150 | 153 |
# Auto route |
151 |
- $self->plugin('AutoRoute'); |
|
154 |
+ { |
|
155 |
+ my $r = $r->under(sub { |
|
156 |
+ my $self = shift; |
|
157 |
+ |
|
158 |
+ my $api = $self->gitprep_api; |
|
159 |
+ |
|
160 |
+ # Admin page authentication |
|
161 |
+ { |
|
162 |
+ my $path = $self->req->url->path->parts->[0] || ''; |
|
163 |
+ |
|
164 |
+ if ($path eq '_admin' && !$api->logined_admin) { |
|
165 |
+ $self->redirect_to('/'); |
|
166 |
+ return; |
|
167 |
+ } |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ return 1; |
|
171 |
+ }); |
|
172 |
+ $self->plugin('AutoRoute', route => $r); |
|
173 |
+ } |
|
152 | 174 |
|
153 | 175 |
# User defined Routes |
154 | 176 |
{ |
155 |
- my $r = $self->routes; |
|
156 | 177 |
|
157 | 178 |
# Reset admin password |
158 | 179 |
$r->any('/reset-password')->name('reset-password') |
... | ... |
@@ -57,6 +57,36 @@ sub root_ns { |
57 | 57 |
return $root; |
58 | 58 |
} |
59 | 59 |
|
60 |
+sub is_admin { |
|
61 |
+ my ($self, $user) = @_; |
|
62 |
+ |
|
63 |
+ # Controler |
|
64 |
+ my $c = $self->cntl; |
|
65 |
+ |
|
66 |
+ # DBI |
|
67 |
+ my $dbi = $c->app->dbi; |
|
68 |
+ |
|
69 |
+ # Check admin |
|
70 |
+ my $row = $dbi->model('user')->select('config', id => $user)->one; |
|
71 |
+ return unless $row; |
|
72 |
+ my $config = $self->json($row->{config}); |
|
73 |
+ |
|
74 |
+ return $config->{admin}; |
|
75 |
+} |
|
76 |
+ |
|
77 |
+sub logined_admin { |
|
78 |
+ my $self = shift; |
|
79 |
+ |
|
80 |
+ # Controler |
|
81 |
+ my $c = $self->cntl; |
|
82 |
+ |
|
83 |
+ # Check logined as admin |
|
84 |
+ my $user = $c->session('user_id'); |
|
85 |
+ |
|
86 |
+ return $self->is_admin($user) && $self->logined; |
|
87 |
+} |
|
88 |
+ |
|
89 |
+ |
|
60 | 90 |
sub json { |
61 | 91 |
my ($self, $value) = @_; |
62 | 92 |
|
... | ... |
@@ -68,21 +98,8 @@ sub json { |
68 | 98 |
} |
69 | 99 |
} |
70 | 100 |
|
71 |
-sub users { |
|
72 |
- my $self = shift; |
|
73 |
- |
|
74 |
- my $users = $self->cntl->app->dbi->model('user')->select( |
|
75 |
- ['id', 'config'], |
|
76 |
- append => 'order by id' |
|
77 |
- )->filter(config => 'json')->all; |
|
78 |
- |
|
79 |
- @$users = grep { ! $_->{config}{admin} } @$users; |
|
80 |
- |
|
81 |
- return $users; |
|
82 |
-} |
|
83 |
- |
|
84 | 101 |
sub logined { |
85 |
- my $self = shift; |
|
102 |
+ my ($self, $user) = @_; |
|
86 | 103 |
|
87 | 104 |
my $c = $self->cntl; |
88 | 105 |
|
... | ... |
@@ -99,6 +116,19 @@ sub logined { |
99 | 116 |
return $password eq $config->{password}; |
100 | 117 |
} |
101 | 118 |
|
119 |
+sub users { |
|
120 |
+ my $self = shift; |
|
121 |
+ |
|
122 |
+ my $users = $self->cntl->app->dbi->model('user')->select( |
|
123 |
+ ['id', 'config'], |
|
124 |
+ append => 'order by id' |
|
125 |
+ )->filter(config => 'json')->all; |
|
126 |
+ |
|
127 |
+ @$users = grep { ! $_->{config}{admin} } @$users; |
|
128 |
+ |
|
129 |
+ return $users; |
|
130 |
+} |
|
131 |
+ |
|
102 | 132 |
sub params { |
103 | 133 |
my $self = shift; |
104 | 134 |
|
... | ... |
@@ -27,6 +27,24 @@ sub create_project { |
27 | 27 |
croak $error if $@; |
28 | 28 |
} |
29 | 29 |
|
30 |
+sub create_user { |
|
31 |
+ my ($self, $user, $data) = @_; |
|
32 |
+ |
|
33 |
+ my $dbi = $self->app->dbi; |
|
34 |
+ |
|
35 |
+ # Create user |
|
36 |
+ my $error; |
|
37 |
+ eval { |
|
38 |
+ $dbi->connector->txn(sub { |
|
39 |
+ eval { $self->_create_db_user($user, $data) }; |
|
40 |
+ croak $error = $@ if $@; |
|
41 |
+ eval {$self->_create_user_dir($user) }; |
|
42 |
+ croak $error = $@ if $@; |
|
43 |
+ }); |
|
44 |
+ }; |
|
45 |
+ croak $error if $@; |
|
46 |
+} |
|
47 |
+ |
|
30 | 48 |
sub delete_project { |
31 | 49 |
my ($self, $user, $project) = @_; |
32 | 50 |
|
... | ... |
@@ -47,22 +65,38 @@ sub delete_project { |
47 | 65 |
return 1; |
48 | 66 |
} |
49 | 67 |
|
50 |
-sub create_user { |
|
51 |
- my ($self, $user, $data) = @_; |
|
52 |
- |
|
68 |
+sub delete_user { |
|
69 |
+ my ($self, $user) = @_; |
|
70 |
+ |
|
53 | 71 |
my $dbi = $self->app->dbi; |
54 | 72 |
|
55 |
- # Create user |
|
73 |
+ # Delete user |
|
56 | 74 |
my $error; |
57 | 75 |
eval { |
58 | 76 |
$dbi->connector->txn(sub { |
59 |
- eval { $self->_create_db_user($user, $data) }; |
|
77 |
+ eval { $self->_delete_db_user($user) }; |
|
60 | 78 |
croak $error = $@ if $@; |
61 |
- eval {$self->_create_user_dir($user) }; |
|
79 |
+ eval {$self->_delete_user_dir($user) }; |
|
62 | 80 |
croak $error = $@ if $@; |
63 | 81 |
}); |
64 | 82 |
}; |
65 | 83 |
croak $error if $@; |
84 |
+ |
|
85 |
+ return 1; |
|
86 |
+} |
|
87 |
+ |
|
88 |
+sub _delete_db_user { |
|
89 |
+ my ($self, $user) = @_; |
|
90 |
+ |
|
91 |
+ $self->app->dbi->model('user')->delete(id => $user); |
|
92 |
+} |
|
93 |
+ |
|
94 |
+sub _delete_user_dir { |
|
95 |
+ my ($self, $user) = @_; |
|
96 |
+ |
|
97 |
+ my $home = $self->app->git->rep_home; |
|
98 |
+ my $user_dir = "$home/$user"; |
|
99 |
+ rmtree $user_dir; |
|
66 | 100 |
} |
67 | 101 |
|
68 | 102 |
sub _create_db_user { |
... | ... |
@@ -6,13 +6,14 @@ |
6 | 6 |
my $errors; |
7 | 7 |
if ($op eq 'create') { |
8 | 8 |
|
9 |
+ # Validation |
|
9 | 10 |
my $params = $api->params; |
10 | 11 |
my $validator = $self->app->validator; |
11 | 12 |
my $rule = [ |
12 | 13 |
id => [ |
13 |
- ['not_blank' => 'Input admin user.'], |
|
14 |
- [{'regex' => qr/^[a-zA-Z0-9_]+$/} => 'Admin User contain invalid character.'], |
|
15 |
- [{'length' => {max => 20}} => 'Admin User is too long.'] |
|
14 |
+ ['not_blank' => 'User name is empty.'], |
|
15 |
+ [{'regex' => qr/^[a-zA-Z0-9_]+$/} => 'User name contain invalid character.'], |
|
16 |
+ [{'length' => {max => 20}} => 'User name is too long.'] |
|
16 | 17 |
], |
17 | 18 |
password => [ |
18 | 19 |
['not_blank' => 'Input password.'], |
... | ... |
@@ -0,0 +1,95 @@ |
1 |
+<% |
|
2 |
+ my $api = gitprep_api; |
|
3 |
+ |
|
4 |
+ my $user = param('user'); |
|
5 |
+ my $op = param('op') || ''; |
|
6 |
+ |
|
7 |
+ my $errors; |
|
8 |
+ if ($op eq 'delete') { |
|
9 |
+ |
|
10 |
+ # Validation |
|
11 |
+ my $params = $api->params; |
|
12 |
+ my $validator = $self->app->validator; |
|
13 |
+ my $rule = [ |
|
14 |
+ user => [ |
|
15 |
+ ['not_blank' => 'User name is empty.'], |
|
16 |
+ [{'regex' => qr/^[a-zA-Z0-9_]+$/} => 'User name contain invalid character.'], |
|
17 |
+ [{'length' => {max => 20}} => 'User name is too long.'] |
|
18 |
+ ] |
|
19 |
+ ]; |
|
20 |
+ my $vresult = $validator->validate($params, $rule); |
|
21 |
+ |
|
22 |
+ if ($vresult->is_ok) { |
|
23 |
+ |
|
24 |
+ # Valid parameters |
|
25 |
+ my $params = $vresult->data; |
|
26 |
+ my $user = $params->{user}; |
|
27 |
+ |
|
28 |
+ # Delete user |
|
29 |
+ eval { app->manager->delete_user($user) }; |
|
30 |
+ if ($@) { |
|
31 |
+ app->log->error($@); |
|
32 |
+ $errors = ['Internal Error']; |
|
33 |
+ } |
|
34 |
+ else { |
|
35 |
+ $self->flash(user_deleted => 1); |
|
36 |
+ $self->flash(user => $user); |
|
37 |
+ $self->redirect_to('/_admin/users'); |
|
38 |
+ } |
|
39 |
+ } |
|
40 |
+ else { $errors = $vresult->messages } |
|
41 |
+ } |
|
42 |
+%> |
|
43 |
+ |
|
44 |
+% layout 'common'; |
|
45 |
+ |
|
46 |
+ %= include '/include/header'; |
|
47 |
+ |
|
48 |
+ <div class="container"> |
|
49 |
+ <div class="alert"> |
|
50 |
+ <button type="button" class="close" data-dismiss="alert">×</button> |
|
51 |
+ <p> |
|
52 |
+ <big> |
|
53 |
+ <big> |
|
54 |
+ If you click delete button, user and all of user's repositories is deleted. |
|
55 |
+ Be careful! |
|
56 |
+ </big> |
|
57 |
+ </big> |
|
58 |
+ </p> |
|
59 |
+ </div> |
|
60 |
+ |
|
61 |
+ % my $id = ''; |
|
62 |
+ % if (flash('success')) { |
|
63 |
+ <div class="alert alert-success"> |
|
64 |
+ <button type="button" class="close" data-dismiss="alert">×</button> |
|
65 |
+ Success: User <b><%= flash('user') %></b> is deleted. |
|
66 |
+ </div> |
|
67 |
+ % } |
|
68 |
+ |
|
69 |
+ % if ($errors) { |
|
70 |
+ <div class="alert"> |
|
71 |
+ <button type="button" class="close" data-dismiss="alert">×</button> |
|
72 |
+ % for my $error (@$errors) { |
|
73 |
+ <p><%= $error %></p> |
|
74 |
+ % } |
|
75 |
+ </div> |
|
76 |
+ % } |
|
77 |
+ |
|
78 |
+ <div class="text-center"><h3>Delete User</h3></div> |
|
79 |
+ <div class="well" style="background-color:white;padding-top:15px;padding-left:60px;width:300px;margin-left:auto;margin-right:auto"> |
|
80 |
+ <form action="<%= url_for->query(op => 'delete') %>" method="post"> |
|
81 |
+ <div class="control-group"> |
|
82 |
+ <label class="control-label" for="user-name">User name</label> |
|
83 |
+ <b><big><big><%= $user %></big></big></b> |
|
84 |
+ </div> |
|
85 |
+ %= hidden_field user => $user; |
|
86 |
+ <div class="control-group"> |
|
87 |
+ <div class="controls"> |
|
88 |
+ <button type="submit" class="btn">Delete user and repositories</button> |
|
89 |
+ </div> |
|
90 |
+ </div> |
|
91 |
+ </form> |
|
92 |
+ </div> |
|
93 |
+ <div class="text-center" style="margin-bottom:20px"><big><a href="/_admin/users">See Users</a></big></div> |
|
94 |
+ </div> |
|
95 |
+ %= include '/include/footer'; |
... | ... |
@@ -8,14 +8,28 @@ |
8 | 8 |
%= include '/include/header'; |
9 | 9 |
|
10 | 10 |
<div class="container"> |
11 |
+ % if (flash('user_deleted')) { |
|
12 |
+ <div class="alert alert-success"> |
|
13 |
+ <button type="button" class="close" data-dismiss="alert">×</button> |
|
14 |
+ Success: User <b><%= flash('user') %></b> is deleted. |
|
15 |
+ </div> |
|
16 |
+ % } |
|
17 |
+ |
|
11 | 18 |
<div><h3>Admin Users</h3></div> |
12 | 19 |
<div style="margin-bottom:10px"><a class="btn" href="/_admin/user/create">Create User</a></div> |
13 | 20 |
<div class="container"> |
14 |
- <ul class="nav nav-tabs nav-stacked"> |
|
15 |
- % for my $user (@$users) { |
|
16 |
- <li><a href="#"><%= $user->{id} %></a></li> |
|
17 |
- % } |
|
18 |
- </ul> |
|
21 |
+ <table class="table"> |
|
22 |
+ % for my $user (@$users) { |
|
23 |
+ <tr> |
|
24 |
+ <td> |
|
25 |
+ <a href="#"><%= $user->{id} %></a> |
|
26 |
+ </td> |
|
27 |
+ <td style="text-align:right"> |
|
28 |
+ <a class="btn btn-mini" href="<%= url_for("/_admin/user/delete?user=$user->{id}") %>">Delete</a> |
|
29 |
+ </td> |
|
30 |
+ </tr> |
|
31 |
+ % } |
|
32 |
+ </table> |
|
19 | 33 |
</div> |
20 | 34 |
</div> |
21 | 35 |
<div class="text-center" style="margin-bottom:20px"><big><a href="/_admin">Admin page</a></big></div> |