From bf886be2a2ce9931d69359b254d3a7ce7604714f Mon Sep 17 00:00:00 2001 From: Tadhg Boyle Date: Thu, 6 Apr 2023 13:52:06 -0700 Subject: [PATCH 01/22] initial commit --- core/classes/Avatars/AvatarSource.php | 249 +++++------------- core/classes/Avatars/AvatarSourceBase.php | 142 ++++------ core/classes/Core/User.php | 19 +- core/classes/Database/DatabaseInitialiser.php | 6 +- core/classes/Minecraft/MCQuery.php | 4 +- core/classes/Misc/Report.php | 2 +- core/includes/image_upload.php | 4 - core/includes/updates/203.php | 49 ++++ core/init.php | 29 -- custom/languages/en_UK.json | 2 + .../Default/core/avatar_source_settings.tpl | 108 ++++++++ .../Default/core/avatar_sources/minecraft.tpl | 58 ++++ .../core/avatar_sources/uploaded_image.tpl | 42 +++ .../panel_templates/Default/core/avatars.tpl | 209 ++++++--------- custom/panel_templates/Default/template.php | 20 -- custom/templates/DefaultRevamp/template.php | 5 +- .../templates/DefaultRevamp/user/settings.tpl | 2 +- ....php => CrafatarMinecraftAvatarSource.php} | 2 +- ...php => CraftheadMinecraftAvatarSource.php} | 2 +- ....php => CravatarMinecraftAvatarSource.php} | 3 +- .../classes/Avatars/GravatarAvatarSource.php | 17 ++ .../classes/Avatars/InitialsAvatarSource.php | 14 + ...e.php => MCHeadsMinecraftAvatarSource.php} | 3 +- .../classes/Avatars/MinecraftAvatarSource.php | 134 ++++++++++ .../Avatars/MinecraftAvatarSourceBase.php | 119 +++++++++ ...e.php => MinotarMinecraftAvatarSource.php} | 3 +- ...hp => NamelessMCMinecraftAvatarSource.php} | 4 +- .../Avatars/UploadedImageAvatarSource.php | 38 +++ ...ce.php => VisageMinecraftAvatarSource.php} | 2 +- .../admin_avatar_settings/minecraft.php | 28 ++ .../admin_avatar_settings/uploaded_image.php | 54 ++++ modules/Core/module.php | 26 +- modules/Core/pages/leaderboards.php | 2 +- modules/Core/pages/panel/avatars.php | 142 +++++----- modules/Core/pages/panel/users_edit.php | 1 + modules/Core/pages/panel/users_reports.php | 6 +- modules/Core/pages/user/settings.php | 3 +- modules/Core/queries/admin_users.php | 9 +- modules/Core/queries/mention_users.php | 4 +- modules/Core/queries/user.php | 2 +- modules/Core/queries/users.php | 5 +- 41 files changed, 990 insertions(+), 583 deletions(-) create mode 100644 custom/panel_templates/Default/core/avatar_source_settings.tpl create mode 100644 custom/panel_templates/Default/core/avatar_sources/minecraft.tpl create mode 100644 custom/panel_templates/Default/core/avatar_sources/uploaded_image.tpl rename modules/Core/classes/Avatars/{CrafatarAvatarSource.php => CrafatarMinecraftAvatarSource.php} (89%) rename modules/Core/classes/Avatars/{CraftheadAvatarSource.php => CraftheadMinecraftAvatarSource.php} (88%) rename modules/Core/classes/Avatars/{CravatarAvatarSource.php => CravatarMinecraftAvatarSource.php} (83%) create mode 100644 modules/Core/classes/Avatars/GravatarAvatarSource.php create mode 100644 modules/Core/classes/Avatars/InitialsAvatarSource.php rename modules/Core/classes/Avatars/{MCHeadsAvatarSource.php => MCHeadsMinecraftAvatarSource.php} (83%) create mode 100644 modules/Core/classes/Avatars/MinecraftAvatarSource.php create mode 100644 modules/Core/classes/Avatars/MinecraftAvatarSourceBase.php rename modules/Core/classes/Avatars/{MinotarAvatarSource.php => MinotarMinecraftAvatarSource.php} (83%) rename modules/Core/classes/Avatars/{NamelessMCAvatarSource.php => NamelessMCMinecraftAvatarSource.php} (84%) create mode 100644 modules/Core/classes/Avatars/UploadedImageAvatarSource.php rename modules/Core/classes/Avatars/{VisageAvatarSource.php => VisageMinecraftAvatarSource.php} (89%) create mode 100644 modules/Core/includes/admin_avatar_settings/minecraft.php create mode 100644 modules/Core/includes/admin_avatar_settings/uploaded_image.php diff --git a/core/classes/Avatars/AvatarSource.php b/core/classes/Avatars/AvatarSource.php index 1f7ce43501..307c0dda3b 100644 --- a/core/classes/Avatars/AvatarSource.php +++ b/core/classes/Avatars/AvatarSource.php @@ -1,175 +1,99 @@ getAvatar($uuid, self::getDefaultPerspective(), $size); + protected function __construct() { + $this->_cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); } /** - * Get a user's avatar from their raw data object. - * Used by the API for TinyMCE mention avatars to avoid reloading the user from the database. - * - * @param object $data User data to use - * @param bool $allow_gifs Whether to allow GIFs or not () - * @param int $size Size in pixels to render avatar at. Default 128 - * @param bool $full Whether to return the full URL or just the path + * Get an avatar URL for a user. * - * @return string Full URL of avatar image. + * @param int|User $user User to fetch avatar for, or their ID. + * @param int $size Size of avatar to fetch in pixels. + * @param bool $full_url Whether to return the full external URL (ie: for display in Discord embed) or just the path. + * @return string The URL to the avatar. */ - public static function getAvatarFromUserData(object $data, bool $allow_gifs = false, int $size = 128, bool $full = false): string { - // If custom avatars are enabled, first check if they have gravatar enabled, and then fallback to normal image - if (defined('CUSTOM_AVATARS')) { - if ($data->gravatar) { - return 'https://secure.gravatar.com/avatar/' . md5(strtolower(trim($data->email))) . '?s=' . $size; - } - - if ($data->has_avatar) { - $exts = ['png', 'jpg', 'jpeg']; + public function getAvatarForUser($user, int $size = 128, bool $full_url = false): string { + if ($user instanceof User) { + $user_id = $user->data()->id; + } else { + $user_id = (int) $user; + } - if ($allow_gifs) { - $exts[] = 'gif'; - } + $this->_cache->setCache('avatars'); - foreach ($exts as $ext) { - if (file_exists(ROOT_PATH . '/uploads/avatars/' . $data->id . '.' . $ext)) { - // We don't check the validity here since we know the file exists for sure - return ($full ? rtrim(URL::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/' . $data->id . '.' . $ext . '?v=' . urlencode($data->avatar_updated); - } - } + foreach ($this->getAllSources() as $source) { + if (!$source->isEnabled() && $source->canBeDisabled()) { + continue; } - } - // Fallback to default avatar image if it is set and the avatar type is custom - if (defined('DEFAULT_AVATAR_TYPE') && DEFAULT_AVATAR_TYPE == 'custom' && DEFAULT_AVATAR_IMAGE !== '') { - if (file_exists(ROOT_PATH . '/uploads/avatars/defaults/' . DEFAULT_AVATAR_IMAGE)) { - // We don't check the validity here since we know the file exists for sure - return ($full ? rtrim(URL::getSelfURL(), '/') : '') . ((defined('CONFIG_PATH')) ? CONFIG_PATH . '/' : '/') . 'uploads/avatars/defaults/' . DEFAULT_AVATAR_IMAGE; + $cache_key = $user_id . '_' . $source->getSafeName() . '_' . $size . '_' . (int) $full_url; + if ($this->_cache->isCached($cache_key)) { + return $this->_cache->retrieve($cache_key); } - } - // Attempt to get their MC avatar if Minecraft integration is enabled - if (Util::getSetting('mc_integration')) { - if ($data->uuid != null && $data->uuid != 'none') { - $uuid = $data->uuid; - } else { - $uuid = $data->username; - // Fallback to steve avatar if they have an invalid username - if (preg_match('#[^][_A-Za-z0-9]#', $uuid)) { - $uuid = 'Steve'; - } + if (!($user instanceof User)) { + $user = new User($user_id); } - $url = self::getAvatarFromUUID($uuid, $size); - // The avatar might be invalid if they are using - // an MC avatar service that uses only UUIDs - // and this user doesn't have one - if (self::validImageUrl($url)) { - return $url; + $avatar = $source->getAvatar($user, $size, $full_url); + if ($avatar) { + $url = $avatar; + // Cache for an hour incase a module does not reset the users avatar cache + $this->_cache->store($cache_key, $url, 3600); + break; } } - return "https://api.dicebear.com/5.x/initials/png?seed={$data->username}&size={$size}"; - } - - /** - * Determine if a URL is a valid image URL for avatars. - * - * @param string $url URL to check - * @return bool Whether the URL is a valid image URL - */ - private static function validImageUrl(string $url): bool { - $cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); - $cache->setCache('avatar_validity'); - - if ($cache->isCached($url)) { - return $cache->retrieve($url); - } - - $is_valid = false; - try { - $response = HttpClient::createClient()->head($url); - $headers = $response->getHeaders(); - if (isset($headers['Content-Type']) && $headers['Content-Type'][0] === 'image/png') { - $is_valid = true; - } - } catch (Exception $ignored) { + // Fallback to initials avatar + if (!isset($url)) { + $url = $this->_sources[InitialsAvatarSource::class]->getAvatar($user, $size, $full_url); } - $cache->store($url, $is_valid, 3600); - return $is_valid; + return $url; } /** - * Get the currently active avatar source. - * - * @return AvatarSourceBase The active source. + * @param int|User $user + * @param string|null $source_class + * @return void */ - public static function getActiveSource(): AvatarSourceBase { - return self::$_active_source; - } - - /** - * Set the active source to the source by name. - * Fallsback to Cravatar if name was not found. - * - * @param string $name Name of source to set as active. - */ - public static function setActiveSource(string $name): void { - $source = self::getSourceByName($name); - if ($source === null) { - $source = self::getSourceByName('cravatar'); + public function clearUserAvatarCache($user, string $source_class = null): void { + if ($user instanceof User) { + $user_id = $user->data()->id; + } else { + $user_id = (int) $user; } - self::$_active_source = $source; - } + $this->_cache->setCache('avatars'); - /** - * Get default perspective to pass to the active avatar source. - * - * @return string Perspective. - */ - private static function getDefaultPerspective(): string { - if (defined('DEFAULT_AVATAR_PERSPECTIVE')) { - return DEFAULT_AVATAR_PERSPECTIVE; + foreach (array_keys($this->_cache->retrieveAll()) as $cache_key) { + if (str_starts_with($cache_key, $user_id . '_' . ($source_class ?? ''))) { + $this->_cache->erase($cache_key); + } } - - return 'face'; } - /** - * Find an avatar source instance by it's name. - * - * @return AvatarSourceBase|null Instance if found, null if not found. - */ - public static function getSourceByName(string $name): ?AvatarSourceBase { - foreach (self::getAllSources() as $source) { - if (strtolower($source->getName()) == strtolower($name)) { - return $source; + public function clearSourceAvatarCache(string $source_class): void { + $this->_cache->setCache('avatars'); + + foreach (array_keys($this->_cache->retrieveAll()) as $cache_key) { + if (str_contains($cache_key, $source_class)) { + $this->_cache->erase($cache_key); } } - - return null; } /** @@ -177,23 +101,16 @@ public static function getSourceByName(string $name): ?AvatarSourceBase { * * @return AvatarSourceBase[] */ - public static function getAllSources(): iterable { - return self::$_sources; + public function getAllSources(): array { + $sources = $this->_sources; + uasort($sources, static function (AvatarSourceBase $a, AvatarSourceBase $b) { + return $a->getOrder() - $b->getOrder(); + }); + return $sources; } - /** - * Get raw url of active avatar source with placeholders. - * - * @return string URL with placeholders. - */ - public static function getUrlToFormat(): string { - // Default to Cravatar - if (!isset(self::$_active_source)) { - require_once(ROOT_PATH . '/modules/Core/classes/Avatars/CravatarAvatarSource.php'); - return (new CravatarAvatarSource())->getUrlToFormat(self::getDefaultPerspective()); - } - - return self::getActiveSource()->getUrlToFormat(self::getDefaultPerspective()); + public function getSourceBySafeName(string $safe_name): ?AvatarSourceBase { + return $this->_sources[$safe_name] ?? null; } /** @@ -201,41 +118,7 @@ public static function getUrlToFormat(): string { * * @param AvatarSourceBase $source Instance of avatar source to register. */ - public static function registerSource(AvatarSourceBase $source): void { - self::$_sources[] = $source; - } - - /** - * Get the names and base urls of all the registered avatar sources for displaying. - * Used for showing list of sources in staffcp. - * - * @return array List of names. - */ - public static function getAllSourceNames(): array { - $names = []; - - foreach (self::getAllSources() as $source) { - $names[$source->getName()] = rtrim($source->getBaseUrl(), '/'); - } - - return $names; - } - - /** - * Get key value array of all registered sources and their available perspectives. - * Used for autoupdating dropdown selector in staffcp. - * - * @return array> Array of source => [] perspectives. - */ - public static function getAllPerspectives(): array { - $perspectives = []; - - foreach (self::getAllSources() as $source) { - foreach ($source->getPerspectives() as $perspective) { - $perspectives[$source->getName()][] = $perspective; - } - } - - return $perspectives; + public function registerSource(AvatarSourceBase $source): void { + $this->_sources[$source->getSafeName()] = $source; } } diff --git a/core/classes/Avatars/AvatarSourceBase.php b/core/classes/Avatars/AvatarSourceBase.php index 14ecde017c..fdb9a1e375 100644 --- a/core/classes/Avatars/AvatarSourceBase.php +++ b/core/classes/Avatars/AvatarSourceBase.php @@ -1,109 +1,75 @@ size = $size; + $this->full_url = $full_url; + + return $this->get($user); + } - /** - * Base URL all avatars from this source will add on to. - */ - protected string $_base_url = ''; - - /** - * A map of `NamelessMC perspective name` => `Avatar source route`, - * as not all avatar sources will have the same name, and subsequentally route, for each perspective. - */ - protected array $_perspectives_map = []; - - /** - * Get the name of this avatar source. - * - * @return string Name of this avatar source. - */ public function getName(): string { return $this->_name; } - /** - * Get base url of this avatar source. - * - * @return string Base url of this source. - */ - public function getBaseUrl(): string { - return $this->_base_url; + public function getModule(): string { + return $this->_module; } - /** - * Get "NamelessMC names" of supported perspectives for this avatar source. - * - * @return array Array of perspective names. - */ - public function getPerspectives(): array { - return array_keys($this->_perspectives_map); + public function getSettings(): ?string { + return $this->_settings; + } + + public function getSettingsUrl(): ?string { + if ($this->_settings === null) { + return null; + } + + return URL::build('/panel/core/avatars/', 'action=settings&source=' . $this->getSafeName()); } - /** - * Get the URL for this users avatar. - * - * @param string $uuid UUID of avatar to get. - * @param string $perspective Perspective to render avatar with. - * @param int $size Size in pixels to render avatar at. Default 128 - * - * @return string Compiled URL of avatar image. - */ - public function getAvatar(string $uuid, string $perspective, int $size = 128): string { - return $this->formatUrl($this->getUrlToFormat($perspective), $uuid, $size); + public function isEnabled(): bool { + return $this->getDatabaseSettings()['enabled']; } - /** - * Replace placeholders in raw url with uuid and size of requested avatar. - * - * @param string $url_to_format Raw url to replace placeholders in. - * @param string $uuid uuid (or username, yuck!) of avatar to get. - * @param int $size Size of avatar image in pixels to get. - * - * @return string Formatted url. - */ - public function formatUrl(string $url_to_format, string $uuid, int $size): string { - return str_replace( - ['{identifier}', '{size}'], - [$uuid, $size], - $url_to_format - ); + public function canBeDisabled(): bool { + return $this->_can_be_disabled; } - /** - * Get raw URL with placeholders to format. - * - `{identifier} = UUID / username` - * - `{size} = size in pixels` - * - * @param string $perspective Perspective to use in url. - * - * @return string URL with placeholders to format. - */ - abstract public function getUrlToFormat(string $perspective): string; - - /** - * Translate NamelessMC perspective name to the relative name for this avatar source. - * - * @param string $perspective NamelessMC perspective name to translate. - * @return string Translated perspective name. - * @throws InvalidArgumentException When an invalid perspective is passed. - */ - public function getRelativePerspective(string $perspective): string { - $perspective = strtolower($perspective); - if (isset($this->_perspectives_map[$perspective])) { - return $this->_perspectives_map[$perspective]; + public function getOrder(): int { + return $this->getDatabaseSettings()['order']; + } + + public function getSafeName(): string { + return static::class; + } + + private function getDatabaseSettings(): array { + $settings = json_decode(Util::getSetting('avatar_source_settings'), true); + if (isset($settings[$this->getSafeName()])) { + return $settings[$this->getSafeName()]; } - $class = static::class; - throw new InvalidArgumentException("Attempted to get invalid perspective of: {$perspective} on {$class}"); + $settings[$this->getSafeName()] = [ + 'enabled' => true, + 'order' => 10, + ]; + + Util::setSetting('avatar_source_settings', json_encode($settings)); + + return $settings[$this->getSafeName()]; } + + abstract protected function get(User $user): ?string; + } diff --git a/core/classes/Core/User.php b/core/classes/Core/User.php index 0d2faef8c0..c92cbb9e49 100644 --- a/core/classes/Core/User.php +++ b/core/classes/Core/User.php @@ -430,25 +430,12 @@ public function getSignature(): string { * Get this user's avatar. * * @param int $size Size of image to render in pixels. - * @param bool $full Whether to use full site URL or not, for external loading - ie discord webhooks. + * @param bool $full_url Whether to use full site URL or not, for external loading - ie discord webhooks. * * @return string URL to their avatar image. */ - public function getAvatar(int $size = 128, bool $full = false): string { - $data_obj = new stdClass(); - // Convert UserData object to stdClass so we can dynamically add the 'uuid' property - foreach (get_object_vars($this->data()) as $key => $value) { - $data_obj->{$key} = $value; - } - - $integrationUser = $this->getIntegration('Minecraft'); - if ($integrationUser != null) { - $data_obj->uuid = $integrationUser->data()->identifier; - } else { - $data_obj->uuid = ''; - } - - return AvatarSource::getAvatarFromUserData($data_obj, $this->hasPermission('usercp.gif_avatar'), $size, $full); + public function getAvatar(int $size = 128, bool $full_url = false): string { + return AvatarSource::getInstance()->getAvatarForUser($this, $size, $full_url); } /** diff --git a/core/classes/Database/DatabaseInitialiser.php b/core/classes/Database/DatabaseInitialiser.php index 0657f0a01a..c8a15ea192 100644 --- a/core/classes/Database/DatabaseInitialiser.php +++ b/core/classes/Database/DatabaseInitialiser.php @@ -185,11 +185,10 @@ private function initialiseSettings(): void { Util::setSetting('nameless_version', '2.0.3'); Util::setSetting('version_checked', date('U')); Util::setSetting('phpmailer', '0'); - Util::setSetting('user_avatars', '0'); - Util::setSetting('avatar_site', 'cravatar'); + Util::setSetting('minecraft_avatar_source', CravatarMinecraftAvatarSource::class); Util::setSetting('mc_integration', '1'); Util::setSetting('discord_integration', '0'); - Util::setSetting('avatar_type', 'helmavatar'); + Util::setSetting('minecraft_avatar_perspective', 'face'); Util::setSetting('home_type', 'news'); Util::setSetting('forum_reactions', '1'); Util::setSetting('error_reporting', '0'); @@ -202,7 +201,6 @@ private function initialiseSettings(): void { Util::setSetting('timezone', $_SESSION['install_timezone']); Util::setSetting('maintenance', '0'); Util::setSetting('maintenance_message', 'This website is currently in maintenance mode.'); - Util::setSetting('default_avatar_type', 'minecraft'); Util::setSetting('private_profile', '1'); Util::setSetting('validate_user_action', '{"action":"promote","group":1}'); Util::setSetting('login_method', 'email'); diff --git a/core/classes/Minecraft/MCQuery.php b/core/classes/Minecraft/MCQuery.php index bdd07578cb..8c9bda4199 100644 --- a/core/classes/Minecraft/MCQuery.php +++ b/core/classes/Minecraft/MCQuery.php @@ -183,11 +183,11 @@ public static function formatPlayerList(array $player_list): array { $avatar = $user->getAvatar(); $profile = $user->getProfileURL(); } else { - $avatar = AvatarSource::getAvatarFromUUID($player['id']); + $avatar = MinecraftAvatarSource::getAvatarFromUUID($player['id']); $profile = '#'; } } else { - $avatar = AvatarSource::getAvatarFromUUID($player['id']); + $avatar = MinecraftAvatarSource::getAvatarFromUUID($player['id']); $profile = '#'; } diff --git a/core/classes/Misc/Report.php b/core/classes/Misc/Report.php index 03087e6ab3..a6b1efd9b6 100644 --- a/core/classes/Misc/Report.php +++ b/core/classes/Misc/Report.php @@ -57,7 +57,7 @@ public static function create(Language $language, User $user_reporting, User $re $reported_user->data()->username, $language->get('general', 'reported_by', ['author' => $user_reporting->data()->username]), $data['report_reason'], - $data['reported_id'] == 0 ? null : ($data['reported_uuid'] !== null ? AvatarSource::getAvatarFromUUID($data['reported_uuid']) : $reported_user->getAvatar()), + $data['reported_id'] == 0 ? null : ($data['reported_uuid'] !== null ? MinecraftAvatarSource::getAvatarFromUUID($data['reported_uuid']) : $reported_user->getAvatar()), $language->get('general', 'view_report'), rtrim(URL::getSelfURL(), '/') . URL::build('/panel/users/reports/', 'id=' . $id), )); diff --git a/core/includes/image_upload.php b/core/includes/image_upload.php index 5351d29295..de89f1b9e7 100644 --- a/core/includes/image_upload.php +++ b/core/includes/image_upload.php @@ -100,10 +100,6 @@ default: // Default to normal avatar upload - if (!defined('CUSTOM_AVATARS')) { - die('Custom avatar uploading is disabled'); - } - $folder = 'avatars'; $image->setName($user->data()->id); break; diff --git a/core/includes/updates/203.php b/core/includes/updates/203.php index 383262a680..d60c1f9609 100644 --- a/core/includes/updates/203.php +++ b/core/includes/updates/203.php @@ -27,6 +27,55 @@ public function run(): void { // Add all groups to member list selectable groups Util::setSetting('member_list_viewable_groups', json_encode(array_map(static fn (Group $group) => $group->id, Group::all())), 'Members'); + // Update avatar settings cache to use the class name for minecraft default source and swap to DB + $cache->setCache('avatar_settings_cache'); + if ($cache->isCached('avatar_source')) { + $default_source = $cache->retrieve('avatar_source'); + switch($default_source) { + case 'cravatar': + $default_source = CravatarMinecraftAvatarSource::class; + break; + case 'crafthead': + $default_source = CraftheadMinecraftAvatarSource::class; + break; + case 'crafatar': + $default_source = CrafatarMinecraftAvatarSource::class; + break; + case 'mc-heads': + $default_source = MCHeadsMinecraftAvatarSource::class; + break; + case 'minotar': + $default_source = MinotarMinecraftAvatarSource::class; + break; + case 'nameless': + $default_source = NamelessMCMinecraftAvatarSource::class; + break; + case 'visage': + $default_source = VisageMinecraftAvatarSource::class; + break; + } + + Util::setSetting('minecraft_avatar_source', $default_source); + $cache->erase('avatar_source'); + } + + // Rename `avatar_type` to `minecraft_avatar_perspective` and move to DB + $cache->setCache('avatar_settings_cache'); + if ($cache->isCached('avatar_perspective')) { + $avatar_type = $cache->retrieve('avatar_perspective'); + Util::setSetting('avatar_perspective', $avatar_type); + $cache->erase('avatar_type'); + } + + // Move `custom_avatars` to DB + // TODO: make sure this is correct + $cache->setCache('avatar_settings_cache'); + if ($cache->isCached('custom_avatars')) { + $custom_avatars = $cache->retrieve('custom_avatars'); + Util::setSetting('custom_user_avatars', $custom_avatars); + $cache->erase('custom_avatars'); + } + $this->setVersion('2.1.0'); } }; diff --git a/core/init.php b/core/init.php index 2a03fa595c..289cee7c77 100644 --- a/core/init.php +++ b/core/init.php @@ -334,35 +334,6 @@ $smarty->assign('OG_IMAGE', rtrim(URL::getSelfURL(), '/') . $cache->retrieve('og_image')); } - // Avatars - $cache->setCache('avatar_settings_cache'); - if ($cache->isCached('custom_avatars') && $cache->retrieve('custom_avatars') == 1) { - define('CUSTOM_AVATARS', true); - } - - if ($cache->isCached('default_avatar_type')) { - define('DEFAULT_AVATAR_TYPE', $cache->retrieve('default_avatar_type')); - if (DEFAULT_AVATAR_TYPE == 'custom' && $cache->isCached('default_avatar_image')) { - define('DEFAULT_AVATAR_IMAGE', $cache->retrieve('default_avatar_image')); - } else { - define('DEFAULT_AVATAR_IMAGE', ''); - } - } else { - define('DEFAULT_AVATAR_TYPE', 'minecraft'); - } - - if ($cache->isCached('avatar_source')) { - define('DEFAULT_AVATAR_SOURCE', $cache->retrieve('avatar_source')); - } else { - define('DEFAULT_AVATAR_SOURCE', 'cravatar'); - } - - if ($cache->isCached('avatar_perspective')) { - define('DEFAULT_AVATAR_PERSPECTIVE', $cache->retrieve('avatar_perspective')); - } else { - define('DEFAULT_AVATAR_PERSPECTIVE', 'face'); - } - // Widgets $widgets = new Widgets($cache, $language, $smarty); diff --git a/custom/languages/en_UK.json b/custom/languages/en_UK.json index 6ccecf61c4..d213c6fc31 100644 --- a/custom/languages/en_UK.json +++ b/custom/languages/en_UK.json @@ -47,6 +47,7 @@ "admin/author_x": "Author: {{author}}", "admin/auto_language_help": "If enabled, guests & logged out users will be able to let the website automatically detect their preferred language.", "admin/avatar_settings_updated_successfully": "Avatar settings updated successfully.", + "admin/avatars_info": "You can change the priority order of how avatars are displayed for users, and modify specific settings for avatar sources.", "admin/avatars": "Avatars", "admin/background_colour": "Background Colour", "admin/background_colour_required": "Background Colour is required", @@ -159,6 +160,7 @@ "admin/editing_announcement": "Editing Announcement", "admin/editing_announcement_failure": "Announcement update failed.", "admin/editing_announcement_success": "Announcement updated successfully.", + "admin/editing_avatar_source_x": "Editing avatar source {{avatarSource}}", "admin/editing_hook": "Editing Webhook", "admin/editing_integration_for_x": "Editing {{integration}} integration for {{user}}", "admin/editing_integration_x": "Editing integration {{integration}}", diff --git a/custom/panel_templates/Default/core/avatar_source_settings.tpl b/custom/panel_templates/Default/core/avatar_source_settings.tpl new file mode 100644 index 0000000000..418fbd4d9e --- /dev/null +++ b/custom/panel_templates/Default/core/avatar_source_settings.tpl @@ -0,0 +1,108 @@ +{include file='header.tpl'} + + + + +
+ + + {include file='sidebar.tpl'} + + +
+ + +
+ + + {include file='navbar.tpl'} + + +
+ + +
+

{$AVATARS}

+ +
+ + + {include file='includes/update.tpl'} + +
+
+ +
+
+
{$EDITING_AVATAR_SOURCE}
+
+
+ + {$BACK} + +
+
+
+ + + {include file='includes/alerts.tpl'} + + {include file=$SETTINGS_TEMPLATE} +
+
+ + +
+ + +
+ + +
+ + {include file='footer.tpl'} + + +
+ + + + + +
+ + {include file='scripts.tpl'} + + + + diff --git a/custom/panel_templates/Default/core/avatar_sources/minecraft.tpl b/custom/panel_templates/Default/core/avatar_sources/minecraft.tpl new file mode 100644 index 0000000000..d9473f85d4 --- /dev/null +++ b/custom/panel_templates/Default/core/avatar_sources/minecraft.tpl @@ -0,0 +1,58 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + diff --git a/custom/panel_templates/Default/core/avatar_sources/uploaded_image.tpl b/custom/panel_templates/Default/core/avatar_sources/uploaded_image.tpl new file mode 100644 index 0000000000..57d228fd42 --- /dev/null +++ b/custom/panel_templates/Default/core/avatar_sources/uploaded_image.tpl @@ -0,0 +1,42 @@ +
+
+ + + +
+
+ + +
+
+ +
+ +{$DEFAULT_AVATAR} + +

+ + + +

+ +{if count($IMAGES)} +
+
+ + +
+
+ + +
+
+{else} + {$NO_AVATARS} +{/if} diff --git a/custom/panel_templates/Default/core/avatars.tpl b/custom/panel_templates/Default/core/avatars.tpl index 252ce28721..f2f106420d 100644 --- a/custom/panel_templates/Default/core/avatars.tpl +++ b/custom/panel_templates/Default/core/avatars.tpl @@ -38,78 +38,59 @@ {include file='includes/alerts.tpl'} - -
-
- - - -
-
- - -
-
- - +
+
+
{$INFO}
+ {$AVATARS_INFO}
-
- - -
-
- - -
- - -
- - {$DEFAULT_AVATAR} - -

- - - -

+
+
- {if count($IMAGES)}
-
- - + isEnabled() || !$source->canBeDisabled() eq 1}checked{/if} {if !$source->canBeDisabled()}disabled{/if} /> + +
+ + +
+
+ +
+ {if $source->getSettings()} + Settings + {/if} +
+ + {/foreach} - -
+ +
- {else} - {$NO_AVATARS} - {/if} - @@ -127,79 +108,49 @@ - - - - - {include file='scripts.tpl'} - - \ No newline at end of file + diff --git a/custom/panel_templates/Default/template.php b/custom/panel_templates/Default/template.php index 402128fce3..f0a78dcb7a 100644 --- a/custom/panel_templates/Default/template.php +++ b/custom/panel_templates/Default/template.php @@ -177,26 +177,6 @@ public function onPageLoad() { break; - case 'avatars': - $this->assets()->include([ - AssetTree::DROPZONE, - AssetTree::IMAGE_PICKER, - ]); - - $this->addJSScript(' - // Dropzone options - Dropzone.options.upload_avatar_dropzone = { - maxFilesize: 2, - dictDefaultMessage: "' . $this->_language->get('admin', 'drag_files_here') . '", - dictInvalidFileType: "' . $this->_language->get('admin', 'invalid_file_type') . '", - dictFileTooBig: "' . $this->_language->get('admin', 'file_too_big') . '" - }; - - $(".image-picker").imagepicker(); - '); - - break; - case 'debugging_and_maintenance': $this->addCSSStyle(' .error_log { diff --git a/custom/templates/DefaultRevamp/template.php b/custom/templates/DefaultRevamp/template.php index 410a120409..ac7d55dfc8 100755 --- a/custom/templates/DefaultRevamp/template.php +++ b/custom/templates/DefaultRevamp/template.php @@ -90,7 +90,6 @@ public function onPageLoad() { 'siteURL' => URL::build('/'), 'fullSiteURL' => URL::getSelfURL() . ltrim(URL::build('/'), '/'), 'page' => PAGE, - 'avatarSource' => AvatarSource::getUrlToFormat(), 'copied' => $this->_language->get('general', 'copied'), 'cookieNotice' => $this->_language->get('general', 'cookie_notice'), 'noMessages' => $this->_language->get('user', 'no_messages'), @@ -114,6 +113,10 @@ public function onPageLoad() { 'csrfToken' => Token::get(), ]; + if (Util::getSetting('mc_integration')) { + $JSVariables['avatarSource'] = MinecraftAvatarSource::getUrlToFormat(); + } + // Logo $cache = new Cache(['name' => 'nameless', 'extension' => '.cache', 'path' => ROOT_PATH . '/cache/']); $cache->setCache('backgroundcache'); diff --git a/custom/templates/DefaultRevamp/user/settings.tpl b/custom/templates/DefaultRevamp/user/settings.tpl index 51f9a02e5f..f318a79017 100755 --- a/custom/templates/DefaultRevamp/user/settings.tpl +++ b/custom/templates/DefaultRevamp/user/settings.tpl @@ -92,7 +92,7 @@ {/if} - {if isset($CUSTOM_AVATARS)} + {if $GRAVATAR_ENABLED}