diff --git a/assets/less/classes/profile/about.less b/assets/less/classes/profile/about.less index 105c648b..33ae7b01 100644 --- a/assets/less/classes/profile/about.less +++ b/assets/less/classes/profile/about.less @@ -1,5 +1,4 @@ .profile__about { - margin-bottom: 2px; &__content { max-height: 1000px; diff --git a/assets/less/classes/profile/accounts.less b/assets/less/classes/profile/accounts.less index 412a0d10..d8753e7d 100644 --- a/assets/less/classes/profile/accounts.less +++ b/assets/less/classes/profile/accounts.less @@ -1,5 +1,4 @@ .profile__accounts { - margin-bottom: 2px; &__content { display: flex; diff --git a/assets/less/classes/profile/background-settings.less b/assets/less/classes/profile/background-settings.less index 2ce3b21a..07561a09 100644 --- a/assets/less/classes/profile/background-settings.less +++ b/assets/less/classes/profile/background-settings.less @@ -1,5 +1,4 @@ .profile__background-settings { - margin-bottom: 2px; &__content { display: flex; diff --git a/assets/less/classes/profile/birthdate.less b/assets/less/classes/profile/birthdate.less new file mode 100644 index 00000000..b9894be6 --- /dev/null +++ b/assets/less/classes/profile/birthdate.less @@ -0,0 +1,19 @@ +.profile__birthdate { + + &__content { + padding: 2px 5px; + } + + &__select { + min-width: auto; + } + + &__label { + display: inline-block; + } + + &__title { + font-size: .9em; + line-height: 1.8em; + } +} diff --git a/assets/less/classes/profile/container.less b/assets/less/classes/profile/container.less new file mode 100644 index 00000000..712d06a4 --- /dev/null +++ b/assets/less/classes/profile/container.less @@ -0,0 +1,3 @@ +.profile__container { + margin-bottom: 2px; +} diff --git a/assets/less/classes/profile/guidelines.less b/assets/less/classes/profile/guidelines.less index 41da12dc..79a76497 100644 --- a/assets/less/classes/profile/guidelines.less +++ b/assets/less/classes/profile/guidelines.less @@ -3,7 +3,6 @@ flex-wrap: auto; justify-content: space-evenly; padding: 2px; - margin-bottom: 2px; @media (max-width: @site-mobile-width) { flex-direction: column; diff --git a/assets/less/classes/profile/profile.less b/assets/less/classes/profile/profile.less index 43bb36f4..f836c278 100644 --- a/assets/less/classes/profile/profile.less +++ b/assets/less/classes/profile/profile.less @@ -1,6 +1,6 @@ .profile { - &__container { + &__content { display: flex; &__main { diff --git a/assets/less/main.less b/assets/less/main.less index f6f5fc69..61c5cb1e 100644 --- a/assets/less/main.less +++ b/assets/less/main.less @@ -132,6 +132,7 @@ html { @import "classes/manage/blacklist"; // Profile +@import "classes/profile/container"; @import "classes/profile/profile"; @import "classes/profile/header"; @import "classes/profile/accounts"; @@ -139,6 +140,7 @@ html { @import "classes/profile/guidelines"; @import "classes/profile/background-settings"; @import "classes/profile/warning"; +@import "classes/profile/birthdate"; // Changelog @import "classes/changelog"; diff --git a/database/2019_01_18_123018_add_birthday_field.php b/database/2019_01_18_123018_add_birthday_field.php new file mode 100644 index 00000000..c56035ee --- /dev/null +++ b/database/2019_01_18_123018_add_birthday_field.php @@ -0,0 +1,22 @@ +exec(" + ALTER TABLE `msz_users` + ADD COLUMN `user_birthdate` DATE NULL DEFAULT NULL AFTER `user_about_parser`, + DROP INDEX `users_indices`, + ADD INDEX `users_indices` (`user_country`, `user_created`, `user_active`, `user_deleted`, `user_birthdate`); + "); +} + +function migrate_down(PDO $conn): void +{ + $conn->exec(" + ALTER TABLE `msz_users` + DROP COLUMN `user_birthdate`; + "); +} diff --git a/public/index.php b/public/index.php index 8b11f3d2..da5c7a9f 100644 --- a/public/index.php +++ b/public/index.php @@ -65,6 +65,10 @@ $changelog = cache_get('index:changelog:v1', function () { ')->fetchAll(PDO::FETCH_ASSOC); }, 300); +$birthdays = user_session_active() + ? cache_get('index:birthdays:v1', user_get_birthdays(), 300) + : []; + $latestUser = cache_get('index:latest_user:v1', function () { return db_query(' SELECT @@ -97,6 +101,7 @@ echo tpl_render('home.' . (user_session_active() ? 'home' : 'landing'), [ 'statistics' => $stats, 'latest_user' => $latestUser, 'online_users' => $onlineUsers, + 'birthdays' => $birthdays, 'featured_changelog' => $changelog, 'featured_news' => $news, ]); diff --git a/public/profile.php b/public/profile.php index 4aa795b4..58301a0b 100644 --- a/public/profile.php +++ b/public/profile.php @@ -145,6 +145,7 @@ switch ($mode) { 'edit_avatar' => perms_check($userPerms, MSZ_PERM_USER_CHANGE_AVATAR), 'edit_background' => perms_check($userPerms, MSZ_PERM_USER_CHANGE_BACKGROUND), 'edit_about' => perms_check($userPerms, MSZ_PERM_USER_EDIT_ABOUT), + 'edit_birthdate' => perms_check($userPerms, MSZ_PERM_USER_EDIT_BIRTHDATE), ]; tpl_vars([ @@ -197,6 +198,38 @@ switch ($mode) { } } + if (!empty($_POST['birthdate']) && is_array($_POST['birthdate'])) { + if (!$perms['edit_birthdate']) { + $notices[] = "You aren't allow to change your birthdate."; + } else { + $setBirthdate = user_set_birthdate( + $userId, + (int)($_POST['birthdate']['day'] ?? 0), + (int)($_POST['birthdate']['month'] ?? 0), + (int)($_POST['birthdate']['year'] ?? 0) + ); + + switch ($setBirthdate) { + case MSZ_E_USER_BIRTHDATE_USER: + $notices[] = 'Invalid user specified while setting birthdate?'; + break; + case MSZ_E_USER_BIRTHDATE_DATE: + $notices[] = 'The given birthdate is invalid.'; + break; + case MSZ_E_USER_BIRTHDATE_FAIL: + $notices[] = 'Failed to set birthdate.'; + break; + case MSZ_E_USER_BIRTHDATE_YEAR: + $notices[] = 'The given birth year is invalid.'; + break; + case MSZ_E_USER_BIRTHDATE_OK: + break; + default: + $notices[] = 'Something unexpected happened while setting your birthdate.'; + } + } + } + if (!empty($_FILES['avatar'])) { if (!empty($_POST['avatar']['delete'])) { user_avatar_delete($userId); @@ -306,7 +339,7 @@ switch ($mode) { sprintf( ' SELECT - u.`user_id`, u.`username`, u.`user_country`, + u.`user_id`, u.`username`, u.`user_country`, u.`user_birthdate`, u.`user_created`, u.`user_active`, u.`user_about_parser`, u.`user_about_content`, u.`user_background_settings`, %1$s, diff --git a/src/Users/user.php b/src/Users/user.php index 998b8ecf..4b15b034 100644 --- a/src/Users/user.php +++ b/src/Users/user.php @@ -7,6 +7,7 @@ define('MSZ_PERM_USER_EDIT_PROFILE', 1); define('MSZ_PERM_USER_CHANGE_AVATAR', 1 << 1); define('MSZ_PERM_USER_CHANGE_BACKGROUND', 1 << 2); define('MSZ_PERM_USER_EDIT_ABOUT', 1 << 3); +define('MSZ_PERM_USER_EDIT_BIRTHDATE', 1 << 4); define('MSZ_PERM_USER_MANAGE_USERS', 1 << 20); define('MSZ_PERM_USER_MANAGE_ROLES', 1 << 21); @@ -191,6 +192,68 @@ function user_check_authority(int $userId, int $subjectId): bool return (bool)($checkHierarchy->execute() ? $checkHierarchy->fetchColumn() : false); } +define('MSZ_E_USER_BIRTHDATE_OK', 0); +define('MSZ_E_USER_BIRTHDATE_USER', 1); +define('MSZ_E_USER_BIRTHDATE_DATE', 2); +define('MSZ_E_USER_BIRTHDATE_FAIL', 3); +define('MSZ_E_USER_BIRTHDATE_YEAR', 4); + +function user_set_birthdate(int $userId, int $day, int $month, int $year, int $yearRange = 100): int +{ + if ($userId < 1) { + return MSZ_E_USER_BIRTHDATE_USER; + } + + $unset = $day === 0 && $month === 0; + + if ($year === 0) { + $checkYear = date('Y'); + } else { + echo $year; + if ($year < date('Y') - $yearRange || $year > date('Y')) { + return MSZ_E_USER_BIRTHDATE_YEAR; + } + + $checkYear = $year; + } + + if (!$unset && !checkdate($month, $day, $checkYear)) { + return MSZ_E_USER_BIRTHDATE_DATE; + } + + $birthdate = $unset ? null : implode('-', [$year, $month, $day]); + $setBirthdate = db_prepare(' + UPDATE `msz_users` + SET `user_birthdate` = :birthdate + WHERE `user_id` = :user + '); + $setBirthdate->bindValue('birthdate', $birthdate); + $setBirthdate->bindValue('user', $userId); + + return $setBirthdate->execute() + ? MSZ_E_USER_BIRTHDATE_OK + : MSZ_E_USER_BIRTHDATE_FAIL; +} + +function user_get_birthdays(int $day = 0, int $month = 0) +{ + if ($day < 1 || $month < 1) { + $date = date('%-m-d'); + } else { + $date = "%-{$month}-{$day}"; + } + + $getBirthdays = db_prepare(' + SELECT `user_id`, `username`, `user_birthdate`, + IF(YEAR(`user_birthdate`) < 1, NULL, YEAR(NOW()) - YEAR(`user_birthdate`)) AS `user_age` + FROM `msz_users` + WHERE `user_deleted` IS NULL + AND `user_birthdate` LIKE :birthdate + '); + $getBirthdays->bindValue('birthdate', $date); + return db_fetch_all($getBirthdays); +} + define('MSZ_USER_ABOUT_MAX_LENGTH', 0xFFFF); define('MSZ_USER_ABOUT_OK', 0); diff --git a/src/manage.php b/src/manage.php index 01fbbb00..bc696917 100644 --- a/src/manage.php +++ b/src/manage.php @@ -13,7 +13,6 @@ function manage_get_menu(int $userId): array $menu = []; $menu['General']['Overview'] = '/manage/index.php?v=overview'; - $menu['General']['Quotes'] = '/manage/index.php?v=quotes'; if (perms_check($perms['general'], MSZ_PERM_GENERAL_VIEW_LOGS)) { $menu['General']['Logs'] = '/manage/index.php?v=logs'; @@ -221,6 +220,11 @@ function manage_perms_list(array $rawPerms): array 'title' => 'Can change own about section.', 'perm' => MSZ_PERM_USER_EDIT_ABOUT, ], + [ + 'section' => 'edit-birthdate', + 'title' => 'Can change own birthdate.', + 'perm' => MSZ_PERM_USER_EDIT_BIRTHDATE, + ], [ 'section' => 'manage-users', 'title' => 'Can manage other users.', diff --git a/templates/home/landing.twig b/templates/home/landing.twig index f00661ee..52a4281b 100644 --- a/templates/home/landing.twig +++ b/templates/home/landing.twig @@ -92,7 +92,27 @@ {% endif %} - {% if latest_user.user_id|default(0) > 0 %} + {% if current_user is defined and birthdays|length > 0 %} +
+ {{ container_title(' Happy Birthday!') }} + + {% for birthday in birthdays %} + +
+
+
+ {{ birthday.username }} +
+ {% if birthday.user_age is not null %} +
+ Turned {{ birthday.user_age }} today! +
+ {% endif %} +
+
+ {% endfor %} +
+ {% elseif latest_user.user_id|default(0) > 0 %}
{{ container_title(' Newest User') }} diff --git a/templates/user/profile.twig b/templates/user/profile.twig index 9e972310..a5412911 100644 --- a/templates/user/profile.twig +++ b/templates/user/profile.twig @@ -66,7 +66,7 @@ {% include 'user/_layout/header.twig' %} {% if is_editing %} -
+
  • General
  • Keep things sane and generally suitable for all ages.
  • @@ -104,15 +104,16 @@
{% endif %} -
+
{% set show_profile_fields = is_editing ? perms.edit_profile : profile_fields|default([])|length > 0 %} {% set show_background_settings = is_editing and perms.edit_background %} + {% set show_birthdate = is_editing and perms.edit_birthdate %} {% set show_sidebar = current_user is not defined or show_profile_fields or show_background_settings %} {% if show_sidebar %} -
+
{% if show_background_settings %} -
+
{{ container_title('Background') }}
@@ -129,13 +130,13 @@
{% endif %} {% if current_user is not defined %} -
+
You must log in to view full profiles!
{% elseif show_profile_fields %} -
+
{{ container_title('Elsewhere') }}
@@ -163,12 +164,46 @@
{% endif %} + {% if show_birthdate %} +
+ {{ container_title('Birthdate') }} + + {% set birthdate = profile.user_birthdate|split('-') %} + +
+
+ + + +
+ +
+ +
+
+
+ {% endif %}
{% endif %} -
+
{% if (is_editing and perms.edit_about) or profile.user_about_content|length > 0 %} -
+
{{ container_title('About ' ~ profile.username) }}
@@ -183,7 +218,7 @@ {% endif %} {% if warnings|length > 0 %} -
+
{{ container_title('Account Standing', false, can_manage_warnings ? '/manage/users.php?v=warnings&u=' ~ profile.user_id : '') }}