mirror of
https://gitlab.com/depesz/explain.depesz.com.git
synced 2024-11-24 08:42:27 +02:00
Users almost done
Functionality is there, I'm just waiting for Metys to help me with styling
This commit is contained in:
parent
9ba0cc07cc
commit
b381985e43
@ -4,11 +4,13 @@
|
||||
"secret" : "|Erp--Wjgb)+eiB/|H=|V7!#+M|L{a8=J2|pd+N1=M|&pJWq|M&,f3q^XS",
|
||||
|
||||
"database" : {
|
||||
"dsn" : "dbi:Pg:database=depesz_explain;host=127.0.0.1;port=5900",
|
||||
"dsn" : "dbi:Pg:database=depesz_explain;host=127.0.0.1;port=5930",
|
||||
"username" : "depesz_explain",
|
||||
"options" : {
|
||||
"auto_commit" : 1,
|
||||
"pg_server_prepare" : 0
|
||||
"pg_server_prepare" : 0,
|
||||
"RaiseError" : 1,
|
||||
"PrintError" : 0
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -32,6 +32,12 @@ sub startup {
|
||||
# route: 'index'
|
||||
$routes->route( '/' )->to( 'controller#index' )->name( 'new-explain' );
|
||||
|
||||
# route: 'user-history'
|
||||
$routes->route( '/user-history/:direction/:key' )->to( 'controller#user_history', direction => undef, key => undef )->name( 'user-history' );
|
||||
|
||||
# route: 'plan-change'
|
||||
$routes->route( '/plan-change/:id' )->to( 'controller#plan_change' )->name( 'plan-change' );
|
||||
|
||||
# route: 'login'
|
||||
$routes->route( '/login' )->to( 'controller#login' )->name( 'login' );
|
||||
|
||||
|
@ -14,6 +14,24 @@ sub logout {
|
||||
$self->redirect_to( 'new-explain' );
|
||||
}
|
||||
|
||||
sub user_history {
|
||||
my $self = shift;
|
||||
$self->redirect_to( 'history' ) unless $self->session->{'user'};
|
||||
|
||||
my @args = ( $self->session->{'user'} );
|
||||
if (
|
||||
( $self->param('direction') ) &&
|
||||
( $self->param('direction') =~ m{\A(?:before|after)\z} ) &&
|
||||
( $self->param('key') )
|
||||
) {
|
||||
push @args, $self->param('direction') eq 'before' ? 'DESC' : 'ASC';
|
||||
push @args, $self->param('key');
|
||||
}
|
||||
my $data = $self->database->get_user_history( @args );
|
||||
$self->stash->{'plans'} = $data;
|
||||
return $self->render();
|
||||
}
|
||||
|
||||
sub user {
|
||||
my $self = shift;
|
||||
|
||||
@ -39,6 +57,64 @@ sub user {
|
||||
$self->stash->{'message'} = 'Changing the password failed.';
|
||||
}
|
||||
|
||||
sub plan_change {
|
||||
my $self = shift;
|
||||
unless ( $self->session->{'user'} ) {
|
||||
$self->app->log->error( 'User tried to access plan change without being logged!' );
|
||||
$self->redirect_to( 'new-explain' );
|
||||
}
|
||||
$self->redirect_to( 'new-explain' ) unless $self->req->param('return');
|
||||
|
||||
my $plan = $self->database->get_plan_data( $self->param('id') );
|
||||
if (
|
||||
( ! defined $plan->{'added_by'} ) ||
|
||||
( $plan->{'added_by'} ne $self->session->{'user'} )
|
||||
) {
|
||||
$self->app->log->error( 'User tried to access plan change for plan [' . $plan->{'id'} . '] of another user: ' . $self->session->{'user'});
|
||||
$self->redirect_to( 'logout' );
|
||||
}
|
||||
|
||||
# All looks fine. Current plan data are in $plan.
|
||||
if (
|
||||
( $self->req->param('delete') ) &&
|
||||
( $self->req->param('delete') eq 'yes' )
|
||||
) {
|
||||
$self->database->delete_plan( $plan->{'id'}, $plan->{'delete_key'} );
|
||||
return $self->redirect_to( $self->req->param('return') );
|
||||
}
|
||||
|
||||
my %changes = ();
|
||||
if ( $plan->{'title'} ne ( $self->req->param('title') // '' ) ) {
|
||||
$changes{'title'} = ( $self->req->param('title') // '' );
|
||||
}
|
||||
if (
|
||||
( $plan->{'is_public'} ) &&
|
||||
( ! $self->req->param('is_public') )
|
||||
) {
|
||||
$changes{ 'is_public' } = 0;
|
||||
} elsif (
|
||||
( $plan->{'is_public'} ) &&
|
||||
( ! $self->req->param('is_public') )
|
||||
) {
|
||||
$changes{ 'is_public' } = 1;
|
||||
}
|
||||
|
||||
if (
|
||||
( ! $plan->{'is_anonymized'}) &&
|
||||
( $self->req->param('is_anonymized') )
|
||||
) {
|
||||
my $explain = Pg::Explain->new( source => $plan->{'plan'} );
|
||||
$explain->anonymize();
|
||||
$changes{'plan'} = $explain->as_text();
|
||||
$changes{ 'is_anonymized' } = 1;
|
||||
}
|
||||
return $self->redirect_to( $self->req->param('return') ) if 0 == scalar keys %changes;
|
||||
|
||||
$self->database->update_plan( $plan->{'id'}, \%changes );
|
||||
|
||||
return $self->redirect_to( $self->req->param('return') );
|
||||
}
|
||||
|
||||
sub login {
|
||||
my $self = shift;
|
||||
|
||||
|
@ -109,6 +109,68 @@ sub user_change_password {
|
||||
return;
|
||||
}
|
||||
|
||||
sub get_user_history {
|
||||
my $self = shift;
|
||||
my ( $user, $direction, $marker ) = @_;
|
||||
|
||||
my $limit = 100;
|
||||
|
||||
$direction = 'DESC' if ( $direction // '' ) ne 'ASC';
|
||||
my $query = '';
|
||||
my @args = ();
|
||||
|
||||
if ( defined $marker ) {
|
||||
my $comparison = $direction eq 'DESC' ? '<' : '>';
|
||||
$query = "
|
||||
SELECT p.id, p.entered_on::date, p.is_public, p.is_anonymized, p.title
|
||||
FROM plans p
|
||||
WHERE p.added_by = ? and not p.is_deleted
|
||||
AND ( p.entered_on, p.id ) $comparison (
|
||||
select x.entered_on, x.id
|
||||
from plans x
|
||||
where x.id = ?
|
||||
)
|
||||
ORDER BY p.entered_on $direction, p.id $direction LIMIT $limit
|
||||
";
|
||||
@args = ( $user, $marker );
|
||||
|
||||
} else {
|
||||
$query = "
|
||||
SELECT p.id, p.entered_on::date, p.is_public, p.is_anonymized, p.title
|
||||
FROM plans p
|
||||
WHERE p.added_by = ? and not p.is_deleted
|
||||
ORDER BY p.entered_on DESC, p.id DESC LIMIT $limit
|
||||
";
|
||||
@args = ( $user );
|
||||
}
|
||||
my $plans = $self->dbh->selectall_arrayref( $query, { Slice => {} }, @args );
|
||||
|
||||
# newest plans always first
|
||||
$plans = [ reverse @{ $plans } ] if $direction eq 'ASC';
|
||||
|
||||
return {
|
||||
'list' => [],
|
||||
'earlier' => 0,
|
||||
'later' => 0,
|
||||
} if 0 == scalar @{ $plans };
|
||||
|
||||
my @later = $self->dbh->selectrow_array(
|
||||
'SELECT p.id FROM plans p where p.added_by = ? and not is_deleted and ( p.entered_on, p.id ) > ( select x.entered_on, x.id from plans x where x.id = ? ) limit 1',
|
||||
undef,
|
||||
$user, $plans->[0]->{'id'},
|
||||
);
|
||||
my @earlier = $self->dbh->selectrow_array(
|
||||
'SELECT p.id FROM plans p where p.added_by = ? and not is_deleted and ( p.entered_on, p.id ) < ( select x.entered_on, x.id from plans x where x.id = ? ) limit 1',
|
||||
undef,
|
||||
$user, $plans->[-1]->{'id'},
|
||||
);
|
||||
return {
|
||||
'list' => $plans,
|
||||
'later' => scalar @later,
|
||||
'earlier' => scalar @earlier,
|
||||
};
|
||||
}
|
||||
|
||||
sub get_pw_salt {
|
||||
my $self = shift;
|
||||
my @salt_chars = ( 'a'..'z', 'A'..'Z', 0..9, '.', '/' );
|
||||
@ -130,6 +192,24 @@ sub user_register {
|
||||
return;
|
||||
}
|
||||
|
||||
sub update_plan {
|
||||
my $self = shift;
|
||||
my ($id, $changes) = @_;
|
||||
my @columns = keys %{ $changes };
|
||||
my @values = values %{ $changes };
|
||||
|
||||
eval {
|
||||
$self->dbh->do(
|
||||
'UPDATE plans SET ' . join(', ', map { "$_ = ?" } @columns) . ' WHERE id = ?',
|
||||
undef,
|
||||
@values, $id
|
||||
);
|
||||
};
|
||||
return 1 unless $EVAL_ERROR;
|
||||
$self->log->error( "update_plan( $id ) => " . $EVAL_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
sub save_with_random_name {
|
||||
my $self = shift;
|
||||
my ( $title, $content, $is_public, $is_anon, $username ) = @_;
|
||||
@ -144,6 +224,20 @@ sub save_with_random_name {
|
||||
return @row;
|
||||
}
|
||||
|
||||
sub get_plan_data {
|
||||
my $self = shift;
|
||||
my ( $plan_id ) = @_;
|
||||
|
||||
my $rows = $self->dbh->selectall_arrayref(
|
||||
'SELECT * FROM plans WHERE id = ? AND NOT is_deleted',
|
||||
{ Slice => {} },
|
||||
$plan_id,
|
||||
);
|
||||
return unless defined $rows;
|
||||
return if 0 == scalar @{ $rows };
|
||||
return $rows->[0];
|
||||
}
|
||||
|
||||
sub get_plan {
|
||||
my $self = shift;
|
||||
my ( $plan_id ) = @_;
|
||||
|
@ -6,6 +6,8 @@ CREATE TABLE users (
|
||||
|
||||
ALTER TABLE plans add column added_by TEXT references users ( username );
|
||||
|
||||
create unique index concurrently plan_paging on plans (added_by, entered_on, id) where is_deleted = false;
|
||||
|
||||
DROP FUNCTION register_plan(in_title text, in_plan text, in_is_public boolean, in_is_anonymized boolean);
|
||||
CREATE FUNCTION register_plan(in_title text, in_plan text, in_is_public boolean, in_is_anonymized boolean, in_username text) RETURNS register_plan_return
|
||||
LANGUAGE plpgsql
|
||||
|
64
templates/controller/user_history.html.ep
Normal file
64
templates/controller/user_history.html.ep
Normal file
@ -0,0 +1,64 @@
|
||||
% layout 'default';
|
||||
|
||||
% my $title = 'User (' . session('user') . ') history';
|
||||
% title $title;
|
||||
|
||||
<h1><%= $title %></h1>
|
||||
|
||||
% if ( scalar @{ $plans->{'list'} } ) {
|
||||
% my $date = '';
|
||||
<table border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>title</th>
|
||||
<th>public</th>
|
||||
<th>anonymized</th>
|
||||
<th>delete</th>
|
||||
<th>action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
% for my $plan ( @{ $plans->{'list'}} ) {
|
||||
|
||||
% if ($plan->{'entered_on'} ne $date) {
|
||||
<tr>
|
||||
<th colspan="6"><%= $plan->{'entered_on'} %></th>
|
||||
</tr>
|
||||
% $date = $plan->{'entered_on'};
|
||||
% }
|
||||
|
||||
<form id="plan-change" method="post" action="<%= url_for 'plan-change', 'id' => $plan->{'id'} %>">
|
||||
<input type="hidden" name="return" value="<%= url_for 'current' %>"/>
|
||||
<tr>
|
||||
<td><a href="<%= url_for( 'show', id => $plan->{ id } ) %>"><%= $plan->{'id'} %></a></td>
|
||||
<td><input type="text" name="title" value="<%= $plan->{'title'} %>"/></td>
|
||||
<td><input type="checkbox" name="is_public" value="1" <% if ($plan->{'is_public'}) { %>checked="1"<% } %>></td>
|
||||
<td>
|
||||
% if ( $plan->{'is_anonymized'} ) {
|
||||
YES
|
||||
% } else {
|
||||
<input type="checkbox" name="is_anonymized" value="1"/>
|
||||
% }
|
||||
</td>
|
||||
<td><input type="text" name="delete" size="5"/></td>
|
||||
<td><button name="submit" type="submit" value="change">Change!</button></td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
% }
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
% }
|
||||
|
||||
|
||||
<div class="paginator">
|
||||
% if ( $plans->{ later } ) {
|
||||
<a class="newer" href="<%= url_for 'current', direction => 'after', 'key' => $plans->{'list'}->[0]->{'id'} %>" title="newer" rel="next">newer</a>
|
||||
% }
|
||||
% if ( $plans->{ earlier } ) {
|
||||
<a class="older" href="<%= url_for 'current', direction => 'before', 'key' => $plans->{'list'}->[-1]->{'id'} %>" title="older" rel="prev">older</a>
|
||||
% }
|
||||
</div>
|
@ -78,22 +78,30 @@
|
||||
% }
|
||||
</ul>
|
||||
<ul class="right">
|
||||
<li>
|
||||
% if ( session('user') ) {
|
||||
<li>
|
||||
% if ( $self->match->endpoint->name eq "user" ) {
|
||||
<span>user: <%= session('user') %></span>
|
||||
% } else {
|
||||
<a href="<%= url_for 'user' %>" title="link to: user page" rel="permalink">user: <%= session('user') %></a>
|
||||
% }
|
||||
</li>
|
||||
<li>
|
||||
% if ( $self->match->endpoint->name eq "user-history" ) {
|
||||
<span>plans</span>
|
||||
% } else {
|
||||
<a href="<%= url_for 'user-history' %>" title="link to: user plans" rel="permalink">plans</a>
|
||||
% }
|
||||
</li>
|
||||
% } else {
|
||||
<li>
|
||||
% if ( $self->match->endpoint->name eq "login" ) {
|
||||
<span>login</span>
|
||||
% } else {
|
||||
<a href="<%= url_for 'login' %>" title="link to: login/register" rel="permalink">login</a>
|
||||
% }
|
||||
</li>
|
||||
% }
|
||||
<li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user