Merge remote-tracking branch 'upstream/develop' into network-thread-view

This commit is contained in:
Michael 2021-10-02 21:00:10 +00:00
commit eea355ae3b
31 changed files with 886 additions and 870 deletions

View file

@ -32,7 +32,7 @@ General
* m - Status Messages and Posts
* r - Profile Details
* h - Photo Albums
* v - Videos
* d - Media
* e - Events and Calendar
* t - Personal Notes
* o - Scheduled Posts
@ -49,12 +49,13 @@ General
* h - Only show hidden contacts
* e - Edit contact groups
../contacts (single contact view)
../contact (single contact view)
-------------------------------
* m - Status messages
* p - Posts and Comments
* d - Media
* o - Profile
* t - Contacts
* d - Common friends
* r - Advanced
../message

View file

@ -479,6 +479,22 @@ Hook data:
- **uid** (input): the user to return the contact data for (can be empty for public contacts).
- **result** (output): Set by the hook function to indicate a successful detection.
### support_follow
Called to assert whether a connector addon provides follow capabilities.
Hook data:
- **protocol** (input): shorthand for the protocol. List of values is available in `src/Core/Protocol.php`.
- **result** (output): should be true if the connector provides follow capabilities, left alone otherwise.
### support_revoke_follow
Called to assert whether a connector addon provides follow revocation capabilities.
Hook data:
- **protocol** (input): shorthand for the protocol. List of values is available in `src/Core/Protocol.php`.
- **result** (output): should be true if the connector provides follow revocation capabilities, left alone otherwise.
### follow
Called before adding a new contact for a user to handle non-native network remote contact (like Twitter).
@ -497,6 +513,14 @@ Hook data:
- **two_way** (input): wether to stop sharing with the remote contact as well.
- **result** (output): wether the unfollowing is successful or not.
### revoke_follow
Called when making a remote contact on a non-native network (like Twitter) unfollow you.
Hook data:
- **contact** (input): the remote contact (uid = local revoking user id) array.
- **result** (output): a boolean value indicating wether the operation was successful or not.
## Complete list of hook callbacks
Here is a complete list of all hook callbacks with file locations (as of 24-Sep-2018). Please see the source for details of any hooks not documented above.
@ -666,7 +690,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll('contact_photo_menu', $args);
Hook::callAll('follow', $arr);
Hook::callAll('unfollow', $hook_data);
### src/Model/Profile.php
@ -750,6 +773,13 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll('logged_in', $a->user);
### src/Core/Protocol.php
Hook::callAll('support_follow', $hook_data);
Hook::callAll('support_revoke_follow', $hook_data);
Hook::callAll('unfollow', $hook_data);
Kook::callAll('revoke_follow', $hook_data);
### src/Core/StorageManager
Hook::callAll('storage_instance', $data);

View file

@ -356,7 +356,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
Hook::callAll('contact_photo_menu', $args);
Hook::callAll('follow', $arr);
Hook::callAll('unfollow', $hook_data);
### src/Model/Profile.php
@ -414,6 +413,13 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
Hook::callAll('logged_in', $a->user);
### src/Core/Protocol.php
Hook::callAll('support_follow', $hook_data);
Hook::callAll('support_revoke_follow', $hook_data);
Hook::callAll('unfollow', $hook_data);
Kook::callAll('revoke_follow', $hook_data);
### src/Core/StorageManager
Hook::callAll('storage_instance', $data);

View file

@ -242,17 +242,11 @@ function events_content(App $a)
}
if ((DI::args()->getArgc() > 2) && (DI::args()->getArgv()[1] === 'ignore') && intval(DI::args()->getArgv()[2])) {
q("UPDATE `event` SET `ignore` = 1 WHERE `id` = %d AND `uid` = %d",
intval(DI::args()->getArgv()[2]),
intval(local_user())
);
DBA::update('event', ['ignore' => true], ['id' => DI::args()->getArgv()[2], 'uid' => local_user()]);
}
if ((DI::args()->getArgc() > 2) && (DI::args()->getArgv()[1] === 'unignore') && intval(DI::args()->getArgv()[2])) {
q("UPDATE `event` SET `ignore` = 0 WHERE `id` = %d AND `uid` = %d",
intval(DI::args()->getArgv()[2]),
intval(local_user())
);
DBA::update('event', ['ignore' => false], ['id' => DI::args()->getArgv()[2], 'uid' => local_user()]);
}
if ($a->getThemeInfoValue('events_in_profile')) {
@ -444,13 +438,7 @@ function events_content(App $a)
}
if (($mode === 'edit' || $mode === 'copy') && $event_id) {
$r = q("SELECT * FROM `event` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($event_id),
intval(local_user())
);
if (DBA::isResult($r)) {
$orig_event = $r[0];
}
$orig_event = DBA::selectFirst('event', [], ['id' => $event_id, 'uid' => local_user()]);
}
// Passed parameters overrides anything found in the DB

View file

@ -158,12 +158,9 @@ function message_content(App $a)
DI::baseUrl()->redirect('message/' . $conversation['id'] );
} else {
$r = q("SELECT `parent-uri`,`convid` FROM `mail` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval(DI::args()->getArgv()[2]),
intval(local_user())
);
if (DBA::isResult($r)) {
$parent = $r[0]['parent-uri'];
$parentmail = DBA::selectFirst('mail', ['parent-uri'], ['id' => DI::args()->getArgv()[2], 'uid' => local_user()]);
if (DBA::isResult($parentmail)) {
$parent = $parentmail['parent-uri'];
if (!DBA::delete('mail', ['parent-uri' => $parent, 'uid' => local_user()])) {
notice(DI::l10n()->t('Conversation was not removed.'));

View file

@ -200,12 +200,7 @@ function photos_post(App $a)
return; // NOTREACHED
}
$r = q("SELECT `album` FROM `photo` WHERE `album` = '%s' AND `uid` = %d",
DBA::escape($album),
intval($page_owner_uid)
);
if (!DBA::isResult($r)) {
if (!DBA::exists('photo', ['album' => $album, 'uid' => $page_owner_uid])) {
notice(DI::l10n()->t('Album not found.'));
DI::baseUrl()->redirect('photos/' . $user['nickname'] . '/album');
return; // NOTREACHED
@ -321,7 +316,7 @@ function photos_post(App $a)
}
if (!empty($_POST['rotate']) && (intval($_POST['rotate']) == 1 || intval($_POST['rotate']) == 2)) {
Logger::log('rotate');
Logger::notice('rotate');
$photo = Photo::getPhotoForUser($page_owner_uid, $resource_id);
@ -681,7 +676,7 @@ function photos_post(App $a)
$type = Images::getMimeTypeBySource($src, $filename, $type);
Logger::log('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', Logger::DEBUG);
Logger::info('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes');
$maximagesize = DI::config()->get('system', 'maximagesize');
@ -701,14 +696,14 @@ function photos_post(App $a)
return;
}
Logger::log('mod/photos.php: photos_post(): loading the contents of ' . $src , Logger::DEBUG);
Logger::info('loading the contents of ' . $src);
$imagedata = @file_get_contents($src);
$image = new Image($imagedata, $type);
if (!$image->isValid()) {
Logger::log('mod/photos.php: photos_post(): unable to process image' , Logger::DEBUG);
Logger::info('unable to process image');
notice(DI::l10n()->t('Unable to process image.'));
@unlink($src);
$foo = 0;
@ -737,7 +732,7 @@ function photos_post(App $a)
$r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0 , 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
if (!$r) {
Logger::log('mod/photos.php: photos_post(): image store failed', Logger::DEBUG);
Logger::info('image store failed');
notice(DI::l10n()->t('Image upload failed.'));
return;
}
@ -1020,13 +1015,15 @@ function photos_content(App $a)
$drop_url = DI::args()->getQueryString();
return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => DI::l10n()->t('Do you really want to delete this photo album and all its photos?'),
'$confirm' => DI::l10n()->t('Delete Album'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'dropalbum',
'$l10n' => [
'message' => DI::l10n()->t('Do you really want to delete this photo album and all its photos?'),
'confirm' => DI::l10n()->t('Delete Album'),
'cancel' => DI::l10n()->t('Cancel'),
],
'$method' => 'post',
'$confirm_url' => $drop_url,
'$confirm_name' => 'dropalbum',
'$confirm_value' => 'dropalbum',
'$cancel' => DI::l10n()->t('Cancel'),
]);
}
@ -1127,13 +1124,15 @@ function photos_content(App $a)
$drop_url = DI::args()->getQueryString();
return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => DI::l10n()->t('Do you really want to delete this photo?'),
'$confirm' => DI::l10n()->t('Delete Photo'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'delete',
'$l10n' => [
'message' => DI::l10n()->t('Do you really want to delete this photo?'),
'confirm' => DI::l10n()->t('Delete Photo'),
'cancel' => DI::l10n()->t('Cancel'),
],
'$method' => 'post',
'$confirm_url' => $drop_url,
'$confirm_name' => 'delete',
'$confirm_value' => 'delete',
'$cancel' => DI::l10n()->t('Cancel'),
]);
}

View file

@ -1,261 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, 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/>.
*
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Attach;
use Friendica\Model\Item;
use Friendica\Model\Profile;
use Friendica\Model\User;
use Friendica\Module\BaseProfile;
use Friendica\Security\Security;
use Friendica\Network\HTTPException;
function videos_init(App $a)
{
if (DI::config()->get('system', 'block_public') && !Session::isAuthenticated()) {
return;
}
Nav::setSelected('home');
if (DI::args()->getArgc() > 1) {
$owner = User::getOwnerDataByNick(DI::args()->getArgv()[1]);
if (empty($owner)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
// If not there, create 'aside' empty
if (!isset(DI::page()['aside'])) {
DI::page()['aside'] = '';
}
DI::page()['aside'] .= Widget\VCard::getHTML($owner);
$tpl = Renderer::getMarkupTemplate("videos_head.tpl");
DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl);
}
return;
}
function videos_post(App $a)
{
$user = User::getByNickname(DI::args()->getArgv()[1]);
if (!DBA::isResult($user)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
if (local_user() != $user['uid']) {
DI::baseUrl()->redirect('videos/' . $user['nickname']);
}
if ((DI::args()->getArgc() == 2) && !empty($_POST['delete']) && !empty($_POST['id'])) {
$video_id = $_POST['id'];
if (Attach::exists(['id' => $video_id, 'uid' => local_user()])) {
// delete the attachment
Attach::delete(['id' => $video_id, 'uid' => local_user()]);
// delete items where the attach is used
Item::deleteForUser(['`attach` LIKE ? AND `uid` = ?',
'%attach/' . $video_id . '%',
local_user()
], local_user());
}
DI::baseUrl()->redirect('videos/' . $user['nickname']);
return; // NOTREACHED
}
DI::baseUrl()->redirect('videos/' . $user['nickname']);
}
function videos_content(App $a)
{
// URLs (most aren't currently implemented):
// videos/name
// videos/name/upload
// videos/name/upload/xxxxx (xxxxx is album name)
// videos/name/album/xxxxx
// videos/name/album/xxxxx/edit
// videos/name/video/xxxxx
// videos/name/video/xxxxx/edit
$user = User::getByNickname(DI::args()->getArgv()[1]);
if (!DBA::isResult($user)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
if (DI::config()->get('system', 'block_public') && !Session::isAuthenticated()) {
notice(DI::l10n()->t('Public access denied.'));
return;
}
if (empty($user)) {
notice(DI::l10n()->t('No videos selected') . EOL );
return;
}
$profile = Profile::getByUID($user['uid']);
//$phototypes = Photo::supportedTypes();
$_SESSION['video_return'] = DI::args()->getCommand();
//
// Parse arguments
//
if (DI::args()->getArgc() > 3) {
$datatype = DI::args()->getArgv()[2];
} elseif((DI::args()->getArgc() > 2) && (DI::args()->getArgv()[2] === 'upload')) {
$datatype = 'upload';
} else {
$datatype = 'summary';
}
//
// Setup permissions structures
//
$can_post = false;
$visitor = 0;
$remote_contact = false;
$contact_id = 0;
$community_page = (($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false);
if ((local_user()) && (local_user() == $user['uid'])) {
$can_post = true;
} elseif ($community_page && !empty(Session::getRemoteContactID($user['uid']))) {
$contact_id = Session::getRemoteContactID($user['uid']);
$can_post = true;
$remote_contact = true;
$visitor = $contact_id;
}
// perhaps they're visiting - but not a community page, so they wouldn't have write access
if (!empty(Session::getRemoteContactID($user['uid'])) && !$visitor) {
$contact_id = Session::getRemoteContactID($user['uid']);
$remote_contact = true;
}
if ($user['hidewall'] && (local_user() != $user['uid']) && !$remote_contact) {
notice(DI::l10n()->t('Access to this item is restricted.'));
return;
}
$sql_extra = Security::getPermissionsSQLByUserId($user['uid']);
$o = "";
// tabs
$_is_owner = (local_user() && (local_user() == $user['uid']));
$o .= BaseProfile::getTabsHTML($a, 'videos', $_is_owner, $user['nickname'], $profile['hide-friends']);
//
// dispatch request
//
if ($datatype === 'upload') {
return; // no uploading for now
// DELETED -- look at mod/photos.php if you want to implement
}
if ($datatype === 'album') {
return; // no albums for now
// DELETED -- look at mod/photos.php if you want to implement
}
if ($datatype === 'video') {
return; // no single video view for now
// DELETED -- look at mod/photos.php if you want to implement
}
// Default - show recent videos (no upload link for now)
//$o = '';
$total = 0;
$r = q("SELECT hash FROM `attach` WHERE `uid` = %d AND filetype LIKE '%%video%%'
$sql_extra GROUP BY hash",
intval($user['uid'])
);
if (DBA::isResult($r)) {
$total = count($r);
}
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 20);
$r = q("SELECT hash, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`created`) AS `created`,
ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`filetype`) as `filetype`
FROM `attach`
WHERE `uid` = %d AND filetype LIKE '%%video%%'
$sql_extra GROUP BY hash ORDER BY `created` DESC LIMIT %d , %d",
intval($user['uid']),
$pager->getStart(),
$pager->getItemsPerPage()
);
$videos = [];
if (DBA::isResult($r)) {
foreach ($r as $rr) {
$alt_e = $rr['filename'];
/// @todo The album isn't part of the above query. This seems to be some unfinished code that needs to be reworked completely.
$rr['album'] = '';
$name_e = $rr['album'];
$videos[] = [
'id' => $rr['id'],
'link' => DI::baseUrl() . '/videos/' . $user['nickname'] . '/video/' . $rr['hash'],
'title' => DI::l10n()->t('View Video'),
'src' => DI::baseUrl() . '/attach/' . $rr['id'] . '?attachment=0',
'alt' => $alt_e,
'mime' => $rr['filetype'],
'album' => [
'link' => DI::baseUrl() . '/videos/' . $user['nickname'] . '/album/' . bin2hex($rr['album']),
'name' => $name_e,
'alt' => DI::l10n()->t('View Album'),
],
];
}
}
$tpl = Renderer::getMarkupTemplate('videos_recent.tpl');
$o .= Renderer::replaceMacros($tpl, [
'$title' => DI::l10n()->t('Recent Videos'),
'$can_post' => $can_post,
'$upload' => [DI::l10n()->t('Upload New Videos'), DI::baseUrl() . '/videos/' . $user['nickname'] . '/upload'],
'$videos' => $videos,
'$delete_url' => (($can_post) ? DI::baseUrl() . '/videos/' . $user['nickname'] : false)
]);
$o .= $pager->renderFull($total);
return $o;
}

View file

@ -71,6 +71,44 @@ class Protocol
const PHANTOM = 'unkn'; // Place holder
/**
* Returns whether the provided protocol supports following
*
* @param $protocol
* @return bool
* @throws HTTPException\InternalServerErrorException
*/
public static function supportsFollow($protocol): bool
{
if (in_array($protocol, self::NATIVE_SUPPORT)) {
return true;
}
$result = null;
Hook::callAll('support_follow', $result);
return $result === true;
}
/**
* Returns whether the provided protocol supports revoking inbound follows
*
* @param $protocol
* @return bool
* @throws HTTPException\InternalServerErrorException
*/
public static function supportsRevokeFollow($protocol): bool
{
if (in_array($protocol, self::NATIVE_SUPPORT)) {
return true;
}
$result = null;
Hook::callAll('support_revoke_follow', $result);
return $result === true;
}
/**
* Returns the address string for the provided profile URL
*
@ -212,7 +250,7 @@ class Protocol
return ActivityPub\Transmitter::sendContactUndo($contact['url'], $contact['id'], $user['uid']);
}
// Catch-all addon hook
// Catch-all hook for connector addons
$hook_data = [
'contact' => $contact,
'two_way' => $two_way,
@ -222,4 +260,36 @@ class Protocol
return $hook_data['result'];
}
/**
* Revoke an incoming follow from the provided contact
*
* @param array $contact Private contact (uid != 0) array
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function revokeFollow(array $contact)
{
if (empty($contact['network'])) {
throw new \InvalidArgumentException('Missing network key in contact array');
}
$protocol = $contact['network'];
if ($protocol == Protocol::DFRN && !empty($contact['protocol'])) {
$protocol = $contact['protocol'];
}
if ($protocol == Protocol::ACTIVITYPUB) {
return ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']);
}
// Catch-all hook for connector addons
$hook_data = [
'contact' => $contact,
'result' => null,
];
Hook::callAll('revoke_follow', $hook_data);
return $hook_data['result'];
}
}

View file

@ -849,6 +849,36 @@ class Contact
return $result;
}
/**
* Revoke follow privileges of the remote user contact
*
* @param array $contact Contact unfriended
* @return bool|null Whether the remote operation is successful or null if no remote operation was performed
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function revokeFollow(array $contact): bool
{
if (empty($contact['network'])) {
throw new \InvalidArgumentException('Empty network in contact array');
}
if (empty($contact['uid'])) {
throw new \InvalidArgumentException('Unexpected public contact record');
}
$result = Protocol::revokeFollow($contact);
// A null value here means the remote network doesn't support explicit follow revocation, we can still
// break the locally recorded relationship
if ($result !== false) {
DBA::update('contact', ['rel' => $contact['rel'] == self::FRIEND ? self::SHARING : self::NOTHING], ['id' => $contact['id']]);
}
return $result;
}
/**
* Marks a contact for archival after a communication issue delay
*
@ -964,7 +994,6 @@ class Contact
$pm_url = '';
$status_link = '';
$photos_link = '';
$contact_drop_link = '';
$poke_link = '';
if ($uid == 0) {
@ -1016,13 +1045,9 @@ class Contact
$posts_link = DI::baseUrl() . '/contact/' . $contact['id'] . '/conversations';
if (!$contact['self']) {
$contact_drop_link = DI::baseUrl() . '/contact/' . $contact['id'] . '/drop?confirm=1';
}
$follow_link = '';
$unfollow_link = '';
if (!$contact['self'] && in_array($contact['network'], Protocol::NATIVE_SUPPORT)) {
if (!$contact['self'] && Protocol::supportsFollow($contact['network'])) {
if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
$unfollow_link = 'unfollow?url=' . urlencode($contact['url']) . '&auto=1';
} elseif(!$contact['pending']) {
@ -1030,10 +1055,6 @@ class Contact
}
}
if (!empty($follow_link) || !empty($unfollow_link)) {
$contact_drop_link = '';
}
/**
* Menu array:
* "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
@ -1053,7 +1074,6 @@ class Contact
'photos' => [DI::l10n()->t('View Photos') , $photos_link , true],
'network' => [DI::l10n()->t('Network Posts') , $posts_link , false],
'edit' => [DI::l10n()->t('View Contact') , $contact_url , false],
'drop' => [DI::l10n()->t('Drop Contact') , $contact_drop_link, false],
'pm' => [DI::l10n()->t('Send PM') , $pm_url , false],
'poke' => [DI::l10n()->t('Poke') , $poke_link , false],
'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true],
@ -1340,12 +1360,13 @@ class Contact
* @param bool $thread_mode
* @param int $update Update mode
* @param int $parent Item parent ID for the update mode
* @param bool $only_media Only display media content
* @return string posts in HTML
* @throws \Exception
*/
public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0, $parent = 0)
public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0, $parent = 0, bool $only_media = false)
{
return self::getPostsFromId(self::getIdForURL($contact_url), $thread_mode, $update, $parent);
return self::getPostsFromId(self::getIdForURL($contact_url), $thread_mode, $update, $parent, $only_media);
}
/**
@ -1354,14 +1375,13 @@ class Contact
* @param int $cid Contact ID
* @param bool $thread_mode
* @param int $update Update mode
* @param int $parent Item parent ID for the update mode
* @param int $parent Item parent ID for the update mode
* @param bool $only_media Only display media content
* @return string posts in HTML
* @throws \Exception
*/
public static function getPostsFromId($cid, $thread_mode = false, $update = 0, $parent = 0)
public static function getPostsFromId($cid, $thread_mode = false, $update = 0, $parent = 0, bool $only_media = false)
{
$a = DI::app();
$contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $cid]);
if (!DBA::isResult($contact)) {
return '';
@ -1392,6 +1412,11 @@ class Contact
}
}
if ($only_media) {
$condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))",
Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]);
}
if (DI::mode()->isMobile()) {
$itemsPerPage = DI::pConfig()->get(local_user(), 'system', 'itemspage_mobile_network',
DI::config()->get('system', 'itemspage_network_mobile'));

View file

@ -68,15 +68,14 @@ class BaseProfile extends BaseModule
'id' => 'photo-tab',
'accesskey' => 'h',
],
// @todo Currently deactivated since it doesn't really work
// [
// 'label' => DI::l10n()->t('Videos'),
// 'url' => DI::baseUrl() . '/videos/' . $nickname,
// 'sel' => $current == 'videos' ? 'active' : '',
// 'title' => DI::l10n()->t('Videos'),
// 'id' => 'video-tab',
// 'accesskey' => 'v',
// ],
[
'label' => DI::l10n()->t('Media'),
'url' => $baseProfileUrl . '/media',
'sel' => $current == 'media' ? 'active' : '',
'title' => DI::l10n()->t('Media'),
'id' => 'media-tab',
'accesskey' => 'd',
],
];
// the calendar link for the full featured events calendar

