Signed-off-by: Georg Ehrke <developer@georgehrke.com>pull/9942/head
parent
3ff3141a1e
commit
4aa4e4080c
@ -0,0 +1,78 @@ |
||||
/* Database selector on install page */ |
||||
form #selectPartStatForm { |
||||
text-align:center; |
||||
white-space: nowrap; |
||||
margin: 0; |
||||
} |
||||
|
||||
form #selectPartStatForm .info { |
||||
white-space: normal; |
||||
} |
||||
|
||||
form #selectPartStatForm input[type="radio"] { |
||||
display: none; |
||||
} |
||||
|
||||
form #selectPartStatForm input[type="radio"]:checked+label { |
||||
background-color: #e8e8e8; |
||||
} |
||||
|
||||
form #selectPartStatForm input[type="radio"]:checked ~ form fieldset#more_options { |
||||
display: none; |
||||
} |
||||
|
||||
form #selectPartStatForm label { |
||||
color: #000; |
||||
background-color: #f8f8f8; |
||||
position: static; |
||||
margin: 0 -3px 5px; |
||||
cursor:pointer; |
||||
border: 1px solid #ddd; |
||||
display: inline-block; |
||||
padding: 0; |
||||
line-height: normal; |
||||
vertical-align: middle; |
||||
text-align: center; |
||||
overflow: visible; |
||||
} |
||||
|
||||
form #selectPartStatForm label:first-of-type { |
||||
border-top-left-radius: 4px; |
||||
border-bottom-left-radius: 4px; |
||||
} |
||||
|
||||
form #selectPartStatForm label:last-of-type { |
||||
border-top-right-radius: 4px; |
||||
border-bottom-right-radius: 4px; |
||||
} |
||||
|
||||
form #selectPartStatForm label span { |
||||
cursor: pointer; |
||||
padding: 10px 20px; |
||||
display: block; |
||||
line-height: normal; |
||||
} |
||||
form #selectPartStatForm label.ui-state-hover, |
||||
form #selectPartStatForm label.ui-state-active { |
||||
color:#000; |
||||
background-color:#e8e8e8; |
||||
} |
||||
|
||||
form input[type="number"] { |
||||
width: 249px; |
||||
background: #fff; |
||||
color: #555; |
||||
cursor: text; |
||||
font-family: inherit; |
||||
-webkit-appearance: textfield; |
||||
-moz-appearance: textfield; |
||||
box-sizing: content-box; |
||||
border: none; |
||||
font-weight: 300; |
||||
} |
||||
|
||||
form input[type="submit"] { |
||||
display: block; |
||||
margin: 0 auto; |
||||
padding: 11px 20px 9px |
||||
} |
||||
@ -0,0 +1,3 @@ |
||||
// $(document).ready(function() {
|
||||
// $('#selectPartStatForm').buttonset();
|
||||
// });
|
||||
@ -0,0 +1,53 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
/** |
||||
* @copyright 2018, Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @author Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* 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/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\DAV\BackgroundJob; |
||||
|
||||
use OC\BackgroundJob\TimedJob; |
||||
use OCP\AppFramework\Utility\ITimeFactory; |
||||
use OCP\IDBConnection; |
||||
|
||||
class CleanupInvitationTokenJob extends TimedJob { |
||||
|
||||
/** @var IDBConnection */ |
||||
private $db; |
||||
|
||||
/** @var ITimeFactory */ |
||||
private $timeFactory; |
||||
|
||||
public function __construct(IDBConnection $db, ITimeFactory $timeFactory) { |
||||
$this->db = $db; |
||||
$this->timeFactory = $timeFactory; |
||||
|
||||
$this->setInterval(60 * 60 * 24); |
||||
} |
||||
|
||||
public function run($argument) { |
||||
$query = $this->db->getQueryBuilder(); |
||||
$query->delete('calendar_invitation_tokens') |
||||
->where($query->expr()->lt('expiration', |
||||
$query->createNamedParameter($this->timeFactory->getTime()))) |
||||
->execute(); |
||||
} |
||||
} |
||||
@ -0,0 +1,118 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2018, Georg Ehrke. |
||||
* |
||||
* @author Georg Ehrke <oc.list@georgehrke.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\DAV\CalDAV\InvitationResponse; |
||||
|
||||
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin; |
||||
use OCA\DAV\Connector\Sabre\CachingTree; |
||||
use OCA\DAV\Connector\Sabre\DavAclPlugin; |
||||
use OCA\DAV\Connector\Sabre\AnonymousOptionsPlugin; |
||||
use OCA\DAV\RootCollection; |
||||
use OCP\SabrePluginEvent; |
||||
use Sabre\DAV\Auth\Plugin; |
||||
use OCA\DAV\AppInfo\PluginManager; |
||||
use Sabre\VObject\ITip\Message; |
||||
|
||||
class InvitationResponseServer { |
||||
|
||||
/** @var \OCA\DAV\Connector\Sabre\Server */ |
||||
public $server; |
||||
|
||||
/** |
||||
* InvitationResponseServer constructor. |
||||
*/ |
||||
public function __construct() { |
||||
$baseUri = \OC::$WEBROOT . '/remote.php/dav/'; |
||||
$logger = \OC::$server->getLogger(); |
||||
$dispatcher = \OC::$server->getEventDispatcher(); |
||||
|
||||
$root = new RootCollection(); |
||||
$this->server = new \OCA\DAV\Connector\Sabre\Server(new CachingTree($root)); |
||||
|
||||
// Add maintenance plugin |
||||
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\MaintenancePlugin(\OC::$server->getConfig())); |
||||
|
||||
// Set URL explicitly due to reverse-proxy situations |
||||
$this->server->httpRequest->setUrl($baseUri); |
||||
$this->server->setBaseUri($baseUri); |
||||
|
||||
$this->server->addPlugin(new BlockLegacyClientPlugin(\OC::$server->getConfig())); |
||||
$this->server->addPlugin(new AnonymousOptionsPlugin()); |
||||
$this->server->addPlugin(new class() extends Plugin { |
||||
public function getCurrentPrincipal() { |
||||
return 'principals/system/public'; |
||||
} |
||||
}); |
||||
|
||||
// allow setup of additional auth backends |
||||
$event = new SabrePluginEvent($this->server); |
||||
$dispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event); |
||||
|
||||
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $logger)); |
||||
$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin()); |
||||
$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin()); |
||||
|
||||
// acl |
||||
$acl = new DavAclPlugin(); |
||||
$acl->principalCollectionSet = [ |
||||
'principals/users', 'principals/groups' |
||||
]; |
||||
$acl->defaultUsernamePath = 'principals/users'; |
||||
$this->server->addPlugin($acl); |
||||
|
||||
// calendar plugins |
||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin()); |
||||
$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin()); |
||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin()); |
||||
$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin()); |
||||
$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin()); |
||||
//$this->server->addPlugin(new \OCA\DAV\DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest())); |
||||
$this->server->addPlugin(new \OCA\DAV\CalDAV\Publishing\PublishPlugin( |
||||
\OC::$server->getConfig(), |
||||
\OC::$server->getURLGenerator() |
||||
)); |
||||
|
||||
// wait with registering these until auth is handled and the filesystem is setup |
||||
$this->server->on('beforeMethod', function () use ($root) { |
||||
// register plugins from apps |
||||
$pluginManager = new PluginManager( |
||||
\OC::$server, |
||||
\OC::$server->getAppManager() |
||||
); |
||||
foreach ($pluginManager->getAppPlugins() as $appPlugin) { |
||||
$this->server->addPlugin($appPlugin); |
||||
} |
||||
foreach ($pluginManager->getAppCollections() as $appCollection) { |
||||
$root->addChild($appCollection); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* @param Message $iTipMessage |
||||
* @return void |
||||
*/ |
||||
public function handleITipMessage(Message $iTipMessage) { |
||||
/** @var \OCA\DAV\CalDAV\Schedule\Plugin $schedulingPlugin */ |
||||
$schedulingPlugin = $this->server->getPlugin('caldav-schedule'); |
||||
$schedulingPlugin->scheduleLocalDelivery($iTipMessage); |
||||
} |
||||
} |
||||
@ -0,0 +1,236 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
/** |
||||
* @copyright 2018, Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @author Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* 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/>. |
||||
* |
||||
*/ |
||||
namespace OCA\DAV\Controller; |
||||
|
||||
use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; |
||||
use OCP\AppFramework\Controller; |
||||
use OCP\AppFramework\Http\TemplateResponse; |
||||
use OCP\AppFramework\Utility\ITimeFactory; |
||||
use OCP\IDBConnection; |
||||
use OCP\IRequest; |
||||
use Sabre\VObject\ITip\Message; |
||||
use Sabre\VObject\Reader; |
||||
|
||||
class InvitationResponseController extends Controller { |
||||
|
||||
/** @var IDBConnection */ |
||||
private $db; |
||||
|
||||
/** @var ITimeFactory */ |
||||
private $timeFactory; |
||||
|
||||
/** @var InvitationResponseServer */ |
||||
private $responseServer; |
||||
|
||||
/** |
||||
* InvitationResponseController constructor. |
||||
* |
||||
* @param string $appName |
||||
* @param IRequest $request |
||||
* @param IDBConnection $db |
||||
* @param ITimeFactory $timeFactory |
||||
* @param InvitationResponseServer $responseServer |
||||
*/ |
||||
public function __construct(string $appName, IRequest $request, |
||||
IDBConnection $db, ITimeFactory $timeFactory, |
||||
InvitationResponseServer $responseServer) { |
||||
parent::__construct($appName, $request); |
||||
$this->db = $db; |
||||
$this->timeFactory = $timeFactory; |
||||
$this->responseServer = $responseServer; |
||||
// Don't run `$server->exec()`, because we just need access to the |
||||
// fully initialized schedule plugin, but we don't want Sabre/DAV |
||||
// to actually handle and reply to the request |
||||
} |
||||
|
||||
/** |
||||
* @PublicPage |
||||
* @NoCSRFRequired |
||||
* |
||||
* @param string $token |
||||
* @return TemplateResponse |
||||
*/ |
||||
public function accept(string $token):TemplateResponse { |
||||
$row = $this->getTokenInformation($token); |
||||
if (!$row) { |
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [], 'guest'); |
||||
} |
||||
|
||||
$iTipMessage = $this->buildITipResponse($row, 'ACCEPTED'); |
||||
$this->responseServer->handleITipMessage($iTipMessage); |
||||
if ($iTipMessage->getScheduleStatus() === '1.2') { |
||||
return new TemplateResponse($this->appName, 'schedule-response-success', [], 'guest'); |
||||
} |
||||
|
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [ |
||||
'organizer' => $row['organizer'], |
||||
], 'guest'); |
||||
} |
||||
|
||||
/** |
||||
* @PublicPage |
||||
* @NoCSRFRequired |
||||
* |
||||
* @param string $token |
||||
* @return TemplateResponse |
||||
*/ |
||||
public function decline(string $token):TemplateResponse { |
||||
$row = $this->getTokenInformation($token); |
||||
if (!$row) { |
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [], 'guest'); |
||||
} |
||||
|
||||
$iTipMessage = $this->buildITipResponse($row, 'DECLINED'); |
||||
$this->responseServer->handleITipMessage($iTipMessage); |
||||
|
||||
if ($iTipMessage->getScheduleStatus() === '1.2') { |
||||
return new TemplateResponse($this->appName, 'schedule-response-success', [], 'guest'); |
||||
} |
||||
|
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [ |
||||
'organizer' => $row['organizer'], |
||||
], 'guest'); |
||||
} |
||||
|
||||
/** |
||||
* @PublicPage |
||||
* @NoCSRFRequired |
||||
* |
||||
* @param string $token |
||||
* @return TemplateResponse |
||||
*/ |
||||
public function options(string $token):TemplateResponse { |
||||
return new TemplateResponse($this->appName, 'schedule-response-options', [ |
||||
'token' => $token |
||||
], 'guest'); |
||||
} |
||||
|
||||
/** |
||||
* @PublicPage |
||||
* @NoCSRFRequired |
||||
* |
||||
* @param string $token |
||||
* |
||||
* @return TemplateResponse |
||||
*/ |
||||
public function processMoreOptionsResult(string $token):TemplateResponse { |
||||
$partstat = $this->request->getParam('partStat'); |
||||
$guests = (int) $this->request->getParam('guests'); |
||||
$comment = $this->request->getParam('comment'); |
||||
|
||||
$row = $this->getTokenInformation($token); |
||||
if (!$row || !\in_array($partstat, ['ACCEPTED', 'DECLINED', 'TENTATIVE'])) { |
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [], 'guest'); |
||||
} |
||||
|
||||
$iTipMessage = $this->buildITipResponse($row, $partstat, $guests, $comment); |
||||
$this->responseServer->handleITipMessage($iTipMessage); |
||||
if ($iTipMessage->getScheduleStatus() === '1.2') { |
||||
return new TemplateResponse($this->appName, 'schedule-response-success', [], 'guest'); |
||||
} |
||||
|
||||
return new TemplateResponse($this->appName, 'schedule-response-error', [ |
||||
'organizer' => $row['organizer'], |
||||
], 'guest'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $token |
||||
* @return array|null |
||||
*/ |
||||
private function getTokenInformation(string $token) { |
||||
$query = $this->db->getQueryBuilder(); |
||||
$query->select('*') |
||||
->from('calendar_invitation_tokens') |
||||
->where($query->expr()->eq('token', $query->createNamedParameter($token))); |
||||
$stmt = $query->execute(); |
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC); |
||||
|
||||
if(!$row) { |
||||
return null; |
||||
} |
||||
|
||||
$currentTime = $this->timeFactory->getTime(); |
||||
if (((int) $row['expiration']) < $currentTime) { |
||||
return null; |
||||
} |
||||
|
||||
return $row; |
||||
} |
||||
|
||||
/** |
||||
* @param array $row |
||||
* @param string $partStat participation status of attendee - SEE RFC 5545 |
||||
* @param int|null $guests |
||||
* @param string|null $comment |
||||
* @return Message |
||||
*/ |
||||
private function buildITipResponse(array $row, string $partStat, int $guests=null, |
||||
string $comment=null):Message { |
||||
$iTipMessage = new Message(); |
||||
$iTipMessage->uid = $row['uid']; |
||||
$iTipMessage->component = 'VEVENT'; |
||||
$iTipMessage->method = 'REPLY'; |
||||
$iTipMessage->sequence = $row['sequence']; |
||||
$iTipMessage->sender = $row['attendee']; |
||||
$iTipMessage->recipient = $row['organizer']; |
||||
|
||||
$message = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
VERSION:2.0 |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=%s:%s |
||||
ORGANIZER:%s |
||||
UID:%s |
||||
SEQUENCE:%s |
||||
REQUEST-STATUS:2.0;Success |
||||
%sEND:VEVENT |
||||
END:VCALENDAR |
||||
EOF; |
||||
|
||||
$vObject = Reader::read(vsprintf($message, [ |
||||
$partStat, $row['attendee'], $row['organizer'], |
||||
$row['uid'], $row['sequence'] ?? 0, $row['recurrenceid'] ?? '' |
||||
])); |
||||
$vEvent = $vObject->{'VEVENT'}; |
||||
/** @var \Sabre\VObject\Property\ICalendar\CalAddress $attendee */ |
||||
$attendee = $vEvent->{'ATTENDEE'}; |
||||
|
||||
$vEvent->DTSTAMP = date('Ymd\\THis\\Z', $this->timeFactory->getTime()); |
||||
|
||||
if ($comment) { |
||||
$attendee->add('X-RESPONSE-COMMENT', $comment); |
||||
$vEvent->add('COMMENT', $comment); |
||||
} |
||||
if ($guests) { |
||||
$attendee->add('X-NUM-GUESTS', $guests); |
||||
} |
||||
|
||||
$iTipMessage->message = $vObject; |
||||
|
||||
return $iTipMessage; |
||||
} |
||||
} |
||||
@ -0,0 +1,71 @@ |
||||
<?php |
||||
namespace OCA\DAV\Migration; |
||||
|
||||
use Doctrine\DBAL\Types\Type; |
||||
use OCP\DB\ISchemaWrapper; |
||||
use OCP\Migration\SimpleMigrationStep; |
||||
use OCP\Migration\IOutput; |
||||
|
||||
/** |
||||
* Auto-generated migration step: Please modify to your needs! |
||||
*/ |
||||
class Version1006Date20180619154313 extends SimpleMigrationStep { |
||||
|
||||
/** |
||||
* @param IOutput $output |
||||
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` |
||||
* @param array $options |
||||
* @return null|ISchemaWrapper |
||||
* @since 13.0.0 |
||||
*/ |
||||
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { |
||||
/** @var ISchemaWrapper $schema */ |
||||
$schema = $schemaClosure(); |
||||
|
||||
if (!$schema->hasTable('calendar_invitation_tokens')) { |
||||
$table = $schema->createTable('calendar_invitation_tokens'); |
||||
|
||||
$table->addColumn('id', Type::BIGINT, [ |
||||
'autoincrement' => true, |
||||
'notnull' => true, |
||||
'length' => 11, |
||||
'unsigned' => true, |
||||
]); |
||||
$table->addColumn('uid', Type::STRING, [ |
||||
'notnull' => true, |
||||
'length' => 255, |
||||
]); |
||||
$table->addColumn('recurrenceid', Type::STRING, [ |
||||
'notnull' => false, |
||||
'length' => 255, |
||||
]); |
||||
$table->addColumn('attendee', Type::STRING, [ |
||||
'notnull' => true, |
||||
'length' => 255, |
||||
]); |
||||
$table->addColumn('organizer', Type::STRING, [ |
||||
'notnull' => true, |
||||
'length' => 255, |
||||
]); |
||||
$table->addColumn('sequence', Type::BIGINT, [ |
||||
'notnull' => false, |
||||
'length' => 11, |
||||
'unsigned' => true, |
||||
]); |
||||
$table->addColumn('token', Type::STRING, [ |
||||
'notnull' => true, |
||||
'length' => 60, |
||||
]); |
||||
$table->addColumn('expiration', Type::BIGINT, [ |
||||
'notnull' => true, |
||||
'length' => 11, |
||||
'unsigned' => true, |
||||
]); |
||||
|
||||
$table->setPrimaryKey(['id'], 'calendar_invitation_tokens_id_idx'); |
||||
$table->addIndex(['token'], 'calendar_invitation_tokens_token_idx'); |
||||
|
||||
return $schema; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,7 @@ |
||||
<div class="update"> |
||||
<p class="message"><?php p($l->t('There was an error updating your attendance status.'));?></p>
|
||||
<p class="message"><?php p($l->t('Please contact the organizer directly.'));?></p>
|
||||
<?php if(isset($_['organizer'])): ?> |
||||
<p class="message"><a href="<?php p($_['organizer']) ?>"><?php p(substr($_['organizer'], 7)) ?></a></p>
|
||||
<?php endif; ?> |
||||
</div> |
||||
@ -0,0 +1,35 @@ |
||||
<?php |
||||
style('dav', 'schedule-response'); |
||||
//script('dav', 'schedule-response'); |
||||
?> |
||||
|
||||
<div class="update"> |
||||
<form action="" method="post"> |
||||
<fieldset id="partStat"> |
||||
<h2><?php p($l->t('Are you accepting the invitation?')); ?></h2>
|
||||
<div id="selectPartStatForm"> |
||||
<input type="radio" id="partStatAccept" name="partStat" value="ACCEPTED" checked /> |
||||
<label for="partStatAccept"> |
||||
<span><?php p($l->t('Accept')); ?></span>
|
||||
</label> |
||||
|
||||
<input type="radio" id="partStatTentative" name="partStat" value="TENTATIVE" /> |
||||
<label for="partStatTentative"> |
||||
<span><?php p($l->t('Tentative')); ?></span>
|
||||
</label> |
||||
|
||||
<input type="radio" class="declined" id="partStatDeclined" name="partStat" value="DECLINED" /> |
||||
<label for="partStatDeclined"> |
||||
<span><?php p($l->t('Decline')); ?></span>
|
||||
</label> |
||||
</div> |
||||
</fieldset> |
||||
<fieldset id="more_options"> |
||||
<input type="number" min="0" name="guests" placeholder="Guests" /> |
||||
<input type="text" name="comment" placeholder="Comment" /> |
||||
</fieldset> |
||||
<fieldset> |
||||
<input type="submit" value="<?php p($l->t('Save'));?>">
|
||||
</fieldset> |
||||
</form> |
||||
</div> |
||||
@ -0,0 +1,4 @@ |
||||
<div class="update" style="justify-content: space-around; display: flex;"> |
||||
<span class="icon icon-checkmark-white"></span> |
||||
<p class="message"><?php p($l->t('Your attendance was updated successfully.'));?></p>
|
||||
</div> |
||||
@ -0,0 +1,100 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
/** |
||||
* @copyright 2018, Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @author Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* 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/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\DAV\Tests\unit\BackgroundJob; |
||||
|
||||
use OCA\DAV\BackgroundJob\CleanupInvitationTokenJob; |
||||
use OCP\AppFramework\Utility\ITimeFactory; |
||||
use OCP\DB\QueryBuilder\IQueryBuilder; |
||||
use OCP\IDBConnection; |
||||
use Test\TestCase; |
||||
|
||||
class CleanupInvitationTokenJobTest extends TestCase { |
||||
|
||||
/** @var IDBConnection | \PHPUnit_Framework_MockObject_MockObject */ |
||||
private $dbConnection; |
||||
|
||||
/** @var ITimeFactory | \PHPUnit_Framework_MockObject_MockObject */ |
||||
private $timeFactory; |
||||
|
||||
/** @var \OCA\DAV\BackgroundJob\GenerateBirthdayCalendarBackgroundJob */ |
||||
private $backgroundJob; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->dbConnection = $this->createMock(IDBConnection::class); |
||||
$this->timeFactory = $this->createMock(ITimeFactory::class); |
||||
|
||||
$this->backgroundJob = new CleanupInvitationTokenJob( |
||||
$this->dbConnection, $this->timeFactory); |
||||
} |
||||
|
||||
public function testRun() { |
||||
$this->timeFactory->expects($this->once()) |
||||
->method('getTime') |
||||
->with() |
||||
->will($this->returnValue(1337)); |
||||
|
||||
$queryBuilder = $this->createMock(IQueryBuilder::class); |
||||
$expr = $this->createMock(\OCP\DB\QueryBuilder\IExpressionBuilder::class); |
||||
$stmt = $this->createMock(\Doctrine\DBAL\Driver\Statement::class); |
||||
|
||||
$this->dbConnection->expects($this->once()) |
||||
->method('getQueryBuilder') |
||||
->with() |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->method('expr') |
||||
->will($this->returnValue($expr)); |
||||
$queryBuilder->method('createNamedParameter') |
||||
->will($this->returnValueMap([ |
||||
[1337, \PDO::PARAM_STR, null, 'namedParameter1337'] |
||||
])); |
||||
|
||||
$expr->expects($this->once()) |
||||
->method('lt') |
||||
->with('expiration', 'namedParameter1337') |
||||
->will($this->returnValue('LT STATEMENT')); |
||||
|
||||
$this->dbConnection->expects($this->once()) |
||||
->method('getQueryBuilder') |
||||
->with() |
||||
->will($this->returnValue($queryBuilder)); |
||||
|
||||
$queryBuilder->expects($this->at(0)) |
||||
->method('delete') |
||||
->with('calendar_invitation_tokens') |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->expects($this->at(3)) |
||||
->method('where') |
||||
->with('LT STATEMENT') |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->expects($this->at(4)) |
||||
->method('execute') |
||||
->with() |
||||
->will($this->returnValue($stmt)); |
||||
|
||||
$this->backgroundJob->run([]); |
||||
} |
||||
} |
||||
@ -0,0 +1,455 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
/** |
||||
* @copyright 2018, Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @author Georg Ehrke <oc.list@georgehrke.com> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* 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/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\DAV\Tests\Unit\DAV\Controller; |
||||
|
||||
use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; |
||||
use OCA\DAV\CalDAV\Schedule\Plugin; |
||||
use OCA\DAV\Controller\InvitationResponseController; |
||||
use OCP\AppFramework\Http\TemplateResponse; |
||||
use OCP\AppFramework\Utility\ITimeFactory; |
||||
use OCP\DB\QueryBuilder\IQueryBuilder; |
||||
use OCP\IDBConnection; |
||||
use OCP\IRequest; |
||||
use Sabre\VObject\ITip\Message; |
||||
use Test\TestCase; |
||||
|
||||
class InvitationResponseControllerTest extends TestCase { |
||||
|
||||
/** @var InvitationResponseController */ |
||||
private $controller; |
||||
|
||||
/** @var IDBConnection|\PHPUnit_Framework_MockObject_MockObject */ |
||||
private $dbConnection; |
||||
|
||||
/** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ |
||||
private $request; |
||||
|
||||
/** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */ |
||||
private $timeFactory; |
||||
|
||||
/** @var InvitationResponseServer|\PHPUnit_Framework_MockObject_MockObject */ |
||||
private $responseServer; |
||||
|
||||
public function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->dbConnection = $this->createMock(IDBConnection::class); |
||||
$this->request = $this->createMock(IRequest::class); |
||||
$this->timeFactory = $this->createMock(ITimeFactory::class); |
||||
$this->responseServer = $this->getMockBuilder(InvitationResponseServer::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
|
||||
$this->controller = new InvitationResponseController( |
||||
'appName', |
||||
$this->request, |
||||
$this->dbConnection, |
||||
$this->timeFactory, |
||||
$this->responseServer |
||||
); |
||||
} |
||||
|
||||
public function testAccept() { |
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => null, |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => null, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 420000, |
||||
], 1337); |
||||
|
||||
$expected = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
VERSION:2.0 |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=ACCEPTED:mailto:attendee@foo.bar |
||||
ORGANIZER:mailto:organizer@foo.bar |
||||
UID:this-is-the-events-uid |
||||
SEQUENCE:0 |
||||
REQUEST-STATUS:2.0;Success |
||||
DTSTAMP:19700101T002217Z |
||||
END:VEVENT |
||||
END:VCALENDAR |
||||
|
||||
EOF; |
||||
$expected = preg_replace('~\R~u', "\r\n", $expected); |
||||
|
||||
$called = false; |
||||
$this->responseServer->expects($this->once()) |
||||
->method('handleITipMessage') |
||||
->will($this->returnCallback(function(Message $iTipMessage) use (&$called, $expected) { |
||||
$called = true; |
||||
$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid); |
||||
$this->assertEquals('VEVENT', $iTipMessage->component); |
||||
$this->assertEquals('REPLY', $iTipMessage->method); |
||||
$this->assertEquals(null, $iTipMessage->sequence); |
||||
$this->assertEquals('mailto:attendee@foo.bar', $iTipMessage->sender); |
||||
$this->assertEquals('mailto:organizer@foo.bar', $iTipMessage->recipient); |
||||
|
||||
$iTipMessage->scheduleStatus = '1.2;Message delivered locally'; |
||||
|
||||
$this->assertEquals($expected, $iTipMessage->message->serialize()); |
||||
})); |
||||
|
||||
|
||||
|
||||
$response = $this->controller->accept('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-success', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
$this->assertTrue($called); |
||||
} |
||||
|
||||
public function testAcceptSequence() { |
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => null, |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => 1337, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 420000, |
||||
], 1337); |
||||
|
||||
$expected = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
VERSION:2.0 |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=ACCEPTED:mailto:attendee@foo.bar |
||||
ORGANIZER:mailto:organizer@foo.bar |
||||
UID:this-is-the-events-uid |
||||
SEQUENCE:1337 |
||||
REQUEST-STATUS:2.0;Success |
||||
DTSTAMP:19700101T002217Z |
||||
END:VEVENT |
||||
END:VCALENDAR |
||||
|
||||
EOF; |
||||
$expected = preg_replace('~\R~u', "\r\n", $expected); |
||||
|
||||
$called = false; |
||||
$this->responseServer->expects($this->once()) |
||||
->method('handleITipMessage') |
||||
->will($this->returnCallback(function(Message $iTipMessage) use (&$called, $expected) { |
||||
$called = true; |
||||
$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid); |
||||
$this->assertEquals('VEVENT', $iTipMessage->component); |
||||
$this->assertEquals('REPLY', $iTipMessage->method); |
||||
$this->assertEquals(1337, $iTipMessage->sequence); |
||||
$this->assertEquals('mailto:attendee@foo.bar', $iTipMessage->sender); |
||||
$this->assertEquals('mailto:organizer@foo.bar', $iTipMessage->recipient); |
||||
|
||||
$iTipMessage->scheduleStatus = '1.2;Message delivered locally'; |
||||
|
||||
$this->assertEquals($expected, $iTipMessage->message->serialize()); |
||||
})); |
||||
|
||||
|
||||
|
||||
$response = $this->controller->accept('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-success', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
$this->assertTrue($called); |
||||
} |
||||
|
||||
public function testAcceptRecurrenceId() { |
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => "RECURRENCE-ID;TZID=Europe/Berlin:20180726T150000\n", |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => null, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 420000, |
||||
], 1337); |
||||
|
||||
$expected = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
VERSION:2.0 |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=ACCEPTED:mailto:attendee@foo.bar |
||||
ORGANIZER:mailto:organizer@foo.bar |
||||
UID:this-is-the-events-uid |
||||
SEQUENCE:0 |
||||
REQUEST-STATUS:2.0;Success |
||||
RECURRENCE-ID;TZID=Europe/Berlin:20180726T150000 |
||||
DTSTAMP:19700101T002217Z |
||||
END:VEVENT |
||||
END:VCALENDAR |
||||
|
||||
EOF; |
||||
$expected = preg_replace('~\R~u', "\r\n", $expected); |
||||
|
||||
$called = false; |
||||
$this->responseServer->expects($this->once()) |
||||
->method('handleITipMessage') |
||||
->will($this->returnCallback(function(Message $iTipMessage) use (&$called, $expected) { |
||||
$called = true; |
||||
$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid); |
||||
$this->assertEquals('VEVENT', $iTipMessage->component); |
||||
$this->assertEquals('REPLY', $iTipMessage->method); |
||||
$this->assertEquals(0, $iTipMessage->sequence); |
||||
$this->assertEquals('mailto:attendee@foo.bar', $iTipMessage->sender); |
||||
$this->assertEquals('mailto:organizer@foo.bar', $iTipMessage->recipient); |
||||
|
||||
$iTipMessage->scheduleStatus = '1.2;Message delivered locally'; |
||||
|
||||
$this->assertEquals($expected, $iTipMessage->message->serialize()); |
||||
})); |
||||
|
||||
|
||||
|
||||
$response = $this->controller->accept('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-success', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
$this->assertTrue($called); |
||||
} |
||||
|
||||
public function testAcceptTokenNotFound() { |
||||
$this->buildQueryExpects('TOKEN123', null, 1337); |
||||
|
||||
$response = $this->controller->accept('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-error', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
} |
||||
|
||||
public function testAcceptExpiredToken() { |
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => null, |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => null, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 42, |
||||
], 1337); |
||||
|
||||
$response = $this->controller->accept('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-error', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
} |
||||
|
||||
public function testDecline() { |
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => null, |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => null, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 420000, |
||||
], 1337); |
||||
|
||||
$expected = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
VERSION:2.0 |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=DECLINED:mailto:attendee@foo.bar |
||||
ORGANIZER:mailto:organizer@foo.bar |
||||
UID:this-is-the-events-uid |
||||
SEQUENCE:0 |
||||
REQUEST-STATUS:2.0;Success |
||||
DTSTAMP:19700101T002217Z |
||||
END:VEVENT |
||||
END:VCALENDAR |
||||
|
||||
EOF; |
||||
$expected = preg_replace('~\R~u', "\r\n", $expected); |
||||
|
||||
$called = false; |
||||
$this->responseServer->expects($this->once()) |
||||
->method('handleITipMessage') |
||||
->will($this->returnCallback(function(Message $iTipMessage) use (&$called, $expected) { |
||||
$called = true; |
||||
$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid); |
||||
$this->assertEquals('VEVENT', $iTipMessage->component); |
||||
$this->assertEquals('REPLY', $iTipMessage->method); |
||||
$this->assertEquals(null, $iTipMessage->sequence); |
||||
$this->assertEquals('mailto:attendee@foo.bar', $iTipMessage->sender); |
||||
$this->assertEquals('mailto:organizer@foo.bar', $iTipMessage->recipient); |
||||
|
||||
$iTipMessage->scheduleStatus = '1.2;Message delivered locally'; |
||||
|
||||
$this->assertEquals($expected, $iTipMessage->message->serialize()); |
||||
})); |
||||
|
||||
|
||||
|
||||
$response = $this->controller->decline('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-success', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
$this->assertTrue($called); |
||||
} |
||||
|
||||
public function testOptions() { |
||||
$response = $this->controller->options('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-options', $response->getTemplateName()); |
||||
$this->assertEquals(['token' => 'TOKEN123'], $response->getParams()); |
||||
} |
||||
|
||||
public function testProcessMoreOptionsResult() { |
||||
$this->request->expects($this->at(0)) |
||||
->method('getParam') |
||||
->with('partStat') |
||||
->will($this->returnValue('TENTATIVE')); |
||||
$this->request->expects($this->at(1)) |
||||
->method('getParam') |
||||
->with('guests') |
||||
->will($this->returnValue('7')); |
||||
$this->request->expects($this->at(2)) |
||||
->method('getParam') |
||||
->with('comment') |
||||
->will($this->returnValue('Foo bar Bli blub')); |
||||
|
||||
$this->buildQueryExpects('TOKEN123', [ |
||||
'id' => 0, |
||||
'uid' => 'this-is-the-events-uid', |
||||
'recurrenceid' => null, |
||||
'attendee' => 'mailto:attendee@foo.bar', |
||||
'organizer' => 'mailto:organizer@foo.bar', |
||||
'sequence' => null, |
||||
'token' => 'TOKEN123', |
||||
'expiration' => 420000, |
||||
], 1337); |
||||
|
||||
$expected = <<<EOF |
||||
BEGIN:VCALENDAR |
||||
VERSION:2.0 |
||||
PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN |
||||
METHOD:REPLY |
||||
BEGIN:VEVENT |
||||
ATTENDEE;PARTSTAT=TENTATIVE;X-RESPONSE-COMMENT=Foo bar Bli blub;X-NUM-GUEST |
||||
S=7:mailto:attendee@foo.bar |
||||
ORGANIZER:mailto:organizer@foo.bar |
||||
UID:this-is-the-events-uid |
||||
SEQUENCE:0 |
||||
REQUEST-STATUS:2.0;Success |
||||
DTSTAMP:19700101T002217Z |
||||
COMMENT:Foo bar Bli blub |
||||
END:VEVENT |
||||
END:VCALENDAR |
||||
|
||||
EOF; |
||||
$expected = preg_replace('~\R~u', "\r\n", $expected); |
||||
|
||||
$called = false; |
||||
$this->responseServer->expects($this->once()) |
||||
->method('handleITipMessage') |
||||
->will($this->returnCallback(function(Message $iTipMessage) use (&$called, $expected) { |
||||
$called = true; |
||||
$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid); |
||||
$this->assertEquals('VEVENT', $iTipMessage->component); |
||||
$this->assertEquals('REPLY', $iTipMessage->method); |
||||
$this->assertEquals(null, $iTipMessage->sequence); |
||||
$this->assertEquals('mailto:attendee@foo.bar', $iTipMessage->sender); |
||||
$this->assertEquals('mailto:organizer@foo.bar', $iTipMessage->recipient); |
||||
|
||||
$iTipMessage->scheduleStatus = '1.2;Message delivered locally'; |
||||
|
||||
$this->assertEquals($expected, $iTipMessage->message->serialize()); |
||||
})); |
||||
|
||||
|
||||
|
||||
$response = $this->controller->processMoreOptionsResult('TOKEN123'); |
||||
$this->assertInstanceOf(TemplateResponse::class, $response); |
||||
$this->assertEquals('schedule-response-success', $response->getTemplateName()); |
||||
$this->assertEquals([], $response->getParams()); |
||||
$this->assertTrue($called); |
||||
} |
||||
|
||||
private function buildQueryExpects($token, $return, $time) { |
||||
$queryBuilder = $this->createMock(IQueryBuilder::class); |
||||
$stmt = $this->createMock(\Doctrine\DBAL\Driver\Statement::class); |
||||
$expr = $this->createMock(\OCP\DB\QueryBuilder\IExpressionBuilder::class); |
||||
|
||||
$this->dbConnection->expects($this->once()) |
||||
->method('getQueryBuilder') |
||||
->with() |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->method('expr') |
||||
->will($this->returnValue($expr)); |
||||
$queryBuilder->method('createNamedParameter') |
||||
->will($this->returnValueMap([ |
||||
[$token, \PDO::PARAM_STR, null, 'namedParameterToken'] |
||||
])); |
||||
|
||||
$stmt->expects($this->once()) |
||||
->method('fetch') |
||||
->with(\PDO::FETCH_ASSOC) |
||||
->will($this->returnValue($return)); |
||||
|
||||
$expr->expects($this->once()) |
||||
->method('eq') |
||||
->with('token', 'namedParameterToken') |
||||
->will($this->returnValue('EQ STATEMENT')); |
||||
|
||||
$this->dbConnection->expects($this->once()) |
||||
->method('getQueryBuilder') |
||||
->with() |
||||
->will($this->returnValue($queryBuilder)); |
||||
|
||||
$queryBuilder->expects($this->at(0)) |
||||
->method('select') |
||||
->with('*') |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->expects($this->at(1)) |
||||
->method('from') |
||||
->with('calendar_invitation_tokens') |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->expects($this->at(4)) |
||||
->method('where') |
||||
->with('EQ STATEMENT') |
||||
->will($this->returnValue($queryBuilder)); |
||||
$queryBuilder->expects($this->at(5)) |
||||
->method('execute') |
||||
->with() |
||||
->will($this->returnValue($stmt)); |
||||
|
||||
$this->timeFactory->method('getTime') |
||||
->will($this->returnValue($time)); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue