Merge remote-tracking branch 'upstream/develop' into fetch-usage

This commit is contained in:
Michael 2022-03-19 11:21:38 +00:00
commit 4e45987f74
196 changed files with 19366 additions and 17273 deletions

View file

@ -25,6 +25,7 @@ use Friendica\BaseModule;
use Friendica\Model\Contact;
use Friendica\Model\User;
use Friendica\Protocol\ActivityPub;
use Friendica\Util\HTTPSignature;
/**
* ActivityPub Followers
@ -45,7 +46,7 @@ class Followers extends BaseModule
$page = $_REQUEST['page'] ?? null;
$followers = ActivityPub\Transmitter::getContacts($owner, [Contact::FOLLOWER, Contact::FRIEND], 'followers', $page);
$followers = ActivityPub\Transmitter::getContacts($owner, [Contact::FOLLOWER, Contact::FRIEND], 'followers', $page, (string)HTTPSignature::getSigner('', $_SERVER));
header('Content-Type: application/activity+json');
echo json_encode($followers);

View file

@ -70,9 +70,7 @@ class Objects extends BaseModule
}
}
$item = Post::selectFirst(['id', 'uid', 'origin', 'author-link', 'changed', 'private', 'psid', 'gravity', 'deleted', 'parent-uri-id'],
['uri-id' => $itemuri['id']], ['order' => ['origin' => true]]);
$item = Post::selectFirst([], ['uri-id' => $itemuri['id'], 'origin' => true]);
if (!DBA::isResult($item)) {
throw new HTTPException\NotFoundException();
}
@ -81,25 +79,17 @@ class Objects extends BaseModule
if (!$validated) {
$requester = HTTPSignature::getSigner('', $_SERVER);
if (!empty($requester) && $item['origin']) {
$requester_id = Contact::getIdForURL($requester, $item['uid']);
if (!empty($requester_id)) {
$permissionSets = DI::permissionSet()->selectByContactId($requester_id, $item['uid']);
$psids = array_merge($permissionSets->column('id'), [PermissionSet::PUBLIC]);
$validated = in_array($item['psid'], $psids);
if (!empty($requester)) {
$receivers = Item::enumeratePermissions($item, false);
$receivers[] = $item['contact-id'];
$validated = in_array(Contact::getIdForURL($requester, $item['uid']), $receivers);
if (!$validated) {
$validated = in_array(Contact::getIdForURL($requester), $receivers);
}
}
}
if ($validated) {
// Valid items are original post or posted from this node (including in the case of a forum)
$validated = ($item['origin'] || (parse_url($item['author-link'], PHP_URL_HOST) == parse_url(DI::baseUrl()->get(), PHP_URL_HOST)));
if (!$validated && $item['deleted']) {
$validated = Post::exists(['origin' => true, 'uri-id' => $item['parent-uri-id']]);
}
}
if (!$validated) {
throw new HTTPException\NotFoundException();
}

View file

@ -164,19 +164,19 @@ class Federation extends BaseAdmin
}
$gserver['platform'] = $systems[$platform]['name'];
$gserver['totallbl'] = DI::l10n()->t('%d total systems', $gserver['total']);
$gserver['monthlbl'] = DI::l10n()->t('%d active users last month', $gserver['month']);
$gserver['halfyearlbl'] = DI::l10n()->t('%d active users last six months', $gserver['halfyear']);
$gserver['userslbl'] = DI::l10n()->t('%d registered users', $gserver['users']);
$gserver['postslbl'] = DI::l10n()->t('%d locally created posts and comments', $gserver['posts']);
$gserver['totallbl'] = DI::l10n()->t('%s total systems', number_format($gserver['total']));
$gserver['monthlbl'] = DI::l10n()->t('%s active users last month', number_format($gserver['month']));
$gserver['halfyearlbl'] = DI::l10n()->t('%s active users last six months', number_format($gserver['halfyear']));
$gserver['userslbl'] = DI::l10n()->t('%s registered users', number_format($gserver['users']));
$gserver['postslbl'] = DI::l10n()->t('%s locally created posts and comments', number_format($gserver['posts']));
if (($gserver['users'] > 0) && ($gserver['posts'] > 0)) {
$gserver['postsuserlbl'] = DI::l10n()->t('%d posts per user', $gserver['posts'] / $gserver['users']);
$gserver['postsuserlbl'] = DI::l10n()->t('%s posts per user', number_format($gserver['posts'] / $gserver['users'], 1));
} else {
$gserver['postsuserlbl'] = '';
}
if (($gserver['users'] > 0) && ($gserver['total'] > 0)) {
$gserver['userssystemlbl'] = DI::l10n()->t('%d users per system', $gserver['users'] / $gserver['total']);
$gserver['userssystemlbl'] = DI::l10n()->t('%s users per system', number_format($gserver['users'] / $gserver['total'], 1));
} else {
$gserver['userssystemlbl'] = '';
}
@ -196,7 +196,7 @@ class Federation extends BaseAdmin
'$intro' => $intro,
'$counts' => $counts,
'$version' => FRIENDICA_VERSION,
'$legendtext' => DI::l10n()->t('Currently this node is aware of %d nodes (%d active users last month, %d active users last six months, %d registered users in total) from the following platforms:', $total, $month, $halfyear, $users),
'$legendtext' => DI::l10n()->t('Currently this node is aware of %d nodes (%d active users last month, %d active users last six months, %d registered users in total) from the following platforms:', number_format($total), number_format($month), number_format($halfyear), number_format($users)),
]);
}

View file

@ -21,9 +21,9 @@
namespace Friendica\Module\Admin\Logs;
use Friendica\DI;
use Friendica\Core\Renderer;
use Friendica\Core\Theme;
use Friendica\DI;
use Friendica\Module\BaseAdmin;
use Psr\Log\LogLevel;
@ -80,9 +80,10 @@ class View extends BaseAdmin
}
}
return Renderer::replaceMacros($t, [
'$title' => DI::l10n()->t('Administration'),
'$page' => DI::l10n()->t('View Logs'),
'$l10n' => [
'$baseurl' => DI::baseUrl()->get(true),
'$title' => DI::l10n()->t('Administration'),
'$page' => DI::l10n()->t('View Logs'),
'$l10n' => [
'Search' => DI::l10n()->t('Search'),
'Search_in_logs' => DI::l10n()->t('Search in logs'),
'Show_all' => DI::l10n()->t('Show all'),

View file

@ -526,7 +526,7 @@ class Site extends BaseAdmin
'$touch_icon' => ['touch_icon', DI::l10n()->t('Touch icon'), DI::config()->get('system', 'touch_icon'), DI::l10n()->t('Link to an icon that will be used for tablets and mobiles.')],
'$additional_info' => ['additional_info', DI::l10n()->t('Additional Info'), $additional_info, DI::l10n()->t('For public servers: you can add additional information here that will be listed at %s/servers.', Search::getGlobalDirectory())],
'$language' => ['language', DI::l10n()->t('System language'), DI::config()->get('system', 'language'), '', $lang_choices],
'$theme' => ['theme', DI::l10n()->t('System theme'), DI::config()->get('system', 'theme'), DI::l10n()->t('Default system theme - may be over-ridden by user profiles - <a href="/admin/themes" id="cnftheme">Change default theme settings</a>'), $theme_choices],
'$theme' => ['theme', DI::l10n()->t('System theme'), DI::config()->get('system', 'theme'), DI::l10n()->t('Default system theme - may be over-ridden by user profiles - <a href="%s" id="cnftheme">Change default theme settings</a>', DI::baseUrl()->get(true) . '/admin/themes'), $theme_choices],
'$theme_mobile' => ['theme_mobile', DI::l10n()->t('Mobile system theme'), DI::config()->get('system', 'mobile-theme', '---'), DI::l10n()->t('Theme for mobile devices'), $theme_choices_mobile],
'$ssl_policy' => ['ssl_policy', DI::l10n()->t('SSL link policy'), DI::config()->get('system', 'ssl_policy'), DI::l10n()->t('Determines whether generated links should be forced to use SSL'), $ssl_choices],
'$force_ssl' => ['force_ssl', DI::l10n()->t('Force SSL'), DI::config()->get('system', 'force_ssl'), DI::l10n()->t('Force all Non-SSL requests to SSL - Attention: on some systems it could lead to endless loops.')],
@ -570,8 +570,8 @@ class Site extends BaseAdmin
'$diaspora_not_able' => DI::l10n()->t('Diaspora support can\'t be enabled because Friendica was installed into a sub directory.'),
'$diaspora_enabled' => ['diaspora_enabled', DI::l10n()->t('Enable Diaspora support'), DI::config()->get('system', 'diaspora_enabled', $diaspora_able), DI::l10n()->t('Enable built-in Diaspora network compatibility for communicating with diaspora servers.')],
'$verifyssl' => ['verifyssl', DI::l10n()->t('Verify SSL'), DI::config()->get('system', 'verifyssl'), DI::l10n()->t('If you wish, you can turn on strict certificate checking. This will mean you cannot connect (at all) to self-signed SSL sites.')],
'$proxyuser' => ['proxyuser', DI::l10n()->t('Proxy user'), DI::config()->get('system', 'proxyuser'), ''],
'$proxy' => ['proxy', DI::l10n()->t('Proxy URL'), DI::config()->get('system', 'proxy'), ''],
'$proxyuser' => ['proxyuser', DI::l10n()->t('Proxy user'), DI::config()->get('system', 'proxyuser'), DI::l10n()->t('User name for the proxy server.')],
'$proxy' => ['proxy', DI::l10n()->t('Proxy URL'), DI::config()->get('system', 'proxy'), DI::l10n()->t('If you want to use a proxy server that Friendica should use to connect to the network, put the URL of the proxy here.')],
'$timeout' => ['timeout', DI::l10n()->t('Network timeout'), DI::config()->get('system', 'curl_timeout'), DI::l10n()->t('Value is in seconds. Set to 0 for unlimited (not recommended).')],
'$maxloadavg' => ['maxloadavg', DI::l10n()->t('Maximum Load Average'), DI::config()->get('system', 'maxloadavg'), DI::l10n()->t('Maximum system load before delivery and poll processes are deferred - default %d.', 20)],
'$min_memory' => ['min_memory', DI::l10n()->t('Minimal Memory'), DI::config()->get('system', 'min_memory'), DI::l10n()->t('Minimal free memory in MB for the worker. Needs access to /proc/meminfo - default 0 (deactivated).')],

View file

@ -76,7 +76,7 @@ class Details extends BaseAdmin
require_once "view/theme/$theme/config.php";
if (function_exists('theme_admin')) {
$admin_form = '<iframe onload="resizeIframe(this);" src="/admin/themes/' . $theme . '/embed?mode=minimal" width="100%" height="600px" frameborder="no"></iframe>';
$admin_form = '<iframe onload="resizeIframe(this);" src="' . DI::baseUrl()->get(true) . '/admin/themes/' . $theme . '/embed?mode=minimal" width="100%" height="600px" frameborder="no"></iframe>';
}
}

View file

@ -24,6 +24,7 @@ namespace Friendica\Module\Admin\Themes;
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Module\BaseAdmin;
use Friendica\Module\Response;
use Friendica\Util\Profiler;
@ -94,7 +95,7 @@ class Embed extends BaseAdmin
$t = Renderer::getMarkupTemplate('admin/addons/embed.tpl');
return Renderer::replaceMacros($t, [
'$action' => '/admin/themes/' . $theme . '/embed?mode=minimal',
'$action' => DI::baseUrl()->get(true) . '/admin/themes/' . $theme . '/embed?mode=minimal',
'$form' => $admin_form,
'$form_security_token' => self::getFormSecurityToken("admin_theme_settings"),
]);

View file

@ -37,7 +37,7 @@ class Index extends BaseAdmin
// reload active themes
if (!empty($_GET['action'])) {
self::checkFormSecurityTokenRedirectOnError(DI::baseUrl()->get() . '/admin/themes', 'admin_themes', 't');
self::checkFormSecurityTokenRedirectOnError('/admin/themes', 'admin_themes', 't');
switch ($_GET['action']) {
case 'reload':

View file

@ -23,7 +23,9 @@ namespace Friendica\Module\Api\Friendica;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException\BadRequestException;
/**
* API endpoints:
@ -49,15 +51,16 @@ class Activity extends BaseApi
'id' => 0, // Id of the post
], $request);
$res = Item::performActivity($request['id'], $this->parameters['verb'], $uid);
$post = Post::selectFirst(['id'], ['uri-id' => $request['id'], 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (empty($post['id'])) {
throw new BadRequestException('Item id not found');
}
$res = Item::performActivity($post['id'], $this->parameters['verb'], $uid);
if ($res) {
if (($this->parameters['extension'] ?? '') == 'xml') {
$ok = 'true';
} else {
$ok = 'ok';
}
$this->response->exit('ok', ['ok' => $ok], $this->parameters['extension'] ?? null);
$status_info = DI::twitterStatus()->createFromUriId($request['id'], $uid)->toArray();
$this->response->exit('status', ['status' => $status_info], $this->parameters['extension'] ?? null);
} else {
$this->response->error(500, 'Error adding activity', '', $this->parameters['extension'] ?? null);
}

View file

@ -23,7 +23,6 @@ namespace Friendica\Module\Api\Friendica\Events;
use Friendica\Content\Text\BBCode;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Module\BaseApi;
/**
@ -40,7 +39,7 @@ class Index extends BaseApi
$request = $this->getRequest([
'since_id' => 0,
'count' => 0,
'count' => 50,
], $request);
$condition = ["`id` > ? AND `uid` = ?", $request['since_id'], $uid];

View file

@ -32,7 +32,7 @@ use Friendica\Network\HTTPException;
*/
class Show extends BaseApi
{
protected function post(array $request = [])
protected function rawContent(array $request = [])
{
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
$uid = BaseApi::getCurrentUserID();

View file

@ -44,7 +44,7 @@ class Photo extends BaseApi
$this->friendicaPhoto = $friendicaPhoto;
}
protected function post(array $request = [])
protected function rawContent(array $request = [])
{
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
$uid = BaseApi::getCurrentUserID();

View file

@ -56,7 +56,7 @@ class Conversation extends BaseApi
Logger::info(BaseApi::LOG_PREFIX . '{subaction}', ['module' => 'api', 'action' => 'conversation', 'subaction' => 'show', 'id' => $id]);
// try to fetch the item for the local user - or the public item, if there is no local one
$item = Post::selectFirst(['parent-uri-id'], ['id' => $id]);
$item = Post::selectFirst(['parent-uri-id'], ['uri-id' => $id]);
if (!DBA::isResult($item)) {
throw new BadRequestException("There is no status with the id $id.");
}
@ -68,15 +68,15 @@ class Conversation extends BaseApi
$id = $parent['id'];
$condition = ["`parent` = ? AND `uid` IN (0, ?) AND `gravity` IN (?, ?) AND `id` > ?",
$condition = ["`parent` = ? AND `uid` IN (0, ?) AND `gravity` IN (?, ?) AND `uri-id` > ?",
$id, $uid, GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
if (!DBA::isResult($statuses)) {

View file

@ -59,8 +59,7 @@ class Block extends BaseApi
Contact\User::setBlocked($cdata['user'], $uid, true);
// Mastodon-expected behavior: relationship is severed on block
Contact::terminateFriendship($owner, $contact);
Contact::revokeFollow($contact);
Contact::terminateFriendship($contact);
System::jsonExit(DI::mstdnRelationship()->createFromContactId($this->parameters['id'], $uid)->toArray());
}

View file

@ -40,7 +40,14 @@ class Unfollow extends BaseApi
DI::mstdnError()->UnprocessableEntity();
}
Contact::unfollow($this->parameters['id'], $uid);
$cdata = Contact::getPublicAndUserContactID($this->parameters['id'], $uid);
if (empty($cdata['user'])) {
DI::mstdnError()->RecordNotFound();
}
$contact = Contact::getById($cdata['user']);
Contact::unfollow($contact);
System::jsonExit(DI::mstdnRelationship()->createFromContactId($this->parameters['id'], $uid)->toArray());
}

View file

@ -21,20 +21,44 @@
namespace Friendica\Module\Api\Mastodon;
use Friendica\App;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Database\Database;
use Friendica\Module\Api\ApiResponse;
use Friendica\Module\BaseApi;
use Friendica\Object\Api\Mastodon\Instance as InstanceEntity;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/**
* @see https://docs.joinmastodon.org/api/rest/instances/
*/
class Instance extends BaseApi
{
/** @var Database */
private $database;
/** @var IManageConfigValues */
private $config;
public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, Database $database, IManageConfigValues $config, array $server, array $parameters = [])
{
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->database = $database;
$this->config = $config;
}
/**
* @param array $request
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \Friendica\Network\HTTPException\NotFoundException
* @throws \ImagickException
*/
protected function rawContent(array $request = [])
{
System::jsonExit(InstanceEntity::get());
System::jsonExit(new InstanceEntity($this->config, $this->baseUrl, $this->database));
}
}

View file

@ -36,12 +36,32 @@ class Accounts extends BaseApi
{
protected function delete(array $request = [])
{
$this->response->unsupported(Router::DELETE, $request);
self::checkAllowedScope(self::SCOPE_WRITE);
$request = $this->getRequest([
'account_ids' => [], // Array of account IDs to remove from the list
], $request);
if (empty($request['account_ids']) || empty($this->parameters['id'])) {
DI::mstdnError()->UnprocessableEntity();
}
return Group::removeMembers($this->parameters['id'], $request['account_ids']);
}
protected function post(array $request = [])
{
$this->response->unsupported(Router::POST, $request);
self::checkAllowedScope(self::SCOPE_WRITE);
$request = $this->getRequest([
'account_ids' => [], // Array of account IDs to add to the list
], $request);
if (empty($request['account_ids']) || empty($this->parameters['id'])) {
DI::mstdnError()->UnprocessableEntity();
}
return Group::addMembers($this->parameters['id'], $request['account_ids']);
}
/**

View file

@ -21,8 +21,8 @@
namespace Friendica\Module\Api\Mastodon;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
@ -63,17 +63,12 @@ class Statuses extends BaseApi
// The imput is defined as text. So we can use Markdown for some enhancements
$body = Markdown::toBBCode($request['status']);
// Avoids potential double expansion of existing links
$body = BBCode::performWithEscapedTags($body, ['url'], function ($body) {
return BBCode::expandTags($body);
});
$item = [];
$item = [];
$item['network'] = Protocol::DFRN;
$item['uid'] = $uid;
$item['verb'] = Activity::POST;
$item['contact-id'] = $owner['id'];
$item['author-id'] = $item['owner-id'] = Contact::getPublicIdByUserId($uid);
$item['title'] = $request['spoiler_text'];
$item['body'] = $body;
if (!empty(self::getCurrentApplication()['name'])) {
@ -114,14 +109,20 @@ class Statuses extends BaseApi
$item['private'] = Item::PRIVATE;
break;
case 'direct':
// Direct messages are currently unsupported
DI::mstdnError()->InternalError('Direct messages are currently unsupported');
// The permissions are assigned in "expandTags"
break;
default:
$item['allow_cid'] = $owner['allow_cid'];
$item['allow_gid'] = $owner['allow_gid'];
$item['deny_cid'] = $owner['deny_cid'];
$item['deny_gid'] = $owner['deny_gid'];
if (is_numeric($request['visibility']) && Group::exists($request['visibility'], $uid)) {
$item['allow_cid'] = '';
$item['allow_gid'] = '<' . $request['visibility'] . '>';
$item['deny_cid'] = '';
$item['deny_gid'] = '';
} else {
$item['allow_cid'] = $owner['allow_cid'];
$item['allow_gid'] = $owner['allow_gid'];
$item['deny_cid'] = $owner['deny_cid'];
$item['deny_gid'] = $owner['deny_gid'];
}
if (!empty($item['allow_cid'] . $item['allow_gid'] . $item['deny_cid'] . $item['deny_gid'])) {
$item['private'] = Item::PRIVATE;
@ -139,16 +140,21 @@ class Statuses extends BaseApi
if ($request['in_reply_to_id']) {
$parent = Post::selectFirst(['uri'], ['uri-id' => $request['in_reply_to_id'], 'uid' => [0, $uid]]);
$item['thr-parent'] = $parent['uri'];
$item['gravity'] = GRAVITY_COMMENT;
$item['object-type'] = Activity\ObjectType::COMMENT;
$item['body'] = '[abstract=' . Protocol::ACTIVITYPUB . ']' . $request['spoiler_text'] . "[/abstract]\n" . $item['body'];
} else {
self::checkThrottleLimit();
$item['gravity'] = GRAVITY_PARENT;
$item['object-type'] = Activity\ObjectType::NOTE;
$item['title'] = $request['spoiler_text'];
}
$item = DI::contentItem()->expandTags($item, $request['visibility'] == 'direct');
if (!empty($request['media_ids'])) {
$item['object-type'] = Activity\ObjectType::IMAGE;
$item['post-type'] = Item::PT_IMAGE;

View file

@ -42,7 +42,7 @@ class Bookmark extends BaseApi
DI::mstdnError()->UnprocessableEntity();
}
$item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]);
$item = Post::selectFirst(['uid', 'id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]);
if (!DBA::isResult($item)) {
DI::mstdnError()->RecordNotFound();
}
@ -51,6 +51,18 @@ class Bookmark extends BaseApi
DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be bookmarked'));
}
if ($item['uid'] == 0) {
$stored = Item::storeForUserByUriId($this->parameters['id'], $uid);
if (!empty($stored)) {
$item = Post::selectFirst(['id', 'gravity'], ['id' => $stored]);
if (!DBA::isResult($item)) {
DI::mstdnError()->RecordNotFound();
}
} else {
DI::mstdnError()->RecordNotFound();
}
}
Item::update(['starred' => true], ['id' => $item['id']]);
System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid)->toArray());

View file

@ -42,7 +42,7 @@ class Unbookmark extends BaseApi
DI::mstdnError()->UnprocessableEntity();
}
$item = Post::selectFirstForUser($uid, ['id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]);
$item = Post::selectFirst(['uid', 'id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]);
if (!DBA::isResult($item)) {
DI::mstdnError()->RecordNotFound();
}
@ -51,6 +51,18 @@ class Unbookmark extends BaseApi
DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be unbookmarked'));
}
if ($item['uid'] == 0) {
$stored = Item::storeForUserByUriId($this->parameters['id'], $uid);
if (!empty($stored)) {
$item = Post::selectFirst(['id', 'gravity'], ['id' => $stored]);
if (!DBA::isResult($item)) {
DI::mstdnError()->RecordNotFound();
}
} else {
DI::mstdnError()->RecordNotFound();
}
}
Item::update(['starred' => false], ['id' => $item['id']]);
System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid)->toArray());

View file

@ -53,13 +53,13 @@ class Favorites extends BaseApi
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ? AND `starred`",
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `uri-id` > ? AND `starred`",
$uid, GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}

View file

@ -23,6 +23,7 @@ namespace Friendica\Module\Api\Twitter\Favorites;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException\BadRequestException;
@ -42,9 +43,14 @@ class Create extends BaseApi
throw new BadRequestException('Item id not specified');
}
Item::performActivity($id, 'like', $uid);
$post = Post::selectFirst(['id'], ['uri-id' => $request['id'], 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (empty($post['id'])) {
throw new BadRequestException('Item id not found');
}
$status_info = DI::twitterStatus()->createFromItemId($id, $uid)->toArray();
Item::performActivity($post['id'], 'like', $uid);
$status_info = DI::twitterStatus()->createFromUriId($id, $uid)->toArray();
$this->response->exit('status', ['status' => $status_info], $this->parameters['extension'] ?? null);
}

View file

@ -23,6 +23,7 @@ namespace Friendica\Module\Api\Twitter\Favorites;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException\BadRequestException;
@ -42,9 +43,14 @@ class Destroy extends BaseApi
throw new BadRequestException('Item id not specified');
}
Item::performActivity($id, 'unlike', $uid);
$post = Post::selectFirst(['id'], ['uri-id' => $request['id'], 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (empty($post['id'])) {
throw new BadRequestException('Item id not found');
}
$status_info = DI::twitterStatus()->createFromItemId($id, $uid)->toArray();
Item::performActivity($post['id'], 'unlike', $uid);
$status_info = DI::twitterStatus()->createFromUriId($id, $uid)->toArray();
$this->response->exit('status', ['status' => $status_info], $this->parameters['extension'] ?? null);
}

View file

@ -22,13 +22,18 @@
namespace Friendica\Module\Api\Twitter\Friendships;
use Exception;
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\DI;
use Friendica\Factory\Api\Twitter\User as TwitterUser;
use Friendica\Model\Contact;
use Friendica\Model\User;
use Friendica\Module\Api\ApiResponse;
use Friendica\Module\Api\Twitter\ContactEndpoint;
use Friendica\Module\BaseApi;
use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/**
* Unfollow Contact
@ -37,6 +42,16 @@ use Friendica\Network\HTTPException;
*/
class Destroy extends ContactEndpoint
{
/** @var TwitterUser */
private $twitterUser;
public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, TwitterUser $twitterUser, array $server, array $parameters = [])
{
parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->twitterUser = $twitterUser;
}
protected function post(array $request = [])
{
BaseApi::checkAllowedScope(BaseApi::SCOPE_WRITE);
@ -66,18 +81,9 @@ class Destroy extends ContactEndpoint
$user = $this->twitterUser->createFromContactId($contact_id, $uid, true)->toArray();
try {
$result = Contact::terminateFriendship($owner, $contact);
if ($result === null) {
Logger::notice(BaseApi::LOG_PREFIX . 'Not supported for {network}', ['module' => 'api', 'action' => 'friendships_destroy', 'network' => $contact['network']]);
throw new HTTPException\ExpectationFailedException('Unfollowing is currently not supported by this contact\'s network.');
}
if ($result === false) {
throw new HTTPException\ServiceUnavailableException('Unable to unfollow this contact, please retry in a few minutes or contact your administrator.');
}
Contact::unfollow($contact);
} catch (Exception $e) {
Logger::error(BaseApi::LOG_PREFIX . $e->getMessage(), ['owner' => $owner, 'contact' => $contact]);
Logger::error(BaseApi::LOG_PREFIX . $e->getMessage(), ['contact' => $contact]);
throw new HTTPException\InternalServerErrorException('Unable to unfollow this contact, please contact your administrator');
}

View file

@ -46,32 +46,32 @@ class Incoming extends ContactEndpoint
$max_id = $this->getRequestValue($request, 'max_id', 0, 0);
$min_id = $this->getRequestValue($request, 'min_id', 0, 0);
$params = ['order' => ['cid' => true], 'limit' => $count];
$params = ['order' => ['contact-id' => true], 'limit' => $count];
$condition = ['uid' => $uid, 'pending' => true];
$condition = ["`uid` = ? AND NOT `blocked` AND NOT `ignore` AND `contact-id` != 0 AND (`suggest-cid` = 0 OR `suggest-cid` IS NULL)", $uid];
$total_count = (int)DBA::count('user-contact', $condition);
$total_count = (int)DBA::count('intro', $condition);
if (!empty($max_id)) {
$condition = DBA::mergeConditions($condition, ["`cid` < ?", $max_id]);
$condition = DBA::mergeConditions($condition, ["`contact-id` < ?", $max_id]);
}
if (!empty($since_id)) {
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $since_id]);
$condition = DBA::mergeConditions($condition, ["`contact-id` > ?", $since_id]);
}
if (!empty($min_id)) {
$condition = DBA::mergeConditions($condition, ["`cid` > ?", $min_id]);
$condition = DBA::mergeConditions($condition, ["`contact-id` > ?", $min_id]);
$params['order'] = ['cid'];
$params['order'] = ['contact-id'];
}
$ids = [];
$contacts = DBA::select('user-contact', ['cid'], $condition, $params);
$contacts = DBA::select('intro', ['contact-id'], $condition, $params);
while ($contact = DBA::fetch($contacts)) {
self::setBoundaries($contact['cid']);
$ids[] = $contact['cid'];
self::setBoundaries($contact['contact-id']);
$ids[] = $contact['contact-id'];
}
DBA::close($contacts);

View file

@ -56,7 +56,7 @@ class Ownership extends BaseApi
BaseApi::checkAllowedScope(BaseApi::SCOPE_READ);
$uid = BaseApi::getCurrentUserID();
$groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid]);
$groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]);
// loop through all groups
$lists = [];

