use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Core\Worker;
+use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Notify\Type;
* @}
*/
+ const LOCK_INSERT = 'contact-insert';
+
/**
* Account types
*
* @}
*/
- /**
+ const MIRROR_DEACTIVATED = 0;
+ const MIRROR_FORWARDED = 1;
+ const MIRROR_OWN_POST = 2;
+ const MIRROR_NATIVE_RESHARE = 3;
+
+ /**
* @param array $fields Array of selected fields, empty for all
* @param array $condition Array of fields for condition
* @param array $params Array of several parameters
* Insert a row into the contact table
* Important: You can't use DBA::lastInsertId() after this call since it will be set to 0.
*
- * @param array $fields field array
- * @param bool $on_duplicate_update Do an update on a duplicate entry
+ * @param array $fields field array
+ * @param int $duplicate_mode Do an update on a duplicate entry
*
* @return boolean was the insert successful?
* @throws \Exception
*/
- public static function insert(array $fields, bool $on_duplicate_update = false)
+ public static function insert(array $fields, int $duplicate_mode = Database::INSERT_DEFAULT)
{
- $ret = DBA::insert('contact', $fields, $on_duplicate_update);
+ if (!empty($fields['baseurl']) && empty($fields['gsid'])) {
+ $fields['gsid'] = GServer::getID($fields['baseurl'], true);
+ }
+
+ if (empty($fields['created'])) {
+ $fields['created'] = DateTimeFormat::utcNow();
+ }
+
+ $ret = DBA::insert('contact', $fields, $duplicate_mode);
$contact = DBA::selectFirst('contact', ['nurl', 'uid'], ['id' => DBA::lastInsertId()]);
if (!DBA::isResult($contact)) {
// Shouldn't happen
$item['title'] = '';
$item['guid'] = '';
$item['uri-id'] = 0;
- $item['attach'] = '';
$slap = OStatus::salmon($item, $user);
if (!empty($contact['notify'])) {
$unfollow_link = '';
if (!$contact['self'] && in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
- $unfollow_link = 'unfollow?url=' . urlencode($contact['url']);
+ $unfollow_link = 'unfollow?url=' . urlencode($contact['url']) . '&auto=1';
} elseif(!$contact['pending']) {
- $follow_link = 'follow?url=' . urlencode($contact['url']);
+ $follow_link = 'follow?url=' . urlencode($contact['url']) . '&auto=1';
}
}
$contact = self::selectFirst(['id'], ['nurl' => $urls, 'uid' => $uid]);
if (!empty($contact['id'])) {
$contact_id = $contact['id'];
- Logger::info('Fetched id by url', ['cid' => $contact_id, 'uid' => $uid, 'url' => $url, 'probed_url' => $data['url'], 'alias' => $data['alias'], 'addr' => $data['addr']]);
+ Logger::info('Fetched id by url', ['cid' => $contact_id, 'uid' => $uid, 'url' => $url, 'data' => $data]);
}
}
$condition = ['nurl' => Strings::normaliseLink($data["url"]), 'uid' => $uid, 'deleted' => false];
// Before inserting we do check if the entry does exist now.
- DBA::lock('contact');
- $contact = DBA::selectFirst('contact', ['id'], $condition, ['order' => ['id']]);
- if (DBA::isResult($contact)) {
- $contact_id = $contact['id'];
- Logger::notice('Contact had been created (shortly) before', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]);
- } else {
- DBA::insert('contact', $fields);
- $contact_id = DBA::lastInsertId();
- if ($contact_id) {
- Logger::info('Contact inserted', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]);
+ if (DI::lock()->acquire(self::LOCK_INSERT, 0)) {
+ $contact = DBA::selectFirst('contact', ['id'], $condition, ['order' => ['id']]);
+ if (DBA::isResult($contact)) {
+ $contact_id = $contact['id'];
+ Logger::notice('Contact had been created (shortly) before', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]);
+ } else {
+ DBA::insert('contact', $fields);
+ $contact_id = DBA::lastInsertId();
+ if ($contact_id) {
+ Logger::info('Contact inserted', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]);
+ }
}
+ DI::lock()->release(self::LOCK_INSERT);
+ } else {
+ Logger::warning('Contact lock had not been acquired');
}
- DBA::unlock();
+
if (!$contact_id) {
Logger::info('Contact was not inserted', ['url' => $url, 'uid' => $uid]);
return 0;
*
* @param string $contact_url Contact URL
* @param bool $thread_mode
- * @param int $update
+ * @param int $update Update mode
+ * @param int $parent Item parent ID for the update mode
* @return string posts in HTML
* @throws \Exception
*/
- public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0)
+ public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0, $parent = 0)
{
- return self::getPostsFromId(self::getIdForURL($contact_url), $thread_mode, $update);
+ return self::getPostsFromId(self::getIdForURL($contact_url), $thread_mode, $update, $parent);
}
/**
* Returns posts from a given contact id
*
- * @param integer $cid
- * @param bool $thread_mode
- * @param integer $update
+ * @param int $cid Contact ID
+ * @param bool $thread_mode
+ * @param int $update Update mode
+ * @param int $parent Item parent ID for the update mode
* @return string posts in HTML
* @throws \Exception
*/
- public static function getPostsFromId($cid, $thread_mode = false, $update = 0)
+ public static function getPostsFromId($cid, $thread_mode = false, $update = 0, $parent = 0)
{
$a = DI::app();
$contact_field = ((($contact["contact-type"] == self::TYPE_COMMUNITY) || ($contact['network'] == Protocol::MAIL)) ? 'owner-id' : 'author-id');
if ($thread_mode) {
- $condition = ["(`$contact_field` = ? OR (`causer-id` = ? AND `post-type` = ?)) AND `gravity` = ? AND " . $sql,
- $cid, $cid, Item::PT_ANNOUNCEMENT, GRAVITY_PARENT, local_user()];
+ $condition = ["((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ?)) AND " . $sql,
+ $cid, GRAVITY_PARENT, $cid, GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), local_user()];
} else {
$condition = ["`$contact_field` = ? AND `gravity` IN (?, ?) AND " . $sql,
$cid, GRAVITY_PARENT, GRAVITY_COMMENT, local_user()];
}
- $last_received = isset($_GET['last_received']) ? DateTimeFormat::utc($_GET['last_received']) : '';
- if (!empty($last_received)) {
- $condition = DBA::mergeConditions($condition, ["`received` < ?", $last_received]);
+ if (!empty($parent)) {
+ $condition = DBA::mergeConditions($condition, ['parent' => $parent]);
+ } else {
+ $last_received = isset($_GET['last_received']) ? DateTimeFormat::utc($_GET['last_received']) : '';
+ if (!empty($last_received)) {
+ $condition = DBA::mergeConditions($condition, ["`received` < ?", $last_received]);
+ }
}
if (DI::mode()->isMobile()) {
}
if ($thread_mode) {
- $r = Item::selectForUser(local_user(), ['uri', 'gravity', 'parent-uri'], $condition, $params);
+ $r = Item::selectForUser(local_user(), ['uri', 'gravity', 'parent-uri', 'thr-parent-id', 'author-id'], $condition, $params);
$items = [];
while ($item = DBA::fetch($r)) {
- if ($item['gravity'] != GRAVITY_PARENT) {
- $item['uri'] = $item['parent-uri'];
- }
- unset($item['parent-uri']);
- unset($item['gravity']);
-
$items[] = $item;
}
DBA::close($r);
$items = Item::inArray($r);
- $o .= conversation($a, $items, 'contact-posts', false);
+ $o .= conversation($a, $items, 'contact-posts', $update);
}
if (!$update) {
$condition['rel'] = self::SHARING;
DBA::update('contact', $fields, $condition);
- unset($fields['last-update']);
- unset($fields['success_update']);
- unset($fields['failure_update']);
+ // If the contact failed, propagate the update fields to all contacts
+ if (empty($fields['failed'])) {
+ unset($fields['last-update']);
+ unset($fields['success_update']);
+ unset($fields['failure_update']);
+ }
if (empty($fields)) {
return;
// If Probe::uri fails the network code will be different ("feed" or "unkn")
if (in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]) && ($ret['network'] != $contact['network'])) {
- if ($uid == 0) {
- self::updateContact($id, $uid, $ret['url'], ['failed' => true, 'last-update' => $updated, 'failure_update' => $updated]);
- }
+ self::updateContact($id, $uid, $ret['url'], ['failed' => true, 'last-update' => $updated, 'failure_update' => $updated]);
return false;
}
$ret['nurl'] = Strings::normaliseLink($ret['url']);
$ret['updated'] = $updated;
+ $ret['failed'] = false;
// Only fill the pubkey if it had been empty before. We have to prevent identity theft.
if (empty($pubkey) && !empty($new_pubkey)) {
if ($uid == 0) {
$ret['last-update'] = $updated;
$ret['success_update'] = $updated;
- $ret['failed'] = false;
}
unset($ret['photo']);
$item['title'] = '';
$item['guid'] = '';
$item['uri-id'] = 0;
- $item['attach'] = '';
$slap = OStatus::salmon($item, $owner);
in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) {
notification([
- 'type' => Type::INTRO,
- 'notify_flags' => $user['notify-flags'],
- 'language' => $user['language'],
- 'to_name' => $user['username'],
- 'to_email' => $user['email'],
- 'uid' => $user['uid'],
- 'link' => DI::baseUrl() . '/notifications/intros',
- 'source_name' => ((strlen(stripslashes($contact_record['name']))) ? stripslashes($contact_record['name']) : DI::l10n()->t('[Name Withheld]')),
- 'source_link' => $contact_record['url'],
- 'source_photo' => $contact_record['photo'],
- 'verb' => ($sharing ? Activity::FRIEND : Activity::FOLLOW),
- 'otype' => 'intro'
+ 'type' => Type::INTRO,
+ 'otype' => Notify\ObjectType::INTRO,
+ 'verb' => ($sharing ? Activity::FRIEND : Activity::FOLLOW),
+ 'uid' => $user['uid'],
+ 'cid' => $contact_record['id'],
+ 'link' => DI::baseUrl() . '/notifications/intros',
]);
}
} elseif (DBA::isResult($user) && in_array($user['page-flags'], [User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_FREELOVE, User::PAGE_FLAGS_COMMUNITY])) {