View file

@ -52,6 +52,7 @@ class Contact extends BaseModule
const TAB_PROFILE = 3;
const TAB_CONTACTS = 4;
const TAB_ADVANCED = 5;
const TAB_MEDIA = 6;
private static function batchActions()
{
@ -86,12 +87,6 @@ class Contact extends BaseModule
self::toggleIgnoreContact($cdata['public']);
$count_actions++;
}
if (!empty($_POST['contacts_batch_drop']) && $cdata['user']
&& self::dropContact($cdata['user'], local_user())
) {
$count_actions++;
}
}
if ($count_actions > 0) {
info(DI::l10n()->tt('%d contact edited.', '%d contacts edited.', $count_actions));
@ -229,31 +224,6 @@ class Contact extends BaseModule
Model\Contact\User::setIgnored($contact_id, local_user(), $ignored);
}
/**
* @param int $contact_id Id for contact with uid != 0
* @param int $uid Id for user we want to drop the contact for
* @return bool
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function dropContact(int $contact_id, int $uid): bool
{
$contact = Model\Contact::getContactForUser($contact_id, $uid);
if (!DBA::isResult($contact)) {
return false;
}
$owner = Model\User::getOwnerDataById($uid);
if (!DBA::isResult($owner)) {
return false;
}
Model\Contact::terminateFriendship($owner, $contact, true);
Model\Contact::remove($contact['id']);
return true;
}
public static function content(array $parameters = [], $update = 0)
{
if (!local_user()) {
@ -372,7 +342,7 @@ class Contact extends BaseModule
}
if ($cmd === 'posts') {
return self::getPostsHTML($a, $contact_id);
return self::getPostsHTML($contact_id);
}
if ($cmd === 'conversations') {
@ -425,36 +395,6 @@ class Contact extends BaseModule
DI::baseUrl()->redirect('contact/' . $cdata['public']);
// NOTREACHED
}
if ($cmd === 'drop' && $cdata['user']) {
// Check if we should do HTML-based delete confirmation
if (!empty($_REQUEST['confirm'])) {
DI::page()['aside'] = '';
return Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_drop_confirm.tpl'), [
'$header' => DI::l10n()->t('Drop contact'),
'$contact' => self::getContactTemplateVars($orig_record),
'$method' => 'get',
'$message' => DI::l10n()->t('Do you really want to delete this contact?'),
'$confirm' => DI::l10n()->t('Yes'),
'$confirm_url' => DI::args()->getCommand(),
'$confirm_name' => 't',
'$confirm_value' => BaseModule::getFormSecurityToken('contact_action'),
'$cancel' => DI::l10n()->t('Cancel'),
]);
}
// Now check how the user responded to the confirmation query
if (!empty($_REQUEST['canceled'])) {
DI::baseUrl()->redirect('contact');
}
if (self::dropContact($cdata['user'], local_user())) {
info(DI::l10n()->t('Contact has been removed.'));
}
DI::baseUrl()->redirect('contact');
// NOTREACHED
}
}
$_SESSION['return_path'] = DI::args()->getQueryString();
@ -856,13 +796,11 @@ class Contact extends BaseModule
'$cmd' => DI::args()->getCommand(),
'$contacts' => $contacts,
'$form_security_token' => BaseModule::getFormSecurityToken('contact_batch_actions'),
'$contact_drop_confirm' => DI::l10n()->t('Do you really want to delete this contact?'),
'multiselect' => 1,
'$batch_actions' => [
'contacts_batch_update' => DI::l10n()->t('Update'),
'contacts_batch_block' => DI::l10n()->t('Block') . '/' . DI::l10n()->t('Unblock'),
'contacts_batch_ignore' => DI::l10n()->t('Ignore') . '/' . DI::l10n()->t('Unignore'),
'contacts_batch_drop' => DI::l10n()->t('Delete'),
],
'$h_batch_actions' => DI::l10n()->t('Batch Actions'),
'$paginate' => $pager->renderFull($total),
@ -911,6 +849,14 @@ class Contact extends BaseModule
'id' => 'posts-tab',
'accesskey' => 'p',
],
[
'label' => DI::l10n()->t('Media'),
'url' => 'contact/' . $pcid . '/media',
'sel' => (($active_tab == self::TAB_MEDIA) ? 'active' : ''),
'title' => DI::l10n()->t('Posts containing media objects'),
'id' => 'media-tab',
'accesskey' => 'd',
],
[
'label' => DI::l10n()->t('Profile'),
'url' => 'contact/' . $cid,
@ -979,7 +925,7 @@ class Contact extends BaseModule
return $o;
}
private static function getPostsHTML($a, $contact_id)
private static function getPostsHTML(int $contact_id)
{
$contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id, 'deleted' => false]);
@ -1145,13 +1091,13 @@ class Contact extends BaseModule
'id' => 'toggle-ignore',
];
if ($contact['uid'] != 0) {
$contact_actions['delete'] = [
'label' => DI::l10n()->t('Delete'),
'url' => 'contact/' . $contact['id'] . '/drop?t=' . $formSecurityToken,
'title' => DI::l10n()->t('Delete contact'),
if ($contact['uid'] != 0 && Protocol::supportsRevokeFollow($contact['network']) && in_array($contact['rel'], [Model\Contact::FOLLOWER, Model\Contact::FRIEND])) {
$contact_actions['revoke_follow'] = [
'label' => DI::l10n()->t('Revoke Follow'),
'url' => 'contact/' . $contact['id'] . '/revoke',
'title' => DI::l10n()->t('Revoke the follow from this contact'),
'sel' => '',
'id' => 'delete',
'id' => 'revoke_follow',
];
}

View file

@ -0,0 +1,54 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, 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\Contact;
use Friendica\BaseModule;
use Friendica\Content\Widget;
use Friendica\DI;
use Friendica\Model;
use Friendica\Model\Contact as ModelContact;
use Friendica\Module\Contact;
use Friendica\Network\HTTPException\BadRequestException;
/**
* GUI for media posts of a contact
*/
class Media extends BaseModule
{
public static function content(array $parameters = [])
{
$cid = $parameters['id'];
$contact = Model\Contact::selectFirst([], ['id' => $cid]);
if (empty($contact)) {
throw new BadRequestException(DI::l10n()->t('Contact not found.'));
}
DI::page()['aside'] = Widget\VCard::getHTML($contact);
$o = Contact::getTabsHTML($contact, Contact::TAB_MEDIA);
$o .= ModelContact::getPostsFromUrl($contact['url'], false, 0, 0, true);
return $o;
}
}

