1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* T3Bot. |
4
|
|
|
* |
5
|
|
|
* @author Frank Nägler <[email protected]> |
6
|
|
|
* |
7
|
|
|
* @link http://www.t3bot.de |
8
|
|
|
* @link http://wiki.typo3.org/T3Bot |
9
|
|
|
*/ |
10
|
|
|
namespace T3Bot\Commands; |
11
|
|
|
|
12
|
|
|
use /* @noinspection PhpInternalEntityUsedInspection */ Doctrine\DBAL\Configuration; |
13
|
|
|
use Doctrine\DBAL\Connection; |
14
|
|
|
use Doctrine\DBAL\DriverManager; |
15
|
|
|
use Slack\DataObject; |
16
|
|
|
use Slack\Message\Attachment; |
17
|
|
|
use Slack\Payload; |
18
|
|
|
use Slack\RealTimeClient; |
19
|
|
|
use T3Bot\Slack\Message; |
20
|
|
|
use T3Bot\Traits\ForgerTrait; |
21
|
|
|
use T3Bot\Traits\GerritTrait; |
22
|
|
|
use T3Bot\Traits\SlackTrait; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Class AbstractCommand. |
26
|
|
|
* |
27
|
|
|
* @property string commandName |
28
|
|
|
* @property array helpCommands |
29
|
|
|
*/ |
30
|
|
|
abstract class AbstractCommand |
31
|
|
|
{ |
32
|
|
|
use SlackTrait, ForgerTrait, GerritTrait; |
33
|
|
|
|
34
|
|
|
const PROJECT_PHASE_DEVELOPMENT = 'development'; |
35
|
|
|
const PROJECT_PHASE_STABILISATION = 'stabilisation'; |
36
|
|
|
const PROJECT_PHASE_SOFT_FREEZE = 'soft_freeze'; |
37
|
|
|
const PROJECT_PHASE_CODE_FREEZE = 'code_freeze'; |
38
|
|
|
const PROJECT_PHASE_FEATURE_FREEZE = 'feature_freeze'; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var string |
42
|
|
|
*/ |
43
|
|
|
protected $commandName; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var array |
47
|
|
|
*/ |
48
|
|
|
protected $helpCommands = []; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var array |
52
|
|
|
*/ |
53
|
|
|
protected $params = []; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var Payload |
57
|
|
|
*/ |
58
|
|
|
protected $payload; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var RealTimeClient |
62
|
|
|
*/ |
63
|
|
|
protected $client; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var array |
67
|
|
|
*/ |
68
|
|
|
protected $configuration; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var Connection |
72
|
|
|
*/ |
73
|
|
|
protected $databaseConnection; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* AbstractCommand constructor. |
77
|
|
|
* |
78
|
|
|
* @param Payload $payload |
79
|
|
|
* @param RealTimeClient $client |
80
|
|
|
* @param array $configuration |
81
|
|
|
*/ |
82
|
102 |
|
public function __construct(Payload $payload, RealTimeClient $client, array $configuration = null) |
83
|
|
|
{ |
84
|
102 |
|
$this->payload = $payload; |
85
|
102 |
|
$this->client = $client; |
86
|
102 |
|
$this->configuration = $configuration; |
|
|
|
|
87
|
102 |
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* |
91
|
|
|
*/ |
92
|
46 |
|
public function process() |
93
|
|
|
{ |
94
|
46 |
|
$commandParts = explode(':', $this->payload->getData()['text']); |
95
|
46 |
|
$params = []; |
96
|
46 |
|
if (!empty($commandParts[1])) { |
97
|
46 |
|
array_shift($commandParts); |
98
|
46 |
|
$params = explode(' ', preg_replace('/\s+/', ' ', implode(':', $commandParts))); |
99
|
|
|
} |
100
|
|
|
|
101
|
46 |
|
$command = !empty($params[0]) ? $params[0] : 'help'; |
102
|
46 |
|
$this->params = $params; |
103
|
46 |
|
$method = 'process' . ucfirst(strtolower($command)); |
104
|
46 |
|
if (method_exists($this, $method)) { |
105
|
45 |
|
return $this->{$method}(); |
106
|
|
|
} |
107
|
|
|
|
108
|
1 |
|
return $this->getHelp(); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @param Message|string $messageToSent |
113
|
|
|
* @param string $user |
114
|
|
|
* @param string $channel the channel id |
115
|
|
|
*/ |
116
|
2 |
|
public function sendResponse($messageToSent, $user = null, $channel = null) |
117
|
|
|
{ |
118
|
2 |
|
if ($user !== null) { |
119
|
|
|
$this->client->apiCall('im.open', ['user' => $user]) |
120
|
|
|
->then(function (Payload $response) use ($messageToSent) { |
121
|
|
|
$channel = $response->getData()['channel']['id']; |
122
|
|
|
$this->postMessage($messageToSent, $channel); |
123
|
|
|
}); |
124
|
|
|
} else { |
125
|
2 |
|
$channel = $channel ?? $this->payload->getData()['channel']; |
126
|
2 |
|
$this->postMessage($messageToSent, $channel); |
127
|
|
|
} |
128
|
2 |
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* generate help. |
132
|
|
|
* |
133
|
|
|
* @return string |
134
|
|
|
*/ |
135
|
1 |
|
public function getHelp() : string |
136
|
|
|
{ |
137
|
1 |
|
$result = "*HELP*\n"; |
138
|
1 |
|
foreach ($this->helpCommands as $command => $helpText) { |
139
|
1 |
|
$result .= "*{$this->commandName}:{$command}*: {$helpText} \n"; |
140
|
|
|
} |
141
|
|
|
|
142
|
1 |
|
return $result; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* build a review message. |
147
|
|
|
* |
148
|
|
|
* @param \stdClass $item the review item |
149
|
|
|
* |
150
|
|
|
* @return Message |
151
|
|
|
*/ |
152
|
12 |
|
protected function buildReviewMessage($item) : Message |
153
|
|
|
{ |
154
|
12 |
|
$created = substr($item->created, 0, 19); |
155
|
12 |
|
$branch = $item->branch; |
156
|
12 |
|
$text = ''; |
157
|
|
|
|
158
|
12 |
|
$message = new Message(); |
159
|
12 |
|
$attachment = new Message\Attachment(); |
160
|
12 |
|
switch ($this->configuration['projectPhase']) { |
161
|
12 |
|
case self::PROJECT_PHASE_STABILISATION: |
162
|
1 |
|
$attachment->setColor(Message\Attachment::COLOR_WARNING); |
163
|
1 |
|
$attachment->setPretext(':warning: *stabilisation phase*'); |
164
|
1 |
|
break; |
165
|
11 |
|
case self::PROJECT_PHASE_SOFT_FREEZE: |
166
|
1 |
|
$attachment->setColor(Message\Attachment::COLOR_DANGER); |
167
|
1 |
|
$attachment->setPretext(':no_entry: *soft merge freeze*'); |
168
|
1 |
|
break; |
169
|
10 |
|
case self::PROJECT_PHASE_CODE_FREEZE: |
170
|
1 |
|
$attachment->setColor(Message\Attachment::COLOR_DANGER); |
171
|
1 |
|
$attachment->setPretext(':no_entry: *merge freeze*'); |
172
|
1 |
|
break; |
173
|
9 |
|
case self::PROJECT_PHASE_FEATURE_FREEZE: |
174
|
1 |
|
$attachment->setColor(Message\Attachment::COLOR_DANGER); |
175
|
1 |
|
$attachment->setPretext(':no_entry: *FEATURE FREEZE*'); |
176
|
1 |
|
break; |
177
|
8 |
|
case self::PROJECT_PHASE_DEVELOPMENT: |
178
|
|
|
default: |
179
|
8 |
|
$attachment->setColor(Message\Attachment::COLOR_NOTICE); |
180
|
8 |
|
break; |
181
|
|
|
} |
182
|
12 |
|
$attachment->setTitle($item->subject); |
183
|
12 |
|
$attachment->setTitleLink('https://review.typo3.org/' . $item->_number); |
184
|
|
|
|
185
|
12 |
|
$text .= 'Branch: ' . $this->bold($branch) . ' | :calendar: ' . $this->bold($created) |
186
|
12 |
|
. ' | ID: ' . $this->bold($item->_number) . "\n"; |
187
|
12 |
|
$text .= '<https://review.typo3.org/' . $item->_number . '|:arrow_right: Goto Review>'; |
188
|
|
|
|
189
|
12 |
|
$attachment->setText($text); |
190
|
12 |
|
$attachment->setFallback($text); |
191
|
12 |
|
$message->setText(' '); |
192
|
12 |
|
$message->addAttachment($attachment); |
193
|
|
|
|
194
|
12 |
|
return $message; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @param string $text |
199
|
|
|
* @param string $channel |
200
|
|
|
* |
201
|
|
|
* @return array |
202
|
|
|
*/ |
203
|
2 |
|
protected function getBaseDataArray(string $text, string $channel) : array |
204
|
|
|
{ |
205
|
2 |
|
$data = []; |
206
|
2 |
|
$data['unfurl_links'] = false; |
207
|
2 |
|
$data['unfurl_media'] = false; |
208
|
2 |
|
$data['parse'] = 'none'; |
209
|
2 |
|
$data['text'] = $text; |
210
|
2 |
|
$data['channel'] = $channel; |
211
|
2 |
|
return $data; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* @param Message\Attachment $attachment |
216
|
|
|
* |
217
|
|
|
* @return DataObject |
218
|
|
|
*/ |
219
|
1 |
|
protected function buildAttachment(Message\Attachment $attachment) : DataObject |
220
|
|
|
{ |
221
|
1 |
|
return Attachment::fromData([ |
222
|
1 |
|
'title' => $attachment->getTitle(), |
223
|
1 |
|
'title_link' => $attachment->getTitleLink(), |
224
|
1 |
|
'text' => $attachment->getText(), |
225
|
1 |
|
'fallback' => $attachment->getFallback(), |
226
|
1 |
|
'color' => $attachment->getColor(), |
227
|
1 |
|
'pretext' => $attachment->getPretext(), |
228
|
1 |
|
'author_name' => $attachment->getAuthorName(), |
229
|
1 |
|
'author_icon' => $attachment->getAuthorIcon(), |
230
|
1 |
|
'author_link' => $attachment->getAuthorLink(), |
231
|
1 |
|
'image_url' => $attachment->getImageUrl(), |
232
|
1 |
|
'thumb_url' => $attachment->getThumbUrl(), |
233
|
|
|
]); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param Message|string $messageToSent |
238
|
|
|
* @param string $channel |
239
|
|
|
*/ |
240
|
2 |
|
protected function postMessage($messageToSent, string $channel) |
241
|
|
|
{ |
242
|
2 |
|
if ($messageToSent instanceof Message) { |
243
|
1 |
|
$data = $this->getBaseDataArray($messageToSent->getText(), $channel); |
244
|
1 |
|
$attachments = $messageToSent->getAttachments(); |
245
|
1 |
|
if (count($attachments)) { |
246
|
1 |
|
$data['attachments'] = []; |
247
|
|
|
} |
248
|
1 |
|
foreach ($attachments as $attachment) { |
249
|
1 |
|
$data['attachments'][] = $this->buildAttachment($attachment); |
250
|
|
|
} |
251
|
1 |
|
$message = new \Slack\Message\Message($this->client, $data); |
252
|
1 |
|
$this->client->postMessage($message); |
253
|
1 |
|
} elseif (is_string($messageToSent)) { |
254
|
1 |
|
$data = $this->getBaseDataArray($messageToSent, $channel); |
255
|
1 |
|
$data['as_user'] = true; |
256
|
1 |
|
$this->client->apiCall('chat.postMessage', $data); |
257
|
|
|
} |
258
|
2 |
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* @return Connection |
262
|
|
|
* |
263
|
|
|
* @throws \Doctrine\DBAL\DBALException |
264
|
|
|
*/ |
265
|
11 |
|
protected function getDatabaseConnection() : Connection |
266
|
|
|
{ |
267
|
11 |
|
if ($this->databaseConnection === null) { |
268
|
11 |
|
$config = new Configuration(); |
269
|
11 |
|
$this->databaseConnection = DriverManager::getConnection($this->configuration['db'], $config); |
270
|
|
|
} |
271
|
11 |
|
return $this->databaseConnection; |
272
|
|
|
} |
273
|
|
|
} |
274
|
|
|
|
Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.
To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.