+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_NORMAL
+ */
+ const PAGE_NORMAL = User::PAGE_FLAGS_NORMAL;
+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_SOAPBOX
+ */
+ const PAGE_SOAPBOX = User::PAGE_FLAGS_SOAPBOX;
+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_COMMUNITY
+ */
+ const PAGE_COMMUNITY = User::PAGE_FLAGS_COMMUNITY;
+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_FREELOVE
+ */
+ const PAGE_FREELOVE = User::PAGE_FLAGS_FREELOVE;
+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_BLOG
+ */
+ const PAGE_BLOG = User::PAGE_FLAGS_BLOG;
+ /**
+ * @deprecated since version 2019.03
+ * @see User::PAGE_FLAGS_PRVGROUP
+ */
+ const PAGE_PRVGROUP = User::PAGE_FLAGS_PRVGROUP;
+ /**
+ * @}
+ */
+
+ /**
+ * Account types
+ *
+ * TYPE_UNKNOWN - the account has been imported from gcontact where this is the default type value
+ *
+ * TYPE_PERSON - the account belongs to a person
+ * Associated page types: PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE
+ *
+ * TYPE_ORGANISATION - the account belongs to an organisation
+ * Associated page type: PAGE_SOAPBOX
+ *
+ * TYPE_NEWS - the account is a news reflector
+ * Associated page type: PAGE_SOAPBOX
+ *
+ * TYPE_COMMUNITY - the account is community forum
+ * Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP
+ *
+ * TYPE_RELAY - the account is a relay
+ * This will only be assigned to contacts, not to user accounts
+ * @{
+ */
+ const TYPE_UNKNOWN = -1;
+ const TYPE_PERSON = User::ACCOUNT_TYPE_PERSON;
+ const TYPE_ORGANISATION = User::ACCOUNT_TYPE_ORGANISATION;
+ const TYPE_NEWS = User::ACCOUNT_TYPE_NEWS;
+ const TYPE_COMMUNITY = User::ACCOUNT_TYPE_COMMUNITY;
+ const TYPE_RELAY = User::ACCOUNT_TYPE_RELAY;
+ /**
+ * @}
+ */
+
+ /**
+ * Contact_is
+ *
+ * Relationship types
+ * @{
+ */
+ const FOLLOWER = 1;
+ const SHARING = 2;
+ const FRIEND = 3;
+ /**
+ * @}
+ */
+
+ /**
+ * @brief Tests if the given contact is a follower
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ *
+ * @return boolean is the contact id a follower?
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
+ public static function isFollower($cid, $uid)
+ {
+ if (self::isBlockedByUser($cid, $uid)) {
+ return false;
+ }
+
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata['user'])) {
+ return false;
+ }
+
+ $condition = ['id' => $cdata['user'], 'rel' => [self::FOLLOWER, self::FRIEND]];
+ return DBA::exists('contact', $condition);
+ }
+
+ /**
+ * @brief Get the basepath for a given contact link
+ * @todo Add functionality to store this value in the contact table
+ *
+ * @param string $url The contact link
+ *
+ * @return string basepath
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
+ public static function getBasepath($url)
+ {
+ $data = Probe::uri($url);
+ if (!empty($data['baseurl'])) {
+ return $data['baseurl'];
+ }
+
+ // When we can't probe the server, we use some ugly function that does some pattern matching
+ return PortableContact::detectServer($url);
+ }
+
+ /**
+ * @brief Returns the contact id for the user and the public contact id for a given contact id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ *
+ * @return array with public and user's contact id
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
+ public static function getPublicAndUserContacID($cid, $uid)
+ {
+ if (empty($uid) || empty($cid)) {
+ return [];
+ }
+
+ $contact = DBA::selectFirst('contact', ['id', 'uid', 'url'], ['id' => $cid]);
+ if (!DBA::isResult($contact)) {
+ return [];
+ }
+
+ // We quit when the user id don't match the user id of the provided contact
+ if (($contact['uid'] != $uid) && ($contact['uid'] != 0)) {
+ return [];
+ }
+
+ if ($contact['uid'] != 0) {
+ $pcid = Contact::getIdForURL($contact['url'], 0, true, ['url' => $contact['url']]);
+ if (empty($pcid)) {
+ return [];
+ }
+ $ucid = $contact['id'];
+ } else {
+ $pcid = $contact['id'];
+ $ucid = Contact::getIdForURL($contact['url'], $uid, true);
+ }
+
+ return ['public' => $pcid, 'user' => $ucid];
+ }
+
+ /**
+ * @brief Block contact id for user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ * @param boolean $blocked Is the contact blocked or unblocked?
+ * @throws \Exception
+ */
+ public static function setBlockedForUser($cid, $uid, $blocked)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ if ($cdata['user'] != 0) {
+ DBA::update('contact', ['blocked' => $blocked], ['id' => $cdata['user'], 'pending' => false]);
+ }
+
+ DBA::update('user-contact', ['blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
+ }
+
+ /**
+ * @brief Returns "block" state for contact id and user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ *
+ * @return boolean is the contact id blocked for the given user?
+ * @throws \Exception
+ */
+ public static function isBlockedByUser($cid, $uid)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ $public_blocked = false;
+
+ if (!empty($cdata['public'])) {
+ $public_contact = DBA::selectFirst('user-contact', ['blocked'], ['cid' => $cdata['public'], 'uid' => $uid]);
+ if (DBA::isResult($public_contact)) {
+ $public_blocked = $public_contact['blocked'];
+ }
+ }
+
+ $user_blocked = $public_blocked;
+
+ if (!empty($cdata['user'])) {
+ $user_contact = DBA::selectFirst('contact', ['blocked'], ['id' => $cdata['user'], 'pending' => false]);
+ if (DBA::isResult($user_contact)) {
+ $user_blocked = $user_contact['blocked'];
+ }
+ }
+
+ if ($user_blocked != $public_blocked) {
+ DBA::update('user-contact', ['blocked' => $user_blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
+ }
+
+ return $user_blocked;
+ }
+
+ /**
+ * @brief Ignore contact id for user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ * @param boolean $ignored Is the contact ignored or unignored?
+ * @throws \Exception
+ */
+ public static function setIgnoredForUser($cid, $uid, $ignored)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ if ($cdata['user'] != 0) {
+ DBA::update('contact', ['readonly' => $ignored], ['id' => $cdata['user'], 'pending' => false]);
+ }
+
+ DBA::update('user-contact', ['ignored' => $ignored], ['cid' => $cdata['public'], 'uid' => $uid], true);
+ }
+
+ /**
+ * @brief Returns "ignore" state for contact id and user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ *
+ * @return boolean is the contact id ignored for the given user?
+ * @throws \Exception
+ */
+ public static function isIgnoredByUser($cid, $uid)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ $public_ignored = false;
+
+ if (!empty($cdata['public'])) {
+ $public_contact = DBA::selectFirst('user-contact', ['ignored'], ['cid' => $cdata['public'], 'uid' => $uid]);
+ if (DBA::isResult($public_contact)) {
+ $public_ignored = $public_contact['ignored'];
+ }
+ }
+
+ $user_ignored = $public_ignored;
+
+ if (!empty($cdata['user'])) {
+ $user_contact = DBA::selectFirst('contact', ['readonly'], ['id' => $cdata['user'], 'pending' => false]);
+ if (DBA::isResult($user_contact)) {
+ $user_ignored = $user_contact['readonly'];
+ }
+ }
+
+ if ($user_ignored != $public_ignored) {
+ DBA::update('user-contact', ['ignored' => $user_ignored], ['cid' => $cdata['public'], 'uid' => $uid], true);
+ }
+
+ return $user_ignored;
+ }
+
+ /**
+ * @brief Set "collapsed" for contact id and user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ * @param boolean $collapsed are the contact's posts collapsed or uncollapsed?
+ * @throws \Exception
+ */
+ public static function setCollapsedForUser($cid, $uid, $collapsed)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $cdata['public'], 'uid' => $uid], true);
+ }
+
+ /**
+ * @brief Returns "collapsed" state for contact id and user id
+ *
+ * @param int $cid Either public contact id or user's contact id
+ * @param int $uid User ID
+ *
+ * @return boolean is the contact id blocked for the given user?
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
+ public static function isCollapsedByUser($cid, $uid)
+ {
+ $cdata = self::getPublicAndUserContacID($cid, $uid);
+ if (empty($cdata)) {
+ return;
+ }
+
+ $collapsed = false;
+
+ if (!empty($cdata['public'])) {
+ $public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]);
+ if (DBA::isResult($public_contact)) {
+ $collapsed = $public_contact['collapsed'];
+ }
+ }
+
+ return $collapsed;
+ }
+