web/admin: contextually add user to group when creating user from group page (#7586)

* move related user list to group folder

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* contextually add user to group when created from group view page

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add banner

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-11-15 23:14:30 +01:00 committed by GitHub
parent bac7e034f8
commit 99cecdb3ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 98 additions and 14 deletions

View File

@ -1,5 +1,5 @@
import "@goauthentik/admin/groups/GroupForm"; import "@goauthentik/admin/groups/GroupForm";
import "@goauthentik/admin/users/RelatedUserList"; import "@goauthentik/app/admin/groups/RelatedUserList";
import "@goauthentik/app/elements/rbac/ObjectPermissionsPage"; import "@goauthentik/app/elements/rbac/ObjectPermissionsPage";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants"; import { EVENT_REFRESH } from "@goauthentik/common/constants";

View File

@ -24,7 +24,7 @@ import { UserOption } from "@goauthentik/elements/user/utils";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit"; import { CSSResult, TemplateResult, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
@ -402,7 +402,16 @@ export class RelatedUserList extends Table<User> {
<ak-forms-modal> <ak-forms-modal>
<span slot="submit"> ${msg("Create")} </span> <span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create User")} </span> <span slot="header"> ${msg("Create User")} </span>
<ak-user-form slot="form"> </ak-user-form> ${this.targetGroup
? html`
<div class="pf-c-banner pf-m-info" slot="above-form">
${msg(
str`This user will be added to the group "${this.targetGroup.name}".`,
)}
</div>
`
: nothing}
<ak-user-form .group=${this.targetGroup} slot="form"> </ak-user-form>
<a slot="trigger" class="pf-c-dropdown__menu-item"> <a slot="trigger" class="pf-c-dropdown__menu-item">
${msg("Create user")} ${msg("Create user")}
</a> </a>
@ -415,7 +424,17 @@ export class RelatedUserList extends Table<User> {
> >
<span slot="submit"> ${msg("Create")} </span> <span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create Service account")} </span> <span slot="header"> ${msg("Create Service account")} </span>
<ak-user-service-account slot="form"> </ak-user-service-account> ${this.targetGroup
? html`
<div class="pf-c-banner pf-m-info" slot="above-form">
${msg(
str`This user will be added to the group "${this.targetGroup.name}".`,
)}
</div>
`
: nothing}
<ak-user-service-account-form .group=${this.targetGroup} slot="form">
</ak-user-service-account-form>
<a slot="trigger" class="pf-c-dropdown__menu-item"> <a slot="trigger" class="pf-c-dropdown__menu-item">
${msg("Create Service account")} ${msg("Create Service account")}
</a> </a>

View File

@ -4,19 +4,30 @@ import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModalForm } from "@goauthentik/elements/forms/ModalForm"; import { ModalForm } from "@goauthentik/elements/forms/ModalForm";
import { msg } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { TemplateResult, html } from "lit"; import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { CoreApi, UserServiceAccountRequest, UserServiceAccountResponse } from "@goauthentik/api"; import {
CoreApi,
Group,
UserServiceAccountRequest,
UserServiceAccountResponse,
} from "@goauthentik/api";
@customElement("ak-user-service-account") @customElement("ak-user-service-account-form")
export class ServiceAccountForm extends Form<UserServiceAccountRequest> { export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
@property({ attribute: false }) @property({ attribute: false })
result?: UserServiceAccountResponse; result?: UserServiceAccountResponse;
@property({ attribute: false })
group?: Group;
getSuccessMessage(): string { getSuccessMessage(): string {
if (this.group) {
return msg(str`Successfully created user and added to group ${this.group.name}`);
}
return msg("Successfully created user."); return msg("Successfully created user.");
} }
@ -26,6 +37,14 @@ export class ServiceAccountForm extends Form<UserServiceAccountRequest> {
}); });
this.result = result; this.result = result;
(this.parentElement as ModalForm).showSubmitButton = false; (this.parentElement as ModalForm).showSubmitButton = false;
if (this.group) {
await new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
groupUuid: this.group.pk,
userAccountRequest: {
pk: this.result.userPk,
},
});
}
return result; return result;
} }

