Merge branch 'bug-noLocalPosts' of https://github.com/matthiasmoritz/friendica into bug-noLocalPosts
This commit is contained in:
commit
2035a7a178
64 changed files with 1931 additions and 1271 deletions
|
@ -51,6 +51,6 @@ AddType audio/ogg .oga
|
|||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
|
||||
RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B]
|
||||
|
||||
</IfModule>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
Version 2022.12 (unreleased)
|
||||
Friendica Core
|
||||
The rewrite rule in .htaccess-dist has been changed. The change has to be applied manually to the existing .htaccess
|
||||
|
||||
Friendica Addons
|
||||
BREAKING: The functions from the boot.php file have been moved into better fitting classes
|
||||
|
|
24
database.sql
24
database.sql
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2022.12-dev (Giant Rhubarb)
|
||||
-- DB_UPDATE_VERSION 1491
|
||||
-- DB_UPDATE_VERSION 1495
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -1656,6 +1656,7 @@ CREATE TABLE IF NOT EXISTS `report` (
|
|||
`comment` text COMMENT 'Report',
|
||||
`forward` boolean COMMENT 'Forward the report to the remote server',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
`status` tinyint unsigned COMMENT 'Status of the report',
|
||||
PRIMARY KEY(`id`),
|
||||
INDEX `uid` (`uid`),
|
||||
INDEX `cid` (`cid`),
|
||||
|
@ -1669,6 +1670,7 @@ CREATE TABLE IF NOT EXISTS `report` (
|
|||
CREATE TABLE IF NOT EXISTS `report-post` (
|
||||
`rid` int unsigned NOT NULL COMMENT 'Report id',
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Uri-id of the reported post',
|
||||
`status` tinyint unsigned COMMENT 'Status of the reported post',
|
||||
PRIMARY KEY(`rid`,`uri-id`),
|
||||
INDEX `uri-id` (`uri-id`),
|
||||
FOREIGN KEY (`rid`) REFERENCES `report` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
|
@ -2437,6 +2439,8 @@ CREATE VIEW `post-thread-view` AS SELECT
|
|||
`post-question`.`end-time` AS `question-end-time`,
|
||||
0 AS `has-categories`,
|
||||
EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`) AS `has-media`,
|
||||
(SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-comments`,
|
||||
(SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-actors`,
|
||||
`diaspora-interaction`.`interaction` AS `signed_text`,
|
||||
`parent-item-uri`.`guid` AS `parent-guid`,
|
||||
`parent-post`.`network` AS `parent-network`,
|
||||
|
@ -2497,6 +2501,24 @@ CREATE VIEW `collection-view` AS SELECT
|
|||
INNER JOIN `post` ON `post-collection`.`uri-id` = `post`.`uri-id`
|
||||
INNER JOIN `post-thread` ON `post-thread`.`uri-id` = `post`.`parent-uri-id`;
|
||||
|
||||
--
|
||||
-- VIEW media-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `media-view`;
|
||||
CREATE VIEW `media-view` AS SELECT
|
||||
`post-media`.`uri-id` AS `uri-id`,
|
||||
`post-media`.`type` AS `type`,
|
||||
`post`.`received` AS `received`,
|
||||
`post`.`created` AS `created`,
|
||||
`post`.`private` AS `private`,
|
||||
`post`.`visible` AS `visible`,
|
||||
`post`.`deleted` AS `deleted`,
|
||||
`post`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`post`.`author-id` AS `author-id`,
|
||||
`post`.`gravity` AS `gravity`
|
||||
FROM `post-media`
|
||||
INNER JOIN `post` ON `post-media`.`uri-id` = `post`.`uri-id`;
|
||||
|
||||
--
|
||||
-- VIEW tag-view
|
||||
--
|
||||
|
|
|
@ -73,7 +73,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
|||
- `:id` is a follow request ID, not a regular account id
|
||||
- Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object.
|
||||
|
||||
|
||||
- [`GET /api/v1/followed_tags'](https://docs.joinmastodon.org/methods/followed_tags/)
|
||||
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance#fetch-instance)
|
||||
- `GET /api/v1/instance/rules` Undocumented, returns Terms of Service
|
||||
- [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains)
|
||||
|
@ -126,12 +126,18 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
|
|||
- [`GET /api/v1/statuses/:id/source`](https://docs.joinmastodon.org/methods/statuses/#source)
|
||||
- [`GET /api/v1/statuses/:id/card`](https://docs.joinmastodon.org/methods/statuses/#card)
|
||||
- [`GET /api/v1/suggestions`](https://docs.joinmastodon.org/methods/accounts/suggestions/)
|
||||
- [`GET /api/v1/tags/:id`](https://docs.joinmastodon.org/methods/tags/#get)
|
||||
- [`GET /api/v1/tags/:id/follow`](https://docs.joinmastodon.org/methods/tags/#follow)
|
||||
- [`GET /api/v1/tags/:id/unfollow`](https://docs.joinmastodon.org/methods/tags/#unfollow)
|
||||
- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/)
|
||||
- [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/)
|
||||
- [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/)
|
||||
- [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/)
|
||||
- [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/)
|
||||
- [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/)
|
||||
- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917)
|
||||
- [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses)
|
||||
- [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags)
|
||||
- [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/)
|
||||
|
||||
|
||||
|
@ -142,9 +148,6 @@ These emdpoints are planned to be implemented somewhere in the future.
|
|||
- [`POST /api/v1/accounts/:id/remove_from_followers`](https://github.com/mastodon/mastodon/pull/16864)
|
||||
- [`GET /api/v1/accounts/familiar_followers`](https://github.com/mastodon/mastodon/pull/17700)
|
||||
- [`GET /api/v1/accounts/lookup`](https://github.com/mastodon/mastodon/pull/15740)
|
||||
- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917)
|
||||
- [`GET /api/v1/trends/statuses`](https://github.com/mastodon/mastodon/pull/17431)
|
||||
- [`GET /api/v1/trends/tags`](https://github.com/mastodon/mastodon/pull/16917)
|
||||
- [`POST /api/v1/polls/:id/votes`](https://docs.joinmastodon.org/methods/statuses/polls/)
|
||||
- [`GET /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/)
|
||||
- [`POST /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/)
|
||||
|
|
|
@ -6,10 +6,11 @@ Table report-post
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------ | --------------------------- | ------------ | ---- | --- | ------- | ----- |
|
||||
| rid | Report id | int unsigned | NO | PRI | NULL | |
|
||||
| uri-id | Uri-id of the reported post | int unsigned | NO | PRI | NULL | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------ | --------------------------- | ---------------- | ---- | --- | ------- | ----- |
|
||||
| rid | Report id | int unsigned | NO | PRI | NULL | |
|
||||
| uri-id | Uri-id of the reported post | int unsigned | NO | PRI | NULL | |
|
||||
| status | Status of the reported post | tinyint unsigned | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
|
@ -14,6 +14,7 @@ Fields
|
|||
| comment | Report | text | YES | | NULL | |
|
||||
| forward | Forward the report to the remote server | boolean | YES | | NULL | |
|
||||
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| status | Status of the report | tinyint unsigned | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
160
mod/fbrowser.php
160
mod/fbrowser.php
|
@ -1,160 +0,0 @@
|
|||
<?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/>.
|
||||
*
|
||||
* @package Friendica\modules
|
||||
* @subpackage FileBrowser
|
||||
* @author Fabio Comuni <fabrixxm@kirgroup.com>
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
/**
|
||||
* @param App $a
|
||||
* @return string
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
function fbrowser_content(App $a)
|
||||
{
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
System::exit();
|
||||
}
|
||||
|
||||
if (DI::args()->getArgc() == 1) {
|
||||
System::exit();
|
||||
}
|
||||
|
||||
// Needed to match the correct template in a module that uses a different theme than the user/site/default
|
||||
$theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? '');
|
||||
if ($theme && is_file("view/theme/$theme/config.php")) {
|
||||
$a->setCurrentTheme($theme);
|
||||
}
|
||||
|
||||
$template_file = "filebrowser.tpl";
|
||||
|
||||
$o = '';
|
||||
|
||||
switch (DI::args()->getArgv()[1]) {
|
||||
case "image":
|
||||
$path = ['' => DI::l10n()->t('Photos')];
|
||||
$albums = false;
|
||||
$sql_extra = "";
|
||||
$sql_extra2 = " ORDER BY created DESC LIMIT 0, 10";
|
||||
|
||||
if (DI::args()->getArgc() == 2) {
|
||||
$photos = DBA::toArray(DBA::p("SELECT distinct(`album`) AS `album` FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?)",
|
||||
DI::userSession()->getLocalUserId(),
|
||||
Photo::CONTACT_AVATAR,
|
||||
Photo::CONTACT_BANNER
|
||||
));
|
||||
|
||||
$albums = array_column($photos, 'album');
|
||||
}
|
||||
|
||||
if (DI::args()->getArgc() == 3) {
|
||||
$album = DI::args()->getArgv()[2];
|
||||
$sql_extra = sprintf("AND `album` = '%s' ", DBA::escape($album));
|
||||
$sql_extra2 = "";
|
||||
$path[$album] = $album;
|
||||
}
|
||||
|
||||
$r = DBA::toArray(DBA::p("SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`,
|
||||
min(`scale`) AS `hiq`, max(`scale`) AS `loq`, ANY_VALUE(`desc`) AS `desc`, ANY_VALUE(`created`) AS `created`
|
||||
FROM `photo` WHERE `uid` = ? $sql_extra AND NOT `photo-type` IN (?, ?)
|
||||
GROUP BY `resource-id` $sql_extra2",
|
||||
DI::userSession()->getLocalUserId(),
|
||||
Photo::CONTACT_AVATAR,
|
||||
Photo::CONTACT_BANNER
|
||||
));
|
||||
|
||||
function _map_files1($rr)
|
||||
{
|
||||
$a = DI::app();
|
||||
$types = Images::supportedTypes();
|
||||
$ext = $types[$rr['type']];
|
||||
$filename_e = $rr['filename'];
|
||||
|
||||
// Take the largest picture that is smaller or equal 640 pixels
|
||||
$photo = Photo::selectFirst(['scale'], ["`resource-id` = ? AND `height` <= ? AND `width` <= ?", $rr['resource-id'], 640, 640], ['order' => ['scale']]);
|
||||
$scale = $photo['scale'] ?? $rr['loq'];
|
||||
|
||||
return [
|
||||
DI::baseUrl() . '/photos/' . $a->getLoggedInUserNickname() . '/image/' . $rr['resource-id'],
|
||||
$filename_e,
|
||||
DI::baseUrl() . '/photo/' . $rr['resource-id'] . '-' . $scale . '.'. $ext,
|
||||
$rr['desc']
|
||||
];
|
||||
}
|
||||
$files = array_map("_map_files1", $r);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate($template_file);
|
||||
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$type' => 'image',
|
||||
'$path' => $path,
|
||||
'$folders' => $albums,
|
||||
'$files' => $files,
|
||||
'$cancel' => DI::l10n()->t('Cancel'),
|
||||
'$nickname' => $a->getLoggedInUserNickname(),
|
||||
'$upload' => DI::l10n()->t('Upload')
|
||||
]);
|
||||
|
||||
break;
|
||||
case "file":
|
||||
if (DI::args()->getArgc()==2) {
|
||||
$files = DBA::selectToArray('attach', ['id', 'filename', 'filetype'], ['uid' => DI::userSession()->getLocalUserId()]);
|
||||
|
||||
function _map_files2($rr)
|
||||
{
|
||||
list($m1, $m2) = explode("/", $rr['filetype']);
|
||||
$filetype = ( (file_exists("images/icons/$m1.png"))?$m1:"zip");
|
||||
$filename_e = $rr['filename'];
|
||||
|
||||
return [DI::baseUrl() . '/attach/' . $rr['id'], $filename_e, DI::baseUrl() . '/images/icons/16/' . $filetype . '.png'];
|
||||
}
|
||||
$files = array_map("_map_files2", $files);
|
||||
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate($template_file);
|
||||
$o = Renderer::replaceMacros($tpl, [
|
||||
'$type' => 'file',
|
||||
'$path' => ['' => DI::l10n()->t('Files')],
|
||||
'$folders' => false,
|
||||
'$files' => $files,
|
||||
'$cancel' => DI::l10n()->t('Cancel'),
|
||||
'$nickname' => $a->getLoggedInUserNickname(),
|
||||
'$upload' => DI::l10n()->t('Upload')
|
||||
]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($_GET['mode'])) {
|
||||
return $o;
|
||||
} else {
|
||||
System::httpExit($o);
|
||||
}
|
||||
}
|
|
@ -85,6 +85,8 @@ class Arguments
|
|||
|
||||
/**
|
||||
* @return string The module name based on the arguments
|
||||
* @deprecated 2022.12 - With the new (sub-)routes, it's not trustworthy anymore, use the ModuleClass instead
|
||||
* @see Router::getModuleClass()
|
||||
*/
|
||||
public function getModuleName(): string
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ use Friendica\Module\HTTPException\MethodNotAllowed;
|
|||
use Friendica\Module\HTTPException\PageNotFound;
|
||||
use Friendica\Module\Special\Options;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Network\HTTPException\MethodNotAllowedException;
|
||||
use Friendica\Network\HTTPException\NotFoundException;
|
||||
use Friendica\Util\Router\FriendicaGroupCountBased;
|
||||
|
@ -79,7 +80,7 @@ class Router
|
|||
/**
|
||||
* @var array Module parameters
|
||||
*/
|
||||
private $parameters = [];
|
||||
protected $parameters = [];
|
||||
|
||||
/** @var L10n */
|
||||
private $l10n;
|
||||
|
@ -114,6 +115,9 @@ class Router
|
|||
/** @var array */
|
||||
private $server;
|
||||
|
||||
/** @var string|null */
|
||||
protected $moduleClass = null;
|
||||
|
||||
/**
|
||||
* @param array $server The $_SERVER variable
|
||||
* @param string $baseRoutesFilepath The path to a base routes file to leverage cache, can be empty
|
||||
|
@ -216,7 +220,7 @@ class Router
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isGroup(array $config)
|
||||
private function isGroup(array $config): bool
|
||||
{
|
||||
return
|
||||
is_array($config) &&
|
||||
|
@ -252,62 +256,63 @@ class Router
|
|||
*
|
||||
* @return RouteCollector|null
|
||||
*/
|
||||
public function getRouteCollector()
|
||||
public function getRouteCollector(): ?RouteCollector
|
||||
{
|
||||
return $this->routeCollector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Friendica\BaseModule-extending class name if a route rule matched
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws InternalServerErrorException
|
||||
* @throws MethodNotAllowedException
|
||||
*/
|
||||
public function getModuleClass(): string
|
||||
{
|
||||
if (empty($this->moduleClass)) {
|
||||
$this->determineModuleClass();
|
||||
}
|
||||
|
||||
return $this->moduleClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relevant module class name for the given page URI or NULL if no route rule matched.
|
||||
*
|
||||
* @return string A Friendica\BaseModule-extending class name if a route rule matched
|
||||
* @return void
|
||||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't
|
||||
* @throws HTTPException\NotFoundException If no rule matched
|
||||
* @throws HTTPException\InternalServerErrorException Unexpected exceptions
|
||||
* @throws HTTPException\MethodNotAllowedException If a rule is private only
|
||||
*/
|
||||
private function getModuleClass(): string
|
||||
private function determineModuleClass(): void
|
||||
{
|
||||
$cmd = $this->args->getCommand();
|
||||
$cmd = '/' . ltrim($cmd, '/');
|
||||
|
||||
$dispatcher = new FriendicaGroupCountBased($this->getCachedDispatchData());
|
||||
|
||||
$this->parameters = [];
|
||||
$this->parameters = [$this->server];
|
||||
|
||||
// Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods
|
||||
if ($this->args->getMethod() === static::OPTIONS) {
|
||||
$moduleClass = Options::class;
|
||||
$this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)];
|
||||
} else {
|
||||
$routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd);
|
||||
if ($routeInfo[0] === Dispatcher::FOUND) {
|
||||
$moduleClass = $routeInfo[1];
|
||||
$this->parameters = $routeInfo[2];
|
||||
} elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
|
||||
throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
|
||||
} else {
|
||||
throw new HTTPException\NotFoundException($this->l10n->t('Page not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
return $moduleClass;
|
||||
}
|
||||
|
||||
public function getModule(?string $module_class = null): ICanHandleRequests
|
||||
{
|
||||
$module_parameters = [$this->server];
|
||||
/**
|
||||
* ROUTING
|
||||
*
|
||||
* From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the
|
||||
* post() and/or content() static methods can be respectively called to produce a data change or an output.
|
||||
**/
|
||||
try {
|
||||
$module_class = $module_class ?? $this->getModuleClass();
|
||||
$module_parameters[] = $this->parameters;
|
||||
// Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods
|
||||
if ($this->args->getMethod() === static::OPTIONS) {
|
||||
$this->moduleClass = Options::class;
|
||||
$this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)];
|
||||
} else {
|
||||
$routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd);
|
||||
if ($routeInfo[0] === Dispatcher::FOUND) {
|
||||
$this->moduleClass = $routeInfo[1];
|
||||
$this->parameters[] = $routeInfo[2];
|
||||
} else if ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
|
||||
throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1])));
|
||||
} else {
|
||||
throw new HTTPException\NotFoundException($this->l10n->t('Page not found.'));
|
||||
}
|
||||
}
|
||||
} catch (MethodNotAllowedException $e) {
|
||||
$module_class = MethodNotAllowed::class;
|
||||
$this->moduleClass = MethodNotAllowed::class;
|
||||
} catch (NotFoundException $e) {
|
||||
$moduleName = $this->args->getModuleName();
|
||||
// Then we try addon-provided modules that we wrap in the LegacyModule class
|
||||
|
@ -319,8 +324,8 @@ class Router
|
|||
} else {
|
||||
include_once "addon/{$moduleName}/{$moduleName}.php";
|
||||
if (function_exists($moduleName . '_module')) {
|
||||
$module_parameters[] = "addon/{$moduleName}/{$moduleName}.php";
|
||||
$module_class = LegacyModule::class;
|
||||
$this->parameters[] = "addon/{$moduleName}/{$moduleName}.php";
|
||||
$this->moduleClass = LegacyModule::class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,24 +333,29 @@ class Router
|
|||
/* Finally, we look for a 'standard' program module in the 'mod' directory
|
||||
* We emulate a Module class through the LegacyModule class
|
||||
*/
|
||||
if (!$module_class && file_exists("mod/{$moduleName}.php")) {
|
||||
$module_parameters[] = "mod/{$moduleName}.php";
|
||||
$module_class = LegacyModule::class;
|
||||
if (!$this->moduleClass && file_exists("mod/{$moduleName}.php")) {
|
||||
$this->parameters[] = "mod/{$moduleName}.php";
|
||||
$this->moduleClass = LegacyModule::class;
|
||||
}
|
||||
|
||||
$module_class = $module_class ?: PageNotFound::class;
|
||||
$this->moduleClass = $this->moduleClass ?: PageNotFound::class;
|
||||
}
|
||||
}
|
||||
|
||||
public function getModule(?string $module_class = null): ICanHandleRequests
|
||||
{
|
||||
$moduleClass = $module_class ?? $this->getModuleClass();
|
||||
|
||||
$stamp = microtime(true);
|
||||
|
||||
try {
|
||||
/** @var ICanHandleRequests $module */
|
||||
return $this->dice->create($module_class, $module_parameters);
|
||||
return $this->dice->create($moduleClass, $this->parameters);
|
||||
} finally {
|
||||
if ($this->dice_profiler_threshold > 0) {
|
||||
$dur = floatval(microtime(true) - $stamp);
|
||||
if ($dur >= $this->dice_profiler_threshold) {
|
||||
$this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $module_class, 'parameters' => $module_parameters]);
|
||||
$this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $moduleClass, 'parameters' => $this->parameters]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class SavedSearches
|
|||
public static function getHTML(string $return_url, string $search = ''): string
|
||||
{
|
||||
$saved = [];
|
||||
$saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()]);
|
||||
$saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()], ['order' => ['term']]);
|
||||
while ($saved_search = DBA::fetch($saved_searches)) {
|
||||
$saved[] = [
|
||||
'id' => $saved_search['id'],
|
||||
|
|
|
@ -30,13 +30,14 @@ use Friendica\Util\Strings;
|
|||
class Card extends BaseFactory
|
||||
{
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @param array $history Link request history
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Card
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException*@throws \Exception
|
||||
*/
|
||||
public function createFromUriId(int $uriId): \Friendica\Object\Api\Mastodon\Card
|
||||
public function createFromUriId(int $uriId, array $history = []): \Friendica\Object\Api\Mastodon\Card
|
||||
{
|
||||
$item = Post::selectFirst(['body'], ['uri-id' => $uriId]);
|
||||
if (!empty($item['body'])) {
|
||||
|
@ -76,6 +77,6 @@ class Card extends BaseFactory
|
|||
}
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Card($data);
|
||||
return new \Friendica\Object\Api\Mastodon\Card($data, $history);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,16 +76,17 @@ class Status extends BaseFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @param int $uid Item user
|
||||
* @param int $uriId Uri-ID of the item
|
||||
* @param int $uid Item user
|
||||
* @param bool $reblog Check for reblogged post
|
||||
*
|
||||
* @return \Friendica\Object\Api\Mastodon\Status
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws ImagickException|HTTPException\NotFoundException
|
||||
*/
|
||||
public function createFromUriId(int $uriId, int $uid = 0): \Friendica\Object\Api\Mastodon\Status
|
||||
public function createFromUriId(int $uriId, int $uid = 0, bool $reblog = true): \Friendica\Object\Api\Mastodon\Status
|
||||
{
|
||||
$fields = ['uri-id', 'uid', 'author-id', 'author-uri-id', 'author-link', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||
$fields = ['uri-id', 'uid', 'author-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id'];
|
||||
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
||||
if (!$item) {
|
||||
|
@ -95,7 +96,10 @@ class Status extends BaseFactory
|
|||
}
|
||||
throw new HTTPException\NotFoundException('Item with URI ID ' . $uriId . ' not found' . ($uid ? ' for user ' . $uid : '.'));
|
||||
}
|
||||
$account = $this->mstdnAccountFactory->createFromUriId($item['author-uri-id'], $uid);
|
||||
|
||||
$is_reshare = $reblog && !is_null($item['causer-uri-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT);
|
||||
|
||||
$account = $this->mstdnAccountFactory->createFromUriId($is_reshare ? $item['causer-uri-id']:$item['author-uri-id'], $uid);
|
||||
|
||||
$count_announce = Post::countPosts([
|
||||
'thr-parent-id' => $uriId,
|
||||
|
@ -183,6 +187,10 @@ class Status extends BaseFactory
|
|||
$reshare = [];
|
||||
}
|
||||
|
||||
if ($is_reshare) {
|
||||
$reshare = $this->createFromUriId($uriId, $uid, false)->toArray();
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare, $poll);
|
||||
}
|
||||
|
||||
|
|
|
@ -305,8 +305,8 @@ class APContact
|
|||
|
||||
$apcontact['pubkey'] = null;
|
||||
if (!empty($compacted['w3id:publicKey'])) {
|
||||
$apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value'));
|
||||
if (strstr($apcontact['pubkey'], 'RSA ')) {
|
||||
$apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value') ?? '');
|
||||
if (strpos($apcontact['pubkey'], 'RSA ') !== false) {
|
||||
$apcontact['pubkey'] = Crypto::rsaToPem($apcontact['pubkey']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3420,8 +3420,7 @@ class Contact
|
|||
["(NOT `unsearchable` OR `nurl` IN (SELECT `nurl` FROM `owner-view` WHERE `publish` OR `net-publish`))
|
||||
AND (`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $search, $search, $search]);
|
||||
|
||||
$contacts = self::selectToArray([], $condition, $params);
|
||||
return $contacts;
|
||||
return self::selectToArray([], $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,6 +70,7 @@ class GServer
|
|||
const DETECT_UNSPECIFIC = [self::DETECT_MANUAL, self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_HOST_META, self::DETECT_CONTACTS, self::DETECT_AP_ACTOR];
|
||||
|
||||
// Implementation specific endpoints
|
||||
// @todo Possibly add Lemmy detection via the endpoint /api/v3/site
|
||||
const DETECT_FRIENDIKA = 10;
|
||||
const DETECT_FRIENDICA = 11;
|
||||
const DETECT_STATUSNET = 12;
|
||||
|
|
|
@ -385,6 +385,9 @@ class Item
|
|||
Post\ThreadUser::update($item['uri-id'], $item['uid'], ['hidden' => true]);
|
||||
}
|
||||
|
||||
DI::notify()->deleteForItem($item['uri-id']);
|
||||
DI::notification()->deleteForItem($item['uri-id']);
|
||||
|
||||
Logger::info('Item has been marked for deletion.', ['id' => $item_id]);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -173,6 +173,64 @@ class Photo
|
|||
return $photo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all browsable albums for a given user
|
||||
*
|
||||
* @param int $uid The given user
|
||||
*
|
||||
* @return array An array of albums
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getBrowsableAlbumsForUser(int $uid): array
|
||||
{
|
||||
$photos = DBA::toArray(
|
||||
DBA::p(
|
||||
"SELECT DISTINCT(`album`) AS `album` FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?)",
|
||||
$uid,
|
||||
static::CONTACT_AVATAR,
|
||||
static::CONTACT_BANNER
|
||||
)
|
||||
);
|
||||
|
||||
return array_column($photos, 'album');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns browsable photos for a given user (optional and a given album)
|
||||
*
|
||||
* @param int $uid The given user id
|
||||
* @param string|null $album (optional) The given album
|
||||
*
|
||||
* @return array All photos of the user/album
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getBrowsablePhotosForUser(int $uid, string $album = null): array
|
||||
{
|
||||
$values = [
|
||||
$uid,
|
||||
Photo::CONTACT_AVATAR,
|
||||
Photo::CONTACT_BANNER
|
||||
];
|
||||
|
||||
if (!empty($album)) {
|
||||
$sqlExtra = "AND `album` = ? ";
|
||||
$values[] = $album;
|
||||
$sqlExtra2 = "";
|
||||
} else {
|
||||
$sqlExtra = '';
|
||||
$sqlExtra2 = ' ORDER BY created DESC LIMIT 0, 10';
|
||||
}
|
||||
|
||||
return DBA::toArray(
|
||||
DBA::p(
|
||||
"SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`,
|
||||
min(`scale`) AS `hiq`, max(`scale`) AS `loq`, ANY_VALUE(`desc`) AS `desc`, ANY_VALUE(`created`) AS `created`
|
||||
FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?) $sqlExtra
|
||||
GROUP BY `resource-id` $sqlExtra2",
|
||||
$values
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if photo with given conditions exists
|
||||
*
|
||||
|
|
|
@ -374,6 +374,21 @@ class Post
|
|||
return self::selectView('post-thread-user-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectPostThread(array $selected = [], array $condition = [], array $params = [])
|
||||
{
|
||||
return self::selectView('post-thread-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the given view for a given user
|
||||
*
|
||||
|
|
|
@ -69,6 +69,8 @@ class Statuses extends BaseApi
|
|||
|
||||
if ($request['pinned']) {
|
||||
$condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'type' => Post\Collection::FEATURED];
|
||||
} elseif ($request['only_media']) {
|
||||
$condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'type' => [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]];
|
||||
} elseif (!$uid) {
|
||||
$condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED],
|
||||
'uid' => 0, 'network' => Protocol::FEDERATED];
|
||||
|
@ -76,16 +78,11 @@ class Statuses extends BaseApi
|
|||
$condition = ["`author-id` = ? AND (`uid` = 0 OR (`uid` = ? AND NOT `global`))", $id, $uid];
|
||||
}
|
||||
|
||||
if (!$request['pinned']) {
|
||||
if (!$request['pinned'] && !$request['only_media']) {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
}
|
||||
|
||||
if ($request['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 (!empty($request['max_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]);
|
||||
}
|
||||
|
@ -99,12 +96,16 @@ class Statuses extends BaseApi
|
|||
$params['order'] = ['uri-id'];
|
||||
}
|
||||
|
||||
if ($request['exclude_replies']) {
|
||||
if (($request['pinned'] || $request['only_media']) && $request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
}
|
||||
|
||||
if ($request['pinned']) {
|
||||
$items = DBA::select('collection-view', ['uri-id'], $condition, $params);
|
||||
} elseif ($request['only_media']) {
|
||||
$items = DBA::select('media-view', ['uri-id'], $condition, $params);
|
||||
} elseif ($request['exclude_replies']) {
|
||||
$items = Post::selectThreadForUser($uid, ['uri-id'], $condition, $params);
|
||||
} else {
|
||||
$items = Post::selectForUser($uid, ['uri-id'], $condition, $params);
|
||||
}
|
||||
|
|
82
src/Module/Api/Mastodon/FollowedTags.php
Normal file
82
src/Module/Api/Mastodon/FollowedTags.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?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\Api\Mastodon;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/followed_tags/
|
||||
*/
|
||||
class FollowedTags extends BaseApi
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = $this->getRequest([
|
||||
'max_id' => 0,
|
||||
'since_id' => 0,
|
||||
'min_id' => 0,
|
||||
'limit' => 100, // Maximum number of results to return. Defaults to 100. Paginate using the HTTP Link header.
|
||||
], $request);
|
||||
|
||||
$params = ['order' => ['id' => true], 'limit' => $request['limit']];
|
||||
|
||||
$condition = ["`uid` = ? AND `term` LIKE ?", $uid, '#%'];
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`id` < ?", $request['max_id']]);
|
||||
}
|
||||
|
||||
if (!empty($request['since_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`id` > ?", $request['since_id']]);
|
||||
}
|
||||
|
||||
if (!empty($request['min_id'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`id` > ?", $request['min_id']]);
|
||||
|
||||
$params['order'] = ['id'];
|
||||
}
|
||||
|
||||
$return = [];
|
||||
|
||||
$saved_searches = DBA::select('search', ['id', 'term'], $condition);
|
||||
while ($saved_search = DBA::fetch($saved_searches)) {
|
||||
self::setBoundaries($saved_search['id']);
|
||||
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($saved_search['term'], '#')], [], true);
|
||||
$return[] = $hashtag->toArray();
|
||||
}
|
||||
|
||||
DBA::close($saved_searches);
|
||||
|
||||
if (!empty($request['min_id'])) {
|
||||
$return = array_reverse($return);
|
||||
}
|
||||
|
||||
self::setLinkHeader();
|
||||
System::jsonExit($return);
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ use Friendica\Core\System;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
@ -67,10 +68,24 @@ class Search extends BaseApi
|
|||
|
||||
if (empty($request['type']) || ($request['type'] == 'accounts')) {
|
||||
$result['accounts'] = self::searchAccounts($uid, $request['q'], $request['resolve'], $limit, $request['offset'], $request['following']);
|
||||
|
||||
if (!is_array($result['accounts'])) {
|
||||
// Curbing the search if we got an exact result
|
||||
$request['type'] = 'accounts';
|
||||
$result['accounts'] = [$result['accounts']];
|
||||
}
|
||||
}
|
||||
|
||||
if ((empty($request['type']) || ($request['type'] == 'statuses')) && (strpos($request['q'], '@') == false)) {
|
||||
$result['statuses'] = self::searchStatuses($uid, $request['q'], $request['account_id'], $request['max_id'], $request['min_id'], $limit, $request['offset']);
|
||||
|
||||
if (!is_array($result['statuses'])) {
|
||||
// Curbing the search if we got an exact result
|
||||
$request['type'] = 'statuses';
|
||||
$result['statuses'] = [$result['statuses']];
|
||||
}
|
||||
}
|
||||
|
||||
if ((empty($request['type']) || ($request['type'] == 'hashtags')) && (strpos($request['q'], '@') == false)) {
|
||||
$result['hashtags'] = self::searchHashtags($request['q'], $request['exclude_unreviewed'], $limit, $request['offset'], $this->parameters['version']);
|
||||
}
|
||||
|
@ -78,31 +93,59 @@ class Search extends BaseApi
|
|||
System::jsonExit($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uid
|
||||
* @param string $q
|
||||
* @param bool $resolve
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @param bool $following
|
||||
* @return array|\Friendica\Object\Api\Mastodon\Account Object if result is absolute (exact account match), list if not
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \Friendica\Network\HTTPException\NotFoundException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function searchAccounts(int $uid, string $q, bool $resolve, int $limit, int $offset, bool $following)
|
||||
{
|
||||
$accounts = [];
|
||||
|
||||
if ((strrpos($q, '@') > 0) || Network::isValidHttpUrl($q)) {
|
||||
$id = Contact::getIdForURL($q, 0, $resolve ? null : false);
|
||||
|
||||
if (!empty($id)) {
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($id, $uid);
|
||||
}
|
||||
if (
|
||||
(strrpos($q, '@') > 0 || Network::isValidHttpUrl($q))
|
||||
&& $id = Contact::getIdForURL($q, 0, $resolve ? null : false)
|
||||
) {
|
||||
return DI::mstdnAccount()->createFromContactId($id, $uid);
|
||||
}
|
||||
|
||||
if (empty($accounts)) {
|
||||
$contacts = Contact::searchByName($q, '', $following ? $uid : 0, $limit, $offset);
|
||||
foreach ($contacts as $contact) {
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($contact['id'], $uid);
|
||||
}
|
||||
DBA::close($contacts);
|
||||
$accounts = [];
|
||||
foreach (Contact::searchByName($q, '', $following ? $uid : 0, $limit, $offset) as $contact) {
|
||||
$accounts[] = DI::mstdnAccount()->createFromContactId($contact['id'], $uid);
|
||||
}
|
||||
|
||||
return $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uid
|
||||
* @param string $q
|
||||
* @param string $account_id
|
||||
* @param int $max_id
|
||||
* @param int $min_id
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return array|\Friendica\Object\Api\Mastodon\Status Object is result is absolute (exact post match), list if not
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \Friendica\Network\HTTPException\NotFoundException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function searchStatuses(int $uid, string $q, string $account_id, int $max_id, int $min_id, int $limit, int $offset)
|
||||
{
|
||||
if (Network::isValidHttpUrl($q)) {
|
||||
$q = Network::convertToIdn($q);
|
||||
// If the user-specific search failed, we search and probe a public post
|
||||
$item_id = Item::fetchByLink($q, $uid) ?: Item::fetchByLink($q);
|
||||
if ($item_id && $item = Post::selectFirst(['uri-id'], ['id' => $item_id])) {
|
||||
return DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
$params = ['order' => ['uri-id' => true], 'limit' => [$offset, $limit]];
|
||||
|
||||
if (substr($q, 0, 1) == '#') {
|
||||
|
@ -148,7 +191,7 @@ class Search extends BaseApi
|
|||
return $statuses;
|
||||
}
|
||||
|
||||
private static function searchHashtags(string $q, bool $exclude_unreviewed, int $limit, int $offset, int $version)
|
||||
private static function searchHashtags(string $q, bool $exclude_unreviewed, int $limit, int $offset, int $version): array
|
||||
{
|
||||
$q = ltrim($q, '#');
|
||||
|
||||
|
|
52
src/Module/Api/Mastodon/Tags.php
Normal file
52
src/Module/Api/Mastodon/Tags.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?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\Api\Mastodon;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/tags/
|
||||
*/
|
||||
class Tags extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_READ);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($this->parameters['hashtag'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$tag = ltrim($this->parameters['hashtag'], '#');
|
||||
$following = DBA::exists('search', ['uid' => $uid, 'term' => '#' . $tag]);
|
||||
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => $tag], [], $following);
|
||||
System::jsonExit($hashtag->toArray());
|
||||
}
|
||||
}
|
51
src/Module/Api/Mastodon/Tags/Follow.php
Normal file
51
src/Module/Api/Mastodon/Tags/Follow.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?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\Api\Mastodon\Tags;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/tags/#follow
|
||||
*/
|
||||
class Follow extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($this->parameters['hashtag'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$fields = ['uid' => $uid, 'term' => '#' . ltrim($this->parameters['hashtag'], '#')];
|
||||
if (!DBA::exists('search', $fields)) {
|
||||
DBA::insert('search', $fields);
|
||||
}
|
||||
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($this->parameters['hashtag'])], [], true);
|
||||
System::jsonExit($hashtag->toArray());
|
||||
}
|
||||
}
|
50
src/Module/Api/Mastodon/Tags/Unfollow.php
Normal file
50
src/Module/Api/Mastodon/Tags/Unfollow.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?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\Api\Mastodon\Tags;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/tags/#unfollow
|
||||
*/
|
||||
class Unfollow extends BaseApi
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
self::checkAllowedScope(self::SCOPE_WRITE);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
if (empty($this->parameters['hashtag'])) {
|
||||
DI::mstdnError()->UnprocessableEntity();
|
||||
}
|
||||
|
||||
$term = ['uid' => $uid, 'term' => '#' . ltrim($this->parameters['hashtag'], '#')];
|
||||
|
||||
DBA::delete('search', $term);
|
||||
|
||||
$hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($this->parameters['hashtag'])], [], false);
|
||||
System::jsonExit($hashtag->toArray());
|
||||
}
|
||||
}
|
60
src/Module/Api/Mastodon/Trends/Links.php
Normal file
60
src/Module/Api/Mastodon/Trends/Links.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?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\Api\Mastodon\Trends;
|
||||
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/trends/#links
|
||||
*/
|
||||
class Links extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$request = $this->getRequest([
|
||||
'limit' => 10, // Maximum number of results to return. Defaults to 10.
|
||||
], $request);
|
||||
|
||||
$condition = ["EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread-view`.`uri-id` AND `type` = ? AND NOT `name` IS NULL AND NOT `description` IS NULL) AND NOT `private` AND `commented` > ? AND `created` > ?",
|
||||
Post\Media::HTML, DateTimeFormat::utc('now -1 day'), DateTimeFormat::utc('now -1 week')];
|
||||
$condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]);
|
||||
|
||||
$trending = [];
|
||||
$statuses = Post::selectPostThread(['uri-id', 'total-comments', 'total-actors'], $condition, ['limit' => $request['limit'], 'order' => ['total-actors' => true]]);
|
||||
while ($status = Post::fetch($statuses)) {
|
||||
$history = [['day' => (string)time(), 'uses' => (string)$status['total-comments'], 'accounts' => (string)$status['total-actors']]];
|
||||
$trending[] = DI::mstdnCard()->createFromUriId($status['uri-id'], $history)->toArray();
|
||||
}
|
||||
DBA::close($statuses);
|
||||
|
||||
System::jsonExit($trending);
|
||||
}
|
||||
}
|
60
src/Module/Api/Mastodon/Trends/Statuses.php
Normal file
60
src/Module/Api/Mastodon/Trends/Statuses.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?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\Api\Mastodon\Trends;
|
||||
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/trends/#statuses
|
||||
*/
|
||||
class Statuses extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = $this->getRequest([
|
||||
'limit' => 10, // Maximum number of results to return. Defaults to 10.
|
||||
], $request);
|
||||
|
||||
$condition = ["NOT `private` AND `commented` > ? AND `created` > ?", DateTimeFormat::utc('now -1 day'), DateTimeFormat::utc('now -1 week')];
|
||||
$condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]);
|
||||
|
||||
$trending = [];
|
||||
$statuses = Post::selectPostThread(['uri-id'], $condition, ['limit' => $request['limit'], 'order' => ['total-actors' => true]]);
|
||||
while ($status = Post::fetch($statuses)) {
|
||||
$trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid);
|
||||
}
|
||||
DBA::close($statuses);
|
||||
|
||||
System::jsonExit($trending);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Api\Mastodon;
|
||||
namespace Friendica\Module\Api\Mastodon\Trends;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
|
@ -29,7 +29,7 @@ use Friendica\Module\BaseApi;
|
|||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/instance/trends/
|
||||
*/
|
||||
class Trends extends BaseApi
|
||||
class Tags extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
|
@ -37,7 +37,6 @@ class Attach extends BaseModule
|
|||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$a = DI::app();
|
||||
if (empty($this->parameters['item'])) {
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
|
|
100
src/Module/Media/Attachment/Browser.php
Normal file
100
src/Module/Media/Attachment/Browser.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?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\Media\Attachment;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException\UnauthorizedException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Browser for Attachments
|
||||
*/
|
||||
class Browser extends BaseModule
|
||||
{
|
||||
/** @var IHandleUserSessions */
|
||||
protected $session;
|
||||
/** @var App */
|
||||
protected $app;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->session = $session;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
if (!$this->session->getLocalUserId()) {
|
||||
throw new UnauthorizedException($this->t('You need to be logged in to access this page.'));
|
||||
}
|
||||
|
||||
// Needed to match the correct template in a module that uses a different theme than the user/site/default
|
||||
$theme = Strings::sanitizeFilePathItem($request['theme'] ?? '');
|
||||
if ($theme && is_file("view/theme/$theme/config.php")) {
|
||||
$this->app->setCurrentTheme($theme);
|
||||
}
|
||||
|
||||
$files = Attach::selectToArray(['id', 'filename', 'filetype'], ['uid' => $this->session->getLocalUserId()]);
|
||||
|
||||
$fileArray = array_map([$this, 'map_files'], $files);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('media/browser.tpl');
|
||||
$output = Renderer::replaceMacros($tpl, [
|
||||
'$type' => 'attachment',
|
||||
'$path' => ['' => $this->t('Files')],
|
||||
'$folders' => false,
|
||||
'$files' => $fileArray,
|
||||
'$cancel' => $this->t('Cancel'),
|
||||
'$nickname' => $this->app->getLoggedInUserNickname(),
|
||||
'$upload' => $this->t('Upload'),
|
||||
]);
|
||||
|
||||
if (empty($request['mode'])) {
|
||||
System::httpExit($output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected function map_files(array $record): array
|
||||
{
|
||||
list($m1, $m2) = explode('/', $record['filetype']);
|
||||
$filetype = file_exists(sprintf('images/icons/%s.png', $m1) ? $m1 : 'text');
|
||||
|
||||
return [
|
||||
sprintf('%s/attach/%s', $this->baseUrl, $record['id']),
|
||||
$record['filename'],
|
||||
sprintf('%s/images/icon/16/%s.png', $this->baseUrl, $filetype),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Profile\Attachment;
|
||||
namespace Friendica\Module\Media\Attachment;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
@ -73,30 +73,12 @@ class Upload extends \Friendica\BaseModule
|
|||
$this->response->setType(Response::TYPE_JSON, 'application/json');
|
||||
}
|
||||
|
||||
$nick = $this->parameters['nickname'];
|
||||
$owner = User::getOwnerDataByNick($nick);
|
||||
$owner = User::getOwnerDataById($this->userSession->getLocalUserId());
|
||||
if (!$owner) {
|
||||
$this->logger->warning('owner is not a valid record:', ['owner' => $owner, 'nick' => $nick]);
|
||||
$this->logger->warning('Owner not found.', ['uid' => $this->userSession->getLocalUserId()]);
|
||||
return $this->return(401, $this->t('Invalid request.'));
|
||||
}
|
||||
|
||||
$can_post = false;
|
||||
$contact_id = 0;
|
||||
$page_owner_uid = $owner['uid'];
|
||||
$community_page = $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
|
||||
|
||||
if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $page_owner_uid) {
|
||||
$can_post = true;
|
||||
} elseif ($community_page && !empty($this->userSession->getRemoteContactID($page_owner_uid))) {
|
||||
$contact_id = $this->userSession->getRemoteContactID($page_owner_uid);
|
||||
$can_post = $this->database->exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]);
|
||||
}
|
||||
|
||||
if (!$can_post) {
|
||||
$this->logger->warning('User does not have required permissions', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]);
|
||||
return $this->return(403, $this->t('Permission denied.'), true);
|
||||
}
|
||||
|
||||
if (empty($_FILES['userfile'])) {
|
||||
$this->logger->warning('No file uploaded (empty userfile)');
|
||||
return $this->return(401, $this->t('Invalid request.'), true);
|
||||
|
@ -126,7 +108,7 @@ class Upload extends \Friendica\BaseModule
|
|||
return $this->return(401, $msg);
|
||||
}
|
||||
|
||||
$newid = Attach::storeFile($tempFileName, $page_owner_uid, $fileName, '<' . $owner['id'] . '>');
|
||||
$newid = Attach::storeFile($tempFileName, $owner['uid'], $fileName, '<' . $owner['id'] . '>');
|
||||
|
||||
@unlink($tempFileName);
|
||||
|
125
src/Module/Media/Photo/Browser.php
Normal file
125
src/Module/Media/Photo/Browser.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?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\Media\Photo;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException\UnauthorizedException;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Browser for Photos
|
||||
*/
|
||||
class Browser extends BaseModule
|
||||
{
|
||||
/** @var IHandleUserSessions */
|
||||
protected $session;
|
||||
/** @var App */
|
||||
protected $app;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->session = $session;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
if (!$this->session->getLocalUserId()) {
|
||||
throw new UnauthorizedException($this->t('You need to be logged in to access this page.'));
|
||||
}
|
||||
|
||||
// Needed to match the correct template in a module that uses a different theme than the user/site/default
|
||||
$theme = Strings::sanitizeFilePathItem($request['theme'] ?? '');
|
||||
if ($theme && is_file("view/theme/$theme/config.php")) {
|
||||
$this->app->setCurrentTheme($theme);
|
||||
}
|
||||
|
||||
$album = $this->parameters['album'] ?? null;
|
||||
|
||||
$photos = Photo::getBrowsablePhotosForUser($this->session->getLocalUserId(), $album);
|
||||
$albums = $album ? false : Photo::getBrowsableAlbumsForUser($this->session->getLocalUserId());
|
||||
|
||||
$path = [
|
||||
'' => $this->t('Photos'),
|
||||
];
|
||||
if (!empty($album)) {
|
||||
$path[$album] = $album;
|
||||
}
|
||||
|
||||
$photosArray = array_map([$this, 'map_files'], $photos);
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('media/browser.tpl');
|
||||
$output = Renderer::replaceMacros($tpl, [
|
||||
'$type' => 'photo',
|
||||
'$path' => $path,
|
||||
'$folders' => $albums,
|
||||
'$files' => $photosArray,
|
||||
'$cancel' => $this->t('Cancel'),
|
||||
'$nickname' => $this->app->getLoggedInUserNickname(),
|
||||
'$upload' => $this->t('Upload'),
|
||||
]);
|
||||
|
||||
if (empty($request['mode'])) {
|
||||
System::httpExit($output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected function map_files(array $record): array
|
||||
{
|
||||
$types = Images::supportedTypes();
|
||||
$ext = $types[$record['type']];
|
||||
$filename_e = $record['filename'];
|
||||
|
||||
// Take the largest picture that is smaller or equal 640 pixels
|
||||
$photo = Photo::selectFirst(
|
||||
['scale'],
|
||||
[
|
||||
"`resource-id` = ? AND `height` <= ? AND `width` <= ?",
|
||||
$record['resource-id'],
|
||||
640,
|
||||
640
|
||||
],
|
||||
['order' => ['scale']]);
|
||||
$scale = $photo['scale'] ?? $record['loq'];
|
||||
|
||||
return [
|
||||
sprintf('%s/photos/%s/image/%s', $this->baseUrl, $this->app->getLoggedInUserNickname(), $record['resource-id']),
|
||||
$filename_e,
|
||||
sprintf('%s/photo/%s-%s.%s', $this->baseUrl, $record['resource-id'], $scale, $ext),
|
||||
$record['desc'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Profile\Photos;
|
||||
namespace Friendica\Module\Media\Photo;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
@ -76,36 +76,11 @@ class Upload extends \Friendica\BaseModule
|
|||
|
||||
$album = trim($request['album'] ?? '');
|
||||
|
||||
if (empty($_FILES['media'])) {
|
||||
$user = $this->database->selectFirst('owner-view', ['id', 'uid', 'nickname', 'page-flags'], ['nickname' => $this->parameters['nickname'], 'blocked' => false]);
|
||||
} else {
|
||||
$user = $this->database->selectFirst('owner-view', ['id', 'uid', 'nickname', 'page-flags'], ['uid' => BaseApi::getCurrentUserID() ?: null, 'blocked' => false]);
|
||||
}
|
||||
$owner = User::getOwnerDataById($this->userSession->getLocalUserId());
|
||||
|
||||
if (!$this->database->isResult($user)) {
|
||||
$this->logger->warning('User is not valid', ['nickname' => $this->parameters['nickname'], 'user' => $user]);
|
||||
return $this->return(404, $this->t('User not found.'));
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup permissions structures
|
||||
*/
|
||||
$can_post = false;
|
||||
$visitor = 0;
|
||||
$contact_id = 0;
|
||||
$page_owner_uid = $user['uid'];
|
||||
|
||||
if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $page_owner_uid) {
|
||||
$can_post = true;
|
||||
} elseif ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY && !$this->userSession->getRemoteContactID($page_owner_uid)) {
|
||||
$contact_id = $this->userSession->getRemoteContactID($page_owner_uid);
|
||||
$can_post = $this->database->exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]);
|
||||
$visitor = $contact_id;
|
||||
}
|
||||
|
||||
if (!$can_post) {
|
||||
$this->logger->warning('No permission to upload files', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]);
|
||||
return $this->return(403, $this->t('Permission denied.'), true);
|
||||
if (!$owner) {
|
||||
$this->logger->warning('Owner not found.', ['uid' => $this->userSession->getLocalUserId()]);
|
||||
return $this->return(401, $this->t('Invalid request.'));
|
||||
}
|
||||
|
||||
if (empty($_FILES['userfile']) && empty($_FILES['media'])) {
|
||||
|
@ -223,9 +198,9 @@ class Upload extends \Friendica\BaseModule
|
|||
$album = $this->t('Wall Photos');
|
||||
}
|
||||
|
||||
$allow_cid = '<' . $user['id'] . '>';
|
||||
$allow_cid = '<' . $owner['id'] . '>';
|
||||
|
||||
$result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $allow_cid);
|
||||
$result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 0, Photo::DEFAULT, $allow_cid);
|
||||
if (!$result) {
|
||||
$this->logger->warning('Photo::store() failed', ['result' => $result]);
|
||||
return $this->return(401, $this->t('Image upload failed.'));
|
||||
|
@ -233,7 +208,7 @@ class Upload extends \Friendica\BaseModule
|
|||
|
||||
if ($width > 640 || $height > 640) {
|
||||
$image->scaleDown(640);
|
||||
$result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $allow_cid);
|
||||
$result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 1, Photo::DEFAULT, $allow_cid);
|
||||
if ($result) {
|
||||
$smallest = 1;
|
||||
}
|
||||
|
@ -241,14 +216,14 @@ class Upload extends \Friendica\BaseModule
|
|||
|
||||
if ($width > 320 || $height > 320) {
|
||||
$image->scaleDown(320);
|
||||
$result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $allow_cid);
|
||||
$result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 2, Photo::DEFAULT, $allow_cid);
|
||||
if ($result && ($smallest == 0)) {
|
||||
$smallest = 2;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->info('upload done');
|
||||
return $this->return(200, "\n\n" . '[url=' . $this->baseUrl . '/photos/' . $user['nickname'] . '/image/' . $resource_id . '][img]' . $this->baseUrl . "/photo/$resource_id-$smallest." . $image->getExt() . "[/img][/url]\n\n");
|
||||
return $this->return(200, "\n\n" . '[url=' . $this->baseUrl . '/photos/' . $owner['nickname'] . '/image/' . $resource_id . '][img]' . $this->baseUrl . "/photo/$resource_id-$smallest." . $image->getExt() . "[/img][/url]\n\n");
|
||||
}
|
||||
|
||||
/**
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Module\Profile\Photos;
|
||||
namespace Friendica\Module\Profile;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Pager;
|
||||
|
@ -40,7 +40,7 @@ use Friendica\Util\Images;
|
|||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Index extends \Friendica\Module\BaseProfile
|
||||
class Photos extends \Friendica\Module\BaseProfile
|
||||
{
|
||||
/** @var IHandleUserSessions */
|
||||
private $session;
|
|
@ -33,6 +33,7 @@ use Friendica\Navigation\Notifications\Collection;
|
|||
use Friendica\Navigation\Notifications\Entity;
|
||||
use Friendica\Navigation\Notifications\Factory;
|
||||
use Friendica\Network\HTTPException\NotFoundException;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
@ -268,4 +269,23 @@ class Notification extends BaseRepository
|
|||
|
||||
return $this->db->delete(self::$table_name, $condition);
|
||||
}
|
||||
|
||||
public function deleteForItem(int $itemUriId): bool
|
||||
{
|
||||
$conditionTarget = [
|
||||
'vid' => Verb::getID(Activity::POST),
|
||||
'target-uri-id' => $itemUriId,
|
||||
];
|
||||
|
||||
$conditionParent = [
|
||||
'vid' => Verb::getID(Activity::POST),
|
||||
'parent-uri-id' => $itemUriId,
|
||||
];
|
||||
|
||||
$this->logger->notice('deleteForItem', ['conditionTarget' => $conditionTarget, 'conditionParent' => $conditionParent]);
|
||||
|
||||
return
|
||||
$this->db->delete(self::$table_name, $conditionTarget)
|
||||
&& $this->db->delete(self::$table_name, $conditionParent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -807,4 +807,10 @@ class Notify extends BaseRepository
|
|||
|
||||
return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $item['body'], $itemlink, true);
|
||||
}
|
||||
|
||||
public function deleteForItem(int $itemUriId): void
|
||||
{
|
||||
$this->db->delete('notify', ['otype' => 'item', 'uri-id' => $itemUriId]);
|
||||
$this->db->delete('notify', ['otype' => 'item', 'parent-uri-id' => $itemUriId]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,6 +226,7 @@ class Introduction implements \JsonSerializable
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
|
|
|
@ -59,7 +59,7 @@ class Card extends BaseDataTransferObject
|
|||
* @param array $attachment Attachment record
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(array $attachment)
|
||||
public function __construct(array $attachment, array $history = [])
|
||||
{
|
||||
$this->url = $attachment['url'] ?? '';
|
||||
$this->title = $attachment['title'] ?? '';
|
||||
|
@ -72,6 +72,7 @@ class Card extends BaseDataTransferObject
|
|||
$this->width = $attachment['width'] ?? 0;
|
||||
$this->height = $attachment['height'] ?? 0;
|
||||
$this->image = $attachment['image'] ?? '';
|
||||
$this->history = $history;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,18 +37,23 @@ class Tag extends BaseDataTransferObject
|
|||
protected $url = null;
|
||||
/** @var array */
|
||||
protected $history = [];
|
||||
/** @var bool */
|
||||
protected $following = false;
|
||||
|
||||
/**
|
||||
* Creates a hashtag record from an tag-view record.
|
||||
*
|
||||
* @param BaseURL $baseUrl
|
||||
* @param array $tag tag-view record
|
||||
* @param array $tag tag-view record
|
||||
* @param array $history
|
||||
* @param array $following "true" if the user is following this tag
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function __construct(BaseURL $baseUrl, array $tag, array $history = [])
|
||||
public function __construct(BaseURL $baseUrl, array $tag, array $history = [], bool $following = false)
|
||||
{
|
||||
$this->name = strtolower($tag['name']);
|
||||
$this->url = $baseUrl . '/search?tag=' . urlencode($this->name);
|
||||
$this->history = $history;
|
||||
$this->name = strtolower($tag['name']);
|
||||
$this->url = $baseUrl . '/search?tag=' . urlencode($this->name);
|
||||
$this->history = $history;
|
||||
$this->following = $following;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -622,7 +622,7 @@ class Post
|
|||
public function addChild(Post $item)
|
||||
{
|
||||
if (!$item->getId()) {
|
||||
Logger::fatal('Post object has no id', ['post' => $item]);
|
||||
Logger::error('Post object has no id', ['post' => $item]);
|
||||
return false;
|
||||
} elseif ($this->getChild($item->getId())) {
|
||||
Logger::warning('Post object already exists', ['post' => $item]);
|
||||
|
@ -633,7 +633,7 @@ class Post
|
|||
* Only add what will be displayed
|
||||
*/
|
||||
if ($item->getDataValue('network') === Protocol::MAIL && DI::userSession()->getLocalUserId() != $item->getDataValue('uid')) {
|
||||
Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => $local_user]);
|
||||
Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => DI::userSession()->getLocalUserId()]);
|
||||
return false;
|
||||
} elseif (DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) ||
|
||||
DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE)) {
|
||||
|
|
|
@ -538,7 +538,7 @@ class DFRN
|
|||
|
||||
XML::addElement($doc, $author, 'poco:utcOffset', DateTimeFormat::timezoneNow($profile['timezone'], 'P'));
|
||||
|
||||
if (trim($profile['homepage']) != '') {
|
||||
if (trim($profile['homepage'])) {
|
||||
$urls = $doc->createElement('poco:urls');
|
||||
XML::addElement($doc, $urls, 'poco:type', 'homepage');
|
||||
XML::addElement($doc, $urls, 'poco:value', $profile['homepage']);
|
||||
|
@ -546,7 +546,7 @@ class DFRN
|
|||
$author->appendChild($urls);
|
||||
}
|
||||
|
||||
if (trim($profile['pub_keywords']) != '') {
|
||||
if (trim($profile['pub_keywords'] ?? '')) {
|
||||
$keywords = explode(',', $profile['pub_keywords']);
|
||||
|
||||
foreach ($keywords as $keyword) {
|
||||
|
@ -554,7 +554,7 @@ class DFRN
|
|||
}
|
||||
}
|
||||
|
||||
if (trim($profile['xmpp']) != '') {
|
||||
if (trim($profile['xmpp'])) {
|
||||
$ims = $doc->createElement('poco:ims');
|
||||
XML::addElement($doc, $ims, 'poco:type', 'xmpp');
|
||||
XML::addElement($doc, $ims, 'poco:value', $profile['xmpp']);
|
||||
|
@ -562,7 +562,7 @@ class DFRN
|
|||
$author->appendChild($ims);
|
||||
}
|
||||
|
||||
if (trim($profile['locality'] . $profile['region'] . $profile['country-name']) != '') {
|
||||
if (trim($profile['locality'] . $profile['region'] . $profile['country-name'])) {
|
||||
$element = $doc->createElement('poco:address');
|
||||
|
||||
XML::addElement($doc, $element, 'poco:formatted', Profile::formatLocation($profile));
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
use Friendica\Database\DBA;
|
||||
|
||||
if (!defined('DB_UPDATE_VERSION')) {
|
||||
define('DB_UPDATE_VERSION', 1491);
|
||||
define('DB_UPDATE_VERSION', 1495);
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -1658,6 +1658,7 @@ return [
|
|||
"comment" => ["type" => "text", "comment" => "Report"],
|
||||
"forward" => ["type" => "boolean", "comment" => "Forward the report to the remote server"],
|
||||
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
|
||||
"status" => ["type" => "tinyint unsigned", "comment" => "Status of the report"],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["id"],
|
||||
|
@ -1670,6 +1671,7 @@ return [
|
|||
"fields" => [
|
||||
"rid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["report" => "id"], "comment" => "Report id"],
|
||||
"uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Uri-id of the reported post"],
|
||||
"status" => ["type" => "tinyint unsigned", "comment" => "Status of the reported post"],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["rid", "uri-id"],
|
||||
|
|
|
@ -664,6 +664,8 @@
|
|||
"question-end-time" => ["post-question", "end-time"],
|
||||
"has-categories" => "0",
|
||||
"has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`)",
|
||||
"total-comments" => "(SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)",
|
||||
"total-actors" => "(SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)",
|
||||
"signed_text" => ["diaspora-interaction", "interaction"],
|
||||
"parent-guid" => ["parent-item-uri", "guid"],
|
||||
"parent-network" => ["parent-post", "network"],
|
||||
|
@ -721,6 +723,22 @@
|
|||
INNER JOIN `post` ON `post-collection`.`uri-id` = `post`.`uri-id`
|
||||
INNER JOIN `post-thread` ON `post-thread`.`uri-id` = `post`.`parent-uri-id`"
|
||||
],
|
||||
"media-view" => [
|
||||
"fields" => [
|
||||
"uri-id" => ["post-media", "uri-id"],
|
||||
"type" => ["post-media", "type"],
|
||||
"received" => ["post", "received"],
|
||||
"created" => ["post", "created"],
|
||||
"private" => ["post", "private"],
|
||||
"visible" => ["post", "visible"],
|
||||
"deleted" => ["post", "deleted"],
|
||||
"thr-parent-id" => ["post", "thr-parent-id"],
|
||||
"author-id" => ["post", "author-id"],
|
||||
"gravity" => ["post", "gravity"],
|
||||
],
|
||||
"query" => "FROM `post-media`
|
||||
INNER JOIN `post` ON `post-media`.`uri-id` = `post`.`uri-id`"
|
||||
],
|
||||
"tag-view" => [
|
||||
"fields" => [
|
||||
"uri-id" => ["post-tag", "uri-id"],
|
||||
|
|
|
@ -31,18 +31,16 @@ use Friendica\App\Router as R;
|
|||
use Friendica\Module;
|
||||
|
||||
$profileRoutes = [
|
||||
'' => [Module\Profile\Index::class, [R::GET]],
|
||||
'/attachment/upload' => [Module\Profile\Attachment\Upload::class, [ R::POST]],
|
||||
'/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]],
|
||||
'/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]],
|
||||
'/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]],
|
||||
'/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]],
|
||||
'' => [Module\Profile\Index::class, [R::GET]],
|
||||
'/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::class, [R::GET ]],
|
||||
'/profile' => [Module\Profile\Profile::class, [R::GET]],
|
||||
'/remote_follow' => [Module\Profile\RemoteFollow::class, [R::GET, R::POST]],
|
||||
'/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]],
|
||||
'/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]],
|
||||
'/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]],
|
||||
];
|
||||
|
||||
$apiRoutes = [
|
||||
|
@ -235,12 +233,14 @@ return [
|
|||
'/featured_tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST]], // not supported
|
||||
'/featured_tags/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::DELETE ]], // not supported
|
||||
'/featured_tags/suggestions' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported
|
||||
'/filters' => [Module\Api\Mastodon\Filters::class, [R::GET ]], // Dummy, not supported
|
||||
'/filters/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST, R::PUT, R::DELETE]], // not supported
|
||||
'/follow_requests' => [Module\Api\Mastodon\FollowRequests::class, [R::GET ]],
|
||||
'/follow_requests/{id:\d+}/{action}' => [Module\Api\Mastodon\FollowRequests::class, [ R::POST]],
|
||||
'/followed_tags' => [Module\Api\Mastodon\FollowedTags::class, [R::GET ]],
|
||||
'/instance' => [Module\Api\Mastodon\Instance::class, [R::GET ]],
|
||||
'/instance/activity' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo
|
||||
'/instance/domain_blocks' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo
|
||||
'/instance/extended_description' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo
|
||||
'/instance/peers' => [Module\Api\Mastodon\Instance\Peers::class, [R::GET ]],
|
||||
'/instance/rules' => [Module\Api\Mastodon\Instance\Rules::class, [R::GET ]],
|
||||
'/lists' => [Module\Api\Mastodon\Lists::class, [R::GET, R::POST]],
|
||||
|
@ -289,18 +289,25 @@ return [
|
|||
'/streaming/user' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented
|
||||
'/streaming/user/notification' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented
|
||||
'/suggestions/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::DELETE ]], // not implemented
|
||||
'/tags/{hashtag}' => [Module\Api\Mastodon\Tags::class, [R::GET ]],
|
||||
'/tags/{hashtag}/follow' => [Module\Api\Mastodon\Tags\Follow::class, [ R::POST]],
|
||||
'/tags/{hashtag}/unfollow' => [Module\Api\Mastodon\Tags\Unfollow::class, [ R::POST]],
|
||||
'/timelines/direct' => [Module\Api\Mastodon\Timelines\Direct::class, [R::GET ]],
|
||||
'/timelines/home' => [Module\Api\Mastodon\Timelines\Home::class, [R::GET ]],
|
||||
'/timelines/list/{id:\d+}' => [Module\Api\Mastodon\Timelines\ListTimeline::class, [R::GET ]],
|
||||
'/timelines/public' => [Module\Api\Mastodon\Timelines\PublicTimeline::class, [R::GET ]],
|
||||
'/timelines/tag/{hashtag}' => [Module\Api\Mastodon\Timelines\Tag::class, [R::GET ]],
|
||||
'/trends' => [Module\Api\Mastodon\Trends::class, [R::GET ]],
|
||||
'/trends/links' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented
|
||||
'/trends/statuses' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented
|
||||
'/trends/tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented
|
||||
'/trends' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]],
|
||||
'/trends/links' => [Module\Api\Mastodon\Trends\Links::class, [R::GET ]],
|
||||
'/trends/statuses' => [Module\Api\Mastodon\Trends\Statuses::class, [R::GET ]],
|
||||
'/trends/tags' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]],
|
||||
],
|
||||
'/v2' => [
|
||||
'/instance' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported
|
||||
],
|
||||
'/v{version:\d+}' => [
|
||||
'/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported
|
||||
'/filters' => [Module\Api\Mastodon\Filters::class, [R::GET ]], // Dummy, not supported
|
||||
'/media' => [Module\Api\Mastodon\Media::class, [ R::POST]],
|
||||
'/search' => [Module\Api\Mastodon\Search::class, [R::GET ]],
|
||||
'/suggestions' => [Module\Api\Mastodon\Suggestions::class, [R::GET ]],
|
||||
|
@ -469,6 +476,14 @@ return [
|
|||
'/magic' => [Module\Magic::class, [R::GET]],
|
||||
'/manifest' => [Module\Manifest::class, [R::GET]],
|
||||
'/friendica.webmanifest' => [Module\Manifest::class, [R::GET]],
|
||||
|
||||
'/media' => [
|
||||
'/attachment/browser' => [Module\Media\Attachment\Browser::class, [R::GET]],
|
||||
'/attachment/upload' => [Module\Media\Attachment\Upload::class, [ R::POST]],
|
||||
'/photo/browser[/{album}]' => [Module\Media\Photo\Browser::class, [R::GET]],
|
||||
'/photo/upload' => [Module\Media\Photo\Upload::class, [ R::POST]],
|
||||
],
|
||||
|
||||
'/moderation' => [
|
||||
'[/]' => [Module\Moderation\Summary::class, [R::GET]],
|
||||
|
||||
|
@ -556,7 +571,7 @@ return [
|
|||
|
||||
// Kept for backwards-compatibility
|
||||
// @TODO remove by version 2023.12
|
||||
'/photos/{nickname}' => [Module\Profile\Photos\Index::class, [R::GET]],
|
||||
'/photos/{nickname}' => [Module\Profile\Photos::class, [R::GET]],
|
||||
|
||||
'/ping' => [Module\Notifications\Ping::class, [R::GET]],
|
||||
|
||||
|
|
|
@ -345,12 +345,12 @@ img.acpopup-img {
|
|||
.fbrowser .path a:before, .fbrowser .path .btn-link:before { content: "/"; padding-right: 5px;}
|
||||
.fbrowser .folders ul { list-style-type: none; padding-left: 10px;}
|
||||
.fbrowser .list { height: auto; overflow-y: hidden; margin: 10px 0px; }
|
||||
.fbrowser.image .photo-album-image-wrapper { float: left; }
|
||||
.fbrowser.image a img, .fbrowser.image .btn-link img { height: 48px; }
|
||||
.fbrowser.image a p, .fbrowser.image .btn-link p { display: none;}
|
||||
.fbrowser.file .photo-album-image-wrapper { float:none; white-space: nowrap; }
|
||||
.fbrowser.file img { display: inline; }
|
||||
.fbrowser.file p { display: inline; white-space: nowrap; }
|
||||
.fbrowser.photo .photo-album-image-wrapper { float: left; }
|
||||
.fbrowser.photo a img, .fbrowser.photo .btn-link img { height: 48px; }
|
||||
.fbrowser.photo a p, .fbrowser.photo .btn-link p { display: none;}
|
||||
.fbrowser.attachment .photo-album-image-wrapper { float:none; white-space: nowrap; }
|
||||
.fbrowser.attachment img { display: inline; }
|
||||
.fbrowser.attachment p { display: inline; white-space: nowrap; }
|
||||
.fbrowser .upload { clear: both; padding-top: 1em;}
|
||||
.fbrowser .error { background: #ffeeee; border: 1px solid #994444; color: #994444; padding: 0.5em;}
|
||||
.fbrowser .error .close { float: right; font-weight: bold; }
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
|
||||
/**
|
||||
* Filebrowser - Friendica Communications Server
|
||||
*
|
||||
* Copyright (c) 2010-2021, the Friendica project
|
||||
*
|
||||
* 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 code handle user interaction for image/file upload/browser dialog.
|
||||
* Is loaded from filebrowser_plain.tpl
|
||||
*
|
||||
* To load filebrowser in colorbox, call
|
||||
*
|
||||
* Dialog.doImageBrowser(eventname, id);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* Dialog.doFileBrowser(eventname, id);
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* eventname: event name to catch return value
|
||||
* id: id returned to event handler
|
||||
*
|
||||
* When user select an item, an event in fired in parent page, on body element
|
||||
* The event is named
|
||||
*
|
||||
* fbrowser.<type>.[<eventname>]
|
||||
*
|
||||
* <type> will be one of "image" or "file", and the event handler will
|
||||
* get the following params:
|
||||
*
|
||||
* filemane: filename of item choosed by user
|
||||
* embed: bbcode to embed element into posts
|
||||
* id: id from caller code
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // open dialog for select an image for a textarea with id "myeditor"
|
||||
* var id="myeditor";
|
||||
* Dialog.doImageBrowser("example", id);
|
||||
*
|
||||
* // setup event handler to get user selection
|
||||
* $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) {
|
||||
* // close colorbox
|
||||
* $.colorbox.close();
|
||||
* // replace textxarea text with bbcode
|
||||
* $(id).value = bbcode;
|
||||
* });
|
||||
**/
|
||||
|
||||
var FileBrowser = {
|
||||
nickname : "",
|
||||
type : "",
|
||||
event: "",
|
||||
id : null,
|
||||
|
||||
init: function(nickname, type) {
|
||||
FileBrowser.nickname = nickname;
|
||||
FileBrowser.type = type;
|
||||
FileBrowser.event = "fbrowser."+type;
|
||||
if (location['hash']!=="") {
|
||||
var h = location['hash'].replace("#","");
|
||||
FileBrowser.event = FileBrowser.event + "." + h.split("-")[0];
|
||||
FileBrowser.id = h.split("-")[1];
|
||||
}
|
||||
|
||||
console.log("FileBrowser:", nickname, type,FileBrowser.event, FileBrowser.id );
|
||||
|
||||
$(".error a.close").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
$(".error").addClass("hidden");
|
||||
});
|
||||
|
||||
$(".folders a, .path a").on("click", function(e){
|
||||
e.preventDefault();
|
||||
location.href = baseurl + "/fbrowser/" + FileBrowser.type + "/" + encodeURIComponent(this.dataset.folder) + "?mode=minimal" + location['hash'];
|
||||
});
|
||||
|
||||
$(".photo-album-photo-link").on('click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var embed = "";
|
||||
if (FileBrowser.type == "image") {
|
||||
embed = "[url="+this.dataset.link+"][img="+this.dataset.img+"]"+this.dataset.alt+"[/img][/url]";
|
||||
}
|
||||
if (FileBrowser.type=="file") {
|
||||
// attachment links are "baseurl/attach/id"; we need id
|
||||
embed = "[attachment]"+this.dataset.link.split("/").pop()+"[/attachment]";
|
||||
}
|
||||
console.log(FileBrowser.event, this.dataset.filename, embed, FileBrowser.id);
|
||||
parent.$("body").trigger(FileBrowser.event, [
|
||||
this.dataset.filename,
|
||||
embed,
|
||||
FileBrowser.id
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
if ($("#upload-image").length)
|
||||
var image_uploader = new window.AjaxUpload(
|
||||
'upload-image',
|
||||
{ action: 'profile/' + FileBrowser.nickname + '/photos/upload?response=json',
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); },
|
||||
onComplete: function(file,response) {
|
||||
if (response['error']!= undefined) {
|
||||
$(".error span").html(response['error']);
|
||||
$(".error").removeClass('hidden');
|
||||
$('#profile-rotator').hide();
|
||||
return;
|
||||
}
|
||||
location = baseurl + "/fbrowser/image/?mode=minimal"+location['hash'];
|
||||
location.reload(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if ($("#upload-file").length)
|
||||
var file_uploader = new window.AjaxUpload(
|
||||
'upload-file',
|
||||
{ action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json',
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); },
|
||||
onComplete: function(file,response) {
|
||||
if (response['error']!= undefined) {
|
||||
$(".error span").html(response['error']);
|
||||
$(".error").removeClass('hidden');
|
||||
$('#profile-rotator').hide();
|
||||
return;
|
||||
}
|
||||
location = baseurl + "/fbrowser/file/?mode=minimal"+location['hash'];
|
||||
location.reload(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
// @license-end
|
|
@ -166,7 +166,7 @@ $(function() {
|
|||
|
||||
/* event from comment textarea button popups */
|
||||
/* insert returned bbcode at cursor position or replace selected text */
|
||||
$("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) {
|
||||
$('body').on('fbrowser.photo.comment', function(e, filename, bbcode, id) {
|
||||
$.colorbox.close();
|
||||
var textarea = document.getElementById("comment-edit-text-" +id);
|
||||
var start = textarea.selectionStart;
|
||||
|
@ -1069,7 +1069,7 @@ var Dialog = {
|
|||
* to the event handler
|
||||
*/
|
||||
doImageBrowser : function (name, id) {
|
||||
var url = Dialog._get_url("image",name,id);
|
||||
var url = Dialog._get_url('photo', name, id);
|
||||
return Dialog.show(url);
|
||||
},
|
||||
|
||||
|
@ -1086,7 +1086,7 @@ var Dialog = {
|
|||
* to the event handler
|
||||
*/
|
||||
doFileBrowser : function (name, id) {
|
||||
var url = Dialog._get_url("file",name,id);
|
||||
var url = Dialog._get_url('attachment', name, id);
|
||||
return Dialog.show(url);
|
||||
},
|
||||
|
||||
|
@ -1095,7 +1095,7 @@ var Dialog = {
|
|||
if (id !== undefined) {
|
||||
hash = hash + "-" + id;
|
||||
}
|
||||
return baseurl + "/fbrowser/"+type+"/?mode=minimal#"+hash;
|
||||
return 'media/' + type + '/browser?mode=minimal#' + hash;
|
||||
},
|
||||
|
||||
_get_size: function() {
|
||||
|
|
156
view/js/module/media/browser.js
Normal file
156
view/js/module/media/browser.js
Normal file
|
@ -0,0 +1,156 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
|
||||
/**
|
||||
* Filebrowser - Friendica Communications Server
|
||||
*
|
||||
* Copyright (c) 2010-2021, the Friendica project
|
||||
*
|
||||
* 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 code handle user interaction for image/file upload/browser dialog.
|
||||
* Is loaded from filebrowser_plain.tpl
|
||||
*
|
||||
* To load filebrowser in colorbox, call
|
||||
*
|
||||
* Dialog.doImageBrowser(eventname, id);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* Dialog.doFileBrowser(eventname, id);
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* eventname: event name to catch return value
|
||||
* id: id returned to event handler
|
||||
*
|
||||
* When user select an item, an event in fired in parent page, on body element
|
||||
* The event is named
|
||||
*
|
||||
* fbrowser.<type>.[<eventname>]
|
||||
*
|
||||
* <type> will be one of "image" or "file", and the event handler will
|
||||
* get the following params:
|
||||
*
|
||||
* filename: filename of item chosen by user
|
||||
* embed: bbcode to embed element into posts
|
||||
* id: id from caller code
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // open dialog for select an image for a textarea with id "myeditor"
|
||||
* var id="myeditor";
|
||||
* Dialog.doImageBrowser("example", id);
|
||||
*
|
||||
* // setup event handler to get user selection
|
||||
* $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) {
|
||||
* // close colorbox
|
||||
* $.colorbox.close();
|
||||
* // replace textarea text with bbcode
|
||||
* $(id).value = bbcode;
|
||||
* });
|
||||
**/
|
||||
const Browser = {
|
||||
nickname: '',
|
||||
type: '',
|
||||
event: '',
|
||||
id: null,
|
||||
|
||||
init: function (nickname, type) {
|
||||
Browser.nickname = nickname;
|
||||
Browser.type = type;
|
||||
Browser.event = 'fbrowser.' + type;
|
||||
if (location['hash'] !== '') {
|
||||
const h = location['hash'].replace('#', '');
|
||||
Browser.event = Browser.event + '.' + h.split('-')[0];
|
||||
Browser.id = h.split('-')[1];
|
||||
}
|
||||
|
||||
$('.error a.close').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('.error').addClass('hidden');
|
||||
});
|
||||
|
||||
$('.folders a, .path a').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
location.href = Browser._getUrl("minimal", location['hash'], this.dataset.folder);
|
||||
location.reload();
|
||||
});
|
||||
|
||||
$(".photo-album-photo-link").on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let embed = '';
|
||||
if (Browser.type === "photo") {
|
||||
embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]';
|
||||
}
|
||||
if (Browser.type === "attachment") {
|
||||
embed = '[attachment]' + this.dataset.link + '[/attachment]';
|
||||
}
|
||||
parent.$('body').trigger(Browser.event, [
|
||||
this.dataset.filename,
|
||||
embed,
|
||||
Browser.id
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
if ($('#upload-photo').length) {
|
||||
new window.AjaxUpload(
|
||||
'upload-photo',
|
||||
{
|
||||
action: 'media/photo/upload?response=json',
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function (file, ext) {
|
||||
$('#profile-rotator').show();
|
||||
$('.error').addClass('hidden');
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response['error'] !== undefined) {
|
||||
$('.error span').html(response['error']);
|
||||
$('.error').removeClass('hidden');
|
||||
$('#profile-rotator').hide();
|
||||
return;
|
||||
}
|
||||
location.href = Browser._getUrl("minimal", location['hash']);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ($('#upload-attachment').length) {
|
||||
new window.AjaxUpload(
|
||||
'upload-attachment',
|
||||
{
|
||||
action: 'media/attachment/upload?response=json',
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function (file, ext) {
|
||||
$('#profile-rotator').show();
|
||||
$('.error').addClass('hidden');
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response['error'] !== undefined) {
|
||||
$('.error span').html(response['error']);
|
||||
$('.error').removeClass('hidden');
|
||||
$('#profile-rotator').hide();
|
||||
return;
|
||||
}
|
||||
location.href = Browser._getUrl("minimal", location['hash']);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_getUrl: function (mode, hash, folder) {
|
||||
let folderValue = folder !== undefined ? folder : Browser.folder;
|
||||
let folderUrl = folderValue !== undefined ? '/' + encodeURIComponent(folderValue) : '';
|
||||
return 'media/' + Browser.type + '/browser' + folderUrl + '?mode=' + mode + hash;
|
||||
}
|
||||
};
|
||||
// @license-end
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 2022.12-dev\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-11-23 18:16+0100\n"
|
||||
"POT-Creation-Date: 2022-11-27 00:36+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -18,36 +18,13 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
#: mod/fbrowser.php:61 src/Content/Nav.php:195 src/Module/BaseProfile.php:64
|
||||
#: view/theme/frio/theme.php:242
|
||||
msgid "Photos"
|
||||
msgstr ""
|
||||
|
||||
#: mod/fbrowser.php:119 mod/fbrowser.php:146 mod/photos.php:997
|
||||
#: mod/photos.php:1098 src/Content/Conversation.php:389
|
||||
#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109
|
||||
#: src/Module/Contact/Unfollow.php:126 src/Module/Post/Edit.php:164
|
||||
#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134
|
||||
#: src/Module/Security/TwoFactor/SignOut.php:125
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: mod/fbrowser.php:121 mod/fbrowser.php:148
|
||||
#: src/Module/Settings/Profile/Photo/Index.php:128
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
#: mod/fbrowser.php:143
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:129 mod/item.php:133
|
||||
msgid "Unable to locate original post."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:179 mod/item.php:184 mod/item.php:853 mod/message.php:69
|
||||
#: mod/item.php:179 mod/item.php:184 mod/item.php:855 mod/message.php:69
|
||||
#: mod/message.php:114 mod/notes.php:44 mod/photos.php:159 mod/photos.php:884
|
||||
#: src/Module/Attach.php:56 src/Module/BaseApi.php:94
|
||||
#: src/Module/Attach.php:55 src/Module/BaseApi.php:94
|
||||
#: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52
|
||||
#: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84
|
||||
#: src/Module/Calendar/Event/Show.php:54 src/Module/Calendar/Export.php:62
|
||||
|
@ -62,9 +39,8 @@ msgstr ""
|
|||
#: src/Module/Notifications/Notification.php:76
|
||||
#: src/Module/Notifications/Notification.php:107
|
||||
#: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66
|
||||
#: src/Module/Post/Edit.php:76 src/Module/Profile/Attachment/Upload.php:97
|
||||
#: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55
|
||||
#: src/Module/Profile/Photos/Upload.php:108 src/Module/Profile/Schedule.php:39
|
||||
#: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:55
|
||||
#: src/Module/Profile/Contacts.php:55 src/Module/Profile/Schedule.php:39
|
||||
#: src/Module/Profile/Schedule.php:56 src/Module/Profile/UnkMail.php:69
|
||||
#: src/Module/Profile/UnkMail.php:121 src/Module/Profile/UnkMail.php:132
|
||||
#: src/Module/Register.php:77 src/Module/Register.php:90
|
||||
|
@ -84,23 +60,23 @@ msgstr ""
|
|||
msgid "Permission denied."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:328 mod/item.php:333
|
||||
#: mod/item.php:330 mod/item.php:335
|
||||
msgid "Empty post discarded."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:671
|
||||
#: mod/item.php:673
|
||||
msgid "Post updated."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:681 mod/item.php:686
|
||||
#: mod/item.php:683 mod/item.php:688
|
||||
msgid "Item wasn't stored."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:697
|
||||
#: mod/item.php:699
|
||||
msgid "Item couldn't be fetched."
|
||||
msgstr ""
|
||||
|
||||
#: mod/item.php:829 src/Module/Admin/Themes/Details.php:39
|
||||
#: mod/item.php:831 src/Module/Admin/Themes/Details.php:39
|
||||
#: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:42
|
||||
#: src/Module/Debug/ItemBody.php:57 src/Module/Item/Feed.php:80
|
||||
msgid "Item not found."
|
||||
|
@ -414,31 +390,28 @@ msgstr ""
|
|||
#: src/Module/HCard.php:51 src/Module/Profile/Common.php:40
|
||||
#: src/Module/Profile/Common.php:51 src/Module/Profile/Contacts.php:39
|
||||
#: src/Module/Profile/Contacts.php:49 src/Module/Profile/Media.php:38
|
||||
#: src/Module/Profile/Photos/Index.php:77
|
||||
#: src/Module/Profile/Photos/Upload.php:87
|
||||
#: src/Module/Profile/RemoteFollow.php:71 src/Module/Profile/Status.php:58
|
||||
#: src/Module/Register.php:267
|
||||
#: src/Module/Profile/Photos.php:77 src/Module/Profile/RemoteFollow.php:71
|
||||
#: src/Module/Profile/Status.php:58 src/Module/Register.php:267
|
||||
msgid "User not found."
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:107 src/Module/BaseProfile.php:67
|
||||
#: src/Module/Profile/Photos/Index.php:169
|
||||
#: src/Module/Profile/Photos.php:169
|
||||
msgid "Photo Albums"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:108 src/Module/Profile/Photos/Index.php:170
|
||||
#: src/Module/Profile/Photos/Index.php:187
|
||||
#: mod/photos.php:108 src/Module/Profile/Photos.php:170
|
||||
#: src/Module/Profile/Photos.php:187
|
||||
msgid "Recent Photos"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:110 mod/photos.php:1066
|
||||
#: src/Module/Profile/Photos/Index.php:172
|
||||
#: src/Module/Profile/Photos/Index.php:189
|
||||
#: mod/photos.php:110 mod/photos.php:1066 src/Module/Profile/Photos.php:172
|
||||
#: src/Module/Profile/Photos.php:189
|
||||
msgid "Upload New Photos"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:128 src/Module/BaseSettings.php:74
|
||||
#: src/Module/Profile/Photos/Index.php:153
|
||||
#: src/Module/Profile/Photos.php:153
|
||||
msgid "everybody"
|
||||
msgstr ""
|
||||
|
||||
|
@ -472,7 +445,7 @@ msgid "%1$s was tagged in %2$s by %3$s"
|
|||
msgstr ""
|
||||
|
||||
#: mod/photos.php:630 mod/photos.php:633 mod/photos.php:660
|
||||
#: src/Module/Profile/Photos/Upload.php:213
|
||||
#: src/Module/Media/Photo/Upload.php:188
|
||||
#: src/Module/Settings/Profile/Photo/Index.php:59
|
||||
#, php-format
|
||||
msgid "Image exceeds size limit of %s"
|
||||
|
@ -496,19 +469,19 @@ msgstr ""
|
|||
msgid "Image file is empty."
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:683 src/Module/Profile/Photos/Upload.php:179
|
||||
#: src/Module/Profile/Photos/Upload.php:180
|
||||
#: mod/photos.php:683 src/Module/Media/Photo/Upload.php:154
|
||||
#: src/Module/Media/Photo/Upload.php:155
|
||||
#: src/Module/Settings/Profile/Photo/Index.php:68
|
||||
msgid "Unable to process image."
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:709 src/Module/Profile/Photos/Upload.php:231
|
||||
#: mod/photos.php:709 src/Module/Media/Photo/Upload.php:206
|
||||
#: src/Module/Settings/Profile/Photo/Index.php:95
|
||||
msgid "Image upload failed."
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:795 src/Module/Conversation/Community.php:187
|
||||
#: src/Module/Directory.php:48 src/Module/Profile/Photos/Index.php:72
|
||||
#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:72
|
||||
#: src/Module/Search/Index.php:64
|
||||
msgid "Public access denied."
|
||||
msgstr ""
|
||||
|
@ -517,7 +490,7 @@ msgstr ""
|
|||
msgid "No photos selected"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:869 src/Module/Profile/Photos/Index.php:92
|
||||
#: mod/photos.php:869 src/Module/Profile/Photos.php:92
|
||||
msgid "Access to this item is restricted."
|
||||
msgstr ""
|
||||
|
||||
|
@ -550,6 +523,16 @@ msgstr ""
|
|||
msgid "Delete Album"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:997 mod/photos.php:1098 src/Content/Conversation.php:389
|
||||
#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109
|
||||
#: src/Module/Contact/Unfollow.php:126
|
||||
#: src/Module/Media/Attachment/Browser.php:78
|
||||
#: src/Module/Media/Photo/Browser.php:88 src/Module/Post/Edit.php:164
|
||||
#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134
|
||||
#: src/Module/Security/TwoFactor/SignOut.php:125
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:1023
|
||||
msgid "Edit Album"
|
||||
msgstr ""
|
||||
|
@ -566,7 +549,7 @@ msgstr ""
|
|||
msgid "Show Oldest First"
|
||||
msgstr ""
|
||||
|
||||
#: mod/photos.php:1051 src/Module/Profile/Photos/Index.php:140
|
||||
#: mod/photos.php:1051 src/Module/Profile/Photos.php:140
|
||||
msgid "View Photo"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1686,6 +1669,11 @@ msgstr ""
|
|||
msgid "Your profile page"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Nav.php:195 src/Module/BaseProfile.php:64
|
||||
#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:242
|
||||
msgid "Photos"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Nav.php:195 view/theme/frio/theme.php:242
|
||||
msgid "Your photos"
|
||||
msgstr ""
|
||||
|
@ -3180,7 +3168,7 @@ msgstr ""
|
|||
msgid "[no subject]"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/Photo.php:1086 src/Module/Profile/Photos/Upload.php:223
|
||||
#: src/Model/Photo.php:1139 src/Module/Media/Photo/Upload.php:198
|
||||
msgid "Wall Photos"
|
||||
msgstr ""
|
||||
|
||||
|
@ -5265,7 +5253,7 @@ msgstr ""
|
|||
msgid "Applications"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Attach.php:50 src/Module/Attach.php:62
|
||||
#: src/Module/Attach.php:49 src/Module/Attach.php:61
|
||||
msgid "Item was not found."
|
||||
msgstr ""
|
||||
|
||||
|
@ -5894,10 +5882,10 @@ msgid "The contact could not be added."
|
|||
msgstr ""
|
||||
|
||||
#: src/Module/Contact/MatchInterests.php:94
|
||||
#: src/Module/Profile/Attachment/Upload.php:80
|
||||
#: src/Module/Profile/Attachment/Upload.php:102
|
||||
#: src/Module/Profile/Photos/Upload.php:113
|
||||
#: src/Module/Profile/Photos/Upload.php:162
|
||||
#: src/Module/Media/Attachment/Upload.php:80
|
||||
#: src/Module/Media/Attachment/Upload.php:85
|
||||
#: src/Module/Media/Photo/Upload.php:83 src/Module/Media/Photo/Upload.php:88
|
||||
#: src/Module/Media/Photo/Upload.php:137
|
||||
msgid "Invalid request."
|
||||
msgstr ""
|
||||
|
||||
|
@ -7129,6 +7117,38 @@ msgstr ""
|
|||
msgid "A Decentralized Social Network"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Browser.php:58
|
||||
#: src/Module/Media/Photo/Browser.php:59
|
||||
msgid "You need to be logged in to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Browser.php:75
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Browser.php:80
|
||||
#: src/Module/Media/Photo/Browser.php:90
|
||||
#: src/Module/Settings/Profile/Photo/Index.php:128
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Upload.php:100
|
||||
msgid "Sorry, maybe your upload is bigger than the PHP configuration allows"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Upload.php:100
|
||||
msgid "Or - did you try to upload an empty file?"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Upload.php:107
|
||||
#, php-format
|
||||
msgid "File exceeds size limit of %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Media/Attachment/Upload.php:117
|
||||
msgid "File upload failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Moderation/BaseUsers.php:72
|
||||
msgid "List of all users"
|
||||
msgstr ""
|
||||
|
@ -8134,28 +8154,11 @@ msgstr ""
|
|||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Attachment/Upload.php:117
|
||||
msgid "Sorry, maybe your upload is bigger than the PHP configuration allows"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Attachment/Upload.php:117
|
||||
msgid "Or - did you try to upload an empty file?"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Attachment/Upload.php:124
|
||||
#, php-format
|
||||
msgid "File exceeds size limit of %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Attachment/Upload.php:134
|
||||
msgid "File upload failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Contacts.php:119
|
||||
msgid "No contacts."
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Profile/Photos/Index.php:146
|
||||
#: src/Module/Profile/Photos.php:146
|
||||
msgid "View Album"
|
||||
msgstr ""
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,10 +5,6 @@ function string_plural_select_de($n){
|
|||
$n = intval($n);
|
||||
return intval($n != 1);
|
||||
}}
|
||||
$a->strings['Photos'] = 'Bilder';
|
||||
$a->strings['Cancel'] = 'Abbrechen';
|
||||
$a->strings['Upload'] = 'Hochladen';
|
||||
$a->strings['Files'] = 'Dateien';
|
||||
$a->strings['Unable to locate original post.'] = 'Konnte den Originalbeitrag nicht finden.';
|
||||
$a->strings['Permission denied.'] = 'Zugriff verweigert.';
|
||||
$a->strings['Empty post discarded.'] = 'Leerer Beitrag wurde verworfen.';
|
||||
|
@ -168,6 +164,7 @@ $a->strings['Do not show a status post for this upload'] = 'Keine Status-Mitteil
|
|||
$a->strings['Permissions'] = 'Berechtigungen';
|
||||
$a->strings['Do you really want to delete this photo album and all its photos?'] = 'Möchtest du wirklich dieses Foto-Album und all seine Foto löschen?';
|
||||
$a->strings['Delete Album'] = 'Album löschen';
|
||||
$a->strings['Cancel'] = 'Abbrechen';
|
||||
$a->strings['Edit Album'] = 'Album bearbeiten';
|
||||
$a->strings['Drop Album'] = 'Album löschen';
|
||||
$a->strings['Show Newest First'] = 'Zeige neueste zuerst';
|
||||
|
@ -203,7 +200,6 @@ $a->strings['I like this (toggle)'] = 'Ich mag das (toggle)';
|
|||
$a->strings['Dislike'] = 'Mag ich nicht';
|
||||
$a->strings['I don\'t like this (toggle)'] = 'Ich mag das nicht (toggle)';
|
||||
$a->strings['Map'] = 'Karte';
|
||||
$a->strings['View Album'] = 'Album betrachten';
|
||||
$a->strings['No system theme config value set.'] = 'Es wurde kein Konfigurationswert für das systemweite Theme gesetzt.';
|
||||
$a->strings['Apologies but the website is unavailable at the moment.'] = 'Entschuldigung, aber die Webseite ist derzeit nicht erreichbar.';
|
||||
$a->strings['Delete this item?'] = 'Diesen Beitrag löschen?';
|
||||
|
@ -420,6 +416,7 @@ $a->strings['Status'] = 'Status';
|
|||
$a->strings['Your posts and conversations'] = 'Deine Beiträge und Unterhaltungen';
|
||||
$a->strings['Profile'] = 'Profil';
|
||||
$a->strings['Your profile page'] = 'Deine Profilseite';
|
||||
$a->strings['Photos'] = 'Bilder';
|
||||
$a->strings['Your photos'] = 'Deine Fotos';
|
||||
$a->strings['Media'] = 'Medien';
|
||||
$a->strings['Your postings with media'] = 'Deine Beiträge die Medien beinhalten';
|
||||
|
@ -1150,7 +1147,7 @@ $a->strings['Displays the menu entry for the Help pages from the navigation menu
|
|||
$a->strings['Single user instance'] = 'Ein-Nutzer Instanz';
|
||||
$a->strings['Make this instance multi-user or single-user for the named user'] = 'Bestimmt, ob es sich bei dieser Instanz um eine Installation mit nur einen Nutzer oder mit mehreren Nutzern handelt.';
|
||||
$a->strings['Maximum image size'] = 'Maximale Bildgröße';
|
||||
$a->strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits.'] = 'Maximale Uploadgröße von Bildern in Bytes. Standard ist 0, d.h. ohne Limit.';
|
||||
$a->strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits. Be aware that this setting does not affect server-side upload limits.'] = 'Maximal akzeptierte Dateigröße in Bytes eines hochzuladenden Bilds. Der Standard ist 0 und entspricht keiner Beschränkung der Dateigröße. Beachte, dass diese Einstellung nicht die serverseitigen Beschränkungen von Dateigrößen beeinflusst.';
|
||||
$a->strings['Maximum image length'] = 'Maximale Bildlänge';
|
||||
$a->strings['Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.'] = 'Maximale Länge in Pixeln der längsten Seite eines hochgeladenen Bildes. Grundeinstellung ist -1, was keine Einschränkung bedeutet.';
|
||||
$a->strings['JPEG image quality'] = 'Qualität des JPEG Bildes';
|
||||
|
@ -1527,7 +1524,6 @@ $a->strings['Fetch information'] = 'Beziehe Information';
|
|||
$a->strings['Fetch keywords'] = 'Schlüsselwörter abrufen';
|
||||
$a->strings['Fetch information and keywords'] = 'Beziehe Information und Schlüsselworte';
|
||||
$a->strings['No mirroring'] = 'Kein Spiegeln';
|
||||
$a->strings['Mirror as forwarded posting'] = 'Spiegeln als weitergeleitete Beiträge';
|
||||
$a->strings['Mirror as my own posting'] = 'Spiegeln als meine eigenen Beiträge';
|
||||
$a->strings['Native reshare'] = 'Natives Teilen';
|
||||
$a->strings['Contact Information / Notes'] = 'Kontakt-Informationen / -Notizen';
|
||||
|
@ -1781,11 +1777,32 @@ $a->strings['Location services are unavailable on your device'] = 'Ortungsdienst
|
|||
$a->strings['Location services are disabled. Please check the website\'s permissions on your device'] = 'Ortungsdienste sind deaktiviert. Bitte überprüfe die Berechtigungen der Website auf deinem Gerät';
|
||||
$a->strings['You can make this page always open when you use the New Post button in the <a href="/settings/display">Theme Customization settings</a>.'] = 'Wenn du magst, kannst du unter den <a href="/settings/display">Benutzerdefinierte Theme-Einstellungen</a> einstellen, dass diese Seite immer geöffnet wird, wenn du den "Neuer Beitrag" Button verwendest.';
|
||||
$a->strings['The requested item doesn\'t exist or has been deleted.'] = 'Der angeforderte Beitrag existiert nicht oder wurde gelöscht.';
|
||||
$a->strings['Unfortunately, the requested conversation isn\'t available to you.</p>
|
||||
<p>Possible reasons include:</p>
|
||||
<ul>
|
||||
<li>The top-level post isn\'t visible.</li>
|
||||
<li>The top-level post was deleted.</li>
|
||||
<li>The node has blocked the top-level author or the author of the shared post.</li>
|
||||
<li>You have ignored or blocked the top-level author or the author of the shared post.</li>
|
||||
</ul><p>'] = 'Leider ist die angeforderte Konversation nicht verfügbar für dich.</p>
|
||||
<p>Mögliche Gründe können sein:</p>
|
||||
<li> Der übergeordnete Beitrag ist nicht sichtbar.</li>
|
||||
<li>Der übergeordnete Beitrag wurde gelöscht</li>
|
||||
<li>Die Instanz hat den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt.</li>
|
||||
<li>Du hast den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt oder ignorierst ihn.</li>
|
||||
<ul><p>';
|
||||
$a->strings['The feed for this item is unavailable.'] = 'Der Feed für diesen Beitrag ist nicht verfügbar.';
|
||||
$a->strings['Unable to follow this item.'] = 'Konnte dem Beitrag nicht folgen.';
|
||||
$a->strings['System down for maintenance'] = 'System zur Wartung abgeschaltet';
|
||||
$a->strings['This Friendica node is currently in maintenance mode, either automatically because it is self-updating or manually by the node administrator. This condition should be temporary, please come back in a few minutes.'] = 'Diese Friendica Instanz befindet sich derzeit im Wartungsmodus, entweder aufgrund von automatischen Updateprozessen oder weil die Administratoren der Instanz den Wartungsmodus aktiviert haben. Dies sollte ein vorübergehender Zustand sein. Bitte versuche es in ein paar Minuten erneut.';
|
||||
$a->strings['A Decentralized Social Network'] = 'Ein dezentrales Soziales Netzwerk';
|
||||
$a->strings['You need to be logged in to access this page.'] = 'Du musst angemeldet sein, um auf diese Seite zuzugreifen. ';
|
||||
$a->strings['Files'] = 'Dateien';
|
||||
$a->strings['Upload'] = 'Hochladen';
|
||||
$a->strings['Sorry, maybe your upload is bigger than the PHP configuration allows'] = 'Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt.';
|
||||
$a->strings['Or - did you try to upload an empty file?'] = 'Oder - hast du versucht, eine leere Datei hochzuladen?';
|
||||
$a->strings['File exceeds size limit of %s'] = 'Die Datei ist größer als das erlaubte Limit von %s';
|
||||
$a->strings['File upload failed.'] = 'Hochladen der Datei fehlgeschlagen.';
|
||||
$a->strings['List of all users'] = 'Liste aller Benutzerkonten';
|
||||
$a->strings['Active'] = 'Aktive';
|
||||
$a->strings['List of active accounts'] = 'Liste der aktiven Benutzerkonten';
|
||||
|
@ -2041,11 +2058,8 @@ $a->strings['audio link'] = 'Audio-Link';
|
|||
$a->strings['Remove Item Tag'] = 'Gegenstands-Tag entfernen';
|
||||
$a->strings['Select a tag to remove: '] = 'Wähle ein Tag zum Entfernen aus: ';
|
||||
$a->strings['Remove'] = 'Entfernen';
|
||||
$a->strings['Sorry, maybe your upload is bigger than the PHP configuration allows'] = 'Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt.';
|
||||
$a->strings['Or - did you try to upload an empty file?'] = 'Oder - hast du versucht, eine leere Datei hochzuladen?';
|
||||
$a->strings['File exceeds size limit of %s'] = 'Die Datei ist größer als das erlaubte Limit von %s';
|
||||
$a->strings['File upload failed.'] = 'Hochladen der Datei fehlgeschlagen.';
|
||||
$a->strings['No contacts.'] = 'Keine Kontakte.';
|
||||
$a->strings['View Album'] = 'Album betrachten';
|
||||
$a->strings['Profile not found.'] = 'Profil nicht gefunden.';
|
||||
$a->strings['You\'re currently viewing your profile as <b>%s</b> <a href="%s" class="btn btn-sm pull-right">Cancel</a>'] = 'Du betrachtest dein Profil gerade als <b>%s</b> <a href="%s" class="btn btn-sm pull-right">Abbrechen</a>';
|
||||
$a->strings['Full Name:'] = 'Kompletter Name:';
|
||||
|
@ -2121,6 +2135,7 @@ Du kannst das Passwort nach dem Anmelden ändern.';
|
|||
$a->strings['Registration successful.'] = 'Registrierung erfolgreich.';
|
||||
$a->strings['Your registration can not be processed.'] = 'Deine Registrierung konnte nicht verarbeitet werden.';
|
||||
$a->strings['You have to leave a request note for the admin.'] = 'Du musst eine Nachricht für den Administrator als Begründung deiner Anfrage hinterlegen.';
|
||||
$a->strings['An internal error occured.'] = 'Ein interner Fehler ist aufgetreten. ';
|
||||
$a->strings['Your registration is pending approval by the site owner.'] = 'Deine Registrierung muss noch vom Betreiber der Seite freigegeben werden.';
|
||||
$a->strings['You must be logged in to use this module.'] = 'Du musst eingeloggt sein, um dieses Modul benutzen zu können.';
|
||||
$a->strings['Only logged in users are permitted to perform a search.'] = 'Nur eingeloggten Benutzern ist das Suchen gestattet.';
|
||||
|
|
|
@ -61,11 +61,11 @@ function enableOnUser(){
|
|||
**/
|
||||
|
||||
/* callback */
|
||||
$('body').on('fbrowser.image.main', function(e, filename, embedcode, id) {
|
||||
$('body').on('fbrowser.photo.main', function(e, filename, embedcode, id) {
|
||||
$.colorbox.close();
|
||||
addeditortext(embedcode);
|
||||
});
|
||||
$('body').on('fbrowser.file.main', function(e, filename, embedcode, id) {
|
||||
$('body').on('fbrowser.attachment.main', function(e, filename, embedcode, id) {
|
||||
$.colorbox.close();
|
||||
addeditortext(embedcode);
|
||||
});
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<!--
|
||||
This is the template used by mod/fbrowser.php
|
||||
-->
|
||||
<script type="text/javascript" src="{{$baseurl}}/view/js/ajaxupload.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||
<script type="text/javascript" src="{{$baseurl}}/view/js/filebrowser.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||
<script type="text/javascript" src="view/js/ajaxupload.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||
<script type="text/javascript" src="view/js/module/media/browser.js?v={{$smarty.const.FRIENDICA_VERSION}}"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
FileBrowser.init("{{$nickname}}", "{{$type}}");
|
||||
Browser.init("{{$nickname}}", "{{$type}}");
|
||||
});
|
||||
</script>
|
||||
<div class="fbrowser {{$type}}">
|
||||
|
@ -33,7 +33,7 @@
|
|||
{{foreach $files as $f}}
|
||||
<div class="photo-album-image-wrapper">
|
||||
<a href="#" class="photo-album-photo-link" data-link="{{$f.0}}" data-filename="{{$f.1}}" data-img="{{$f.2}}" data-alt="{{$f.3}}">
|
||||
<img src="{{$f.2}}">
|
||||
<img alt="{{$f.3}}" src="{{$f.1}}">
|
||||
<p>{{$f.1}}</p>
|
||||
</a>
|
||||
</div>
|
|
@ -1563,10 +1563,10 @@ textarea.comment-edit-text:focus + .comment-edit-form .preview {
|
|||
max-height: calc(100vh - 220px);
|
||||
}
|
||||
}
|
||||
.fbrowser.image .photo-album-image-wrapper {
|
||||
.fbrowser.photo .photo-album-image-wrapper {
|
||||
box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.fbrowser.image .photo-album-image-wrapper .caption {
|
||||
.fbrowser.photo .photo-album-image-wrapper .caption {
|
||||
pointer-events: none;
|
||||
}
|
||||
.fbrowser .profile-rotator-wrapper {
|
||||
|
@ -3605,6 +3605,11 @@ section .profile-match-wrapper {
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
.generic-page-wrapper.contact-follow-wrapper {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
/* Medium devices (desktops, 992px and up) */
|
||||
@media (min-width: 992px) {
|
||||
.mod-home.is-not-singleuser #content,
|
||||
|
|
|
@ -1,264 +0,0 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
|
||||
/**
|
||||
* Filebrowser - Friendica Communications Server
|
||||
*
|
||||
* Copyright (c) 2010-2021, the Friendica project
|
||||
*
|
||||
* 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 code handle user interaction for image/file upload/browser dialog.
|
||||
* Is loaded from filebrowser_plain.tpl
|
||||
*
|
||||
* To load filebrowser in colorbox, call
|
||||
*
|
||||
* Dialog.doImageBrowser(eventname, id);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* Dialog.doFileBrowser(eventname, id);
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* eventname: event name to catch return value
|
||||
* id: id returned to event handler
|
||||
*
|
||||
* When user select an item, an event in fired in parent page, on body element
|
||||
* The event is named
|
||||
*
|
||||
* fbrowser.<type>.[<eventname>]
|
||||
*
|
||||
* <type> will be one of "image" or "file", and the event handler will
|
||||
* get the following params:
|
||||
*
|
||||
* filemane: filename of item choosed by user
|
||||
* embed: bbcode to embed element into posts
|
||||
* id: id from caller code
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // open dialog for select an image for a textarea with id "myeditor"
|
||||
* var id="myeditor";
|
||||
* Dialog.doImageBrowser("example", id);
|
||||
*
|
||||
* // setup event handler to get user selection
|
||||
* $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) {
|
||||
* // close colorbox
|
||||
* $.colorbox.close();
|
||||
* // replace textxarea text with bbcode
|
||||
* $(id).value = bbcode;
|
||||
* });
|
||||
**/
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
*
|
||||
* This is a modified version to work with
|
||||
* the frio theme.and bootstrap modals
|
||||
*
|
||||
* The origninal file is under:
|
||||
* js/filebrowser.js
|
||||
*
|
||||
*/
|
||||
|
||||
var FileBrowser = {
|
||||
nickname: "",
|
||||
type: "",
|
||||
event: "",
|
||||
folder: "",
|
||||
id: null,
|
||||
|
||||
init: function (nickname, type, hash) {
|
||||
FileBrowser.nickname = nickname;
|
||||
FileBrowser.type = type;
|
||||
FileBrowser.event = "fbrowser." + type;
|
||||
|
||||
if (hash !== "") {
|
||||
var h = hash.replace("#", "");
|
||||
var destination = h.split("-")[0];
|
||||
FileBrowser.id = h.split("-")[1];
|
||||
FileBrowser.event = FileBrowser.event + "." + destination;
|
||||
if (destination === "comment") {
|
||||
// Get the comment textimput field
|
||||
var commentElm = document.getElementById("comment-edit-text-" + FileBrowser.id);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("FileBrowser: " + nickname, type, FileBrowser.event, FileBrowser.id);
|
||||
|
||||
FileBrowser.postLoad();
|
||||
|
||||
$(".error .close").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
$(".error").addClass("hidden");
|
||||
});
|
||||
|
||||
// Click on album link
|
||||
$(".fbrowser").on("click", ".folders button, .path button", function (e) {
|
||||
e.preventDefault();
|
||||
var url =
|
||||
baseurl +
|
||||
"/fbrowser/" +
|
||||
FileBrowser.type +
|
||||
"/" +
|
||||
encodeURIComponent(this.dataset.folder) +
|
||||
"?mode=none&theme=frio";
|
||||
FileBrowser.folder = this.dataset.folder;
|
||||
|
||||
FileBrowser.loadContent(url);
|
||||
});
|
||||
|
||||
//Embed on click
|
||||
$(".fbrowser").on("click", ".photo-album-photo-link", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var embed = "";
|
||||
if (FileBrowser.type === "image") {
|
||||
embed = "[url=" + this.dataset.link + "][img=" + this.dataset.img + "]" + this.dataset.alt + "[/img][/url]";
|
||||
}
|
||||
if (FileBrowser.type === "file") {
|
||||
// attachment links are "baseurl/attach/id"; we need id
|
||||
embed = "[attachment]" + this.dataset.link.split("/").pop() + "[/attachment]";
|
||||
}
|
||||
|
||||
// Delete prefilled Text of the comment input
|
||||
// Note: not the best solution but function commentOpenUI don't
|
||||
// work as expected (we need a way to wait until commentOpenUI would be finished).
|
||||
// As for now we insert pieces of this function here
|
||||
if (commentElm !== null && typeof commentElm !== "undefined") {
|
||||
if (commentElm.value === "") {
|
||||
$("#comment-edit-text-" + FileBrowser.id)
|
||||
.addClass("comment-edit-text-full")
|
||||
.removeClass("comment-edit-text-empty");
|
||||
$("#comment-edit-submit-wrapper-" + FileBrowser.id).show();
|
||||
$("#comment-edit-text-" + FileBrowser.id).attr("tabindex", "9");
|
||||
$("#comment-edit-submit-" + FileBrowser.id).attr("tabindex", "10");
|
||||
}
|
||||
}
|
||||
|
||||
console.log(FileBrowser.event, this.dataset.filename, embed, FileBrowser.id);
|
||||
|
||||
$("body").trigger(FileBrowser.event, [this.dataset.filename, embed, FileBrowser.id, this.dataset.img]);
|
||||
|
||||
// Close model
|
||||
$("#modal").modal("hide");
|
||||
// Update autosize for this textarea
|
||||
autosize.update($(".text-autosize"));
|
||||
});
|
||||
|
||||
// EventListener for switching between image and file mode
|
||||
$(".fbrowser").on("click", ".fbswitcher .btn", function (e) {
|
||||
e.preventDefault();
|
||||
FileBrowser.type = this.getAttribute("data-mode");
|
||||
$(".fbrowser")
|
||||
.removeClass()
|
||||
.addClass("fbrowser " + FileBrowser.type);
|
||||
url = baseurl + "/fbrowser/" + FileBrowser.type + "?mode=none&theme=frio";
|
||||
|
||||
FileBrowser.loadContent(url);
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize the AjaxUpload for the upload buttons
|
||||
uploadButtons: function () {
|
||||
if ($("#upload-image").length) {
|
||||
//AjaxUpload for images
|
||||
var image_uploader = new window.AjaxUpload("upload-image", {
|
||||
action:
|
||||
"profile/" +
|
||||
FileBrowser.nickname +
|
||||
"/photos/upload?response=json&album=" +
|
||||
encodeURIComponent(FileBrowser.folder),
|
||||
name: "userfile",
|
||||
responseType: "json",
|
||||
onSubmit: function (file, ext) {
|
||||
$(".fbrowser-content").hide();
|
||||
$(".fbrowser .profile-rotator-wrapper").show();
|
||||
$(".error").addClass("hidden");
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response["error"] != undefined) {
|
||||
$(".error span").html(response["error"]);
|
||||
$(".error").removeClass("hidden");
|
||||
$(".fbrowser .profile-rotator-wrapper").hide();
|
||||
$(".fbrowser-content").show();
|
||||
return;
|
||||
}
|
||||
|
||||
// load new content to fbrowser window
|
||||
FileBrowser.loadContent(
|
||||
baseurl +
|
||||
"/fbrowser/" +
|
||||
FileBrowser.type +
|
||||
"/" +
|
||||
encodeURIComponent(FileBrowser.folder) +
|
||||
"?mode=none&theme=frio",
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if ($("#upload-file").length) {
|
||||
//AjaxUpload for files
|
||||
var file_uploader = new window.AjaxUpload("upload-file", {
|
||||
action: "profile/" + FileBrowser.nickname + "/attachment/upload?response=json",
|
||||
name: "userfile",
|
||||
responseType: "json",
|
||||
onSubmit: function (file, ext) {
|
||||
$(".fbrowser-content").hide();
|
||||
$(".fbrowser .profile-rotator-wrapper").show();
|
||||
$(".error").addClass("hidden");
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response["error"] != undefined) {
|
||||
$(".error span").html(response["error"]);
|
||||
$(".error").removeClass("hidden");
|
||||
$(".fbrowser .profile-rotator-wrapper").hide();
|
||||
$(".fbrowser-content").show();
|
||||
return;
|
||||
}
|
||||
|
||||
var url = baseurl + "/fbrowser/" + FileBrowser.type + "?mode=none&theme=frio";
|
||||
// Load new content to fbrowser window
|
||||
FileBrowser.loadContent(url);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Stuff which should be executed if ne content was loaded
|
||||
postLoad: function () {
|
||||
FileBrowser.initGallery();
|
||||
$(".fbrowser .fbswitcher .btn").removeClass("active");
|
||||
$(".fbrowser .fbswitcher [data-mode=" + FileBrowser.type + "]").addClass("active");
|
||||
// We need to add the AjaxUpload to the button
|
||||
FileBrowser.uploadButtons();
|
||||
},
|
||||
|
||||
// Load new content (e.g. change photo album)
|
||||
loadContent: function (url) {
|
||||
$(".fbrowser-content").hide();
|
||||
$(".fbrowser .profile-rotator-wrapper").show();
|
||||
|
||||
// load new content to fbrowser window
|
||||
$(".fbrowser").load(url, function (responseText, textStatus) {
|
||||
$(".profile-rotator-wrapper").hide();
|
||||
if (textStatus === "success") {
|
||||
$(".fbrowser_content").show();
|
||||
FileBrowser.postLoad();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize justified Gallery
|
||||
initGallery: function () {
|
||||
$(".fbrowser.image .fbrowser-content-container").justifiedGallery({
|
||||
rowHeight: 80,
|
||||
margins: 4,
|
||||
border: 0,
|
||||
});
|
||||
},
|
||||
};
|
||||
// @license-end
|
|
@ -82,7 +82,7 @@ $(document).ready(function () {
|
|||
});
|
||||
|
||||
// Insert filebrowser images into the input field (field_fileinput.tpl).
|
||||
$("body").on("fbrowser.image.input", function (e, filename, embedcode, id, img) {
|
||||
$("body").on("fbrowser.photo.input", function (e, filename, embedcode, id, img) {
|
||||
// Select the clicked button by it's attribute.
|
||||
var elm = $("[image-input='select']");
|
||||
// Select the input field which belongs to this button.
|
||||
|
@ -132,12 +132,12 @@ Dialog.show = function (url, title) {
|
|||
Dialog._get_url = function (type, name, id) {
|
||||
var hash = name;
|
||||
if (id !== undefined) hash = hash + "-" + id;
|
||||
return "fbrowser/" + type + "/?mode=none&theme=frio#" + hash;
|
||||
return 'media/' + type + '/browser?mode=none&theme=frio#' + hash;
|
||||
};
|
||||
|
||||
// Does load the filebrowser into the jot modal.
|
||||
Dialog.showJot = function () {
|
||||
var type = "image";
|
||||
var type = "photo";
|
||||
var name = "main";
|
||||
|
||||
var url = Dialog._get_url(type, name);
|
||||
|
@ -159,15 +159,15 @@ Dialog._load = function (url) {
|
|||
let filebrowser = document.getElementById("filebrowser");
|
||||
|
||||
// Try to fetch the hash form the url.
|
||||
let match = url.match(/fbrowser\/[a-z]+\/.*(#.*)/);
|
||||
let match = url.match(/media\/[a-z]+\/.*(#.*)/);
|
||||
if (!filebrowser || match === null) {
|
||||
return; //not fbrowser
|
||||
}
|
||||
|
||||
// Initialize the filebrowser.
|
||||
loadScript("view/js/ajaxupload.js");
|
||||
loadScript("view/theme/frio/js/filebrowser.js", function () {
|
||||
FileBrowser.init(filebrowser.dataset.nickname, filebrowser.dataset.type, match[1]);
|
||||
loadScript("view/theme/frio/js/module/media/browser.js", function () {
|
||||
Browser.init(filebrowser.dataset.nickname, filebrowser.dataset.type, match[1]);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
250
view/theme/frio/js/module/media/browser.js
Normal file
250
view/theme/frio/js/module/media/browser.js
Normal file
|
@ -0,0 +1,250 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
|
||||
/**
|
||||
* Filebrowser - Friendica Communications Server
|
||||
*
|
||||
* Copyright (c) 2010-2021, the Friendica project
|
||||
*
|
||||
* 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 code handle user interaction for photo/file upload/browser dialog.
|
||||
* Is loaded from filebrowser_plain.tpl
|
||||
*
|
||||
* To load filebrowser in colorbox, call
|
||||
*
|
||||
* Dialog.doImageBrowser(eventname, id);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* Dialog.doFileBrowser(eventname, id);
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* eventname: event name to catch return value
|
||||
* id: id returned to event handler
|
||||
*
|
||||
* When user select an item, an event in fired in parent page, on body element
|
||||
* The event is named
|
||||
*
|
||||
* fbrowser.<type>.[<eventname>]
|
||||
*
|
||||
* <type> will be one of "image" or "file", and the event handler will
|
||||
* get the following params:
|
||||
*
|
||||
* filename: filename of item chosen by user
|
||||
* embed: bbcode to embed element into posts
|
||||
* id: id from caller code
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // open dialog for select an image for a textarea with id "myeditor"
|
||||
* var id="myeditor";
|
||||
* Dialog.doImageBrowser("example", id);
|
||||
*
|
||||
* // setup event handler to get user selection
|
||||
* $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) {
|
||||
* // close colorbox
|
||||
* $.colorbox.close();
|
||||
* // replace textarea text with bbcode
|
||||
* $(id).value = bbcode;
|
||||
* });
|
||||
**/
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
*
|
||||
* This is a modified version to work with
|
||||
* the frio theme and Bootstrap modals
|
||||
*
|
||||
* The original file is under:
|
||||
* js/module/media/browser.js
|
||||
*
|
||||
*/
|
||||
|
||||
var Browser = {
|
||||
nickname: '',
|
||||
type: '',
|
||||
event: '',
|
||||
folder: '',
|
||||
id: null,
|
||||
|
||||
init: function (nickname, type, hash) {
|
||||
Browser.nickname = nickname;
|
||||
Browser.type = type;
|
||||
Browser.event = 'fbrowser.' + type;
|
||||
|
||||
if (hash !== '') {
|
||||
const h = hash.replace('#', '');
|
||||
const destination = h.split('-')[0];
|
||||
Browser.id = h.split('-')[1];
|
||||
Browser.event = Browser.event + '.' + destination;
|
||||
if (destination === 'comment') {
|
||||
// Get the comment textinput field
|
||||
var commentElm = document.getElementById('comment-edit-text-' + Browser.id);
|
||||
}
|
||||
}
|
||||
|
||||
Browser.postLoad();
|
||||
|
||||
$('.error .close').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('.error').addClass('hidden');
|
||||
});
|
||||
|
||||
// Click on album link
|
||||
$('.fbrowser').on('click', '.folders button, .path button', function (e) {
|
||||
e.preventDefault();
|
||||
let url = Browser._getUrl("none", this.dataset.folder);
|
||||
Browser.folder = this.dataset.folder;
|
||||
|
||||
Browser.loadContent(url);
|
||||
});
|
||||
|
||||
//Embed on click
|
||||
$('.fbrowser').on('click', '.photo-album-photo-link', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let embed = '';
|
||||
if (Browser.type === 'photo') {
|
||||
embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]';
|
||||
}
|
||||
if (Browser.type === 'attachment') {
|
||||
embed = '[attachment]' + this.dataset.link + '[/attachment]';
|
||||
}
|
||||
|
||||
// Delete prefilled Text of the comment input
|
||||
// Note: not the best solution but function commentOpenUI don't
|
||||
// work as expected (we need a way to wait until commentOpenUI would be finished).
|
||||
// As for now we insert pieces of this function here
|
||||
if (commentElm !== null && typeof commentElm !== 'undefined') {
|
||||
if (commentElm.value === '') {
|
||||
$('#comment-edit-text-' + Browser.id)
|
||||
.addClass('comment-edit-text-full')
|
||||
.removeClass('comment-edit-text-empty');
|
||||
$('#comment-edit-submit-wrapper-' + Browser.id).show();
|
||||
$('#comment-edit-text-' + Browser.id).attr('tabindex', '9');
|
||||
$('#comment-edit-submit-' + Browser.id).attr('tabindex', '10');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(Browser.event, this.dataset.filename, embed, Browser.id);
|
||||
|
||||
$('body').trigger(Browser.event, [this.dataset.filename, embed, Browser.id, this.dataset.img]);
|
||||
|
||||
// Close model
|
||||
$('#modal').modal('hide');
|
||||
// Update autosize for this textarea
|
||||
autosize.update($('.text-autosize'));
|
||||
});
|
||||
|
||||
// EventListener for switching between photo and file mode
|
||||
$('.fbrowser').on('click', '.fbswitcher .btn', function (e) {
|
||||
e.preventDefault();
|
||||
Browser.type = this.getAttribute('data-mode');
|
||||
$('.fbrowser')
|
||||
.removeClass()
|
||||
.addClass('fbrowser ' + Browser.type);
|
||||
|
||||
Browser.loadContent(Browser._getUrl("none"));
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize the AjaxUpload for the upload buttons
|
||||
uploadButtons: function () {
|
||||
if ($('#upload-photo').length) {
|
||||
//AjaxUpload for photos
|
||||
new window.AjaxUpload(
|
||||
'upload-photo',
|
||||
{
|
||||
action: 'media/photo/upload?response=json&album=' + encodeURIComponent(Browser.folder),
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function (file, ext) {
|
||||
$('.fbrowser-content').hide();
|
||||
$('.fbrowser .profile-rotator-wrapper').show();
|
||||
$('.error').addClass('hidden');
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response['error'] !== undefined) {
|
||||
$('.error span').html(response['error']);
|
||||
$('.error').removeClass('hidden');
|
||||
$('.fbrowser .profile-rotator-wrapper').hide();
|
||||
$('.fbrowser-content').show();
|
||||
return;
|
||||
}
|
||||
// load new content to fbrowser window
|
||||
Browser.loadContent(Browser._getUrl("none"));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if ($('#upload-attachment').length) {
|
||||
//AjaxUpload for files
|
||||
new window.AjaxUpload(
|
||||
'upload-attachment',
|
||||
{
|
||||
action: 'media/attachment/upload?response=json',
|
||||
name: 'userfile',
|
||||
responseType: 'json',
|
||||
onSubmit: function (file, ext) {
|
||||
$('.fbrowser-content').hide();
|
||||
$('.fbrowser .profile-rotator-wrapper').show();
|
||||
$('.error').addClass('hidden');
|
||||
},
|
||||
onComplete: function (file, response) {
|
||||
if (response["error"] !== undefined) {
|
||||
$('.error span').html(response['error']);
|
||||
$('.error').removeClass('hidden');
|
||||
$('.fbrowser .profile-rotator-wrapper').hide();
|
||||
$('.fbrowser-content').show();
|
||||
return;
|
||||
}
|
||||
// Load new content to fbrowser window
|
||||
Browser.loadContent(Browser._getUrl("none"));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Stuff which should be executed if no content was loaded
|
||||
postLoad: function () {
|
||||
Browser.initGallery();
|
||||
$('.fbrowser .fbswitcher .btn').removeClass('active');
|
||||
$('.fbrowser .fbswitcher [data-mode=' + Browser.type + ']').addClass('active');
|
||||
// We need to add the AjaxUpload to the button
|
||||
Browser.uploadButtons();
|
||||
},
|
||||
|
||||
// Load new content (e.g. change photo album)
|
||||
loadContent: function (url) {
|
||||
$('.fbrowser-content').hide();
|
||||
$('.fbrowser .profile-rotator-wrapper').show();
|
||||
|
||||
// load new content to fbrowser window
|
||||
$('.fbrowser').load(url, function (responseText, textStatus) {
|
||||
$('.profile-rotator-wrapper').hide();
|
||||
if (textStatus === 'success') {
|
||||
$(".fbrowser_content").show();
|
||||
Browser.postLoad();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize justified Gallery
|
||||
initGallery: function () {
|
||||
$('.fbrowser.photo .fbrowser-content-container').justifiedGallery({
|
||||
rowHeight: 80,
|
||||
margins: 4,
|
||||
border: 0,
|
||||
});
|
||||
},
|
||||
|
||||
_getUrl: function (mode, folder) {
|
||||
let folderValue = folder !== undefined ? folder : Browser.folder;
|
||||
let folderUrl = folderValue !== undefined ? '/' + encodeURIComponent(folderValue) : '';
|
||||
return 'media/' + Browser.type + '/browser' + folderUrl + '?mode=' + mode + "&theme=frio";
|
||||
}
|
||||
};
|
||||
// @license-end
|
|
@ -1,43 +1,45 @@
|
|||
<h1>{{$header}}</h1>
|
||||
<div class="generic-page-wrapper contact-follow-wrapper">
|
||||
<h2>{{$header}}</h2>
|
||||
|
||||
{{if !$myaddr}}
|
||||
<p id="dfrn-request-intro">
|
||||
{{$page_desc nofilter}}
|
||||
</p>
|
||||
<p>
|
||||
{{$invite_desc nofilter}}
|
||||
</p>
|
||||
<p id="dfrn-request-intro">
|
||||
{{$page_desc nofilter}}
|
||||
</p>
|
||||
<p>
|
||||
{{$invite_desc nofilter}}
|
||||
</p>
|
||||
{{/if}}
|
||||
|
||||
<form action="{{$action}}" method="post">
|
||||
<form action="{{$action}}" method="post">
|
||||
{{if $url}}
|
||||
<dl>
|
||||
<dt>{{$url_label}}</dt>
|
||||
<dd><a target="blank" href="{{$zrl}}">{{$url}}</a></dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{$url_label}}</dt>
|
||||
<dd><a target="blank" href="{{$zrl}}">{{$url}}</a></dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{if $keywords}}
|
||||
<dl>
|
||||
<dt>{{$keywords_label}}</dt>
|
||||
<dd>{{$keywords}}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>{{$keywords_label}}</dt>
|
||||
<dd>{{$keywords}}</dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
<div id="dfrn-request-url-wrapper">
|
||||
<label id="dfrn-url-label" for="dfrn-url">{{$your_address}}</label>
|
||||
{{if $myaddr}}
|
||||
{{$myaddr}}
|
||||
<input type="hidden" name="dfrn_url" id="dfrn-url" value="{{$myaddr}}" />
|
||||
{{else}}
|
||||
<input type="text" name="dfrn_url" id="dfrn-url" size="32" value="{{$myaddr}}">
|
||||
{{/if}}
|
||||
<input type="hidden" name="url" id="url" value="{{$url}}">
|
||||
<div id="dfrn-request-url-end"></div>
|
||||
</div>
|
||||
<div id="dfrn-request-url-wrapper">
|
||||
<label id="dfrn-url-label" for="dfrn-url">{{$your_address}}</label>
|
||||
{{if $myaddr}}
|
||||
{{$myaddr}}
|
||||
<input type="hidden" name="dfrn_url" id="dfrn-url" value="{{$myaddr}}" />
|
||||
{{else}}
|
||||
<input type="text" name="dfrn_url" id="dfrn-url" size="32" value="{{$myaddr}}">
|
||||
{{/if}}
|
||||
<input type="hidden" name="url" id="url" value="{{$url}}">
|
||||
<div id="dfrn-request-url-end"></div>
|
||||
</div>
|
||||
|
||||
<div id="dfrn-request-submit-wrapper">
|
||||
<div id="dfrn-request-submit-wrapper">
|
||||
{{if $submit}}
|
||||
<input class="btn btn-primary" type="submit" name="submit" id="dfrn-request-submit-button" value="{{$submit}}">
|
||||
<input class="btn btn-primary" type="submit" name="submit" id="dfrn-request-submit-button" value="{{$submit}}">
|
||||
{{/if}}
|
||||
<input class="btn btn-default" type="submit" name="cancel" id="dfrn-request-cancel-button" value="{{$cancel}}">
|
||||
</div>
|
||||
</form>
|
||||
<input class="btn btn-default" type="submit" name="cancel" id="dfrn-request-cancel-button" value="{{$cancel}}">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -61,13 +61,13 @@
|
|||
**/
|
||||
|
||||
/* callback */
|
||||
$('body').on('fbrowser.image.main', function(e, filename, embedcode, id) {
|
||||
$('body').on('fbrowser.photo.main', function(e, filename, embedcode, id) {
|
||||
///@todo this part isn't ideal and need to be done in a better way
|
||||
jotTextOpenUI(document.getElementById("profile-jot-text"));
|
||||
jotActive();
|
||||
addeditortext(embedcode);
|
||||
})
|
||||
.on('fbrowser.file.main', function(e, filename, embedcode, id) {
|
||||
.on('fbrowser.attachment.main', function(e, filename, embedcode, id) {
|
||||
jotTextOpenUI(document.getElementById("profile-jot-text"));
|
||||
jotActive();
|
||||
addeditortext(embedcode);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
{{/foreach}}
|
||||
|
||||
{{* Switch between image and file mode *}}
|
||||
<div class="fbswitcher btn-group btn-group-xs pull-right" aria-label="Switch between image and file mode">
|
||||
<button type="button" class="btn btn-default" data-mode="image" aria-label="Image Mode"><i class="fa fa-picture-o" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-default" data-mode="file" aria-label="File Mode"><i class="fa fa-file-o" aria-hidden="true"></i></button>
|
||||
<div class="fbswitcher btn-group btn-group-xs pull-right" aria-label="Switch between photo and attachment mode">
|
||||
<button type="button" class="btn btn-default" data-mode="photo" aria-label="Photo Mode"><i class="fa fa-picture-o" aria-hidden="true"></i></button>
|
||||
<button type="button" class="btn btn-default" data-mode="attachment" aria-label="Attachment Mode"><i class="fa fa-file-o" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
</ol>
|
||||
|
|
@ -2517,29 +2517,29 @@ footer {
|
|||
.fbrowser .list {
|
||||
padding: 10px;
|
||||
}
|
||||
.fbrowser.image .photo-album-image-wrapper {
|
||||
.fbrowser.photo .photo-album-image-wrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a img {
|
||||
.fbrowser.photo a img {
|
||||
width: auto;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a p {
|
||||
.fbrowser.photo a p {
|
||||
display: none;
|
||||
}
|
||||
.fbrowser.file .photo-album-image-wrapper {
|
||||
.fbrowser.attachment .photo-album-image-wrapper {
|
||||
float: none;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.fbrowser.file img {
|
||||
.fbrowser.attachment img {
|
||||
display: inline;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.fbrowser.file p {
|
||||
.fbrowser.attachment p {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -2516,29 +2516,29 @@ footer {
|
|||
.fbrowser .list {
|
||||
padding: 10px;
|
||||
}
|
||||
.fbrowser.image .photo-album-image-wrapper {
|
||||
.fbrowser.photo .photo-album-image-wrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a img {
|
||||
.fbrowser.photo a img {
|
||||
width: auto;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a p {
|
||||
.fbrowser.photo a p {
|
||||
display: none;
|
||||
}
|
||||
.fbrowser.file .photo-album-image-wrapper {
|
||||
.fbrowser.attachment .photo-album-image-wrapper {
|
||||
float: none;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.fbrowser.file img {
|
||||
.fbrowser.attachment img {
|
||||
display: inline;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.fbrowser.file p {
|
||||
.fbrowser.attachment p {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -2516,29 +2516,29 @@ footer {
|
|||
.fbrowser .list {
|
||||
padding: 10px;
|
||||
}
|
||||
.fbrowser.image .photo-album-image-wrapper {
|
||||
.fbrowser.photo .photo-album-image-wrapper {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a img {
|
||||
.fbrowser.photo a img {
|
||||
width: auto;
|
||||
height: 48px;
|
||||
}
|
||||
.fbrowser.image a p {
|
||||
.fbrowser.photo a p {
|
||||
display: none;
|
||||
}
|
||||
.fbrowser.file .photo-album-image-wrapper {
|
||||
.fbrowser.attachment .photo-album-image-wrapper {
|
||||
float: none;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.fbrowser.file img {
|
||||
.fbrowser.attachment img {
|
||||
display: inline;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.fbrowser.file p {
|
||||
.fbrowser.attachment p {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -1673,11 +1673,11 @@ footer { height: 100px; display: table-row; }
|
|||
}
|
||||
.fbrowser .folders ul { list-style: url("icons/folder.png"); padding-left: 22px;}
|
||||
.fbrowser .list { padding: 10px; }
|
||||
.fbrowser.image .photo-album-image-wrapper { width: 48px; height: 48px; }
|
||||
.fbrowser.image a img { width: auto; height: 48px; }
|
||||
.fbrowser.image a p { display: none;}
|
||||
.fbrowser.file .photo-album-image-wrapper { float:none; white-space: nowrap; width: 100%; height: auto; }
|
||||
.fbrowser.file img { display: inline; width: 16px; height: 16px}
|
||||
.fbrowser.file p { display: inline; white-space: nowrap; }
|
||||
.fbrowser.photo .photo-album-image-wrapper { width: 48px; height: 48px; }
|
||||
.fbrowser.photo a img { width: auto; height: 48px; }
|
||||
.fbrowser.photo a p { display: none;}
|
||||
.fbrowser.attachment .photo-album-image-wrapper { float:none; white-space: nowrap; width: 100%; height: auto; }
|
||||
.fbrowser.attachment img { display: inline; width: 16px; height: 16px}
|
||||
.fbrowser.attachment p { display: inline; white-space: nowrap; }
|
||||
|
||||
.fbrowser .upload { clear: both; padding-top: 1em;}
|
||||
|
|
|
@ -3261,7 +3261,7 @@ img.photo-album-photo {
|
|||
}
|
||||
|
||||
/* upload/select popup */
|
||||
fbrowser.image .photo-album-image-wrapper { margin-left: 10px; }
|
||||
fbrowser.photo .photo-album-image-wrapper { margin-left: 10px; }
|
||||
#message-preview { margin-top: 15px; }
|
||||
#message-preview span { width: 100%; }
|
||||
#message-preview .mail-count, #message-preview .mail-delete { display:none; }
|
||||
|
|
Loading…
Reference in a new issue