diff --git a/application/common/components/ExternalGroupsSync.php b/application/common/components/ExternalGroupsSync.php new file mode 100644 index 00000000..4e59d667 --- /dev/null +++ b/application/common/components/ExternalGroupsSync.php @@ -0,0 +1,110 @@ + Yii::$app->params['google']['applicationName'], + 'jsonAuthFilePath' => Yii::$app->params['google']['jsonAuthFilePath'], + 'jsonAuthString' => Yii::$app->params['google']['jsonAuthString'], + 'spreadsheetId' => $googleSheetId, + ]); + $tabName = Yii::$app->params['idpName']; + + $values = $googleSheetsClient->getValuesFromTab($tabName); + $columnLabels = $values[0]; + + Assert::eq($columnLabels[0], 'email', sprintf( + "The first column in the '%s' tab must be 'email'", + $tabName + )); + Assert::eq($columnLabels[1], 'groups', sprintf( + "The second column in the '%s' tab must be 'groups'", + $tabName + )); + Assert::eq( + count($columnLabels), + 2, + 'There should only be two columns with values' + ); + + $data = []; + for ($i = 1; $i < count($values); $i++) { + $email = trim($values[$i][0]); + $groups = trim($values[$i][1] ?? ''); + $data[$email] = $groups; + } + return $data; + } +} diff --git a/application/common/components/Sheets.php b/application/common/components/Sheets.php index 3c989847..848e21dd 100644 --- a/application/common/components/Sheets.php +++ b/application/common/components/Sheets.php @@ -2,6 +2,7 @@ namespace common\components; +use Google\Service\Exception; use InvalidArgumentException; use yii\base\Component; use yii\helpers\Json; @@ -127,6 +128,43 @@ public function getHeader() return $header['values'][0]; } + /** + * Get all the values from the specified tab in this Google Sheet. + * + * @param string $tabName + * @param string $range + * @return array[] + * Example: + * ``` + * [ + * [ + * "A1's value", + * "B1's value" + * ], + * [ + * "A2's value", + * "B2's value" + * ], + * [ + * "A3's value", + * "B3's value" + * ] + * ] + * ``` + * @throws Exception + */ + public function getValuesFromTab(string $tabName, string $range = 'A:ZZ'): array + { + $client = $this->getGoogleClient(); + + $valueRange = $client->spreadsheets_values->get( + $this->spreadsheetId, + $tabName . '!' . $range + ); + + return $valueRange->values; + } + /** * @param string[] $header * @param array $records diff --git a/application/common/config/main.php b/application/common/config/main.php index 08f3bec7..b243e29d 100644 --- a/application/common/config/main.php +++ b/application/common/config/main.php @@ -239,6 +239,7 @@ ], Env::getArrayFromPrefix('ABANDONED_USER_') ), + 'externalGroupsSyncSets' => Env::getArrayFromPrefix('EXTERNAL_GROUPS_SYNC_'), 'googleAnalytics' => [ 'apiSecret' => Env::get('GA_API_SECRET'), 'measurementId' => Env::get('GA_MEASUREMENT_ID'), diff --git a/application/common/models/User.php b/application/common/models/User.php index 553f77f2..dfdae13e 100644 --- a/application/common/models/User.php +++ b/application/common/models/User.php @@ -1062,9 +1062,9 @@ public static function updateUsersExternalGroups( $successful = $user->updateExternalGroups($appPrefix, $groupsForPrefix); if (! $successful) { $errors[] = sprintf( - "Failed to update external groups for %s: \n%s", + 'Failed to update external groups for %s: %s', $email, - json_encode($user->getFirstErrors(), JSON_PRETTY_PRINT) + join(' / ', $user->getFirstErrors()) ); } } @@ -1084,9 +1084,9 @@ public function updateExternalGroups(string $appPrefix, string $csvAppExternalGr if (! str_starts_with($appExternalGroup, $appPrefix . '-')) { $this->addErrors([ 'groups_external' => sprintf( - 'The given group %s does not start with the given prefix (%s)', - json_encode($appExternalGroup), - json_encode($appPrefix) + 'The given group (%s) does not start with the given prefix (%s)', + $appExternalGroup, + $appPrefix ), ]); return false; @@ -1096,17 +1096,7 @@ public function updateExternalGroups(string $appPrefix, string $csvAppExternalGr $this->addInMemoryExternalGroups($appExternalGroups); $this->scenario = self::SCENARIO_UPDATE_USER; - $saved = $this->save(true, ['groups_external']); - if ($saved) { - return true; - } else { - Yii::warning(sprintf( - 'Failed to update external groups for %s: %s', - $this->email, - join(', ', $this->getFirstErrors()) - )); - return false; - } + return $this->save(true, ['groups_external']); } /** diff --git a/application/console/controllers/CronController.php b/application/console/controllers/CronController.php index 22f15390..01c4648c 100644 --- a/application/console/controllers/CronController.php +++ b/application/console/controllers/CronController.php @@ -2,6 +2,7 @@ namespace console\controllers; +use common\components\ExternalGroupsSync; use common\helpers\Utils; use common\models\Invite; use common\models\Method; @@ -137,6 +138,16 @@ public function actionExportToSheets() User::exportToSheets(); } + /** + * Sync external groups from Google Sheets + */ + public function actionSyncExternalGroups() + { + ExternalGroupsSync::syncAllSets( + \Yii::$app->params['externalGroupsSyncSets'] ?? [] + ); + } + /** * Run all cron tasks, catching and logging errors to allow remaining tasks to run after an exception */ diff --git a/local.env.dist b/local.env.dist index 6d2604aa..c460df7a 100644 --- a/local.env.dist +++ b/local.env.dist @@ -337,3 +337,11 @@ GOOGLE_delegatedAdmin=admin@example.com # spreadsheet ID GOOGLE_spreadsheetId=putAnActualSheetIDHerejD70xAjqPnOCHlDK3YomH + +# === external groups sync sets === # + +# EXTERNAL_GROUPS_SYNC_set1AppPrefix= +# EXTERNAL_GROUPS_SYNC_set1GoogleSheetId= +# EXTERNAL_GROUPS_SYNC_set2AppPrefix= +# EXTERNAL_GROUPS_SYNC_set2GoogleSheetId= +# ... with as many sets as you want.