use Friendica\Core\Worker;
use Friendica\Database\DBM;
use Friendica\Network\Probe;
+use Friendica\Object\Photo;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\OStatus;
+use Friendica\Protocol\Salmon;
use dba;
require_once 'boot.php';
require_once 'include/text.php';
+/**
+ * @brief functions for interacting with a contact
+ */
class Contact extends BaseObject
{
+ /**
+ * Creates the self-contact for the provided user id
+ *
+ * @param int $uid
+ * @return bool Operation success
+ */
+ public static function createSelfFromUserId($uid)
+ {
+ // Only create the entry if it doesn't exist yet
+ if (dba::exists('contact', ['uid' => intval($uid), 'self'])) {
+ return true;
+ }
+
+ $user = dba::select('user', ['uid', 'username', 'nickname'], ['uid' => intval($uid)], ['limit' => 1]);
+ if (!DBM::is_result($user)) {
+ return false;
+ }
+
+ $return = dba::insert('contact', [
+ 'uid' => $user['uid'],
+ 'created' => datetime_convert(),
+ 'self' => 1,
+ 'name' => $user['username'],
+ 'nick' => $user['nickname'],
+ 'photo' => System::baseUrl() . '/photo/profile/' . $user['uid'] . '.jpg',
+ 'thumb' => System::baseUrl() . '/photo/avatar/' . $user['uid'] . '.jpg',
+ 'micro' => System::baseUrl() . '/photo/micro/' . $user['uid'] . '.jpg',
+ 'blocked' => 0,
+ 'pending' => 0,
+ 'url' => System::baseUrl() . '/profile/' . $user['nickname'],
+ 'nurl' => normalise_link(System::baseUrl() . '/profile/' . $user['nickname']),
+ 'addr' => $user['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3),
+ 'request' => System::baseUrl() . '/dfrn_request/' . $user['nickname'],
+ 'notify' => System::baseUrl() . '/dfrn_notify/' . $user['nickname'],
+ 'poll' => System::baseUrl() . '/dfrn_poll/' . $user['nickname'],
+ 'confirm' => System::baseUrl() . '/dfrn_confirm/' . $user['nickname'],
+ 'poco' => System::baseUrl() . '/poco/' . $user['nickname'],
+ 'name-date' => datetime_convert(),
+ 'uri-date' => datetime_convert(),
+ 'avatar-date' => datetime_convert(),
+ 'closeness' => 0
+ ]);
+
+ return $return;
+ }
+
/**
* @brief Marks a contact for removal
*
- * @param int $id
+ * @param int $id contact id
* @return null
*/
public static function remove($id)
{
// We want just to make sure that we don't delete our "self" contact
- $r = q(
- "SELECT `uid` FROM `contact` WHERE `id` = %d AND NOT `self` LIMIT 1", intval($id)
- );
- if (!DBM::is_result($r) || !intval($r[0]['uid'])) {
+ $r = dba::select('contact', array('uid'), array('id' => $id, 'self' => false), array('limit' => 1));
+
+ if (!DBM::is_result($r) || !intval($r['uid'])) {
return;
}
- $archive = PConfig::get($r[0]['uid'], 'system', 'archive_removed_contacts');
+ $archive = PConfig::get($r['uid'], 'system', 'archive_removed_contacts');
if ($archive) {
- q(
- "UPDATE `contact` SET `archive` = 1, `network` = 'none', `writable` = 0 WHERE id = %d", intval($id)
- );
+ dba::update('contact', array('archive' => true, 'network' => 'none', 'writable' => false), array('id' => $id));
return;
}
/**
* @brief Sends an unfriend message. Does not remove the contact
*
- * @param array $user User unfriending
+ * @param array $user User unfriending
* @param array $contact Contact unfriended
+ * @return void
*/
public static function terminateFriendship(array $user, array $contact)
{
$slap = OStatus::salmon($item, $user);
if ((x($contact, 'notify')) && (strlen($contact['notify']))) {
- require_once 'include/salmon.php';
- slapper($user, $contact['notify'], $slap);
+ Salmon::slapper($user, $contact['notify'], $slap);
}
} elseif ($contact['network'] === NETWORK_DIASPORA) {
Diaspora::sendUnshare($user, $contact);
* This provides for the possibility that their database is temporarily messed
* up or some other transient event and that there's a possibility we could recover from it.
*
- * @param array $contact
+ * @param array $contact contact to mark for archival
* @return type
*/
public static function markForArchival(array $contact)
{
- // Contact already archived, nothing to do
- if ($contact['archive']) {
+ // Contact already archived or "self" contact? => nothing to do
+ if ($contact['archive'] || $contact['self']) {
return;
}
if ($contact['term-date'] <= NULL_DATE) {
- q(
- "UPDATE `contact` SET `term-date` = '%s' WHERE `id` = %d", dbesc(datetime_convert()), intval($contact['id'])
- );
+ dba::update('contact', array('term-date' => datetime_convert()), array('id' => $contact['id']));
if ($contact['url'] != '') {
- q(
- "UPDATE `contact` SET `term-date` = '%s'
- WHERE `nurl` = '%s' AND `term-date` <= '1000-00-00'", dbesc(datetime_convert()), dbesc(normalise_link($contact['url']))
- );
+ dba::update('contact', array('term-date' => datetime_convert()), array('`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), NULL_DATE));
}
} else {
-
/* @todo
* We really should send a notification to the owner after 2-3 weeks
* so they won't be surprised when the contact vanishes and can take
/// @todo Check for contact vitality via probing
$expiry = $contact['term-date'] . ' + 32 days ';
if (datetime_convert() > datetime_convert('UTC', 'UTC', $expiry)) {
-
/* Relationship is really truly dead. archive them rather than
* delete, though if the owner tries to unarchive them we'll start
* the whole process over again.
*/
- q(
- "UPDATE `contact` SET `archive` = 1 WHERE `id` = %d", intval($contact['id'])
- );
+ dba::update('contact', array('archive' => 1), array('id' => $contact['id']));
if ($contact['url'] != '') {
- q(
- "UPDATE `contact` SET `archive` = 1 WHERE `nurl` = '%s'", dbesc(normalise_link($contact['url']))
- );
+ dba::update('contact', array('archive' => 1), array('nurl' => normalise_link($contact['url']), 'self' => false));
}
}
}
*
* @see Contact::markForArchival()
*
- * @param array $contact
+ * @param array $contact contact to be unmarked for archival
* @return null
*/
public static function unmarkForArchival(array $contact)
{
- $r = q(
- "SELECT `term-date` FROM `contact` WHERE `id` = %d AND (`term-date` > '%s' OR `archive`)", intval($contact['id']), dbesc('1000-00-00 00:00:00')
- );
+ $condition = array('`id` = ? AND (`term-date` > ? OR `archive`)', $contact['id'], NULL_DATE);
+ $exists = dba::exists('contact', $condition);
// We don't need to update, we never marked this contact for archival
- if (!DBM::is_result($r)) {
+ if (!$exists) {
return;
}
* 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
+ * @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
*/
if (DBM::is_result($r)) {
// If there is more than one entry we filter out the connector networks
if (count($r) > 1) {
- foreach ($r AS $id => $result) {
+ foreach ($r as $id => $result) {
if ($result["network"] == NETWORK_STATUSNET) {
unset($r[$id]);
}
$profile["micro"] = $profile["thumb"];
}
- if ((($profile["addr"] == "") || ($profile["name"] == "")) && ($profile["gid"] != 0) &&
- in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
+ if ((($profile["addr"] == "") || ($profile["name"] == "")) && ($profile["gid"] != 0)
+ && in_array($profile["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))
+ ) {
Worker::add(PRIORITY_LOW, "UpdateGContact", $profile["gid"]);
}
* 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
+ * @param int $uid User id
*
* @return array Contact data
*/
/**
* @brief Returns the data array for the photo menu of a given contact
*
- * @param array $contact
- * @param int $uid
+ * @param array $contact contact
+ * @param int $uid optional, default 0
* @return array
*/
public static function photoMenu(array $contact, $uid = 0)
if ($contact['uid'] != $uid) {
if ($uid == 0) {
$profile_link = zrl($contact['url']);
- $menu = Array('profile' => array(t('View Profile'), $profile_link, true));
+ $menu = array('profile' => array(t('View Profile'), $profile_link, true));
return $menu;
}
- $r = q("SELECT * FROM `contact` WHERE `nurl` = '%s' AND `network` = '%s' AND `uid` = %d", dbesc($contact['nurl']), dbesc($contact['network']), intval($uid));
+ $r = dba::select('contact', array(), array('nurl' => $contact['nurl'], 'network' => $contact['network'], 'uid' => $uid), array('limit' => 1));
if ($r) {
- return self::photoMenu($r[0], $uid);
+ return self::photoMenu($r, $uid);
} else {
$profile_link = zrl($contact['url']);
$connlnk = 'follow/?url=' . $contact['url'];
$contact_drop_link = System::baseUrl() . '/contacts/' . $contact['id'] . '/drop?confirm=1';
/**
- * menu array:
+ * Menu array:
* "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
*/
$menu = array(
$menucondensed = array();
- foreach ($menu AS $menuname => $menuitem) {
+ foreach ($menu as $menuname => $menuitem) {
if ($menuitem[1] != '') {
$menucondensed[$menuname] = $menuitem;
}
}
/**
+ * @brief Returns ungrouped contact count or list for user
+ *
* Returns either the total number of ungrouped contacts for the given user
* id or a paginated list of ungrouped contacts.
*
- * @brief Returns ungrouped contact count or list for user
+ * @param int $uid uid
+ * @param int $start optional, default 0
+ * @param int $count optional, default 0
*
- * @param int $uid
- * @param int $start
- * @param int $count
* @return array
*/
public static function getUngroupedList($uid, $start = 0, $count = 0)
"SELECT COUNT(*) AS `total`
FROM `contact`
WHERE `uid` = %d
- AND `self` = 0
+ AND NOT `self`
+ AND NOT `blocked`
+ AND NOT `pending`
AND `id` NOT IN (
SELECT DISTINCT(`contact-id`)
FROM `group_member`
WHERE `uid` = %d
- ) ", intval($uid), intval($uid)
+ )", intval($uid), intval($uid)
);
return $r;
"SELECT *
FROM `contact`
WHERE `uid` = %d
- AND `self` = 0
+ AND NOT `self`
+ AND NOT `blocked`
+ AND NOT `pending`
AND `id` NOT IN (
SELECT DISTINCT(`contact-id`)
FROM `group_member` WHERE `uid` = %d
)
- AND `blocked` = 0
- AND `pending` = 0
LIMIT %d, %d", intval($uid), intval($uid), intval($start), intval($count)
);
-
return $r;
}
* Fourth, we update the existing record with the new data (avatar, alias, nick)
* if there's any updates
*
- * @param string $url Contact URL
- * @param integer $uid The user id for the contact (0 = public contact)
+ * @param string $url Contact URL
+ * @param integer $uid The user id for the contact (0 = public contact)
* @param boolean $no_update Don't update the contact
*
* @return integer Contact ID
if (!DBM::is_result($contact)) {
// The link could be provided as http although we stored it as https
$ssl_url = str_replace('http://', 'https://', $url);
- $r = dba::p("SELECT `id`, `avatar-date` FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ? LIMIT 1", $url, normalise_link($url), $ssl_url, $uid);
+ $r = dba::select('contact', array('id', 'avatar-date'), array('`alias` IN (?, ?, ?) AND `uid` = ?', $url, normalise_link($url), $ssl_url, $uid), array('limit' => 1));
$contact = dba::fetch($r);
dba::close($r);
}
$url = $data["url"];
if (!$contact_id) {
- dba::insert('contact', array('uid' => $uid, 'created' => datetime_convert(), 'url' => $data["url"],
+ dba::insert(
+ 'contact', array('uid' => $uid, 'created' => datetime_convert(), 'url' => $data["url"],
'nurl' => normalise_link($data["url"]), 'addr' => $data["addr"],
'alias' => $data["alias"], 'notify' => $data["notify"], 'poll' => $data["poll"],
'name' => $data["name"], 'nick' => $data["nick"], 'photo' => $data["photo"],
'confirm' => $data["confirm"], 'poco' => $data["poco"],
'name-date' => datetime_convert(), 'uri-date' => datetime_convert(),
'avatar-date' => datetime_convert(), 'writable' => 1, 'blocked' => 0,
- 'readonly' => 0, 'pending' => 0));
+ 'readonly' => 0, 'pending' => 0)
+ );
- $contacts = q("SELECT `id` FROM `contact` WHERE `nurl` = '%s' AND `uid` = %d ORDER BY `id` LIMIT 2", dbesc(normalise_link($data["url"])), intval($uid));
+ $s = dba::select('contact', array('id'), array('nurl' => normalise_link($data["url"]), 'uid' => $uid), array('order' => array('id'), 'limit' => 2));
+ $contacts = dba::inArray($s);
if (!DBM::is_result($contacts)) {
return 0;
}
}
}
- require_once 'include/Photo.php';
+ self::updateAvatar($data["photo"], $uid, $contact_id);
- update_contact_avatar($data["photo"], $uid, $contact_id);
-
- $contact = dba::select('contact', array('url', 'nurl', 'addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date'), array('id' => $contact_id), array('limit' => 1));
+ $fields = array('url', 'nurl', 'addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date', 'pubkey');
+ $contact = dba::select('contact', $fields, array('id' => $contact_id), array('limit' => 1));
// This condition should always be true
if (!DBM::is_result($contact)) {
'name' => $data['name'],
'nick' => $data['nick']);
+ // Only fill the pubkey if it was empty before. We have to prevent identity theft.
+ if (!empty($contact['pubkey'])) {
+ unset($contact['pubkey']);
+ } else {
+ $updated['pubkey'] = $data['pubkey'];
+ }
+
if ($data['keywords'] != '') {
$updated['keywords'] = $data['keywords'];
}
/**
* @brief Returns posts from a given contact url
*
- * @param App $a argv application class
* @param string $contact_url Contact URL
*
* @return string posts in HTML
*/
public static function getPostsFromUrl($contact_url)
{
+ $a = self::getApp();
+
require_once 'include/conversation.php';
// There are no posts with "uid = 0" with connector networks
// This speeds up the query a lot
$r = q("SELECT `network`, `id` AS `author-id`, `contact-type` FROM `contact`
- WHERE `contact`.`nurl` = '%s' AND `contact`.`uid` = 0", dbesc(normalise_link($contact_url)));
+ WHERE `contact`.`nurl` = '%s' AND `contact`.`uid` = 0", dbesc(normalise_link($contact_url)));
if (!DBM::is_result($r)) {
return '';
" ORDER BY `item`.`created` DESC LIMIT %d, %d", intval($author_id), intval(local_user()), intval($a->pager['start']), intval($a->pager['itemspage'])
);
- $a = self::getApp();
$o = conversation($a, $r, 'community', false);
// "page-flags" is a field in the user table,
// "forum" and "prv" are used in the contact table. They stand for PAGE_COMMUNITY and PAGE_PRVGROUP.
// "community" is used in the gcontact table and is true if the contact is PAGE_COMMUNITY or PAGE_PRVGROUP.
- if (
- (isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_COMMUNITY))
+ if ((isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_COMMUNITY))
|| (isset($contact['page-flags']) && (intval($contact['page-flags']) == PAGE_PRVGROUP))
|| (isset($contact['forum']) && intval($contact['forum']))
|| (isset($contact['prv']) && intval($contact['prv']))
return $account_type;
}
+
+ /**
+ * @brief Blocks a contact
+ *
+ * @param int $uid
+ * @return bool
+ */
+ public static function block($uid)
+ {
+ $return = dba::update('contact', ['blocked' => true], ['id' => $uid]);
+
+ return $return;
+ }
+
+ /**
+ * @brief Unblocks a contact
+ *
+ * @param int $uid
+ * @return bool
+ */
+ public static function unblock($uid)
+ {
+ $return = dba::update('contact', ['blocked' => false], ['id' => $uid]);
+
+ return $return;
+ }
+
+ /**
+ * @brief Updates the avatar links in a contact only if needed
+ *
+ * @param string $avatar Link to avatar picture
+ * @param int $uid User id of contact owner
+ * @param int $cid Contact id
+ * @param bool $force force picture update
+ *
+ * @return array Returns array of the different avatar sizes
+ */
+ public static function updateAvatar($avatar, $uid, $cid, $force = false)
+ {
+ // Limit = 1 returns the row so no need for dba:inArray()
+ $r = dba::select('contact', array('avatar', 'photo', 'thumb', 'micro', 'nurl'), array('id' => $cid), array('limit' => 1));
+ if (!DBM::is_result($r)) {
+ return false;
+ } else {
+ $data = array($r["photo"], $r["thumb"], $r["micro"]);
+ }
+
+ if (($r["avatar"] != $avatar) || $force) {
+ $photos = Photo::importProfilePhoto($avatar, $uid, $cid, true);
+
+ if ($photos) {
+ dba::update(
+ 'contact',
+ array('avatar' => $avatar, 'photo' => $photos[0], 'thumb' => $photos[1], 'micro' => $photos[2], 'avatar-date' => datetime_convert()),
+ array('id' => $cid)
+ );
+
+ // Update the public contact (contact id = 0)
+ if ($uid != 0) {
+ $pcontact = dba::select('contact', array('id'), array('nurl' => $r[0]['nurl']), array('limit' => 1));
+ if (DBM::is_result($pcontact)) {
+ self::updateAvatar($avatar, 0, $pcontact['id'], $force);
+ }
+ }
+
+ return $photos;
+ }
+ }
+
+ return $data;
+ }
}