Skip to content

Commit

Permalink
personalised avatars
Browse files Browse the repository at this point in the history
  • Loading branch information
ellite committed Mar 24, 2024
1 parent 7f115dd commit 8e6faae
Show file tree
Hide file tree
Showing 20 changed files with 321 additions and 60 deletions.
39 changes: 39 additions & 0 deletions endpoints/user/delete_avatar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

require_once '../../includes/connect_endpoint.php';

session_start();

if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
die(json_encode([
"success" => false,
"message" => translate('session_expired', $i18n)
]));
}

$input = json_decode(file_get_contents('php://input'), true);
if (isset($input['avatar'])) {
$avatar = "images/uploads/logos/avatars/".$input['avatar'];
$sql = "SELECT avatar FROM user";
$stmt = $db->prepare($sql);
$result = $stmt->execute();
$userAvatar = $result->fetchArray(SQLITE3_ASSOC)['avatar'];

// Check if $avatar matches the avatar in the user table
if ($avatar === $userAvatar) {
echo json_encode(array("success" => false));
} else {
// The avatars do not match
$filePath = "../../" . $avatar;
if (file_exists($filePath)) {
unlink($filePath);
echo json_encode(array("success" => true, "message" => translate("success", $i18n)));
} else {
echo json_encode(array("success" => false, "message" => translate("error", $i18n)));
}
}
} else {
echo json_encode(array("success" => false, "message" => translate("error", $i18n)));
}

?>
99 changes: 94 additions & 5 deletions endpoints/user/save_user.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,95 @@ function update_exchange_rate($db) {
$row = $result->fetchArray(SQLITE3_ASSOC);
$mainCurrencyId = $row['main_currency'];

function sanitizeFilename($filename) {
$filename = preg_replace("/[^a-zA-Z0-9\s]/", "", $filename);
$filename = str_replace(" ", "-", $filename);
$filename = str_replace(".", "", $filename);
return $filename;
}

function validateFileExtension($fileExtension) {
$allowedExtensions = ['png', 'jpg', 'jpeg', 'gif', 'jtif', 'webp'];
return in_array($fileExtension, $allowedExtensions);
}

function resizeAndUploadAvatar($uploadedFile, $uploadDir, $name) {
$targetWidth = 80;
$targetHeight = 80;

$timestamp = time();
$originalFileName = $uploadedFile['name'];
$fileExtension = strtolower(pathinfo($originalFileName, PATHINFO_EXTENSION));
$fileExtension = validateFileExtension($fileExtension) ? $fileExtension : 'png';
$fileName = $timestamp . '-avatars-' . sanitizeFilename($name) . '.' . $fileExtension;
$uploadFile = $uploadDir . $fileName;

if (move_uploaded_file($uploadedFile['tmp_name'], $uploadFile)) {
$fileInfo = getimagesize($uploadFile);

if ($fileInfo !== false) {
$width = $fileInfo[0];
$height = $fileInfo[1];

// Load the image based on its format
if ($fileExtension === 'png') {
$image = imagecreatefrompng($uploadFile);
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
$image = imagecreatefromjpeg($uploadFile);
} elseif ($fileExtension === 'gif') {
$image = imagecreatefromgif($uploadFile);
} elseif ($fileExtension === 'webp') {
$image = imagecreatefromwebp($uploadFile);
} else {
// Handle other image formats as needed
return "";
}

// Enable alpha channel (transparency) for PNG images
if ($fileExtension === 'png') {
imagesavealpha($image, true);
}

$newWidth = $width;
$newHeight = $height;

if ($width > $targetWidth) {
$newWidth = $targetWidth;
$newHeight = ($targetWidth / $width) * $height;
}

if ($newHeight > $targetHeight) {
$newWidth = ($targetHeight / $newHeight) * $newWidth;
$newHeight = $targetHeight;
}

$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
imagesavealpha($resizedImage, true);
$transparency = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
imagefill($resizedImage, 0, 0, $transparency);
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);

if ($fileExtension === 'png') {
imagepng($resizedImage, $uploadFile);
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
imagejpeg($resizedImage, $uploadFile);
} elseif ($fileExtension === 'gif') {
imagegif($resizedImage, $uploadFile);
} elseif ($fileExtension === 'webp') {
imagewebp($resizedImage, $uploadFile);
} else {
return "";
}

imagedestroy($image);
imagedestroy($resizedImage);
return "images/uploads/logos/avatars/".$fileName;
}
}

return "";
}

