Loading lib/Travelynx.pm +2 −0 Original line number Diff line number Diff line Loading @@ -2548,6 +2548,7 @@ sub startup { $authed_r->get('/fgr')->to('passengerrights#list_candidates'); $authed_r->get('/account/password')->to('account#password_form'); $authed_r->get('/account/mail')->to('account#change_mail'); $authed_r->get('/account/name')->to('account#change_name'); $authed_r->get('/export.json')->to('account#json_export'); $authed_r->get('/history.json')->to('traveling#json_history'); $authed_r->get('/history.csv')->to('traveling#csv_history'); Loading @@ -2572,6 +2573,7 @@ sub startup { ->to('passengerrights#generate'); $authed_r->post('/account/password')->to('account#change_password'); $authed_r->post('/account/mail')->to('account#change_mail'); $authed_r->post('/account/name')->to('account#change_name'); $authed_r->post('/delete')->to('account#delete'); $authed_r->post('/logout')->to('account#do_logout'); $authed_r->post('/set_token')->to('api#set_token'); Loading lib/Travelynx/Controller/Account.pm +87 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,93 @@ sub change_mail { } } sub change_name { my ($self) = @_; my $action = $self->req->param('action'); my $password = $self->req->param('password'); my $old_name = $self->current_user->{name}; my $new_name = $self->req->param('name'); if ( $action and $action eq 'update_name' ) { if ( $self->validation->csrf_protect->has_error('csrf_token') ) { $self->render( 'change_name', invalid => 'csrf', ); return; } if ( not length($new_name) ) { $self->render( 'change_name', invalid => 'user_empty' ); return; } if ( $new_name !~ m{ ^ [0-9a-zA-Z_-]+ $ }x ) { $self->render( 'change_name', invalid => 'user_format' ); return; } if ( not $self->authenticate( $old_name, $self->param('password') ) ) { $self->render( 'change_name', invalid => 'password' ); return; } # This call is technically superfluous. The users table has a unique # constraint on the "name" column, so having two users with the same name # is not possible. However, to minimize the number of failed SQL # queries, we first do a select check here and only attempt an update # if it succeeded. if ( $self->users->check_if_user_name_exists( name => $new_name ) ) { $self->render( 'change_name', invalid => 'user_collision' ); return; } my $success = $self->users->change_name( uid => $self->current_user->{id}, name => $new_name ); if ( not $success ) { $self->render( 'change_name', invalid => 'user_collision' ); return; } $self->flash( success => 'name' ); $self->redirect_to('account'); my $ip = $self->req->headers->header('X-Forwarded-For'); my $ua = $self->req->headers->user_agent; my $date = DateTime->now( time_zone => 'Europe/Berlin' ) ->strftime('%d.%m.%Y %H:%M:%S %z'); # In case Mojolicious is not running behind a reverse proxy $ip //= sprintf( '%s:%s', $self->tx->remote_address, $self->tx->remote_port ); my $confirm_url = $self->url_for('confirm_mail')->to_abs->scheme('https'); my $imprint_url = $self->url_for('impressum')->to_abs->scheme('https'); my $body = "Hallo ${new_name},\n\n"; $body .= "Der Name deines Travelynx-Accounts wurde erfolgreich geändert.\n"; $body .= "Alter Name: ${old_name}\n"; $body .= "Neue Name: ${new_name}\n\n"; $body .= "Daten zur Anfrage:\n"; $body .= " * Datum: ${date}\n"; $body .= " * Client: ${ip}\n"; $body .= " * UserAgent: ${ua}\n\n\n"; $body .= "Impressum: ${imprint_url}\n"; $self->sendmail->custom( $self->current_user->{email}, 'travelynx: Name geändert', $body ); } else { $self->render('change_name'); } } sub password_form { my ($self) = @_; Loading lib/Travelynx/Model/Users.pm +70 −75 Original line number Diff line number Diff line package Travelynx::Model::Users; # Copyright (C) 2020 Daniel Friesel # # SPDX-License-Identifier: AGPL-3.0-or-later Loading Loading @@ -101,11 +102,7 @@ sub set_privacy { my $uid = $opt{uid}; my $public_level = $opt{level}; $db->update( 'users', { public_level => $public_level }, { id => $uid } ); $db->update( 'users', { public_level => $public_level }, { id => $uid } ); } sub mark_for_password_reset { Loading @@ -128,8 +125,7 @@ sub mark_for_password_reset { { user_id => $uid, token => $token, requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) } ); Loading Loading @@ -170,8 +166,7 @@ sub mark_for_mail_change { user_id => $uid, email => $email, token => $token, requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) }, { on_conflict => \ Loading @@ -198,11 +193,7 @@ sub change_mail_with_token { )->hash; if ($res_h) { $db->update( 'users', { email => $res_h->{email} }, { id => $uid } ); $db->update( 'users', { email => $res_h->{email} }, { id => $uid } ); $db->delete( 'pending_mails', { user_id => $uid } ); $tx->commit; return 1; Loading @@ -210,6 +201,20 @@ sub change_mail_with_token { return; } sub change_name { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; eval { $db->update( 'users', { name => $opt{name} }, { id => $uid } ); }; if ($@) { return 0; } return 1; } sub remove_password_token { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; Loading Loading @@ -358,11 +363,7 @@ sub set_password_hash { my $uid = $opt{uid}; my $password = $opt{password_hash}; $db->update( 'users', { password => $password }, { id => $uid } ); $db->update( 'users', { password => $password }, { id => $uid } ); } sub check_if_user_name_exists { Loading @@ -370,11 +371,9 @@ sub check_if_user_name_exists { my $db = $opt{db} // $self->{pg}->db; my $user_name = $opt{name}; my $count = $db->select( 'users', 'count(*) as count', { name => $user_name } )->hash->{count}; my $count = $db->select( 'users', 'count(*) as count', { name => $user_name } ) ->hash->{count}; if ($count) { return 1; Loading Loading @@ -422,15 +421,11 @@ sub use_history { my $value = $opt{set}; if ($value) { $db->update( 'users', { use_history => $value }, { id => $uid } ); $db->update( 'users', { use_history => $value }, { id => $uid } ); } else { return $db->select( 'users', ['use_history'], { id => $uid } )->hash->{use_history}; return $db->select( 'users', ['use_history'], { id => $uid } ) ->hash->{use_history}; } } Loading templates/account.html.ep +5 −2 Original line number Diff line number Diff line Loading @@ -7,7 +7,10 @@ <div class="col s12"> <div class="card success-color"> <div class="card-content white-text"> % if ($success eq 'mail') { % if ($success eq 'name') { <span class="card-title">Name geändert</span> % } % elsif ($success eq 'mail') { <span class="card-title">Mail-Adresse geändert</span> % } % elsif ($success eq 'password') { Loading Loading @@ -41,7 +44,7 @@ <table class="striped"> <tr> <th scope="row">Name</th> <td><%= $acc->{name} %></td> <td><a href="/account/name"><i class="material-icons">edit</i></a><%= $acc->{name} %></td> </tr> <tr> <th scope="row">Mail</th> Loading Loading
lib/Travelynx.pm +2 −0 Original line number Diff line number Diff line Loading @@ -2548,6 +2548,7 @@ sub startup { $authed_r->get('/fgr')->to('passengerrights#list_candidates'); $authed_r->get('/account/password')->to('account#password_form'); $authed_r->get('/account/mail')->to('account#change_mail'); $authed_r->get('/account/name')->to('account#change_name'); $authed_r->get('/export.json')->to('account#json_export'); $authed_r->get('/history.json')->to('traveling#json_history'); $authed_r->get('/history.csv')->to('traveling#csv_history'); Loading @@ -2572,6 +2573,7 @@ sub startup { ->to('passengerrights#generate'); $authed_r->post('/account/password')->to('account#change_password'); $authed_r->post('/account/mail')->to('account#change_mail'); $authed_r->post('/account/name')->to('account#change_name'); $authed_r->post('/delete')->to('account#delete'); $authed_r->post('/logout')->to('account#do_logout'); $authed_r->post('/set_token')->to('api#set_token'); Loading
lib/Travelynx/Controller/Account.pm +87 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,93 @@ sub change_mail { } } sub change_name { my ($self) = @_; my $action = $self->req->param('action'); my $password = $self->req->param('password'); my $old_name = $self->current_user->{name}; my $new_name = $self->req->param('name'); if ( $action and $action eq 'update_name' ) { if ( $self->validation->csrf_protect->has_error('csrf_token') ) { $self->render( 'change_name', invalid => 'csrf', ); return; } if ( not length($new_name) ) { $self->render( 'change_name', invalid => 'user_empty' ); return; } if ( $new_name !~ m{ ^ [0-9a-zA-Z_-]+ $ }x ) { $self->render( 'change_name', invalid => 'user_format' ); return; } if ( not $self->authenticate( $old_name, $self->param('password') ) ) { $self->render( 'change_name', invalid => 'password' ); return; } # This call is technically superfluous. The users table has a unique # constraint on the "name" column, so having two users with the same name # is not possible. However, to minimize the number of failed SQL # queries, we first do a select check here and only attempt an update # if it succeeded. if ( $self->users->check_if_user_name_exists( name => $new_name ) ) { $self->render( 'change_name', invalid => 'user_collision' ); return; } my $success = $self->users->change_name( uid => $self->current_user->{id}, name => $new_name ); if ( not $success ) { $self->render( 'change_name', invalid => 'user_collision' ); return; } $self->flash( success => 'name' ); $self->redirect_to('account'); my $ip = $self->req->headers->header('X-Forwarded-For'); my $ua = $self->req->headers->user_agent; my $date = DateTime->now( time_zone => 'Europe/Berlin' ) ->strftime('%d.%m.%Y %H:%M:%S %z'); # In case Mojolicious is not running behind a reverse proxy $ip //= sprintf( '%s:%s', $self->tx->remote_address, $self->tx->remote_port ); my $confirm_url = $self->url_for('confirm_mail')->to_abs->scheme('https'); my $imprint_url = $self->url_for('impressum')->to_abs->scheme('https'); my $body = "Hallo ${new_name},\n\n"; $body .= "Der Name deines Travelynx-Accounts wurde erfolgreich geändert.\n"; $body .= "Alter Name: ${old_name}\n"; $body .= "Neue Name: ${new_name}\n\n"; $body .= "Daten zur Anfrage:\n"; $body .= " * Datum: ${date}\n"; $body .= " * Client: ${ip}\n"; $body .= " * UserAgent: ${ua}\n\n\n"; $body .= "Impressum: ${imprint_url}\n"; $self->sendmail->custom( $self->current_user->{email}, 'travelynx: Name geändert', $body ); } else { $self->render('change_name'); } } sub password_form { my ($self) = @_; Loading
lib/Travelynx/Model/Users.pm +70 −75 Original line number Diff line number Diff line package Travelynx::Model::Users; # Copyright (C) 2020 Daniel Friesel # # SPDX-License-Identifier: AGPL-3.0-or-later Loading Loading @@ -101,11 +102,7 @@ sub set_privacy { my $uid = $opt{uid}; my $public_level = $opt{level}; $db->update( 'users', { public_level => $public_level }, { id => $uid } ); $db->update( 'users', { public_level => $public_level }, { id => $uid } ); } sub mark_for_password_reset { Loading @@ -128,8 +125,7 @@ sub mark_for_password_reset { { user_id => $uid, token => $token, requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) } ); Loading Loading @@ -170,8 +166,7 @@ sub mark_for_mail_change { user_id => $uid, email => $email, token => $token, requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) requested_at => DateTime->now( time_zone => 'Europe/Berlin' ) }, { on_conflict => \ Loading @@ -198,11 +193,7 @@ sub change_mail_with_token { )->hash; if ($res_h) { $db->update( 'users', { email => $res_h->{email} }, { id => $uid } ); $db->update( 'users', { email => $res_h->{email} }, { id => $uid } ); $db->delete( 'pending_mails', { user_id => $uid } ); $tx->commit; return 1; Loading @@ -210,6 +201,20 @@ sub change_mail_with_token { return; } sub change_name { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; eval { $db->update( 'users', { name => $opt{name} }, { id => $uid } ); }; if ($@) { return 0; } return 1; } sub remove_password_token { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; Loading Loading @@ -358,11 +363,7 @@ sub set_password_hash { my $uid = $opt{uid}; my $password = $opt{password_hash}; $db->update( 'users', { password => $password }, { id => $uid } ); $db->update( 'users', { password => $password }, { id => $uid } ); } sub check_if_user_name_exists { Loading @@ -370,11 +371,9 @@ sub check_if_user_name_exists { my $db = $opt{db} // $self->{pg}->db; my $user_name = $opt{name}; my $count = $db->select( 'users', 'count(*) as count', { name => $user_name } )->hash->{count}; my $count = $db->select( 'users', 'count(*) as count', { name => $user_name } ) ->hash->{count}; if ($count) { return 1; Loading Loading @@ -422,15 +421,11 @@ sub use_history { my $value = $opt{set}; if ($value) { $db->update( 'users', { use_history => $value }, { id => $uid } ); $db->update( 'users', { use_history => $value }, { id => $uid } ); } else { return $db->select( 'users', ['use_history'], { id => $uid } )->hash->{use_history}; return $db->select( 'users', ['use_history'], { id => $uid } ) ->hash->{use_history}; } } Loading
templates/account.html.ep +5 −2 Original line number Diff line number Diff line Loading @@ -7,7 +7,10 @@ <div class="col s12"> <div class="card success-color"> <div class="card-content white-text"> % if ($success eq 'mail') { % if ($success eq 'name') { <span class="card-title">Name geändert</span> % } % elsif ($success eq 'mail') { <span class="card-title">Mail-Adresse geändert</span> % } % elsif ($success eq 'password') { Loading Loading @@ -41,7 +44,7 @@ <table class="striped"> <tr> <th scope="row">Name</th> <td><%= $acc->{name} %></td> <td><a href="/account/name"><i class="material-icons">edit</i></a><%= $acc->{name} %></td> </tr> <tr> <th scope="row">Mail</th> Loading