From 16686a3420313fac3076565ddc7662d2a1ab7a0f Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Fri, 17 May 2024 15:20:37 -0700 Subject: [PATCH 1/9] Use Select fields for properties we'd like to filter on --- src/endpoints/NotionEndpoint.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index 1c2a18c..86dac62 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -8,9 +8,9 @@ use Notion\Pages\PageParent; use Notion\Pages\Properties\Date; use Notion\Pages\Properties\RichTextProperty; +use Notion\Pages\Properties\Select; use Notion\Pages\Properties\Title; use Notion\Pages\Properties\Url; -use viget\phonehome\models\SettingsNotion; use viget\phonehome\models\SitePayload; class NotionEndpoint implements EndpointInterface @@ -23,7 +23,7 @@ class NotionEndpoint implements EndpointInterface private const PROPERTY_PLUGINS = "Plugins"; private const PROPERTY_MODULES = "Modules"; private const PROPERTY_DATE_UPDATED = "Date Updated"; - private const PROPERTY_TITLE = "Title"; + private const PROPERTY_NAME = "Name"; public function __construct( private readonly string $secret, @@ -41,10 +41,10 @@ public function send(SitePayload $payload): void // TODO only run if needed $database = $database ->addProperty(\Notion\Databases\Properties\Url::create(self::PROPERTY_URL)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_ENVIRONMENT)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_CRAFT_VERSION)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_PHP_VERSION)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_DB_VERSION)) + ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_ENVIRONMENT)) + ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_CRAFT_VERSION)) + ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_PHP_VERSION)) + ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_DB_VERSION)) ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_PLUGINS)) ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_MODULES)) ->addProperty(\Notion\Databases\Properties\Date::create(self::PROPERTY_DATE_UPDATED)) @@ -66,12 +66,12 @@ public function send(SitePayload $payload): void $page = $page ?? Page::create($parent); // Update properties - $page = $page->addProperty(self::PROPERTY_TITLE, Title::fromString($payload->siteName)) + $page = $page->addProperty(self::PROPERTY_NAME, Title::fromString($payload->siteName)) ->addProperty(self::PROPERTY_URL, Url::create($payload->siteUrl)) - ->addProperty(self::PROPERTY_ENVIRONMENT, RichTextProperty::fromString($payload->environment)) - ->addProperty(self::PROPERTY_CRAFT_VERSION, RichTextProperty::fromString($payload->craftVersion)) - ->addProperty(self::PROPERTY_PHP_VERSION, RichTextProperty::fromString($payload->phpVersion)) - ->addProperty(self::PROPERTY_DB_VERSION, RichTextProperty::fromString($payload->dbVersion)) + ->addProperty(self::PROPERTY_ENVIRONMENT, Select::fromName($payload->environment)) + ->addProperty(self::PROPERTY_CRAFT_VERSION, Select::fromName($payload->craftVersion)) + ->addProperty(self::PROPERTY_PHP_VERSION, Select::fromName($payload->phpVersion)) + ->addProperty(self::PROPERTY_DB_VERSION, Select::fromName($payload->dbVersion)) ->addProperty(self::PROPERTY_PLUGINS, RichTextProperty::fromString($payload->plugins)) ->addProperty(self::PROPERTY_MODULES, RichTextProperty::fromString($payload->modules)) ->addProperty(self::PROPERTY_DATE_UPDATED, Date::create(new \DateTimeImmutable('now', new \DateTimeZone('UTC')))) From 65dc694b91cbfa62d563756f9ce42cb049976714 Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Fri, 17 May 2024 15:21:07 -0700 Subject: [PATCH 2/9] Delete unused settings class --- src/models/SettingsNotion.php | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/models/SettingsNotion.php diff --git a/src/models/SettingsNotion.php b/src/models/SettingsNotion.php deleted file mode 100644 index ecc395c..0000000 --- a/src/models/SettingsNotion.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Fri, 17 May 2024 16:18:53 -0700 Subject: [PATCH 3/9] Switch plugin data to use multi-select --- src/endpoints/NotionEndpoint.php | 13 +++++++++++-- src/models/SitePayload.php | 21 +++++---------------- src/models/SitePayloadPlugin.php | 26 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/models/SitePayloadPlugin.php diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index 86dac62..b07707c 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -7,11 +7,13 @@ use Notion\Pages\Page; use Notion\Pages\PageParent; use Notion\Pages\Properties\Date; +use Notion\Pages\Properties\MultiSelect; use Notion\Pages\Properties\RichTextProperty; use Notion\Pages\Properties\Select; use Notion\Pages\Properties\Title; use Notion\Pages\Properties\Url; use viget\phonehome\models\SitePayload; +use viget\phonehome\models\SitePayloadPlugin; class NotionEndpoint implements EndpointInterface { @@ -21,6 +23,7 @@ class NotionEndpoint implements EndpointInterface private const PROPERTY_PHP_VERSION = "PHP Version"; private const PROPERTY_DB_VERSION = "DB Version"; private const PROPERTY_PLUGINS = "Plugins"; + private const PROPERTY_PLUGIN_VERSIONS = "Plugin Versions"; private const PROPERTY_MODULES = "Modules"; private const PROPERTY_DATE_UPDATED = "Date Updated"; private const PROPERTY_NAME = "Name"; @@ -45,7 +48,8 @@ public function send(SitePayload $payload): void ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_CRAFT_VERSION)) ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_PHP_VERSION)) ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_DB_VERSION)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_PLUGINS)) + ->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGINS)) + ->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGIN_VERSIONS)) ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_MODULES)) ->addProperty(\Notion\Databases\Properties\Date::create(self::PROPERTY_DATE_UPDATED)) ; @@ -66,13 +70,18 @@ public function send(SitePayload $payload): void $page = $page ?? Page::create($parent); // Update properties + + $plugins = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->id)->values()->all(); + $pluginVersions = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->versionedId)->values()->all(); + $page = $page->addProperty(self::PROPERTY_NAME, Title::fromString($payload->siteName)) ->addProperty(self::PROPERTY_URL, Url::create($payload->siteUrl)) ->addProperty(self::PROPERTY_ENVIRONMENT, Select::fromName($payload->environment)) ->addProperty(self::PROPERTY_CRAFT_VERSION, Select::fromName($payload->craftVersion)) ->addProperty(self::PROPERTY_PHP_VERSION, Select::fromName($payload->phpVersion)) ->addProperty(self::PROPERTY_DB_VERSION, Select::fromName($payload->dbVersion)) - ->addProperty(self::PROPERTY_PLUGINS, RichTextProperty::fromString($payload->plugins)) + ->addProperty(self::PROPERTY_PLUGINS, MultiSelect::fromNames(...$plugins)) + ->addProperty(self::PROPERTY_PLUGIN_VERSIONS, MultiSelect::fromNames(...$pluginVersions)) ->addProperty(self::PROPERTY_MODULES, RichTextProperty::fromString($payload->modules)) ->addProperty(self::PROPERTY_DATE_UPDATED, Date::create(new \DateTimeImmutable('now', new \DateTimeZone('UTC')))) ; diff --git a/src/models/SitePayload.php b/src/models/SitePayload.php index 3b24af2..5a61f7b 100644 --- a/src/models/SitePayload.php +++ b/src/models/SitePayload.php @@ -6,6 +6,7 @@ use craft\base\PluginInterface; use craft\helpers\App; use craft\models\Site; +use Illuminate\Support\Collection; use yii\base\Module; final class SitePayload @@ -18,7 +19,8 @@ public function __construct( public readonly string $craftVersion, public readonly string $phpVersion, public readonly string $dbVersion, - public readonly string $plugins, + /** @var Collection $plugins */ + public readonly Collection $plugins, public readonly string $modules ) { @@ -33,7 +35,8 @@ public static function fromSite(Site $site): self craftVersion: App::editionName(Craft::$app->getEdition()), phpVersion: App::phpVersion(), dbVersion: self::_dbDriver(), - plugins: self::_plugins(), + plugins: Collection::make(Craft::$app->plugins->getAllPlugins()) + ->map(SitePayloadPlugin::fromPluginInterface(...)), modules: self::_modules() ); } @@ -56,20 +59,6 @@ private static function _dbDriver(): string return $driverName . ' ' . App::normalizeVersion($db->getSchema()->getServerVersion()); } - /** - * Returns the list of plugins and versions - * - * @return string - */ - private static function _plugins(): string - { - $plugins = Craft::$app->plugins->getAllPlugins(); - - return implode(PHP_EOL, array_map(function($plugin) { - return "{$plugin->name} ({$plugin->developer}): {$plugin->version}"; - }, $plugins)); - } - /** * Returns the list of modules * diff --git a/src/models/SitePayloadPlugin.php b/src/models/SitePayloadPlugin.php new file mode 100644 index 0000000..980afdd --- /dev/null +++ b/src/models/SitePayloadPlugin.php @@ -0,0 +1,26 @@ +id, + versionedId: $pluginInterface->id . ':' . $pluginInterface->version, + ); + } +} \ No newline at end of file From cb3c345a8a0a4a68851620729d93a3dd0c32f2ea Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Fri, 17 May 2024 17:02:49 -0700 Subject: [PATCH 4/9] Only update database fields if they don't exist --- src/endpoints/NotionEndpoint.php | 76 +++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index b07707c..af68d37 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -2,6 +2,8 @@ namespace viget\phonehome\endpoints; +use DateTimeImmutable; +use DateTimeZone; use Notion\Databases\Query; use Notion\Notion; use Notion\Pages\Page; @@ -39,22 +41,65 @@ public function send(SitePayload $payload): void { $notion = Notion::create($this->secret); $database = $notion->databases()->find($this->databaseId); + $existingProperties = $database->properties()->getAll(); + + // Checks if a property exists + $hasProperty = function (string $handle) use ($existingProperties): bool { + return !empty($existingProperties[$handle]); + }; + + $shouldUpdate = false; // Make sure properties are present on page - // TODO only run if needed - $database = $database - ->addProperty(\Notion\Databases\Properties\Url::create(self::PROPERTY_URL)) - ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_ENVIRONMENT)) - ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_CRAFT_VERSION)) - ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_PHP_VERSION)) - ->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_DB_VERSION)) - ->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGINS)) - ->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGIN_VERSIONS)) - ->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_MODULES)) - ->addProperty(\Notion\Databases\Properties\Date::create(self::PROPERTY_DATE_UPDATED)) - ; - - $notion->databases()->update($database); + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Url::create(self::PROPERTY_URL)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_ENVIRONMENT)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_CRAFT_VERSION)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_PHP_VERSION)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_DB_VERSION)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGINS)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGIN_VERSIONS)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_MODULES)); + $shouldUpdate = true; + } + + if (!$hasProperty(self::PROPERTY_URL)) { + $database = $database->addProperty(\Notion\Databases\Properties\Date::create(self::PROPERTY_DATE_UPDATED)); + $shouldUpdate = true; + } + + // Only update if properties have changed + if ($shouldUpdate) { + $notion->databases()->update($database); + } $query = Query::create() ->changeFilter( @@ -83,8 +128,7 @@ public function send(SitePayload $payload): void ->addProperty(self::PROPERTY_PLUGINS, MultiSelect::fromNames(...$plugins)) ->addProperty(self::PROPERTY_PLUGIN_VERSIONS, MultiSelect::fromNames(...$pluginVersions)) ->addProperty(self::PROPERTY_MODULES, RichTextProperty::fromString($payload->modules)) - ->addProperty(self::PROPERTY_DATE_UPDATED, Date::create(new \DateTimeImmutable('now', new \DateTimeZone('UTC')))) - ; + ->addProperty(self::PROPERTY_DATE_UPDATED, Date::create(new DateTimeImmutable('now', new DateTimeZone('UTC')))); if ($isCreate) { $notion->pages()->create($page); From f79a3be3cc54455fcb174f71e3047d8afe13f5f6 Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Mon, 20 May 2024 10:05:29 -0700 Subject: [PATCH 5/9] Use a config for property updates --- src/endpoints/NotionEndpoint.php | 138 ++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 50 deletions(-) diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index af68d37..fd11d4d 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -4,6 +4,14 @@ use DateTimeImmutable; use DateTimeZone; +use Exception; +use Notion\Databases\Database; +use Notion\Databases\Properties\Date as DateDb; +use Notion\Databases\Properties\MultiSelect as MultiSelectDb; +use Notion\Databases\Properties\PropertyInterface; +use Notion\Databases\Properties\RichTextProperty as RichTextDb; +use Notion\Databases\Properties\Select as SelectDb; +use Notion\Databases\Properties\Url as UrlDb; use Notion\Databases\Query; use Notion\Notion; use Notion\Pages\Page; @@ -30,6 +38,41 @@ class NotionEndpoint implements EndpointInterface private const PROPERTY_DATE_UPDATED = "Date Updated"; private const PROPERTY_NAME = "Name"; + /** + * @var array + * }> + */ + private const PROPERTY_CONFIG = [ + self::PROPERTY_URL => [ + 'class' => UrlDb::class, + ], + self::PROPERTY_ENVIRONMENT => [ + 'class' => SelectDb::class, + ], + self::PROPERTY_CRAFT_VERSION => [ + 'class' => SelectDb::class, + ], + self::PROPERTY_PHP_VERSION => [ + 'class' => SelectDb::class, + ], + self::PROPERTY_DB_VERSION => [ + 'class' => SelectDb::class, + ], + self::PROPERTY_PLUGINS => [ + 'class' => MultiSelectDb::class, + ], + self::PROPERTY_PLUGIN_VERSIONS => [ + 'class' => MultiSelectDb::class, + ], + self::PROPERTY_MODULES => [ + 'class' => RichTextDb::class, + ], + self::PROPERTY_DATE_UPDATED => [ + 'class' => DateDb::class, + ], + ]; + public function __construct( private readonly string $secret, private readonly string $databaseId, @@ -37,70 +80,65 @@ public function __construct( { } - public function send(SitePayload $payload): void + /** + * @param string $propertyName + * @param class-string $propertyClass + * @param Database $database Pass by reference because there's some immutable stuff going on in the Notion lib + * @return bool True if property was created + * @throws Exception + */ + private function createProperty(string $propertyName, string $propertyClass, Database &$database): bool { - $notion = Notion::create($this->secret); - $database = $notion->databases()->find($this->databaseId); $existingProperties = $database->properties()->getAll(); - // Checks if a property exists - $hasProperty = function (string $handle) use ($existingProperties): bool { - return !empty($existingProperties[$handle]); - }; - - $shouldUpdate = false; - - // Make sure properties are present on page - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Url::create(self::PROPERTY_URL)); - $shouldUpdate = true; - } - - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_ENVIRONMENT)); - $shouldUpdate = true; - } - - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_CRAFT_VERSION)); - $shouldUpdate = true; - } - - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_PHP_VERSION)); - $shouldUpdate = true; - } - - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Select::create(self::PROPERTY_DB_VERSION)); - $shouldUpdate = true; + // Don't create a property if it already exists + if (!empty($existingProperties[$propertyName])) { + return false; } - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGINS)); - $shouldUpdate = true; - } + // If you're using a class that isn't in this list, most likely the ::create + // method is compatible. But it's worth double-checking. + $database = match ($propertyClass) { + UrlDb::class, + SelectDb::class, + MultiSelectDb::class, + RichTextDb::class, + DateDb::class => $database->addProperty($propertyClass::create($propertyName)), + default => throw new Exception("createProperty doesnt support the class $propertyClass. Double check that its ::create method is compatible and add to this method") + }; - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\MultiSelect::create(self::PROPERTY_PLUGIN_VERSIONS)); - $shouldUpdate = true; - } + return true; + } - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\RichTextProperty::create(self::PROPERTY_MODULES)); - $shouldUpdate = true; - } + /** + * @throws Exception + */ + public function send(SitePayload $payload): void + { + $notion = Notion::create($this->secret); + $database = $notion->databases()->find($this->databaseId); - if (!$hasProperty(self::PROPERTY_URL)) { - $database = $database->addProperty(\Notion\Databases\Properties\Date::create(self::PROPERTY_DATE_UPDATED)); - $shouldUpdate = true; + // Loop through property config and create properties that don't exist on the DB + $updated = false; + foreach (self::PROPERTY_CONFIG as $propertyName => $config) { + $didUpdate = $this->createProperty( + $propertyName, + $config['class'], + $database + ); + + // Always stay true if one property updated + if ($didUpdate === true) { + $updated = true; + } } // Only update if properties have changed - if ($shouldUpdate) { + if ($updated) { $notion->databases()->update($database); } + // Find existing DB record for site $query = Query::create() ->changeFilter( Query\TextFilter::property(self::PROPERTY_URL)->equals($payload->siteUrl), From 5c860350a6cf7a2c48076e3ef9608b4668d2f33f Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Mon, 20 May 2024 10:10:14 -0700 Subject: [PATCH 6/9] Differentiate between Craft Version & Edition --- src/PhoneHome.php | 2 ++ src/endpoints/NotionEndpoint.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/PhoneHome.php b/src/PhoneHome.php index 3524547..34fafbd 100644 --- a/src/PhoneHome.php +++ b/src/PhoneHome.php @@ -37,6 +37,8 @@ public function init(): void // If enabled hasn't been configured, enable for non-devMode environments $enabled = $this->getSettings()->enabled ?? Craft::$app->getConfig()->getGeneral()->devMode === false; + $this->phoneHome->sendPayload(); + if (!$enabled) { return; } diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index fd11d4d..c144451 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -29,6 +29,7 @@ class NotionEndpoint implements EndpointInterface { private const PROPERTY_URL = "Url"; private const PROPERTY_ENVIRONMENT = "Environment"; + private const PROPERTY_CRAFT_EDITION = "Craft Edition"; private const PROPERTY_CRAFT_VERSION = "Craft Version"; private const PROPERTY_PHP_VERSION = "PHP Version"; private const PROPERTY_DB_VERSION = "DB Version"; @@ -50,6 +51,9 @@ class NotionEndpoint implements EndpointInterface self::PROPERTY_ENVIRONMENT => [ 'class' => SelectDb::class, ], + self::PROPERTY_CRAFT_EDITION => [ + 'class' => SelectDb::class, + ], self::PROPERTY_CRAFT_VERSION => [ 'class' => SelectDb::class, ], @@ -160,6 +164,7 @@ public function send(SitePayload $payload): void $page = $page->addProperty(self::PROPERTY_NAME, Title::fromString($payload->siteName)) ->addProperty(self::PROPERTY_URL, Url::create($payload->siteUrl)) ->addProperty(self::PROPERTY_ENVIRONMENT, Select::fromName($payload->environment)) + ->addProperty(self::PROPERTY_CRAFT_EDITION, Select::fromName($payload->craftEdition)) ->addProperty(self::PROPERTY_CRAFT_VERSION, Select::fromName($payload->craftVersion)) ->addProperty(self::PROPERTY_PHP_VERSION, Select::fromName($payload->phpVersion)) ->addProperty(self::PROPERTY_DB_VERSION, Select::fromName($payload->dbVersion)) From 1d90e78fbb74e3239039a5fa5382183aac826cf3 Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Mon, 20 May 2024 10:43:42 -0700 Subject: [PATCH 7/9] PHPStan Level Up. Store modules as MultiSelect --- phpstan.neon | 2 +- src/PhoneHome.php | 3 +++ src/endpoints/NotionEndpoint.php | 9 ++++----- src/models/SitePayload.php | 32 ++++++++++++++++++++++--------- src/services/PhoneHomeService.php | 5 +++-- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index a2e5224..ced22c0 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,6 +2,6 @@ includes: - vendor/craftcms/phpstan/phpstan.neon parameters: - level: 4 + level: 9 paths: - src diff --git a/src/PhoneHome.php b/src/PhoneHome.php index 34fafbd..496efbe 100644 --- a/src/PhoneHome.php +++ b/src/PhoneHome.php @@ -23,6 +23,9 @@ class PhoneHome extends Plugin public string $schemaVersion = '1.0.0'; public bool $hasCpSettings = true; + /** + * @phpstan-ignore-next-line + */ public static function config(): array { return [ diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index c144451..4b9205d 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -70,7 +70,7 @@ class NotionEndpoint implements EndpointInterface 'class' => MultiSelectDb::class, ], self::PROPERTY_MODULES => [ - 'class' => RichTextDb::class, + 'class' => MultiSelectDb::class, ], self::PROPERTY_DATE_UPDATED => [ 'class' => DateDb::class, @@ -157,9 +157,8 @@ public function send(SitePayload $payload): void $page = $page ?? Page::create($parent); // Update properties - - $plugins = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->id)->values()->all(); - $pluginVersions = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->versionedId)->values()->all(); + $plugins = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->id)->all(); + $pluginVersions = $payload->plugins->map(fn(SitePayloadPlugin $plugin) => $plugin->versionedId)->all(); $page = $page->addProperty(self::PROPERTY_NAME, Title::fromString($payload->siteName)) ->addProperty(self::PROPERTY_URL, Url::create($payload->siteUrl)) @@ -170,7 +169,7 @@ public function send(SitePayload $payload): void ->addProperty(self::PROPERTY_DB_VERSION, Select::fromName($payload->dbVersion)) ->addProperty(self::PROPERTY_PLUGINS, MultiSelect::fromNames(...$plugins)) ->addProperty(self::PROPERTY_PLUGIN_VERSIONS, MultiSelect::fromNames(...$pluginVersions)) - ->addProperty(self::PROPERTY_MODULES, RichTextProperty::fromString($payload->modules)) + ->addProperty(self::PROPERTY_MODULES, MultiSelect::fromNames(...$payload->modules->all())) ->addProperty(self::PROPERTY_DATE_UPDATED, Date::create(new DateTimeImmutable('now', new DateTimeZone('UTC')))); if ($isCreate) { diff --git a/src/models/SitePayload.php b/src/models/SitePayload.php index 5a61f7b..83d5890 100644 --- a/src/models/SitePayload.php +++ b/src/models/SitePayload.php @@ -16,27 +16,40 @@ public function __construct( public readonly string $siteUrl, public readonly string $siteName, public readonly string $environment, + /** @var string $craftEdition - Solo, Team, Pro, etc */ + public readonly string $craftEdition, + /** @var string The version number */ public readonly string $craftVersion, public readonly string $phpVersion, public readonly string $dbVersion, - /** @var Collection $plugins */ + /** @var Collection $plugins */ public readonly Collection $plugins, - public readonly string $modules + /** @var Collection $modules */ + public readonly Collection $modules ) { } public static function fromSite(Site $site): self { + $siteUrl = $site->getBaseUrl(); + $environment = Craft::$app->env; + + if (!$siteUrl || !$environment) { + throw new \Exception('$siteUrl or $environment not found'); + } + return new self( - siteUrl: $site->getBaseUrl(), + siteUrl: $siteUrl, siteName: $site->name, - environment: Craft::$app->env, - craftVersion: App::editionName(Craft::$app->getEdition()), + environment: $environment, + craftEdition: App::editionName(Craft::$app->getEdition()), + craftVersion: App::normalizeVersion(Craft::$app->getVersion()), phpVersion: App::phpVersion(), dbVersion: self::_dbDriver(), plugins: Collection::make(Craft::$app->plugins->getAllPlugins()) - ->map(SitePayloadPlugin::fromPluginInterface(...)), + ->map(SitePayloadPlugin::fromPluginInterface(...)) + ->values(), modules: self::_modules() ); } @@ -62,9 +75,9 @@ private static function _dbDriver(): string /** * Returns the list of modules * - * @return string + * @return Collection */ - private static function _modules(): string + private static function _modules(): Collection { $modules = []; @@ -82,7 +95,8 @@ private static function _modules(): string } } - return implode(PHP_EOL, $modules); + // ->values() forces a 0 indexed array + return Collection::make($modules)->values(); } } \ No newline at end of file diff --git a/src/services/PhoneHomeService.php b/src/services/PhoneHomeService.php index 2e168ec..a063d5f 100644 --- a/src/services/PhoneHomeService.php +++ b/src/services/PhoneHomeService.php @@ -4,6 +4,7 @@ use Craft; use craft\helpers\Queue; +use craft\web\Request; use Illuminate\Support\Collection; use viget\phonehome\endpoints\EndpointInterface; use viget\phonehome\jobs\SendPayloadJob; @@ -29,13 +30,13 @@ public function tryQueuePhoneHome(): void Craft::$app->getIsInstalled() === false || Craft::$app->getRequest()->getIsConsoleRequest() || !Craft::$app->getRequest()->getIsCpRequest() // Only run on CP request - || $request->getIsAjax() + || $request instanceof Request && $request->getIsAjax() ) { return; } // Only run when the cache is empty (once per day at most) - if (Craft::$app->getCache()->get(self::CACHE_KEY) !== false) { + if (Craft::$app->getCache()?->get(self::CACHE_KEY) !== false) { return; } From 2fa37abebaa2ad396c6682bfdf7c98ab62f0fdc7 Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Mon, 20 May 2024 10:53:55 -0700 Subject: [PATCH 8/9] Allow modification of property type --- src/endpoints/NotionEndpoint.php | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/endpoints/NotionEndpoint.php b/src/endpoints/NotionEndpoint.php index 4b9205d..e3a9367 100644 --- a/src/endpoints/NotionEndpoint.php +++ b/src/endpoints/NotionEndpoint.php @@ -18,7 +18,6 @@ use Notion\Pages\PageParent; use Notion\Pages\Properties\Date; use Notion\Pages\Properties\MultiSelect; -use Notion\Pages\Properties\RichTextProperty; use Notion\Pages\Properties\Select; use Notion\Pages\Properties\Title; use Notion\Pages\Properties\Url; @@ -84,36 +83,6 @@ public function __construct( { } - /** - * @param string $propertyName - * @param class-string $propertyClass - * @param Database $database Pass by reference because there's some immutable stuff going on in the Notion lib - * @return bool True if property was created - * @throws Exception - */ - private function createProperty(string $propertyName, string $propertyClass, Database &$database): bool - { - $existingProperties = $database->properties()->getAll(); - - // Don't create a property if it already exists - if (!empty($existingProperties[$propertyName])) { - return false; - } - - // If you're using a class that isn't in this list, most likely the ::create - // method is compatible. But it's worth double-checking. - $database = match ($propertyClass) { - UrlDb::class, - SelectDb::class, - MultiSelectDb::class, - RichTextDb::class, - DateDb::class => $database->addProperty($propertyClass::create($propertyName)), - default => throw new Exception("createProperty doesnt support the class $propertyClass. Double check that its ::create method is compatible and add to this method") - }; - - return true; - } - /** * @throws Exception */ @@ -125,7 +94,7 @@ public function send(SitePayload $payload): void // Loop through property config and create properties that don't exist on the DB $updated = false; foreach (self::PROPERTY_CONFIG as $propertyName => $config) { - $didUpdate = $this->createProperty( + $didUpdate = $this->configureProperty( $propertyName, $config['class'], $database @@ -178,4 +147,35 @@ public function send(SitePayload $payload): void $notion->pages()->update($page); } } + + /** + * @param string $propertyName + * @param class-string $propertyClass + * @param Database $database Pass by reference because there's some immutable stuff going on in the Notion lib + * @return bool True if property was created + * @throws Exception + */ + private function configureProperty(string $propertyName, string $propertyClass, Database &$database): bool + { + $existingProperties = $database->properties()->getAll(); + $existingProperty = $existingProperties[$propertyName] ?? null; + + // Don't configure a property if it already exists and has same type + if ($existingProperty && $existingProperty::class === $propertyClass) { + return false; + } + + // If you're using a class that isn't in this list, most likely the ::create + // method is compatible. But it's worth double-checking. + $database = match ($propertyClass) { + UrlDb::class, + SelectDb::class, + MultiSelectDb::class, + RichTextDb::class, + DateDb::class => $database->addProperty($propertyClass::create($propertyName)), + default => throw new Exception("createProperty doesnt support the class $propertyClass. Double check that its ::create method is compatible and add to this method") + }; + + return true; + } } \ No newline at end of file From 66398fc9b3b374dffd47a922bc423c1489f5725b Mon Sep 17 00:00:00 2001 From: Joshua Pease Date: Mon, 20 May 2024 11:27:27 -0700 Subject: [PATCH 9/9] Whoops... remove debug code --- src/PhoneHome.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PhoneHome.php b/src/PhoneHome.php index 496efbe..7e423d3 100644 --- a/src/PhoneHome.php +++ b/src/PhoneHome.php @@ -40,8 +40,6 @@ public function init(): void // If enabled hasn't been configured, enable for non-devMode environments $enabled = $this->getSettings()->enabled ?? Craft::$app->getConfig()->getGeneral()->devMode === false; - $this->phoneHome->sendPayload(); - if (!$enabled) { return; }