Merge pull request #12228 from MrPetovan/task/4090-move-mod-photos

Create /profile/{nickname}/photos route
pull/12209/head
Philipp 1 week ago committed by GitHub
commit d2ba254a5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      doc/FAQ.md
  2. 2
      doc/de/FAQ.md
  3. 70
      mod/photos.php
  4. 6
      src/Content/Item.php
  5. 2
      src/Content/Nav.php
  6. 2
      src/Model/Contact.php
  7. 5
      src/Model/Photo.php
  8. 4
      src/Module/BaseProfile.php
  9. 196
      src/Module/Profile/Photos/Index.php
  10. 2
      src/Module/Settings/Profile/Index.php
  11. 2
      src/Module/Settings/Profile/Photo/Index.php
  12. 5
      static/routes.config.php
  13. 381
      view/lang/C/messages.po
  14. 4
      view/templates/photo_albums.tpl
  15. 3
      view/templates/photos_upload.tpl
  16. 6
      view/theme/frio/templates/photo_albums.tpl
  17. 4
      view/theme/frio/templates/photos_upload.tpl
  18. 3
      view/theme/frio/theme.php

@ -50,7 +50,7 @@ We recommend to talk to the admin(s) of the affected friendica server. (Admins,
### 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.

@ -69,7 +69,7 @@ Andere erlauben nur kostenpflichtige Zertifikate als eigenes Angebot bzw. von an
### 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.

@ -284,8 +284,7 @@ function photos_post(App $a)
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');
}
}
@ -778,7 +777,6 @@ function photos_post(App $a)
function photos_content(App $a)
{
// URLs:
// photos/name
// photos/name/upload
// photos/name/upload/xxxxx (xxxxx is album name)
// photos/name/album/xxxxx
@ -905,7 +903,7 @@ function photos_content(App $a)
$uploader = '';
$ret = ['post_url' => 'photos/' . $user['nickname'],
$ret = ['post_url' => 'profile/' . $user['nickname'] . '/photos',
'addon_text' => $uploader,
'default_upload' => true];
@ -1522,68 +1520,4 @@ function photos_content(App $a)
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;
}

@ -361,7 +361,7 @@ class Item
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';
}
@ -729,7 +729,7 @@ class Item
'message_id' => $shared['uri'],
'comment' => $item['body'],
'shared' => $shared['body'],
];
];
}
}
@ -737,7 +737,7 @@ class Item
}
/**
* 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

@ -192,7 +192,7 @@ class Nav
// 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')];

@ -1158,7 +1158,7 @@ class Contact
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';
}

@ -1130,8 +1130,8 @@ class Photo
$picture['height'] = $photo['height'];
$picture['type'] = $photo['type'];
$picture['albumpage'] = DI::baseUrl() . '/photos/' . $user['nickname'] . '/image/' . $resource_id;
$picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $image->getExt();
$picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $image->getExt();
$picture['picture'] = DI::baseUrl() . '/photo/' . $resource_id . '-0.' . $image->getExt();
$picture['preview'] = DI::baseUrl() . '/photo/' . $resource_id . '-' . $smallest . '.' . $image->getExt();
Logger::info('upload done', ['picture' => $picture]);
return $picture;
@ -1272,4 +1272,3 @@ class Photo
return $resource_id;
}
}

@ -62,7 +62,7 @@ class BaseProfile extends BaseModule
],
[
'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',
@ -78,7 +78,7 @@ class BaseProfile extends BaseModule
],
];
// 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'),

@ -0,0 +1,196 @@
<?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;
}
}

@ -230,7 +230,7 @@ class Index extends BaseSettings
'$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'),

@ -132,7 +132,7 @@ class Index extends BaseSettings
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>'
),
]);

@ -36,6 +36,7 @@ $profileRoutes = [
'/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]],
@ -553,6 +554,10 @@ return [
'/{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' => [

File diff suppressed because it is too large Load Diff

@ -2,14 +2,14 @@
<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>

@ -3,7 +3,7 @@
<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>
@ -47,4 +47,3 @@
<div class="photos-upload-end"></div>
</form>

@ -2,7 +2,7 @@
<div class="pull-left">
<h3>{{$title}}</h3>
</div>
<div class="pull-right">
{{if $can_post}}
<div class="photos-upload-link">
@ -15,14 +15,14 @@
<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>

@ -4,7 +4,7 @@
<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>
@ -40,7 +40,7 @@
<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}}

@ -236,6 +236,9 @@ function frio_remote_nav(App $a, array &$nav_info)
// 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')];

Loading…
Cancel
Save