import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search"; import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText"; import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; import { GroupMatchingModeToLabel, UserMatchingModeToLabel, } from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; import { msg } from "@lit/localize"; import { TemplateResult, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { FlowsInstancesListDesignationEnum, GroupMatchingModeEnum, PlexSource, PlexSourcePropertyMapping, PropertymappingsApi, SourcesApi, UserMatchingModeEnum, } from "@goauthentik/api"; async function propertyMappingsProvider(page = 1, search = "") { const propertyMappings = await new PropertymappingsApi( DEFAULT_CONFIG, ).propertymappingsSourcePlexList({ ordering: "managed", pageSize: 20, search: search.trim(), page, }); return { pagination: propertyMappings.pagination, options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]), }; } function makePropertyMappingsSelector(instanceMappings?: string[]) { const localMappings = instanceMappings ? new Set(instanceMappings) : undefined; return localMappings ? ([pk, _]: DualSelectPair) => localMappings.has(pk) : ([_0, _1, _2, _]: DualSelectPair) => false; } @customElement("ak-source-plex-form") export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { const source = await new SourcesApi(DEFAULT_CONFIG).sourcesPlexRetrieve({ slug: pk, }); this.plexToken = source.plexToken; this.loadServers(); this.clearIcon = false; return source; } @state() clearIcon = false; @property() plexToken?: string; @property({ attribute: false }) plexResources?: PlexResource[]; get defaultInstance(): PlexSource | undefined { return { clientId: randomString(40, ascii_letters + digits), } as PlexSource; } async send(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, }); } if (this.can(CapabilitiesEnum.CanSaveMedia)) { 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`

${msg( "Select which server a user has to be a member of to be allowed to authenticate.", )}

${msg("Hold control/command to select multiple items.")}

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

${placeholderHelperText}

${this.can(CapabilitiesEnum.CanSaveMedia) ? html` ${this.instance?.icon ? html`

${msg("Currently set to:")} ${this.instance?.icon}

` : html``}
${this.instance?.icon ? html`

${msg("Delete currently set icon.")}

` : html``}` : html`

${iconHelperText}

`} ${msg("Protocol settings")}
${this.renderSettings()}
${msg("Flow settings")}

${msg("Flow to use when authenticating existing users.")}

${msg("Flow to use when enrolling new users.")}

${msg("Plex Attribute mapping")}

${msg("Property mappings for user creation.")}

${msg("Property mappings for group creation.")}

`; } } declare global { interface HTMLElementTagNameMap { "ak-source-plex-form": PlexSourceForm; } }