1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace bedezign\yii2\audit\commands; |
4
|
|
|
|
5
|
|
|
use bedezign\yii2\audit\Audit; |
6
|
|
|
use bedezign\yii2\audit\components\panels\Panel; |
7
|
|
|
use bedezign\yii2\audit\models\AuditEntry; |
8
|
|
|
use bedezign\yii2\audit\models\AuditError; |
9
|
|
|
use Yii; |
10
|
|
|
use yii\base\Exception; |
11
|
|
|
use yii\console\Controller; |
12
|
|
|
use yii\console\ExitCode; |
13
|
|
|
use yii\helpers\Console; |
14
|
|
|
use yii\helpers\Html; |
15
|
|
|
use yii\helpers\Url; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Task runner commands for Audit. |
19
|
|
|
* |
20
|
|
|
* @package bedezign\yii2\audit\commands |
21
|
|
|
*/ |
22
|
|
|
class AuditController extends Controller |
23
|
|
|
{ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var bool True to cleanup the AuditEntry. |
27
|
|
|
*/ |
28
|
|
|
public $entry; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var bool True to cleanup solo AuditEntry records (no trail/mail/error/javascript). |
32
|
|
|
*/ |
33
|
|
|
public $entrySolo; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var string|null Comma separated list of panels to cleanup. |
37
|
|
|
*/ |
38
|
|
|
public $panels; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var int|null Max age in days to cleanup, if null then the panel settings are used. |
42
|
|
|
*/ |
43
|
|
|
public $age; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @inheritdoc |
47
|
|
|
*/ |
48
|
|
|
public function options($actionID) |
49
|
|
|
{ |
50
|
|
|
return array_merge( |
51
|
|
|
parent::options($actionID), |
52
|
|
|
($actionID == 'cleanup') ? ['entry', 'entrySolo', 'panels', 'age'] : [] |
53
|
|
|
); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Cleanup the Audit data |
58
|
|
|
* |
59
|
|
|
* @return int |
60
|
|
|
*/ |
61
|
|
|
public function actionCleanup() |
62
|
|
|
{ |
63
|
|
|
/** @var Audit $audit */ |
64
|
|
|
$audit = Yii::$app->getModule(Audit::findModuleIdentifier()); |
65
|
|
|
if (!$audit) { |
66
|
|
|
$this->stderr('Unable to load the Audit Component. Please make sure it was added to your console configuration?'); |
67
|
|
|
return ExitCode::CONFIG; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
if ($this->panels === '') { |
71
|
|
|
$panels = []; |
72
|
|
|
} else { |
73
|
|
|
$panels = !empty($this->panels) ? explode(',', $this->panels) : array_keys($audit->panels); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
// summary |
77
|
|
|
$this->preCleanupSummary($this->entry, $this->entrySolo, $panels, $this->age); |
78
|
|
|
|
79
|
|
|
// confirm |
80
|
|
|
if ($this->confirm('Cleanup the above data?')) { |
81
|
|
|
// cleanup panels |
82
|
|
|
foreach ($panels as $id) { |
83
|
|
|
if (!$this->cleanupPanel($id, $this->age)) { |
84
|
|
|
$this->stdout("\nCleanup failed. The rest of the cleanups are canceled.\n", Console::FG_RED); |
85
|
|
|
return self::EXIT_CODE_ERROR; |
|
|
|
|
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
// cleanup audit_entry |
89
|
|
|
if ($this->entry) { |
90
|
|
|
if (!$this->cleanupEntry($this->age)) { |
91
|
|
|
$this->stdout("\nCleanup failed.\n", Console::FG_RED); |
92
|
|
|
return self::EXIT_CODE_ERROR; |
|
|
|
|
93
|
|
|
} |
94
|
|
|
} |
95
|
|
|
// cleanup solo audit_entry |
96
|
|
|
if ($this->entrySolo) { |
97
|
|
|
if (!$this->cleanupEntrySolo()) { |
98
|
|
|
$this->stdout("\nCleanup failed.\n", Console::FG_RED); |
99
|
|
|
return self::EXIT_CODE_ERROR; |
|
|
|
|
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
// success! |
103
|
|
|
$this->stdout("\nCleanup was successful.\n", Console::FG_GREEN); |
104
|
|
|
} |
105
|
|
|
return ExitCode::OK; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Displays a summary of the data and dates to clean |
110
|
|
|
* |
111
|
|
|
* @param bool $entry |
112
|
|
|
* @param bool $entrySolo |
113
|
|
|
* @param array $panels |
114
|
|
|
* @param int|null $maxAge |
115
|
|
|
*/ |
116
|
|
|
protected function preCleanupSummary($entry, $entrySolo, $panels, $maxAge) |
117
|
|
|
{ |
118
|
|
|
$audit = Audit::getInstance(); |
119
|
|
|
|
120
|
|
|
// heading |
121
|
|
|
$n = count($panels); |
122
|
|
|
$this->stdout("Total $n " . ($n === 1 ? 'cleanup' : 'cleanups') . " to be applied:\n", Console::FG_YELLOW); |
123
|
|
|
$this->stdout("\t" . 'DATA CLEANUP TO DATETIME' . "\n"); |
124
|
|
|
$this->stdout("\t" . '---------------------------------------------' . "\n"); |
125
|
|
|
|
126
|
|
|
// audit panels |
127
|
|
|
foreach ($panels as $id) { |
128
|
|
|
/** @var Panel $panel */ |
129
|
|
|
$panel = $audit->getPanel($id); |
130
|
|
|
$age = $maxAge !== null ? $maxAge : $panel->maxAge; |
131
|
|
|
$dots = str_repeat('.', 24 - strlen($id)); |
132
|
|
|
if ($age !== null) { |
133
|
|
|
$date = date('Y-m-d 23:59:59', strtotime("-$age days")); |
134
|
|
|
$this->stdout("\t" . $id . ' ' . $dots . ' ' . $date . "\n"); |
135
|
|
|
} else { |
136
|
|
|
$this->stdout("\t" . $id . ' ' . $dots . ' no maxAge, skipping' . "\n"); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
// audit entry |
141
|
|
|
if ($entry) { |
142
|
|
|
$maxAge = $maxAge !== null ? $maxAge : $audit->maxAge; |
143
|
|
|
$date = $maxAge !== null ? date('Y-m-d 23:59:59', strtotime("-$maxAge days")) : 'no maxAge, skipping'; |
144
|
|
|
$this->stdout("\t" . 'AuditEntry .............. ' . $date . "\n"); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
// audit entry solo |
148
|
|
|
if ($entrySolo) { |
149
|
|
|
$this->stdout("\t" . 'AuditEntry solo ......... ' . date('Y-m-d 23:59:59') . "\n"); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
$this->stdout("\n"); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Cleans the AuditEntry data |
157
|
|
|
* |
158
|
|
|
* @param $maxAge |
159
|
|
|
* @return bool |
160
|
|
|
*/ |
161
|
|
|
protected function cleanupEntry($maxAge) |
162
|
|
|
{ |
163
|
|
|
$maxAge = $maxAge !== null ? $maxAge : Audit::getInstance()->maxAge; |
164
|
|
|
if ($maxAge === null) { |
165
|
|
|
$this->stdout("\n*** skipped AuditEntry\n", Console::FG_PURPLE); |
166
|
|
|
return true; |
167
|
|
|
} |
168
|
|
|
$date = date('Y-m-d 23:59:59', strtotime("-$maxAge days")); |
169
|
|
|
$this->stdout("\n*** cleaning AuditEntry", Console::FG_YELLOW); |
170
|
|
|
$start = microtime(true); |
171
|
|
|
$count = AuditEntry::deleteAll(['<=', 'created', $date]); |
172
|
|
|
if ($count !== false) { |
173
|
|
|
$time = microtime(true) - $start; |
174
|
|
|
$this->stdout("\n*** cleaned AuditEntry (records: " . $count . ",time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN); |
175
|
|
|
return true; |
176
|
|
|
} |
177
|
|
|
$time = microtime(true) - $start; |
178
|
|
|
$this->stdout("\n*** failed to clean AuditEntry (time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_RED); |
179
|
|
|
return false; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Cleans the AuditEntry solo data (no trail/mail/error/javascript) |
184
|
|
|
* |
185
|
|
|
* @return bool |
186
|
|
|
*/ |
187
|
|
|
protected function cleanupEntrySolo() |
188
|
|
|
{ |
189
|
|
|
$this->stdout("\n*** cleaning AuditEntry solo", Console::FG_YELLOW); |
190
|
|
|
$start = microtime(true); |
191
|
|
|
$count = 0; |
192
|
|
|
foreach (AuditEntry::find()->each(100) as $auditEntry) { |
193
|
|
|
/** @var AuditEntry $auditEntry */ |
194
|
|
|
/** @var Audit $audit */ |
195
|
|
|
$audit = Yii::$app->getModule('audit'); |
196
|
|
|
$auditEntryCurrent = $audit->getEntry(); |
197
|
|
|
if ($auditEntryCurrent && $auditEntryCurrent->id == $auditEntry->id) { |
198
|
|
|
continue; |
199
|
|
|
} |
200
|
|
|
if (!$auditEntry->hasRelatedData()) { |
201
|
|
|
foreach ($auditEntry->data as $data) { |
202
|
|
|
$data->delete(); |
203
|
|
|
} |
204
|
|
|
try { |
205
|
|
|
$auditEntry->delete(); |
206
|
|
|
$count++; |
207
|
|
|
$this->stdout('.', Console::FG_CYAN); |
208
|
|
|
} catch (Exception $e) { |
|
|
|
|
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
$time = microtime(true) - $start; |
213
|
|
|
$this->stdout("\n*** cleaned AuditEntry (records: " . $count . ",time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN); |
214
|
|
|
return true; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Cleans the Panel data |
219
|
|
|
* |
220
|
|
|
* @param $id |
221
|
|
|
* @param $maxAge |
222
|
|
|
* @return bool |
223
|
|
|
*/ |
224
|
|
|
protected function cleanupPanel($id, $maxAge) |
225
|
|
|
{ |
226
|
|
|
/** @var Panel $panel */ |
227
|
|
|
$panel = Audit::getInstance()->getPanel($id); |
228
|
|
|
$age = $maxAge !== null ? $maxAge : $panel->maxAge; |
229
|
|
|
if ($age === null) { |
230
|
|
|
$this->stdout("\n*** skipped $id\n", Console::FG_PURPLE); |
231
|
|
|
return true; |
232
|
|
|
} |
233
|
|
|
$this->stdout("\n*** cleaning $id", Console::FG_YELLOW); |
234
|
|
|
$start = microtime(true); |
235
|
|
|
$count = $panel->cleanup($maxAge); |
236
|
|
|
if ($count !== false) { |
237
|
|
|
$time = microtime(true) - $start; |
238
|
|
|
$this->stdout("\n*** cleaned $id (records: " . $count . ", time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN); |
239
|
|
|
return true; |
240
|
|
|
} |
241
|
|
|
$time = microtime(true) - $start; |
242
|
|
|
$this->stdout("\n*** failed to clean $id (time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_RED); |
243
|
|
|
return false; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Email errors to support email. |
248
|
|
|
* |
249
|
|
|
* @param string|null $email |
250
|
|
|
* @return int |
251
|
|
|
*/ |
252
|
|
|
public function actionErrorEmail($email = null) |
253
|
|
|
{ |
254
|
|
|
$email = $email ? $email : Yii::$app->params['supportEmail']; |
255
|
|
|
|
256
|
|
|
// find all errors to email |
257
|
|
|
$batch = AuditError::find()->where(['emailed' => 0])->batch(); |
258
|
|
|
foreach ($batch as $auditErrors) { |
259
|
|
|
/** @var AuditError $model */ |
260
|
|
|
foreach ($auditErrors as $model) { |
261
|
|
|
|
262
|
|
|
// define params and message |
263
|
|
|
$url = ['audit/default/view', 'id' => $model->entry_id]; |
264
|
|
|
$params = [ |
265
|
|
|
'entry_id' => $model->entry_id, |
266
|
|
|
'message' => $model->message, |
267
|
|
|
'file' => $model->file, |
268
|
|
|
'line' => $model->line, |
269
|
|
|
'url' => Url::to($url), |
270
|
|
|
'link' => Html::a(Yii::t('audit', 'view audit entry'), $url), |
271
|
|
|
]; |
272
|
|
|
$message = [ |
273
|
|
|
'subject' => Yii::t('audit', 'Audit Error in Audit Entry #{entry_id}', $params), |
274
|
|
|
'text' => Yii::t('audit', '{message}' . "\n" . 'in {file} on line {line}.' . "\n" . '-- {url}', $params), |
275
|
|
|
'html' => Yii::t('audit', '<b>{message}</b><br />in <i>{file}</i> on line <i>{line}</i>.<br/>-- {link}', $params), |
276
|
|
|
]; |
277
|
|
|
|
278
|
|
|
// send email |
279
|
|
|
Yii::$app->mailer->compose() |
280
|
|
|
->setFrom([$email => 'Audit :: ' . Yii::$app->name]) |
281
|
|
|
->setTo($email) |
282
|
|
|
->setSubject($message['subject']) |
283
|
|
|
->setTextBody($message['text']) |
284
|
|
|
->setHtmlBody($message['html']) |
285
|
|
|
->send(); |
286
|
|
|
|
287
|
|
|
// mark as emailed |
288
|
|
|
$model->emailed = 1; |
289
|
|
|
$model->save(false, ['emailed']); |
290
|
|
|
|
291
|
|
|
} |
292
|
|
|
} |
293
|
|
|
return self::EXIT_CODE_NORMAL; |
|
|
|
|
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
} |
297
|
|
|
|
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.