View File

@ -8,15 +8,18 @@ import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/Radio"; import "@goauthentik/elements/forms/Radio";
import YAML from "yaml"; import YAML from "yaml";
import { msg } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { CoreApi, User, UserTypeEnum } from "@goauthentik/api"; import { CoreApi, Group, User, UserTypeEnum } from "@goauthentik/api";
@customElement("ak-user-form") @customElement("ak-user-form")
export class UserForm extends ModelForm<User, number> { export class UserForm extends ModelForm<User, number> {
@property({ attribute: false })
group?: Group;
static get defaultUserAttributes(): { [key: string]: unknown } { static get defaultUserAttributes(): { [key: string]: unknown } {
return {}; return {};
} }
@ -42,6 +45,9 @@ export class UserForm extends ModelForm<User, number> {
if (this.instance) { if (this.instance) {
return msg("Successfully updated user."); return msg("Successfully updated user.");
} else { } else {
if (this.group) {
return msg(str`Successfully created user and added to group ${this.group.name}`);
}
return msg("Successfully created user."); return msg("Successfully created user.");
} }
} }
@ -50,21 +56,31 @@ export class UserForm extends ModelForm<User, number> {
if (data.attributes === null) { if (data.attributes === null) {
data.attributes = UserForm.defaultUserAttributes; data.attributes = UserForm.defaultUserAttributes;
} }
let user;
if (this.instance?.pk) { if (this.instance?.pk) {
return new CoreApi(DEFAULT_CONFIG).coreUsersPartialUpdate({ user = await new CoreApi(DEFAULT_CONFIG).coreUsersPartialUpdate({
id: this.instance.pk, id: this.instance.pk,
patchedUserRequest: data, patchedUserRequest: data,
}); });
} else { } else {
data.groups = []; data.groups = [];
return new CoreApi(DEFAULT_CONFIG).coreUsersCreate({ user = await new CoreApi(DEFAULT_CONFIG).coreUsersCreate({
userRequest: data, userRequest: data,
}); });
} }
if (this.group) {
await new CoreApi(DEFAULT_CONFIG).coreGroupsAddUserCreate({
groupUuid: this.group.pk,
userAccountRequest: {
pk: user.pk,
},
});
}
return user;
} }
renderForm(): TemplateResult { renderForm(): TemplateResult {
return html` <ak-form-element-horizontal return html`<ak-form-element-horizontal
label=${msg("Username")} label=${msg("Username")}
?required=${true} ?required=${true}
name="username" name="username"

View File

@ -399,7 +399,7 @@ export class UserListPage extends TablePage<User> {
<ak-forms-modal .closeAfterSuccessfulSubmit=${false} .cancelText=${msg("Close")}> <ak-forms-modal .closeAfterSuccessfulSubmit=${false} .cancelText=${msg("Close")}>
<span slot="submit"> ${msg("Create")} </span> <span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create Service account")} </span> <span slot="header"> ${msg("Create Service account")} </span>
<ak-user-service-account slot="form"> </ak-user-service-account> <ak-user-service-account-form slot="form"> </ak-user-service-account-form>
<button slot="trigger" class="pf-c-button pf-m-secondary"> <button slot="trigger" class="pf-c-button pf-m-secondary">
${msg("Create Service account")} ${msg("Create Service account")}
</button> </button>

View File

@ -6063,6 +6063,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -6340,6 +6340,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -5979,6 +5979,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -7965,6 +7965,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -6187,6 +6187,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -7865,4 +7865,7 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit> </trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit>
</body></file></xliff> </body></file></xliff>

View File

@ -5972,6 +5972,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -7967,6 +7967,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -6020,6 +6020,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -6019,6 +6019,9 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="sd47f3d3c9741343d"> <trans-unit id="sd47f3d3c9741343d">
<source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source> <source>4: Very unguessable: strong protection from offline slow-hash scenario. (guesses &amp;gt;= 10^10)</source>
</trans-unit>
<trans-unit id="s3d2a8b86a4f5a810">
<source>Successfully created user and added to group <x id="0" equiv-text="${this.group.name}"/></source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>