View file

@ -0,0 +1,108 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, 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\Contact;
use Friendica\BaseModule;
use Friendica\Content\Nav;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model;
use Friendica\Module\Contact;
use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException;
class Revoke extends BaseModule
{
/** @var array */
private static $contact;
public static function init(array $parameters = [])
{
if (!local_user()) {
return;
}
$data = Model\Contact::getPublicAndUserContactID($parameters['id'], local_user());
if (!DBA::isResult($data)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('Unknown contact.'));
}
if (empty($data['user'])) {
throw new HTTPException\ForbiddenException();
}
self::$contact = Model\Contact::getById($data['user']);
if (self::$contact['deleted']) {
throw new HTTPException\NotFoundException(DI::l10n()->t('Contact is deleted.'));
}
if (!empty(self::$contact['network']) && self::$contact['network'] == Protocol::PHANTOM) {
throw new HTTPException\NotFoundException(DI::l10n()->t('Contact is being deleted.'));
}
}
public static function post(array $parameters = [])
{
if (!local_user()) {
throw new HTTPException\UnauthorizedException();
}
self::checkFormSecurityTokenRedirectOnError('contact/' . $parameters['id'], 'contact_revoke');
$result = Model\Contact::revokeFollow(self::$contact);
if ($result === true) {
notice(DI::l10n()->t('Follow was successfully revoked.'));
} elseif ($result === null) {
notice(DI::l10n()->t('Follow was successfully revoked, however the remote contact won\'t be aware of this revokation.'));
} else {
notice(DI::l10n()->t('Unable to revoke follow, please try again later or contact the administrator.'));
}
DI::baseUrl()->redirect('contact/' . $parameters['id']);
}
public static function content(array $parameters = []): string
{
if (!local_user()) {
return Login::form($_SERVER['REQUEST_URI']);
}
Nav::setSelected('contact');
return Renderer::replaceMacros(Renderer::getMarkupTemplate('contact_drop_confirm.tpl'), [
'$l10n' => [
'header' => DI::l10n()->t('Revoke Follow'),
'message' => DI::l10n()->t('Do you really want to revoke this contact\'s follow? This cannot be undone and they will have to manually follow you back again.'),
'confirm' => DI::l10n()->t('Yes'),
'cancel' => DI::l10n()->t('Cancel'),
],
'$contact' => Contact::getContactTemplateVars(self::$contact),
'$method' => 'post',
'$confirm_url' => DI::args()->getCommand(),
'$confirm_name' => 'form_security_token',
'$confirm_value' => BaseModule::getFormSecurityToken('contact_revoke'),
]);
}
}

View file

@ -0,0 +1,53 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, 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\Profile;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Profile as ProfileModel;
use Friendica\Module\BaseProfile;
use Friendica\Network\HTTPException;
class Media extends BaseProfile
{
public static function content(array $parameters = [])
{
$a = DI::app();
$profile = ProfileModel::load($a, $parameters['nickname']);
if (empty($profile)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
if (!$profile['net-publish']) {
DI::page()['htmlhead'] .= '<meta content="noindex, noarchive" name="robots" />' . "\n";
}
$is_owner = local_user() == $profile['uid'];
$o = self::getTabsHTML($a, 'media', $is_owner, $profile['nickname'], $profile['hide-friends']);
$o .= Contact::getPostsFromUrl($profile['url'], false, 0, 0, true);
return $o;
}
}

View file

@ -1037,9 +1037,12 @@ class Processor
self::switchContact($cid);
if (DBA::exists('contact', ['id' => $cid, 'rel' => Contact::SHARING])) {
$contact = Contact::getById($cid, ['rel']);
if ($contact['rel'] == Contact::SHARING) {
Contact::remove($cid);
Logger::info('Rejected contact request - contact removed', ['contact' => $cid, 'user' => $uid]);
} elseif ($contact['rel'] == Contact::FRIEND) {
Contact::update(['rel' => Contact::FOLLOWER], ['id' => $cid]);
} else {
Logger::info('Rejected contact request', ['contact' => $cid, 'user' => $uid]);
}

View file

@ -2047,15 +2047,16 @@ class Transmitter
* @param string $target Target profile
* @param $id
* @param integer $uid User ID
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @return bool Operation success
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public static function sendContactReject($target, $id, $uid)
public static function sendContactReject($target, $id, $uid): bool
{
$profile = APContact::getByURL($target);
if (empty($profile['inbox'])) {
Logger::warning('No inbox found for target', ['target' => $target, 'profile' => $profile]);
return;
return false;
}
$owner = User::getOwnerDataById($uid);
@ -2075,7 +2076,7 @@ class Transmitter
Logger::debug('Sending reject to ' . $target . ' for user ' . $uid . ' with id ' . $id);
$signed = LDSignature::sign($data, $owner);
HTTPSignature::transmit($signed, $profile['inbox'], $uid);
return HTTPSignature::transmit($signed, $profile['inbox'], $uid);
}
/**

View file

@ -37,6 +37,7 @@ $profileRoutes = [
'/contacts/common' => [Module\Profile\Common::class, [R::GET]],
'/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]],
'/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]],
'/media' => [Module\Profile\Media::class, [R::GET]],
];
return [
@ -235,10 +236,11 @@ return [
'/{id:\d+}/block' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/conversations' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/contacts[/{type}]' => [Module\Contact\Contacts::class, [R::GET]],
'/{id:\d+}/drop' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/ignore' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/media' => [Module\Contact\Media::class, [R::GET]],
'/{id:\d+}/poke' => [Module\Contact\Poke::class, [R::GET, R::POST]],
'/{id:\d+}/posts' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/revoke' => [Module\Contact\Revoke::class, [R::GET, R::POST]],
'/{id:\d+}/update' => [Module\Contact::class, [R::GET]],
'/{id:\d+}/updateprofile' => [Module\Contact::class, [R::GET]],
'/archived' => [Module\Contact::class, [R::GET]],

File diff suppressed because it is too large Load diff

View file

@ -49,8 +49,8 @@ msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-01 16:40+0200\n"
"PO-Revision-Date: 2021-10-01 15:32+0000\n"
"POT-Creation-Date: 2021-10-02 08:34-0400\n"
"PO-Revision-Date: 2021-10-02 19:18+0000\n"
"Last-Translator: Tobias Diekershoff <tobias.diekershoff@gmx.net>\n"
"Language-Team: German (http://www.transifex.com/Friendica/friendica/language/de/)\n"
"MIME-Version: 1.0\n"
@ -79,7 +79,7 @@ msgstr[1] "Das wöchentliche Limit von %d Beiträgen wurde erreicht. Der Beitrag
msgid "Monthly posting limit of %d post reached. The post was rejected."
msgstr "Das monatliche Limit von %d Beiträgen wurde erreicht. Der Beitrag wurde verworfen."
#: include/api.php:4437 mod/photos.php:89 mod/photos.php:198
#: include/api.php:4430 mod/photos.php:89 mod/photos.php:198
#: mod/photos.php:626 mod/photos.php:1035 mod/photos.php:1052
#: mod/photos.php:1599 src/Model/User.php:1169 src/Model/User.php:1177
#: src/Model/User.php:1185 src/Module/Settings/Profile/Photo/Crop.php:101
@ -602,7 +602,7 @@ msgstr "Abbrechen"
#: mod/editpost.php:134 src/Content/Conversation.php:380
#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:459
#: src/Module/Admin/Logs/View.php:93
#: src/Module/Admin/Logs/View.php:92
msgid "Message"
msgstr "Nachricht"
@ -632,7 +632,7 @@ msgstr "Der Veranstaltungstitel und die Anfangszeit müssen angegeben werden."
msgid "Create New Event"
msgstr "Neue Veranstaltung erstellen"
#: mod/events.php:536 src/Module/Admin/Logs/View.php:97
#: mod/events.php:536 src/Module/Admin/Logs/View.php:96
msgid "Event details"
msgstr "Veranstaltungsdetails"
@ -761,7 +761,7 @@ msgid "OStatus support is disabled. Contact can't be added."
msgstr "OStatus-Unterstützung ist nicht aktiviert. Der Kontakt kann nicht zugefügt werden."
#: mod/follow.php:138 src/Content/Item.php:463 src/Content/Widget.php:76
#: src/Model/Contact.php:1051 src/Model/Contact.php:1064
#: src/Model/Contact.php:1046 src/Model/Contact.php:1059
#: view/theme/vier/theme.php:172
msgid "Connect/Follow"
msgstr "Verbinden/Folgen"
@ -2321,11 +2321,11 @@ msgid ""
"select \"Export account\""
msgstr "Um Deinen Account zu exportieren, rufe \"Einstellungen -> Persönliche Daten exportieren\" auf und wähle \"Account exportieren\""
#: mod/unfollow.php:65 mod/unfollow.php:129
#: mod/unfollow.php:65 mod/unfollow.php:135
msgid "You aren't following this contact."
msgstr "Du folgst diesem Kontakt."
#: mod/unfollow.php:71 mod/unfollow.php:135
#: mod/unfollow.php:71
msgid "Unfollowing is currently not supported by your network."
msgstr "Bei diesem Netzwerk wird das Entfolgen derzeit nicht unterstützt."
@ -2333,6 +2333,24 @@ msgstr "Bei diesem Netzwerk wird das Entfolgen derzeit nicht unterstützt."
msgid "Disconnect/Unfollow"
msgstr "Verbindung lösen/Nicht mehr folgen"
#: mod/unfollow.php:149
msgid "Unfollowing is currently not supported by this contact's network."
msgstr "Bei dem Netzwerk dieses Kontakts wird das Entfolgen derzeit nicht unterstützt."
#: mod/unfollow.php:153
msgid ""
"Unable to unfollow this contact, please retry in a few minutes or contact "
"your administrator."
msgstr "Konnte dem Kontakt nicht entfolgen. Bitte warte ein paar Minuten und versuche es dann noch einmal, oder kontaktiere deinen Administrator."
#: mod/unfollow.php:157
msgid "Contact was successfully unfollowed"
msgstr "Kontakt wurde erfolgreich entfolgt."
#: mod/unfollow.php:161
msgid "Unable to unfollow this contact, please contact your administrator"
msgstr "Konnte dem Kontakt nicht entfolgen. Bitte kontaktiere deinen Administrator."
#: mod/videos.php:120
msgid "No videos selected"
msgstr "Keine Videos ausgewählt"
@ -2469,12 +2487,12 @@ msgstr "Addon bereits aktiviert"
msgid "Addon already disabled"
msgstr "Addon bereits deaktiviert"
#: src/Console/ArchiveContact.php:105
#: src/Console/ArchiveContact.php:106
#, php-format
msgid "Could not find any unarchived contact entry for this URL (%s)"
msgstr "Für die URL (%s) konnte kein nicht-archivierter Kontakt gefunden werden"
#: src/Console/ArchiveContact.php:108
#: src/Console/ArchiveContact.php:109
msgid "The contact entries have been archived"
msgstr "Die Kontakteinträge wurden archiviert."
@ -3047,31 +3065,31 @@ msgstr "Veranstaltung"
msgid "Follow Thread"
msgstr "Folge der Unterhaltung"
#: src/Content/Item.php:443 src/Model/Contact.php:1056
#: src/Content/Item.php:443 src/Model/Contact.php:1051
msgid "View Status"
msgstr "Status anschauen"
#: src/Content/Item.php:444 src/Content/Item.php:466 src/Model/Contact.php:982
#: src/Model/Contact.php:1048 src/Model/Contact.php:1057
#: src/Content/Item.php:444 src/Content/Item.php:466 src/Model/Contact.php:977
#: src/Model/Contact.php:1043 src/Model/Contact.php:1052
#: src/Module/Directory.php:160 src/Module/Settings/Profile/Index.php:223
msgid "View Profile"
msgstr "Profil anschauen"
#: src/Content/Item.php:445 src/Model/Contact.php:1058
#: src/Content/Item.php:445 src/Model/Contact.php:1053
msgid "View Photos"
msgstr "Bilder anschauen"
#: src/Content/Item.php:446 src/Model/Contact.php:1049
#: src/Model/Contact.php:1059
#: src/Content/Item.php:446 src/Model/Contact.php:1044
#: src/Model/Contact.php:1054
msgid "Network Posts"
msgstr "Netzwerkbeiträge"
#: src/Content/Item.php:447 src/Model/Contact.php:1050
#: src/Model/Contact.php:1060
#: src/Content/Item.php:447 src/Model/Contact.php:1045
#: src/Model/Contact.php:1055
msgid "View Contact"
msgstr "Kontakt anzeigen"
#: src/Content/Item.php:448 src/Model/Contact.php:1062
#: src/Content/Item.php:448 src/Model/Contact.php:1057
msgid "Send PM"
msgstr "Private Nachricht senden"
@ -3094,7 +3112,7 @@ msgstr "Ignorieren"
msgid "Languages"
msgstr "Sprachen"
#: src/Content/Item.php:458 src/Model/Contact.php:1063
#: src/Content/Item.php:458 src/Model/Contact.php:1058
msgid "Poke"
msgstr "Anstupsen"
@ -3211,7 +3229,7 @@ msgid "Addon applications, utilities, games"
msgstr "Zusätzliche Anwendungen, Dienstprogramme, Spiele"
#: src/Content/Nav.php:230 src/Content/Text/HTML.php:891
#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:99
#: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:99
msgid "Search"
msgstr "Suche"
@ -3543,7 +3561,7 @@ msgstr "Personen"
msgid "Organisations"
msgstr "Organisationen"
#: src/Content/Widget.php:529 src/Model/Contact.php:1480
#: src/Content/Widget.php:529 src/Model/Contact.php:1474
msgid "News"
msgstr "Nachrichten"
@ -4407,85 +4425,85 @@ msgstr "%s ist jetzt mit %s befreundet"
msgid "Legacy module file not found: %s"
msgstr "Legacy-Moduldatei nicht gefunden: %s"
#: src/Model/Contact.php:1052 src/Model/Contact.php:1065
#: src/Model/Contact.php:1047 src/Model/Contact.php:1060
msgid "UnFollow"
msgstr "Entfolgen"
#: src/Model/Contact.php:1061
#: src/Model/Contact.php:1056
msgid "Drop Contact"
msgstr "Kontakt löschen"
#: src/Model/Contact.php:1071 src/Module/Admin/Users/Pending.php:107
#: src/Model/Contact.php:1066 src/Module/Admin/Users/Pending.php:107
#: src/Module/Notifications/Introductions.php:111
#: src/Module/Notifications/Introductions.php:183
msgid "Approve"
msgstr "Genehmigen"
#: src/Model/Contact.php:1476
#: src/Model/Contact.php:1470
msgid "Organisation"
msgstr "Organisation"
#: src/Model/Contact.php:1484
#: src/Model/Contact.php:1478
msgid "Forum"
msgstr "Forum"
#: src/Model/Contact.php:2340
#: src/Model/Contact.php:2334
msgid "Disallowed profile URL."
msgstr "Nicht erlaubte Profil-URL."
#: src/Model/Contact.php:2345 src/Module/Friendica.php:81
#: src/Model/Contact.php:2339 src/Module/Friendica.php:81
msgid "Blocked domain"
msgstr "Blockierte Domain"
#: src/Model/Contact.php:2350
#: src/Model/Contact.php:2344
msgid "Connect URL missing."
msgstr "Connect-URL fehlt"
#: src/Model/Contact.php:2359
#: src/Model/Contact.php:2353
msgid ""
"The contact could not be added. Please check the relevant network "
"credentials in your Settings -> Social Networks page."
msgstr "Der Kontakt konnte nicht hinzugefügt werden. Bitte überprüfe die Einstellungen unter Einstellungen -> Soziale Netzwerke"
#: src/Model/Contact.php:2396
#: src/Model/Contact.php:2390
msgid "The profile address specified does not provide adequate information."
msgstr "Die angegebene Profiladresse liefert unzureichende Informationen."
#: src/Model/Contact.php:2398
#: src/Model/Contact.php:2392
msgid "No compatible communication protocols or feeds were discovered."
msgstr "Es wurden keine kompatiblen Kommunikationsprotokolle oder Feeds gefunden."
#: src/Model/Contact.php:2401
#: src/Model/Contact.php:2395
msgid "An author or name was not found."
msgstr "Es wurde kein Autor oder Name gefunden."
#: src/Model/Contact.php:2404
#: src/Model/Contact.php:2398
msgid "No browser URL could be matched to this address."
msgstr "Zu dieser Adresse konnte keine passende Browser-URL gefunden werden."
#: src/Model/Contact.php:2407
#: src/Model/Contact.php:2401
msgid ""
"Unable to match @-style Identity Address with a known protocol or email "
"contact."
msgstr "Konnte die @-Adresse mit keinem der bekannten Protokolle oder Email-Kontakte abgleichen."
#: src/Model/Contact.php:2408
#: src/Model/Contact.php:2402
msgid "Use mailto: in front of address to force email check."
msgstr "Verwende mailto: vor der E-Mail-Adresse, um eine Überprüfung der E-Mail-Adresse zu erzwingen."
#: src/Model/Contact.php:2414
#: src/Model/Contact.php:2408
msgid ""
"The profile address specified belongs to a network which has been disabled "
"on this site."
msgstr "Die Adresse dieses Profils gehört zu einem Netzwerk, mit dem die Kommunikation auf dieser Seite ausgeschaltet wurde."
#: src/Model/Contact.php:2419
#: src/Model/Contact.php:2413
msgid ""
"Limited profile. This person will be unable to receive direct/personal "
"notifications from you."
msgstr "Eingeschränktes Profil. Diese Person wird keine direkten/privaten Nachrichten von dir erhalten können."
#: src/Model/Contact.php:2478
#: src/Model/Contact.php:2472
msgid "Unable to retrieve contact information."
msgstr "Konnte die Kontaktinformationen nicht empfangen."
@ -5081,7 +5099,7 @@ msgstr "Einschalten"
#: src/Module/Admin/Blocklist/Contact.php:78
#: src/Module/Admin/Blocklist/Server.php:88
#: src/Module/Admin/Federation.php:159 src/Module/Admin/Item/Delete.php:65
#: src/Module/Admin/Logs/Settings.php:80 src/Module/Admin/Logs/View.php:84
#: src/Module/Admin/Logs/Settings.php:80 src/Module/Admin/Logs/View.php:83
#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:497
#: src/Module/Admin/Storage.php:131 src/Module/Admin/Summary.php:233
#: src/Module/Admin/Themes/Details.php:90
@ -5519,7 +5537,7 @@ msgstr "Mention"
msgid "Implicit Mention"
msgstr "Implicit Mention"
#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:99
#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:98
#: src/Module/Debug/ActivityPubConversion.php:62
msgid "Source"
msgstr "Quelle"
@ -5577,82 +5595,82 @@ msgid ""
"'display_errors' is to enable these options, set to '0' to disable them."
msgstr "Um die Protokollierung von PHP-Fehlern und Warnungen vorübergehend zu aktivieren, kannst du der Datei index.php deiner Installation Folgendes voranstellen. Der in der Datei 'error_log' angegebene Dateiname ist relativ zum obersten Verzeichnis von Friendica und muss vom Webserver beschreibbar sein. Die Option '1' für 'log_errors' und 'display_errors' aktiviert diese Optionen, ersetze die '1' durch eine '0', um sie zu deaktivieren."
#: src/Module/Admin/Logs/View.php:71
#: src/Module/Admin/Logs/View.php:70
#, php-format
msgid ""
"Error trying to open <strong>%1$s</strong> log file.<br/>Check to see if "
"file %1$s exist and is readable."
msgstr "Fehler beim Öffnen der Logdatei <strong>%1$s</strong>.<br/>Bitte überprüfe ob die Datei %1$s existiert und gelesen werden kann."
#: src/Module/Admin/Logs/View.php:80
#: src/Module/Admin/Logs/View.php:79
#, php-format
msgid ""
"Couldn't open <strong>%1$s</strong> log file.<br/>Check to see if file %1$s "
"is readable."
msgstr "Konnte die Logdatei <strong>%1$s</strong> nicht öffnen.<br/>Bitte stelle sicher, dass die Datei %1$s lesbar ist."
#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:110
#: src/Module/Admin/Logs/View.php:84 src/Module/BaseAdmin.php:110
msgid "View Logs"
msgstr "Protokolle anzeigen"
#: src/Module/Admin/Logs/View.php:88
#: src/Module/Admin/Logs/View.php:87
msgid "Search in logs"
msgstr "Logs durchsuchen"
#: src/Module/Admin/Logs/View.php:89
#: src/Module/Admin/Logs/View.php:88
#: src/Module/Notifications/Notifications.php:138
msgid "Show all"
msgstr "Alle anzeigen"
#: src/Module/Admin/Logs/View.php:90
#: src/Module/Admin/Logs/View.php:89
msgid "Date"
msgstr "Datum"
#: src/Module/Admin/Logs/View.php:91
#: src/Module/Admin/Logs/View.php:90
msgid "Level"
msgstr "Level"
#: src/Module/Admin/Logs/View.php:92
#: src/Module/Admin/Logs/View.php:91
msgid "Context"
msgstr "Zusammenhang"
#: src/Module/Admin/Logs/View.php:94
#: src/Module/Admin/Logs/View.php:93
msgid "ALL"
msgstr "ALLE"
#: src/Module/Admin/Logs/View.php:95
#: src/Module/Admin/Logs/View.php:94
msgid "View details"
msgstr "Details anzeigen"
#: src/Module/Admin/Logs/View.php:96
#: src/Module/Admin/Logs/View.php:95
msgid "Click to view details"
msgstr "Anklicken zum Anzeigen der Details"
#: src/Module/Admin/Logs/View.php:98
#: src/Module/Admin/Logs/View.php:97
msgid "Data"
msgstr "Daten"
#: src/Module/Admin/Logs/View.php:100
#: src/Module/Admin/Logs/View.php:99
msgid "File"
msgstr "Datei"
#: src/Module/Admin/Logs/View.php:101
#: src/Module/Admin/Logs/View.php:100
msgid "Line"
msgstr "Zeile"
#: src/Module/Admin/Logs/View.php:102
#: src/Module/Admin/Logs/View.php:101
msgid "Function"
msgstr "Funktion"
#: src/Module/Admin/Logs/View.php:103
#: src/Module/Admin/Logs/View.php:102
msgid "UID"
msgstr "UID"
#: src/Module/Admin/Logs/View.php:104
#: src/Module/Admin/Logs/View.php:103
msgid "Process ID"
msgstr "Prozess ID"
#: src/Module/Admin/Logs/View.php:105
#: src/Module/Admin/Logs/View.php:104
msgid "Close"
msgstr "Schließen"

View file

@ -491,6 +491,10 @@ $a->strings["To export your account, go to \"Settings->Export your personal data
$a->strings["You aren't following this contact."] = "Du folgst diesem Kontakt.";
$a->strings["Unfollowing is currently not supported by your network."] = "Bei diesem Netzwerk wird das Entfolgen derzeit nicht unterstützt.";
$a->strings["Disconnect/Unfollow"] = "Verbindung lösen/Nicht mehr folgen";
$a->strings["Unfollowing is currently not supported by this contact's network."] = "Bei dem Netzwerk dieses Kontakts wird das Entfolgen derzeit nicht unterstützt.";
$a->strings["Unable to unfollow this contact, please retry in a few minutes or contact your administrator."] = "Konnte dem Kontakt nicht entfolgen. Bitte warte ein paar Minuten und versuche es dann noch einmal, oder kontaktiere deinen Administrator.";
$a->strings["Contact was successfully unfollowed"] = "Kontakt wurde erfolgreich entfolgt.";
$a->strings["Unable to unfollow this contact, please contact your administrator"] = "Konnte dem Kontakt nicht entfolgen. Bitte kontaktiere deinen Administrator.";
$a->strings["No videos selected"] = "Keine Videos ausgewählt";
$a->strings["View Video"] = "Video ansehen";
$a->strings["Recent Videos"] = "Neueste Videos";

View file

@ -2,10 +2,10 @@
<center>
<form action="{{$confirm_url}}" id="confirm-form" method="{{$method}}">
<h3 id="confirm-message">{{$message}}</h3>
<h3 id="confirm-message">{{$l10n.message}}</h3>
<button class="confirm-button" id="confirm-submit-button" type="submit" name="{{$confirm_name}}" value="{{$confirm_value}}">{{$confirm}}</button>
<button class="confirm-button" id="confirm-cancel-button" type="submit" name="canceled" value="{{$cancel}}">{{$cancel}}</button>
<button class="confirm-button" id="confirm-submit-button" type="submit" name="{{$confirm_name}}" value="{{$confirm_value}}">{{$l10n.confirm}}</button>
<button class="confirm-button" id="confirm-cancel-button" type="submit" name="canceled" value="{{$l10n.cancel}}">{{$l10n.cancel}}</button>
</form>
</center>

View file

@ -1,4 +1,4 @@
<h1>{{$header}}</h1>
<h1>{{$l10n.header}}</h1>
{{include file="contact_template.tpl" no_contacts_checkbox=True}}

View file

@ -15,13 +15,13 @@
<a class="btn" rel="#contact-actions-menu" href="#" id="contact-edit-actions-button">{{$contact_action_button}}</a>
<ul role="menu" aria-haspopup="true" id="contact-actions-menu" class="menu-popup">
{{if $lblsuggest}}<li role="menuitem"><a href="#" title="{{$contact_actions.suggest.title}}" onclick="window.location.href='{{$contact_actions.suggest.url}}'; return false;">{{$contact_actions.suggest.label}}</a></li>{{/if}}
{{if $poll_enabled}}<li role="menuitem"><a href="#" title="{{$contact_actions.update.title}}" onclick="window.location.href='{{$contact_actions.update.url}}'; return false;">{{$contact_actions.update.label}}</a></li>{{/if}}
{{if $lblsuggest}}<li role="menuitem"><a href="#" title="{{$contact_actions.suggest.title}}" onclick="window.location.href='{{$contact_actions.suggest.url}}'; return false;">{{$contact_actions.suggest.label}}</a></li>{{/if}}
{{if $poll_enabled}}<li role="menuitem"><a href="#" title="{{$contact_actions.update.title}}" onclick="window.location.href='{{$contact_actions.update.url}}'; return false;">{{$contact_actions.update.label}}</a></li>{{/if}}
{{if $contact_actions.updateprofile}}<li role="menuitem"><a href="{{$contact_actions.updateprofile.url}}" title="{{$contact_actions.updateprofile.title}}">{{$contact_actions.updateprofile.label}}</a></li>{{/if}}
<li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.delete.url}}<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li> {{/if}}
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.revoke_follow.url}}<li role="menuitem"><a href="{{$contact_actions.revoke_follow.url}}" title="{{$contact_actions.revoke_follow.title}}">{{$contact_actions.revoke_follow.label}}</a></li>{{/if}}
</ul>
</div>

View file

@ -38,20 +38,6 @@
return false;
}
});
// add javascript confirm dialog to "drop" links. Plain html url have "?confirm=1" to show confirmation form, we need to remove it
$(".drop").each(function() {
$(this).attr('href', $(this).attr('href').replace("confirm=1","") );
$(this).click(function(e){
if (confirm("{{$contact_drop_confirm}}")) {
return true;
} else {
e.preventDefault();
return false;
}
});
});
});
</script>

View file

@ -2504,14 +2504,6 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
#directory-search-wrapper {
padding: 10px 0;
}
#contact-drop-confirm .contact-actions,
#contact-drop-confirm .contact-photo-overlay,
#contact-drop-confirm .contact-photo-menu {
display: none;
}
#contact-drop-confirm #confirm-form {
margin-top: 20px;
}
/* contact-edit */
#contact-edit-actions {

View file

@ -1,9 +1,9 @@
<form action="{{$confirm_url}}" id="confirm-form" method="{{$method}}" class="generic-page-wrapper">
<div id="confirm-message">{{$message}}</div>
<div id="confirm-message">{{$l10n.message}}</div>
<div class="form-group pull-right settings-submit-wrapper">
<button type="submit" name="{{$confirm_name}}" id="confirm-submit-button" class="btn btn-primary confirm-button" value="{{$confirm_value}}">{{$confirm}}</button>
<button type="submit" name="canceled" value="{{$cancel}} id="confirm-cancel-button" class="btn confirm-button" data-dismiss="modal">{{$cancel}}</button>
<button type="submit" name="{{$confirm_name}}" id="confirm-submit-button" class="btn btn-primary confirm-button" value="{{$confirm_value}}">{{$l10n.confirm}}</button>
<button type="submit" name="canceled" value="{{$l10n.cancel}}" id="confirm-cancel-button" class="btn confirm-button" data-dismiss="modal">{{$l10n.cancel}}</button>
</div>
</form>

View file

@ -1,5 +1,5 @@
<div id="contact-drop-confirm">
<h2 class="heading">{{$header}}</h2>
<h2 class="heading">{{$l10n.header}}</h2>
{{include file="contact_template.tpl" no_contacts_checkbox=True}}

View file

@ -27,7 +27,7 @@
{{/if}}
<li role="presentation"><a role="menuitem" href="{{$contact_actions.block.url}}" title="{{$contact_actions.block.title}}">{{$contact_actions.block.label}}</a></li>
<li role="presentation"><a role="menuitem" href="{{$contact_actions.ignore.url}}" title="{{$contact_actions.ignore.title}}">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.delete.url}}<li role="presentation"><button role="menuitem" type="button" class="btn-link" title="{{$contact_actions.delete.title}}" onclick="addToModal('{{$contact_actions.delete.url}}&confirm=1');">{{$contact_actions.delete.label}}</button></li>{{/if}}
{{if $contact_actions.revoke_follow.url}}<li role="presentation"><button role="menuitem" type="button" class="btn-link" title="{{$contact_actions.revoke_follow.title}}" onclick="addToModal('{{$contact_actions.revoke_follow.url}}');">{{$contact_actions.revoke_follow.label}}</button></li>{{/if}}
</ul>
</li>
</ul>

View file

@ -65,11 +65,6 @@
<i class="fa fa-user" aria-hidden="true"></i>
</a>
{{/if}}
{{if $contact.photo_menu.drop}}
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.drop.1}}'); return false;" data-toggle="tooltip" title="{{$contact.photo_menu.drop.0}}">
<i class="fa fa-user-times" aria-hidden="true"></i>
</button>
{{/if}}
{{if $contact.photo_menu.follow}}
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.follow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.follow.0}}">
<i class="fa fa-user-plus" aria-hidden="true"></i>
@ -198,11 +193,6 @@ We use this part to filter the contacts with jquery.textcomplete *}}
<i class="fa fa-user" aria-hidden="true"></i>
</a>
{/if}
{if $photo_menu.drop}
<a class="contact-action-link btn-link" href="{$photo_menu.drop.1}" data-toggle="tooltip" title="{$photo_menu.drop.0}">
<i class="fa fa-user-times" aria-hidden="true"></i>
</a>
{/if}
{if $photo_menu.follow}
<a class="contact-action-link btn-link" href="{$photo_menu.follow.1}" data-toggle="tooltip" title="{$photo_menu.follow.0}">
<i class="fa fa-user-plus" aria-hidden="true"></i>

View file

@ -1,8 +1,4 @@
<script type="text/javascript">
var dropContact = "{{$contact_drop_confirm}}";
</script>
{{$tabs nofilter}}
<div id="contacts" class="generic-page-wrapper">

View file

@ -16,13 +16,13 @@
<a class="btn" id="contact-edit-actions-button">{{$contact_action_button}}</a>
<ul role="menu" aria-haspopup="true" id="contact-actions-menu" class="menu-popup">
{{if $lblsuggest}}<li role="menuitem"><a href="#" title="{{$contact_actions.suggest.title}}" onclick="window.location.href='{{$contact_actions.suggest.url}}'; return false;">{{$contact_actions.suggest.label}}</a></li>{{/if}}
{{if $poll_enabled}}<li role="menuitem"><a href="#" title="{{$contact_actions.update.title}}" onclick="window.location.href='{{$contact_actions.update.url}}'; return false;">{{$contact_actions.update.label}}</a></li>{{/if}}
{{if $lblsuggest}}<li role="menuitem"><a href="#" title="{{$contact_actions.suggest.title}}" onclick="window.location.href='{{$contact_actions.suggest.url}}'; return false;">{{$contact_actions.suggest.label}}</a></li>{{/if}}
{{if $poll_enabled}}<li role="menuitem"><a href="#" title="{{$contact_actions.update.title}}" onclick="window.location.href='{{$contact_actions.update.url}}'; return false;">{{$contact_actions.update.label}}</a></li>{{/if}}
{{if $contact_actions.updateprofile}}<li role="menuitem"><a href="{{$contact_actions.updateprofile.url}}" title="{{$contact_actions.updateprofile.title}}">{{$contact_actions.updateprofile.label}}</a></li>{{/if}}
<li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.delete.url}}<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li>{{/if}}
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.revoke_follow.url}}<li role="menuitem"><a href="{{$contact_actions.revoke_follow.url}}" title="{{$contact_actions.revoke_follow.title}}">{{$contact_actions.revoke_follow.label}}</a></li>{{/if}}
</ul>
</div>