View file

@ -78,10 +78,10 @@ class Statuses extends BaseApi
$groups = $this->dba->selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]);
$gids = array_column($groups, 'contact-id');
$condition = ['uid' => $uid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'contact-id' => $gids];
$condition = DBA::mergeConditions($condition, ["`id` > ?", $since_id]);
$condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $since_id]);
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
if ($exclude_replies) {
@ -89,11 +89,11 @@ class Statuses extends BaseApi
$condition[] = GRAVITY_PARENT;
}
if ($conversation_id > 0) {
$condition[0] .= " AND `parent` = ?";
$condition[0] .= " AND `parent-uri-id` = ?";
$condition[] = $conversation_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
$items = [];

View file

@ -59,10 +59,10 @@ class Tweets extends BaseApi
$start = max(0, ($page - 1) * $count);
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
if (preg_match('/^#(\w+)$/', $searchTerm, $matches) === 1 && isset($matches[1])) {
$searchTerm = $matches[1];
$condition = ["`iid` > ? AND `name` = ? AND (NOT `private` OR (`private` AND `uid` = ?))", $since_id, $searchTerm, $uid];
$condition = ["`uri-id` > ? AND `name` = ? AND (NOT `private` OR (`private` AND `uid` = ?))", $since_id, $searchTerm, $uid];
$tags = DBA::select('tag-search-view', ['uri-id'], $condition);
$uriids = [];
@ -83,13 +83,13 @@ class Tweets extends BaseApi
$params['group_by'] = ['uri-id'];
} else {
$condition = ["`id` > ?
$condition = ["`uri-id` > ?
" . ($exclude_replies ? " AND `gravity` = " . GRAVITY_PARENT : ' ') . "
AND (`uid` = 0 OR (`uid` = ? AND NOT `global`))
AND `body` LIKE CONCAT('%',?,'%')",
$since_id, $uid, $_REQUEST['q']];
if ($max_id > 0) {
$condition[0] .= ' AND `id` <= ?';
$condition[0] .= ' AND `uri-id` <= ?';
$condition[] = $max_id;
}
}

View file

@ -25,6 +25,7 @@ use Friendica\Module\BaseApi;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Network\HTTPException\BadRequestException;
/**
@ -45,13 +46,18 @@ class Destroy extends BaseApi
throw new BadRequestException('An id is missing.');
}
$post = Post::selectFirst(['id'], ['uri-id' => $request['id'], 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (empty($post['id'])) {
throw new BadRequestException('Item id not found');
}
$this->logger->notice('API: api_statuses_destroy: ' . $id);
$include_entities = $this->getRequestValue($request, 'include_entities', false);
$ret = DI::twitterStatus()->createFromItemId($id, $uid, $include_entities)->toArray();
$ret = DI::twitterStatus()->createFromUriId($id, $uid, $include_entities)->toArray();
Item::deleteForUser(['id' => $id], $uid);
Item::deleteForUser(['id' => $post['id']], $uid);
$this->response->exit('status', ['status' => $ret], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid));
}

View file

@ -53,11 +53,11 @@ class HomeTimeline extends BaseApi
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `id` > ?",
$condition = ["`uid` = ? AND `gravity` IN (?, ?) AND `uri-id` > ?",
$uid, GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
if ($exclude_replies) {
@ -65,11 +65,11 @@ class HomeTimeline extends BaseApi
$condition[] = GRAVITY_PARENT;
}
if ($conversation_id > 0) {
$condition[0] .= " AND `parent` = ?";
$condition[0] .= " AND `parent-uri-id` = ?";
$condition[] = $conversation_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
$ret = [];

View file

@ -52,7 +52,7 @@ class Mentions extends BaseApi
$query = "`gravity` IN (?, ?) AND `uri-id` IN
(SELECT `uri-id` FROM `post-user-notification` WHERE `uid` = ? AND `notification-type` & ? != 0 ORDER BY `uri-id`)
AND (`uid` = 0 OR (`uid` = ? AND NOT `global`)) AND `id` > ?";
AND (`uid` = 0 OR (`uid` = ? AND NOT `global`)) AND `uri-id` > ?";
$condition = [
GRAVITY_PARENT, GRAVITY_COMMENT,
@ -64,13 +64,13 @@ class Mentions extends BaseApi
];
if ($max_id > 0) {
$query .= " AND `id` <= ?";
$query .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
array_unshift($condition, $query);
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
$ret = [];

View file

@ -46,15 +46,15 @@ class NetworkPublicTimeline extends BaseApi
$start = max(0, ($page - 1) * $count);
$condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `id` > ? AND `private` = ?",
$condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `uri-id` > ? AND `private` = ?",
GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, Item::DISPLAY_FIELDLIST, $condition, $params);
$ret = [];

View file

@ -52,30 +52,30 @@ class PublicTimeline extends BaseApi
$start = max(0, ($page - 1) * $count);
if ($exclude_replies && !$conversation_id) {
$condition = ["`gravity` = ? AND `id` > ? AND `private` = ? AND `wall` AND NOT `author-hidden`",
$condition = ["`gravity` = ? AND `uri-id` > ? AND `private` = ? AND `wall` AND NOT `author-hidden`",
GRAVITY_PARENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
} else {
$condition = ["`gravity` IN (?, ?) AND `id` > ? AND `private` = ? AND `wall` AND `origin` AND NOT `author-hidden`",
$condition = ["`gravity` IN (?, ?) AND `uri-id` > ? AND `private` = ? AND `wall` AND `origin` AND NOT `author-hidden`",
GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
if ($conversation_id > 0) {
$condition[0] .= " AND `parent` = ?";
$condition[0] .= " AND `parent-uri-id` = ?";
$condition[] = $conversation_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
}

View file

@ -50,8 +50,8 @@ class Retweet extends BaseApi
throw new BadRequestException('An id is missing.');
}
$fields = ['uri-id', 'network', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink'];
$item = Post::selectFirst($fields, ['id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED]]);
$fields = ['id', 'uri-id', 'network', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink'];
$item = Post::selectFirst($fields, ['uri-id' => $id, 'uid' => [0, $uid], 'private' => [Item::PUBLIC, Item::UNLISTED]], ['order' => ['uid' => true]]);
if (DBA::isResult($item) && !empty($item['body'])) {
if (in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::TWITTER])) {
@ -59,7 +59,7 @@ class Retweet extends BaseApi
throw new InternalServerErrorException();
}
$item_id = $id;
$item_id = $item['id'];
} else {
$item_id = Diaspora::performReshare($item['uri-id'], $uid);
}

View file

@ -52,23 +52,18 @@ class Show extends BaseApi
$conversation = !empty($request['conversation']);
// try to fetch the item for the local user - or the public item, if there is no local one
$uri_item = Post::selectFirst(['uri-id'], ['id' => $id]);
if (!DBA::isResult($uri_item)) {
throw new BadRequestException(sprintf("There is no status with the id %d", $id));
}
$item = Post::selectFirst(['id'], ['uri-id' => $uri_item['uri-id'], 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
$item = Post::selectFirst(['id'], ['uri-id' => $id, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
if (!DBA::isResult($item)) {
throw new BadRequestException(sprintf("There is no status with the uri-id %d for the given user.", $uri_item['uri-id']));
throw new BadRequestException(sprintf("There is no status with the uri-id %d for the given user.", $id));
}
$id = $item['id'];
$item_id = $item['id'];
if ($conversation) {
$condition = ['parent' => $id, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$params = ['order' => ['id' => true]];
$condition = ['parent' => $item_id, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$params = ['order' => ['uri-id' => true]];
} else {
$condition = ['id' => $id, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$condition = ['id' => $item_id, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$params = [];
}

View file

@ -21,9 +21,9 @@
namespace Friendica\Module\Api\Twitter\Statuses;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Protocol;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
@ -78,17 +78,12 @@ class Update extends BaseApi
$body = Markdown::toBBCode($request['status']);
}
// Avoids potential double expansion of existing links
$body = BBCode::performWithEscapedTags($body, ['url'], function ($body) {
return BBCode::expandTags($body);
});
$item = [];
$item['network'] = Protocol::DFRN;
$item['uid'] = $uid;
$item['verb'] = Activity::POST;
$item['contact-id'] = $owner['id'];
$item['author-id'] = Contact::getPublicIdByUserId($uid);
$item['owner-id'] = $item['author-id'];
$item['author-id'] = $item['owner-id'] = Contact::getPublicIdByUserId($uid);
$item['title'] = $request['title'];
$item['body'] = $body;
$item['app'] = $request['source'];
@ -115,7 +110,7 @@ class Update extends BaseApi
}
if ($request['in_reply_to_status_id']) {
$parent = Post::selectFirst(['uri'], ['id' => $request['in_reply_to_status_id'], 'uid' => [0, $uid]]);
$parent = Post::selectFirst(['uri'], ['uri-id' => $request['in_reply_to_status_id'], 'uid' => [0, $uid]]);
$item['thr-parent'] = $parent['uri'];
$item['gravity'] = GRAVITY_COMMENT;
@ -127,6 +122,8 @@ class Update extends BaseApi
$item['object-type'] = Activity\ObjectType::NOTE;
}
$item = DI::contentItem()->expandTags($item);
if (!empty($request['media_ids'])) {
$ids = explode(',', $request['media_ids']);
} elseif (!empty($_FILES['media'])) {

View file

@ -53,7 +53,7 @@ class UserTimeline extends BaseApi
$start = max(0, ($page - 1) * $count);
$condition = ["(`uid` = ? OR (`uid` = ? AND NOT `global`)) AND `gravity` IN (?, ?) AND `id` > ? AND `author-id` = ?",
$condition = ["(`uid` = ? OR (`uid` = ? AND NOT `global`)) AND `gravity` IN (?, ?) AND `uri-id` > ? AND `author-id` = ?",
0, $uid, GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, $cid];
if ($exclude_replies) {
@ -62,15 +62,15 @@ class UserTimeline extends BaseApi
}
if ($conversation_id > 0) {
$condition[0] .= " AND `parent` = ?";
$condition[0] .= " AND `parent-uri-id` = ?";
$condition[] = $conversation_id;
}
if ($max_id > 0) {
$condition[0] .= " AND `id` <= ?";
$condition[0] .= " AND `uri-id` <= ?";
$condition[] = $max_id;
}
$params = ['order' => ['id' => true], 'limit' => [$start, $count]];
$params = ['order' => ['uri-id' => true], 'limit' => [$start, $count]];
$statuses = Post::selectForUser($uid, [], $condition, $params);
$ret = [];

View file

@ -29,7 +29,7 @@ use Friendica\Content\Pager;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Navigation\Notifications\ValueObject\FormattedNotification;
use Friendica\Navigation\Notifications\ValueObject\FormattedNotify;
use Friendica\Network\HTTPException\ForbiddenException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -43,29 +43,29 @@ abstract class BaseNotifications extends BaseModule
{
/** @var array Array of URL parameters */
const URL_TYPES = [
FormattedNotification::NETWORK => 'network',
FormattedNotification::SYSTEM => 'system',
FormattedNotification::HOME => 'home',
FormattedNotification::PERSONAL => 'personal',
FormattedNotification::INTRO => 'intros',
FormattedNotify::NETWORK => 'network',
FormattedNotify::SYSTEM => 'system',
FormattedNotify::HOME => 'home',
FormattedNotify::PERSONAL => 'personal',
FormattedNotify::INTRO => 'intros',
];
/** @var array Array of the allowed notifications and their printable name */
const PRINT_TYPES = [
FormattedNotification::NETWORK => 'Network',
FormattedNotification::SYSTEM => 'System',
FormattedNotification::HOME => 'Home',
FormattedNotification::PERSONAL => 'Personal',
FormattedNotification::INTRO => 'Introductions',
FormattedNotify::NETWORK => 'Network',
FormattedNotify::SYSTEM => 'System',
FormattedNotify::HOME => 'Home',
FormattedNotify::PERSONAL => 'Personal',
FormattedNotify::INTRO => 'Introductions',
];
/** @var array The array of access keys for notification pages */
const ACCESS_KEYS = [
FormattedNotification::NETWORK => 'w',
FormattedNotification::SYSTEM => 'y',
FormattedNotification::HOME => 'h',
FormattedNotification::PERSONAL => 'r',
FormattedNotification::INTRO => 'i',
FormattedNotify::NETWORK => 'w',
FormattedNotify::SYSTEM => 'y',
FormattedNotify::HOME => 'h',
FormattedNotify::PERSONAL => 'r',
FormattedNotify::INTRO => 'i',
];
/** @var int The default count of items per page */

View file

@ -558,7 +558,7 @@ class Contact extends BaseModule
'details' => $contact['location'],
'tags' => $contact['keywords'],
'about' => $contact['about'],
'account_type' => Model\Contact::getAccountType($contact),
'account_type' => Model\Contact::getAccountType($contact['contact-type']),
'sparkle' => $sparkle,
'itemurl' => ($contact['addr'] ?? '') ?: $contact['url'],
'network' => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']),

View file

@ -101,7 +101,7 @@ class Hovercard extends BaseModule
'network_link' => Strings::formatNetworkName($contact['network'], $contact['url']),
'tags' => $contact['keywords'],
'bd' => $contact['bd'] <= DBA::NULL_DATE ? '' : $contact['bd'],
'account_type' => Contact::getAccountType($contact),
'account_type' => Contact::getAccountType($contact['contact-type']),
'actions' => $actions,
],
]);

