Passed
Push — master ( a84c2d...e6338b )
by Alexey
04:17
created

PrivateMessageProcessor::createResponseMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 6
cp 0
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 3
crap 2

1 Method

Rating   Name   Duplication   Size   Complexity  
A PrivateMessageProcessor::sendPlainTextMessage() 0 4 1
1
<?php
2
3
namespace Skobkin\Bundle\PointToolsBundle\Service\Telegram;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Skobkin\Bundle\PointToolsBundle\Entity\Telegram\Account;
7
use Skobkin\Bundle\PointToolsBundle\Entity\User;
8
use Skobkin\Bundle\PointToolsBundle\Exception\Telegram\CommandProcessingException;
9
use Skobkin\Bundle\PointToolsBundle\Repository\SubscriptionEventRepository;
10
use Skobkin\Bundle\PointToolsBundle\Repository\SubscriptionRepository;
11
use Skobkin\Bundle\PointToolsBundle\Repository\UserRepository;
12
use Skobkin\Bundle\PointToolsBundle\Service\Factory\Telegram\AccountFactory;
13
use Skobkin\Bundle\PointToolsBundle\Service\UserApi;
14
use unreal4u\TelegramAPI\Telegram\Types\Message;
15
use unreal4u\TelegramAPI\Telegram\Types\ReplyKeyboardMarkup;
16
17
/**
18
 * Processes all private messages
19
 */
