зеркало из https://github.com/nextcloud/activity.git
Return JSON instead of compiled HTML
This commit is contained in:
Родитель
ca6cbaf261
Коммит
e19c4682b9
|
@ -189,10 +189,10 @@ class Application extends App {
|
|||
|
||||
return new Settings(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$server->getRequest(),
|
||||
$server->getConfig(),
|
||||
$server->getSecureRandom()->getMediumStrengthGenerator(),
|
||||
$c->query('URLGenerator'),
|
||||
$server->getURLGenerator(),
|
||||
$c->query('ActivityData'),
|
||||
$c->query('UserSettings'),
|
||||
$c->query('ActivityL10N'),
|
||||
|
@ -206,13 +206,16 @@ class Application extends App {
|
|||
|
||||
return new Activities(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$server->getRequest(),
|
||||
$c->query('ActivityData'),
|
||||
$c->query('DisplayHelper'),
|
||||
$c->query('GroupHelper'),
|
||||
$c->query('Navigation'),
|
||||
$c->query('UserSettings'),
|
||||
$server->getDateTimeFormatter(),
|
||||
$server->getPreviewManager(),
|
||||
$server->getURLGenerator(),
|
||||
new View(''),
|
||||
$c->query('CurrentUID')
|
||||
);
|
||||
});
|
||||
|
@ -223,7 +226,7 @@ class Application extends App {
|
|||
|
||||
return new Feed(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$server->getRequest(),
|
||||
$c->query('ActivityData'),
|
||||
$c->query('GroupHelperSingleEntries'),
|
||||
$c->query('UserSettings'),
|
||||
|
|
|
@ -23,15 +23,21 @@
|
|||
|
||||
namespace OCA\Activity\Controller;
|
||||
|
||||
use OC\Files\View;
|
||||
use OCA\Activity\Data;
|
||||
use OCA\Activity\Display;
|
||||
use OCA\Activity\GroupHelper;
|
||||
use OCA\Activity\Navigation;
|
||||
use OCA\Activity\UserSettings;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\Files;
|
||||
use OCP\IDateTimeFormatter;
|
||||
use OCP\IPreview;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\Template;
|
||||
|
||||
class Activities extends Controller {
|
||||
const DEFAULT_PAGE_SIZE = 30;
|
||||
|
@ -54,6 +60,15 @@ class Activities extends Controller {
|
|||
/** @var IDateTimeFormatter */
|
||||
protected $dateTimeFormatter;
|
||||
|
||||
/** @var IPreview */
|
||||
protected $preview;
|
||||
|
||||
/** @var IURLGenerator */
|
||||
protected $urlGenerator;
|
||||
|
||||
/** @var View */
|
||||
protected $view;
|
||||
|
||||
/** @var string */
|
||||
protected $user;
|
||||
|
||||
|
@ -68,6 +83,9 @@ class Activities extends Controller {
|
|||
* @param Navigation $navigation
|
||||
* @param UserSettings $settings
|
||||
* @param IDateTimeFormatter $dateTimeFormatter
|
||||
* @param IPreview $preview
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param View $view
|
||||
* @param string $user
|
||||
*/
|
||||
public function __construct($appName,
|
||||
|
@ -78,6 +96,9 @@ class Activities extends Controller {
|
|||
Navigation $navigation,
|
||||
UserSettings $settings,
|
||||
IDateTimeFormatter $dateTimeFormatter,
|
||||
IPreview $preview,
|
||||
IURLGenerator $urlGenerator,
|
||||
View $view,
|
||||
$user) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->data = $data;
|
||||
|
@ -86,6 +107,9 @@ class Activities extends Controller {
|
|||
$this->navigation = $navigation;
|
||||
$this->settings = $settings;
|
||||
$this->dateTimeFormatter = $dateTimeFormatter;
|
||||
$this->preview = $preview;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->view = $view;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
|
@ -110,16 +134,75 @@ class Activities extends Controller {
|
|||
*
|
||||
* @param int $page
|
||||
* @param string $filter
|
||||
* @return TemplateResponse
|
||||
* @return JSONResponse
|
||||
*/
|
||||
public function fetch($page, $filter = 'all') {
|
||||
$pageOffset = $page - 1;
|
||||
$filter = $this->data->validateFilter($filter);
|
||||
|
||||
return new TemplateResponse('activity', 'stream.list', [
|
||||
'activity' => $this->data->read($this->helper, $this->settings, $pageOffset * self::DEFAULT_PAGE_SIZE, self::DEFAULT_PAGE_SIZE, $filter),
|
||||
'displayHelper' => $this->display,
|
||||
'dateTimeFormatter' => $this->dateTimeFormatter,
|
||||
], '');
|
||||
$activities = $this->data->read($this->helper, $this->settings, $pageOffset * self::DEFAULT_PAGE_SIZE, self::DEFAULT_PAGE_SIZE, $filter);
|
||||
|
||||
$preparedActivities = [];
|
||||
foreach ($activities as $activity) {
|
||||
$activity['relativeTimestamp'] = (string) Template::relative_modified_date($activity['timestamp'], true);
|
||||
$activity['readableTimestamp'] = (string) $this->dateTimeFormatter->formatDate($activity['timestamp']);
|
||||
$activity['relativeDateTimestamp'] = (string) Template::relative_modified_date($activity['timestamp']);
|
||||
$activity['readableDateTimestamp'] = (string) $this->dateTimeFormatter->formatDateTime($activity['timestamp']);
|
||||
|
||||
if (strpos($activity['subjectformatted']['markup']['trimmed'], '<a ') !== false) {
|
||||
// We do not link the subject as we create links for the parameters instead
|
||||
$activity['link'] = '';
|
||||
}
|
||||
|
||||
if ($activity['file']) {
|
||||
$this->view->chroot('/' . $activity['affecteduser'] . '/files');
|
||||
$exist = $this->view->file_exists($activity['file']);
|
||||
$is_dir = $this->view->is_dir($activity['file']);
|
||||
$activity['preview'] = [
|
||||
'link' => $this->getPreviewLink($activity['file'], $is_dir),
|
||||
'source' => '',
|
||||
'isMimeTypeIcon' => true,
|
||||
];
|
||||
|
||||
// show a preview image if the file still exists
|
||||
if ($is_dir) {
|
||||
$activity['preview']['source'] = Template::mimetype_icon('dir');
|
||||
} else {
|
||||
$mimeType = Files::getMimeType($activity['file']);
|
||||
if (!$is_dir && $mimeType && $this->preview->isMimeSupported($mimeType) && $exist) {
|
||||
$activity['preview']['isMimeTypeIcon'] = false;
|
||||
$activity['preview']['source'] = $this->urlGenerator->linkToRoute('core_ajax_preview', [
|
||||
'file' => $activity['file'],
|
||||
'x' => 150,
|
||||
'y' => 150,
|
||||
]);
|
||||
} else {
|
||||
$activity['preview']['source'] = Template::mimetype_icon($mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$preparedActivities[] = $activity;
|
||||
}
|
||||
|
||||
return new JSONResponse($preparedActivities);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param bool $isDir
|
||||
* @return string
|
||||
*/
|
||||
protected function getPreviewLink($path, $isDir) {
|
||||
if ($isDir) {
|
||||
return $this->urlGenerator->linkTo('files', 'index.php', array('dir' => $path));
|
||||
} else {
|
||||
$parentDir = (substr_count($path, '/') === 1) ? '/' : dirname($path);
|
||||
$fileName = basename($path);
|
||||
return $this->urlGenerator->linkTo('files', 'index.php', array(
|
||||
'dir' => $parentDir,
|
||||
'scrollto' => $fileName,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,8 @@
|
|||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.box .preview-dir-icon{
|
||||
.box .preview-dir-icon,
|
||||
.box .preview-mimetype-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
|
130
js/script.js
130
js/script.js
|
@ -33,6 +33,7 @@ $(function(){
|
|||
OCActivity.InfinitScrolling = {
|
||||
ignoreScroll: false,
|
||||
container: $('#container'),
|
||||
lastDateGroup: null,
|
||||
content: $('#app-content'),
|
||||
|
||||
prefill: function () {
|
||||
|
@ -43,26 +44,7 @@ $(function(){
|
|||
OC.generateUrl('/apps/activity/activities/fetch'),
|
||||
'filter=' + OCActivity.Filter.filter + '&page=' + OCActivity.Filter.currentPage,
|
||||
function (data) {
|
||||
if (data.trim().length) {
|
||||
OCActivity.InfinitScrolling.appendContent(data);
|
||||
|
||||
// Continue prefill
|
||||
OCActivity.InfinitScrolling.prefill();
|
||||
} else if (OCActivity.Filter.currentPage == 1) {
|
||||
// First page is empty - No activities :(
|
||||
var $emptyContent = $('#emptycontent');
|
||||
$emptyContent.removeClass('hidden');
|
||||
if (OCActivity.Filter.filter == 'all') {
|
||||
$emptyContent.find('p').text(t('activity', 'This stream will show events like additions, changes & shares'));
|
||||
} else {
|
||||
$emptyContent.find('p').text(t('activity', 'There are no events for this filter'));
|
||||
}
|
||||
$('#loading_activities').addClass('hidden');
|
||||
} else {
|
||||
// Page is empty - No more activities :(
|
||||
$('#no_more_activities').removeClass('hidden');
|
||||
$('#loading_activities').addClass('hidden');
|
||||
}
|
||||
OCActivity.InfinitScrolling.handleActivitiesCallback(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -78,41 +60,101 @@ $(function(){
|
|||
OC.generateUrl('/apps/activity/activities/fetch'),
|
||||
'filter=' + OCActivity.Filter.filter + '&page=' + OCActivity.Filter.currentPage,
|
||||
function (data) {
|
||||
OCActivity.InfinitScrolling.appendContent(data);
|
||||
OCActivity.InfinitScrolling.ignoreScroll = false;
|
||||
|
||||
if (!data.trim().length) {
|
||||
// Page is empty - No more activities :(
|
||||
$('#no_more_activities').removeClass('hidden');
|
||||
$('#loading_activities').addClass('hidden');
|
||||
OCActivity.InfinitScrolling.ignoreScroll = true;
|
||||
}
|
||||
OCActivity.InfinitScrolling.handleActivitiesCallback(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
appendContent: function (content) {
|
||||
var firstNewGroup = $(content).first(),
|
||||
lastGroup = this.container.children().last();
|
||||
handleActivitiesCallback: function (data) {
|
||||
var $numActivities = data.length;
|
||||
|
||||
// Is the first new container the same as the last one?
|
||||
if (lastGroup && lastGroup.data('date') === firstNewGroup.data('date')) {
|
||||
var appendedBoxes = firstNewGroup.find('.box'),
|
||||
lastBoxContainer = lastGroup.find('.boxcontainer');
|
||||
if ($numActivities > 0) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var $activity = data[i];
|
||||
this.appendActivityToContainer($activity);
|
||||
}
|
||||
|
||||
// Move content into the last box
|
||||
OCActivity.InfinitScrolling.processElements(appendedBoxes);
|
||||
lastBoxContainer.append(appendedBoxes);
|
||||
// Continue prefill
|
||||
this.prefill();
|
||||
|
||||
} else if (OCActivity.Filter.currentPage == 1) {
|
||||
// First page is empty - No activities :(
|
||||
var $emptyContent = $('#emptycontent');
|
||||
$emptyContent.removeClass('hidden');
|
||||
if (OCActivity.Filter.filter == 'all') {
|
||||
$emptyContent.find('p').text(t('activity', 'This stream will show events like additions, changes & shares'));
|
||||
} else {
|
||||
$emptyContent.find('p').text(t('activity', 'There are no events for this filter'));
|
||||
}
|
||||
$('#loading_activities').addClass('hidden');
|
||||
|
||||
// Remove the first box, so it's not duplicated
|
||||
content = $(content).slice(1);
|
||||
} else {
|
||||
content = $(content);
|
||||
// Page is empty - No more activities :(
|
||||
$('#no_more_activities').removeClass('hidden');
|
||||
$('#loading_activities').addClass('hidden');
|
||||
}
|
||||
},
|
||||
|
||||
appendActivityToContainer: function ($activity) {
|
||||
this.makeSureDateGroupExists($activity.relativeTimestamp, $activity.readableTimestamp);
|
||||
this.addActivity($activity);
|
||||
},
|
||||
|
||||
makeSureDateGroupExists: function($relativeTimestamp, $readableTimestamp) {
|
||||
var $lastGroup = this.container.children().last();
|
||||
|
||||
if ($lastGroup.data('date') !== $relativeTimestamp) {
|
||||
var $content = '<div class="section activity-section group" data-date="' + escapeHTML($relativeTimestamp) + '">' + "\n"
|
||||
+' <h2>'+"\n"
|
||||
+' <span class="tooltip" title="' + escapeHTML($readableTimestamp) + '">' + escapeHTML($relativeTimestamp) + '</span>' + "\n"
|
||||
+' </h2>' + "\n"
|
||||
+' <div class="boxcontainer">' + "\n"
|
||||
+' </div>' + "\n"
|
||||
+'</div>';
|
||||
$content = $($content);
|
||||
OCActivity.InfinitScrolling.processElements($content);
|
||||
this.container.append($content);
|
||||
this.lastDateGroup = $content;
|
||||
}
|
||||
},
|
||||
|
||||
addActivity: function($activity) {
|
||||
var $content = ''
|
||||
+ '<div class="box">' + "\n"
|
||||
+ ' <div class="messagecontainer">' + "\n"
|
||||
|
||||
+ ' <div class="activity-icon ' + (($activity.typeicon) ? escapeHTML($activity.typeicon) + ' svg' : '') + '"></div>' + "\n"
|
||||
|
||||
+ ' <div class="activitysubject">' + "\n"
|
||||
+ (($activity.link) ? ' <a href="' + $activity.link + '">' + "\n" : '')
|
||||
+ ' ' + $activity.subjectformatted.markup.trimmed + "\n"
|
||||
+ (($activity.link) ? ' </a>' + "\n" : '')
|
||||
+ ' </div>' + "\n"
|
||||
|
||||
+' <span class="activitytime tooltip" title="' + escapeHTML($activity.readableDateTimestamp) + '">' + "\n"
|
||||
+ ' ' + escapeHTML($activity.relativeDateTimestamp) + "\n"
|
||||
+' </span>' + "\n";
|
||||
|
||||
if ($activity.message) {
|
||||
$content += '<div class="activitymessage">' + "\n"
|
||||
+ $activity.messageformatted.markup.trimmed + "\n"
|
||||
+'</div>' + "\n";
|
||||
}
|
||||
|
||||
OCActivity.InfinitScrolling.processElements(content);
|
||||
this.container.append(content);
|
||||
if ($activity.preview) {
|
||||
var $preview = $activity.preview;
|
||||
$content += (($preview.link) ? '<a href="' + $preview.link + '">' + "\n" : '')
|
||||
+ '<img class="preview' + (($preview.isMimeTypeIcon) ? ' preview-mimetype-icon' : '') + '" src="' + $preview.source + '" alt=""/>' + "\n"
|
||||
+ (($preview.link) ? '</a>' + "\n" : '')
|
||||
}
|
||||
|
||||
$content += ' </div>' + "\n"
|
||||
+'</div>';
|
||||
|
||||
$content = $($content);
|
||||
OCActivity.InfinitScrolling.processElements($content);
|
||||
this.lastDateGroup.append($content);
|
||||
},
|
||||
|
||||
processElements: function (parentElement) {
|
||||
|
|
|
@ -99,6 +99,7 @@ class GroupHelper
|
|||
// and the time difference is not bigger than 3 days.
|
||||
if ($this->getGroupKey($activity) === $this->groupKey &&
|
||||
abs($activity['timestamp'] - $this->groupTime) < (3 * 24 * 60 * 60)
|
||||
&& (!isset($this->openGroup['activity_ids']) || sizeof($this->openGroup['activity_ids']) <= 5)
|
||||
) {
|
||||
$parameter = $this->getGroupParameter($activity);
|
||||
if ($parameter !== false) {
|
||||
|
@ -114,9 +115,7 @@ class GroupHelper
|
|||
$this->openGroup['activity_ids'][] = (int) $activity['activity_id'];
|
||||
}
|
||||
} else {
|
||||
if (!empty($this->openGroup)) {
|
||||
$this->activities[] = $this->openGroup;
|
||||
}
|
||||
$this->closeOpenGroup();
|
||||
|
||||
$this->groupKey = $this->getGroupKey($activity);
|
||||
$this->groupTime = $activity['timestamp'];
|
||||
|
@ -124,6 +123,15 @@ class GroupHelper
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the currently open group and adds it to the list of activities
|
||||
*/
|
||||
protected function closeOpenGroup() {
|
||||
if (!empty($this->openGroup)) {
|
||||
$this->activities[] = $this->openGroup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grouping key for an activity
|
||||
*
|
||||
|
@ -146,6 +154,12 @@ class GroupHelper
|
|||
return $activity['app'] . '|' . $activity['user'] . '|' . $activity['subject'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter which is the varying part
|
||||
*
|
||||
* @param array $activity
|
||||
* @return bool|int False if the activity should not be grouped, parameter position otherwise
|
||||
*/
|
||||
protected function getGroupParameter($activity) {
|
||||
if (!$this->allowGrouping) {
|
||||
return false;
|
||||
|
@ -161,9 +175,7 @@ class GroupHelper
|
|||
* @return array translated activities ready for use
|
||||
*/
|
||||
public function getActivities() {
|
||||
if (!empty($this->openGroup)) {
|
||||
$this->activities[] = $this->openGroup;
|
||||
}
|
||||
$this->closeOpenGroup();
|
||||
|
||||
$return = array();
|
||||
foreach ($this->activities as $activity) {
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace OCA\Activity\Tests\Controller;
|
|||
|
||||
use OCA\Activity\Controller\Activities;
|
||||
use OCA\Activity\Tests\TestCase;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\Template;
|
||||
|
||||
class ActivitiesTest extends TestCase {
|
||||
|
@ -40,6 +39,15 @@ class ActivitiesTest extends TestCase {
|
|||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $dateTimeFormatter;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $preview;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $urlGenerator;
|
||||
|
||||
/** @var \PHPUnit_Framework_MockObject_MockObject */
|
||||
protected $view;
|
||||
|
||||
/** @var \OCP\IL10N */
|
||||
protected $l10n;
|
||||
|
||||
|
@ -67,6 +75,15 @@ class ActivitiesTest extends TestCase {
|
|||
$this->dateTimeFormatter = $this->getMockBuilder('OCP\IDateTimeFormatter')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->preview = $this->getMockBuilder('OCP\IPreview')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->urlGenerator = $this->getMockBuilder('OCP\IURLGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->view = $this->getMockBuilder('OC\Files\View')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->request = $this->getMock('OCP\IRequest');
|
||||
|
||||
|
@ -79,6 +96,9 @@ class ActivitiesTest extends TestCase {
|
|||
$this->navigation,
|
||||
$this->userSettings,
|
||||
$this->dateTimeFormatter,
|
||||
$this->preview,
|
||||
$this->urlGenerator,
|
||||
$this->view,
|
||||
'test'
|
||||
);
|
||||
}
|
||||
|
@ -93,7 +113,7 @@ class ActivitiesTest extends TestCase {
|
|||
->willReturn($template);
|
||||
|
||||
$templateResponse = $this->controller->showList();
|
||||
$this->assertTrue($templateResponse instanceof TemplateResponse, 'Asserting type of return is \OCP\AppFramework\Http\TemplateResponse');
|
||||
$this->assertInstanceOf('\OCP\AppFramework\Http\TemplateResponse', $templateResponse, 'Asserting type of return is \OCP\AppFramework\Http\TemplateResponse');
|
||||
|
||||
$renderedResponse = $templateResponse->render();
|
||||
$this->assertNotEmpty($renderedResponse);
|
||||
|
@ -104,10 +124,10 @@ class ActivitiesTest extends TestCase {
|
|||
->method('read')
|
||||
->willReturn([]);
|
||||
|
||||
$templateResponse = $this->controller->fetch(1);
|
||||
$this->assertTrue($templateResponse instanceof TemplateResponse, 'Asserting type of return is \OCP\AppFramework\Http\TemplateResponse');
|
||||
/** @var \OCP\AppFramework\Http\JSONResponse $response */
|
||||
$response = $this->controller->fetch(1);
|
||||
$this->assertInstanceOf('\OCP\AppFramework\Http\JSONResponse', $response, 'Asserting type of return is \OCP\AppFramework\Http\TemplateResponse');
|
||||
|
||||
$renderedResponse = $templateResponse->render();
|
||||
$this->assertEmpty($renderedResponse);
|
||||
$this->assertSame([], $response->getData());
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче