Fix#10 - Add name, surname and username editing
This commit is contained in:
Jan Jon 2018-07-22 21:03:07 +02:00 committed by Vojtěch Sajdl
parent 3d8329137b
commit 9e472db6f9
3 changed files with 378 additions and 206 deletions

View File

@ -16,9 +16,19 @@ if (isset($_POST['password']))
$displayed_user->change_password(); $displayed_user->change_password();
} }
if (isset($_POST['username']))
{
$displayed_user->change_username();
}
if (isset($_POST['name']))
{
$displayed_user->change_name();
}
if (isset($_POST['email'])) if (isset($_POST['email']))
{ {
$displayed_user->email_link(); $success = $displayed_user->email_link();
} }
if (isset($_POST['permission'])) if (isset($_POST['permission']))
@ -36,10 +46,19 @@ Template::render_header(_("User"), true);
?> ?>
<div class="text-center"> <div class="text-center">
<h1><?php echo _("User settings");?></h1> <h1><?php
if ($_SESSION['user'] == $_GET['id'])
{
echo _("User settings");
}else{
echo _("User");
} ?></h1>
</div> </div>
<?php if (isset($message)){?> <?php if (isset($message)){?>
<p class="alert alert-danger"><?php echo $message?></p> <p class="alert alert-danger"><?php echo $message?></p>
<?php } <?php }
if (isset($success)){?>
<p class="alert alert-success"><?php echo $success?></p>
<?php }
$displayed_user->render_user_settings(); $displayed_user->render_user_settings();

View File