20
class PrivateMessageProcessor
21
{
22
    /**
23
     * @var MessageSender
24
     */
25
    private $messenger;
26
27
    /**
28
     * @var UserApi
29
     */
30
    private $userApi;
31
32
    /**
33
     * @var AccountFactory
34
     */
35
    private $accountFactory;
36
37
    /**
38
     * @var EntityManagerInterface
39
     */
40
    private $em;
41
42
    /**
43
     * @var \Twig_Environment
44
     */
45
    private $twig;
46
47
    /**
48
     * @var UserRepository
49
     */
50
    private $userRepo;
51
52
    /**
53
     * @var SubscriptionRepository
54
     */
55
    private $subscriptionRepo;
56
57
    /**
58
     * @var SubscriptionEventRepository
59
     */
60
    private $subscriptionEventRepo;
61
62
    /**
63
     * @var int
64
     */
65
    private $pointUserId;
66
67
68
    public function __construct(
69
        MessageSender $messageSender,
70
        UserApi $userApi,
71
        AccountFactory $accountFactory,
72
        EntityManagerInterface $em,
73
        \Twig_Environment $twig,
74
        int $pointUserId
75
    )
76
    {
77
        $this->messenger = $messageSender;
78
        $this->userApi = $userApi;
79
        $this->accountFactory = $accountFactory;
80
        $this->em = $em;
81
        $this->twig = $twig;
82
        $this->pointUserId = $pointUserId;
83
84
        $this->userRepo = $em->getRepository('SkobkinPointToolsBundle:User');
85
        $this->subscriptionRepo = $em->getRepository('SkobkinPointToolsBundle:Subscription');
86
        $this->subscriptionEventRepo = $em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent');
87
    }
88
89
    public function process(Message $message)
90
    {
91
        if (!IncomingUpdateDispatcher::CHAT_TYPE_PRIVATE === $message->chat->type) {
92
            throw new \LogicException('This service can process only private chat messages');
93
        }
94
95
        try {
96
            // Registering Telegram user
97
            /** @var Account $account */
98
            $account = $this->accountFactory->findOrCreateFromMessage($message);
99
            $this->em->flush();
100
        } catch (\Exception $e) {
101
            // Low-level message in case of incorrect $account
102
            $this->messenger->sendMessageToChat($message->chat->id, 'There was an error during your Telegram account registration. Try again or report the bug.');
103
        }
104
105
        try {
106
            $words = explode(' ', $message->text, 10);
107
108
            if (0 === count($words)) {
109
                return;
110
            }
111
112
            switch ($words[0]) {
113
                case '/link':
114
                case 'link':
115
                    if (array_key_exists(2, $words)) {
116
                        if ($this->linkAccount($account, $words[1], $words[2])) {
117
                            // Saving linking status
118
                            $this->em->flush();
119
                            $this->sendAccountLinked($account);
120
                        } else {
121
                            $this->sendError($account, 'Account linking error', 'Check login and password or try again later.');
122
                        }
123
                    } else {
124
                        $this->sendError($account, 'Login/Password error', 'You need to specify login and password separated by space after /link (example: `/link mylogin MypASSw0rd`)');
125
                    }
126
                    break;
127
128
                case '/me':
129
                case 'me':
130
                    if ($user = $account->getUser()) {
131
                        $this->sendUserEvents($account, $user);
132
                    } else {
133
                        $this->sendError($account, 'Account not linked', 'You must /link your account first to be able to use this command.');
134
                    }
135
                    break;
136
137
                case '/last':
138
                case 'last':
139
                    if (array_key_exists(1, $words)) {
140 View Code Duplication
                        if (null !== $user = $this->userRepo->findUserByLogin($words[1])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141
                            $this->sendUserEvents($account, $user);
142
                        } else {
143
                            $this->sendError($account, 'User not found');
144
                        }
145
                    } else {
146
                        $this->sendGlobalEvents($account);
147
                    }
148
149
                    break;
150
151
                case '/sub':
152
                case 'sub':
153
                    if (array_key_exists(1, $words)) {
154 View Code Duplication
                        if (null !== $user = $this->userRepo->findUserByLogin($words[1])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
                            $this->sendUserSubscribers($account, $user);
156
                        } else {
157
                            $this->sendError($account, 'User not found');
158
                        }
159
                    } else {
160
                        if ($user = $account->getUser()) {
161
                            $this->sendUserSubscribers($account, $user);
162
                        } else {
163
                            $this->sendError($account, 'Account not linked', 'You must /link your account first to be able to use this command.');
164
                        }
165
                    }
166
167
                    break;
168
169
                case '/stats':
170
                case 'stats':
171
                    $this->sendStats($account);
172
173
                    break;
174
175
                case '/help':
176
                default:
177
                    $this->sendHelp($account);
178
                    break;
179
            }
180
        } catch (CommandProcessingException $e) {
181
            $this->sendError($account, 'Processing error', $e->getMessage());
182
183
            if ($e->getPrevious()) {
184
                throw $e->getPrevious();
185
            }
186
        } catch (\Exception $e) {
187
            $this->sendError($account, 'Unknown error');
188
189
            throw $e;
190
        }
191
    }
192
193
    private function linkAccount(Account $account, string $login, string $password): bool
194
    {
195
        /** @var User $user */
196
        if (null === $user = $this->userRepo->findUserByLogin($login)) {
197
            throw new CommandProcessingException('User not found in Point Tools database. Please try again later.');
198
        }
199
200
        if ($this->userApi->isAuthDataValid($login, $password)) {
201
            $account->setUser($user);
202
203
            return true;
204
        }
205
206
        return false;
207
    }
208
209
    private function sendAccountLinked(Account $account)
210
    {
211
        $this->messenger->sendMessageToUser($account, 'Account linked. Try using /me now.');
212
    }
213
214
    private function sendUserSubscribers(Account $account, User $user)
215
    {
216
        $subscribers = [];
217
        foreach ($user->getSubscribers() as $subscription) {
218
            $subscribers[] = '@'.$subscription->getSubscriber()->getLogin();
219
        }
220
221
        $this->sendTemplatedMessage(
222
            $account,
223
            '@SkobkinPointTools/Telegram/user_subscribers.md.twig',
224
            [
225
                'user' => $user,
226
                'subscribers' => $subscribers,
227
            ]
228
        );
229
    }
230
231
    private function sendUserEvents(Account $account, User $user)
232
    {
233
        $events = $this->subscriptionEventRepo->getUserLastSubscribersEvents($user, 10);
234
235
        $this->sendTemplatedMessage(
236
            $account,
237
            '@SkobkinPointTools/Telegram/last_user_subscriptions.md.twig',
238
            [
239
                'user' => $user,
240
                'events' => $events,
241
            ]
242
        );
243
    }
244
245
    private function sendGlobalEvents(Account $account)
246
    {
247
        $events = $this->subscriptionEventRepo->getLastSubscriptionEvents(10);
248
249
        $this->sendTemplatedMessage($account, '@SkobkinPointTools/Telegram/last_global_subscriptions.md.twig', ['events' => $events]);
250
    }
251
252
    private function sendStats(Account $account)
253
    {
254
        $this->sendTemplatedMessage(
255
            $account,
256
            '@SkobkinPointTools/Telegram/stats.md.twig',
257
            [
258
                'total_users' => $this->userRepo->getUsersCount(),
259
                'active_users' => $this->subscriptionRepo->getUserSubscribersCountById($this->pointUserId),
260
                'today_events' => $this->subscriptionEventRepo->getLastDayEventsCount(),
261
            ]
262
        );
263
    }
264
265
    private function sendHelp(Account $account)
266
    {
267
        $this->sendTemplatedMessage($account, '@SkobkinPointTools/Telegram/help.md.twig');
268
    }
269
270
    private function sendError(Account $account, string $title, string $text = '')
271
    {
272
        $this->sendTemplatedMessage(
273
            $account,
274
            '@SkobkinPointTools/Telegram/error.md.twig',
275
            [
276
                'title' => $title,
277
                'text' => $text,
278
            ]
279
        );
280
    }
281
282
    private function sendTemplatedMessage(
283
        Account $account,
284
        string $template,
285
        array $templateData = [],
286
        ReplyKeyboardMarkup $keyboardMarkup = null,
287
        bool $disableWebPreview = true,
288
        string $format = MessageSender::PARSE_MODE_MARKDOWN
289
    ): bool
290
    {
291
        $text = $this->twig->render($template, $templateData);
292
293
        return $this->messenger->sendMessageToUser($account, $text, $format, $keyboardMarkup, $disableWebPreview, false);
294
    }
295
296
    private function sendPlainTextMessage(Account $account, string $text, ReplyKeyboardMarkup $keyboardMarkup = null, bool $disableWebPreview = true): bool
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
297
    {
298
        return $this->messenger->sendMessageToUser($account, $text, MessageSender::PARSE_MODE_NOPARSE, $keyboardMarkup, $disableWebPreview);
299
    }
300
}