add: serverside record models

chore: ui improvements
fix: login modal fail to show if not logged in
fix: cannot set null for nullable fields
This commit is contained in:
2024-04-05 12:42:19 +08:00
parent aeab0dfdbc
commit a4b3a57e1d
Signed by: LuoRain
GPG key ID: 16B4D3D5372966A6
25 changed files with 405 additions and 90 deletions

View file

@ -63,7 +63,7 @@
"prefer-stable": true,
"autoload-dev": {
"psr-4": {
"FoskyM\\OAuthCenter\\Tests\\": "tests/"
"RhodesIsland\\OAuthCenter\\Tests\\": "tests/"
}
},
"archive": {

View file

@ -31,6 +31,7 @@ return [
(new Extend\Routes('forum'))
->post('/oauth/authorize', 'oauth.authorize.post', Controllers\AuthorizeController::class)
->post('/oauth/authorize/redirect', 'oauth.authorize.redirect', Controllers\AuthorizeRedirectController::class)
->post('/oauth/token', 'oauth.token', Controllers\TokenController::class),
(new Extend\Routes('api'))
@ -45,12 +46,16 @@ return [
->patch('/oauth-scopes/{id}', 'oauth.scopes.update', Api\Controller\UpdateScopeController::class)
->delete('/oauth-scopes/{id}', 'oauth.scopes.delete', Api\Controller\DeleteScopeController::class)
->get('/oauth-records', 'oauth.records.list', Api\Controller\ListRecordController::class)
->get('/user', 'user.show', Controllers\ApiUserController::class),
(new Extend\Settings)
->serializeToForum('rhodes-island-oauth-center.display_mode', 'rhodes-island-oauth-center.display_mode')
->serializeToForum('rhodes-island-oauth-center.allow_implicit', 'rhodes-island-oauth-center.allow_implicit', 'boolval')
->serializeToForum('rhodes-island-oauth-center.enforce_state', 'rhodes-island-oauth-center.enforce_state', 'boolval')
->serializeToForum('rhodes-island-oauth-center.require_exact_redirect_uri', 'rhodes-island-oauth-center.require_exact_redirect_uri', 'boolval'),
->serializeToForum('rhodes-island-oauth-center.require_exact_redirect_uri', 'rhodes-island-oauth-center.require_exact_redirect_uri', 'boolval')
->serializeToForum('rhodes-island-oauth-center.use_redirect_authorize', 'rhodes-island-oauth-center.use_redirect_authorize', 'boolval'),
(new Extend\Middleware('api'))
->insertAfter(AuthenticateWithHeader::class, ResourceScopeMiddleware::class),

View file

@ -28,6 +28,11 @@ app.initializers.add('foskym/flarum-oauth-center', () => {
setting: "rhodes-island-oauth-center.require_exact_redirect_uri",
type: "boolean"
})
.registerSetting({
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.use_redirect_authorize'),
setting: "rhodes-island-oauth-center.use_redirect_authorize",
type: "boolean"
})
.registerSetting({
label: app.translator.trans('rhodes-island-oauth-center.admin.settings.access_lifetime'),
setting: "rhodes-island-oauth-center.access_lifetime",

View file

@ -1,9 +1,11 @@
import Extend from 'flarum/common/extenders';
import Client from "./models/Client";
import Scope from "./models/Scope";
import Record from './models/Record';
export default [
new Extend.Store()
.add('oauth-clients', Client)
.add('oauth-scopes', Scope),
.add('oauth-scopes', Scope)
.add('oauth-records', Record),
];

View file

@ -4,11 +4,11 @@ export default class Client extends Model {
client_id = Model.attribute<string>('client_id');
client_secret = Model.attribute<string>('client_secret');
redirect_uri = Model.attribute<string>('redirect_uri');
grant_types = Model.attribute<string>('grant_types');
scope = Model.attribute<string>('scope');
grant_types = Model.attribute<string | null>('grant_types');
scope = Model.attribute<string | null>('scope');
user_id = Model.attribute<number>('user_id');
client_name = Model.attribute<string>('client_name');
client_icon = Model.attribute<string>('client_icon');
client_desc = Model.attribute<string>('client_desc');
client_home = Model.attribute<string>('client_home');
client_icon = Model.attribute<string | null>('client_icon');
client_desc = Model.attribute<string | null>('client_desc');
client_home = Model.attribute<string | null>('client_home');
}

View file

@ -0,0 +1,8 @@
import Model from 'flarum/common/Model';
import type Client from './Client';
export default class Record extends Model {
client = Model.hasOne<Client>('client');
user_id = Model.attribute<number>('user_id');
authorized_at = Model.attribute<Date, string>('authorized_at', Model.transformDate);
}

View file

@ -86,7 +86,6 @@ export default class AuthorizePage extends IndexPage {
finalScopes.push(definedScope);
}
}
console.log(wantedScopes, definedScopes, finalScopes);
this.clientScopes = finalScopes;
this.loading = false;
@ -103,7 +102,7 @@ export default class AuthorizePage extends IndexPage {
super.oncreate(vnode);
if (!app.session.user) {
app.modal.show(LogInModal);
setTimeout(() => app.modal.show(LogInModal)); // make sure mithril wont get double redraw
}
}
@ -136,14 +135,14 @@ export default class AuthorizePage extends IndexPage {
<div className="OAuth-Details">
<div className="OAuth-App">
<p>{app.translator.trans('rhodes-island-oauth-center.forum.authorize.app_text')}</p>
{(clientHome && clientHome != "" ? <Tooltip text={app.translator.trans('rhodes-island-oauth-center.forum.authorize.to_app_homepage', { name: this.client!!.client_name() })}>
{(clientHome ? <Tooltip text={app.translator.trans('rhodes-island-oauth-center.forum.authorize.to_app_homepage', { name: this.client!!.client_name() })}>
<a href={clientHome} target="_blank" className="OAuth-App-Info">
{clientIcon && clientIcon != "" ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
{clientIcon ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
<p>{this.client!!.client_name()}</p>
<small>{this.client!!.client_desc()}</small>
</a>
</Tooltip> : <div className="OAuth-App-Info">
{clientIcon && clientIcon != "" ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
{clientIcon ? <img src={clientIcon} class="OAuth-App-Icon"/> : <i class="OAuth-App-Icon fas fa-5x fa-cube"></i>}
<p>{this.client!!.client_name()}</p>
<small>{this.client!!.client_desc()}</small>
</div>)}
@ -176,16 +175,16 @@ export default class AuthorizePage extends IndexPage {
}
</div>
</div>
<div class="OAuth-Action">
<Button className="Button Button--primary Button--block" onclick={() => this.submit(true)}
loading={this.submitting}>
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.agree')}
</Button>
<Button className="Button Button--link Button--block" onclick={() => this.submit(false)}
loading={this.submitting}>
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.deny')}
</Button>
</div>
{this.submitting ? <LoadingIndicator/> :
<div class="OAuth-Action">
<Button className="Button Button--primary Button--block" onclick={() => this.submit(true)}>
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.agree')}
</Button>
<Button className="Button Button--link Button--block" onclick={() => this.submit(false)}>
{app.translator.trans('rhodes-island-oauth-center.forum.authorize.deny')}
</Button>
</div>
}
</div>
</div>
</div>
@ -194,19 +193,37 @@ export default class AuthorizePage extends IndexPage {
submit(authorized: boolean) {
this.submitting = true;
app.request({
method: 'POST',
url: '/oauth/authorize',
body: {
response_type: this.params!!.response_type,
client_id: this.params!!.client_id,
redirect_uri: this.params!!.redirect_uri,
state: this.params!!.state,
scope: this.params!!.scope,
is_authorized: authorized,
const form = {
response_type: this.params!!.response_type,
client_id: this.params!!.client_id,
redirect_uri: this.params!!.redirect_uri,
state: this.params!!.state,
scope: this.params!!.scope,
is_authorized: authorized,
};
if (app.forum.attribute('rhodes-island-oauth-center.use_redirect_authorize')) {
const formEl = document.createElement("form");
formEl.style.display = "none";
formEl.action = "/oauth/authorize/redirect";
formEl.method = "POST";
for (const k in form) {
const el = document.createElement("input");
el.name = k;
el.value = (form as any)[k];
formEl.appendChild(el);
}
}).then((params: any) => {
window.location.href = params.location;
});
document.body.appendChild(formEl);
formEl.submit();
} else {
app.request({
method: 'POST',
url: '/oauth/authorize',
body: form
}).then((params: any) => {
window.location.href = params.redirect;
}).catch(() => {
// TODO: error handling
});
}
}
}

View file

@ -1,14 +1,65 @@
import app from "flarum/common/app";
import LoadingIndicator from "flarum/common/components/LoadingIndicator";
import Placeholder from "flarum/common/components/Placeholder";
import UserPage from 'flarum/forum/components/UserPage';
import type Client from "src/common/models/Client";
import type Record from "src/common/models/Record";
export default class AuthorizedPage extends UserPage {
records: Record[] = [];
loading = true;
nomore = false;
page = 0;
oninit(vnode: any) {
super.oninit(vnode);
this.loadUser(m.route.param('username'));
this.loadRecords();
}
loadRecords() {
app.store.find('oauth-records', { page: this.page } as any).then(records => {
this.records = this.records.concat(records as unknown as Record[]);
this.loading = false;
if (this.records.length < 10) {
this.nomore = true;
}
m.redraw();
});
}
loadMore() {
this.loadRecords();
this.page += 1
}
content() {
if (this.records.length == 0) {
return <Placeholder>{app.translator.trans('rhodes-island-oauth-center.forum.authorized.no_records')}</Placeholder>;
}
return (
<div className="AuthorizedPage">
<div className="AuthorizedRecords">
{this.records.map(record =>
{
const client = record.attribute("client") as Client;
return <li className="AuthorizedRecord">
<h3>
{client.client_name}
<time>
{record.authorized_at().toLocaleString()}
</time>
</h3>
<p>{client.client_desc}</p>
<hr />
</li>
}
)}
</div>
{this.loading && <LoadingIndicator/>}
</div>
);
}

View file

@ -1,14 +0,0 @@
import app from 'flarum/forum/app';
import AuthorizePage from "./components/oauth/AuthorizePage";
import AuthorizedPage from "./components/user/AuthorizedPage";
app.initializers.add('foskym/flarum-oauth-center', () => {
app.routes['oauth.authorize'] = {
path: '/oauth/authorize',
component: AuthorizePage
};
app.routes['user.authorized'] = {
path: '/u/:username/authorized',
component: AuthorizedPage
};
});

28
js/src/forum/index.tsx Normal file
View file

@ -0,0 +1,28 @@
import app from 'flarum/forum/app';
import { extend } from 'flarum/common/extend';
import AuthorizePage from "./components/oauth/AuthorizePage";
import AuthorizedPage from "./components/user/AuthorizedPage";
import UserPage from 'flarum/forum/components/UserPage';
import LinkButton from "flarum/common/components/LinkButton";
app.initializers.add('foskym/flarum-oauth-center', () => {
app.routes['oauth.authorize'] = {
path: '/oauth/authorize',
component: AuthorizePage
};
app.routes['user.authorized'] = {
path: '/u/:username/authorized',
component: AuthorizedPage
};
/*extend(UserPage.prototype, 'navItems', function (items) {
if (app.session.user?.id() === this.user?.id()) {
items.add(
'authorized',
<LinkButton href={app.route('user.authorized', { username: this.user!!.username() })} icon="fas fa-user-friends">{app.translator.trans('rhodes-island-oauth-center.forum.page.label.authorized')}</LinkButton>,
-110
);
}
});*/ // TODO: finish this
});

View file

@ -42,7 +42,7 @@ rhodes-island-oauth-center:
title:
authorize: Authorize
label:
authorized: Authorized Logs
authorized: Authorization Logs
authorize:
title: Third party application authorization
description: Authorize third party application to use your identity

View file

@ -11,6 +11,7 @@ rhodes-island-oauth-center:
allow_implicit: 允许隐式授权response_type=token
enforce_state: 强制状态验证state 参数)
require_exact_redirect_uri: 需要精确的重定向 URI
use_redirect_authorize: 授权时直接进行跳转
clients:
client_id: 应用 ID
client_secret: 应用密钥
@ -52,3 +53,5 @@ rhodes-island-oauth-center:
agree: 授权
deny: 拒绝
not_logged_in: 请登录后再继续操作
authorized:
no_records: 无授权记录

View file

@ -0,0 +1,29 @@
<?php
/*
* This file is part of foskym/flarum-oauth-center.
*
* Copyright (c) 2023 FoskyM.
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\Builder;
return [
'up' => function (Builder $schema) {
if ($schema->hasTable('oauth_records')) {
return;
}
$schema->create('oauth_records', function (Blueprint $table) {
$table->increments('id');
$table->string('client_id', 80);
$table->string('user_id', 80)->nullable();
$table->timestamp('authorized_at');
});
},
'down' => function (Builder $schema) {
$schema->dropIfExists('oauth_records');
},
];

View file

@ -6,6 +6,7 @@ use Flarum\Api\Controller\AbstractCreateController;
use Flarum\Http\RequestUtil;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use RhodesIsland\OAuthCenter\Utils;
use Tobscure\JsonApi\Document;
use RhodesIsland\OAuthCenter\Models\Client;
use RhodesIsland\OAuthCenter\Api\Serializer\ClientSerializer;
@ -20,17 +21,9 @@ class CreateClientController extends AbstractCreateController
$attributes = Arr::get($request->getParsedBody(), 'data.attributes');
$validAttrs = [
'user_id' => $actor->id
];
$attrs = Utils::processAttributes($attributes, Utils::CLIENT_ATTRIBUTES, Utils::CLIENT_NULLABLE_ATTRIBUTES);
$attrs["user_id"] = $actor->id;
collect(['client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'client_name', 'client_desc', 'client_icon', 'client_home'])
->each(function (string $attribute) use (&$validAttrs, $attributes) {
if (($val = Arr::get($attributes, $attribute)) !== null) {
$validAttrs[$attribute] = $val;
}
});
return Client::create($validAttrs);
return Client::create($attrs);
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace RhodesIsland\OAuthCenter\Api\Controller;
use Flarum\Api\Controller\AbstractListController;
use Flarum\Http\RequestUtil;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
use RhodesIsland\OAuthCenter\Models\Record;
use RhodesIsland\OAuthCenter\Api\Serializer\RecordSerializer;
class ListRecordController extends AbstractListController
{
public $serializer = RecordSerializer::class;
protected function data(ServerRequestInterface $request, Document $document)
{
$page = Arr::get($request->getQueryParams(), 'page', 0);
$actor = RequestUtil::getActor($request);
$actor->assertRegistered();
$pageSize = 10;
$skip = $page * $pageSize;
$records = Record::where('user_id', $actor->id)
->orderBy('authorized_at', 'desc')
->skip($skip)
->take($pageSize)
->get();
return $records;
}
}

View file

@ -6,6 +6,7 @@ use Flarum\Api\Controller\AbstractListController;
use Flarum\Http\RequestUtil;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use RhodesIsland\OAuthCenter\Utils;
use Tobscure\JsonApi\Document;
use RhodesIsland\OAuthCenter\Models\Client;
use RhodesIsland\OAuthCenter\Api\Serializer\ClientSerializer;
@ -23,12 +24,11 @@ class UpdateClientController extends AbstractListController
$attributes = Arr::get($request->getParsedBody(), 'data.attributes', []);
collect(['client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'client_name', 'client_desc', 'client_icon', 'client_home'])
->each(function (string $attribute) use ($client, $attributes) {
if (($val = Arr::get($attributes, $attribute)) !== null) {
$client->$attribute = $val;
}
});
$attrs = Utils::processAttributes($attributes, Utils::CLIENT_ATTRIBUTES, Utils::CLIENT_NULLABLE_ATTRIBUTES);
foreach ($attrs as $k => $v) {
$client[$k] = $v;
}
$client->save();

View file

@ -0,0 +1,30 @@
<?php
namespace RhodesIsland\OAuthCenter\Api\Serializer;
use Flarum\Api\Serializer\AbstractSerializer;
use RhodesIsland\OAuthCenter\Models\Record;
use InvalidArgumentException;
class RecordSerializer extends AbstractSerializer
{
protected $type = 'oauth-records';
protected function getDefaultAttributes($model)
{
if (!($model instanceof Record)) {
throw new InvalidArgumentException(
get_class($this) . ' can only serialize instances of ' . Record::class
);
}
// See https://docs.flarum.org/extend/api.html#serializers for more information.
return [
"id" => $model->id,
"client" => $model->client,
"user_id" => $model->user_id,
"authorized_at" => $model->authorized_at
];
}
}

View file

@ -9,16 +9,12 @@
* file that was distributed with this source code.
*/
namespace RhodesIsland\OAuthCenter\Controllers;
use Flarum\User\User;
use Flarum\Http\RequestUtil;
use RhodesIsland\OAuthCenter\OAuth;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Diactoros\Response\JsonResponse;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\Group\Group;
class ApiUserController implements RequestHandlerInterface
{

View file

@ -9,8 +9,8 @@
* file that was distributed with this source code.
*/
namespace RhodesIsland\OAuthCenter\Controllers;
use Flarum\User\User;
use Flarum\Http\RequestUtil;
use RhodesIsland\OAuthCenter\Models\Record;
use RhodesIsland\OAuthCenter\OAuth;
use Illuminate\Support\Arr;
use Psr\Http\Message\ResponseInterface;
@ -18,7 +18,6 @@ use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Diactoros\Response\JsonResponse;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\Group\Group;
class AuthorizeController implements RequestHandlerInterface
{
@ -34,6 +33,7 @@ class AuthorizeController implements RequestHandlerInterface
$actor->assertRegistered();
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
// TODO: i18n description
return new JsonResponse([ 'error' => 'no_permission', 'error_description' => 'Don\'t have the permissions of oauth' ]);
}
@ -45,18 +45,23 @@ class AuthorizeController implements RequestHandlerInterface
$response = $oauth->response();
if (!$server->validateAuthorizeRequest($request, $response)) {
return new JsonResponse(json_decode($response->getResponseBody(), true));
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
}
$is_authorized = Arr::get($params, 'is_authorized', 0);
$server->handleAuthorizeRequest($request, $response, $is_authorized, $actor->id);
if ($is_authorized) {
// $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
/*Record::create([
'client_id' => Arr::get($params, 'client_id'),
'user_id' => $actor->id,
'authorized_at' => date('Y-m-d H:i:s')
]);*/
return new JsonResponse([
'location' => $response->getHttpHeader('Location')
"redirect" => $response->getHttpHeader("Location")
]);
}
return new JsonResponse(json_decode($response->getResponseBody(), true));
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
}
}

View file

@ -0,0 +1,65 @@
<?php
/*
* This file is part of foskym/flarum-oauth-center.
*
* Copyright (c) 2024 FoskyM.
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/
namespace RhodesIsland\OAuthCenter\Controllers;
use Flarum\Http\RequestUtil;
use RhodesIsland\OAuthCenter\Models\Record;
use RhodesIsland\OAuthCenter\OAuth;
use Illuminate\Support\Arr;
use Laminas\Diactoros\Response\HtmlResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Diactoros\Response\JsonResponse;
use Flarum\Settings\SettingsRepositoryInterface;
class AuthorizeRedirectController implements RequestHandlerInterface
{
protected $settings;
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$actor = RequestUtil::getActor($request);
$actor->assertRegistered();
if (!$actor->hasPermission('rhodes-island-oauth-center.use-oauth')) {
// TODO: better error response
return new HtmlResponse('Don\'t have the permissions of oauth');
}
$params = $request->getParsedBody();
$oauth = new OAuth($this->settings);
$server = $oauth->server();
$request = $oauth->request()::createFromGlobals();
$response = $oauth->response();
if (!$server->validateAuthorizeRequest($request, $response)) {
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
}
$is_authorized = (bool) Arr::get($params, 'is_authorized', 0);
$server->handleAuthorizeRequest($request, $response, $is_authorized, $actor->id);
if ($is_authorized) {
/*Record::create([
'client_id' => Arr::get($params, 'client_id'),
'user_id' => $actor->id,
'authorized_at' => date('Y-m-d H:i:s')
]);*/
}
return new JsonResponse($response->getParameters(), $response->getStatusCode(), $response->getHttpHeaders());
}
}

View file

@ -2,28 +2,18 @@
namespace RhodesIsland\OAuthCenter\Middlewares;
use Flarum\Foundation\ErrorHandling\ExceptionHandler\IlluminateValidationExceptionHandler;
use Flarum\Foundation\ErrorHandling\JsonApiFormatter;
use RhodesIsland\OAuthCenter\OAuth;
use RhodesIsland\OAuthCenter\Storage;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Flarum\Http\RequestUtil;
use Flarum\Api\JsonApiResponse;
use Tobscure\JsonApi\Document;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
use RhodesIsland\OAuthCenter\Models\Scope;
class UnsetCsrfMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandlerInterface $handler): Response
{
$uri = [
'/oauth/token',
'/oauth/authorize/redirect'
];
$path = $request->getUri()->getPath();
if (in_array($path, $uri)) {

View file

@ -27,4 +27,9 @@ class Client extends AbstractModel
return $client;
}
public function record()
{
return $this->hasMany(Record::class, 'client_id', 'client_id');
}
}

24
src/Models/Record.php Normal file
View file

@ -0,0 +1,24 @@
<?php
/*
* This file is part of foskym/flarum-oauth-center.
*
* Copyright (c) 2023 FoskyM.
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/
namespace RhodesIsland\OAuthCenter\Models;
use Flarum\Database\AbstractModel;
class Record extends AbstractModel
{
protected $table = 'oauth_records';
protected $guarded = [];
public function client()
{
return $this->belongsTo(Client::class, 'client_id', 'client_id');
}
}

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace RhodesIsland\OAuthCenter;
use Flarum\Extend\Model;
use Flarum\User\User;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use OAuth2\OpenID\Storage\UserClaimsInterface;

40
src/Utils.php Normal file
View file

@ -0,0 +1,40 @@
<?php
namespace RhodesIsland\OAuthCenter;
use Illuminate\Support\Arr;
class Utils {
public const CLIENT_ATTRIBUTES = [
"client_id",
"client_secret",
"redirect_uri",
"client_name"
];
public const CLIENT_NULLABLE_ATTRIBUTES = [
"grant_types",
"scope",
"client_icon",
"client_desc",
"client_home"
];
public static function nullIfEmpty(string $value): string | null {
return $value == "" ? null : $value;
}
public static function processAttributes(array $attributes, array $requiredAttributes, array $nullableAttributes): array {
$result = [];
collect($requiredAttributes)->each(function (string $attribute) use (&$result, $attributes) {
if (($val = Arr::get($attributes, $attribute)) !== null) {
$result[$attribute] = $val;
}
});
collect($nullableAttributes)->each(function (string $attribute) use (&$result, $attributes) {
if (($val = Arr::get($attributes, $attribute)) !== null) {
$result[$attribute] = Utils::nullIfEmpty($val);
}
});
return $result;
}
}