if (isset($_SESSION['username']) && isset($_POST['username']) && isset($_POST['email']) && isset($_POST['avatar'])) {
$oldUsername = $_SESSION['username'];
$username = validate($_POST['username']);
Expand All @@ -95,18 +184,18 @@ function update_exchange_rate($db) {

if (! empty($_FILES['profile_pic']["name"])) {
$file = $_FILES['profile_pic'];
$avatar = $file['name'];

if (! in_array(mime_content_type($file['tmp_name']), ['image/png', 'image/jpeg'])) {
$fileType = mime_content_type($_FILES['profile_pic']['tmp_name']);
if (strpos($fileType, 'image') === false) {
$response = [
"success" => false,
"errorMessage" => translate('file_type_error', $i18n)
"errorMessage" => translate('fill_all_fields', $i18n)
];
echo json_encode($response);
exit();
}

move_uploaded_file($file['tmp_name'], '../../images/avatars/' . $avatar);
$name = $file['name'];
$avatar = resizeAndUploadAvatar($_FILES['profile_pic'], '../../images/uploads/logos/avatars/', $name);
}

if (isset($_POST['password']) && $_POST['password'] != "") {
Expand Down
2 changes: 1 addition & 1 deletion includes/header.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<nav>
<div class="dropdown">
<button class="dropbtn" onClick="toggleDropdown()">
<img src="images/avatars/<?= is_numeric($userData['avatar']) ? $userData['avatar'].'.svg' : $userData['avatar'] ?>" alt="me" id="avatar">
<img src="<?= $userData['avatar'] ?>" alt="me" id="avatar">
<span id="user"><?= $username ?></span>
</button>
<div class="dropdown-content">
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/de.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "Zahlungsweisen Icons",
// Settings page
'upload_avatar' => "Avatar hochladen",
'file_type_error' => "Dateityp nicht unterstützt",
'user_details' => "Benutzerdetails",
"household" => "Haushalt",
"save_member" => "Mitglied speichern",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/el.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "Εικονίδια Payment",
// Settings page
'upload_avatar' => "μεταφόρτωση άβαταρ",
'file_type_error' => "Το αρχείο πρέπει να είναι τύπου jpg, jpeg, png, webp ή gif",
'user_details' => "Λεπτομέρειες χρήστη",
"household" => "Νοικοκυριό",
"save_member" => "Αποθήκευση μέλους",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/es.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "Iconos de Pago",
// Settings page
'upload_avatar' => "Subir avatar",
'file_type_error' => "El archivo debe ser una imagen en formato PNG, JPG, WEBP o SVG",
'user_details' => "Detalles del Usuario",
"household" => "Hogar",
"save_member" => "Guardar Miembro",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/fr.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "Icônes de paiement",
// Page de paramètres
'upload_avatar' => "Télécharger un Avatar",
'file_type_error' => "Le type de fichier n'est pas pris en charge",
'user_details' => "Détails de l'utilisateur",
"household" => "Ménage",
"save_member" => "Enregistrer le membre",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/jp.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "支払いアイコン",
// Settings page
'upload_avatar' => "アバターをアップロードする",
'file_type_error' => "ファイルタイプが許可されていません",
'user_details' => "ユーザー詳細",
"household" => "世帯",
"save_member" => "世帯員を保存",
Expand Down
3 changes: 2 additions & 1 deletion includes/i18n/pt.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@
'icons' => "Ícones",
'payment_icons' => "Ícones de Pagamentos",
// Settings page
'upload_avatar' => "Carregar avatar",
'upload_avatar' => "Enviar avatar",
'file_type_error' => "Tipo de ficheiro não permitido",
'user_details' => "Detalhes do utilizador",
"household" => "Agregado",
"save_member" => "Guardar Membro",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/pt_br.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
'payment_icons' => "Ícones de pagamento",
// Settings page
'upload_avatar' => "Carregar avatar",
'file_type_error' => "Tipo de arquivo não permitido",
'user_details' => "Informações do Usuário",
"household" => "Membros",
"save_member" => "Salvar membro",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/tr.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "Ödeme İkonları",
// Settings page
'upload_avatar' => "Avatarı yükle",
'file_type_error' => "Dosya türü izin verilmiyor",
'user_details' => "Kullanıcı Detayları",
"household" => "Hane",
"save_member" => "Üyeyi Kaydet",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/zh_cn.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@

// 设置页面
'upload_avatar' => "上传头像",
'file_type_error' => "文件类型不允许",
'user_details' => "用户详情",
"household" => "家庭",
"save_member" => "保存成员",
Expand Down
1 change: 1 addition & 0 deletions includes/i18n/zh_tw.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
'payment_icons' => "付款圖示",
// 設定頁面
'upload_avatar' => "上传头像",
'file_type_error' => "文件类型不允许",
'user_details' => "使用者詳細資訊",
"household" => "家庭",
"save_member" => "儲存成員",
Expand Down
25 changes: 25 additions & 0 deletions migrations/000013.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/**
* This migration script updates the avatar field of the user table to use the new avatar path.
*/

/** @noinspection PhpUndefinedVariableInspection */
$sql = "SELECT avatar FROM user";
$stmt = $db->prepare($sql);
$result = $stmt->execute();
$row = $result->fetchArray(SQLITE3_ASSOC);

if ($row) {
$avatar = $row['avatar'];

if (strlen($avatar) < 2) {
$avatarFullPath = "images/avatars/" . $avatar . ".svg";
$sql = "UPDATE user SET avatar = :avatarFullPath";
$stmt = $db->prepare($sql);
$stmt->bindValue(':avatarFullPath', $avatarFullPath, SQLITE3_TEXT);
$stmt->execute();
}
}

?>
2 changes: 1 addition & 1 deletion registration.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function validate($value) {
$confirm_password = $_POST['confirm_password'];
$main_currency = $_POST['main_currency'];
$language = $_POST['language'];
$avatar = "0";
$avatar = "images/avatars/0.svg";

if ($password != $confirm_password) {
$passwordMismatch = true;
Expand Down
44 changes: 36 additions & 8 deletions scripts/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ function closeAvatarSelect() {

document.querySelectorAll('.avatar-option').forEach((avatar) => {
avatar.addEventListener("click", () => {
console.log(avatar);
changeAvatar(avatar.src);
document.getElementById('avatarUser').value = avatar.alt.replace('.svg', '');
document.getElementById('avatarUser').value = avatar.getAttribute('data-src');
closeAvatarSelect();
})
});
Expand All @@ -27,23 +28,50 @@ function changeAvatar(src) {
function successfulUpload(field, msg) {
var reader = new FileReader();

if (! ['image/png', 'image/jpeg'].includes(field.files[0]['type'])) {
alert(msg);

return;
if (field.files.length === 0) {
return;
}

if (! ['image/jpeg', 'image/png', 'image/gif', 'image/jtif', 'image/webp'].includes(field.files[0]['type'])) {
showErrorMessage(msg);
return;
}

reader.onload = function() {
changeAvatar(reader.result);
};

reader.readAsDataURL(field.files[0]);

label = document.querySelector('label[for="' + field.name + '"]');
label.style.borderColor = '#90EE90';
closeAvatarSelect();
}

function deleteAvatar(path) {
fetch('/endpoints/user/delete_avatar.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ avatar: path }),
})
.then(response => response.json())
.then(data => {
if (data.success) {
console.log(path);
var avatarContainer = document.querySelector(`.avatar-container[data-src="${path}"]`);
console.log(avatarContainer);
if (avatarContainer) {
avatarContainer.remove();
}
showSuccessMessage();
} else {
showErrorMessage();
}
})
.catch((error) => {
console.error('Error:', error);
});
}

function addMemberButton(memberId) {
document.getElementById("addMember").disabled = true;
const url = 'endpoints/household/household.php?action=add';
Expand Down
22 changes: 16 additions & 6 deletions settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div class="fields">
<div>
<div class="user-avatar">
<img src="images/avatars/<?= is_numeric($userData['avatar']) ? $userData['avatar'].'.svg' : $userData['avatar'] ?>" alt="avatar" class="avatar" id="avatarImg" onClick="toggleAvatarSelect()"/>
<img src="<?= $userData['avatar'] ?>" alt="avatar" class="avatar" id="avatarImg" onClick="toggleAvatarSelect()"/>
<span class="edit-avatar" onClick="toggleAvatarSelect()">
<img src="images/siteicons/editavatar.png" title="Change avatar" />
</span>
Expand All @@ -29,14 +29,24 @@
<div class="avatar-list">
<?php foreach (scandir('images/avatars') as $index => $image) :?>
<?php if (! str_starts_with($image, '.')) :?>
<img src="images/avatars/<?=$image?>" alt="<?=$image?>" class="avatar-option"/>
<img src="images/avatars/<?=$image?>" alt="<?=$image?>" class="avatar-option" data-src="images/avatars/<?=$image?>"/>
<?php endif ?>
<?php endforeach ?>
<?php foreach (scandir('images/uploads/logos/avatars') as $index => $image) :?>
<?php if (! str_starts_with($image, '.')) :?>
<div class="avatar-container" data-src="<?=$image?>">
<img src="images/uploads/logos/avatars/<?=$image?>" alt="<?=$image?>" class="avatar-option" data-src="images/uploads/logos/avatars/<?=$image?>"/>
<div class="remove-avatar" onclick="deleteAvatar('<?=$image?>')" title="Delete avatar">
<i class="fa-solid fa-xmark"></i>
</div>
</div>
<?php endif ?>
<?php endforeach ?>
<label for="profile_pic" class="add-avatar" title="<?= translate('upload_avatar', $i18n) ?>">
<i class="fa-solid fa-arrow-up-from-bracket"></i>
</label>
</div>
<div class="profile-pic-container">
<label for="profile_pic"><?= translate('upload_avatar', $i18n) ?></label>
<input type="file" id="profile_pic" name="profile_pic" onChange="successfulUpload(this, '<?= translate('file_type_error', $i18n) ?>')" />
</div>
<input type="file" id="profile_pic"class="hidden-input" name="profile_pic" accept="image/jpeg, image/png, image/gif, image/webp" onChange="successfulUpload(this, '<?= translate('file_type_error', $i18n) ?>')" />
</div>
</div>
<div class="grow">
Expand Down
Loading

0 comments on commit 8e6faae

Please sign in to comment.