. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| Server IP : 85.13.141.101 / Your IP :
216.73.216.95 [
Web Server : Apache System : Linux dd40236 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : w00ad34b ( 1052) PHP Version : 8.2.30-nmm1 Disable Function : NONE Domains : 429 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /www/htdocs/w00ad34b/spd-cloud/apps/activity/lib/Controller/ |
Upload File : |
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Joas Schilling <coding@schilljs.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Activity\Controller;
use OC\Files\View;
use OCA\Activity\Data;
use OCA\Activity\Exception\InvalidFilterException;
use OCA\Activity\GroupHelper;
use OCA\Activity\UserSettings;
use OCA\Activity\ViewInfoCache;
use OCP\Activity\IFilter;
use OCP\Activity\IManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\Files\FileInfo;
use OCP\Files\IMimeTypeDetector;
use OCP\IPreview;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserSession;
class APIv2 extends OCSController {
/** @var string */
protected $filter;
/** @var int */
protected $since;
/** @var int */
protected $limit;
/** @var string */
protected $sort;
/** @var string */
protected $objectType;
/** @var int */
protected $objectId;
/** @var string */
protected $user;
/** @var bool */
protected $loadPreviews;
/** @var IManager */
protected $activityManager;
/** @var Data */
protected $data;
/** @var GroupHelper */
protected $helper;
/** @var UserSettings */
protected $settings;
/** @var IURLGenerator */
protected $urlGenerator;
/** @var IUserSession */
protected $userSession;
/** @var IPreview */
protected $preview;
/** @var IMimeTypeDetector */
protected $mimeTypeDetector;
/** @var View */
protected $view;
/** @var ViewInfoCache */
protected $infoCache;
/**
* OCSEndPoint constructor.
*
* @param string $appName
* @param IRequest $request
* @param IManager $activityManager
* @param Data $data
* @param GroupHelper $helper
* @param UserSettings $settings
* @param IURLGenerator $urlGenerator
* @param IUserSession $userSession
* @param IPreview $preview
* @param IMimeTypeDetector $mimeTypeDetector
* @param View $view
* @param ViewInfoCache $infoCache
*/
public function __construct($appName,
IRequest $request,
IManager $activityManager,
Data $data,
GroupHelper $helper,
UserSettings $settings,
IURLGenerator $urlGenerator,
IUserSession $userSession,
IPreview $preview,
IMimeTypeDetector $mimeTypeDetector,
View $view,
ViewInfoCache $infoCache) {
parent::__construct($appName, $request);
$this->activityManager = $activityManager;
$this->data = $data;
$this->helper = $helper;
$this->settings = $settings;
$this->urlGenerator = $urlGenerator;
$this->userSession = $userSession;
$this->preview = $preview;
$this->mimeTypeDetector = $mimeTypeDetector;
$this->view = $view;
$this->infoCache = $infoCache;
}
/**
* @param string $filter
* @param int $since
* @param int $limit
* @param bool $previews
* @param string $objectType
* @param int $objectId
* @param string $sort
* @throws InvalidFilterException when the filter is invalid
* @throws \OutOfBoundsException when no user is given
*/
protected function validateParameters($filter, $since, $limit, $previews, $objectType, $objectId, $sort) {
$this->filter = \is_string($filter) ? $filter : 'all';
if ($this->filter !== $this->data->validateFilter($this->filter)) {
throw new InvalidFilterException('Invalid filter');
}
$this->since = (int) $since;
$this->limit = (int) $limit;
$this->loadPreviews = (bool) $previews;
$this->objectType = (string) $objectType;
$this->objectId = (int) $objectId;
$this->sort = \in_array($sort, ['asc', 'desc'], true) ? $sort : 'desc';
if (($this->objectType !== '' && $this->objectId === 0) || ($this->objectType === '' && $this->objectId !== 0)) {
// Only allowed together
$this->objectType = '';
$this->objectId = 0;
}
$user = $this->userSession->getUser();
if ($user instanceof IUser) {
$this->user = $user->getUID();
} else {
// No user logged in
throw new \OutOfBoundsException('Not logged in');
}
}
/**
* @NoAdminRequired
*
* @param int $since
* @param int $limit
* @param bool $previews
* @param string $object_type
* @param int $object_id
* @param string $sort
* @return DataResponse
*/
public function getDefault($since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc'): DataResponse {
return $this->get('all', $since, $limit, $previews, $object_type, $object_id, $sort);
}
/**
* @NoAdminRequired
*
* @param string $filter
* @param int $since
* @param int $limit
* @param bool $previews
* @param string $object_type
* @param int $object_id
* @param string $sort
* @return DataResponse
*/
public function getFilter($filter, $since = 0, $limit = 50, $previews = false, $object_type = '', $object_id = 0, $sort = 'desc'): DataResponse {
return $this->get($filter, $since, $limit, $previews, $object_type, $object_id, $sort);
}
/**
* @NoAdminRequired
*
* @return DataResponse
*/
public function listFilters(): DataResponse {
$filters = $this->activityManager->getFilters();
$filters = array_map(function(IFilter $filter) {
return [
'id' => $filter->getIdentifier(),
'name' => $filter->getName(),
'icon' => $filter->getIcon(),
'priority' => $filter->getPriority(),
];
}, $filters);
// php 5.6 has problems with usort and objects
usort($filters, function(array $a, array $b) {
if ($a['priority'] === $b['priority']) {
return $a['id'] > $b['id'];
}
return $a['priority'] > $b['priority'];
});
return new DataResponse($filters);
}
/**
* @param string $filter
* @param int $since
* @param int $limit
* @param bool $previews
* @param string $filterObjectType
* @param int $filterObjectId
* @param string $sort
* @return DataResponse
*/
protected function get($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort): DataResponse {
try {
$this->validateParameters($filter, $since, $limit, $previews, $filterObjectType, $filterObjectId, $sort);
} catch (InvalidFilterException $e) {
return new DataResponse(null, Http::STATUS_NOT_FOUND);
} catch (\OutOfBoundsException $e) {
return new DataResponse(null, Http::STATUS_FORBIDDEN);
}
$this->activityManager->setRequirePNG($this->request->isUserAgent([IRequest::USER_AGENT_CLIENT_IOS]));
try {
$response = $this->data->get(
$this->helper,
$this->settings,
$this->user,
$this->since,
$this->limit,
$this->sort,
$this->filter,
$this->objectType,
$this->objectId
);
} catch (\OutOfBoundsException $e) {
// Invalid since argument
return new DataResponse(null, Http::STATUS_FORBIDDEN);
} catch (\BadMethodCallException $e) {
// No activity settings enabled
return new DataResponse(null, Http::STATUS_NO_CONTENT);
}
$this->activityManager->setRequirePNG(false);
$headers = $this->generateHeaders($response['headers'], $response['has_more'], $response['data']);
if (empty($response['data']) || $this->request->getHeader('If-None-Match') === $headers['ETag']) {
return new DataResponse([], Http::STATUS_NOT_MODIFIED, $headers);
}
$preparedActivities = [];
foreach ($response['data'] as $activity) {
$activity['datetime'] = date(\DateTime::ATOM, $activity['timestamp']);
unset($activity['timestamp']);
if ($this->loadPreviews) {
$activity['previews'] = [];
if ($activity['object_type'] === 'files') {
if (!empty($activity['objects']) && \is_array($activity['objects'])) {
foreach ($activity['objects'] as $objectId => $objectName) {
if (((int) $objectId) === 0 || $objectName === '') {
// No file, no preview
continue;
}
$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $objectId, $objectName);
}
} else if ($activity['object_id']) {
$activity['previews'][] = $this->getPreview($activity['affecteduser'], (int) $activity['object_id'], $activity['object_name']);
}
}
}
unset($activity['affecteduser']);
$preparedActivities[] = $activity;
}
return new DataResponse($preparedActivities, Http::STATUS_OK, $headers);
}
protected function generateHeaders(array $headers, bool $hasMoreActivities, array $data): array {
if ($hasMoreActivities && isset($headers['X-Activity-Last-Given'])) {
// Set the "Link" header for the next page
$nextPageParameters = [
'since' => $headers['X-Activity-Last-Given'],
'limit' => $this->limit,
'sort' => $this->sort,
];
if ($this->objectType && $this->objectId) {
$nextPageParameters['object_type'] = $this->objectType;
$nextPageParameters['object_id'] = $this->objectId;
}
if ($this->request->getParam('format') !== null) {
$nextPageParameters['format'] = $this->request->getParam('format');
}
$nextPage = $this->request->getServerProtocol(); # http
$nextPage .= '://' . $this->request->getServerHost(); # localhost
$nextPage .= $this->request->getScriptName(); # /ocs/v2.php
$nextPage .= $this->request->getPathInfo(); # /apps/activity/api/v2/activity
$nextPage .= '?' . http_build_query($nextPageParameters);
$headers['Link'] = '<' . $nextPage . '>; rel="next"';
}
$ids = [];
foreach ($data as $activity) {
$ids[] = $activity['activity_id'];
}
$headers['ETag'] = md5(json_encode($ids));
return $headers;
}
protected function getPreview(string $owner, int $fileId, string $filePath): array {
$info = $this->infoCache->getInfoById($owner, $fileId, $filePath);
if (!$info['exists'] || $info['view'] !== '') {
return $this->getPreviewFromPath($fileId, $filePath, $info);
}
$preview = [
'link' => $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
'source' => '',
'mimeType' => 'application/octet-stream',
'isMimeTypeIcon' => true,
'fileId' => $fileId,
'view' => $info['view'] ?: 'files',
];
// show a preview image if the file still exists
if ($info['is_dir']) {
$preview['source'] = $this->getPreviewPathFromMimeType('dir');
$preview['mimeType'] = 'dir';
} else {
$this->view->chroot('/' . $owner . '/files');
$fileInfo = $this->view->getFileInfo($info['path']);
if (!$fileInfo instanceof FileInfo) {
$preview = $this->getPreviewFromPath($fileId, $filePath, $info);
} else if ($this->preview->isAvailable($fileInfo)) {
$preview['source'] = $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreview', [
'file' => $info['path'],
'c' => $this->view->getETag($info['path']),
'x' => 150,
'y' => 150,
]);
$preview['mimeType'] = $fileInfo->getMimetype() ?: 'application/octet-stream';
$preview['isMimeTypeIcon'] = false;
} else {
$preview['mimeType'] = $fileInfo->getMimetype() ?: 'application/octet-stream';
$preview['source'] = $this->getPreviewPathFromMimeType($preview['mimeType']);
}
}
return $preview;
}
protected function getPreviewFromPath(int $fileId, string $filePath, array $info): array {
$mimeType = $info['is_dir'] ? 'dir' : $this->mimeTypeDetector->detectPath($filePath);
return [
'link' => $this->getPreviewLink($info['path'], $info['is_dir'], $info['view']),
'source' => $this->getPreviewPathFromMimeType($mimeType),
'mimeType' => $mimeType,
'isMimeTypeIcon' => true,
'fileId' => $fileId,
'view' => $info['view'] ?: 'files',
];
}
protected function getPreviewPathFromMimeType(string $mimeType): string {
$mimeTypeIcon = $this->mimeTypeDetector->mimeTypeIcon($mimeType);
if (substr($mimeTypeIcon, -4) === '.png') {
$mimeTypeIcon = substr($mimeTypeIcon, 0, -4) . '.svg';
}
return $this->urlGenerator->getAbsoluteURL($mimeTypeIcon);
}
protected function getPreviewLink(string $path, bool $isDir, string $view): string {
$params = [
'dir' => $path,
];
if (!$isDir) {
$params['dir'] = (substr_count($path, '/') === 1) ? '/' : \dirname($path);
$params['scrollto'] = basename($path);
}
if ($view !== '') {
$params['view'] = $view;
}
return $this->urlGenerator->linkToRouteAbsolute('files.view.index', $params);
}
}