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

Map Discord roles to NextCloud groups #395

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 1 addition & 1 deletion js/settings.js

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion lib/Service/ProviderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class ProviderService
'id' => 'appid',
'secret' => 'secret',
],
'group_mapping' => 'groupMapping',
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what $configMapping is about. We control the schema, can't we just force all the providers to use the same one?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hybridauth is external lib

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just works as it should. I think with the little Tutorial, everyone can set this up!

],
self::TYPE_OPENID => [
'openid_identifier' => 'url',
Expand Down Expand Up @@ -232,7 +233,7 @@ public function handleDefault($provider)
{
$config = [];
$scopes = [
'discord' => 'identify email guilds',
'discord' => 'identify email guilds guilds.members.read',
];
$providers = json_decode($this->config->getAppValue($this->appName, 'oauth_providers'), true) ?: [];
if (is_array($providers) && in_array($provider, array_keys($providers))) {
Expand Down Expand Up @@ -413,6 +414,24 @@ private function auth($class, array $config, $provider, $providerType = null)
throw new LoginException($this->l->t('Login is available only to members of the following Discord guilds: %s', $config['guilds']));
};
$checkGuilds();

// read Discord roles into NextCloud groups
$profile->data['groups'] = [];
if(!empty($allowedGuilds)) {
foreach($userGuilds as $guild) {
if (!in_array($guild->id ?? null, $allowedGuilds)) {
// Only read groups from the explicitly declared guilds.
// It doesn't make sense to try to map in random, unknown groups from arbitrary guilds.
// and without this, a user in many guilds will trip a HTTP 429 rate limit from the Discord API.
continue;
}
# https://discord.com/developers/docs/resources/guild#get-guild-member
$guild_data = $adapter->apiRequest('users/@me/guilds/' . $guild->id . '/member' );
$profile->data['groups'] = array_merge($profile->data['groups'], $guild_data->roles ?? []);
// TODO: /member returns roles as their ID; to get their name requires an extra API call
// (and perhaps extra permissions?)
}
}
}

if (!empty($config['logout_url'])) {
Expand All @@ -422,6 +441,7 @@ private function auth($class, array $config, $provider, $providerType = null)
}

$profile->data['default_group'] = $config['default_group'];
$profile->data['group_mapping'] = $config['group_mapping'];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be wrapped in an isset()? My PHP is kind of weak.


if ($provider === 'telegram') {
$provider = 'tg'; //For backward compatibility
Expand Down
3 changes: 3 additions & 0 deletions lib/Settings/AdminSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public function getForm()
];
}
}
// make sure these render the 'Add Group Mapping' button
$providers['discord']['hasGroupMapping'] = true;

$customProviders = json_decode($this->config->getAppValue($this->appName, 'custom_providers'), true);

$params = [
Expand Down
36 changes: 36 additions & 0 deletions src/components/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@
<input type="text" :name="'providers['+name+'][guilds]'" v-model="provider.guilds"/>
</label>
</template>
<template v-if="provider.hasGroupMapping">
<button class="group-mapping-add" type="button" @click="provider.groupMapping.push({foreign: '', local: ''})">
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason the existence of the Add Group Mapping button widens the Discord box and breaks the layout. I do not understand. I've already spent 40 minutes looking at it.

Seriously what is this BS

srs

Fix the CSS here.

{{ t(appName, 'Add group mapping') }}
</button>
<div v-for="(mapping, mappingIdx) in provider.groupMapping" :key="mapping">
<input type="text" class="foreign-group" v-model="mapping.foreign" />
<select class="local-group" :name="mapping.foreign ? 'providers['+name+'][groupMapping]['+mapping.foreign+']' : ''">
<option v-for="group in groups" :key="group" :value="group" :selected="mapping.local === group">
{{ group }}
</option>
</select>
<span class="group-mapping-remove" @click="provider.groupMapping.splice(mappingIdx, 1)">x</span>
</div>
</template>
Comment on lines +123 to +136
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is also copy-pasted!!

</div>
<br/>

Expand Down Expand Up @@ -148,6 +162,10 @@ export default {
data.custom_providers = {}
}

// In the 'custom' providers, those that can have multiple instances of the same protocol, rewrite groupMapping
// from { foreign0: local0, foreign1, local1, ... }
// to [ { 'foreign': foreign0, 'local': local0 }, { 'foreign': foreign1, 'local': local1 }, ... ]
// This is necessary for Vue to use groupMapping as a read-write data model.
for (var provType in providerTypes) {
if (!data.custom_providers[provType]) {
data.custom_providers[provType] = []
Expand All @@ -165,6 +183,24 @@ export default {
}
}
}

// For the fixed providers, with only a singleton instance of the login server, rewrite groupMapping
// from { foreign0: local0, foreign1, local1, ... }
// to [ { 'foreign': foreign0, 'local': local0 }, { 'foreign': foreign1, 'local': local1 }, ... ]
// This is necessary for Vue to use groupMapping as a read-write data model.
for (var provType in data.providers) {
if (data.providers[provType].hasGroupMapping) {
var groupMappingArr = []
var groupMapping = data.providers[provType].groupMapping
if (groupMapping) {
for (var foreignGroup in groupMapping) {
groupMappingArr.push({foreign: foreignGroup, local: groupMapping[foreignGroup]})
Comment on lines +193 to +197
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is copy-pasted!! 💢

}
}
data.providers[provType].groupMapping = groupMappingArr
}
}

data.appName = appName
return data
},
Expand Down