Commit 6cee1e20 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

allow users to change their name

parent 08abde26
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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');
@@ -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');
+87 −0
Original line number Diff line number Diff line
@@ -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) = @_;

+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
@@ -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 {
@@ -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' )
		}
	);

@@ -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 => \
@@ -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;
@@ -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;
@@ -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 {
@@ -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;
@@ -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};
	}
}

+5 −2
Original line number Diff line number Diff line
@@ -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') {
@@ -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>