X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FProfile%2FPhotos.php;h=3e5b9d604cc303b5fc9deaa632f7072e9e04ce8b;hb=c81a9d1ddd7e5b7fff6a173a159ae78ee7fc7698;hp=12c0552b6aa98663b25c1f10f01a29afdbe5178e;hpb=5ea22197ac37c58c82cecb1b8d55bd29077f3924;p=friendica.git diff --git a/src/Module/Profile/Photos.php b/src/Module/Profile/Photos.php index 12c0552b6a..3e5b9d604c 100644 --- a/src/Module/Profile/Photos.php +++ b/src/Module/Profile/Photos.php @@ -1,6 +1,6 @@ session = $session; - $this->page = $page; - $this->config = $config; - $this->app = $app; - $this->database = $database; + $this->session = $session; + $this->page = $page; + $this->config = $config; + $this->app = $app; + $this->database = $database; + $this->systemMessages = $systemMessages; + $this->aclFormatter = $aclFormatter; + + $owner = Profile::load($this->app, $this->parameters['nickname'] ?? '', false); + if (!$owner || $owner['account_removed'] || $owner['account_expired']) { + throw new HTTPException\NotFoundException($this->t('User not found.')); + } + + $this->owner = $owner; } - protected function content(array $request = []): string + protected function post(array $request = []) { - parent::content($request); + if ($this->session->getLocalUserId() != $this->owner['uid']) { + throw new HTTPException\ForbiddenException($this->t('Permission denied.')); + } - if ($this->config->get('system', 'block_public') && !$this->session->isAuthenticated()) { - throw new HttpException\ForbiddenException($this->t('Public access denied.')); + $str_contact_allow = isset($request['contact_allow']) ? $this->aclFormatter->toString($request['contact_allow']) : $this->owner['allow_cid'] ?? ''; + $str_group_allow = isset($request['group_allow']) ? $this->aclFormatter->toString($request['group_allow']) : $this->owner['allow_gid'] ?? ''; + $str_contact_deny = isset($request['contact_deny']) ? $this->aclFormatter->toString($request['contact_deny']) : $this->owner['deny_cid'] ?? ''; + $str_group_deny = isset($request['group_deny']) ? $this->aclFormatter->toString($request['group_deny']) : $this->owner['deny_gid'] ?? ''; + + $visibility = $request['visibility'] ?? ''; + if ($visibility === 'public') { + // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected + $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + } else if ($visibility === 'custom') { + // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL + // case that would make it public. So we always append the author's contact id to the allowed contacts. + // See https://github.com/friendica/friendica/issues/9672 + $str_contact_allow .= $this->aclFormatter->toString(Contact::getPublicIdByUserId($this->owner['uid'])); } - $owner = Profile::load($this->app, $this->parameters['nickname'] ?? ''); - if (!$owner || $owner['account_removed'] || $owner['account_expired']) { - throw new HTTPException\NotFoundException($this->t('User not found.')); + // default post action - upload a photo + Hook::callAll('photo_post_init', $request); + + // Determine the album to use + $album = trim($request['album'] ?? ''); + $newalbum = trim($request['newalbum'] ?? ''); + + $this->logger->debug('album= ' . $album . ' newalbum= ' . $newalbum); + + $album = $album ?: $newalbum ?: DateTimeFormat::localNow('Y'); + + /* + * We create a wall item for every photo, but we don't want to + * overwhelm the data stream with a hundred newly uploaded photos. + * So we will make the first photo uploaded to this album in the last several hours + * visible by default, the rest will become visible over time when and if + * they acquire comments, likes, dislikes, and/or tags + */ + + $r = Photo::selectToArray([], ['`album` = ? AND `uid` = ? AND `created` > ?', $album, $this->owner['uid'], DateTimeFormat::utc('now - 3 hours')]); + if (!$r || ($album == $this->t(Photo::PROFILE_PHOTOS))) { + $visible = 1; + } else { + $visible = 0; + } + + if (!empty($request['not_visible']) && $request['not_visible'] !== 'false') { + $visible = 0; + } + + $ret = ['src' => '', 'filename' => '', 'filesize' => 0, 'type' => '']; + + Hook::callAll('photo_post_file', $ret); + + if (!empty($ret['src']) && !empty($ret['filesize'])) { + $src = $ret['src']; + $filename = $ret['filename']; + $filesize = $ret['filesize']; + $type = $ret['type']; + $error = UPLOAD_ERR_OK; + } elseif (!empty($_FILES['userfile'])) { + $src = $_FILES['userfile']['tmp_name']; + $filename = basename($_FILES['userfile']['name']); + $filesize = intval($_FILES['userfile']['size']); + $type = $_FILES['userfile']['type']; + $error = $_FILES['userfile']['error']; + } else { + $error = UPLOAD_ERR_NO_FILE; + } + + if ($error !== UPLOAD_ERR_OK) { + switch ($error) { + case UPLOAD_ERR_INI_SIZE: + $this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', ini_get('upload_max_filesize'))); + break; + case UPLOAD_ERR_FORM_SIZE: + $this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', Strings::formatBytes($request['MAX_FILE_SIZE'] ?? 0))); + break; + case UPLOAD_ERR_PARTIAL: + $this->systemMessages->addNotice($this->t('Image upload didn\'t complete, please try again')); + break; + case UPLOAD_ERR_NO_FILE: + $this->systemMessages->addNotice($this->t('Image file is missing')); + break; + case UPLOAD_ERR_NO_TMP_DIR: + case UPLOAD_ERR_CANT_WRITE: + case UPLOAD_ERR_EXTENSION: + $this->systemMessages->addNotice($this->t('Server can\'t accept new file upload at this time, please contact your administrator')); + break; + } + @unlink($src); + $foo = 0; + Hook::callAll('photo_post_end', $foo); + return; + } + + $type = Images::getMimeTypeBySource($src, $filename, $type); + + $this->logger->info('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes'); + + $maximagesize = Strings::getBytesFromShorthand($this->config->get('system', 'maximagesize')); + + if ($maximagesize && ($filesize > $maximagesize)) { + $this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))); + @unlink($src); + $foo = 0; + Hook::callAll('photo_post_end', $foo); + return; + } + + if (!$filesize) { + $this->systemMessages->addNotice($this->t('Image file is empty.')); + @unlink($src); + $foo = 0; + Hook::callAll('photo_post_end', $foo); + return; + } + + $this->logger->debug('loading contents', ['src' => $src]); + + $imagedata = @file_get_contents($src); + + $image = new Image($imagedata, $type); + + if (!$image->isValid()) { + $this->logger->notice('unable to process image'); + $this->systemMessages->addNotice($this->t('Unable to process image.')); + @unlink($src); + $foo = 0; + Hook::callAll('photo_post_end',$foo); + return; + } + + $exif = $image->orient($src); + @unlink($src); + + $max_length = $this->config->get('system', 'max_image_length'); + if ($max_length > 0) { + $image->scaleDown($max_length); + } + + $width = $image->getWidth(); + $height = $image->getHeight(); + + $smallest = 0; + + $resource_id = Photo::newResource(); + + $r = Photo::store($image, $this->owner['uid'], 0, $resource_id, $filename, $album, 0 , Photo::DEFAULT, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + + if (!$r) { + $this->logger->warning('image store failed'); + $this->systemMessages->addNotice($this->t('Image upload failed.')); + return; } - $owner_uid = $owner['uid']; - $is_owner = $this->session->getLocalUserId() && ($this->session->getLocalUserId() == $owner_uid); + if ($width > 640 || $height > 640) { + $image->scaleDown(640); + Photo::store($image, $this->owner['uid'], 0, $resource_id, $filename, $album, 1, Photo::DEFAULT, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + $smallest = 1; + } - $remote_contact = false; - if ($this->session->getRemoteContactID($owner_uid)) { - $contact_id = $this->session->getRemoteContactID($owner_uid); + if ($width > 320 || $height > 320) { + $image->scaleDown(320); + Photo::store($image, $this->owner['uid'], 0, $resource_id, $filename, $album, 2, Photo::DEFAULT, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + $smallest = 2; + } - $contact = Contact::getContactForUser($contact_id, $owner_uid, ['blocked', 'pending']); - $remote_contact = $contact && !$contact['blocked'] && !$contact['pending']; + $uri = Item::newURI(); + + // Create item container + $lat = $lon = null; + if (!empty($exif['GPS']) && Feature::isEnabled($this->owner['uid'], 'photo_location')) { + $lat = Photo::getGps($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']); + $lon = Photo::getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']); } - if ($owner['hidewall'] && !$this->session->isAuthenticated()) { - $this->baseUrl->redirect('profile/' . $owner['nickname'] . '/restricted'); + $arr = []; + if ($lat && $lon) { + $arr['coord'] = $lat . ' ' . $lon; + } + + $arr['guid'] = System::createUUID(); + $arr['uid'] = $this->owner['uid']; + $arr['uri'] = $uri; + $arr['post-type'] = Item::PT_IMAGE; + $arr['wall'] = 1; + $arr['resource-id'] = $resource_id; + $arr['contact-id'] = $this->owner['id']; + $arr['owner-name'] = $this->owner['name']; + $arr['owner-link'] = $this->owner['url']; + $arr['owner-avatar'] = $this->owner['thumb']; + $arr['author-name'] = $this->owner['name']; + $arr['author-link'] = $this->owner['url']; + $arr['author-avatar'] = $this->owner['thumb']; + $arr['title'] = ''; + $arr['allow_cid'] = $str_contact_allow; + $arr['allow_gid'] = $str_group_allow; + $arr['deny_cid'] = $str_contact_deny; + $arr['deny_gid'] = $str_group_deny; + $arr['visible'] = $visible; + $arr['origin'] = 1; + + $arr['body'] = '[url=' . $this->baseUrl . '/photos/' . $this->owner['nickname'] . '/image/' . $resource_id . ']' + . '[img]' . $this->baseUrl . "/photo/{$resource_id}-{$smallest}.".$image->getExt() . '[/img]' + . '[/url]'; + + $item_id = Item::insert($arr); + // Update the photo albums cache + Photo::clearAlbumCache($this->owner['uid']); + + Hook::callAll('photo_post_end', $item_id); + + // addon uploaders should call "exit()" within the photo_post_end hook + // if they do not wish to be redirected + + $this->baseUrl->redirect($this->session->get('photo_return') ?? 'profile/' . $this->owner['nickname'] . '/photos'); + } + + 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_uid = $this->owner['uid']; + $is_owner = $this->session->getLocalUserId() == $owner_uid; + + if ($this->owner['hidewall'] && !$this->session->isAuthenticated()) { + $this->baseUrl->redirect('profile/' . $this->owner['nickname'] . '/restricted'); } $this->session->set('photo_return', $this->args->getCommand()); @@ -102,7 +332,7 @@ class Photos extends \Friendica\Module\BaseProfile WHERE `uid` = ? AND `photo-type` = ? $sql_extra", - $owner['uid'], + $this->owner['uid'], Photo::DEFAULT, )); $total = $photo[0]['count']; @@ -125,7 +355,7 @@ class Photos extends \Friendica\Module\BaseProfile GROUP BY `resource-id` ORDER BY `created` DESC LIMIT ? , ?", - $owner['uid'], + $this->owner['uid'], Photo::DEFAULT, $pager->getStart(), $pager->getItemsPerPage() @@ -133,15 +363,15 @@ class Photos extends \Friendica\Module\BaseProfile $phototypes = Images::supportedTypes(); - $photos = array_map(function ($photo) use ($owner, $phototypes) { + $photos = array_map(function ($photo) use ($phototypes) { return [ 'id' => $photo['id'], - 'link' => 'photos/' . $owner['nickname'] . '/image/' . $photo['resource-id'], + 'link' => 'photos/' . $this->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']), + 'link' => 'photos/' . $this->owner['nickname'] . '/album/' . bin2hex($photo['album']), 'name' => $photo['album'], 'alt' => $this->t('View Album'), ], @@ -153,38 +383,43 @@ class Photos extends \Friendica\Module\BaseProfile '$ispublic' => $this->t('everybody') ]); - if ($albums = Photo::getAlbums($owner['uid'])) { - $albums = array_map(function ($album) use ($owner) { + if ($albums = Photo::getAlbums($this->owner['uid'])) { + $albums = array_map(function ($album) { return [ 'text' => $album['album'], 'total' => $album['total'], - 'url' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($album['album']), + 'url' => 'photos/' . $this->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'], + '$nick' => $this->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(), + '$upload' => [$this->t('Upload New Photos'), 'photos/' . $this->owner['nickname'] . '/upload'], + '$can_post' => $this->session->getLocalUserId() && $this->owner['uid'] == $this->session->getLocalUserId(), ]); } + // Removing vCard for owner + if ($is_owner) { + $this->page['aside'] = ''; + } + if (!empty($photo_albums_widget)) { $this->page['aside'] .= $photo_albums_widget; } - $o = self::getTabsHTML('photos', $is_owner, $owner['nickname'], Profile::getByUID($owner['uid'])['hide-friends'] ?? false); + $o = self::getTabsHTML('photos', $is_owner, $this->owner['nickname'], Profile::getByUID($this->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'], + '$can_post' => $is_owner, + '$upload' => [$this->t('Upload New Photos'), 'photos/' . $this->owner['nickname'] . '/upload'], '$photos' => $photos, '$paginate' => $pager->renderFull($total), ]);