@ -127,72 +127,72 @@ class User
$messages[] = _("Rank"); $messages[] = _("Rank");
} }
if (!isset($messages)){ if (isset($messages)){
$name = $_POST['name'];
$surname = $_POST['surname'];
$username = $_POST['username'];
$email = $_POST['email'];
$pass = $_POST['password'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
{
$message = "Invalid email!";
return;
}
$variables = array();
if (strlen($name)>50){
$variables[] = 'name: 50';
}
if (strlen($surname)>50){
$variables[] = 'surname: 50';
}
if (strlen($username)>50){
$variables[] = 'username: 50';
}
if (strlen($email)>60){
$variables[] = 'email: 60';
}
if (!empty($variables))
{
$message = _("Please mind the following character limits: ");
$message .= implode(", ", $variables);
return;
}
$salt = uniqid(mt_rand(), true);
$hash = hash('sha256', $pass.$salt);
$permission = $_POST['permission'];
$stmt = $mysqli->prepare("INSERT INTO users values (NULL, ?, ?, ?, ?, ?, ?, ?, 1)");
$stmt->bind_param("ssssssi", $email, $username, $name, $surname, $hash, $salt, $permission);
$stmt->execute();
if ($stmt->affected_rows>0)
{
$to = $email;
$subject = _('User account created').' - '.NAME;
$msg = sprintf(_("Hi %s!<br>"."Your account has been created. You can login with your email address at <a href=\"%s\">%s</a> with password %s - please change it as soon as possible."), $name." ".$surname,WEB_URL."/admin", WEB_URL."/admin", $pass);
$headers = "Content-Type: text/html; charset=utf-8 ".PHP_EOL;
$headers .= "MIME-Version: 1.0 ".PHP_EOL;
$headers .= "From: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL;
$headers .= "Reply-To: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL;
mail($to, $subject, $msg, $headers);
if (!INSTALL_OVERRIDE)
{
header("Location: ".WEB_URL."/admin/?do=settings");
}
}
else{
$message = _("Username or email already used");
}
}
else{
$message = "Please enter ".implode(", ", $messages); $message = "Please enter ".implode(", ", $messages);
return;
}
$name = $_POST['name'];
$surname = $_POST['surname'];
$username = $_POST['username'];
$email = $_POST['email'];
$pass = $_POST['password'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
{
$message = "Invalid email!";
return;
}
$variables = array();
if (strlen($name)>50){
$variables[] = 'name: 50';
}
if (strlen($surname)>50){
$variables[] = 'surname: 50';
}
if (strlen($username)>50){
$variables[] = 'username: 50';
}
if (strlen($email)>60){
$variables[] = 'email: 60';
}
if (!empty($variables))
{
$message = _("Please mind the following character limits: ");
$message .= implode(", ", $variables);
return;
}
$salt = uniqid(mt_rand(), true);
$hash = hash('sha256', $pass.$salt);
$permission = $_POST['permission'];
$stmt = $mysqli->prepare("INSERT INTO users values (NULL, ?, ?, ?, ?, ?, ?, ?, 1)");
$stmt->bind_param("ssssssi", $email, $username, $name, $surname, $hash, $salt, $permission);
$stmt->execute();
if ($stmt->affected_rows==0)
{
$message = _("Username or email already used");
return;
}
$to = $email;
$subject = _('User account created').' - '.NAME;
$msg = sprintf(_("Hi %s!<br>"."Your account has been created. You can login with your email address at <a href=\"%s\">%s</a> with password %s - please change it as soon as possible."), $name." ".$surname,WEB_URL."/admin", WEB_URL."/admin", $pass);
$headers = "Content-Type: text/html; charset=utf-8 ".PHP_EOL;
$headers .= "MIME-Version: 1.0 ".PHP_EOL;
$headers .= "From: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL;
$headers .= "Reply-To: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL;
mail($to, $subject, $msg, $headers);
if (!INSTALL_OVERRIDE)
{
header("Location: ".WEB_URL."/admin/?do=settings");
} }
} }
else { else {
@ -210,55 +210,63 @@ class User
public static function login() public static function login()
{ {
global $message, $mysqli; global $message, $mysqli;
if (isset($_POST['email'])) if (!isset($_POST['email']) && !isset($_POST['email']))
{ {
$email = $_POST['email']; return;
$pass = $_POST['pass'];
$stmt = $mysqli->prepare("SELECT id,password_salt as salt,active FROM users WHERE email=?");
$stmt->bind_param("s", $email);
$stmt->execute();
$query = $stmt->get_result();
if ($query->num_rows)
{
$result = $query->fetch_assoc();
$salt = $result["salt"];
$id = $result["id"];
$active = $result["active"];
if (!$active)
{
$message = _("Your account has been disabled. Please contact administrator.");
}
else
{
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash=?");
$stmt->bind_param("is", $id, $hash);
$stmt->execute();
$query = $stmt->get_result();
if (!$query->fetch_assoc()['count'])
{
$message = _("Wrong email or password");
}else
{
if (isset($_POST['remember'])&&$_POST['remember'])
{
$year = strtotime('+356 days', time());
$token = Token::add($id, 'remember', $year);
setcookie('token', $token, $year, "/");
setcookie('user', $id, $year, "/");
}
$_SESSION['user'] = $id;
header("Location: ".WEB_URL."/admin");
}
}
}
else{
$message = _("Wrong email or password");
}
} }
if ((!isset($_POST['email']) || !isset($_POST['email'])))
{
$message = _("Please fill in your email and password!");
return;
}
$email = $_POST['email'];
$pass = $_POST['pass'];
$stmt = $mysqli->prepare("SELECT id,password_salt as salt,active FROM users WHERE email=?");
$stmt->bind_param("s", $email);
$stmt->execute();
$query = $stmt->get_result();
if ($query->num_rows<1)
{
$message = _("Wrong email or password");
return;
}
$result = $query->fetch_assoc();
$salt = $result["salt"];
$id = $result["id"];
$active = $result["active"];
if (!$active)
{
$message = _("Your account has been disabled. Please contact administrator.");
return;
}
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash=?");
$stmt->bind_param("is", $id, $hash);
$stmt->execute();
$query = $stmt->get_result();
if (!$query->fetch_assoc()['count'])
{
$message = _("Wrong email or password");
return;
}
if (isset($_POST['remember'])&&$_POST['remember'])
{
$year = strtotime('+356 days', time());
$token = Token::add($id, 'remember', $year);
setcookie('token', $token, $year, "/");
setcookie('user', $id, $year, "/");
}
$_SESSION['user'] = $id;
header("Location: ".WEB_URL."/admin");
} }
/** /**
@ -301,29 +309,70 @@ class User
{ {
global $permissions, $user; global $permissions, $user;
?> ?>
<div class="row"> <div class="row user">
<div class="col-md-2 col-md-offset-2"><img src="https://www.gravatar.com/avatar/<?php echo md5( strtolower( trim( $this->email ) ) );?>" alt="<?php echo _("Profile picture");?>"></div> <div class="col-md-2 col-md-offset-2"><img src="https://www.gravatar.com/avatar/<?php echo md5( strtolower( trim( $this->email ) ) );?>?s=160"
<div class="col-md-6"><h3><?php echo $this->name." ".$this->surname;?></h3></div> alt="<?php echo _("Profile picture");?>"></div>
</div> <div class="col-md-6">
<div class="row"> <?php if($this->id==$_SESSION['user']||$user->get_rank()<1){
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("ID");?></strong></div> ?>
<div class="col-md-6"><?php echo $this->id; ?></div> <form action="<?php echo WEB_URL;?>/admin/?do=user&amp;id=<?php echo $this->id; ?>" method="POST">
</div> <div class="input-group">
<div class="row"> <div class="col-md-12">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Username");?></strong></div> <div class="row">
<div class="col-md-6"><?php echo $this->username." "; if ($this->id!=$_SESSION['user'] && $user->get_rank()<=1 && ($user->get_rank()<$this->rank)) <label class="form-name" for="name"><?php echo _("Name"); ?></label>
{ <label class="form-name" for="surname"><?php echo _("Surname"); ?></label>
echo "<a href='".WEB_URL."/admin/?do=user&id=".$this->id."&what=toggle'>"; </div>
echo "<i class='fa fa-".($this->active?"check success":"times danger")."'></i></a>"; <div class="row">
}else{ <input type="text" name="name" placeholder="<?php echo _("Name"); ?>"
echo "<i class='fa fa-".($this->active?"check success":"times danger")."'></i>"; title="<?php echo _("Name"); ?>" class="form-control form-name"
}?></div> value=<?php echo htmlspecialchars($this->name, ENT_QUOTES);?>>
<input type="text" name="surname" placeholder="<?php echo _("Surname"); ?>"
title="<?php echo _("Surname"); ?>" class="form-control form-name"
value=<?php echo htmlspecialchars($this->surname, ENT_QUOTES);?>>
</div>
</div>
</div>
<div class="input-group">
<button type="submit" class="btn btn-primary pull-right"><?php echo _("Change name");?></button>
</div>
</form>
<?php
}else{
?>
<h3><?php echo $this->name." ".$this->surname;?></h3>
<?php
}?>
</div>
</div> </div>
<form action="<?php echo WEB_URL;?>/admin/?do=user&amp;id=<?php echo $this->id; ?>" method="POST">
<div class="row user">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Username");?></strong></div>
<div class="col-md-6">
<?php
if ($this->id==$_SESSION['user'] || $user->get_rank()<1){?>
<div class="input-group">
<input type="text" class="form-control" name="username" required value="<?php echo htmlspecialchars($this->username, ENT_QUOTES);?>">
<span class="input-group-btn">
<button type="submit" class="btn btn-primary pull-right"><?php echo _("Change username");?></button>
</span>
</div>
<?php
}else{?><?php echo $this->username." ";
if ($user->get_rank()>=1){
echo "<i class='fa fa-".($this->active?"check success":"times danger")."'></i>";
}
}
?>
</div>
</div>
</form>
<form action="<?php echo WEB_URL;?>/admin/?do=user&id=<?php echo $this->id; ?>" method="POST"> <form action="<?php echo WEB_URL;?>/admin/?do=user&id=<?php echo $this->id; ?>" method="POST">
<div class="row"> <div class="row user">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Role");?></strong></div> <div class="col-md-2 col-md-offset-2"><strong><?php echo _("Role");?></strong></div>
<div class="col-md-6"><?php if ($user->get_rank() == 0 && $this->id != $_SESSION['user']){?> <div class="input-group"><select class="form-control" name="permission"><?php foreach ($permissions as $key => $value) { <div class="col-md-6"><?php if ($user->get_rank() == 0 && $this->id != $_SESSION['user']){?>
<div class="input-group"><select class="form-control" name="permission">
<?php foreach ($permissions as $key => $value) {
echo "<option value='$key' ".($key==$this->rank?"selected":"").">$value</option>"; echo "<option value='$key' ".($key==$this->rank?"selected":"").">$value</option>";
} ?> } ?>
</select><span class="input-group-btn"> </select><span class="input-group-btn">
@ -333,10 +382,10 @@ class User
</div> </div>
</form> </form>
<?php if($this->id==$_SESSION['user']) <?php if($this->id==$_SESSION['user']||$user->get_rank()<1)
{?> {?>
<form action="<?php echo WEB_URL;?>/admin/?do=user" method="POST"> <form action="<?php echo WEB_URL;?>/admin/?do=user&amp;id=<?php echo $this->id; ?>" method="POST">
<div class="row"> <div class="row user">
<div class="col-md-2 col-md-offset-2"><strong>Email</strong></div> <div class="col-md-2 col-md-offset-2"><strong>Email</strong></div>
<div class="col-md-6"> <div class="col-md-6">
<div class="input-group"> <div class="input-group">
@ -348,6 +397,21 @@ class User
</div> </div>
</div> </div>
</form> </form>
<?php }else
{
?>
<div class="row user">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Email");?></strong></div>
<div class="col-md-6">
<a href="mailto:<?php echo $this->email; ?>"><?php echo $this->email; ?></a>
</div>
</div>
<?php
}
if($this->id==$_SESSION['user']){
?>
<form action="<?php echo WEB_URL;?>/admin/?do=user" method="POST"> <form action="<?php echo WEB_URL;?>/admin/?do=user" method="POST">
<div class="row"> <div class="row">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Password");?></strong></div> <div class="col-md-2 col-md-offset-2"><strong><?php echo _("Password");?></strong></div>
@ -364,17 +428,7 @@ class User
</form> </form>
<?php <?php
} }
else
{
?>
<div class="row">
<div class="col-md-2 col-md-offset-2"><strong><?php echo _("Email");?></strong></div>
<div class="col-md-6">
<a href="mailto:<?php echo $this->email; ?>"><?php echo $this->email; ?></a>
</div>
</div>
<?php
}
if ($this->id!=$_SESSION['user'] && $user->get_rank()<=1 && ($user->get_rank()<$this->rank)) if ($this->id!=$_SESSION['user'] && $user->get_rank()<=1 && ($user->get_rank()<$this->rank))
{?> {?>
<div class="row"> <div class="row">
@ -392,6 +446,71 @@ class User
<?php } <?php }
} }
/**
* Changes username of user by POST[ID].
* @return void
*/
public function change_username()
{
global $mysqli, $message, $user;
$id = $this->id;
$stmt = $mysqli->prepare("SELECT count(*) FROM users WHERE username LIKE ?");
$stmt->bind_param("s",$_POST["username"]);
$stmt->execute();
if ($stmt->num_rows > 0)
{
$message = _("This username is already taken.");
return;
}
$stmt->close();
if ($_SESSION['user'] != $id && $user->get_rank()>0)
{
$message = _("Cannot change username of other users!");
}else{
$stmt = $mysqli->prepare("UPDATE users SET username = ? WHERE id=?");
$stmt->bind_param("si",$_POST["username"],$id);
$stmt->execute();
$stmt->close();
header("Location: /admin/?do=user&id=".$id);
}
}
/**
* Changes name and surname of user by POST[ID].
* @return void
*/
public function change_name()
{
global $mysqli, $message, $user;
if (strlen(trim($_POST['name']))==0) {
$messages[] = _("Name");
}
if(strlen(trim($_POST['surname']))==0) {
$messages[] = _("Surname");
}
if (!empty($messages))
{
$message = "Please enter ".implode(", ", $messages);
return;
}
$id = $this->id;
if ($_SESSION['user'] != $id && $user->get_rank()>0)
{
$message = _("Cannot change names of other users!");
}else{
$stmt = $mysqli->prepare("UPDATE users SET `name` = ?, `surname` = ? WHERE id=?");
$stmt->bind_param("ssi",$_POST["name"],$_POST["surname"],$id);
$stmt->execute();
$stmt->close();
header("Location: /admin/?do=user&id=".$id);
}
}
/** /**
* Changes user password and deletes all remember tokens so all other sessions * Changes user password and deletes all remember tokens so all other sessions
* won't stay logged in without knowing new pass. Uses token when reseting password. * won't stay logged in without knowing new pass. Uses token when reseting password.
@ -405,72 +524,77 @@ class User
if ($_POST['password']!=$_POST['password_repeat']) if ($_POST['password']!=$_POST['password_repeat'])
{ {
$message = _("Passwords do not match!"); $message = _("Passwords do not match!");
}else{ return;
if (!$token) }
if (!$token)
{
if ($_SESSION['user']!=$id)
{ {
if ($_SESSION['user']!=$id) $message = _("Cannot change password of other users!");
{
$message = _("Cannot change password of other users!");
}else{
$stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?");
$stmt->bind_param("i", $id);
$stmt->execute();
$query = $stmt->get_result();
$result = $query->fetch_assoc();
$salt = $result['salt'];
$pass = $_POST['old_password'];
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash = ?");
$stmt->bind_param("is", $id, $hash);
$stmt->execute();
if ($stmt->get_result()->fetch_assoc()['count'])
{
$pass = $_POST['password'];
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?");
$stmt->bind_param("si", $hash, $id);
$stmt->execute();
$stmt->close();
$stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'");
$stmt->bind_param("d", $id);
$stmt->execute();
$stmt->get_result();
User::logout();
}
else{
$message = _("Wrong password!");
}
}
}else{ }else{
if (Token::validate($token, $id, "passwd")) $stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?");
$stmt->bind_param("i", $id);
$stmt->execute();
$query = $stmt->get_result();
$result = $query->fetch_assoc();
$salt = $result['salt'];
$pass = $_POST['old_password'];
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash = ?");
$stmt->bind_param("is", $id, $hash);
$stmt->execute();
if ($stmt->get_result()->fetch_assoc()['count'])
{ {
$stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?");
$stmt->bind_param("i", $id);
$stmt->execute();
$query = $stmt->get_result();
$result = $query->fetch_assoc();
$salt = $result['salt'];
$pass = $_POST['password']; $pass = $_POST['password'];
$hash = hash('sha256', $pass.$salt); $hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?"); $stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?");
$stmt->bind_param("si", $hash,$id); $stmt->bind_param("si", $hash, $id);
$stmt->execute(); $stmt->execute();
$stmt->close(); $stmt->close();
$stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'");
$stmt->bind_param("d", $id);
$stmt->execute();
$stmt->get_result();
}
else
{
$message = _("Invalid token detected, please retry your request from start!");
}
Token::delete($token); $stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'");
$stmt->bind_param("d", $id);
$stmt->execute();
$stmt->get_result();
User::logout();
}
else{
$message = _("Wrong password!");
}
} }
}else{
if (Token::validate($token, $id, "passwd"))
{
$stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?");
$stmt->bind_param("i", $id);
$stmt->execute();
$query = $stmt->get_result();
$result = $query->fetch_assoc();
$salt = $result['salt'];
$pass = $_POST['password'];
$hash = hash('sha256', $pass.$salt);
$stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?");
$stmt->bind_param("si", $hash,$id);
$stmt->execute();
$stmt->close();
$stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'");
$stmt->bind_param("d", $id);
$stmt->execute();
$stmt->get_result();
}
else
{
$message = _("Invalid token detected, please retry your request from start!");
}
Token::delete($token);
} }
} }
@ -511,11 +635,23 @@ class User
* @return void * @return void
*/ */
public function email_link(){ public function email_link(){
global $user; global $user, $mysqli;
$email = $_POST['email']; $email = $_POST['email'];
$time = strtotime('+1 day', time());
$id = $this->id; $id = $this->id;
if ($user->get_rank()<1 && $id!=$_SESSION['user'])
{
$stmt = $mysqli->prepare("UPDATE users SET email = ? WHERE id=?");
$stmt->bind_param("sd", $email, $id);
$stmt->execute();
$stmt->get_result();
header("Location: /admin/?do=user&id=".$id);
return;
}
$time = strtotime('+1 day', time());
$token = Token::add($id, 'email;$email', $time); $token = Token::add($id, 'email;$email', $time);
$link = WEB_URL."/admin/?do=change-email&id=$id&token=$token"; $link = WEB_URL."/admin/?do=change-email&id=$id&token=$token";
@ -528,6 +664,7 @@ class User
$headers .= "Reply-To: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL; $headers .= "Reply-To: ".MAILER_NAME.' <'.MAILER_ADDRESS.'>'.PHP_EOL;
mail($to, $subject, $msg, $headers); mail($to, $subject, $msg, $headers);
return _('Confirmation email sent!');
} }
/** /**

View File

@ -93,7 +93,7 @@ div.center {
#wrapper #wrapper
{ {
max-width: 900px; max-width: 1024px;
min-height: calc(100vh - 157px); min-height: calc(100vh - 157px);
padding-right: 15px; padding-right: 15px;
padding-left: 15px padding-left: 15px
@ -599,4 +599,20 @@ i.danger{
body .h1,body .h2,body .h3,body h1,body h2,body h3 { body .h1,body .h2,body .h3,body h1,body h2,body h3 {
margin-top: 18px; margin-top: 18px;
}
.row.user .input-group
{
width: 100%;
margin-bottom: 5px
}
.row.user .form-name{
width: 50%;
float: left;
}
label.form-name
{
line-height: 20px
} }