View file

@ -364,7 +364,7 @@ class Profile extends BaseModule
'$url' => $url,
'$profileurllabel' => $this->t('Profile URL'),
'$profileurl' => $contact['url'],
'$account_type' => Contact::getAccountType($contact),
'$account_type' => Contact::getAccountType($contact['contact-type']),
'$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
'$location_label' => $this->t('Location:'),
'$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),

View file

@ -38,7 +38,10 @@ use Psr\Log\LoggerInterface;
class Revoke extends BaseModule
{
/** @var array */
/**
* User-specific contact (uid != 0) array
* @var array
*/
protected $contact;
/** @var Database */
@ -82,14 +85,9 @@ class Revoke extends BaseModule
self::checkFormSecurityTokenRedirectOnError('contact/' . $this->parameters['id'], 'contact_revoke');
$result = Model\Contact::revokeFollow($this->contact);
if ($result === true) {
notice($this->t('Follow was successfully revoked.'));
} elseif ($result === null) {
notice($this->t('Follow was successfully revoked, however the remote contact won\'t be aware of this revokation.'));
} else {
notice($this->t('Unable to revoke follow, please try again later or contact the administrator.'));
}
Model\Contact::revokeFollow($this->contact);
notice($this->t('Follow was successfully revoked.'));
$this->baseUrl->redirect('contact/' . $this->parameters['id']);
}

