Replaced "getDetailsByURL" with "getByURL/getByURLForUser"
This commit is contained in:
parent
869f3cfec4
commit
d9c6a46ffe
|
@ -57,7 +57,7 @@ function common_content(App $a)
|
||||||
|
|
||||||
if (DBA::isResult($contact)) {
|
if (DBA::isResult($contact)) {
|
||||||
DI::page()['aside'] = "";
|
DI::page()['aside'] = "";
|
||||||
Model\Profile::load($a, "", Model\Contact::getDetailsByURL($contact["url"]));
|
Model\Profile::load($a, "", Model\Contact::getByURLForUser($contact["url"], 0, [], false));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['self' => true, 'uid' => $uid]);
|
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['self' => true, 'uid' => $uid]);
|
||||||
|
@ -124,7 +124,7 @@ function common_content(App $a)
|
||||||
$entries = [];
|
$entries = [];
|
||||||
foreach ($common_friends as $common_friend) {
|
foreach ($common_friends as $common_friend) {
|
||||||
//get further details of the contact
|
//get further details of the contact
|
||||||
$contact_details = Model\Contact::getDetailsByURL($common_friend['url'], $uid);
|
$contact_details = Model\Contact::getByURLForUser($common_friend['url'], $uid, [], false);
|
||||||
|
|
||||||
// $rr['id'] is needed to use contact_photo_menu()
|
// $rr['id'] is needed to use contact_photo_menu()
|
||||||
/// @TODO Adding '/" here avoids E_NOTICE on missing constants
|
/// @TODO Adding '/" here avoids E_NOTICE on missing constants
|
||||||
|
|
|
@ -164,7 +164,7 @@ function display_fetchauthor($a, $item)
|
||||||
$profiledata["about"] = "";
|
$profiledata["about"] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
$profiledata = Contact::getDetailsByURL($profiledata["url"], local_user(), $profiledata);
|
$profiledata = array_merge($profiledata, Contact::getByURLForUser($profiledata["url"], local_user(), [], false));
|
||||||
|
|
||||||
if (!empty($profiledata["photo"])) {
|
if (!empty($profiledata["photo"])) {
|
||||||
$profiledata["photo"] = DI::baseUrl()->remove($profiledata["photo"]);
|
$profiledata["photo"] = DI::baseUrl()->remove($profiledata["photo"]);
|
||||||
|
|
|
@ -145,7 +145,7 @@ function undo_post_tagging($s) {
|
||||||
if ($cnt) {
|
if ($cnt) {
|
||||||
foreach ($matches as $mtch) {
|
foreach ($matches as $mtch) {
|
||||||
if (in_array($mtch[1], ['!', '@'])) {
|
if (in_array($mtch[1], ['!', '@'])) {
|
||||||
$contact = Contact::getDetailsByURL($mtch[2]);
|
$contact = Contact::getByURL($mtch[2], 0, ['addr'], false);
|
||||||
$mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr'];
|
$mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr'];
|
||||||
}
|
}
|
||||||
$s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s);
|
$s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s);
|
||||||
|
|
|
@ -102,7 +102,7 @@ function match_content(App $a)
|
||||||
'follow' => [DI::l10n()->t("Connect/Follow"), $connlnk]
|
'follow' => [DI::l10n()->t("Connect/Follow"), $connlnk]
|
||||||
];
|
];
|
||||||
|
|
||||||
$contact_details = Contact::getDetailsByURL($profile->url, 0);
|
$contact_details = Contact::getByURL($profile->url, 0, [], false);
|
||||||
|
|
||||||
$entry = [
|
$entry = [
|
||||||
'url' => Contact::magicLink($profile->url),
|
'url' => Contact::magicLink($profile->url),
|
||||||
|
|
|
@ -396,7 +396,7 @@ function message_content(App $a)
|
||||||
$body_e = BBCode::convert($message['body']);
|
$body_e = BBCode::convert($message['body']);
|
||||||
$to_name_e = $message['name'];
|
$to_name_e = $message['name'];
|
||||||
|
|
||||||
$contact = Contact::getDetailsByURL($message['from-url']);
|
$contact = Contact::getByURL($message['from-url'], 0, ['thumb', 'addr'], false);
|
||||||
if (isset($contact["thumb"])) {
|
if (isset($contact["thumb"])) {
|
||||||
$from_photo = $contact["thumb"];
|
$from_photo = $contact["thumb"];
|
||||||
} else {
|
} else {
|
||||||
|
@ -528,7 +528,7 @@ function render_messages(array $msg, $t)
|
||||||
$body_e = $rr['body'];
|
$body_e = $rr['body'];
|
||||||
$to_name_e = $rr['name'];
|
$to_name_e = $rr['name'];
|
||||||
|
|
||||||
$contact = Contact::getDetailsByURL($rr['url']);
|
$contact = Contact::getByURL($rr['url'], 0, ['thumb', 'addr'], false);
|
||||||
if (isset($contact["thumb"])) {
|
if (isset($contact["thumb"])) {
|
||||||
$from_photo = $contact["thumb"];
|
$from_photo = $contact["thumb"];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -331,7 +331,7 @@ function ping_init(App $a)
|
||||||
|
|
||||||
if (DBA::isResult($notifs)) {
|
if (DBA::isResult($notifs)) {
|
||||||
foreach ($notifs as $notif) {
|
foreach ($notifs as $notif) {
|
||||||
$contact = Contact::getDetailsByURL($notif['url']);
|
$contact = Contact::getByURL($notif['url'], 0, ['micro'], false);
|
||||||
if (isset($contact['micro'])) {
|
if (isset($contact['micro'])) {
|
||||||
$notif['photo'] = ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO);
|
$notif['photo'] = ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -104,7 +104,7 @@ function suggest_content(App $a)
|
||||||
'hide' => [DI::l10n()->t('Ignore/Hide'), $ignlnk]
|
'hide' => [DI::l10n()->t('Ignore/Hide'), $ignlnk]
|
||||||
];
|
];
|
||||||
|
|
||||||
$contact_details = Contact::getDetailsByURL($rr["url"], local_user(), $rr);
|
$contact_details = array_merge($rr, Contact::getByURLForUser($rr["url"], local_user(), [], false));
|
||||||
|
|
||||||
$entry = [
|
$entry = [
|
||||||
'url' => Contact::magicLink($rr['url']),
|
'url' => Contact::magicLink($rr['url']),
|
||||||
|
|
|
@ -146,7 +146,7 @@ function unfollow_content(App $a)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
DI::page()['aside'] = '';
|
DI::page()['aside'] = '';
|
||||||
Profile::load($a, '', Contact::getDetailsByURL($contact['url']));
|
Profile::load($a, '', Contact::getByURL($contact['url'], 0, [], false));
|
||||||
|
|
||||||
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), ['$title' => DI::l10n()->t('Status Messages and Posts')]);
|
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), ['$title' => DI::l10n()->t('Status Messages and Posts')]);
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ class Item
|
||||||
// Checking for the alias that is used for OStatus
|
// Checking for the alias that is used for OStatus
|
||||||
$pattern = '/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism';
|
$pattern = '/[@!]\[url\=(.*?)\](.*?)\[\/url\]/ism';
|
||||||
if (preg_match($pattern, $tag, $matches)) {
|
if (preg_match($pattern, $tag, $matches)) {
|
||||||
$data = Contact::getDetailsByURL($matches[1]);
|
$data = Contact::getByURL($matches[1], 0, ['alias', 'nick'], false);
|
||||||
|
|
||||||
if ($data['alias'] != '') {
|
if ($data['alias'] != '') {
|
||||||
$newtag = '@[url=' . $data['alias'] . ']' . $data['nick'] . '[/url]';
|
$newtag = '@[url=' . $data['alias'] . ']' . $data['nick'] . '[/url]';
|
||||||
|
@ -149,15 +149,8 @@ class Item
|
||||||
$name = $nameparts[0];
|
$name = $nameparts[0];
|
||||||
|
|
||||||
// Try to detect the contact in various ways
|
// Try to detect the contact in various ways
|
||||||
if (strpos($name, 'http://')) {
|
if (strpos($name, 'http://') || strpos($name, '@')) {
|
||||||
// At first we have to ensure that the contact exists
|
$contact = Contact::getByURLForUser($name, $profile_uid, []);
|
||||||
Contact::getIdForURL($name);
|
|
||||||
|
|
||||||
// Now we should have something
|
|
||||||
$contact = Contact::getDetailsByURL($name, $profile_uid);
|
|
||||||
} elseif (strpos($name, '@')) {
|
|
||||||
// This function automatically probes when no entry was found
|
|
||||||
$contact = Contact::getDetailsByAddr($name, $profile_uid);
|
|
||||||
} else {
|
} else {
|
||||||
$contact = false;
|
$contact = false;
|
||||||
$fields = ['id', 'url', 'nick', 'name', 'alias', 'network', 'forum', 'prv'];
|
$fields = ['id', 'url', 'nick', 'name', 'alias', 'network', 'forum', 'prv'];
|
||||||
|
|
|
@ -1975,11 +1975,7 @@ class BBCode
|
||||||
*/
|
*/
|
||||||
private static function bbCodeMention2DiasporaCallback($match)
|
private static function bbCodeMention2DiasporaCallback($match)
|
||||||
{
|
{
|
||||||
$contact = Contact::getDetailsByURL($match[3]);
|
$contact = Contact::getByURL($match[3], 0, ['addr']);
|
||||||
|
|
||||||
if (empty($contact['addr'])) {
|
|
||||||
$contact = Probe::uri($match[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($contact['addr'])) {
|
if (empty($contact['addr'])) {
|
||||||
return $match[0];
|
return $match[0];
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Markdown
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = Contact::getDetailsByAddr($matches[3]);
|
$data = Contact::getByURL($matches[3]);
|
||||||
|
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -77,7 +77,7 @@ class Search
|
||||||
// Ensure that we do have a contact entry
|
// Ensure that we do have a contact entry
|
||||||
Contact::getIdForURL($user_data['url'] ?? '');
|
Contact::getIdForURL($user_data['url'] ?? '');
|
||||||
|
|
||||||
$contactDetails = Contact::getDetailsByURL($user_data['url'] ?? '', local_user());
|
$contactDetails = Contact::getByURLForUser($user_data['url'] ?? '', local_user(), [], false);
|
||||||
|
|
||||||
$result = new ContactResult(
|
$result = new ContactResult(
|
||||||
$user_data['name'] ?? '',
|
$user_data['name'] ?? '',
|
||||||
|
@ -143,7 +143,7 @@ class Search
|
||||||
|
|
||||||
foreach ($profiles as $profile) {
|
foreach ($profiles as $profile) {
|
||||||
$profile_url = $profile['url'] ?? '';
|
$profile_url = $profile['url'] ?? '';
|
||||||
$contactDetails = Contact::getDetailsByURL($profile_url, local_user());
|
$contactDetails = Contact::getByURLForUser($profile_url, local_user(), [], false);
|
||||||
|
|
||||||
$result = new ContactResult(
|
$result = new ContactResult(
|
||||||
$profile['name'] ?? '',
|
$profile['name'] ?? '',
|
||||||
|
@ -232,7 +232,7 @@ class Search
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = Contact::getDetailsByURL($row["nurl"], local_user());
|
$contact = Contact::getByURLForUser($row["nurl"], local_user(), [], false);
|
||||||
|
|
||||||
if ($contact["name"] == "") {
|
if ($contact["name"] == "") {
|
||||||
$contact["name"] = end(explode("/", $urlParts["path"]));
|
$contact["name"] = end(explode("/", $urlParts["path"]));
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Introduction extends BaseFactory
|
||||||
$formattedNotifications = [];
|
$formattedNotifications = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/// @todo Fetch contact details by "Contact::getDetailsByUrl" instead of queries to contact, fcontact and gcontact
|
/// @todo Fetch contact details by "Contact::getByUrl" instead of queries to contact, fcontact and gcontact
|
||||||
$stmtNotifications = $this->dba->p(
|
$stmtNotifications = $this->dba->p(
|
||||||
"SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*,
|
"SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*,
|
||||||
`fcontact`.`name` AS `fname`, `fcontact`.`url` AS `furl`, `fcontact`.`addr` AS `faddr`,
|
`fcontact`.`name` AS `fname`, `fcontact`.`url` AS `furl`, `fcontact`.`addr` AS `faddr`,
|
||||||
|
@ -213,7 +213,7 @@ class Introduction extends BaseFactory
|
||||||
// If the network and addr is still not available
|
// If the network and addr is still not available
|
||||||
// get the missing data data from other sources
|
// get the missing data data from other sources
|
||||||
if (empty($intro['gnetwork']) || empty($intro['gaddr'])) {
|
if (empty($intro['gnetwork']) || empty($intro['gaddr'])) {
|
||||||
$ret = Contact::getDetailsByURL($intro['url']);
|
$ret = Contact::getByURL($intro['url'], 0, ['network', 'addr'], false);
|
||||||
|
|
||||||
if (empty($intro['gnetwork']) && !empty($ret['network'])) {
|
if (empty($intro['gnetwork']) && !empty($ret['network'])) {
|
||||||
$intro['gnetwork'] = $ret['network'];
|
$intro['gnetwork'] = $ret['network'];
|
||||||
|
|
|
@ -228,6 +228,37 @@ class Contact
|
||||||
return $contact;
|
return $contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a contact for a given user by a given url.
|
||||||
|
* In difference to "getByURL" the function will fetch a public contact when no user contact had been found.
|
||||||
|
*
|
||||||
|
* @param string $url profile url
|
||||||
|
* @param integer $uid User ID of the contact
|
||||||
|
* @param array $fields Field list
|
||||||
|
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||||
|
* @return array contact array
|
||||||
|
*/
|
||||||
|
public static function getByURLForUser(string $url, int $uid = 0, array $fields = [], $update = null)
|
||||||
|
{
|
||||||
|
if ($uid != 0) {
|
||||||
|
$contact = self::getByURL($url, $uid, $fields, $update);
|
||||||
|
if (!empty($contact)) {
|
||||||
|
if (!empty($contact['id'])) {
|
||||||
|
$contact['cid'] = $contact['id'];
|
||||||
|
$contact['zid'] = 0;
|
||||||
|
}
|
||||||
|
return $contact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = self::getByURL($url, 0, $fields, $update);
|
||||||
|
if (!empty($contact['id'])) {
|
||||||
|
$contact['cid'] = 0;
|
||||||
|
$contact['zid'] = $contact['id'];
|
||||||
|
}
|
||||||
|
return $contact;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if the given contact is a follower
|
* Tests if the given contact is a follower
|
||||||
*
|
*
|
||||||
|
@ -1005,218 +1036,6 @@ class Contact
|
||||||
GContact::updateFromPublicContactURL($contact['url']);
|
GContact::updateFromPublicContactURL($contact['url']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get contact data for a given profile link
|
|
||||||
*
|
|
||||||
* The function looks at several places (contact table and gcontact table) for the contact
|
|
||||||
* It caches its result for the same script execution to prevent duplicate calls
|
|
||||||
*
|
|
||||||
* @param string $url The profile link
|
|
||||||
* @param int $uid User id
|
|
||||||
* @param array $default If not data was found take this data as default value
|
|
||||||
*
|
|
||||||
* @return array Contact data
|
|
||||||
* @throws HTTPException\InternalServerErrorException
|
|
||||||
*/
|
|
||||||
public static function getDetailsByURL($url, $uid = -1, array $default = [])
|
|
||||||
{
|
|
||||||
static $cache = [];
|
|
||||||
|
|
||||||
if ($url == '') {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uid == -1) {
|
|
||||||
$uid = local_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($cache[$url][$uid])) {
|
|
||||||
return $cache[$url][$uid];
|
|
||||||
}
|
|
||||||
|
|
||||||
$ssl_url = str_replace('http://', 'https://', $url);
|
|
||||||
|
|
||||||
$nurl = Strings::normaliseLink($url);
|
|
||||||
|
|
||||||
// Fetch contact data from the contact table for the given user
|
|
||||||
$s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
|
|
||||||
FROM `contact` WHERE `nurl` = ? AND `uid` = ?", $nurl, $uid);
|
|
||||||
$r = DBA::toArray($s);
|
|
||||||
|
|
||||||
// Fetch contact data from the contact table for the given user, checking with the alias
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`
|
|
||||||
FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", $nurl, $url, $ssl_url, $uid);
|
|
||||||
$r = DBA::toArray($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the data from the contact table with "uid=0" (which is filled automatically)
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
|
|
||||||
FROM `contact` WHERE `nurl` = ? AND `uid` = 0", $nurl);
|
|
||||||
$r = DBA::toArray($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the data from the contact table with "uid=0" (which is filled automatically) - checked with the alias
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`
|
|
||||||
FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", $nurl, $url, $ssl_url);
|
|
||||||
$r = DBA::toArray($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the data from the gcontact table
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$s = DBA::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
|
|
||||||
`keywords`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`
|
|
||||||
FROM `gcontact` WHERE `nurl` = ?", $nurl);
|
|
||||||
$r = DBA::toArray($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DBA::isResult($r)) {
|
|
||||||
// If there is more than one entry we filter out the connector networks
|
|
||||||
if (count($r) > 1) {
|
|
||||||
foreach ($r as $id => $result) {
|
|
||||||
if (!in_array($result["network"], Protocol::NATIVE_SUPPORT)) {
|
|
||||||
unset($r[$id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$profile = array_shift($r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($profile)) {
|
|
||||||
$authoritativeResult = true;
|
|
||||||
// "bd" always contains the upcoming birthday of a contact.
|
|
||||||
// "birthday" might contain the birthday including the year of birth.
|
|
||||||
if ($profile["birthday"] > DBA::NULL_DATE) {
|
|
||||||
$bd_timestamp = strtotime($profile["birthday"]);
|
|
||||||
$month = date("m", $bd_timestamp);
|
|
||||||
$day = date("d", $bd_timestamp);
|
|
||||||
|
|
||||||
$current_timestamp = time();
|
|
||||||
$current_year = date("Y", $current_timestamp);
|
|
||||||
$current_month = date("m", $current_timestamp);
|
|
||||||
$current_day = date("d", $current_timestamp);
|
|
||||||
|
|
||||||
$profile["bd"] = $current_year . "-" . $month . "-" . $day;
|
|
||||||
$current = $current_year . "-" . $current_month . "-" . $current_day;
|
|
||||||
|
|
||||||
if ($profile["bd"] < $current) {
|
|
||||||
$profile["bd"] = ( ++$current_year) . "-" . $month . "-" . $day;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$profile["bd"] = DBA::NULL_DATE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$authoritativeResult = false;
|
|
||||||
$profile = $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($profile["photo"]) && isset($default["photo"])) {
|
|
||||||
$profile["photo"] = $default["photo"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($profile["name"]) && isset($default["name"])) {
|
|
||||||
$profile["name"] = $default["name"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($profile["network"]) && isset($default["network"])) {
|
|
||||||
$profile["network"] = $default["network"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($profile["thumb"]) && isset($profile["photo"])) {
|
|
||||||
$profile["thumb"] = $profile["photo"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($profile["micro"]) && isset($profile["thumb"])) {
|
|
||||||
$profile["micro"] = $profile["thumb"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((empty($profile["addr"]) || empty($profile["name"])) && !empty($profile["gid"])
|
|
||||||
&& in_array($profile["network"], Protocol::FEDERATED)
|
|
||||||
) {
|
|
||||||
Worker::add(PRIORITY_LOW, "UpdateGContact", $url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show contact details of Diaspora contacts only if connected
|
|
||||||
if (empty($profile["cid"]) && ($profile["network"] ?? "") == Protocol::DIASPORA) {
|
|
||||||
$profile["location"] = "";
|
|
||||||
$profile["about"] = "";
|
|
||||||
$profile["birthday"] = DBA::NULL_DATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only cache the result if it came from the DB since this method is used in widely different contexts
|
|
||||||
// @see display_fetch_author for an example of $default parameter diverging from the DB result
|
|
||||||
if ($authoritativeResult) {
|
|
||||||
$cache[$url][$uid] = $profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get contact data for a given address
|
|
||||||
*
|
|
||||||
* The function looks at several places (contact table and gcontact table) for the contact
|
|
||||||
*
|
|
||||||
* @param string $addr The profile link
|
|
||||||
* @param int $uid User id
|
|
||||||
*
|
|
||||||
* @return array Contact data
|
|
||||||
* @throws HTTPException\InternalServerErrorException
|
|
||||||
* @throws \ImagickException
|
|
||||||
*/
|
|
||||||
public static function getDetailsByAddr($addr, $uid = -1)
|
|
||||||
{
|
|
||||||
if ($addr == '') {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uid == -1) {
|
|
||||||
$uid = local_user();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch contact data from the contact table for the given user
|
|
||||||
$r = q("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self`, `rel`, `pending`,`baseurl`
|
|
||||||
FROM `contact` WHERE `addr` = '%s' AND `uid` = %d AND NOT `deleted`",
|
|
||||||
DBA::escape($addr),
|
|
||||||
intval($uid)
|
|
||||||
);
|
|
||||||
// Fetch the data from the contact table with "uid=0" (which is filled automatically)
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$r = q("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`,
|
|
||||||
`keywords`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self`, `rel`, `pending`, `baseurl`
|
|
||||||
FROM `contact` WHERE `addr` = '%s' AND `uid` = 0 AND NOT `deleted`",
|
|
||||||
DBA::escape($addr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the data from the gcontact table
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$r = q("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`,
|
|
||||||
`keywords`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self`, 2 AS `rel`, 0 AS `pending`, `server_url` AS `baseurl`
|
|
||||||
FROM `gcontact` WHERE `addr` = '%s'",
|
|
||||||
DBA::escape($addr)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DBA::isResult($r)) {
|
|
||||||
$data = Probe::uri($addr);
|
|
||||||
|
|
||||||
$profile = self::getDetailsByURL($data['url'], $uid, $data);
|
|
||||||
} else {
|
|
||||||
$profile = $r[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the data array for the photo menu of a given contact
|
* Returns the data array for the photo menu of a given contact
|
||||||
*
|
*
|
||||||
|
|
|
@ -111,7 +111,7 @@ class GContact
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$gcontacts[] = Contact::getDetailsByURL($result['nurl'], local_user());
|
$gcontacts[] = Contact::getByURLForUser($result['nurl'], local_user(), [], false);
|
||||||
}
|
}
|
||||||
DBA::close($results);
|
DBA::close($results);
|
||||||
return $gcontacts;
|
return $gcontacts;
|
||||||
|
|
|
@ -63,7 +63,7 @@ class AllFriends extends BaseModule
|
||||||
}
|
}
|
||||||
|
|
||||||
DI::page()['aside'] = "";
|
DI::page()['aside'] = "";
|
||||||
Model\Profile::load($app, "", Model\Contact::getDetailsByURL($contact["url"]));
|
Model\Profile::load($app, "", Model\Contact::getByURL($contact["url"], 0, [], false));
|
||||||
|
|
||||||
$total = Model\GContact::countAllFriends(local_user(), $cid);
|
$total = Model\GContact::countAllFriends(local_user(), $cid);
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class AllFriends extends BaseModule
|
||||||
$entries = [];
|
$entries = [];
|
||||||
foreach ($friends as $friend) {
|
foreach ($friends as $friend) {
|
||||||
//get further details of the contact
|
//get further details of the contact
|
||||||
$contactDetails = Model\Contact::getDetailsByURL($friend['url'], $uid, $friend);
|
$contactDetails = array_merge($friend, Model\Contact::getByURLForUser($friend['url'], $uid, [], false));
|
||||||
|
|
||||||
$connlnk = '';
|
$connlnk = '';
|
||||||
// $friend[cid] is only available for common contacts. So if the contact is a common one, use contact_photo_menu to generate the photoMenu
|
// $friend[cid] is only available for common contacts. So if the contact is a common one, use contact_photo_menu to generate the photoMenu
|
||||||
|
|
|
@ -971,7 +971,7 @@ class Contact extends BaseModule
|
||||||
if (DBA::isResult($contact)) {
|
if (DBA::isResult($contact)) {
|
||||||
DI::page()['aside'] = '';
|
DI::page()['aside'] = '';
|
||||||
|
|
||||||
$profiledata = Model\Contact::getDetailsByURL($contact['url']);
|
$profiledata = Model\Contact::getByURL($contact['url'], 0, [], false);
|
||||||
|
|
||||||
Model\Profile::load($a, '', $profiledata, true);
|
Model\Profile::load($a, '', $profiledata, true);
|
||||||
|
|
||||||
|
@ -994,7 +994,7 @@ class Contact extends BaseModule
|
||||||
if (DBA::isResult($contact)) {
|
if (DBA::isResult($contact)) {
|
||||||
DI::page()['aside'] = '';
|
DI::page()['aside'] = '';
|
||||||
|
|
||||||
$profiledata = Model\Contact::getDetailsByURL($contact['url']);
|
$profiledata = Model\Contact::getByURL($contact['url'], 0, [], false);
|
||||||
|
|
||||||
if (local_user() && in_array($profiledata['network'], Protocol::FEDERATED)) {
|
if (local_user() && in_array($profiledata['network'], Protocol::FEDERATED)) {
|
||||||
$profiledata['remoteconnect'] = DI::baseUrl() . '/follow?url=' . urlencode($profiledata['url']);
|
$profiledata['remoteconnect'] = DI::baseUrl() . '/follow?url=' . urlencode($profiledata['url']);
|
||||||
|
|
|
@ -108,7 +108,7 @@ class Advanced extends BaseModule
|
||||||
throw new BadRequestException(DI::l10n()->t('Contact not found.'));
|
throw new BadRequestException(DI::l10n()->t('Contact not found.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
Model\Profile::load(DI::app(), "", Model\Contact::getDetailsByURL($contact["url"]));
|
Model\Profile::load(DI::app(), "", Model\Contact::getByURL($contact["url"], 0, [], false));
|
||||||
|
|
||||||
$warning = DI::l10n()->t('<strong>WARNING: This is highly advanced</strong> and if you enter incorrect information your communications with this contact may stop working.');
|
$warning = DI::l10n()->t('<strong>WARNING: This is highly advanced</strong> and if you enter incorrect information your communications with this contact may stop working.');
|
||||||
$info = DI::l10n()->t('Please use your browser \'Back\' button <strong>now</strong> if you are uncertain what to do on this page.');
|
$info = DI::l10n()->t('Please use your browser \'Back\' button <strong>now</strong> if you are uncertain what to do on this page.');
|
||||||
|
|
|
@ -58,31 +58,16 @@ class Hovercard extends BaseModule
|
||||||
$contact = [];
|
$contact = [];
|
||||||
|
|
||||||
// if it's the url containing https it should be converted to http
|
// if it's the url containing https it should be converted to http
|
||||||
$contact_nurl = Strings::normaliseLink(GContact::cleanContactUrl($contact_url));
|
if (!$contact_url) {
|
||||||
if (!$contact_nurl) {
|
|
||||||
throw new HTTPException\BadRequestException();
|
throw new HTTPException\BadRequestException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for contact data
|
// Search for contact data
|
||||||
// Look if the local user has got the contact
|
// Look if the local user has got the contact
|
||||||
if (Session::isAuthenticated()) {
|
if (Session::isAuthenticated()) {
|
||||||
$contact = Contact::getDetailsByURL($contact_nurl, local_user());
|
$contact = Contact::getByURLForUser($contact_url, local_user(), [], false);
|
||||||
}
|
} else {
|
||||||
|
$contact = Contact::getByURL($contact_url, 0, [], false);
|
||||||
// If not then check the global user
|
|
||||||
if (!count($contact)) {
|
|
||||||
$contact = Contact::getDetailsByURL($contact_nurl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feeds url could have been destroyed through "cleanContactUrl", so we now use the original url
|
|
||||||
if (!count($contact) && Session::isAuthenticated()) {
|
|
||||||
$contact_nurl = Strings::normaliseLink($contact_url);
|
|
||||||
$contact = Contact::getDetailsByURL($contact_nurl, local_user());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!count($contact)) {
|
|
||||||
$contact_nurl = Strings::normaliseLink($contact_url);
|
|
||||||
$contact = Contact::getDetailsByURL($contact_nurl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!count($contact)) {
|
if (!count($contact)) {
|
||||||
|
@ -110,7 +95,7 @@ class Hovercard extends BaseModule
|
||||||
'about' => $contact['about'],
|
'about' => $contact['about'],
|
||||||
'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']),
|
'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']),
|
||||||
'tags' => $contact['keywords'],
|
'tags' => $contact['keywords'],
|
||||||
'bd' => $contact['birthday'] <= DBA::NULL_DATE ? '' : $contact['birthday'],
|
'bd' => $contact['bd'] <= DBA::NULL_DATE ? '' : $contact['bd'],
|
||||||
'account_type' => Contact::getAccountType($contact),
|
'account_type' => Contact::getAccountType($contact),
|
||||||
'actions' => $actions,
|
'actions' => $actions,
|
||||||
],
|
],
|
||||||
|
|
|
@ -138,7 +138,7 @@ class Poke extends BaseModule
|
||||||
throw new HTTPException\NotFoundException();
|
throw new HTTPException\NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
Model\Profile::load(DI::app(), '', Model\Contact::getDetailsByURL($contact["url"]));
|
Model\Profile::load(DI::app(), '', Model\Contact::getByURL($contact["url"], 0, [], false));
|
||||||
|
|
||||||
$verbs = [];
|
$verbs = [];
|
||||||
foreach (DI::l10n()->getPokeVerbs() as $verb => $translations) {
|
foreach (DI::l10n()->getPokeVerbs() as $verb => $translations) {
|
||||||
|
|
|
@ -103,7 +103,7 @@ class Contacts extends BaseProfile
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact_details = Contact::getDetailsByURL($contact['url'], $a->profile['uid'], $contact);
|
$contact_details = array_merge($contact, Contact::getByURLForUser($contact['url'], $a->profile['uid'], [], false));
|
||||||
|
|
||||||
$contacts[] = [
|
$contacts[] = [
|
||||||
'id' => $contact['id'],
|
'id' => $contact['id'],
|
||||||
|
|
|
@ -350,7 +350,7 @@ class Acl extends BaseModule
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = Contact::getDetailsByURL($author);
|
$contact = Contact::getByURL($author, 0, ['micro', 'name', 'id', 'network', 'nick', 'addr', 'url', 'forum'], false);
|
||||||
|
|
||||||
if (count($contact) > 0) {
|
if (count($contact) > 0) {
|
||||||
$unknown_contacts[] = [
|
$unknown_contacts[] = [
|
||||||
|
|
|
@ -237,13 +237,13 @@ class Index extends BaseSearch
|
||||||
} else {
|
} else {
|
||||||
// Cheaper local lookup for anonymous users, no probe
|
// Cheaper local lookup for anonymous users, no probe
|
||||||
if ($isAddr) {
|
if ($isAddr) {
|
||||||
$contact = Contact::selectFirst(['id' => 'cid'], ['addr' => $search, 'uid' => 0]);
|
$contact = Contact::selectFirst(['id'], ['addr' => $search, 'uid' => 0]);
|
||||||
} else {
|
} else {
|
||||||
$contact = Contact::getDetailsByURL($search, 0, ['cid' => 0]);
|
$contact = array_merge(['id' => 0], Contact::getByURL($search, 0, ['id']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBA::isResult($contact)) {
|
if (DBA::isResult($contact)) {
|
||||||
$contact_id = $contact['cid'];
|
$contact_id = $contact['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -877,7 +877,7 @@ class Post
|
||||||
|
|
||||||
$terms = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]);
|
$terms = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]);
|
||||||
foreach ($terms as $term) {
|
foreach ($terms as $term) {
|
||||||
$profile = Contact::getDetailsByURL($term['url']);
|
$profile = Contact::getByURL($term['url'], 0, ['addr', 'contact-type'], false);
|
||||||
if (!empty($profile['addr']) && ((($profile['contact-type'] ?? '') ?: Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) &&
|
if (!empty($profile['addr']) && ((($profile['contact-type'] ?? '') ?: Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) &&
|
||||||
($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])) {
|
($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])) {
|
||||||
$text .= '@' . $profile['addr'] . ' ';
|
$text .= '@' . $profile['addr'] . ' ';
|
||||||
|
|
|
@ -987,7 +987,7 @@ class Processor
|
||||||
{
|
{
|
||||||
$parent_terms = Tag::getByURIId($parent['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]);
|
$parent_terms = Tag::getByURIId($parent['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]);
|
||||||
|
|
||||||
$parent_author = Contact::getDetailsByURL($parent['author-link'], 0);
|
$parent_author = Contact::getByURL($parent['author-link'], 0, ['url', 'nurl', 'alias'], false);
|
||||||
|
|
||||||
$implicit_mentions = [];
|
$implicit_mentions = [];
|
||||||
if (empty($parent_author['url'])) {
|
if (empty($parent_author['url'])) {
|
||||||
|
@ -1003,7 +1003,7 @@ class Processor
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($parent_terms as $term) {
|
foreach ($parent_terms as $term) {
|
||||||
$contact = Contact::getDetailsByURL($term['url'], 0);
|
$contact = Contact::getByURL($term['url'], 0, ['url', 'nurl', 'alias'], false);
|
||||||
if (!empty($contact['url'])) {
|
if (!empty($contact['url'])) {
|
||||||
$implicit_mentions[] = $contact['url'];
|
$implicit_mentions[] = $contact['url'];
|
||||||
$implicit_mentions[] = $contact['nurl'];
|
$implicit_mentions[] = $contact['nurl'];
|
||||||
|
|
|
@ -1008,7 +1008,7 @@ class Transmitter
|
||||||
$url = DI::baseUrl() . '/search?tag=' . urlencode($term['name']);
|
$url = DI::baseUrl() . '/search?tag=' . urlencode($term['name']);
|
||||||
$tags[] = ['type' => 'Hashtag', 'href' => $url, 'name' => '#' . $term['name']];
|
$tags[] = ['type' => 'Hashtag', 'href' => $url, 'name' => '#' . $term['name']];
|
||||||
} else {
|
} else {
|
||||||
$contact = Contact::getDetailsByURL($term['url']);
|
$contact = Contact::getByURL($term['url'], 0, ['addr'], false);
|
||||||
if (!empty($contact['addr'])) {
|
if (!empty($contact['addr'])) {
|
||||||
$mention = '@' . $contact['addr'];
|
$mention = '@' . $contact['addr'];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1141,7 +1141,7 @@ class Transmitter
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = Contact::getDetailsByURL($match[1]);
|
$data = Contact::getByURL($match[1], 0, ['url', 'nick'], false);
|
||||||
if (empty($data['nick'])) {
|
if (empty($data['nick'])) {
|
||||||
return $match[0];
|
return $match[0];
|
||||||
}
|
}
|
||||||
|
@ -1861,7 +1861,7 @@ class Transmitter
|
||||||
$mentions = [];
|
$mentions = [];
|
||||||
|
|
||||||
foreach (Tag::getByURIId($uriid, [Tag::IMPLICIT_MENTION]) as $tag) {
|
foreach (Tag::getByURIId($uriid, [Tag::IMPLICIT_MENTION]) as $tag) {
|
||||||
$profile = Contact::getDetailsByURL($tag['url']);
|
$profile = Contact::getByURL($tag['url'], 0, ['addr', 'contact-type', 'nick'], false);
|
||||||
if (!empty($profile['addr'])
|
if (!empty($profile['addr'])
|
||||||
&& $profile['contact-type'] != Contact::TYPE_COMMUNITY
|
&& $profile['contact-type'] != Contact::TYPE_COMMUNITY
|
||||||
&& !strstr($body, $profile['addr'])
|
&& !strstr($body, $profile['addr'])
|
||||||
|
|
|
@ -755,7 +755,7 @@ class DFRN
|
||||||
{
|
{
|
||||||
$author = $doc->createElement($element);
|
$author = $doc->createElement($element);
|
||||||
|
|
||||||
$contact = Contact::getDetailsByURL($contact_url, $item["uid"]);
|
$contact = Contact::getByURLForUser($contact_url, $item["uid"], ['url', 'name', 'addr', 'photo']);
|
||||||
if (!empty($contact)) {
|
if (!empty($contact)) {
|
||||||
XML::addElement($doc, $author, "name", $contact["name"]);
|
XML::addElement($doc, $author, "name", $contact["name"]);
|
||||||
XML::addElement($doc, $author, "uri", $contact["url"]);
|
XML::addElement($doc, $author, "uri", $contact["url"]);
|
||||||
|
|
|
@ -1568,7 +1568,7 @@ class Diaspora
|
||||||
*/
|
*/
|
||||||
private static function plink($addr, $guid, $parent_guid = '')
|
private static function plink($addr, $guid, $parent_guid = '')
|
||||||
{
|
{
|
||||||
$contact = Contact::getDetailsByAddr($addr);
|
$contact = Contact::getByURL($addr);
|
||||||
if (empty($contact)) {
|
if (empty($contact)) {
|
||||||
Logger::info('No contact data for address', ['addr' => $addr]);
|
Logger::info('No contact data for address', ['addr' => $addr]);
|
||||||
return '';
|
return '';
|
||||||
|
@ -3729,7 +3729,7 @@ class Diaspora
|
||||||
|
|
||||||
private static function prependParentAuthorMention($body, $profile_url)
|
private static function prependParentAuthorMention($body, $profile_url)
|
||||||
{
|
{
|
||||||
$profile = Contact::getDetailsByURL($profile_url);
|
$profile = Contact::getByURL($profile_url, 0, ['addr', 'name', 'contact-type'], false);
|
||||||
if (!empty($profile['addr'])
|
if (!empty($profile['addr'])
|
||||||
&& $profile['contact-type'] != Contact::TYPE_COMMUNITY
|
&& $profile['contact-type'] != Contact::TYPE_COMMUNITY
|
||||||
&& !strstr($body, $profile['addr'])
|
&& !strstr($body, $profile['addr'])
|
||||||
|
|
|
@ -177,7 +177,7 @@ class Profiler implements ContainerInterface
|
||||||
$output .= "\nDatabase Read:\n";
|
$output .= "\nDatabase Read:\n";
|
||||||
foreach ($this->callstack["database"] as $func => $time) {
|
foreach ($this->callstack["database"] as $func => $time) {
|
||||||
$time = round($time, 3);
|
$time = round($time, 3);
|
||||||
if ($time > 0) {
|
if ($time > 0.001) {
|
||||||
$output .= $func . ": " . $time . "\n";
|
$output .= $func . ": " . $time . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue