### How can I upload images, files, links, videos and sound files to posts?
You can upload images from your computer using the [editor](help/Text_editor).
-An overview of all uploaded images is listed at *yourpage.com/photos/profilename*.
+An overview of all uploaded images is listed at *yourpage.com/profile/profilename/photos*.
On that page, you can also upload images directly and choose if your contacts will receive a message about this upload.
Generally, you can attach any kind of file to a post.
### Wie kann ich Bilder, Dateien, Links, Video und Audio in Beiträge einfügen?
Bilder können direkt im [Beitragseditor](help/Text_editor) vom Computer hochgeladen werden.
-Eine Übersicht aller Bilder, die auf Deinem Server liegen, findest Du unter <i>deineSeite.de/photos/profilname</i>.
+Eine Übersicht aller Bilder, die auf Deinem Server liegen, findest Du unter <i>deineSeite.de/profile/profilname/photos</i>.
Dort kannst Du auch direkt Bilder hochladen und festlegen, ob Deine Kontakte eine Nachricht über das neue Bild bekommen.
Alle Arten von Dateien können grundsätzlich als Anhang in Friendica hochgeladen werden.
DI::baseUrl()->redirect('photos/' . DI::args()->getArgv()[1] . '/image/' . DI::args()->getArgv()[3]);
}
- DI::baseUrl()->redirect('photos/' . DI::args()->getArgv()[1]);
- return; // NOTREACHED
+ DI::baseUrl()->redirect('profile/' . DI::args()->getArgv()[1] . '/photos');
}
}
function photos_content(App $a)
{
// URLs:
- // photos/name
// photos/name/upload
// photos/name/upload/xxxxx (xxxxx is album name)
// photos/name/album/xxxxx
$uploader = '';
- $ret = ['post_url' => 'photos/' . $user['nickname'],
+ $ret = ['post_url' => 'profile/' . $user['nickname'] . '/photos',
'addon_text' => $uploader,
'default_upload' => true];
return $o;
}
-
- // Default - show recent photos with upload link (if applicable)
- //$o = '';
- $total = 0;
- $r = DBA::toArray(DBA::p("SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = ? AND `photo-type` = ?
- $sql_extra GROUP BY `resource-id`",
- $user['uid'],
- Photo::DEFAULT,
- ));
- if (DBA::isResult($r)) {
- $total = count($r);
- }
-
- $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 20);
-
- $r = DBA::toArray(DBA::p("SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`,
- ANY_VALUE(`type`) AS `type`, ANY_VALUE(`album`) AS `album`, max(`scale`) AS `scale`,
- ANY_VALUE(`created`) AS `created` FROM `photo`
- WHERE `uid` = ? AND `photo-type` = ?
- $sql_extra GROUP BY `resource-id` ORDER BY `created` DESC LIMIT ? , ?",
- $user['uid'],
- Photo::DEFAULT,
- $pager->getStart(),
- $pager->getItemsPerPage()
- ));
-
- $photos = [];
- if (DBA::isResult($r)) {
- // "Twist" is only used for the duepunto theme with style "slackr"
- $twist = false;
- foreach ($r as $rr) {
- $twist = !$twist;
- $ext = $phototypes[$rr['type']];
-
- $alt_e = $rr['filename'];
- $name_e = $rr['album'];
-
- $photos[] = [
- 'id' => $rr['id'],
- 'twist' => ' ' . ($twist ? 'rotleft' : 'rotright') . rand(2,4),
- 'link' => 'photos/' . $user['nickname'] . '/image/' . $rr['resource-id'],
- 'title' => DI::l10n()->t('View Photo'),
- 'src' => 'photo/' . $rr['resource-id'] . '-' . ((($rr['scale']) == 6) ? 4 : $rr['scale']) . '.' . $ext,
- 'alt' => $alt_e,
- 'album' => [
- 'link' => 'photos/' . $user['nickname'] . '/album/' . bin2hex($rr['album']),
- 'name' => $name_e,
- 'alt' => DI::l10n()->t('View Album'),
- ],
-
- ];
- }
- }
-
- $tpl = Renderer::getMarkupTemplate('photos_recent.tpl');
- $o .= Renderer::replaceMacros($tpl, [
- '$title' => DI::l10n()->t('Recent Photos'),
- '$can_post' => $can_post,
- '$upload' => [DI::l10n()->t('Upload New Photos'), 'photos/' . $user['nickname'] . '/upload'],
- '$photos' => $photos,
- '$paginate' => $pager->renderFull($total),
- ]);
-
- return $o;
}
if ($sparkle) {
$status_link = $profile_link . '/status';
- $photos_link = str_replace('/profile/', '/photos/', $profile_link);
+ $photos_link = $profile_link . '/photos';
$profile_link = $profile_link . '/profile';
}
'message_id' => $shared['uri'],
'comment' => $item['body'],
'shared' => $shared['body'],
- ];
+ ];
}
}
}
/**
- * Add a link to a shared post at the end of the post
+ * Add a link to a shared post at the end of the post
*
* @param string $body
* @param integer $quote_uri_id
// user menu
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname(), DI::l10n()->t('Status'), '', DI::l10n()->t('Your posts and conversations')];
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/profile', DI::l10n()->t('Profile'), '', DI::l10n()->t('Your profile page')];
- $nav['usermenu'][] = ['photos/' . $a->getLoggedInUserNickname(), DI::l10n()->t('Photos'), '', DI::l10n()->t('Your photos')];
+ $nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/photos', DI::l10n()->t('Photos'), '', DI::l10n()->t('Your photos')];
$nav['usermenu'][] = ['profile/' . $a->getLoggedInUserNickname() . '/media', DI::l10n()->t('Media'), '', DI::l10n()->t('Your postings with media')];
$nav['usermenu'][] = ['calendar/', DI::l10n()->t('Calendar'), '', DI::l10n()->t('Your calendar')];
$nav['usermenu'][] = ['notes/', DI::l10n()->t('Personal notes'), '', DI::l10n()->t('Your personal notes')];
if ($sparkle) {
$status_link = $profile_link . '/status';
- $photos_link = str_replace('/profile/', '/photos/', $profile_link);
+ $photos_link = $profile_link . '/photos';
$profile_link = $profile_link . '/profile';
}
],
[
'label' => DI::l10n()->t('Photos'),
- 'url' => DI::baseUrl() . '/photos/' . $nickname,
+ 'url' => $baseProfileUrl . '/photos',
'sel' => $current == 'photos' ? 'active' : '',
'title' => DI::l10n()->t('Photo Albums'),
'id' => 'photo-tab',
],
];
- // the calendar link for the full featured events calendar
+ // the calendar link for the full-featured events calendar
if ($is_owner && $a->getThemeInfoValue('events_in_profile')) {
$tabs[] = [
'label' => DI::l10n()->t('Calendar'),
--- /dev/null
+<?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\Profile\Photos;
+
+use Friendica\App;
+use Friendica\Content\Pager;
+use Friendica\Content\Widget;
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Core\Session\Capability\IHandleUserSessions;
+use Friendica\Database\Database;
+use Friendica\Model\Contact;
+use Friendica\Model\Photo;
+use Friendica\Model\Profile;
+use Friendica\Model\User;
+use Friendica\Module\Response;
+use Friendica\Network\HTTPException;
+use Friendica\Security\Security;
+use Friendica\Util\Images;
+use Friendica\Util\Profiler;
+use Psr\Log\LoggerInterface;
+
+class Index extends \Friendica\Module\BaseProfile
+{
+ /** @var IHandleUserSessions */
+ private $session;
+ /** @var App\Page */
+ private $page;
+ /** @var IManageConfigValues */
+ private $config;
+ /** @var App */
+ private $app;
+ /** @var Database */
+ private $database;
+
+ public function __construct(Database $database, App $app, IManageConfigValues $config, App\Page $page, IHandleUserSessions $session, 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->session = $session;
+ $this->page = $page;
+ $this->config = $config;
+ $this->app = $app;
+ $this->database = $database;
+ }
+
+ protected function content(array $request = []): string
+ {
+ parent::content($request);
+
+ if ($this->config->get('system', 'block_public') && !$this->session->isAuthenticated()) {
+ throw new HttpException\ForbiddenException($this->t('Public access denied.'));
+ }
+
+ $owner = User::getOwnerDataByNick($this->parameters['nickname']);
+ if (!isset($owner['account_removed']) || $owner['account_removed']) {
+ throw new HTTPException\NotFoundException($this->t('User not found.'));
+ }
+
+ $owner_uid = $owner['uid'];
+ $is_owner = $this->session->getLocalUserId() && ($this->session->getLocalUserId() == $owner_uid);
+
+ $remote_contact = false;
+ if ($this->session->getRemoteContactID($owner_uid)) {
+ $contact_id = $this->session->getRemoteContactID($owner_uid);
+
+ $contact = Contact::getContactForUser($contact_id, $owner_uid, ['blocked', 'pending']);
+ $remote_contact = $contact && !$contact['blocked'] && !$contact['pending'];
+ }
+
+ if ($owner['hidewall'] && !$is_owner && !$remote_contact) {
+ throw new HttpException\ForbiddenException($this->t('Access to this item is restricted.'));
+ }
+
+ $this->session->set('photo_return', $this->args->getCommand());
+
+ $sql_extra = Security::getPermissionsSQLByUserId($owner_uid);
+
+ $photo = $this->database->toArray($this->database->p(
+ "SELECT COUNT(DISTINCT `resource-id`) AS `count`
+ FROM `photo`
+ WHERE `uid` = ?
+ AND `photo-type` = ?
+ $sql_extra",
+ $owner['uid'],
+ Photo::DEFAULT,
+ ));
+ $total = $photo[0]['count'];
+
+ $pager = new Pager($this->l10n, $this->args->getQueryString(), 20);
+
+ $photos = $this->database->toArray($this->database->p(
+ "SELECT
+ `resource-id`,
+ ANY_VALUE(`id`) AS `id`,
+ ANY_VALUE(`filename`) AS `filename`,
+ ANY_VALUE(`type`) AS `type`,
+ ANY_VALUE(`album`) AS `album`,
+ max(`scale`) AS `scale`,
+ ANY_VALUE(`created`) AS `created`
+ FROM `photo`
+ WHERE `uid` = ?
+ AND `photo-type` = ?
+ $sql_extra
+ GROUP BY `resource-id`
+ ORDER BY `created` DESC
+ LIMIT ? , ?",
+ $owner['uid'],
+ Photo::DEFAULT,
+ $pager->getStart(),
+ $pager->getItemsPerPage()
+ ));
+
+ $phototypes = Images::supportedTypes();
+
+ $photos = array_map(function ($photo) use ($owner, $phototypes) {
+ return [
+ 'id' => $photo['id'],
+ 'link' => 'photos/' . $owner['nickname'] . '/image/' . $photo['resource-id'],
+ 'title' => $this->t('View Photo'),
+ 'src' => 'photo/' . $photo['resource-id'] . '-' . ((($photo['scale']) == 6) ? 4 : $photo['scale']) . '.' . $phototypes[$photo['type']],
+ 'alt' => $photo['filename'],
+ 'album' => [
+ 'link' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($photo['album']),
+ 'name' => $photo['album'],
+ 'alt' => $this->t('View Album'),
+ ],
+ ];
+ }, $photos);
+
+ $tpl = Renderer::getMarkupTemplate('photos_head.tpl');
+ $this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
+ '$ispublic' => $this->t('everybody')
+ ]);
+
+ if ($albums = Photo::getAlbums($owner['uid'])) {
+ $albums = array_map(function ($album) use ($owner) {
+ return [
+ 'text' => $album['album'],
+ 'total' => $album['total'],
+ 'url' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($album['album']),
+ 'urlencode' => urlencode($album['album']),
+ 'bin2hex' => bin2hex($album['album'])
+ ];
+ }, $albums);
+
+ $photo_albums_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate('photo_albums.tpl'), [
+ '$nick' => $owner['nickname'],
+ '$title' => $this->t('Photo Albums'),
+ '$recent' => $this->t('Recent Photos'),
+ '$albums' => $albums,
+ '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'],
+ '$can_post' => $this->session->getLocalUserId() && $owner['uid'] == $this->session->getLocalUserId(),
+ ]);
+ }
+
+ $this->page['aside'] .= Widget\VCard::getHTML($owner);
+
+ if (!empty($photo_albums_widget)) {
+ $this->page['aside'] .= $photo_albums_widget;
+ }
+
+ $o = self::getTabsHTML($this->app, 'photos', $is_owner, $owner['nickname'], Profile::getByUID($owner['uid'])['hide-friends'] ?? false);
+
+ $tpl = Renderer::getMarkupTemplate('photos_recent.tpl');
+ $o .= Renderer::replaceMacros($tpl, [
+ '$title' => $this->t('Recent Photos'),
+ '$can_post' => $is_owner || $remote_contact && $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY,
+ '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'],
+ '$photos' => $photos,
+ '$paginate' => $pager->renderFull($total),
+ ]);
+
+ return $o;
+ }
+}
'$banner' => DI::l10n()->t('Edit Profile Details'),
'$submit' => DI::l10n()->t('Submit'),
'$profpic' => DI::l10n()->t('Change Profile Photo'),
- '$profpiclink' => '/photos/' . $profile['nickname'],
+ '$profpiclink' => '/profile/' . $profile['nickname'] . '/photos',
'$viewprof' => DI::l10n()->t('View Profile'),
'$lbl_personal_section' => DI::l10n()->t('Personal'),
DI::l10n()->t('or'),
($newuser) ?
'<a href="' . DI::baseUrl() . '">' . DI::l10n()->t('skip this step') . '</a>'
- : '<a href="' . DI::baseUrl() . '/photos/' . DI::app()->getLoggedInUserNickname() . '">'
+ : '<a href="' . DI::baseUrl() . '/profile/' . DI::app()->getLoggedInUserNickname() . '/photos">'
. DI::l10n()->t('select a photo from your photo albums') . '</a>'
),
]);
'/contacts/common' => [Module\Profile\Common::class, [R::GET]],
'/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]],
'/media' => [Module\Profile\Media::class, [R::GET]],
+ '/photos' => [Module\Profile\Photos\Index::class, [R::GET ]],
'/photos/upload' => [Module\Profile\Photos\Upload::class, [ R::POST]],
'/profile' => [Module\Profile\Profile::class, [R::GET]],
'/remote_follow' => [Module\Profile\RemoteFollow::class, [R::GET, R::POST]],
'/{type}/{customsize:\d+}/{nickname_ext}' => [Module\Photo::class, [R::GET]],
],
+ // Kept for backwards-compatibility
+ // @TODO remove by version 2023.12
+ '/photos/{nickname}' => [Module\Profile\Photos\Index::class, [R::GET]],
+
'/ping' => [Module\Notifications\Ping::class, [R::GET]],
'/post' => [
<h3>{{$title}}</h3>
<ul role="menubar" class="sidebar-photos-albums-ul">
<li role="menuitem" class="sidebar-photos-albums-li">
- <a href="{{$baseurl}}/photos/{{$nick}}" class="sidebar-photos-albums-element" title="{{$title}}">{{$recent}}</a>
+ <a href="profile/{{$nick}}/photos" class="sidebar-photos-albums-element" title="{{$title}}">{{$recent}}</a>
</li>
{{if $albums}}
{{foreach $albums as $al}}
{{if $al.text}}
<li role="menuitem" class="sidebar-photos-albums-li">
- <a href="{{$baseurl}}/photos/{{$nick}}/album/{{$al.bin2hex}}" class="sidebar-photos-albums-element">
+ <a href="photos/{{$nick}}/album/{{$al.bin2hex}}" class="sidebar-photos-albums-element">
<span class="badge pull-right">{{$al.total}}</span>{{$al.text}}
</a>
</li>
<div id="photos-usage-message">{{$usage}}</div>
-<form action="photos/{{$nickname}}" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form">
+<form action="profile/{{$nickname}}/photos" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form">
<div id="photos-upload-new-wrapper">
<div id="photos-upload-newalbum-div">
<label id="photos-upload-newalbum-text" for="photos-upload-newalbum">{{$newalbum}}</label>
<div class="photos-upload-end"></div>
</form>
-
<div class="pull-left">
<h3>{{$title}}</h3>
</div>
-
+
<div class="pull-right">
{{if $can_post}}
<div class="photos-upload-link">
<ul role="menubar" class="sidebar-photos-albums-ul clear">
<li role="menuitem" class="sidebar-photos-albums-li">
- <a href="{{$baseurl}}/photos/{{$nick}}" class="sidebar-photos-albums-element" title="{{$title}}">{{$recent}}</a>
+ <a href="profile/{{$nick}}/photos" class="sidebar-photos-albums-element" title="{{$title}}">{{$recent}}</a>
</li>
{{if $albums}}
{{foreach $albums as $al}}
{{if $al.text}}
<li role="menuitem" class="sidebar-photos-albums-li">
- <a href="{{$baseurl}}/photos/{{$nick}}/album/{{$al.bin2hex}}" class="sidebar-photos-albums-element">
+ <a href="photos/{{$nick}}/album/{{$al.bin2hex}}" class="sidebar-photos-albums-element">
<span class="badge pull-right">{{$al.total}}</span>{{$al.text}}
</a>
</li>
<div id="photos-usage-message">{{$usage}}</div>
- <form action="photos/{{$nickname}}" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form">
+ <form action="profile/{{$nickname}}/photos" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form">
<div id="photos-upload-div" class="form-group">
<label id="photos-upload-text" for="photos-upload-newalbum">{{$newalbum}}</label>
<div class="photos-upload-wrapper">
<div id="photos-upload-perms" class="btn-group pull-right">
<button class="btn btn-default" data-toggle="modal" data-target="#aclModal" onclick="return false;">
- <i id="jot-perms-icon" class="fa {{$lockstate}}"></i>
+ <i id="jot-perms-icon" class="fa {{$lockstate}}"></i>
</button>
{{$default_upload_submit nofilter}}
// user menu
$nav_info['nav']['usermenu'][] = [$server_url . '/profile/' . $remoteUser['nick'], DI::l10n()->t('Status'), '', DI::l10n()->t('Your posts and conversations')];
$nav_info['nav']['usermenu'][] = [$server_url . '/profile/' . $remoteUser['nick'] . '/profile', DI::l10n()->t('Profile'), '', DI::l10n()->t('Your profile page')];
+ // Kept for backwards-compatibility reasons, the remote server may not have updated to version 2022.12 yet
+ // @TODO Switch with the new routes by version 2023.12
+ //$nav_info['nav']['usermenu'][] = [$server_url . '/profile/' . $remoteUser['nick'] . '/photos', DI::l10n()->t('Photos'), '', DI::l10n()->t('Your photos')];
$nav_info['nav']['usermenu'][] = [$server_url . '/photos/' . $remoteUser['nick'], DI::l10n()->t('Photos'), '', DI::l10n()->t('Your photos')];
$nav_info['nav']['usermenu'][] = [$server_url . '/profile/' . $remoteUser['nick'] . '/media', DI::l10n()->t('Media'), '', DI::l10n()->t('Your postings with media')];
$nav_info['nav']['usermenu'][] = [$server_url . '/calendar/', DI::l10n()->t('Calendar'), '', DI::l10n()->t('Your calendar')];