View file

@ -119,7 +119,7 @@ class Network extends BaseModule
if (self::$forumContactId) {
// If self::$forumContactId belongs to a communitity forum or a privat goup,.add a mention to the status editor
$condition = ["`id` = ? AND (`forum` OR `prv`)", self::$forumContactId];
$condition = ["`id` = ? AND `contact-type` = ?", self::$forumContactId, Contact::TYPE_COMMUNITY];
$contact = DBA::selectFirst('contact', ['addr'], $condition);
if (!empty($contact['addr'])) {
$content = '!' . $contact['addr'];

View file

@ -114,6 +114,10 @@ class ActivityPubConversion extends BaseModule
$object_data['thread-completion'] = $activity['thread-completion'];
}
if (!empty($activity['completion-mode'])) {
$object_data['completion-mode'] = $activity['completion-mode'];
}
$results[] = [
'title' => DI::l10n()->t('Object data'),
'content' => visible_whitespace(var_export($object_data, true))

View file

@ -78,7 +78,7 @@ class Receive extends BaseModule
$this->logger->info('Diaspora: Dispatching.');
Diaspora::dispatchPublic($msg);
Diaspora::dispatchPublic($msg, Diaspora::PUSHED);
}
/**
@ -92,8 +92,19 @@ class Receive extends BaseModule
$this->logger->info('Diaspora: Receiving post.');
$importer = User::getByGuid($this->parameters['guid']);
if (empty($importer)) {
// We haven't found the user.
// To avoid the remote system trying again we send the message that we accepted the content.
throw new HTTPException\AcceptedException();
}
$msg = $this->decodePost(false, $importer['prvkey'] ?? '');
if ($importer['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) {
// Communities aren't working with the Diaspora protoccol
// We throw an "accepted" here, so that the sender doesn't repeat the delivery
throw new HTTPException\AcceptedException();
}
$msg = $this->decodePost(false, $importer['prvkey']);
$this->logger->info('Diaspora: Dispatching.');

View file

@ -165,7 +165,7 @@ class Directory extends BaseModule
'img_hover' => $contact['name'],
'name' => $contact['name'],
'details' => $details,
'account_type' => Model\Contact::getAccountType($contact),
'account_type' => Model\Contact::getAccountType($contact['contact-type']),
'profile' => $profile,
'location' => $location_e,
'tags' => $contact['pub_keywords'],

View file

@ -21,18 +21,45 @@
namespace Friendica\Module\Notifications;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Contact\Introduction\Repository\Introduction;
use Friendica\Core\L10n;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Module\Response;
use Friendica\Module\Security\Login;
use Friendica\Navigation\Notifications\Factory;
use Friendica\Navigation\Notifications\Repository;
use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/**
* Interacting with the /notification command
*/
class Notification extends BaseModule
{
/** @var Introduction */
private $introductionRepo;
/** @var Repository\Notification */
private $notificationRepo;
/** @var Repository\Notify */
private $notifyRepo;
/** @var IManagePersonalConfigValues */
private $pconfig;
/** @var Factory\Notification */
private $notificationFactory;
public function __construct(Introduction $introductionRepo, Repository\Notification $notificationRepo, Factory\Notification $notificationFactory, Repository\Notify $notifyRepo, IManagePersonalConfigValues $pconfig, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->introductionRepo = $introductionRepo;
$this->notificationRepo = $notificationRepo;
$this->notificationFactory = $notificationFactory;
$this->notifyRepo = $notifyRepo;
$this->pconfig = $pconfig;
}
/**
* {@inheritDoc}
*
@ -45,26 +72,26 @@ class Notification extends BaseModule
protected function post(array $request = [])
{
if (!local_user()) {
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.'));
throw new HTTPException\UnauthorizedException($this->l10n->t('Permission denied.'));
}
$request_id = $this->parameters['id'] ?? false;
if ($request_id) {
$intro = DI::intro()->selectOneById($request_id, local_user());
$intro = $this->introductionRepo->selectOneById($request_id, local_user());
switch ($_POST['submit']) {
case DI::l10n()->t('Discard'):
case $this->l10n->t('Discard'):
Contact\Introduction::discard($intro);
DI::intro()->delete($intro);
$this->introductionRepo->delete($intro);
break;
case DI::l10n()->t('Ignore'):
case $this->l10n->t('Ignore'):
$intro->ignore();
DI::intro()->save($intro);
$this->introductionRepo->save($intro);
break;
}
DI::baseUrl()->redirect('notifications/intros');
$this->baseUrl->redirect('notifications/intros');
}
}
@ -76,15 +103,15 @@ class Notification extends BaseModule
protected function rawContent(array $request = [])
{
if (!local_user()) {
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.'));
throw new HTTPException\UnauthorizedException($this->l10n->t('Permission denied.'));
}
if (DI::args()->get(1) === 'mark' && DI::args()->get(2) === 'all') {
if ($this->args->get(1) === 'mark' && $this->args->get(2) === 'all') {
try {
DI::notification()->setAllSeenForUser(local_user());
$success = DI::notify()->setAllSeenForUser(local_user());
$this->notificationRepo->setAllSeenForUser(local_user());
$success = $this->notifyRepo->setAllSeenForUser(local_user());
} catch (\Exception $e) {
DI::logger()->warning('set all seen failed.', ['exception' => $e]);
$this->logger->warning('set all seen failed.', ['exception' => $e]);
$success = false;
}
@ -104,38 +131,71 @@ class Notification extends BaseModule
protected function content(array $request = []): string
{
if (!local_user()) {
notice(DI::l10n()->t('You must be logged in to show this page.'));
notice($this->l10n->t('You must be logged in to show this page.'));
return Login::form();
}
$request_id = $this->parameters['id'] ?? false;
if ($request_id) {
$Notify = DI::notify()->selectOneById($request_id);
if ($Notify->uid !== local_user()) {
throw new HTTPException\ForbiddenException();
}
if (DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) {
$Notify->setSeen();
DI::notify()->save($Notify);
} else {
if ($Notify->uriId) {
DI::notification()->setAllSeenForUser($Notify->uid, ['target-uri-id' => $Notify->uriId]);
}
DI::notify()->setAllSeenForRelatedNotify($Notify);
}
if ((string)$Notify->link) {
System::externalRedirect($Notify->link);
}
DI::baseUrl()->redirect();
if (isset($this->parameters['notify_id'])) {
$this->handleNotify($this->parameters['notify_id']);
} elseif (isset($this->parameters['id'])) {
$this->handleNotification($this->parameters['id']);
}
DI::baseUrl()->redirect('notifications/system');
$this->baseUrl->redirect('notifications/system');
return '';
}
private function handleNotify(int $notifyId)
{
$Notify = $this->notifyRepo->selectOneById($notifyId);
if ($Notify->uid !== local_user()) {
throw new HTTPException\ForbiddenException();
}
if ($this->pconfig->get(local_user(), 'system', 'detailed_notif')) {
$Notify->setSeen();
$this->notifyRepo->save($Notify);
} else {
if ($Notify->uriId) {
$this->notificationRepo->setAllSeenForUser($Notify->uid, ['target-uri-id' => $Notify->uriId]);
}
$this->notifyRepo->setAllSeenForRelatedNotify($Notify);
}
if ((string)$Notify->link) {
System::externalRedirect($Notify->link);
}
$this->baseUrl->redirect();
}
private function handleNotification(int $notificationId)
{
$Notification = $this->notificationRepo->selectOneById($notificationId);
if ($Notification->uid !== local_user()) {
throw new HTTPException\ForbiddenException();
}
if ($this->pconfig->get(local_user(), 'system', 'detailed_notif')) {
$Notification->setSeen();
$this->notificationRepo->save($Notification);
} else {
if ($Notification->parentUriId) {
$this->notificationRepo->setAllSeenForUser($Notification->uid, ['parent-uri-id' => $Notification->parentUriId]);
} else {
$Notification->setSeen();
$this->notificationRepo->save($Notification);
}
}
$message = $this->notificationFactory->getMessageFromNotification($Notification);
if ($message['link']) {
System::externalRedirect($message['link']);
}
$this->baseUrl->redirect();
}
}

View file

@ -28,7 +28,7 @@ use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Module\BaseNotifications;
use Friendica\Module\Response;
use Friendica\Navigation\Notifications\ValueObject\FormattedNotification;
use Friendica\Navigation\Notifications\ValueObject\FormattedNotify;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
@ -41,14 +41,14 @@ use Psr\Log\LoggerInterface;
*/
class Notifications extends BaseNotifications
{
/** @var \Friendica\Navigation\Notifications\Factory\FormattedNotification */
protected $formattedNotificationFactory;
/** @var \Friendica\Navigation\Notifications\Factory\FormattedNotify */
protected $formattedNotifyFactory;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, \Friendica\Navigation\Notifications\Factory\FormattedNotification $formattedNotificationFactory, array $server, array $parameters = [])
public function __construct(L10n $l10n, App\BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, \Friendica\Navigation\Notifications\Factory\FormattedNotify $formattedNotifyFactory, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->formattedNotificationFactory = $formattedNotificationFactory;
$this->formattedNotifyFactory = $formattedNotifyFactory;
}
/**
@ -59,30 +59,30 @@ class Notifications extends BaseNotifications
$notificationHeader = '';
$notifications = [];
$factory = $this->formattedNotificationFactory;
$factory = $this->formattedNotifyFactory;
if (($this->args->get(1) == 'network')) {
$notificationHeader = $this->t('Network Notifications');
$notifications = [
'ident' => FormattedNotification::NETWORK,
'ident' => FormattedNotify::NETWORK,
'notifications' => $factory->getNetworkList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE),
];
} elseif (($this->args->get(1) == 'system')) {
$notificationHeader = $this->t('System Notifications');
$notifications = [
'ident' => FormattedNotification::SYSTEM,
'ident' => FormattedNotify::SYSTEM,
'notifications' => $factory->getSystemList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE),
];
} elseif (($this->args->get(1) == 'personal')) {
$notificationHeader = $this->t('Personal Notifications');
$notifications = [
'ident' => FormattedNotification::PERSONAL,
'ident' => FormattedNotify::PERSONAL,
'notifications' => $factory->getPersonalList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE),
];
} elseif (($this->args->get(1) == 'home')) {
$notificationHeader = $this->t('Home Notifications');
$notifications = [
'ident' => FormattedNotification::HOME,
'ident' => FormattedNotify::HOME,
'notifications' => $factory->getHomeList($this->showAll, $this->firstItemNum, self::ITEMS_PER_PAGE),
];
} else {
@ -120,7 +120,7 @@ class Notifications extends BaseNotifications
];
// Loop trough ever notification This creates an array with the output html for each
// notification and apply the correct template according to the notificationtype (label).
/** @var FormattedNotification $Notification */
/** @var FormattedNotify $Notification */
foreach ($notifications['notifications'] as $Notification) {
$notificationArray = $Notification->toArray();

View file

@ -0,0 +1,295 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Module\Notifications;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Contact\Introduction\Repository\Introduction;
use Friendica\Content\ForumManager;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Group;
use Friendica\Model\Post;
use Friendica\Model\Verb;
use Friendica\Module\Register;
use Friendica\Module\Response;
use Friendica\Navigation\Notifications\Entity;
use Friendica\Navigation\Notifications\Exception\NoMessageException;
use Friendica\Navigation\Notifications\Factory;
use Friendica\Navigation\Notifications\Repository;
use Friendica\Navigation\Notifications\ValueObject;
use Friendica\Protocol\Activity;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler;
use GuzzleHttp\Psr7\Uri;
use Psr\Log\LoggerInterface;
class Ping extends BaseModule
{
/** @var Repository\Notification */
private $notificationRepo;
/** @var Introduction */
private $introductionRepo;
/** @var Factory\FormattedNavNotification */
private $formattedNavNotification;
public function __construct(Repository\Notification $notificationRepo, Introduction $introductionRepo, Factory\FormattedNavNotification $formattedNavNotification, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->notificationRepo = $notificationRepo;
$this->introductionRepo = $introductionRepo;
$this->formattedNavNotification = $formattedNavNotification;
}
protected function rawContent(array $request = [])
{
$regs = [];
$navNotifications = [];
$intro_count = 0;
$mail_count = 0;
$home_count = 0;
$network_count = 0;
$register_count = 0;
$sysnotify_count = 0;
$groups_unseen = [];
$forums_unseen = [];
$event_count = 0;
$today_event_count = 0;
$birthday_count = 0;
$today_birthday_count = 0;
if (local_user()) {
if (DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) {
$notifications = $this->notificationRepo->selectDetailedForUser(local_user());
} else {
$notifications = $this->notificationRepo->selectDigestForUser(local_user());
}
$condition = [
"`unseen` AND `uid` = ? AND NOT `origin` AND (`vid` != ? OR `vid` IS NULL)",
local_user(), Verb::getID(Activity::FOLLOW)
];
$items = Post::selectForUser(local_user(), ['wall', 'uid', 'uri-id'], $condition, ['limit' => 1000]);
if (DBA::isResult($items)) {
$items_unseen = Post::toArray($items, false);
$arr = ['items' => $items_unseen];
Hook::callAll('network_ping', $arr);
foreach ($items_unseen as $item) {
if ($item['wall']) {
$home_count++;
} else {
$network_count++;
}
}
}
DBA::close($items);
if ($network_count) {
// Find out how unseen network posts are spread across groups
$group_counts = Group::countUnseen();
if (DBA::isResult($group_counts)) {
foreach ($group_counts as $group_count) {
if ($group_count['count'] > 0) {
$groups_unseen[] = $group_count;
}
}
}
$forum_counts = ForumManager::countUnseenItems();
if (DBA::isResult($forum_counts)) {
foreach ($forum_counts as $forum_count) {
if ($forum_count['count'] > 0) {
$forums_unseen[] = $forum_count;
}
}
}
}
$intros = $this->introductionRepo->selectForUser(local_user());
$intro_count = $intros->count();
$myurl = DI::baseUrl() . '/profile/' . DI::app()->getLoggedInUserNickname();
$mail_count = DBA::count('mail', ["`uid` = ? AND NOT `seen` AND `from-url` != ?", local_user(), $myurl]);
if (intval(DI::config()->get('config', 'register_policy')) === Register::APPROVE && DI::app()->isSiteAdmin()) {
$regs = \Friendica\Model\Register::getPending();
if (DBA::isResult($regs)) {
$register_count = count($regs);
}
}
$cachekey = 'ping:events:' . local_user();
$ev = DI::cache()->get($cachekey);
if (is_null($ev)) {
$ev = DBA::selectToArray('event', ['type', 'start'],
["`uid` = ? AND `start` < ? AND `finish` > ? AND NOT `ignore`",
local_user(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utcNow()]);
if (DBA::isResult($ev)) {
DI::cache()->set($cachekey, $ev, Duration::HOUR);
}
}
if (DBA::isResult($ev)) {
$all_events = count($ev);
if ($all_events) {
$str_now = DateTimeFormat::localNow('Y-m-d');
foreach ($ev as $x) {
$bd = false;
if ($x['type'] === 'birthday') {
$birthday_count++;
$bd = true;
} else {
$event_count++;
}
if (DateTimeFormat::local($x['start'], 'Y-m-d') === $str_now) {
if ($bd) {
$today_birthday_count++;
} else {
$today_event_count++;
}
}
}
}
}
$navNotifications = array_map(function (Entity\Notification $notification) {
try {
return $this->formattedNavNotification->createFromNotification($notification);
} catch (NoMessageException $e) {
return null;
}
}, $notifications->getArrayCopy());
$navNotifications = array_filter($navNotifications);
$sysnotify_count = array_reduce($navNotifications, function (int $carry, ValueObject\FormattedNavNotification $navNotification) {
return $carry + ($navNotification->seen ? 0 : 1);
}, 0);
// merge all notification types in one array
foreach ($intros as $intro) {
$navNotifications[] = $this->formattedNavNotification->createFromIntro($intro);
}
if (DBA::isResult($regs)) {
if (count($regs) <= 1 || DI::pConfig()->get(local_user(), 'system', 'detailed_notif')) {
foreach ($regs as $reg) {
$navNotifications[] = $this->formattedNavNotification->createFromParams(
[
'name' => $reg['name'],
'url' => $reg['url'],
],
DI::l10n()->t('{0} requested registration'),
new \DateTime($reg['created'], new \DateTimeZone('UTC')),
new Uri(DI::baseUrl()->get(true) . '/admin/users/pending')
);
}
} else {
$navNotifications[] = $this->formattedNavNotification->createFromParams(
[
'name' => $regs[0]['name'],
'url' => $regs[0]['url'],
],
DI::l10n()->t('{0} and %d others requested registration', count($regs) - 1),
new \DateTime($regs[0]['created'], new \DateTimeZone('UTC')),
new Uri(DI::baseUrl()->get(true) . '/admin/users/pending')
);
}
}
// sort notifications by $[]['date']
$sort_function = function (ValueObject\FormattedNavNotification $a, ValueObject\FormattedNavNotification $b) {
$a = $a->toArray();
$b = $b->toArray();
// Unseen messages are kept at the top
if ($a['seen'] == $b['seen']) {
if ($a['timestamp'] == $b['timestamp']) {
return 0;
} else {
return $a['timestamp'] < $b['timestamp'] ? 1 : -1;
}
} else {
return $a['seen'] ? 1 : -1;
}
};
usort($navNotifications, $sort_function);
}
$sysmsgs = [];
$sysmsgs_info = [];
if (!empty($_SESSION['sysmsg'])) {
$sysmsgs = $_SESSION['sysmsg'];
unset($_SESSION['sysmsg']);
}
if (!empty($_SESSION['sysmsg_info'])) {
$sysmsgs_info = $_SESSION['sysmsg_info'];
unset($_SESSION['sysmsg_info']);
}
$notification_count = $sysnotify_count + $intro_count + $register_count;
$data = [];
$data['intro'] = $intro_count;
$data['mail'] = $mail_count;
$data['net'] = ($network_count < 1000) ? $network_count : '999+';
$data['home'] = ($home_count < 1000) ? $home_count : '999+';
$data['register'] = $register_count;
$data['events'] = $event_count;
$data['events-today'] = $today_event_count;
$data['birthdays'] = $birthday_count;
$data['birthdays-today'] = $today_birthday_count;
$data['groups'] = $groups_unseen;
$data['forums'] = $forums_unseen;
$data['notification'] = ($notification_count < 50) ? $notification_count : '49+';
$data['notifications'] = $navNotifications;
$data['sysmsgs'] = [
'notice' => $sysmsgs,
'info' => $sysmsgs_info
];
if (isset($_GET['callback'])) {
// JSONP support
header("Content-type: application/javascript");
echo $_GET['callback'] . '(' . json_encode(['result' => $data]) . ')';
exit;
} else {
System::jsonExit(['result' => $data]);
}
}
}

View file

@ -24,10 +24,14 @@ namespace Friendica\Module;
use Friendica\Core\Hook;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\APContact;
use Friendica\Model\Group;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Model\Tag;
use Friendica\Model\User;
use Friendica\Network\HTTPException;
use Friendica\Protocol\ActivityPub;
/**
* Outputs the permission tooltip HTML content for the provided item, photo or event id.
@ -44,9 +48,9 @@ class PermissionTooltip extends \Friendica\BaseModule
throw new HTTPException\BadRequestException(DI::l10n()->t('Wrong type "%s", expected one of: %s', $type, implode(', ', $expectedTypes)));
}
$condition = ['id' => $referenceId];
$condition = ['id' => $referenceId, 'uid' => [0, local_user()]];
if ($type == 'item') {
$fields = ['uid', 'psid', 'private'];
$fields = ['uid', 'psid', 'private', 'uri-id'];
$model = Post::selectFirst($fields, $condition);
} else {
$fields = ['uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
@ -72,13 +76,32 @@ class PermissionTooltip extends \Friendica\BaseModule
// Kept for backwards compatiblity
Hook::callAll('lockview_content', $model);
if ($model['uid'] != local_user() ||
isset($model['private'])
&& $model['private'] == Item::PRIVATE
&& empty($model['allow_cid'])
if ($type == 'item') {
$receivers = $this->fetchReceivers($model['uri-id']);
if (empty($receivers)) {
switch ($model['private']) {
case Item::PUBLIC:
$receivers = DI::l10n()->t('Public');
break;
case Item::UNLISTED:
$receivers = DI::l10n()->t('Unlisted');
break;
case Item::PRIVATE:
$receivers = DI::l10n()->t('Limited/Private');
break;
}
}
} else {
$receivers = '';
}
if (empty($model['allow_cid'])
&& empty($model['allow_gid'])
&& empty($model['deny_cid'])
&& empty($model['deny_gid']))
&& empty($model['deny_gid'])
&& empty($receivers))
{
echo DI::l10n()->t('Remote privacy information not available.');
exit;
@ -136,7 +159,75 @@ class PermissionTooltip extends \Friendica\BaseModule
$l[] = '<strike>' . $contact['name'] . '</strike>';
}
echo $o . implode(', ', $l);
if (!empty($l)) {
echo $o . implode(', ', $l);
} else {
echo $o . $receivers;
}
exit();
}
/**
* Fetch a list of receivers
*
* @param int $uriId
* @return string
*/
private function fetchReceivers(int $uriId):string
{
$own_url = '';
$uid = local_user();
if ($uid) {
$owner = User::getOwnerDataById($uid);
if (!empty($owner['url'])) {
$own_url = $owner['url'];
}
}
$receivers = [];
foreach (Tag::getByURIId($uriId, [Tag::TO, Tag::CC, Tag::BCC]) as $receiver) {
// We only display BCC when it contains the current user
if (($receiver['type'] == Tag::BCC) && ($receiver['url'] != $own_url)) {
continue;
}
if ($receiver['url'] == ActivityPub::PUBLIC_COLLECTION) {
$receivers[$receiver['type']][] = DI::l10n()->t('Public');
} else {
$apcontact = DBA::selectFirst('apcontact', ['name'], ['followers' => $receiver['url']]);
if (!empty($apcontact['name'])) {
$receivers[$receiver['type']][] = DI::l10n()->t('Followers (%s)', $apcontact['name']);
} elseif ($apcontact = APContact::getByURL($receiver['url'], false)) {
$receivers[$receiver['type']][] = $apcontact['name'];
} else {
$receivers[$receiver['type']][] = $receiver['name'];
}
}
}
$output = '';
foreach ($receivers as $type => $receiver) {
$max = DI::config()->get('system', 'max_receivers');
$total = count($receiver);
if ($total > $max) {
$receiver = array_slice($receiver, 0, $max);
$receiver[] = DI::l10n()->t('%d more', $total - $max);
}
switch ($type) {
case Tag::TO:
$output .= DI::l10n()->t('<b>To:</b> %s<br>', implode(', ', $receiver));
break;
case Tag::CC:
$output .= DI::l10n()->t('<b>CC:</b> %s<br>', implode(', ', $receiver));
break;
case Tag::BCC:
$output .= DI::l10n()->t('<b>BCC:</b> %s<br>', implode(', ', $receiver));
break;
}
}
return $output;
}
}

View file

@ -288,9 +288,10 @@ class Photo extends BaseModule
}
}
If (($contact['uid'] != 0) && empty($contact['photo']) && empty($contact['avatar'])) {
if (!empty($contact['uid']) && empty($contact['photo']) && empty($contact['avatar'])) {
$contact = Contact::getByURL($contact['url'], false, ['avatar', 'photo', 'xmpp', 'addr']);
}
if (!empty($contact['photo']) && !empty($contact['avatar'])) {
// Fetch photo directly
$resourceid = MPhoto::ridFromURI($contact['photo']);

View file

@ -118,7 +118,7 @@ class Status extends BaseProfile
$commvisitor = $commpage && $remote_contact;
DI::page()['aside'] .= Widget::postedByYear(DI::baseUrl() . '/profile/' . $profile['nickname'] . '/status', $profile['profile_uid'] ?? 0, true);
DI::page()['aside'] .= Widget::categories(DI::baseUrl() . '/profile/' . $profile['nickname'] . '/status', XML::escape($category));
DI::page()['aside'] .= Widget::categories($profile['uid'], DI::baseUrl() . '/profile/' . $profile['nickname'] . '/status', $category);
DI::page()['aside'] .= Widget::tagCloud($profile['uid']);
if (Security::canWriteToUserWall($profile['uid'])) {
@ -159,7 +159,7 @@ class Status extends BaseProfile
// Does the profile page belong to a forum?
// If not then we can improve the performance with an additional condition
$condition2 = ['uid' => $profile['uid'], 'page-flags' => [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]];
$condition2 = ['uid' => $profile['uid'], 'account-type' => User::ACCOUNT_TYPE_COMMUNITY];
if (!DBA::exists('user', $condition2)) {
$condition = DBA::mergeConditions($condition, ['contact-id' => $profile['id']]);
}

View file

@ -380,11 +380,11 @@ class Register extends BaseModule
'type' => Model\Notification\Type::SYSTEM,
'event' => 'SYSTEM_REGISTER_REQUEST',
'uid' => $admin['uid'],
'link' => $base_url . '/admin/users/',
'link' => DI::baseUrl()->get(true) . '/admin/users/',
'source_name' => $user['username'],
'source_mail' => $user['email'],
'source_nick' => $user['nickname'],
'source_link' => $base_url . '/admin/users/',
'source_link' => DI::baseUrl()->get(true) . '/admin/users/',
'source_photo' => User::getAvatarUrl($user, Proxy::SIZE_THUMB),
'show_in_notification_page' => false
]);

View file

@ -208,7 +208,7 @@ class Index extends BaseSettings
'$baseurl' => DI::baseUrl()->get(true),
]);
$personal_account = !in_array($profile['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP]);
$personal_account = ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY);
$tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl');
$o .= Renderer::replaceMacros($tpl, [