156 lines
4.5 KiB
TypeScript
156 lines
4.5 KiB
TypeScript
import {
|
|
Interior,
|
|
InteriorsFilter,
|
|
InteriorType,
|
|
} from '../types/interior-types';
|
|
import { Orientation } from '../types/product-types';
|
|
import { IdNumberResult, Maybe } from '../types/types';
|
|
import { BaseSQLDataSource } from './BaseSQLDataSource';
|
|
import { ImageServerApi } from './imageserver-api';
|
|
import * as CONFIG from '../config';
|
|
import { moveS3File } from '../s3';
|
|
|
|
const MINUTE = 60;
|
|
|
|
export class InteriorAPI extends BaseSQLDataSource {
|
|
imageServerApi: ImageServerApi;
|
|
constructor(config, imageServerApi: ImageServerApi) {
|
|
super(config);
|
|
this.imageServerApi = imageServerApi;
|
|
}
|
|
|
|
getInteriorType(roomTypePart: string): string {
|
|
switch (roomTypePart) {
|
|
case 'wallpaper':
|
|
return InteriorType[InteriorType.WALLPAPER];
|
|
case 'painting':
|
|
return InteriorType[InteriorType.PAINTING];
|
|
case 'poster':
|
|
return InteriorType[InteriorType.POSTER];
|
|
case 'framed-print':
|
|
return InteriorType[InteriorType.FRAMED_PRINT];
|
|
default:
|
|
throw new Error(`Unknown room type: ${roomTypePart}`);
|
|
}
|
|
}
|
|
|
|
getInteriorOrientation(roomOrientationPart: string): string {
|
|
switch (roomOrientationPart) {
|
|
case 'landscape':
|
|
return Orientation[Orientation.LANDSCAPE];
|
|
case 'standing':
|
|
return Orientation[Orientation.STANDING];
|
|
case 'square':
|
|
return Orientation[Orientation.SQUARE];
|
|
default:
|
|
throw new Error(`Unknown room orientation: ${roomOrientationPart}`);
|
|
}
|
|
}
|
|
|
|
getInteriorRoomNumber(roomNumberPart: string): number {
|
|
return parseInt(roomNumberPart.slice(4), 10);
|
|
}
|
|
|
|
decorateRow(row: any): Interior {
|
|
if (row.roomName) {
|
|
const parts = row.roomName.split('_');
|
|
row.roomNumber = this.getInteriorRoomNumber(parts[0]);
|
|
row.type = this.getInteriorType(parts[1]);
|
|
row.orientation = this.getInteriorOrientation(parts[2]);
|
|
}
|
|
return row;
|
|
}
|
|
|
|
async getInteriors(filter: Maybe<InteriorsFilter>): Promise<Array<Interior>> {
|
|
const sql = /* sql */ `
|
|
SELECT rooms.*, room_types.name roomType FROM rooms
|
|
LEFT JOIN room_types ON rooms.room_type_id = room_types.id
|
|
`;
|
|
|
|
const allInteriors = await this.cachedRaw(sql)
|
|
.cache(MINUTE * 60)
|
|
.then((data) =>
|
|
data.rows.map((row) => {
|
|
const res = {
|
|
...row,
|
|
roomName: row.name,
|
|
roomType: row.roomtype,
|
|
id: row.s3_suffix,
|
|
};
|
|
this.decorateRow(res);
|
|
return res;
|
|
}),
|
|
);
|
|
|
|
// Based on filter get valid interiors and filter out any else from all interiors
|
|
if (filter) {
|
|
const validUris = await this.imageServerApi.getInteriorsForProduct(
|
|
filter.productId,
|
|
);
|
|
return allInteriors.filter((i: Interior) => {
|
|
const it = i.type.toString().replace('_', '-').toLowerCase();
|
|
const or = i.orientation.toString().toLocaleLowerCase();
|
|
const uriMatch = `${or}/${it}/room${i.roomNumber}.`;
|
|
const foundUri = validUris.find(({ uri }) => uri.includes(uriMatch));
|
|
if (foundUri) {
|
|
i.uri = foundUri.uri;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
// No filter so return all
|
|
return allInteriors;
|
|
}
|
|
|
|
async getPrintProductInteriors(printId: number): Promise<Array<Interior>> {
|
|
return this.knex
|
|
.select('*')
|
|
.from('v_interior_image_urls')
|
|
.orderBy('position')
|
|
.where('print_id', printId)
|
|
.cache(MINUTE)
|
|
.then((rows) => {
|
|
return rows.map((row) => {
|
|
const res = {
|
|
...row,
|
|
id: row.uri,
|
|
};
|
|
this.decorateRow(res);
|
|
return res;
|
|
});
|
|
});
|
|
}
|
|
|
|
// Mutations
|
|
async addOwnUploadToPrintId(
|
|
printId: number,
|
|
uploadedS3Key: string,
|
|
): Promise<IdNumberResult> {
|
|
// Get the last position entered in interiors for this printId
|
|
const positionRes: any = await this.knex
|
|
.queryBuilder()
|
|
.from('interiors')
|
|
.where({ print_id: printId })
|
|
.max('position')
|
|
.first();
|
|
const position = positionRes.max === null ? 0 : positionRes.max + 1;
|
|
|
|
// Insert the printId in interiors returning the id (important as it is used as image key name)
|
|
const res = await this.knex('interiors')
|
|
.insert({ print_id: printId, position: position })
|
|
.returning('id');
|
|
const interiorId = res[0];
|
|
// Move file
|
|
moveS3File(
|
|
CONFIG.uploadBucket,
|
|
uploadedS3Key,
|
|
CONFIG.imageBucket,
|
|
`interior-images/${interiorId}.jpg`,
|
|
);
|
|
return {
|
|
id: interiorId,
|
|
};
|
|
}
|
|
}
|