diff --git a/dashboard/src/components/AppArchive.vue b/dashboard/src/components/AppArchive.vue new file mode 100644 index 000000000..a5529494a --- /dev/null +++ b/dashboard/src/components/AppArchive.vue @@ -0,0 +1,308 @@ + + + diff --git a/dashboard/src/models/ArchivesModel.js b/dashboard/src/models/ArchivesModel.js new file mode 100644 index 000000000..28bfa5166 --- /dev/null +++ b/dashboard/src/models/ArchivesModel.js @@ -0,0 +1,81 @@ + +import { fetcher } from 'pankow'; +import DomainsModel from './DomainsModel.js'; + +function create() { + const accessToken = localStorage.token; + const origin = import.meta.env.VITE_API_ORIGIN || window.location.origin; + + const domainsModel = DomainsModel.create(); + + return { + async list() { + const page = 1; + const per_page = 1000; + + let error, result; + try { + result = await fetcher.get(`${origin}/api/v1/archives`, { page, per_page, access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body.archives]; + }, + async remove(id) { + let error, result; + try { + result = await fetcher.del(`${origin}/api/v1/archives/${id}`, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 204) return [error || result]; + return [null]; + }, + async restore(id, data) { + // preflight domain checks + if (!data.overwriteDns) { + const allDomains = [{ domain: data.domain, subdomain: data.subdomain }].concat(Object.keys(data.secondaryDomains).map(function (k) { + return { + domain: data.secondaryDomains[k].domain, + subdomain: data.secondaryDomains[k].subdomain + }; + })); + + for (const domain in allDomains) { + const [error, result] = await domainsModel.checkRecords(domain.domain, domain.subdomain); + if (error) return [error]; + + const fqdn = domain.subdomain + '.' + domain.domain; + + if (result.error) { + if (result.error.reason === 'Access Denied') return [{ type: 'provider', fqdn, message: 'DNS credentials for ' + domain.domain + ' are invalid. Update it in Domains & Certs view' }]; + return [{ type: 'provider', fqdn, message: result.error.message }]; + } + + if (result.needsOverwrite) { + // $scope.archiveRestore.needsOverwrite = true; + // $scope.archiveRestore.overwriteDns = true; + return [{ type: 'externally_exists', fqdn, message: 'DNS Record already exists. Confirm that the domain is not in use for services external to Cloudron' }]; + } + } + } + + let error, result; + try { + result = await fetcher.post(`${origin}/api/v1/archives/${id}/unarchive`, data, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 202) return [error || result]; + return [null, result.body]; + }, + }; +} + +export default { + create, +}; diff --git a/dashboard/src/models/DomainsModel.js b/dashboard/src/models/DomainsModel.js index 5dc40dc74..f8227fa3c 100644 --- a/dashboard/src/models/DomainsModel.js +++ b/dashboard/src/models/DomainsModel.js @@ -98,6 +98,16 @@ function create() { if (error || result.status !== 204) return [error || result]; return [null]; }, + async checkRecords(domain, subdomain) { + let error, result; + try { + result = await fetcher.get(`${origin}/api/v1/domains/${domain}/dns_check`, { subdomain, access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + }, }; } diff --git a/dashboard/src/views/BackupsView.vue b/dashboard/src/views/BackupsView.vue index 60425032c..2fada07db 100644 --- a/dashboard/src/views/BackupsView.vue +++ b/dashboard/src/views/BackupsView.vue @@ -6,6 +6,7 @@ import { Button } from 'pankow'; import Section from '../components/Section.vue'; import BackupSchedule from '../components/BackupSchedule.vue'; import BackupList from '../components/BackupList.vue'; +import AppArchive from '../components/AppArchive.vue'; import BackupsModel from '../models/BackupsModel.js'; import ProfileModel from '../models/ProfileModel.js'; @@ -119,5 +120,6 @@ onMounted(async () => { + diff --git a/dashboard/src/views/VolumesView.vue b/dashboard/src/views/VolumesView.vue index fa7196ff7..22132a82e 100644 --- a/dashboard/src/views/VolumesView.vue +++ b/dashboard/src/views/VolumesView.vue @@ -292,7 +292,7 @@ onMounted(async () =>{ - +