import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { first, randomString } from "@goauthentik/common/utils"; import "@goauthentik/elements/SearchSelect"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import { t } from "@lingui/macro"; import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { until } from "lit/directives/until.js"; import { CapabilitiesEnum, Flow, FlowsApi, FlowsInstancesListDesignationEnum, FlowsInstancesListRequest, PlexSource, SourcesApi, UserMatchingModeEnum, } from "@goauthentik/api"; @customElement("ak-source-plex-form") export class PlexSourceForm extends ModelForm { loadInstance(pk: string): Promise { return new SourcesApi(DEFAULT_CONFIG) .sourcesPlexRetrieve({ slug: pk, }) .then((source) => { this.plexToken = source.plexToken; this.loadServers(); return source; }); } @state() clearIcon = false; @property() plexToken?: string; @property({ attribute: false }) plexResources?: PlexResource[]; get defaultInstance(): PlexSource | undefined { return { clientId: randomString(40), } as PlexSource; } getSuccessMessage(): string { if (this.instance) { return t`Successfully updated source.`; } else { return t`Successfully created source.`; } } send = async (data: PlexSource): Promise => { data.plexToken = this.plexToken || ""; let source: PlexSource; if (this.instance?.pk) { source = await new SourcesApi(DEFAULT_CONFIG).sourcesPlexUpdate({ slug: this.instance.slug, plexSourceRequest: data, }); } else { source = await new SourcesApi(DEFAULT_CONFIG).sourcesPlexCreate({ plexSourceRequest: data, }); } const c = await config(); if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { const icon = this.getFormFiles()["icon"]; if (icon || this.clearIcon) { await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({ slug: source.slug, file: icon, clear: this.clearIcon, }); } } else { await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconUrlCreate({ slug: source.slug, filePathRequest: { url: data.icon || "", }, }); } return source; }; async doAuth(): Promise { const authInfo = await PlexAPIClient.getPin(this.instance?.clientId || ""); const authWindow = await popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700); PlexAPIClient.pinPoll(this.instance?.clientId || "", authInfo.pin.id).then((token) => { authWindow?.close(); this.plexToken = token; this.loadServers(); }); } async loadServers(): Promise { if (!this.plexToken) { return; } this.plexResources = await new PlexAPIClient(this.plexToken).getServers(); } renderSettings(): TemplateResult { if (!this.plexToken) { return html` `; } return html`

${t`Select which server a user has to be a member of to be allowed to authenticate.`}

${t`Hold control/command to select multiple items.`}

`; } renderForm(): TemplateResult { return html`

${t`Path template for users created. Use placeholders like \`%(slug)s\` to insert the source slug.`}

${until( config().then((c) => { if (c.capabilities.includes(CapabilitiesEnum.SaveMedia)) { return html` ${this.instance?.icon ? html`

${t`Currently set to:`} ${this.instance?.icon}

` : html``}
${this.instance?.icon ? html`
{ const target = ev.target as HTMLInputElement; this.clearIcon = target.checked; }} />

${t`Delete currently set icon.`}

` : html``}`; } return html`

${t`Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test".`}

`; }), )} ${t`Protocol settings`}
${this.renderSettings()}
${t`Flow settings`}
=> { const args: FlowsInstancesListRequest = { ordering: "slug", designation: FlowsInstancesListDesignationEnum.Authentication, }; if (query !== undefined) { args.search = query; } const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList( args, ); return flows.results; }} .renderElement=${(flow: Flow): string => { return flow.slug; }} .renderDescription=${(flow: Flow): TemplateResult => { return html`${flow.name}`; }} .value=${(flow: Flow | undefined): string | undefined => { return flow?.pk; }} .selected=${(flow: Flow): boolean => { let selected = this.instance?.enrollmentFlow === flow.pk; if ( !this.instance?.pk && !this.instance?.enrollmentFlow && flow.slug === "default-source-authentication" ) { selected = true; } return selected; }} ?blankable=${true} >

${t`Flow to use when authenticating existing users.`}

=> { const args: FlowsInstancesListRequest = { ordering: "slug", designation: FlowsInstancesListDesignationEnum.Enrollment, }; if (query !== undefined) { args.search = query; } const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList( args, ); return flows.results; }} .renderElement=${(flow: Flow): string => { return flow.slug; }} .renderDescription=${(flow: Flow): TemplateResult => { return html`${flow.name}`; }} .value=${(flow: Flow | undefined): string | undefined => { return flow?.pk; }} .selected=${(flow: Flow): boolean => { let selected = this.instance?.enrollmentFlow === flow.pk; if ( !this.instance?.pk && !this.instance?.enrollmentFlow && flow.slug === "default-source-enrollment" ) { selected = true; } return selected; }} ?blankable=${true} >

${t`Flow to use when enrolling new users.`}

`; } }