Passed
Push — v4 ( 52e3c8...d52e5e )
by Benjamin
04:06
created

SettingsController::actionOauth()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @link      https://dukt.net/craft/analytics/
4
 * @copyright Copyright (c) 2018, Dukt
5
 * @license   https://dukt.net/craft/analytics/docs/license
6
 */
7
8
namespace dukt\analytics\controllers;
9
10
use Craft;
11
use craft\errors\InvalidPluginException;
12
use craft\web\Controller;
13
use dukt\analytics\models\SiteView;
14
use dukt\analytics\models\View;
15
use dukt\analytics\web\assets\settings\SettingsAsset;
16
use dukt\analytics\Plugin as Analytics;
17
use Exception;
18
use Google_Service_Exception;
19
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
20
use yii\web\NotFoundHttpException;
21
use yii\web\Response;
22
23
class SettingsController extends Controller
24
{
25
    // Public Methods
26
    // =========================================================================
27
28
    /**
29
     * Index.
30
     *
31
     * @return Response
32
     * @throws \yii\base\InvalidConfigException
33
     */
34
    public function actionIndex(): Response
35
    {
36
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
37
38
        if ($isOauthProviderConfigured) {
39
            $errors = [];
40
41
            try {
42
                $provider = Analytics::$plugin->oauth->getOauthProvider();
43
                $token = Analytics::$plugin->oauth->getToken();
44
45
                if ($token) {
46
                    $oauthAccount = Analytics::$plugin->cache->get(['getAccount', $token]);
47
48
                    if (!$oauthAccount) {
49
                        $oauthAccount = $provider->getResourceOwner($token);
50
                        Analytics::$plugin->cache->set(['getAccount', $token], $oauthAccount);
51
                    }
52
53
                    if ($oauthAccount) {
54
                        Craft::info("Account:\r\n".print_r($oauthAccount, true), __METHOD__);
55
56
                        $plugin = Craft::$app->getPlugins()->getPlugin('analytics');
57
                        $settings = $plugin->getSettings();
58
                    }
59
                }
60
            } catch (Google_Service_Exception $e) {
61
                Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
62
63
                foreach ($e->getErrors() as $error) {
64
                    $errors[] = $error['message'];
65
                }
66
            } catch (IdentityProviderException $e) {
67
                $error = $e->getMessage();
68
                $data = $e->getResponseBody();
69
70
                if (isset($data['error_description'])) {
71
                    $error = $data['error_description'];
72
                }
73
74
                $errors[] = $error;
75
            } catch (Exception $e) {
76
                if (method_exists($e, 'getResponse')) {
77
                    Craft::info('Couldn’t get OAuth account: '.$e->getResponse(), __METHOD__);
78
                } else {
79
                    Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
80
                }
81
82
                $errors[] = $e->getMessage();
83
            }
84
        }
85
86
        Craft::$app->getView()->registerAssetBundle(SettingsAsset::class);
87
88
        return $this->renderTemplate('analytics/settings/_index', [
89
            'isOauthProviderConfigured' => $isOauthProviderConfigured,
90
            'errors' => $errors ?? null,
91
            'oauthAccount' => $oauthAccount ?? null,
92
            'settings' => $settings ?? null,
93
            'googleIconUrl' => Craft::$app->assetManager->getPublishedUrl('@dukt/analytics/icons/google.svg', true),
94
        ]);
95
    }
96
97
    /**
98
     * OAuth Settings.
99
     *
100
     * @return Response
101
     * @throws \craft\errors\SiteNotFoundException
102
     */
103
    public function actionOauth(): Response
104
    {
105
        return $this->renderTemplate('analytics/settings/_oauth', [
106
            'javascriptOrigin' => Analytics::$plugin->oauth->getJavascriptOrigin(),
107
            'redirectUri' => Analytics::$plugin->oauth->getRedirectUri(),
108
            'googleIconUrl' => Craft::$app->assetManager->getPublishedUrl('@dukt/analytics/icons/google.svg', true),
109
            'settings' => Analytics::$plugin->getSettings(),
110
        ]);
111
    }
112
113
    /**
114
     * Saves the settings.
115
     *
116
     * @return null|Response
117
     * @throws InvalidPluginException
118
     * @throws \yii\base\InvalidConfigException
119
     * @throws \yii\web\BadRequestHttpException
120
     */
121
    public function actionSaveSettings()
122
    {
123
        $this->requirePostRequest();
124
125
        $pluginHandle = Craft::$app->getRequest()->getRequiredBodyParam('pluginHandle');
126
        $settings = Craft::$app->getRequest()->getBodyParam('settings');
127
128
        $plugin = Craft::$app->getPlugins()->getPlugin($pluginHandle);
0 ignored issues
show
Bug introduced by
It seems like $pluginHandle can also be of type array; however, parameter $handle of craft\services\Plugins::getPlugin() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

128
        $plugin = Craft::$app->getPlugins()->getPlugin(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
129
130
        if (!$plugin) {
131
            throw new InvalidPluginException($pluginHandle);
0 ignored issues
show
Bug introduced by
It seems like $pluginHandle can also be of type array; however, parameter $handle of craft\errors\InvalidPluginException::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

131
            throw new InvalidPluginException(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
132
        }
133
134
        $settings = Analytics::$plugin->getApis()->getAnalytics()->populateAccountExplorerSettings($settings);
0 ignored issues
show
Bug introduced by
It seems like $settings can also be of type string; however, parameter $settings of dukt\analytics\apis\Anal...countExplorerSettings() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
        $settings = Analytics::$plugin->getApis()->getAnalytics()->populateAccountExplorerSettings(/** @scrutinizer ignore-type */ $settings);
Loading history...
135
136
        if (Craft::$app->getPlugins()->savePluginSettings($plugin, $settings)) {
137
            Craft::$app->getSession()->setNotice(Craft::t('analytics', 'Plugin settings saved.'));
138
139
            return $this->redirectToPostedUrl();
140
        }
141
142
        Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save plugin settings.'));
143
144
        // Send the plugin back to the template
145
        Craft::$app->getUrlManager()->setRouteParams([
146
            'plugin' => $plugin
147
        ]);
148
149
        return null;
150
    }
151
152
    /**
153
     * Returns the account explorer data.
154
     *
155
     * @return Response
156
     * @throws \yii\base\InvalidConfigException
157
     */
158
    public function actionGetAccountExplorerData(): Response
159
    {
160
        $accountExplorerData = Analytics::$plugin->getApis()->getAnalytics()->getAccountExplorerData();
161
162
        Analytics::$plugin->cache->set(['accountExplorerData'], $accountExplorerData);
163
164
        return $this->asJson($accountExplorerData);
165
    }
166
167
    /**
168
     * Views index.
169
     *
170
     * @return Response
171
     * @throws \yii\base\InvalidConfigException
172
     */
173
    public function actionViews(): Response
174
    {
175
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
176
177
        $variables['isConnected'] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$variables was never initialized. Although not strictly required by PHP, it is generally a good practice to add $variables = array(); before regardless.
Loading history...
178
179
        try {
180
            $token = Analytics::$plugin->oauth->getToken();
181
182
            if ($isOauthProviderConfigured && $token) {
183
                $variables['isConnected'] = true;
184
                $variables['reportingViews'] = Analytics::$plugin->getViews()->getViews();
185
            }
186
        } catch (IdentityProviderException $e) {
187
            $variables['error'] = $e->getMessage();
188
189
            $data = $e->getResponseBody();
190
191
            if (isset($data['error_description'])) {
192
                $variables['error'] = $data['error_description'];
193
            }
194
        }
195
196
        return $this->renderTemplate('analytics/settings/views/_index', $variables);
197
    }
198
199
    /**
200
     * Edit a view.
201
     *
202
     * @param int|null  $viewId
203
     * @param View|null $reportingView
204
     *
205
     * @return Response
206
     * @throws NotFoundHttpException
207
     * @throws \yii\base\InvalidConfigException
208
     */
209
    public function actionEditView(int $viewId = null, View $reportingView = null): Response
210
    {
211
        $variables['isNewView'] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$variables was never initialized. Although not strictly required by PHP, it is generally a good practice to add $variables = array(); before regardless.
Loading history...
212
213
        if ($viewId !== null) {
214
            if ($reportingView === null) {
215
                $reportingView = Analytics::$plugin->getViews()->getViewById($viewId);
216
217
                if (!$reportingView) {
218
                    throw new NotFoundHttpException('View not found');
219
                }
220
            }
221
222
            $variables['title'] = $reportingView->name;
223
            $variables['reportingView'] = $reportingView;
224
        } else {
225
            if ($reportingView === null) {
226
                $reportingView = new View();
227
                $variables['isNewView'] = true;
228
            }
229
            $variables['title'] = Craft::t('analytics', 'Create a new view');
230
        }
231
232
        $variables['reportingView'] = $reportingView;
233
        $variables['accountExplorerOptions'] = $this->getAccountExplorerOptions($reportingView);
234
235
        Craft::$app->getView()->registerAssetBundle(SettingsAsset::class);
236
237
        return $this->renderTemplate('analytics/settings/views/_edit', $variables);
238
    }
239
240
    /**
241
     * Saves a view.
242
     *
243
     * @return null|Response
244
     * @throws \dukt\analytics\errors\InvalidViewException
245
     * @throws \yii\base\InvalidConfigException
246
     * @throws \yii\web\BadRequestHttpException
247
     */
248
    public function actionSaveView()
249
    {
250
        $this->requirePostRequest();
251
252
        $reportingView = new View();
253
254
        // Set the simple stuff
255
        $request = Craft::$app->getRequest();
256
        $reportingView->id = $request->getBodyParam('viewId');
257
        $reportingView->name = $request->getBodyParam('name');
0 ignored issues
show
Documentation Bug introduced by
It seems like $request->getBodyParam('name') can also be of type array. However, the property $name is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
258
259
        $accountExplorer = $request->getBodyParam('accountExplorer');
260
261
        $reportingView->gaAccountId = $accountExplorer['account'];
262
        $reportingView->gaPropertyId = $accountExplorer['property'];
263
        $reportingView->gaViewId = $accountExplorer['view'];
264
265
266
        $accountExplorerData = Analytics::$plugin->getApis()->getAnalytics()->getAccountExplorerData();
267
268
        foreach ($accountExplorerData['accounts'] as $dataAccount) {
269
            if ($dataAccount->id == $reportingView->gaAccountId) {
270
                $reportingView->gaAccountName = $dataAccount->name;
271
            }
272
        }
273
274
        foreach ($accountExplorerData['properties'] as $dataProperty) {
275
            if ($dataProperty->id == $reportingView->gaPropertyId) {
276
                $reportingView->gaPropertyName = $dataProperty->name;
277
            }
278
        }
279
        foreach ($accountExplorerData['views'] as $dataView) {
280
            if ($dataView->id == $reportingView->gaViewId) {
281
                $reportingView->gaViewName = $dataView->name;
282
                $reportingView->gaViewCurrency = $dataView->currency;
283
            }
284
        }
285
286
        // Save it
287
        if (!Analytics::$plugin->getViews()->saveView($reportingView)) {
288
            Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save the view.'));
289
290
            // Send the view back to the template
291
            Craft::$app->getUrlManager()->setRouteParams([
292
                'reportingView' => $reportingView
293
            ]);
294
295
            return null;
296
        }
297
298
        Craft::$app->getSession()->setNotice(Craft::t('analytics', 'View saved.'));
299
300
        return $this->redirectToPostedUrl($reportingView);
301
    }
302
303
    /**
304
     * Deletes a view.
305
     *
306
     * @return Response
307
     * @throws \Throwable
308
     * @throws \yii\db\StaleObjectException
309
     * @throws \yii\web\BadRequestHttpException
310
     */
311
    public function actionDeleteView(): Response
312
    {
313
        $this->requirePostRequest();
314
        $this->requireAcceptsJson();
315
316
        $request = Craft::$app->getRequest();
317
        $viewId = $request->getRequiredBodyParam('id');
318
319
        Analytics::$plugin->getViews()->deleteViewById($viewId);
320
321
        return $this->asJson(['success' => true]);
322
    }
323
324
    /**
325
     * Sites index.
326
     *
327
     * @return Response
328
     * @throws \yii\base\InvalidConfigException
329
     */
330
    public function actionSites(): Response
331
    {
332
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
333
334
        $variables['isConnected'] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$variables was never initialized. Although not strictly required by PHP, it is generally a good practice to add $variables = array(); before regardless.
Loading history...
335
336
        try {
337
            $token = Analytics::$plugin->oauth->getToken();
338
339
            if ($isOauthProviderConfigured && $token) {
340
                $variables['isConnected'] = true;
341
                $variables['sites'] = Craft::$app->getSites()->getAllSites();
342
                $variables['siteViews'] = Analytics::$plugin->getViews()->getSiteViews();
343
            }
344
        } catch (IdentityProviderException $e) {
345
            $variables['error'] = $e->getMessage();
346
347
            $data = $e->getResponseBody();
348
349
            if (isset($data['error_description'])) {
350
                $variables['error'] = $data['error_description'];
351
            }
352
        }
353
354
        return $this->renderTemplate('analytics/settings/sites/_index', $variables);
355
    }
356
357
    /**
358
     * Edit a site.
359
     *
360
     * @param $siteId
361
     *
362
     * @return Response
363
     * @throws \yii\base\InvalidConfigException
364
     */
365
    public function actionEditSite($siteId): Response
366
    {
367
        $site = Craft::$app->getSites()->getSiteById($siteId);
368
        $siteView = Analytics::$plugin->getViews()->getSiteViewBySiteId($siteId);
369
        $reportingViews = Analytics::$plugin->getViews()->getViews();
370
371
        return $this->renderTemplate('analytics/settings/sites/_edit', [
372
            'site' => $site,
373
            'siteView' => $siteView,
374
            'reportingViews' => $reportingViews,
375
        ]);
376
    }
377
378
    /**
379
     * Saves a site.
380
     *
381
     * @return null|Response
382
     * @throws \yii\base\InvalidConfigException
383
     * @throws \yii\db\Exception
384
     * @throws \yii\web\BadRequestHttpException
385
     */
386
    public function actionSaveSite()
387
    {
388
        $this->requirePostRequest();
389
390
        $siteView = new SiteView();
391
392
        // Set the simple stuff
393
        $request = Craft::$app->getRequest();
394
        $siteView->siteId = $request->getBodyParam('siteId');
395
        $siteView->viewId = $request->getBodyParam('viewId');
396
397
        // Save it
398
        if (!Analytics::$plugin->getViews()->saveSiteView($siteView)) {
399
            Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save the site view.'));
400
401
            // Send the view back to the template
402
            Craft::$app->getUrlManager()->setRouteParams([
403
                'siteView' => $siteView
404
            ]);
405
406
            return null;
407
        }
408
409
        Craft::$app->getSession()->setNotice(Craft::t('analytics', 'Site view saved.'));
410
411
        return $this->redirectToPostedUrl($siteView);
412
    }
413
414
    // Private Methods
415
    // =========================================================================
416
417
    /**
418
     * @param View $reportingView
419
     *
420
     * @return array
421
     */
422
    private function getAccountExplorerOptions(View $reportingView): array
423
    {
424
        $accountExplorerData = Analytics::$plugin->cache->get(['accountExplorerData']);
425
426
        return [
427
            'accounts' => $this->getAccountOptions($accountExplorerData, $reportingView),
428
            'properties' => $this->getPropertyOptions($accountExplorerData, $reportingView),
429
            'views' => $this->getViewOptions($accountExplorerData, $reportingView),
430
        ];
431
    }
432
433
    /**
434
     * @param      $accountExplorerData
435
     * @param View $reportingView
436
     *
437
     * @return array
438
     */
439
    private function getAccountOptions($accountExplorerData, View $reportingView): array
440
    {
441
        $accountOptions = [];
442
443
        if (isset($accountExplorerData['accounts'])) {
444
            foreach ($accountExplorerData['accounts'] as $account) {
445
                $accountOptions[] = ['label' => $account['name'], 'value' => $account['id']];
446
            }
447
        } else {
448
            $accountOptions[] = ['label' => $reportingView->gaAccountName, 'value' => $reportingView->gaAccountId];
449
        }
450
451
        return $accountOptions;
452
    }
453
454
    /**
455
     * @param      $accountExplorerData
456
     * @param View $reportingView
457
     *
458
     * @return array
459
     */
460
    private function getPropertyOptions($accountExplorerData, View $reportingView): array
461
    {
462
        $propertyOptions = [];
463
464
        if (isset($accountExplorerData['properties'])) {
465
            foreach ($accountExplorerData['properties'] as $webProperty) {
466
                $propertyOptions[] = ['label' => $webProperty['name'], 'value' => $webProperty['id']];
467
            }
468
        } else {
469
            $propertyOptions[] = ['label' => $reportingView->gaPropertyName, 'value' => $reportingView->gaPropertyId];
470
        }
471
472
        return $propertyOptions;
473
    }
474
475
    /**
476
     * @param      $accountExplorerData
477
     * @param View $reportingView
478
     *
479
     * @return array
480
     */
481
    private function getViewOptions($accountExplorerData, View $reportingView): array
482
    {
483
        $viewOptions = [];
484
485
        if (isset($accountExplorerData['views'])) {
486
            foreach ($accountExplorerData['views'] as $dataView) {
487
                $viewOptions[] = ['label' => $dataView['name'], 'value' => $dataView['id']];
488
            }
489
        } else {
490
            $viewOptions[] = ['label' => $reportingView->gaViewName, 'value' => $reportingView->gaViewId];
491
        }
492
493
        return $viewOptions;
494
    }
495
}