Return JSON instead of compiled HTML

This commit is contained in:
Joas Schilling 2015-07-02 18:07:29 +02:00
Родитель ca6cbaf261
Коммит e19c4682b9
6 изменённых файлов: 228 добавлений и 67 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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());
}
}