Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e94165b
chore(2.0): update dependencies
dsevillamartin May 28, 2025
4d67dbd
chore(2.0): JSON:API changes
dsevillamartin May 28, 2025
ebbbc22
chore(2.0): Search & Filter API changes
dsevillamartin May 28, 2025
8898e32
wip more flarum v2 upgrades
dsevillamartin May 28, 2025
4aaea1a
Apply fixes from StyleCI
StyleCIBot May 28, 2025
b790e68
delete unused action
dsevillamartin May 28, 2025
2dcf0db
Use ProviderResource for listing linked accs, add working gambit/filter
dsevillamartin May 29, 2025
8eefc6a
Update GitHub workflows to Flarum 2.0
dsevillamartin May 29, 2025
901a97b
Refactor forum class names & clean up some styles for security page
dsevillamartin May 29, 2025
ba5df73
Reduce padding between settings items in admin
dsevillamartin May 29, 2025
d95175c
Apply fixes from StyleCI
StyleCIBot May 29, 2025
4703402
Update fof/extend req to be remote ds/2.0 branch
dsevillamartin May 29, 2025
e599070
Make user.loginProvider be null if not using (but logged in)
dsevillamartin May 29, 2025
7b2e787
Fix phpstan errors
dsevillamartin May 29, 2025
9106d76
Apply fixes from StyleCI
StyleCIBot May 29, 2025
e8bef84
Make AuthSettingsPage have <form> and provider settings not interacta…
dsevillamartin May 30, 2025
6357302
Show group to assign in collapsed view
dsevillamartin Jun 7, 2025
b8acbfa
Increase space between provider settings in admin
dsevillamartin Nov 17, 2025
7fd86c6
Apply fixes from StyleCI
StyleCIBot Nov 17, 2025
2714959
Revert custom avatar upload handling -- let Flarum core take care of it
dsevillamartin Nov 17, 2025
ce7c241
Fix Security page not properly updating status when (un)linking provi…
dsevillamartin Nov 17, 2025
cff8bcd
Apply fixes from StyleCI
StyleCIBot Nov 17, 2025
8ee8276
Adjust error handling of validation exception (account already linked…
dsevillamartin Nov 23, 2025
03be46d
Adjust comments and remove extra log in error handler
dsevillamartin Nov 30, 2025
496262e
Apply fixes from StyleCI
StyleCIBot Nov 30, 2025
1aea38c
Update flarum/core and fof/extend requirements to not include beta or…
dsevillamartin Nov 30, 2025
ecf4403
chore: Increase PHPStan to level 6, deal with test deprecations, othe…
imorland Dec 17, 2025
777a787
Apply fixes from StyleCI
StyleCIBot Dec 17, 2025
f3c2897
Merge branch '2.x' into ds/2.0
imorland Dec 17, 2025
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
3 changes: 1 addition & 2 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ on: [workflow_dispatch, push, pull_request]

jobs:
run:
uses: flarum/framework/.github/workflows/REUSABLE_backend.yml@1.x
uses: flarum/framework/.github/workflows/REUSABLE_backend.yml@2.x
with:
enable_backend_testing: true
enable_phpstan: true
php_versions: '["7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]'

backend_directory: .
4 changes: 2 additions & 2 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [workflow_dispatch, push, pull_request]

jobs:
run:
uses: flarum/framework/.github/workflows/REUSABLE_frontend.yml@1.x
uses: flarum/framework/.github/workflows/REUSABLE_frontend.yml@2.x
with:
enable_bundlewatch: false
enable_prettier: true
Expand All @@ -13,7 +13,7 @@ jobs:
frontend_directory: ./js
backend_directory: .
js_package_manager: yarn
main_git_branch: 1.x
main_git_branch: 2.x

secrets:
bundlewatch_github_token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}
15 changes: 8 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@
}
],
"require": {
"php": "^7.4 || ^8.0",
"flarum/core": "^1.8.1",
"flarum/core": "^2.0.0",
"league/oauth1-client": "^1.10.1",
"league/oauth2-facebook": "^2.2.0",
"league/oauth2-github": "^3.1.0",
"league/oauth2-google": "^4.0.1",
"omines/oauth2-gitlab": "^3.3.0",
"wohali/oauth2-discord-new": "^1.2.1",
"fof/extend": "^1.3.3"
"fof/extend": "^2.0.0"
},
"minimum-stability": "beta",
"prefer-stable": true,
"replace": {
"flarum/auth-facebook": "*",
"flarum/auth-github": "*",
Expand Down Expand Up @@ -77,8 +78,8 @@
"flarum/gdpr"
]
},
"flagrow": {
"discuss": "https://discuss.flarum.org/d/25182"
"branch-alias": {
"dev-2.x": "2.x-dev"
},
"flarum-cli": {
"modules": {
Expand All @@ -88,8 +89,8 @@
}
},
"require-dev": {
"flarum/phpstan": "*",
"flarum/testing": "^1.0.0"
"flarum/phpstan": "^2.0.0",
"flarum/testing": "^2.0.0"
},
"scripts": {
"analyse:phpstan": "phpstan analyse",
Expand Down
38 changes: 16 additions & 22 deletions extend.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@

namespace FoF\OAuth;

use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Api\Context;
use Flarum\Api\Resource;
use Flarum\Api\Schema;
use Flarum\Extend;
use Flarum\Frontend\Document;
use Flarum\Search\Database\DatabaseSearchDriver;
use Flarum\User\Event\LoggedOut;
use Flarum\User\Event\RegisteringFromProvider;
use Flarum\User\Filter\UserFilterer;
use Flarum\User\Search\UserSearcher;
use FoF\Extend\Events\OAuthLoginSuccessful;

Expand Down Expand Up @@ -45,16 +46,15 @@
(new Extend\Routes('forum'))
->get('/auth/twitter', 'auth.twitter', Controllers\TwitterAuthController::class),

(new Extend\Routes('api'))
->get('/users/{id}/linked-accounts', 'users.provider.list', Api\Controllers\ListProvidersController::class)
->get('/linked-accounts', 'user.provider.list', Api\Controllers\ListProvidersController::class)
->delete('/linked-accounts/{id}', 'users.provider.delete', Api\Controllers\DeleteProviderLinkController::class),
new Extend\ApiResource(Api\Resource\ProviderResource::class),

(new Extend\ServiceProvider())
->register(OAuthServiceProvider::class),

(new Extend\ApiSerializer(ForumSerializer::class))
->attributes(Api\AddForumAttributes::class),
(new Extend\ApiResource(Resource\ForumResource::class))
->fields(Api\AddForumAttributes::class),
(new Extend\ApiResource(Resource\UserResource::class))
->fields(Api\AddUserAttributes::class),

(new Extend\Settings())
->default('fof-oauth.only_icons', false)
Expand All @@ -74,20 +74,14 @@
->listen(LoggedOut::class, Listeners\HandleLogout::class)
->subscribe(Listeners\ClearOAuthCache::class),

(new Extend\ApiSerializer(CurrentUserSerializer::class))
->attributes(Api\CurrentUserAttributes::class),

(new Extend\Filter(UserFilterer::class))
->addFilter(Query\SsoIdFilterGambit::class),

(new Extend\SimpleFlarumSearch(UserSearcher::class))
->addGambit(Query\SsoIdFilterGambit::class),

(new Extend\Conditional())
->whenExtensionEnabled('flarum-gdpr', fn () => [
(new Extend\ApiSerializer(ForumSerializer::class))
->attribute('passwordlessSignUp', function (ForumSerializer $serializer) {
return !$serializer->getActor()->isGuest() && $serializer->getActor()->loginProviders()->count() > 0;
}),
(new Extend\ApiResource(Resource\ForumResource::class))
->fields(fn () => [
Schema\Str::make('passwordlessSignUp')
->get(fn ($model, Context $context) => !$context->getActor()->isGuest() && $context->getActor()->loginProviders()->count() > 0),
]),
]),
(new Extend\SearchDriver(DatabaseSearchDriver::class))
->addFilter(UserSearcher::class, Query\SsoIdFilter::class),
];
6 changes: 3 additions & 3 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"prettier": "@flarum/prettier-config",
"devDependencies": {
"@flarum/prettier-config": "^1.0.0",
"flarum-tsconfig": "^1.0.3",
"flarum-webpack-config": "^2.0.0",
"flarum-tsconfig": "^2.0.0",
"flarum-webpack-config": "^3.0.2",
"prettier": "^3.0.3",
"typescript-coverage-report": "^0.6.1",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
"webpack-cli": "^5.0"
},
"scripts": {
"analyze": "cross-env ANALYZER=true yarn run build",
Expand Down
82 changes: 46 additions & 36 deletions js/src/admin/components/AuthSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import app from 'flarum/admin/app';
import Button from 'flarum/common/components/Button';
import Dropdown from 'flarum/common/components/Dropdown';
import ExtensionPage from 'flarum/admin/components/ExtensionPage';
import icon from 'flarum/common/helpers/icon';
import Icon from 'flarum/common/components/Icon';
import Badge from 'flarum/common/components/Badge';
import ItemList from 'flarum/common/utils/ItemList';

export default class AuthSettingsPage extends ExtensionPage {
Expand All @@ -16,7 +17,7 @@ export default class AuthSettingsPage extends ExtensionPage {
return (
<div className="container">
<div className="AuthSettingsPage">
<div className="Form">
<form className="Form">
{this.buildSettingComponent({
type: 'boolean',
setting: 'fof-oauth.only_icons',
Expand Down Expand Up @@ -74,7 +75,7 @@ export default class AuthSettingsPage extends ExtensionPage {
</div>

{this.submitButton()}
</div>
</form>
</div>
</div>
);
Expand All @@ -89,6 +90,9 @@ export default class AuthSettingsPage extends ExtensionPage {
const showSettings = !!this.showing[name];
const callbackUrl = `${app.forum.attribute('baseUrl')}/auth/${name}`;

const groupId = this.setting(`fof-oauth.${name}.group`)();
const selectedGroup = groupId ? app.store.getById('groups', groupId) : null;

items.add(
`fof-oauth.${name}`,
<div className={`Provider ${enabled ? 'enabled' : 'disabled'} ${showSettings && 'showing'}`}>
Expand All @@ -98,46 +102,52 @@ export default class AuthSettingsPage extends ExtensionPage {
setting: `fof-oauth.${name}`,
label: (
<div>
{icon(provider.icon)}
<Icon name={provider.icon} />
<span>{app.translator.trans(`fof-oauth.lib.providers.${name}`)}</span>
</div>
),
})}

{
<Button
className={`Button Button--rounded ${this.showing[name] && 'active'}`}
onclick={() => (this.showing[name] = !showSettings)}
aria-label={app.translator.trans('fof-oauth.admin.settings_accessibility_label', {
name,
})}
>
{icon(`fas fa-cog`)}
</Button>
}
{enabled && selectedGroup && (
<div className="Provider--group">
{/*<Icon name={selectedGroup.icon() || 'fas fa-user-group'} />*/}
<Badge icon={selectedGroup.icon() || 'fas fa-user-group'} />
{selectedGroup.namePlural()}
</div>
)}

<Button
className={`Button Button--rounded ${this.showing[name] && 'active'}`}
onclick={() => (this.showing[name] = !showSettings)}
aria-label={app.translator.trans('fof-oauth.admin.settings_accessibility_label', {
name,
})}
>
<Icon name="fas fa-cog" />
</Button>
</div>

<div className="Provider--settings">
<div>
<p>
{app.translator.trans(`fof-oauth.admin.settings.providers.${name}.description`, {
link: (
<a href={provider.link} target="_blank">
{provider.link}
</a>
),
})}
</p>
<p>
{app.translator.trans(`fof-oauth.admin.settings.providers.callback_url_text`, {
url: (
<a href={callbackUrl} target="_blank">
{callbackUrl}
</a>
),
})}
</p>
<div className="Provider--settings" inert={!showSettings}>
<p>
{app.translator.trans(`fof-oauth.admin.settings.providers.${name}.description`, {
link: (
<a href={provider.link} target="_blank">
{provider.link}
</a>
),
})}
</p>
<p>
{app.translator.trans(`fof-oauth.admin.settings.providers.callback_url_text`, {
url: (
<a href={callbackUrl} target="_blank">
{callbackUrl}
</a>
),
})}
</p>

<div class="Form">
{Object.keys(provider.fields).map((field) =>
this.buildSettingComponent({
type: 'string',
Expand Down Expand Up @@ -187,7 +197,7 @@ export default class AuthSettingsPage extends ExtensionPage {
<Dropdown
label={
selectedGroup
? [icon(selectedGroup.icon() || icons[selectedGroup.id()]), '\t', selectedGroup.namePlural()]
? [<Icon name={selectedGroup.icon() || icons[selectedGroup.id()]} />, '\t', selectedGroup.namePlural()]
: app.translator.trans('fof-oauth.admin.settings.providers.no_group_label')
}
buttonClassName="Button"
Expand Down
16 changes: 16 additions & 0 deletions js/src/admin/extend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import app from 'flarum/admin/app';
import Extend from 'flarum/common/extenders';
import AuthSettingsPage from './components/AuthSettingsPage';

export default [
new Extend.Admin() //
.page(AuthSettingsPage)
.permission(
() => ({
icon: 'fas fa-sign-in-alt',
label: app.translator.trans('fof-oauth.admin.permissions.moderate_user_providers'),
permission: 'moderateUserProviders',
}),
'moderate'
),
];
21 changes: 2 additions & 19 deletions js/src/admin/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
import app from 'flarum/admin/app';
import AuthSettingsPage from './components/AuthSettingsPage';
import ConfigureWithOAuthPage from './components/ConfigureWithOAuthPage';
import ConfigureWithOAuthButton from './components/ConfigureWithOAuthButton';

export * from './components';
export { default as extend } from './extend';

app.initializers.add('fof/oauth', () => {
app.extensionData
.for('fof-oauth')
.registerPage(AuthSettingsPage)
.registerPermission(
{
icon: 'fas fa-sign-in-alt',
label: app.translator.trans('fof-oauth.admin.permissions.moderate_user_providers'),
permission: 'moderateUserProviders',
},
'moderate'
);
//
});

// Needed for backwards compatibility
export { AuthSettingsPage, ConfigureWithOAuthPage, ConfigureWithOAuthButton };
11 changes: 6 additions & 5 deletions js/src/forum/components/LinkStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import app from 'flarum/forum/app';
import Component, { ComponentAttrs } from 'flarum/common/Component';
import icon from 'flarum/common/helpers/icon';
import Button from 'flarum/common/components/Button';
import type Mithril from 'mithril';
import LinkedAccount from '../models/LinkedAccount';
import User from 'flarum/common/models/User';
import ProviderInfo from './ProviderInfo';
import extractText from 'flarum/common/utils/extractText';
import Icon from 'flarum/common/components/Icon';
import LogInButton from 'flarum/forum/components/LogInButton';

export interface ILinkStatusAttrs extends ComponentAttrs {
provider: LinkedAccount;
user: User;
refresh?: () => Promise<void>;
}

export interface LinkStatusState {
Expand All @@ -36,7 +37,7 @@ export default class LinkStatus extends Component<ILinkStatusAttrs, LinkStatusSt

view(): Mithril.Children {
return (
<div className={`LinkedAccounts-Account LinkedAccounts-Account--${this.attrs.provider.name()}`}>
<div className={`LinkedAccountsList-item LinkedAccountsList-item--${this.attrs.provider.name()}`}>
{this.iconView()}
{this.statusView()}
{this.actionView()}
Expand All @@ -47,7 +48,7 @@ export default class LinkStatus extends Component<ILinkStatusAttrs, LinkStatusSt
iconView() {
return (
<div className="LinkedAccountsList-item-icon">
{icon(this.attrs.provider.icon(), { className: `Provider-Icon Provider-Icon--${this.attrs.provider.name()}` })}
<Icon name={this.attrs.provider.icon()} className={`Provider-Icon Provider-Icon--${this.attrs.provider.name()}`} />
</div>
);
}
Expand Down Expand Up @@ -81,6 +82,7 @@ export default class LinkStatus extends Component<ILinkStatusAttrs, LinkStatusSt
<LogInButton
className={`Button FoFLogInButton LogInButton--${provider.name()}`}
icon={provider.icon()}
provider={provider.name()}
path={`/auth/${provider.name()}?linkTo=${user.id()}`}
loading={this.state.loading}
>
Expand All @@ -106,9 +108,8 @@ export default class LinkStatus extends Component<ILinkStatusAttrs, LinkStatusSt
) {
this.state.loading = true;
await provider.delete();
await app.store.find<LinkedAccount[]>('users/' + this.attrs.user.id() + '/linked-accounts', {});
await this.attrs.refresh?.();
this.state.loading = false;
m.redraw();
}
}
}
Loading
Loading