Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions js/src/forum/components/DiscussionList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Component from '../../common/Component';
import ItemList from '../../common/utils/ItemList';
import listItems from '../../common/helpers/listItems';
import DiscussionListItem from './DiscussionListItem';
import Button from '../../common/components/Button';
import LoadingIndicator from '../../common/components/LoadingIndicator';
Expand Down Expand Up @@ -38,6 +40,32 @@ export default class DiscussionList extends Component {
this.refresh();
}

aboveDiscussions() {
const items = new ItemList();

if (app.markedAllAsRead) {
items.add('cancel-read-all', Button.component({
className: 'Button Button--block',
onclick: () => {
app.request({
method: 'DELETE',
url: app.forum.attribute('apiUrl') + '/discussions/read'
}).then(payload => {
app.store.pushPayload(payload);
app.markedAllAsRead = false;
this.cancellingAllRead = false;
m.redraw();
});
this.cancellingAllRead = true;
},
loading: this.cancellingAllRead,
children: app.translator.trans('core.forum.index.mark_all_as_read_done')
}));
}

return items;
}

view() {
const params = this.props.params;
let loading;
Expand All @@ -64,6 +92,7 @@ export default class DiscussionList extends Component {
return (
<div className={'DiscussionList'+(this.props.params.q ? ' DiscussionList--searchResults' : '')}>
<ul className="DiscussionList-discussions">
{listItems(this.aboveDiscussions().toArray())}
{this.discussions.map(discussion => {
return (
<li key={discussion.id()} data-id={discussion.id()}>
Expand Down
18 changes: 13 additions & 5 deletions js/src/forum/components/IndexPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,18 @@ export default class IndexPage extends Page {
* @return void
*/
markAllAsRead() {
const confirmation = confirm(app.translator.trans('core.forum.index.mark_all_as_read_confirmation'));

if (confirmation) {
app.session.user.save({markedAllAsReadAt: new Date()});
}
app.request({
method: 'POST',
url: app.forum.attribute('apiUrl') + '/discussions/read'
}).then(payload => {
app.store.pushPayload(payload);
app.markedAllAsRead = true;
m.redraw();

setTimeout(() => {
app.markedAllAsRead = false;
m.redraw();
}, 10000);
});
}
}
68 changes: 68 additions & 0 deletions src/Api/Controller/ReadAllDiscussionsCancelController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Flarum\Api\Controller;

use Carbon\Carbon;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Foundation\ValidationException;
use Flarum\User\User;
use Flarum\User\UserRepository;
use Illuminate\Session\Store;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Tobscure\JsonApi\Document;

class ReadAllDiscussionsCancelController extends AbstractShowController
{
/**
* {@inheritdoc}
*/
public $serializer = CurrentUserSerializer::class;

/**
* @var \Flarum\User\UserRepository
*/
protected $users;

/**
* @param \Flarum\User\UserRepository $users
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}

/**
* Get the data to be serialized and assigned to the response document.
*
* @param ServerRequestInterface $request
* @param Document $document
* @return mixed
* @throws ValidationException
*/
protected function data(ServerRequestInterface $request, Document $document)
{
/**
* @var $actor User
*/
$actor = $request->getAttribute('actor');

/**
* @var $session Store
*/
$session = $request->getAttribute('session');

if ($session->has('can_cancel_marked_all_until') && Carbon::now()->isBefore($session->get('can_cancel_marked_all_until'))) {
$actor->marked_all_as_read_at = $session->get('previous_marked_all_as_read_at');
$actor->save();
} else {
throw new ValidationException([
'something' => [
app(TranslatorInterface::class)->trans('core.api.too_late_to_cancel_read_all'),
],
]);
}

return $this->users->findOrFail($actor->id, $actor);
}
}
61 changes: 61 additions & 0 deletions src/Api/Controller/ReadAllDiscussionsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Flarum\Api\Controller;

use Carbon\Carbon;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\User\User;
use Flarum\User\UserRepository;
use Illuminate\Session\Store;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;

class ReadAllDiscussionsController extends AbstractShowController
{
/**
* {@inheritdoc}
*/
public $serializer = CurrentUserSerializer::class;

/**
* @var \Flarum\User\UserRepository
*/
protected $users;

/**
* @param \Flarum\User\UserRepository $users
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}

/**
* Get the data to be serialized and assigned to the response document.
*
* @param ServerRequestInterface $request
* @param Document $document
* @return mixed
*/
protected function data(ServerRequestInterface $request, Document $document)
{
/**
* @var $actor User
*/
$actor = $request->getAttribute('actor');

/**
* @var $session Store
*/
$session = $request->getAttribute('session');

$session->put('previous_marked_all_as_read_at', $actor->marked_all_as_read_at);
$session->put('can_cancel_marked_all_until', Carbon::now()->addSeconds(15));
$session->save();

$actor->markAllAsRead();
$actor->save();

return $this->users->findOrFail($actor->id, $actor);
}
}
14 changes: 14 additions & 0 deletions src/Api/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@
$route->toController(Controller\CreateDiscussionController::class)
);

// Mark all discussions as read
$map->post(
'/discussions/read',
'discussions.readAll',
$route->toController(Controller\ReadAllDiscussionsController::class)
);

// Cancel marking all discussions as read
$map->delete(
'/discussions/read',
'discussions.cancelReadAll',
$route->toController(Controller\ReadAllDiscussionsCancelController::class)
);

// Show a single discussion
$map->get(
'/discussions/{id}',
Expand Down
5 changes: 0 additions & 5 deletions src/User/Command/EditUserHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ public function handle(EditUser $command)
$validate['password'] = $attributes['password'];
}

if (! empty($attributes['markedAllAsReadAt'])) {
$this->assertPermission($isSelf);
$user->markAllAsRead();
}

if (! empty($attributes['preferences'])) {
$this->assertPermission($isSelf);

Expand Down