1<?php
2/*
3 * vim:set softtabstop=4 shiftwidth=4 expandtab:
4 *
5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later)
6 * Copyright 2001 - 2020 Ampache.org
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 *
21 */
22
23declare(strict_types=1);
24
25namespace Ampache\Module\Application\PrivateMessage;
26
27use Ampache\Config\ConfigContainerInterface;
28use Ampache\Config\ConfigurationKeyEnum;
29use Ampache\MockeryTestCase;
30use Ampache\Repository\Model\PrivateMessageInterface;
31use Ampache\Module\Application\Exception\AccessDeniedException;
32use Ampache\Module\Authorization\AccessLevelEnum;
33use Ampache\Module\Authorization\GuiGatekeeperInterface;
34use Ampache\Module\Util\UiInterface;
35use Ampache\Repository\PrivateMessageRepositoryInterface;
36use Mockery\MockInterface;
37use Psr\Http\Message\ServerRequestInterface;
38
39class SetIsReadActionTest extends MockeryTestCase
40{
41    /** @var ConfigContainerInterface|MockInterface|null */
42    private MockInterface $configContainer;
43
44    /** @var UiInterface|MockInterface|null */
45    private MockInterface $ui;
46
47    /** @var PrivateMessageRepositoryInterface|MockInterface|null */
48    private MockInterface $privateMessageRepository;
49
50    private ?SetIsReadAction $subject;
51
52    public function setUp(): void
53    {
54        $this->configContainer          = $this->mock(ConfigContainerInterface::class);
55        $this->ui                       = $this->mock(UiInterface::class);
56        $this->privateMessageRepository = $this->mock(PrivateMessageRepositoryInterface::class);
57
58        $this->subject = new SetIsReadAction(
59            $this->configContainer,
60            $this->ui,
61            $this->privateMessageRepository
62        );
63    }
64
65    public function testRunThrowsExceptionIfAccessIsDenied(): void
66    {
67        $this->expectException(AccessDeniedException::class);
68
69        $request    = $this->mock(ServerRequestInterface::class);
70        $gatekeeper = $this->mock(GuiGatekeeperInterface::class);
71
72        $gatekeeper->shouldReceive('mayAccess')
73            ->with(AccessLevelEnum::TYPE_INTERFACE, AccessLevelEnum::LEVEL_USER)
74            ->once()
75            ->andReturnFalse();
76
77        $this->subject->run($request, $gatekeeper);
78    }
79
80    public function testRunThrowsExceptionIfSocialFeaturesAreDisabled(): void
81    {
82        $this->expectException(AccessDeniedException::class);
83
84        $request    = $this->mock(ServerRequestInterface::class);
85        $gatekeeper = $this->mock(GuiGatekeeperInterface::class);
86
87        $gatekeeper->shouldReceive('mayAccess')
88            ->with(AccessLevelEnum::TYPE_INTERFACE, AccessLevelEnum::LEVEL_USER)
89            ->once()
90            ->andReturnTrue();
91
92        $this->configContainer->shouldReceive('isFeatureEnabled')
93            ->with(ConfigurationKeyEnum::SOCIABLE)
94            ->once()
95            ->andReturnFalse();
96
97        $this->subject->run($request, $gatekeeper);
98    }
99
100    public function testRunReturnsNullIfDemoMode(): void
101    {
102        $request    = $this->mock(ServerRequestInterface::class);
103        $gatekeeper = $this->mock(GuiGatekeeperInterface::class);
104
105        $gatekeeper->shouldReceive('mayAccess')
106            ->with(AccessLevelEnum::TYPE_INTERFACE, AccessLevelEnum::LEVEL_USER)
107            ->once()
108            ->andReturnTrue();
109
110        $this->configContainer->shouldReceive('isFeatureEnabled')
111            ->with(ConfigurationKeyEnum::SOCIABLE)
112            ->once()
113            ->andReturnTrue();
114        $this->configContainer->shouldReceive('isFeatureEnabled')
115            ->with(ConfigurationKeyEnum::DEMO_MODE)
116            ->once()
117            ->andReturnTrue();
118
119        $this->assertNull(
120            $this->subject->run($request, $gatekeeper)
121        );
122    }
123
124    public function testRunThrowsExceptionIfAccessToMessageIsDenied(): void
125    {
126        $messageId = 666;
127
128        $this->expectException(AccessDeniedException::class);
129        $this->expectExceptionMessage(sprintf('Unknown or unauthorized private message `%d`.', $messageId));
130
131        $request    = $this->mock(ServerRequestInterface::class);
132        $gatekeeper = $this->mock(GuiGatekeeperInterface::class);
133        $message    = $this->mock(PrivateMessageInterface::class);
134
135        $gatekeeper->shouldReceive('mayAccess')
136            ->with(AccessLevelEnum::TYPE_INTERFACE, AccessLevelEnum::LEVEL_USER)
137            ->once()
138            ->andReturnTrue();
139        $gatekeeper->shouldReceive('getUserId')
140            ->withNoArgs()
141            ->once()
142            ->andReturn(456);
143
144        $this->configContainer->shouldReceive('isFeatureEnabled')
145            ->with(ConfigurationKeyEnum::SOCIABLE)
146            ->once()
147            ->andReturnTrue();
148        $this->configContainer->shouldReceive('isFeatureEnabled')
149            ->with(ConfigurationKeyEnum::DEMO_MODE)
150            ->once()
151            ->andReturnFalse();
152
153        $request->shouldReceive('getQueryParams')
154            ->withNoArgs()
155            ->once()
156            ->andReturn(['read' => 1, 'msgs' => implode(',', [$messageId, 42])]);
157
158        $this->privateMessageRepository->shouldReceive('getById')
159            ->with($messageId)
160            ->once()
161            ->andReturn($message);
162
163        $message->shouldReceive('getRecipientUserId')
164            ->withNoArgs()
165            ->once()
166            ->andReturn(123);
167
168        $this->subject->run($request, $gatekeeper);
169    }
170
171    public function testRunSetsReadMode(): void
172    {
173        $messageId = 666;
174        $userId    = 42;
175        $webPath   = 'some-path';
176
177        $request    = $this->mock(ServerRequestInterface::class);
178        $gatekeeper = $this->mock(GuiGatekeeperInterface::class);
179        $message    = $this->mock(PrivateMessageInterface::class);
180
181        $gatekeeper->shouldReceive('mayAccess')
182            ->with(AccessLevelEnum::TYPE_INTERFACE, AccessLevelEnum::LEVEL_USER)
183            ->once()
184            ->andReturnTrue();
185        $gatekeeper->shouldReceive('getUserId')
186            ->withNoArgs()
187            ->once()
188            ->andReturn($userId);
189
190        $this->configContainer->shouldReceive('isFeatureEnabled')
191            ->with(ConfigurationKeyEnum::SOCIABLE)
192            ->once()
193            ->andReturnTrue();
194        $this->configContainer->shouldReceive('isFeatureEnabled')
195            ->with(ConfigurationKeyEnum::DEMO_MODE)
196            ->once()
197            ->andReturnFalse();
198        $this->configContainer->shouldReceive('getWebPath')
199            ->withNoArgs()
200            ->once()
201            ->andReturn($webPath);
202
203        $request->shouldReceive('getQueryParams')
204            ->withNoArgs()
205            ->once()
206            ->andReturn(['read' => 1, 'msgs' => (string) $messageId]);
207
208        $this->privateMessageRepository->shouldReceive('getById')
209            ->with($messageId)
210            ->once()
211            ->andReturn($message);
212        $this->privateMessageRepository->shouldReceive('setIsRead')
213            ->with($messageId, 1)
214            ->once();
215
216        $message->shouldReceive('getRecipientUserId')
217            ->withNoArgs()
218            ->once()
219            ->andReturn($userId);
220
221        $this->ui->shouldReceive('showHeader')
222            ->withNoArgs()
223            ->once();
224        $this->ui->shouldReceive('showConfirmation')
225            ->with(
226                'No Problem',
227                'Message\'s state has been changed',
228                sprintf(
229                    '%s/browse.php?action=pvmsg',
230                    $webPath
231                )
232            )
233            ->once();
234        $this->ui->shouldReceive('showQueryStats')
235            ->withNoArgs()
236            ->once();
237        $this->ui->shouldReceive('showFooter')
238            ->withNoArgs()
239            ->once();
240
241        $this->subject->run($request, $gatekeeper);
242    }
243}
244