From ace7a22c2f404a34bcf134187b3d5b199dda2da2 Mon Sep 17 00:00:00 2001 From: ralf Date: Wed, 10 May 2023 09:49:42 +0200 Subject: [PATCH] * Mail: performance improvements for huge addressbooks by caching avatars --- api/src/Mail/Avatar.php | 82 ++++++++++++++++++++++++++++++++++ mail/inc/class.mail_ui.inc.php | 27 +++-------- 2 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 api/src/Mail/Avatar.php diff --git a/api/src/Mail/Avatar.php b/api/src/Mail/Avatar.php new file mode 100644 index 0000000000..890115b8c5 --- /dev/null +++ b/api/src/Mail/Avatar.php @@ -0,0 +1,82 @@ + + * @license https://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + */ + +namespace EGroupware\Api\Mail; + +use EGroupware\Api; + +/** + * Class for managing avatars for email addresses including proper caching + */ +class Avatar +{ + const CACHE_TIME = 86400; + + /** + * Get (cached) avatar URL for given email + * + * @param string $email + * @param array|null &$lavatar on return values for keys "lname" and "fname" + * @return string|null + * @ToDo add a domain based image as fallback eg. as fallback from their website + */ + static function getAvatar(string $address, array &$lavatar=null) + { + if (empty($address)) + { + return $lavatar = null; + } + $email = strtolower(current(Api\Mail::stripRFC822Addresses([$address]))); + + // we cache on instance level, but also add current user to the key, as not all users might see the same contacts + $cached = Api\Cache::getInstance(__CLASS__, $GLOBALS['egw_info']['user']['account_id'].'-'.$email, + static function($email, $address) + { + if (($contacts = $GLOBALS['egw']->contacts->search(['contact_email' => $email, 'contact_email_home' => $email], + ['contact_id', 'email', 'email_home', 'n_fn', 'n_given', 'n_family'], '', '', '', false, 'OR', false))) + { + return [$contacts[0]['photo'], ['lname' => $contacts[0]['n_family'], 'fname' => $contacts[0]['n_given']]]; + } + return [1 => self::getLavatar($address)]; + }, [$email, $address], self::CACHE_TIME); + + $lavatar = $cached[1] ?? null; + + return $cached[0] ?? null; + } + + /** + * Get (L)etter avatar from given email address + * + * @param string $address + * @return string[] with values for keys "fname" and (optional) "lname" + * - "Ralf Becker " --> ["fname" => "Ralf", "lname" => "Becker"] + * - "'Becker, Ralf' --> dito + * - "ralf.becker@egroupware.org" --> dito + * - "rb@egroupware.org" --> ["fname" --> "r", "lname" => "b"] + */ + static function getLavatar(string $address) : array + { + if (preg_match("/^\"?'?(.*)'?\"?\s+<([^<>'\"]+)>$/", $address, $matches)) + { + if (($parts = preg_split('/[, ]+/', $matches[1]))) + { + return ['fname' => array_shift($parts), 'lname' => array_pop($parts)]; + } + $address = $matches[2]; + } + if (($parts = preg_split('/[._]/', $address)) && count($parts) >= 2) + { + return ['fname' => array_shift($parts), 'lname' => array_pop($parts)]; + } + return ['fname' => $address[0], 'lname' => $address[1]]; + } +} \ No newline at end of file diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 9ed3b175f7..e5a5fc9e44 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -1955,8 +1955,6 @@ $filter['before']= date("d-M-Y", $cutoffdate2); if(!empty($header['label3'])) $flags .= "3"; if(!empty($header['label4'])) $flags .= "4"; if(!empty($header['label5'])) $flags .= "5"; - - $data["status"] = ""; //error_log(__METHOD__.array2string($header).' Flags:'.$flags); // the css for this row @@ -2131,30 +2129,17 @@ $filter['before']= date("d-M-Y", $cutoffdate2); $data['attachmentsBlock'] = $imageHTMLBlock; if ($_folderType) { - $fromcontact = self::getContactFromAddress($data['fromaddress']); - if(!empty($fromcontact) && $fromcontact[0]['photo']) - { - $data['fromavatar'] = $fromcontact[0]['photo']; - } + $data['fromavatar'] = Api\Mail\Avatar::getAvatar($data['fromaddress']); } - $data['address'] = ($_folderType ? $data["toaddress"] : $data["fromaddress"]); - $data['lavatar'] = ['fname' => $data['address']]; + $data['address'] = $_folderType ? $data["toaddress"] : $data["fromaddress"]; + $data['lavatar'] = Api\Mail\Avatar::getLavatar($data['address']); - $contact = self::getContactFromAddress($data['address']); - if(!empty($contact)) + if (($data['avatar'] = Api\Mail\Avatar::getAvatar($data['address'], $data['lavatar'])) && !$_folderType) { - $data['lavatar'] = ['fname' => $contact[0]['n_given'], 'lname' => $contact[0]['n_family']]; - if($contact[0]['photo']) - { - $data['avatar'] = $contact[0]['photo']; - } - if(!$_folderType) - { - $data['fromavatar'] = $data['avatar']; - } + $data['fromavatar'] = $data['avatar']; } - if (in_array("bodypreview", $cols)&&$header['bodypreview']) + if (in_array("bodypreview", $cols) && $header['bodypreview']) { $data["bodypreview"] = $header['bodypreview']; }