FavoritePlugin is now an "ActivityVerbHandlerPlugin"

This commit is contained in:
Mikael Nordfeldth 2015-03-10 15:39:35 +01:00
parent e338931ffa
commit af67f15cf2
9 changed files with 189 additions and 175 deletions

View File

@ -31,6 +31,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
class ActivityVerbPlugin extends Plugin class ActivityVerbPlugin extends Plugin
{ {
public function onRouterInitialized(URLMapper $m) public function onRouterInitialized(URLMapper $m)
{ {
$m->connect('notice/:id/:verb', $m->connect('notice/:id/:verb',

View File

@ -35,8 +35,15 @@ class ActivityverbAction extends ManagedAction
protected $canPost = true; protected $canPost = true;
protected $verb = null; protected $verb = null;
protected function doPreparation($args) public function title()
{
$title = null;
Event::handle('ActivityVerbTitle', array($this, $this->verb, $this->notice, $this->scoped, &$title));
return $title;
}
protected function doPreparation()
{ {
$this->verb = $this->trimmed('verb'); $this->verb = $this->trimmed('verb');
if (empty($this->verb)) { if (empty($this->verb)) {
@ -50,13 +57,15 @@ class ActivityverbAction extends ManagedAction
throw new ClientException(sprintf(_('%1$s has no access to notice %2$d.'), throw new ClientException(sprintf(_('%1$s has no access to notice %2$d.'),
$this->scoped->getNickname(), $this->notice->getID()), 403); $this->scoped->getNickname(), $this->notice->getID()), 403);
} }
Event::handle('ActivityVerbDoPreparation', array($this, $this->verb, $this->notice, $this->scoped));
} }
protected function doPost() protected function doPost()
{ {
if (Event::handle('ActivityVerbDoPost', array($this, $this->verb, $this->notice, $this->scoped))) { if (Event::handle('ActivityVerbDoPost', array($this, $this->verb, $this->notice, $this->scoped))) {
// TRANS: Error when a POST method for an activity verb has not been handled by a plugin. // TRANS: Error when a POST method for an activity verb has not been handled by a plugin.
throw new ClientException(_('Could not show content for verb "%1$s".')); throw new ClientException(sprintf(_('Could not handle POST for verb "%1$s".'), $this->verb));
} }
} }
@ -64,7 +73,7 @@ class ActivityverbAction extends ManagedAction
{ {
if (Event::handle('ActivityVerbShowContent', array($this, $this->verb, $this->notice, $this->scoped))) { if (Event::handle('ActivityVerbShowContent', array($this, $this->verb, $this->notice, $this->scoped))) {
// TRANS: Error when a page for an activity verb has not been handled by a plugin. // TRANS: Error when a page for an activity verb has not been handled by a plugin.
throw new ClientException(_('Could not show content for verb "%1$s".')); $this->element('div', 'error', sprintf(_('Could not show content for verb "%1$s".'), $this->verb));
} }
} }
} }

View File

@ -0,0 +1,82 @@
<?php
/*
* GNU Social - a federating social network
* Copyright (C) 2014, Free Software Foundation, Inc.
*
* 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 <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* @package Activity
* @maintainer Mikael Nordfeldth <mmn@hethane.se>
*/
abstract class ActivityVerbHandlerPlugin extends ActivityHandlerPlugin
{
public function onActivityVerbTitle(ManagedAction $action, $verb, Notice $target, Profile $scoped, &$title)
{
if (!$this->isMyVerb($verb)) {
return true;
}
$title = $this->getActionTitle($action, $verb, $target, $scoped);
return false;
}
abstract protected function getActionTitle(ManagedAction $action, $verb, Notice $target, Profile $scoped);
public function onActivityVerbShowContent(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
if (!$this->isMyVerb($verb)) {
return true;
}
return $this->showActionContent($action, $verb, $target, $scoped);
}
protected function showActionContent(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
if (!GNUsocial::isAjax()) {
$nl = new NoticeListItem($target, $action, array('options'=>false, 'attachments'=>false,
'item_tag'=>'div', 'id_prefix'=>'fave'));
$nl->show();
}
$form = $this->getActivityForm($action, $verb, $target, $scoped);
$form->show();
return false;
}
public function onActivityVerbDoPreparation(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
if (!$this->isMyVerb($verb)) {
return true;
}
return $this->doActionPreparation($action, $verb, $target, $scoped);
}
abstract protected function doActionPreparation(ManagedAction $action, $verb, Notice $target, Profile $scoped);
public function onActivityVerbDoPost(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
if (!$this->isMyVerb($verb)) {
return true;
}
return $this->doActionPost($action, $verb, $target, $scoped);
}
abstract protected function doActionPost(ManagedAction $action, $verb, Notice $target, Profile $scoped);
abstract protected function getActivityForm(ManagedAction $action, $verb, Notice $target, Profile $scoped);
}

View File

@ -23,7 +23,7 @@ if (!defined('GNUSOCIAL')) { exit(1); }
* @package Activity * @package Activity
* @maintainer Mikael Nordfeldth <mmn@hethane.se> * @maintainer Mikael Nordfeldth <mmn@hethane.se>
*/ */
class FavoritePlugin extends ActivityHandlerPlugin class FavoritePlugin extends ActivityVerbHandlerPlugin
{ {
protected $email_notify_fave = 1; protected $email_notify_fave = 1;
@ -39,9 +39,10 @@ class FavoritePlugin extends ActivityHandlerPlugin
public function verbs() public function verbs()
{ {
return array(ActivityVerb::FAVORITE); return array(ActivityVerb::FAVORITE, ActivityVerb::LIKE,
ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE);
} }
public function onCheckSchema() public function onCheckSchema()
{ {
$schema = Schema::get(); $schema = Schema::get();
@ -78,14 +79,14 @@ class FavoritePlugin extends ActivityHandlerPlugin
printfnq("DONE.\n"); printfnq("DONE.\n");
} }
} }
public function onEndUpgrade() public function onEndUpgrade()
{ {
printfnq("Ensuring all faves have a URI..."); printfnq("Ensuring all faves have a URI...");
$fave = new Fave(); $fave = new Fave();
$fave->whereAdd('uri IS NULL'); $fave->whereAdd('uri IS NULL');
if ($fave->find()) { if ($fave->find()) {
while ($fave->fetch()) { while ($fave->fetch()) {
try { try {
@ -104,7 +105,7 @@ class FavoritePlugin extends ActivityHandlerPlugin
} }
} }
} }
printfnq("DONE.\n"); printfnq("DONE.\n");
} }
@ -180,7 +181,7 @@ class FavoritePlugin extends ActivityHandlerPlugin
} }
// FIXME: Set this to abstract public in lib/activityhandlerplugin.php ddwhen all plugins have migrated! // FIXME: Set this to abstract public in lib/activityhandlerplugin.php ddwhen all plugins have migrated!
protected function saveObjectFromActivity(Activity $act, Notice $stored, array $options=array()) protected function saveObjectFromActivity(Activity $act, Notice $stored, array $options=array())
{ {
assert($this->isMyActivity($act)); assert($this->isMyActivity($act));
@ -263,7 +264,7 @@ class FavoritePlugin extends ActivityHandlerPlugin
} }
return true; return true;
} }
public function onNoticeDeleteRelated(Notice $notice) public function onNoticeDeleteRelated(Notice $notice)
{ {
parent::onNoticeDeleteRelated($notice); parent::onNoticeDeleteRelated($notice);
@ -503,6 +504,62 @@ class FavoritePlugin extends ActivityHandlerPlugin
} }
} }
protected function getActionTitle(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
return Fave::existsForProfile($target, $scoped)
// TRANS: Page/dialog box title when a notice is marked as favorite already
? _m('TITLE', 'Unmark notice as favorite')
// TRANS: Page/dialog box title when a notice is not marked as favorite
: _m('TITLE', 'Mark notice as favorite');
}
protected function doActionPreparation(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
if ($action->isPost()) {
// The below tests are only for presenting to the user. POSTs which inflict
// duplicate favorite entries are handled with AlreadyFulfilledException.
return false;
}
$exists = Fave::existsForProfile($target, $scoped);
$expected_verb = $exists ? ActivityVerb::UNFAVORITE : ActivityVerb::FAVORITE;
switch (true) {
case $exists && ActivityUtils::compareTypes($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)):
case !$exists && ActivityUtils::compareTypes($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)):
common_redirect(common_local_url('activityverb',
array('id' => $target->getID(),
'verb' => ActivityUtils::resolveUri($expected_verb, true))));
break;
default:
// No need to redirect as we are on the correct action already.
}
return false;
}
protected function doActionPost(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
switch (true) {
case ActivityUtils::compareTypes($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)):
Fave::addNew($scoped, $target);
break;
case ActivityUtils::compareTypes($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)):
Fave::removeEntry($scoped, $target);
break;
default:
throw new ServerException('ActivityVerb POST not handled by plugin that was supposed to do it.');
}
return false;
}
protected function getActivityForm(ManagedAction $action, $verb, Notice $target, Profile $scoped)
{
return Fave::existsForProfile($target, $scoped)
? new DisfavorForm($action, $target)
: new FavorForm($action, $target);
}
public function onPluginVersion(array &$versions) public function onPluginVersion(array &$versions)
{ {
$versions[] = array('name' => 'Favorite', $versions[] = array('name' => 'Favorite',

View File

@ -1,84 +0,0 @@
<?php
/**
* Disfavor action.
*
* PHP version 5
*
* @category Action
* @package GNUsocial
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://www.gnu.org/software/social/
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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 <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* DisfavorAction class.
*
* @category Action
* @package GNUsocial
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://www.gnu.org/software/social/
*/
class DisfavorAction extends FormAction
{
protected $needPost = true;
protected function doPreparation()
{
$this->target = Notice::getKV($this->trimmed('notice'));
if (!$this->target instanceof Notice) {
throw new ServerException(_m('No such notice.'));
}
}
protected function doPost()
{
$fave = new Fave();
$fave->user_id = $this->scoped->getID();
$fave->notice_id = $this->target->getID();
if (!$fave->find(true)) {
// TRANS: Client error displayed when trying to remove a 'favor' when there is none in the first place.
throw new AlreadyFulfilledException(_('This is already not favorited.'));
}
$result = $fave->delete();
if ($result === false) {
common_log_db_error($fave, 'DELETE', __FILE__);
// TRANS: Server error displayed when removing a favorite from the database fails.
throw new ServerException(_('Could not delete favorite.'));
}
Fave::blowCacheForProfileId($this->scoped->getID());
// TRANS: Message when a disfavor action has been taken for a notice.
return _('Disfavored the notice.');
}
protected function showContent()
{
// We show the 'Favor' form because right now all calls to Disfavor will directly disfavor a notice.
$disfavor = new FavorForm($this, $this->target);
$disfavor->show();
}
}

View File

@ -1,76 +0,0 @@
<?php
/**
* Favor action.
*
* PHP version 5
*
* @category Action
* @package GNUsocial
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://www.gnu.org/software/social/
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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 <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* FavorAction class.
*
* @category Action
* @package GNUsocial
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://www.gnu.org/software/social/
*/
class FavorAction extends FormAction
{
protected $needPost = true;
protected function doPreparation()
{
$this->target = Notice::getKV($this->trimmed('notice'));
if (!$this->target instanceof Notice) {
throw new ServerException(_m('No such notice.'));
}
if (!$this->target->inScope($this->scoped)) {
// TRANS: Client error displayed when trying to interact with a notice a the target has no access to.
// TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
throw new ClientException(sprintf(_m('%1$s has no right to interact with notice %2$d.'), $this->scoped->getNickname(), $this->target->getID()), 403);
}
}
protected function doPost()
{
// throws exception on failure, might be an AlreadyFulfilledException
$stored = Fave::addNew($this->scoped, $this->target);
// TRANS: Message when a favor action has been taken for a notice.
return _('Favorited the notice');
}
protected function showContent()
{
$disfavor = new DisfavorForm($this, $this->target);
$disfavor->show();
}
}

View File

@ -79,6 +79,27 @@ class Fave extends Managed_DataObject
return $stored; return $stored;
} }
public function removeEntry(Profile $actor, Notice $target)
{
$fave = new Fave();
$fave->user_id = $actor->getID();
$fave->notice_id = $target->getID();
if (!$fave->find(true)) {
// TRANS: Client error displayed when trying to remove a 'favor' when there is none in the first place.
throw new AlreadyFulfilledException(_('This is already not favorited.'));
}
$result = $fave->delete();
if ($result === false) {
common_log_db_error($fave, 'DELETE', __FILE__);
// TRANS: Server error displayed when removing a favorite from the database fails.
throw new ServerException(_('Could not delete favorite.'));
}
Fave::blowCacheForProfileId($actor->getID());
Fave::blowCacheForNoticeId($target->getID());
}
// exception throwing takeover! // exception throwing takeover!
public function insert() public function insert()
{ {

View File

@ -81,7 +81,9 @@ class DisfavorForm extends Form
*/ */
function action() function action()
{ {
return common_local_url('disfavor'); return common_local_url('activityverb',
array('id' => $this->notice->getID(),
'verb' => ActivityUtils::resolveUri(ActivityVerb::UNFAVORITE, true)));
} }
/** /**

View File

@ -81,7 +81,9 @@ class FavorForm extends Form
*/ */
function action() function action()
{ {
return common_local_url('favor'); return common_local_url('activityverb',
array('id' => $this->notice->getID(),
'verb' => ActivityUtils::resolveUri(ActivityVerb::FAVORITE, true)));
} }
/** /**