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): Promise> { 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> { 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 { // 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, }; } }