Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Craft 4 #43

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# OAuth 2.0 Client Changelog

All notable changes to this project will be documented in this file.
## 4.0.0-beta.1 - Unreleased

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Now requires Craft 4 & PHP 8.0.2
- Apps no longer keep track of who created them

## Fixed
- Fixed saving an app with no scopes producing an error

### Removed
- Removed route `oauthclient/authorize/refresh/` use `oauth/authorize/refresh/` instead
- Removed route `oauthclient/authorize/` use `oauth/authorize/` instead
- Removed `Plugin::$plugin` static property - use `Plugin::getInstance()` instead
- Removed `userId` property from Apps

## 2.1.9 - 2021-03-30
### Added
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
OAuth 2.0 Client plugin for Craft CMS 3
OAuth 2.0 Client plugin for Craft CMS 4
===

This plugin provides developers with an easy centralized approach to managing and storing OAuth 2.0
Expand Down Expand Up @@ -26,7 +26,7 @@ act as an authentication provider for users to login to the CMS.

## Requirements

This plugin should work on Craft CMS 3.1.34.3 or later
This plugin should work on Craft CMS 4.0.0 or later

## Installation

Expand Down Expand Up @@ -222,7 +222,7 @@ use venveo\oauthclient\Plugin;

// Get the plugin instance. Note: make sure you do this after the application has been inited, such as in a route or
// event.
$plugin = Plugin::$plugin;
$plugin = Plugin::getInstance();
// Let's grab a valid token - we could pass the current user ID in here to limit it
$tokens = $plugin->credentials->getValidTokensForAppAndUser('google');
// Get the app from the apps service
Expand Down
11 changes: 5 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "venveo/craft-oauthclient",
"description": "Simple OAuth 2.0 client",
"type": "craft-plugin",
"version": "2.1.9",
"version": "4.0.0-beta.1",
"keywords": [
"craft",
"cms",
Expand All @@ -22,9 +22,10 @@
}
],
"require": {
"craftcms/cms": "^3.1.34.3",
"php": "^8.0.2",
"craftcms/cms": "^4.0",
"league/oauth2-client": "^2.2.1",
"league/oauth2-google": "^2.2 || ^3.0",
"league/oauth2-google": "^4.0",
"league/oauth2-facebook": "^2.0",
"league/oauth2-github": "^2.0 || ^3.0"
},
Expand All @@ -34,11 +35,9 @@
}
},
"extra": {
"hasCpSettings": true,
"hasCpSection": false,
"name": "OAuth 2.0 Client",
"handle": "oauthclient",
"changelogUrl": "https://raw.githubusercontent.com/venveo/craft-oauthclient/master/CHANGELOG.md",
"changelogUrl": "https://raw.githubusercontent.com/venveo/craft-oauthclient/main/CHANGELOG.md",
"class": "venveo\\oauthclient\\Plugin"
}
}
98 changes: 44 additions & 54 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
use craft\events\RegisterUrlRulesEvent;
use craft\events\RegisterUserPermissionsEvent;
use craft\helpers\UrlHelper;
use craft\log\FileTarget;
use craft\log\MonologTarget;
use craft\services\ProjectConfig;
use craft\services\UserPermissions;
use craft\web\twig\variables\CraftVariable;
use craft\web\UrlManager;
use Monolog\Formatter\LineFormatter;
use Psr\Log\LogLevel;
use venveo\oauthclient\services\Apps as AppsService;
use venveo\oauthclient\services\Credentials as CredentialsService;
use venveo\oauthclient\services\Providers;
Expand All @@ -42,44 +44,27 @@
*/
class Plugin extends BasePlugin
{
const HANDLE = 'oauthclient';

// Static Properties
// =========================================================================
public static $PROJECT_CONFIG_KEY = 'oauthClient';
public const HANDLE = 'oauthclient';

public static string $PROJECT_CONFIG_KEY = 'oauthClient';

/**
* @var Plugin
*/
public static $plugin;
public string $schemaVersion = '4.0.0';
public bool $hasCpSettings = true;

// Public Properties
// =========================================================================

/**
* @var string
*/
public $schemaVersion = '2.1.3';
public $hasCpSettings = true;

// Public Methods
// =========================================================================

/**
* @inheritdoc
*/
public function init()
public function init(): void
{
parent::init();
self::$plugin = $this;

if (Craft::$app->request->getIsConsoleRequest()) {
$this->controllerNamespace = 'venveo\oauthclient\console\controllers';
}

$this->_registerLogger();
$this->_setComponents();
$this->_registerCpRoutes();
$this->_registerVariables();
$this->_registerProjectConfig();
Expand All @@ -92,35 +77,42 @@ public function init()
/**
* Register a custom logger
*/
private function _registerLogger()
private function _registerLogger(): void
{
Craft::getLogger()->dispatcher->targets[] = new FileTarget([
'logFile' => Craft::getAlias('@storage/logs/oauthclient.log'),
'categories' => ['venveo\oauthclient\*'],
Craft::getLogger()->dispatcher->targets[] = new MonologTarget([
'name' => 'oauthclient',
'categories' => ['venveo\oauthcleint\*'],
'level' => LogLevel::INFO,
'logContext' => false,
'allowLineBreaks' => false,
'formatter' => new LineFormatter(
format: "[%datetime%] %message%\n",
dateFormat: 'Y-m-d H:i:s',
),
]);
}

// Private Methods
// =========================================================================

/**
* Set our service components
* @inheritdoc
*/
private function _setComponents()
public static function config(): array
{
$this->setComponents([
'apps' => AppsService::class,
'providers' => ProvidersService::class,
'tokens' => TokensService::class,
'credentials' => CredentialsService::class,
]);

return [
'components' => [
'apps' => ['class' => AppsService::class],
'providers' => ['class' => ProvidersService::class],
'tokens' => ['class' => TokensService::class],
'credentials' => ['class' => CredentialsService::class]
],
];
}


/**
* Adds the event handler for registering CP routes
*/
private function _registerCpRoutes()
private function _registerCpRoutes(): void
{
Event::on(UrlManager::class, UrlManager::EVENT_REGISTER_CP_URL_RULES, function (RegisterUrlRulesEvent $event) {
$event->rules = array_merge($event->rules, [
Expand All @@ -130,11 +122,6 @@ private function _registerCpRoutes()
'oauthclient/apps/<handle:{handle}>' => 'oauthclient/apps/edit',
'oauthclient/apps/delete' => 'oauthclient/apps/delete',

// TODO: Remove these in next version in favor of `oauth` route
'oauthclient/authorize/refresh/<id:\d+>' => 'oauthclient/authorize/refresh',
'oauthclient/authorize/<handle:{handle}>' => 'oauthclient/authorize/authorize-app',
// These are duplicates of potentially non-admin-facing actions. Craft automatically checks routes for
// the plugin handle, so we needed new routes without the handle.
'oauth/authorize/refresh/<id:\d+>' => 'oauthclient/authorize/refresh',
'oauth/authorize/<handle:{handle}>' => 'oauthclient/authorize/authorize-app',
]);
Expand All @@ -144,7 +131,7 @@ private function _registerCpRoutes()
/**
* Set our Twig variable
*/
private function _registerVariables()
private function _registerVariables(): void
{
Event::on(
CraftVariable::class,
Expand All @@ -159,7 +146,7 @@ function (Event $event) {
/**
* Register project config handlers
*/
private function _registerProjectConfig()
private function _registerProjectConfig(): void
{
Craft::$app->projectConfig
->onAdd(self::$PROJECT_CONFIG_KEY . '.apps.{uid}', [$this->apps, 'handleUpdatedApp'])
Expand All @@ -175,7 +162,7 @@ private function _registerProjectConfig()
* Handle project config rebuilding
* @param RebuildConfigEvent $e
*/
private function _handleProjectConfigRebuild(RebuildConfigEvent $e)
private function _handleProjectConfigRebuild(RebuildConfigEvent $e): void
{
$appData = [];
$apps = $this->apps->getAllApps();
Expand All @@ -197,32 +184,35 @@ private function _handleProjectConfigRebuild(RebuildConfigEvent $e)
private function _registerPermissions()
{
Event::on(UserPermissions::class, UserPermissions::EVENT_REGISTER_PERMISSIONS, function (RegisterUserPermissionsEvent $event) {
$apps = Plugin::$plugin->apps->getAllApps();
$apps = $this->apps->getAllApps();
$loginPermissions = [];
foreach ($apps as $app) {
$suffix = ':' . $app->uid;
$loginPermissions['oauthclient-login' . $suffix] = ['label' => self::t('Login to “{name}” ({handle}) app', ['name' => $app->name, 'handle' => $app->handle])];
}
$event->permissions[self::t('OAuth Client')] = [
'oauthclient-login' => [
'label' => self::t('Login to Apps'), 'nested' => $loginPermissions
]
$event->permissions[] = [
'heading' => self::t('OAuth Client'),
'permissions' => [
'oauthclient-login' => [
'label' => self::t('Login to Apps'), 'nested' => $loginPermissions
]
],
];
});
}

/**
* @see Craft::t()
*/
public static function t($message, $params = [], $language = null)
public static function t($message, $params = [], $language = null): string
{
return Craft::t(self::HANDLE, $message, $params, $language);
}

/**
* @inheritdoc
*/
public function getSettingsResponse()
public function getSettingsResponse(): mixed
{
return Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('oauthclient/apps'));
}
Expand Down
6 changes: 3 additions & 3 deletions src/base/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/
abstract class Provider extends Component implements ProviderInterface
{
const EVENT_CREATE_TOKEN_MODEL_FROM_RESPONSE = 'EVENT_CREATE_TOKEN_MODEL_FROM_RESPONSE';
public const EVENT_CREATE_TOKEN_MODEL_FROM_RESPONSE = 'EVENT_CREATE_TOKEN_MODEL_FROM_RESPONSE';

protected $configuredProvider;
private $app;
Expand Down Expand Up @@ -53,7 +53,7 @@ public function getDefaultAuthorizationUrlOptions(): array
* @inheritDoc
* @throws ReflectionException
*/
public function getConfiguredProvider()
public function getConfiguredProvider(): AbstractProvider
{
if ($this->configuredProvider instanceof AbstractProvider) {
return $this->configuredProvider;
Expand Down Expand Up @@ -113,7 +113,7 @@ public function setApp(AppModel $app)

/**
* Gets a unique state parameter. We're gonna use the CSRF token by default
* @return string|null
* @return string
*/
public function getState(): string
{
Expand Down
6 changes: 3 additions & 3 deletions src/base/ProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static function getProviderClass(): string;
* Gets a concrete League provider instance
* @return AbstractProvider
*/
public function getConfiguredProvider();
public function getConfiguredProvider(): AbstractProvider;

/**
* Get the URL used to authorize the token
Expand All @@ -41,12 +41,12 @@ public function getAuthorizeURL($options): string;

/**
* Get the session security state
* @return string|null
* @return string
*/
public function getState(): string;

/**
* Gets an access token, returing a League access token
* Gets an access token, returning a League access token
* @param $grant
* @param array $options
* @return AccessTokenInterface
Expand Down
15 changes: 7 additions & 8 deletions src/console/controllers/AppsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
namespace venveo\oauthclient\console\controllers;

use craft\console\Controller;
use venveo\oauthclient\models\Token;
use venveo\oauthclient\Plugin;
use yii\console\ExitCode;

class AppsController extends Controller
{
Expand All @@ -19,24 +19,23 @@ class AppsController extends Controller
* @param $appHandle
* @return int
*/
public function actionRefreshTokens($appHandle)
public function actionRefreshTokens($appHandle): int
{
$credentialService = Plugin::$plugin->credentials;
$appService = Plugin::$plugin->apps;
$credentialService = Plugin::getInstance()->credentials;
$appService = Plugin::getInstance()->apps;
if (!$app = $appService->getAppByHandle($appHandle)) {
$this->stderr('No app found with that handle' . PHP_EOL);
return 1;
return ExitCode::UNSPECIFIED_ERROR;
}

$tokens = $app->getAllTokens();
$total = count($tokens);
if (!$total) {
$this->stdout('No tokens exist for that app' . PHP_EOL);
return 0;
return ExitCode::OK;
}
$progress = 0;
$hadErrors = false;
/** @var Token $token */
foreach ($tokens as $token) {
++$progress;
$prefix = "($progress/$total)";
Expand All @@ -49,6 +48,6 @@ public function actionRefreshTokens($appHandle)
}
}

return $hadErrors ? 1 : 0;
return $hadErrors ? ExitCode::UNSPECIFIED_ERROR : ExitCode::OK;
}
}
Loading