/* GoToSocial Copyright (C) GoToSocial Authors admin@gotosocial.org SPDX-License-Identifier: AGPL-3.0-or-later This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import { RootState } from "../../../redux/store"; import { SearchAppParams, SearchAppResp, App, AppCreateParams, } from "../../types/application"; import { OAuthAccessToken, OAuthAccessTokenRequestBody } from "../../types/oauth"; import { gtsApi } from "../gts-api"; import parse from "parse-link-header"; const extended = gtsApi.injectEndpoints({ endpoints: (build) => ({ searchApp: build.query({ query: (form) => { const params = new(URLSearchParams); Object.entries(form).forEach(([k, v]) => { if (v !== undefined) { params.append(k, v); } }); let query = ""; if (params.size !== 0) { query = `?${params.toString()}`; } return { url: `/api/v1/apps${query}` }; }, // Headers required for paging. transformResponse: (apiResp: App[], meta) => { const apps = apiResp; const linksStr = meta?.response?.headers.get("Link"); const links = parse(linksStr); return { apps, links }; }, providesTags: [{ type: "Application", id: "TRANSFORMED" }] }), getApp: build.query({ query: (id) => ({ method: "GET", url: `/api/v1/apps/${id}`, }), providesTags: (_result, _error, id) => [ { type: 'Application', id } ], }), createApp: build.mutation({ query: (formData) => ({ method: "POST", url: `/api/v1/apps`, asForm: true, body: formData, discardEmpty: true }), invalidatesTags: [{ type: "Application", id: "TRANSFORMED" }], }), getOOBAuthCode: build.mutation({ async queryFn({ app, scope, redirectURI }, api, _extraOpts, _fetchWithBQ) { // Fetch the instance URL string from // oauth state, eg., https://example.org. const state = api.getState() as RootState; if (!state.login.instanceUrl) { return { error: { status: 'CUSTOM_ERROR', error: "oauthState.instanceUrl undefined", } }; } const instanceUrl = state.login.instanceUrl; // Parse instance URL + set params on it. const url = new URL(instanceUrl); url.pathname = "/oauth/authorize"; url.searchParams.set("client_id", app.client_id); url.searchParams.set("redirect_uri", redirectURI); url.searchParams.set("response_type", "code"); url.searchParams.set("scope", scope); // Set the app ID in state so we know which // app to get out of our store after redirect. url.searchParams.set("state", app.id); // Whisk the user away to the authorize page. window.location.assign(url.toString()); return { data: null }; } }), getAccessTokenForApp: build.mutation({ query: (formData) => ({ method: "POST", url: `/oauth/token`, asForm: true, body: formData, discardEmpty: true }), }), }) }); export const { useLazySearchAppQuery, useCreateAppMutation, useGetAppQuery, useGetOOBAuthCodeMutation, useGetAccessTokenForAppMutation, } = extended;