Create db_api service wrapper and OO classes
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Garrett Mills 2020-11-16 08:23:59 -06:00
parent 65de891fe8
commit 0378522e9a
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
7 changed files with 261 additions and 19 deletions

View File

@ -41,7 +41,6 @@
</ion-list> </ion-list>
</ion-content> </ion-content>
<ion-footer> <ion-footer>
<!-- <ion-searchbar placeholder="Filter pages..." (ionChange)="onFilterChange($event)"></ion-searchbar>-->
<ion-item button lines="full" (click)="showOptions($event)"> <ion-item button lines="full" (click)="showOptions($event)">
<ion-icon name="list" slot="start"></ion-icon> <ion-icon name="list" slot="start"></ion-icon>
<ion-label>Menu</ion-label> <ion-label>Menu</ion-label>

View File

@ -1,4 +1,4 @@
import {Component, OnInit, ViewChild, HostListener, Host} from '@angular/core'; import {Component, OnInit, ViewChild, HostListener} from '@angular/core';
import { import {
AlertController, AlertController,
@ -144,21 +144,6 @@ export class AppComponent implements OnInit {
}).then(popover => popover.present()); }).then(popover => popover.present());
} }
onFilterChange($event) {
const query = $event.detail.value.toLowerCase();
this.menuTree.treeModel.clearFilter();
if ( query ) {
this.menuTree.treeModel.filterNodes(node => {
if ( node.data.virtual ) {
// "Virtual" tree nodes should always be shown
return true;
}
return node.data.name.toLowerCase().indexOf(query) >= 0;
});
}
}
@HostListener('document:keyup.control./', ['$event']) @HostListener('document:keyup.control./', ['$event'])
async handleKeyboardEvent() { async handleKeyboardEvent() {
if ( this.hasSearchOpen ) { if ( this.hasSearchOpen ) {

View File

@ -285,12 +285,27 @@ export class ApiService {
}); });
} }
public _build_url(endpoint) { public _build_url(endpoint, base = this.baseEndpoint) {
if ( !endpoint.startsWith('/') ) { if ( !endpoint.startsWith('/') ) {
endpoint = `/${endpoint}`; endpoint = `/${endpoint}`;
} }
return `${this.baseEndpoint.endsWith('/') ? this.baseEndpoint.slice(0, -1) : this.baseEndpoint}${endpoint}`; return `${base.endsWith('/') ? base.slice(0, -1) : base}${endpoint}`;
}
public async getToken(): Promise<string> {
return new Promise(async (res, rej) => {
if ( this.isOffline ) {
return rej(new ResourceNotAvailableOfflineError());
}
this.get('token').subscribe({
next: response => {
return res(response.data);
},
error: rej,
});
});
} }
public async syncOfflineData() { public async syncOfflineData() {

View File

@ -0,0 +1,139 @@
import {Injectable} from '@angular/core';
import {ApiService} from './api.service';
import {Observable} from 'rxjs';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import ApiResponse from '../structures/ApiResponse';
import {environment} from '../../environments/environment';
import {debug} from '../utility';
import * as Structures from '../structures/db-api';
@Injectable({
providedIn: 'root',
})
export class DbApiService {
protected token?: string;
protected tokenTime?: number;
protected databaseBase: string = environment.databaseBase;
constructor(
protected readonly api: ApiService,
protected readonly http: HttpClient,
) {
Structures._setDbApi(this);
}
public async getDatabase(databaseId: string): Promise<Structures.Database> {
return new Promise(async (res, rej) => {
this._authRequest(`/${databaseId}`).subscribe({
next: async response => {
if ( response.status !== 200 ) {
debug('Invalid get database response.', response);
return rej(new Error('Invalid database ID.'));
}
return res(new Structures.Database(response.data));
},
error: rej,
});
});
}
public async getDatabases(): Promise<Structures.Database[]> {
return new Promise(async (res, rej) => {
this._authRequest('/').subscribe({
next: async response => {
return res(response.data.map(x => new Structures.Database(x)));
},
error: rej,
});
});
}
public async getColumns(databaseId: string): Promise<Structures.DatabaseColumn[]> {
return new Promise(async (res, rej) => {
this._authRequest(`${databaseId}/columns`).subscribe({
next: async response => {
return res(response.data.map(x => new Structures.DatabaseColumn(x)));
},
error: rej,
});
});
}
public async getColumnOrder(databaseId: string): Promise<string[]> {
return new Promise(async (res, rej) => {
this._authRequest(`${databaseId}/columns/order`).subscribe({
next: async response => {
return res(response.data);
},
error: rej,
});
});
}
public async getData(databaseId: string): Promise<Structures.DatabaseRecord[]> {
return new Promise(async (res, rej) => {
this._authRequest(`${databaseId}/data`).subscribe({
next: async response => {
return res(response.data.map(x => new Structures.DatabaseRecord(x)));
},
error: rej,
});
});
}
public async getDataRecord(databaseId: string, recordId: string): Promise<Structures.DatabaseRecord> {
return new Promise(async (res, rej) => {
this._authRequest(`${databaseId}/record/${recordId}`).subscribe({
next: async response => {
return res(new Structures.DatabaseRecord(response.data));
},
error: rej,
});
});
}
protected _authRequest(endpoint, params = {}, method: 'get' | 'post' = 'get') {
return new Observable<ApiResponse>(sub => {
this.getToken().then(token => {
const headers = new HttpHeaders({
authorization: `bearer ${token}`
});
debug('Auth request headers', headers);
if ( method === 'get' ) {
const data = {
params,
headers,
};
this.http.get(this.api._build_url(endpoint, this.databaseBase), data).subscribe({
next: (response: any) => {
return sub.next(new ApiResponse(response));
},
error: e => {
return sub.error(e);
},
});
}
});
});
}
public async getToken(): Promise<string> {
const now = (new Date()).getTime();
// 1 hour
if ( this.token && this.tokenTime && (now - this.tokenTime) < (60 * 60 * 1000) ) {
return this.token;
}
this.token = await this.api.getToken();
this.tokenTime = now;
return this.token;
}
}

View File

@ -0,0 +1,102 @@
import {DbApiService} from '../service/db-api.service';
let privDbApi!: DbApiService;
export function _setDbApi(dbApi: DbApiService) {
privDbApi = dbApi;
}
export function _getDbApi(): DbApiService {
return privDbApi;
}
export class Database {
public name!: string;
public uuid!: string;
public pageId!: string;
public columnIds: string[] = [];
public versionNum?: number;
static async all() {
return _getDbApi().getDatabases();
}
static async one(databaseId: string) {
return _getDbApi().getDatabase(databaseId);
}
constructor(record?: any) {
if ( record ) {
this.loadFrom(record);
}
}
loadFrom(record: any) {
this.name = record.name;
this.uuid = record.uuid;
this.pageId = record.page_id;
this.columnIds = record.column_ids;
if ( record.version_num ) {
this.versionNum = record.version_num;
}
}
async columns() {
const order = await this.columnOrder();
const columns = await _getDbApi().getColumns(this.uuid);
return order.map(x => columns.find(col => col.uuid === x));
}
async columnOrder() {
return _getDbApi().getColumnOrder(this.uuid);
}
async data() {
return _getDbApi().getData(this.uuid);
}
async record(id: string) {
return _getDbApi().getDataRecord(this.uuid, id);
}
}
export class DatabaseColumn {
public name!: string;
public databaseId!: string;
public uuid!: string;
public type!: string;
public metadata: any;
constructor(record?: any) {
if ( record ) {
this.loadFrom(record);
}
}
loadFrom(record: any) {
this.name = record.name;
this.databaseId = record.database_id;
this.uuid = record.uuid;
this.type = record.type;
this.metadata = record.metadata;
}
}
export class DatabaseRecord {
public data: any = {};
public uuid!: string;
public databaseId!: string;
constructor(record?: any) {
if ( record ) {
this.loadFrom(record);
}
}
loadFrom(record: any) {
this.data = record.data;
this.uuid = record.uuid;
this.databaseId = record.database_id;
}
}

View File

@ -1,6 +1,7 @@
export const environment = { export const environment = {
production: true, production: true,
backendBase: '/api/v1', backendBase: '/api/v1',
databaseBase: '/db_api/v1',
statUrl: '/stat?ngsw-bypass', statUrl: '/stat?ngsw-bypass',
versionUrl: '/i/version.html?ngsw-bypass', versionUrl: '/i/version.html?ngsw-bypass',
outputDebug: false, outputDebug: false,

View File

@ -5,6 +5,7 @@
export const environment = { export const environment = {
production: false, production: false,
backendBase: '/link_api/api/v1', backendBase: '/link_api/api/v1',
databaseBase: '/link_api/db_api/v1',
statUrl: '/link_api/stat?ngsw-bypass', statUrl: '/link_api/stat?ngsw-bypass',
versionUrl: '/link_api/assets/version.html?ngsw-bypass', versionUrl: '/link_api/assets/version.html?ngsw-bypass',
outputDebug: true, outputDebug: true,