From 6d92c195e9bbe085cea1ad4d5c296e42d309624f Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Wed, 14 Jul 2021 16:43:25 -0600 Subject: [PATCH] rework endpoints and enable setting custom marketplace urls --- ui/config-sample.json | 7 +- .../app-release-notes.page.ts | 5 +- .../marketplace-list.page.html | 10 +- .../marketplace-list/marketplace-list.page.ts | 26 +- .../marketplace-show/marketplace-show.page.ts | 11 +- .../marketplace-routes/marketplace.service.ts | 43 +- .../dev-options/dev-options.page.html | 4 - .../dev-options/dev-options.page.ts | 3 - .../preferences/preferences.page.html | 19 - .../privacy.module.ts} | 8 +- .../server-routes/privacy/privacy.page.html | 34 ++ .../privacy.page.scss} | 0 .../privacy.page.ts} | 10 +- .../server-routes/server-routing.module.ts | 8 +- ui/src/app/services/api/api-types.ts | 32 +- .../app/services/api/api.service.factory.ts | 4 +- ui/src/app/services/api/api.service.ts | 30 +- ui/src/app/services/api/live-api.service.ts | 35 +- ui/src/app/services/api/mock-api.service.ts | 371 ++++++++---------- ui/src/app/services/api/mock-app-fixures.ts | 78 +--- ui/src/app/services/config.service.ts | 10 +- ui/src/app/services/http.service.ts | 8 +- ui/src/app/services/patch-db/data-model.ts | 14 +- ui/src/app/services/server-config.service.ts | 66 ++-- 24 files changed, 397 insertions(+), 439 deletions(-) delete mode 100644 ui/src/app/pages/server-routes/preferences/preferences.page.html rename ui/src/app/pages/server-routes/{preferences/preferences.module.ts => privacy/privacy.module.ts} (79%) create mode 100644 ui/src/app/pages/server-routes/privacy/privacy.page.html rename ui/src/app/pages/server-routes/{preferences/preferences.page.scss => privacy/privacy.page.scss} (100%) rename ui/src/app/pages/server-routes/{preferences/preferences.page.ts => privacy/privacy.page.ts} (70%) diff --git a/ui/config-sample.json b/ui/config-sample.json index 50460a61e..0550fd161 100644 --- a/ui/config-sample.json +++ b/ui/config-sample.json @@ -1,4 +1,8 @@ { + "start9Marketplace": { + "clearnet": "", + "tor": "" + }, "patchDb": { "poll": { "cooldown": 10000 @@ -14,7 +18,6 @@ "rpcPort": "5959", "wsPort": "5960", "maskAs": "tor", - "skipStartupAlerts": true, - "registryURL": "" + "skipStartupAlerts": true } } diff --git a/ui/src/app/pages/marketplace-routes/app-release-notes/app-release-notes.page.ts b/ui/src/app/pages/marketplace-routes/app-release-notes/app-release-notes.page.ts index 83559afdc..8d1acf450 100644 --- a/ui/src/app/pages/marketplace-routes/app-release-notes/app-release-notes.page.ts +++ b/ui/src/app/pages/marketplace-routes/app-release-notes/app-release-notes.page.ts @@ -10,7 +10,6 @@ import { MarketplaceService } from '../marketplace.service' }) export class AppReleaseNotes { @ViewChild(IonContent) content: IonContent - error = '' selected: string pkgId: string @@ -22,8 +21,8 @@ export class AppReleaseNotes { ngOnInit () { this.pkgId = this.route.snapshot.paramMap.get('pkgId') const version = this.route.snapshot.paramMap.get('version') - if (!this.marketplaceService.pkgs[this.pkgId]) { - this.marketplaceService.setPkg(this.pkgId, version) + if (!this.marketplaceService.pkgs[this.pkgId]?.['release-notes']) { + this.marketplaceService.getPkg(this.pkgId, version) } } diff --git a/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.html b/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.html index 09d98df88..d4d0831f7 100644 --- a/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.html +++ b/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.html @@ -46,17 +46,17 @@ - + -

{{ pkg.title }}

-

{{ pkg.descriptionShort }}

+

{{ pkg.manifest.title }}

+

{{ pkg.manifest.description.short }}

- Installed - Update Available + Installed + Update Available

Installing diff --git a/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.ts b/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.ts index cd7c4832c..ba5a08d97 100644 --- a/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.ts +++ b/ui/src/app/pages/marketplace-routes/marketplace-list/marketplace-list.page.ts @@ -1,6 +1,5 @@ import { Component, ViewChild } from '@angular/core' -import { ApiService } from 'src/app/services/api/api.service' -import { MarketplaceData, MarketplaceEOS, AvailablePreview } from 'src/app/services/api/api-types' +import { MarketplaceData, MarketplaceEOS, MarketplacePkg } from 'src/app/services/api/api-types' import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component' import { IonContent, ModalController } from '@ionic/angular' import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards' @@ -8,6 +7,7 @@ import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service' import { PackageState } from 'src/app/services/patch-db/data-model' import { Subscription } from 'rxjs' import { ErrorToastService } from 'src/app/services/error-toast.service' +import { MarketplaceService } from '../marketplace.service' @Component({ selector: 'marketplace-list', @@ -24,7 +24,7 @@ export class MarketplaceListPage { data: MarketplaceData eos: MarketplaceEOS - pkgs: AvailablePreview[] = [] + pkgs: MarketplacePkg[] = [] PackageState = PackageState @@ -35,7 +35,7 @@ export class MarketplaceListPage { subs: Subscription[] = [] constructor ( - private readonly apiService: ApiService, + private readonly marketplaceService: MarketplaceService, private readonly modalCtrl: ModalController, private readonly errToast: ErrorToastService, private readonly wizardBaker: WizardBaker, @@ -46,8 +46,8 @@ export class MarketplaceListPage { try { const [data, eos, pkgs] = await Promise.all([ - this.apiService.getMarketplaceData({ }), - this.apiService.getEos({ }), + this.marketplaceService.getMarketplaceData(), + this.marketplaceService.getEos(), this.getPkgs(), ]) this.data = data @@ -94,14 +94,14 @@ export class MarketplaceListPage { ) } - private async getPkgs (): Promise { + private async getPkgs (): Promise { try { - const pkgs = await this.apiService.getAvailableList({ - category: this.category !== 'all' ? this.category : undefined, - query: this.query, - page: this.page, - 'per-page': this.perPage, - }) + const pkgs = await this.marketplaceService.getPkgs( + this.category !== 'all' ? this.category : undefined, + this.query, + this.page, + this.perPage, + ) this.needInfinite = pkgs.length >= this.perPage this.page++ return pkgs diff --git a/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show.page.ts b/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show.page.ts index 9963d457e..72a8184ec 100644 --- a/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show.page.ts +++ b/ui/src/app/pages/marketplace-routes/marketplace-show/marketplace-show.page.ts @@ -1,6 +1,6 @@ import { Component, ViewChild } from '@angular/core' import { ActivatedRoute } from '@angular/router' -import { AlertController, IonContent, ModalController, NavController, ToastController } from '@ionic/angular' +import { AlertController, IonContent, ModalController, NavController } from '@ionic/angular' import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component' import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards' import { Emver } from 'src/app/services/emver.service' @@ -51,8 +51,9 @@ export class MarketplaceShowPage { this.installedPkg = pkg }), ] - - this.getPkg() + if (!this.marketplaceService.pkgs[this.pkgId]) { + this.getPkg() + } } ngAfterViewInit () { @@ -65,7 +66,7 @@ export class MarketplaceShowPage { async getPkg (version?: string): Promise { try { - await this.marketplaceService.setPkg(this.pkgId, version) + await this.marketplaceService.getPkg(this.pkgId, version) } catch (e) { console.error(e) this.errToast.present(e.message) @@ -117,7 +118,7 @@ export class MarketplaceShowPage { } async install () { - const { id, title, version, dependencies, alerts } = this.marketplaceService.pkgs[this.pkgId].manifest + const { id, title, version, alerts } = this.marketplaceService.pkgs[this.pkgId].manifest const { cancelled } = await wizardModal( this.modalCtrl, this.wizardBaker.install({ diff --git a/ui/src/app/pages/marketplace-routes/marketplace.service.ts b/ui/src/app/pages/marketplace-routes/marketplace.service.ts index 504b659b7..2b3da29f2 100644 --- a/ui/src/app/pages/marketplace-routes/marketplace.service.ts +++ b/ui/src/app/pages/marketplace-routes/marketplace.service.ts @@ -1,20 +1,53 @@ import { Injectable } from '@angular/core' -import { AvailableShow } from 'src/app/services/api/api-types' +import { MarketplacePkg } from 'src/app/services/api/api-types' import { ApiService } from 'src/app/services/api/api.service' @Injectable({ providedIn: 'root', }) export class MarketplaceService { - pkgs: { [id: string]: AvailableShow } = { } - additionalInfo + pkgs: { [id: string]: MarketplacePkg } = { } + releaseNotes: { [id: string]: { + [version: string]: string + } } constructor ( private readonly apiService: ApiService, ) { } - async setPkg (id: string, version?: string): Promise { - this.pkgs[id] = await this.apiService.getAvailableShow({ id, version }) + async getMarketplaceData () { + return this.apiService.getMarketplaceData({ }) + } + + async getEos () { + return this.apiService.getEos({ }) + } + + async getPkgs (category: string, query: string, page: number, perPage: number) : Promise { + const pkgs = await this.apiService.getMarketplacePkgs({ + category: category !== 'all' ? category : undefined, + query, + page: String(page), + 'per-page': String(perPage), + }) + this.pkgs = pkgs.reduce((cur, val) => { + cur[val.manifest.id] = val + return cur + }, { }) + return pkgs + } + + async getPkg (id: string, version?: string): Promise { + const pkg = (await this.apiService.getMarketplacePkgs({ id, version }))[0] + if (pkg) { + this.pkgs[id] = pkg + } else { + throw new Error(`No results for ${id}${version ? ' ' + version : ''}.`) + } + } + + async getReleaseNotes (id: string): Promise { + this.releaseNotes[id] = await this.apiService.getReleaseNotes({ id }) } } diff --git a/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.html b/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.html index 0a473a3cb..bfd154b86 100644 --- a/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.html +++ b/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.html @@ -13,10 +13,6 @@ SSH Keys - - Marketplace URL - {{ server.registry }} - \ No newline at end of file diff --git a/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.ts b/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.ts index ee41080a9..4e36df01e 100644 --- a/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.ts +++ b/ui/src/app/pages/server-routes/developer-routes/dev-options/dev-options.page.ts @@ -1,8 +1,6 @@ import { Component } from '@angular/core' import { ServerConfigService } from 'src/app/services/server-config.service' import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service' -import { ServerInfo } from 'src/app/services/patch-db/data-model' -import { Subscription } from 'rxjs' @Component({ selector: 'dev-options', @@ -10,7 +8,6 @@ import { Subscription } from 'rxjs' styleUrls: ['./dev-options.page.scss'], }) export class DevOptionsPage { - subs: Subscription[] = [] constructor ( private readonly serverConfigService: ServerConfigService, diff --git a/ui/src/app/pages/server-routes/preferences/preferences.page.html b/ui/src/app/pages/server-routes/preferences/preferences.page.html deleted file mode 100644 index b0745664d..000000000 --- a/ui/src/app/pages/server-routes/preferences/preferences.page.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - Preferences - - - - - - - - Auto Check for Updates - {{ patch.data.ui['auto-check-updates'] }} - - - - diff --git a/ui/src/app/pages/server-routes/preferences/preferences.module.ts b/ui/src/app/pages/server-routes/privacy/privacy.module.ts similarity index 79% rename from ui/src/app/pages/server-routes/preferences/preferences.module.ts rename to ui/src/app/pages/server-routes/privacy/privacy.module.ts index 3d6183464..618cfcdac 100644 --- a/ui/src/app/pages/server-routes/preferences/preferences.module.ts +++ b/ui/src/app/pages/server-routes/privacy/privacy.module.ts @@ -1,7 +1,7 @@ import { NgModule } from '@angular/core' import { CommonModule } from '@angular/common' import { IonicModule } from '@ionic/angular' -import { PreferencesPage } from './preferences.page' +import { PrivacyPage } from './privacy.page' import { Routes, RouterModule } from '@angular/router' import { SharingModule } from 'src/app/modules/sharing.module' import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module' @@ -9,7 +9,7 @@ import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-b const routes: Routes = [ { path: '', - component: PreferencesPage, + component: PrivacyPage, }, ] @@ -22,7 +22,7 @@ const routes: Routes = [ PwaBackComponentModule, ], declarations: [ - PreferencesPage, + PrivacyPage, ], }) -export class PreferencesPageModule { } +export class PrivacyPageModule { } diff --git a/ui/src/app/pages/server-routes/privacy/privacy.page.html b/ui/src/app/pages/server-routes/privacy/privacy.page.html new file mode 100644 index 000000000..dfbce4048 --- /dev/null +++ b/ui/src/app/pages/server-routes/privacy/privacy.page.html @@ -0,0 +1,34 @@ + + + + + + Privacy and Security + + + + + + + Marketplace Settings + + Use Tor + {{ patch.data['server-info']['eos-marketplace'] === config.start9Marketplace.tor }} + + + Package Marketplace + {{ patch.data['server-info']['package-marketplace'] }} + + + Auto Check for Updates + {{ patch.data.ui['auto-check-updates'] }} + + + + + Change Password + ******** + + + + diff --git a/ui/src/app/pages/server-routes/preferences/preferences.page.scss b/ui/src/app/pages/server-routes/privacy/privacy.page.scss similarity index 100% rename from ui/src/app/pages/server-routes/preferences/preferences.page.scss rename to ui/src/app/pages/server-routes/privacy/privacy.page.scss diff --git a/ui/src/app/pages/server-routes/preferences/preferences.page.ts b/ui/src/app/pages/server-routes/privacy/privacy.page.ts similarity index 70% rename from ui/src/app/pages/server-routes/preferences/preferences.page.ts rename to ui/src/app/pages/server-routes/privacy/privacy.page.ts index 968fa31d8..7344fb3f3 100644 --- a/ui/src/app/pages/server-routes/preferences/preferences.page.ts +++ b/ui/src/app/pages/server-routes/privacy/privacy.page.ts @@ -2,17 +2,19 @@ import { Component } from '@angular/core' import { ServerConfigService } from 'src/app/services/server-config.service' import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service' import { Subscription } from 'rxjs' +import { ConfigService } from 'src/app/services/config.service' @Component({ - selector: 'preferences', - templateUrl: './preferences.page.html', - styleUrls: ['./preferences.page.scss'], + selector: 'privacy', + templateUrl: './privacy.page.html', + styleUrls: ['./privacy.page.scss'], }) -export class PreferencesPage { +export class PrivacyPage { subs: Subscription[] = [] constructor ( private readonly serverConfigService: ServerConfigService, + public readonly config: ConfigService, public readonly patch: PatchDbModel, ) { } diff --git a/ui/src/app/pages/server-routes/server-routing.module.ts b/ui/src/app/pages/server-routes/server-routing.module.ts index c85246830..6a69e1b64 100644 --- a/ui/src/app/pages/server-routes/server-routing.module.ts +++ b/ui/src/app/pages/server-routes/server-routing.module.ts @@ -23,12 +23,8 @@ const routes: Routes = [ loadChildren: () => import('./server-logs/server-logs.module').then(m => m.ServerLogsPageModule), }, { - path: 'preferences', - loadChildren: () => import('./preferences/preferences.module').then(m => m.PreferencesPageModule), - }, - { - path: 'preferences/edit', - loadChildren: () => import('./preferences/preferences.module').then(m => m.PreferencesPageModule), + path: 'privacy', + loadChildren: () => import('./privacy/privacy.module').then(m => m.PrivacyPageModule), }, { path: 'wifi', diff --git a/ui/src/app/services/api/api-types.ts b/ui/src/app/services/api/api-types.ts index 34eb17f90..bc2ea2373 100644 --- a/ui/src/app/services/api/api-types.ts +++ b/ui/src/app/services/api/api-types.ts @@ -44,10 +44,17 @@ export module RR { export type RefreshLanReq = { } // network.lan.refresh export type RefreshLanRes = null - // registry + // marketplace URLs - export type SetRegistryReq = WithExpire<{ url: string }> // registry.set - export type SetRegistryRes = WithRevision + export type SetEosMarketplaceReq = WithExpire<{ url: string }> // marketplace.eos.set + export type SetEosMarketplaceRes = WithRevision + + export type SetPackageMarketplaceReq = WithExpire<{ url: string }> // marketplace.package.set + export type SetPackageMarketplaceRes = WithRevision + + // password + export type UpdatePasswordReq = { password: string } // password.set + export type UpdatePasswordRes = null // notification @@ -160,11 +167,11 @@ export module RR { export type GetMarketplaceEOSReq = { } export type GetMarketplaceEOSRes = MarketplaceEOS - export type GetAvailableListReq = { category?: string, query?: string, page: number, 'per-page': number } - export type GetAvailableListRes = AvailablePreview[] + export type GetMarketplacePackagesReq = { id?: string, version?: string, category?: string, query?: string, page?: string, 'per-page'?: string } + export type GetMarketplacePackagesRes = MarketplacePkg[] - export type GetAvailableShowReq = { id: string, version?: string } - export type GetAvailableShowRes = AvailableShow + export type GetReleaseNotesReq = { id: string } + export type GetReleaseNotesRes = { [version: string]: string} } export type WithExpire = { 'expire-id'?: string } & T @@ -180,15 +187,7 @@ export interface MarketplaceEOS { 'release-notes': { [version: string]: string } } -export interface AvailablePreview { - id: string - title: string - version: string - icon: URL - descriptionShort: string -} - -export interface AvailableShow { +export interface MarketplacePkg { icon: URL license: URL instructions: URL @@ -201,7 +200,6 @@ export interface AvailableShow { icon: URL } }, - 'release-notes': { [version: string]: string } } export interface Breakages { diff --git a/ui/src/app/services/api/api.service.factory.ts b/ui/src/app/services/api/api.service.factory.ts index b23e46824..6dbce96fa 100644 --- a/ui/src/app/services/api/api.service.factory.ts +++ b/ui/src/app/services/api/api.service.factory.ts @@ -5,8 +5,8 @@ import { ConfigService } from '../config.service' export function ApiServiceFactory (config: ConfigService, http: HttpService) { if (config.mocks.enabled) { - return new MockApiService(http) + return new MockApiService(config, http) } else { - return new LiveApiService(http) + return new LiveApiService(config, http) } } diff --git a/ui/src/app/services/api/api.service.ts b/ui/src/app/services/api/api.service.ts index c9ebc311c..86dd58dc7 100644 --- a/ui/src/app/services/api/api.service.ts +++ b/ui/src/app/services/api/api.service.ts @@ -53,13 +53,21 @@ export abstract class ApiService implements Source, Http { abstract refreshLan (params: RR.RefreshLanReq): Promise - // registry + // marketplace URLs - protected abstract setRegistryRaw (params: RR.SetRegistryReq): Promise - setRegistry = (params: RR.SetRegistryReq) => this.syncResponse( - () => this.setRegistryRaw(params), + protected abstract setEosMarketplaceRaw (isTor: boolean): Promise + setEosMarketplace = (isTor: boolean) => this.syncResponse( + () => this.setEosMarketplaceRaw(isTor), )() + protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise + setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse( + () => this.setPackageMarketplaceRaw(params), + )() + + // password + abstract updatePassword (params: RR.UpdatePasswordReq): Promise + // notification abstract getNotificationsRaw (params: RR.GetNotificationsReq): Promise @@ -165,9 +173,9 @@ export abstract class ApiService implements Source, Http { abstract getEos (params: RR.GetMarketplaceEOSReq): Promise - abstract getAvailableList (params: RR.GetAvailableListReq): Promise + abstract getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise - abstract getAvailableShow (params: RR.GetAvailableShowReq): Promise + abstract getReleaseNotes (params: RR.GetReleaseNotesReq): Promise // Helper allowing quick decoration to sync the response patch and return the response contents. // Pass in a tempUpdate function which returns a UpdateTemp corresponding to a temporary @@ -187,3 +195,13 @@ export abstract class ApiService implements Source, Http { } } } + +export function getMarketURL (eosOrPackage: 'eos' | 'package', data: DataModel): string { + const eosMarketplace = data['server-info']['eos-marketplace'] + if (eosOrPackage === 'eos') { + return eosMarketplace + } else { + const packageMarketplace = data['server-info']['package-marketplace'] + return packageMarketplace || eosMarketplace + } +} \ No newline at end of file diff --git a/ui/src/app/services/api/live-api.service.ts b/ui/src/app/services/api/live-api.service.ts index ed5576591..4707d28f9 100644 --- a/ui/src/app/services/api/live-api.service.ts +++ b/ui/src/app/services/api/live-api.service.ts @@ -1,12 +1,15 @@ import { Injectable } from '@angular/core' import { HttpService, Method } from '../http.service' -import { ApiService } from './api.service' +import { ApiService, getMarketURL } from './api.service' import { RR } from './api-types' import { parsePropertiesPermissive } from 'src/app/util/properties.util' +import { ConfigService } from '../config.service' @Injectable() export class LiveApiService extends ApiService { + constructor ( + private readonly config: ConfigService, private readonly http: HttpService, ) { super() } @@ -66,10 +69,22 @@ export class LiveApiService extends ApiService { return this.http.rpcRequest({ method: 'network.lan.refresh', params }) } - // registry + // marketplace URLs - async setRegistryRaw (params: RR.SetRegistryReq): Promise { - return this.http.rpcRequest({ method: 'registry.set', params }) + async setEosMarketplaceRaw (isTor: boolean): Promise { + const params: RR.SetEosMarketplaceReq = { + url: isTor ? this.config.start9Marketplace.tor : this.config.start9Marketplace.clearnet, + } + return this.http.rpcRequest({ method: 'marketplace.eos.set', params }) + } + + async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise { + return this.http.rpcRequest({ method: 'marketplace.package.set', params }) + } + + // password + async updatePassword (params: RR.UpdatePasswordReq): Promise { + return this.http.rpcRequest({ method: 'password.set', params }) } // notification @@ -200,18 +215,18 @@ export class LiveApiService extends ApiService { // marketplace async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise { - return this.http.rpcRequest({ method: 'marketplace.data', params }) + return this.http.simpleGet(getMarketURL('package', this.patch.data), params) } async getEos (params: RR.GetMarketplaceEOSReq): Promise { - return this.http.rpcRequest({ method: 'marketplace.eos', params }) + return this.http.simpleGet(getMarketURL('eos', this.patch.data), params) } - async getAvailableList (params: RR.GetAvailableListReq): Promise { - return this.http.rpcRequest({ method: 'marketplace.available.list', params }) + async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise { + return this.http.simpleGet(getMarketURL('package', this.patch.data), params) } - async getAvailableShow (params: RR.GetAvailableShowReq): Promise { - return this.http.rpcRequest({ method: 'marketplace.available', params }) + async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise { + return this.http.simpleGet(getMarketURL('package', this.patch.data), params) } } diff --git a/ui/src/app/services/api/mock-api.service.ts b/ui/src/app/services/api/mock-api.service.ts index a2fb2c275..9868cc413 100644 --- a/ui/src/app/services/api/mock-api.service.ts +++ b/ui/src/app/services/api/mock-api.service.ts @@ -1,36 +1,24 @@ import { Injectable } from '@angular/core' import { pauseFor } from '../../util/misc.util' -import { ApiService } from './api.service' -import { Observable } from 'rxjs' -import { PatchOp, Store, Update } from 'patch-db-client' -import { DataModel, PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model' -import { RR } from './api-types' +import { ApiService, getMarketURL } from './api.service' +import { PatchOp } from 'patch-db-client' +import { PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model' +import { RR, WithRevision } from './api-types' import { parsePropertiesPermissive } from 'src/app/util/properties.util' import { Mock } from './mock-app-fixures' -import { HttpService, Method } from '../http.service' +import { HttpService } from '../http.service' import markdown from 'raw-loader!src/assets/markdown/md-sample.md' import { ConfigService } from '../config.service' -const configService = new ConfigService() + @Injectable() export class MockApiService extends ApiService { - sequence = 0 welcomeAck = false constructor ( + private readonly config: ConfigService, private readonly http: HttpService, ) { super() } - // every time a patch is returned from the mock, we override its sequence to be 1 more than the last sequence in the patch-db as provided by `o`. - watch$ (store: Store): Observable> { - store.sequence$.subscribe(seq => { - console.log('INCOMING: ', seq) - if (this.sequence < seq) { - this.sequence = seq - } - }) - return super.watch$() - } - async getStatic (url: string): Promise { await pauseFor(2000) return markdown @@ -106,20 +94,14 @@ export class MockApiService extends ApiService { async updateServerRaw (params: RR.UpdateServerReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/status', - value: ServerStatus.Updating, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/status', + value: ServerStatus.Updating, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async restartServer (params: RR.RestartServerReq): Promise { @@ -139,43 +121,56 @@ export class MockApiService extends ApiService { return null } - // registry + // marketplace URLs - async setRegistryRaw (params: RR.SetRegistryReq): Promise { + async setEosMarketplaceRaw (isTor: boolean): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/registry', - value: params.url, - }, - ], - expireId: null, - }, + const params: RR.SetEosMarketplaceReq = { + url: isTor ? this.config.start9Marketplace.tor : this.config.start9Marketplace.clearnet, } + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/eos-marketplace', + value: params.url, + }, + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) + } + + async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise { + await pauseFor(2000) + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/package-marketplace', + value: params.url, + }, + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) + } + + // password + async updatePassword (params: RR.UpdatePasswordReq): Promise { + await pauseFor(2000) + return null } // notification async getNotificationsRaw (params: RR.GetNotificationsReq): Promise { await pauseFor(2000) + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/unread-notification-count', + value: 0, + }, + ] + const { revision } = await this.http.rpcRequest({ method: 'db.patch', params: { patch } }) as WithRevision return { response: Mock.Notifications, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/unread-notification-count', - value: 0, - }, - ], - expireId: null, - }, + revision, } } @@ -193,48 +188,36 @@ export class MockApiService extends ApiService { async connectWifiRaw (params: RR.ConnectWifiReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/wifi/selected', - value: params.ssid, - }, - { - op: PatchOp.REPLACE, - path: '/server-info/wifi/connected', - value: params.ssid, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/wifi/selected', + value: params.ssid, }, - } + { + op: PatchOp.REPLACE, + path: '/server-info/wifi/connected', + value: params.ssid, + }, + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async deleteWifiRaw (params: RR.DeleteWifiReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/wifi/selected', - value: null, - }, - { - op: PatchOp.REPLACE, - path: '/server-info/wifi/connected', - value: null, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/wifi/selected', + value: null, }, - } + { + op: PatchOp.REPLACE, + path: '/server-info/wifi/connected', + value: null, + }, + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } // ssh @@ -258,20 +241,14 @@ export class MockApiService extends ApiService { async createBackupRaw (params: RR.CreateBackupReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: '/server-info/status', - value: ServerStatus.BackingUp, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: '/server-info/status', + value: ServerStatus.BackingUp, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async restoreBackupRaw (params: RR.RestoreBackupReq): Promise { @@ -308,7 +285,6 @@ export class MockApiService extends ApiService { const pkg: PackageDataEntry = { ...Mock.bitcoinproxy, state: PackageState.Installing, - // installed: undefined, 'install-progress': { size: 100, downloaded: 10, @@ -319,20 +295,14 @@ export class MockApiService extends ApiService { 'read-complete': false, }, } - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.ADD, - path: `/package-data/${params.id}`, - value: pkg, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.ADD, + path: `/package-data/${params.id}`, + value: pkg, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise { @@ -352,43 +322,31 @@ export class MockApiService extends ApiService { async setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/installed/status/configured`, - value: true, - }, - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/installed/status/main/status`, - value: PackageMainStatus.Running, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/configured`, + value: true, }, - } + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/main/status`, + value: PackageMainStatus.Running, + }, + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async restorePackageRaw (params: RR.RestorePackageReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/installed/status/main/status`, - value: PackageMainStatus.Restoring, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/main/status`, + value: PackageMainStatus.Restoring, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async executePackageAction (params: RR.ExecutePackageActionReq): Promise { @@ -403,20 +361,14 @@ export class MockApiService extends ApiService { async startPackageRaw (params: RR.StartPackageReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/installed/status/main/status`, - value: PackageMainStatus.Running, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/main/status`, + value: PackageMainStatus.Running, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async dryStopPackage (params: RR.DryStopPackageReq): Promise { @@ -426,20 +378,26 @@ export class MockApiService extends ApiService { async stopPackageRaw (params: RR.StopPackageReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/installed/status/main/status`, - value: PackageMainStatus.Stopping, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/main/status`, + value: PackageMainStatus.Stopping, }, - } + ] + const res = await this.http.rpcRequest>({ method: 'db.patch', params: { patch } }) + setTimeout(() => { + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/installed/status/main/status`, + value: PackageMainStatus.Stopped, + }, + ] + this.http.rpcRequest>({ method: 'db.patch', params: { patch } }) + }, 2000) + + return res } async dryRemovePackage (params: RR.DryRemovePackageReq): Promise { @@ -449,20 +407,14 @@ export class MockApiService extends ApiService { async removePackageRaw (params: RR.RemovePackageReq): Promise { await pauseFor(2000) - return { - response: null, - revision: { - id: this.nextSequence(), - patch: [ - { - op: PatchOp.REPLACE, - path: `/package-data/${params.id}/state`, - value: PackageState.Removing, - }, - ], - expireId: null, + const patch = [ + { + op: PatchOp.REPLACE, + path: `/package-data/${params.id}/state`, + value: PackageState.Removing, }, - } + ] + return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) } async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise { @@ -473,7 +425,7 @@ export class MockApiService extends ApiService { // marketplace async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise { - const registryURL = configService.mocks.registryURL + const registryURL = getMarketURL('package', this.patch.data) if (!registryURL) { await pauseFor(2000) return { @@ -481,47 +433,36 @@ export class MockApiService extends ApiService { } } const url = `${registryURL}/marketplace/data` - let md = await this.http.simpleGet(url) - return (md as any) + return this.http.simpleGet(url) } async getEos (params: RR.GetMarketplaceEOSReq): Promise { - const registryURL = configService.mocks.registryURL + const registryURL = getMarketURL('eos', this.patch.data) if (!registryURL) { await pauseFor(2000) return Mock.MarketplaceEos } const url = `${registryURL}/sys/version/eos` - let eos = await this.http.simpleGet(url) - return (eos as any) + return this.http.simpleGet(url) } - async getAvailableList (params: RR.GetAvailableListReq): Promise { - const registryURL = configService.mocks.registryURL + async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise { + const registryURL = getMarketURL('package', this.patch.data) if (!registryURL) { await pauseFor(2000) return Mock.AvailableList } - const url = `${registryURL}/marketplace/available/list?${params.category ? `category=${params.category}` : ''}&per-page=${params['per-page'] || '20'}&page=${params.page || '1'}&query=${params.query || ''}` - let av = await this.http.simpleGet(url) - return (av as any).services + const url = `${registryURL}/marketplace/packages` + return this.http.simpleGet(url, params) } - async getAvailableShow (params: RR.GetAvailableShowReq): Promise { - const registryURL = configService.mocks.registryURL + async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise { + const registryURL = getMarketURL('package', this.patch.data) if (!registryURL) { await pauseFor(2000) - return Mock.AvailableShow[params.id][params.version || 'latest'] + return Mock.ReleaseNotes } - const url = `${registryURL}/marketplace/available?id=${params.id}` - let res = await this.http.simpleGet(url) - console.log('res RES RES', res) - return (res as any) - } - - private nextSequence () { - console.log('next') - this.sequence++ - return this.sequence + const url = `${registryURL}/marketplace/release-notes` + return this.http.simpleGet(url) } } diff --git a/ui/src/app/services/api/mock-app-fixures.ts b/ui/src/app/services/api/mock-app-fixures.ts index b0ef9f060..46927bd52 100644 --- a/ui/src/app/services/api/mock-app-fixures.ts +++ b/ui/src/app/services/api/mock-app-fixures.ts @@ -1,5 +1,5 @@ import { DependencyErrorType, DockerIoFormat, Manifest, PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model' -import { Metric, NotificationLevel, RR, ServerNotification, ServerNotifications } from './api-types' +import { MarketplacePkg, Metric, NotificationLevel, RR, ServerNotification, ServerNotifications } from './api-types' export module Mock { @@ -9,29 +9,11 @@ export module Mock { 'release-notes': { '1.0.0': 'Some **Markdown** release _notes_' }, } - export const AvailableList: RR.GetAvailableListRes = [ - { - id: 'bitcoind', - title: 'Bitcoin Core', - version: '0.21.1', - descriptionShort: 'A Bitcoin full node by Bitcoin Core.', - icon: 'assets/img/service-icons/bitcoind.png', - }, - { - id: 'lnd', - title: 'LND', - version: '0.11.1', - descriptionShort: 'A BOLT-compliant, lightning network node.', - icon: 'assets/img/service-icons/lnd.png', - }, - { - id: 'bitcoin-proxy', - title: 'Bitcoin Proxy', - version: '0.2.2', - descriptionShort: 'A super charger for your Bitcoin node.', - icon: 'assets/img/service-icons/bitcoin-proxy.png', - }, - ] + export const ReleaseNotes: RR.GetReleaseNotesRes = { + '0.19.2': 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.', + '0.19.1': 'release notes for Bitcoin 0.19.1', + '0.19.0': 'release notes for Bitcoin 0.19.0', + } export const MockManifestBitcoind: Manifest = { id: 'bitcoind', @@ -395,7 +377,7 @@ export module Mock { export const AvailableShow: { [id: string]: { - [version: string]: RR.GetAvailableShowRes + [version: string]: MarketplacePkg } } = { 'bitcoind': { @@ -410,11 +392,6 @@ export module Mock { categories: ['bitcoin', 'cryptocurrency'], versions: ['0.19.0', '0.20.0', '0.21.0'], 'dependency-metadata': { }, - 'release-notes': { - '0.19.2': 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.', - '0.19.1': 'release notes for Bitcoin 0.19.1', - '0.19.0': 'release notes for Bitcoin 0.19.0', - }, }, '0.20.0': { icon: 'assets/img/service-icons/bitcoind.png', @@ -427,11 +404,6 @@ export module Mock { categories: ['bitcoin', 'cryptocurrency'], versions: ['0.19.0', '0.20.0', '0.21.0'], 'dependency-metadata': { }, - 'release-notes': { - '0.19.2': 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.', - '0.19.1': 'release notes for Bitcoin 0.19.1', - '0.19.0': 'release notes for Bitcoin 0.19.0', - }, }, '0.21.0': { icon: 'assets/img/service-icons/bitcoind.png', @@ -445,11 +417,6 @@ export module Mock { categories: ['bitcoin', 'cryptocurrency'], versions: ['0.19.0', '0.20.0', '0.21.0'], 'dependency-metadata': { }, - 'release-notes': { - '0.19.2': 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.', - '0.19.1': 'release notes for Bitcoin 0.19.1', - '0.19.0': 'release notes for Bitcoin 0.19.0', - }, }, 'latest': { icon: 'assets/img/service-icons/bitcoind.png', @@ -462,11 +429,6 @@ export module Mock { categories: ['bitcoin', 'cryptocurrency'], versions: ['0.19.0', '0.20.0', '0.21.0'], 'dependency-metadata': { }, - 'release-notes': { - '0.21.0': 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.', - '0.20.0': 'release notes for Bitcoin 0.20.0', - '0.19.2': 'release notes for Bitcoin 0.19.2', - }, }, }, 'lnd': { @@ -491,11 +453,6 @@ export module Mock { icon: 'assets/img/service-icons/bitcoin-proxy.png', }, }, - 'release-notes': { - '0.19.2': 'release notes for LND 0.19.2', - '0.19.1': 'release notes for LND 0.19.1', - '0.19.0': 'release notes for LND 0.19.0', - }, }, '0.11.1': { icon: 'assets/img/service-icons/lnd.png', @@ -518,11 +475,6 @@ export module Mock { icon: 'assets/img/service-icons/bitcoin-proxy.png', }, }, - 'release-notes': { - '0.19.2': 'release notes for LND 0.19.2', - '0.19.1': 'release notes for LND 0.19.1', - '0.19.0': 'release notes for LND 0.19.0', - }, }, 'latest': { icon: 'assets/img/service-icons/lnd.png', @@ -541,11 +493,6 @@ export module Mock { icon: 'assets/img/service-icons/bitcoin-proxy.png', }, }, - 'release-notes': { - '0.19.2': 'release notes for LND 0.19.2', - '0.19.1': 'release notes for LND 0.19.1', - '0.19.0': 'release notes for LND 0.19.0', - }, }, }, 'bitcoin-proxy': { @@ -562,15 +509,12 @@ export module Mock { icon: 'assets/img/service-icons/bitcoind.png', }, }, - 'release-notes': { - '0.19.2': 'release notes for btc proxy 0.19.2', - '0.19.1': 'release notes for btc proxy 0.19.1', - '0.19.0': 'release notes for btc proxy 0.19.0', - }, }, }, } + export const AvailableList: RR.GetMarketplacePackagesRes = Object.values(Mock.AvailableShow).map(service => service['latest']) + export const bitcoind: PackageDataEntry = { state: PackageState.Installed, 'static-files': { @@ -731,8 +675,8 @@ export module Mock { selected: 'Goosers5G', connected: 'Goosers5G', }, - 'package-registry': 'https://registry.start9.com', - 'system-registry': 'https://registry.start9.com', + 'package-marketplace': 'https://registry.start9.com', + 'eos-marketplace': 'https://registry.start9.com', 'unread-notification-count': 4, specs: { CPU: 'Cortex-A72: 4 Cores @1500MHz', diff --git a/ui/src/app/services/config.service.ts b/ui/src/app/services/config.service.ts index 8e66e8641..ae3ef9b10 100644 --- a/ui/src/app/services/config.service.ts +++ b/ui/src/app/services/config.service.ts @@ -1,9 +1,13 @@ import { Injectable } from '@angular/core' -import { InstalledPackageDataEntry, InterfaceDef, Manifest, PackageDataEntry, PackageMainStatus, PackageState } from './patch-db/data-model' +import { InterfaceDef, Manifest, PackageDataEntry, PackageMainStatus, PackageState } from './patch-db/data-model' -const { patchDb, api, mocks } = require('../../../config.json') as UiConfig +const { start9Marketplace, patchDb, api, mocks } = require('../../../config.json') as UiConfig type UiConfig = { + start9Marketplace: { + clearnet: string + tor: string + } patchDb: { poll: { cooldown: number /* in ms */ @@ -20,7 +24,6 @@ type UiConfig = { wsPort: number maskAs: 'tor' | 'lan' skipStartupAlerts: boolean - registryURL: String } } @Injectable({ @@ -30,6 +33,7 @@ export class ConfigService { origin = removePort(removeProtocol(window.origin)) version = require('../../../package.json').version + start9Marketplace = start9Marketplace patchDb = patchDb api = api mocks = mocks diff --git a/ui/src/app/services/http.service.ts b/ui/src/app/services/http.service.ts index 660f97479..b6a5c203f 100644 --- a/ui/src/app/services/http.service.ts +++ b/ui/src/app/services/http.service.ts @@ -44,9 +44,11 @@ export class HttpService { if (isRpcSuccess(res)) return res.result } - async simpleGet (url: string): Promise { - const data = await this.http.get(url).toPromise() - return data + async simpleGet (url: string, params: { [param: string]: string | string[] } = { }): Promise { + Object.keys(params).forEach(key => { + if (!params[key]) delete params[key] + }) + return this.http.get(url, { params }).toPromise() } async httpRequest (httpOpts: HttpOptions): Promise { diff --git a/ui/src/app/services/patch-db/data-model.ts b/ui/src/app/services/patch-db/data-model.ts index 77aaffd02..63b1f1e98 100644 --- a/ui/src/app/services/patch-db/data-model.ts +++ b/ui/src/app/services/patch-db/data-model.ts @@ -6,14 +6,19 @@ export interface DataModel { ui: UIData } +export interface UIData { + 'welcome-ack': string + 'auto-check-updates': boolean +} + export interface ServerInfo { id: string version: string 'lan-address': URL 'tor-address': URL status: ServerStatus - 'package-registry': URL - 'system-registry': URL + 'eos-marketplace': URL + 'package-marketplace': URL | null // uses EOS marketplace if null wifi: WiFiInfo 'unread-notification-count': number specs: { @@ -376,8 +381,3 @@ export interface InterfaceInfo { } export type URL = string - -export interface UIData { - 'welcome-ack': string - 'auto-check-updates': boolean -} diff --git a/ui/src/app/services/server-config.service.ts b/ui/src/app/services/server-config.service.ts index 96eb8f132..1d1030d60 100644 --- a/ui/src/app/services/server-config.service.ts +++ b/ui/src/app/services/server-config.service.ts @@ -34,35 +34,25 @@ export class ServerConfigService { } saveFns: { [key: string]: (val: any) => Promise } = { - name: async (value: string) => { - return this.apiService.setDbValue({ pointer: 'ui/name', value }) - }, autoCheckUpdates: async (value: boolean) => { return this.apiService.setDbValue({ pointer: 'ui/auto-check-updates', value }) }, ssh: async (pubkey: string) => { return this.sshService.add(pubkey) }, - registry: async (url: string) => { - return this.apiService.setRegistry({ url }) + eosMarketplace: async (enabled: boolean) => { + return this.apiService.setEosMarketplace(enabled) + }, + packageMarketplace: async (url: string) => { + return this.apiService.setPackageMarketplace({ url }) + }, + password: async (password: string) => { + return this.apiService.updatePassword({ password }) }, - // password: async (password: string) => { - // return this.apiService.updatePassword({ password }) - // }, } } const serverConfig: ConfigSpec = { - name: { - type: 'string', - name: 'Device Name', - description: 'A unique label for this device.', - nullable: false, - pattern: '^.{1,40}$', - patternDescription: 'Must be less than 40 characters', - masked: false, - copyable: false, - }, autoCheckUpdates: { type: 'boolean', name: 'Auto Check for Updates', @@ -80,29 +70,33 @@ const serverConfig: ConfigSpec = { masked: false, copyable: false, }, - registry: { + eosMarketplace: { + type: 'boolean', + name: 'Use Tor', + description: `Use Start9's Tor Hidden Service Marketplace (instead of clearnet).`, + default: false, + }, + packageMarketplace: { type: 'string', - name: 'Marketplace URL', - description: 'The URL of the service marketplace. By default, your Embassy connects to the official Start9 Embassy Marketplace.', + name: 'Package Marketplace', + description: `Use for alternative embassy marketplace. Leave empty to use start9's marketplace.`, nullable: true, // @TODO regex for URL // pattern: '', - patternDescription: 'Must be a valid URL', - changeWarning: 'Downloading services from an alternative marketplace can result in malicious or harmful code being installed on your device.', - default: 'https://registry.start9.com', + patternDescription: 'Must be a valid URL.', + masked: false, + copyable: false, + }, + password: { + type: 'string', + name: 'Change Password', + description: `Your Embassy's master password, used for authentication and disk encryption.`, + nullable: false, + // @TODO regex for 12 chars + // pattern: '', + patternDescription: 'Must contain at least 12 characters.', + changeWarning: 'If you forget your master password, there is absolutely no way to recover your data. This can result in loss of money! Keep in mind, old backups will still be encrypted by the password used to encrypt them.', masked: false, copyable: false, }, - // password: { - // type: 'string', - // name: 'Change Password', - // description: 'The master password for your Embassy. Must contain at least 128 bits of entropy.', - // nullable: false, - // // @TODO figure out how to confirm min entropy - // // pattern: '^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[*.!@#$%^&*\]).{12,32}$', - // patternDescription: 'Password too simple. Password must contain at least 128 bits of entroy.', - // changeWarning: 'Changing your password will have no affect on old backups. In order to restore old backups, you must provide the password that was used to create them.', - // masked: true, - // copyable: true, - // }, }