// apps.ts // Copyright (C) 2020 Dwayne Harris // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . import { apiFetch } from '../api' import { setEntities } from '../actions/entities' import { startRequest, finishRequest } from '../actions/requests' import { setFieldNotification } from '../actions/forms' import { listSet, listAppend } from '../actions/lists' import { objectToQuerystring } from '../utils' import { normalize } from '../utils/normalization' import { EntityListKey, Entity } from '../types' import { AppThunkAction, RequestKey, EntityType, App, AvailabilityResponse, NotificationType }from '../types' interface AppsResponse { apps: App[] continuation?: string } export const fetchApps = (sort?: string, continuation?: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.FetchApps)) try { const response = await apiFetch({ path: `/v1/apps?${objectToQuerystring({ sort, continuation })}`, }) const apps = normalize(response.apps, EntityType.App) dispatch(setEntities(apps.entities)) if (continuation) { dispatch(listAppend(EntityListKey.Apps, apps.keys, response.continuation)) } else { dispatch(listSet(EntityListKey.Apps, apps.keys, response.continuation)) } dispatch(finishRequest(RequestKey.FetchApps, true)) } catch (err) { dispatch(finishRequest(RequestKey.FetchApps, false)) throw err } } export const fetchCreatedApps = (sort?: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.FetchSelfApps)) try { const response = await apiFetch({ path: `/v1/self/apps?${objectToQuerystring({ sort })}`, }) const apps = normalize(response.apps, EntityType.App) dispatch(setEntities(apps.entities)) dispatch(listSet(EntityListKey.CreatedApps, apps.keys)) dispatch(finishRequest(RequestKey.FetchSelfApps, true)) } catch (err) { dispatch(finishRequest(RequestKey.FetchSelfApps, false)) throw err } } export const checkAppAvailability = (name: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.FetchAppAvailability)) try { const { id, available } = await apiFetch({ path: '/v1/app/available', method: 'post', body: { name, }, }) if (available) { dispatch(setFieldNotification('name', NotificationType.Success, `${id} is available`)) } else { dispatch(setFieldNotification('name', NotificationType.Error, `${id} isn't available`)) } dispatch(finishRequest(RequestKey.FetchAppAvailability, true)) } catch (err) { dispatch(finishRequest(RequestKey.FetchAppAvailability, false)) throw err } } interface AppOptions { name: string about?: string websiteUrl?: string companyName?: string version: string composerUrl?: string rendererUrl?: string imageUrl?: string coverImageUrl?: string iconImageUrl?: string } interface CreateAppResponse { id: string } export const createApp = (options: AppOptions): AppThunkAction => async dispatch => { const { name, about, websiteUrl, companyName, version, composerUrl, rendererUrl, imageUrl, coverImageUrl, iconImageUrl } = options dispatch(startRequest(RequestKey.CreateApp)) try { const { id } = await apiFetch({ path: '/v1/app', method: 'post', body: { name, about, websiteUrl, companyName, version, composerUrl, rendererUrl, imageUrl, coverImageUrl, iconImageUrl, }, }) dispatch(finishRequest(RequestKey.CreateApp, true)) return id } catch (err) { dispatch(finishRequest(RequestKey.CreateApp, false)) throw err } } export const updateApp = (id: string, options: AppOptions): AppThunkAction => async dispatch => { const { name, about, websiteUrl, companyName, version, composerUrl, rendererUrl, imageUrl, coverImageUrl, iconImageUrl } = options dispatch(startRequest(RequestKey.UpdateApp)) try { await apiFetch({ path: `/v1/app/${id}`, method: 'put', body: { name, about, websiteUrl, companyName, version, composerUrl, rendererUrl, imageUrl, coverImageUrl, iconImageUrl, }, }) dispatch(finishRequest(RequestKey.UpdateApp, true)) } catch (err) { dispatch(finishRequest(RequestKey.UpdateApp, false)) throw err } } export const fetchApp = (id: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.FetchApp)) try { const app = await apiFetch({ path: `/v1/app/${id}`, method: 'get', }) const apps = normalize([app], EntityType.App) dispatch(setEntities(apps.entities)) dispatch(finishRequest(RequestKey.FetchApp, true)) } catch (err) { dispatch(finishRequest(RequestKey.FetchApp, false)) throw err } } export const installApp = (id: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.InstallApp)) try { await apiFetch({ path: `/v1/app/${id}/install`, method: 'post' }) dispatch(finishRequest(RequestKey.InstallApp, true)) } catch (err) { dispatch(finishRequest(RequestKey.InstallApp, false)) throw err } } export const uninstallApp = (id: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.UninstallApp)) try { await apiFetch({ path: `/v1/app/${id}/uninstall`, method: 'post' }) dispatch(finishRequest(RequestKey.UninstallApp, true)) } catch (err) { dispatch(finishRequest(RequestKey.UninstallApp, false)) throw err } } interface FetchPendingAppsResponse { apps: Entity[] continuation?: string } export const fetchPendingApps = (continuation?: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.FetchPendingApps)) try { const response = await apiFetch({ path: `/v1/apps/pending?${objectToQuerystring({ continuation })}`, method: 'get', }) const apps = normalize(response.apps, EntityType.App) dispatch(setEntities(apps.entities)) dispatch(listSet(EntityListKey.PendingApps, apps.keys, response.continuation)) dispatch(finishRequest(RequestKey.FetchPendingApps, true)) } catch (err) { dispatch(finishRequest(RequestKey.FetchPendingApps, false)) throw err } } export const activateApp = (id: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.ActivateApp)) try { await apiFetch({ path: `/v1/app/${id}/activate`, method: 'post', }) dispatch(finishRequest(RequestKey.ActivateApp, true)) } catch (err) { dispatch(finishRequest(RequestKey.ActivateApp, false)) throw err } } export const setPreinstall = (id: string): AppThunkAction => async dispatch => { dispatch(startRequest(RequestKey.SetPreinstall)) try { await apiFetch({ path: `/v1/app/${id}/preinstall`, method: 'post', }) dispatch(finishRequest(RequestKey.SetPreinstall, true)) } catch (err) { dispatch(finishRequest(RequestKey.SetPreinstall, false)) throw err } }