Skip to content

Commit

Permalink
feat: bloco: route to get imageCapa
Browse files Browse the repository at this point in the history
  • Loading branch information
guesant committed Mar 29, 2024
1 parent 146ed35 commit 69240d4
Show file tree
Hide file tree
Showing 24 changed files with 197 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { IImagemFindOneResultDto } from '../../../../base/imagem/operations';
import { ICampusFindOneResultDto } from '../../../campus';
import { IBlocoModel } from '../../IBlocoModel';

export interface IBlocoFindOneResultDto extends Pick<IBlocoModel, 'id' | 'nome' | 'codigo'> {
campus: ICampusFindOneResultDto;
imagemCapa: IImagemFindOneResultDto | null;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IAmbienteModel } from '..';
import { IDatedObject, IEntityDate, IObjectUuid } from '../../(core)';
import { IImagemModel } from '../../base/imagem';
import { ICampusModel } from '../campus';

export interface IBlocoModel extends IObjectUuid, IDatedObject {
Expand All @@ -19,6 +20,7 @@ export interface IBlocoModel extends IObjectUuid, IDatedObject {
//

ambientes: IAmbienteModel[];
imagemCapa: IImagemModel | null;

// =================================

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as Dto from 'application/business/(spec)';

export interface IImagemArquivoModel extends Dto.IObjectUuid {
id: string;

//

largura: number;
altura: number;
formato: string;
mimeType: string;

imagem: Dto.IImagemModel;
arquivo: Dto.IArquivoModel;

//

dateCreated: Dto.IEntityDate;
// dateUpdated: Dto.IEntityDate;
// dateDeleted: null | Dto.IEntityDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './IImagemArquivoModel';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as Dto from 'application/business/(spec)';
import { IArquivoFindOneResultDto } from '../../../arquivo/operations';
import { IImagemArquivoModel } from '../../IImagemArquivoModel';

export interface IImagemArquivoFindOneResultDto extends Pick<IImagemArquivoModel, 'id' | 'largura' | 'altura' | 'formato' | 'mimeType'> {
imagem: Dto.IObjectUuid;
arquivo: IArquivoFindOneResultDto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './IImagemArquivoFindOneResultDto';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './imagem-arquivo-find-one';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as Dto from 'application/business/(spec)';
import { IImagemArquivoModel } from '../imagem-arquivo';

export interface IImagemModel extends Dto.IObjectUuid, Dto.IDatedObject {
id: string;

//

descricao: string | null;
imagemArquivo: IImagemArquivoModel[];

//

dateCreated: Dto.IEntityDate;
dateUpdated: Dto.IEntityDate;
dateDeleted: null | Dto.IEntityDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './IImagemModel';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IImagemArquivoFindOneResultDto } from '../../../imagem-arquivo/operations';
import { IImagemModel } from '../../IImagemModel';

export interface IImagemFindOneResultDto extends Pick<IImagemModel, 'id' | 'descricao'> {
imagemArquivo: Omit<IImagemArquivoFindOneResultDto, 'imagem'>[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './IImagemFindOneResultDto';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './imagem-find-one';
2 changes: 2 additions & 0 deletions luna-backend/src/application/business/(spec)/base/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './arquivo';
export * from './imagem';
export * from './imagem-arquivo';
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ export class BlocoController {
return this.blocoService.blocoFindByIdStrict(contextoDeAcesso, { id });
}

@Get('/:id/imagem/capa')
@DtoOperationFindOne(BlocoOperations.BLOCO_GET_IMAGEM_CAPA)
async blocoGetImagemCapa(
@ContextoDeAcessoHttp() contextoDeAcesso: IContextoDeAcesso,
@HttpDtoParam(BlocoOperations.BLOCO_GET_IMAGEM_CAPA, 'id')
id: string,
) {
return this.blocoService.blocoGetImagemCapa(contextoDeAcesso, id);
}

//

@Post('/')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DatabaseContextService } from '../../../../infrastructure/integrate-dat
import { BlocoEntity } from '../../../../infrastructure/integrate-database/typeorm/entities/ambientes/bloco.entity';
import { paginateConfig } from '../../../../infrastructure/utils/paginateConfig';
import { IQueryBuilderViewOptionsLoad, getQueryBuilderViewLoadMeta } from '../../../utils/QueryBuilderViewOptionsLoad';
import { ArquivoService } from '../../base/arquivo/arquivo.service';
import { ImagemService } from '../../base/imagem/imagem.service';
import { CampusService, ICampusQueryBuilderViewOptions } from '../campus/campus.service';

Expand All @@ -31,6 +32,7 @@ export class BlocoService {
private campusService: CampusService,
private databaseContext: DatabaseContextService,
private imagemService: ImagemService,
private arquivoService: ArquivoService,
) {}

get blocoRepository() {
Expand Down Expand Up @@ -137,14 +139,16 @@ export class BlocoService {
return paginated;
}

async blocoFindById(contextoDeAcesso: IContextoDeAcesso, dto: Dtos.IBlocoFindOneByIdInputDto): Promise<Dtos.IBlocoFindOneResultDto | null> {
async blocoFindById(contextoDeAcesso: IContextoDeAcesso | null, dto: Dtos.IBlocoFindOneByIdInputDto): Promise<Dtos.IBlocoFindOneResultDto | null> {
// =========================================================

const qb = this.blocoRepository.createQueryBuilder(aliasBloco);

// =========================================================

await contextoDeAcesso.aplicarFiltro('bloco:find', qb, aliasBloco, null);
if (contextoDeAcesso) {
await contextoDeAcesso.aplicarFiltro('bloco:find', qb, aliasBloco, null);
}

// =========================================================

Expand All @@ -167,7 +171,7 @@ export class BlocoService {
return bloco;
}

async blocoFindByIdStrict(contextoDeAcesso: IContextoDeAcesso, dto: Dtos.IBlocoFindOneByIdInputDto) {
async blocoFindByIdStrict(contextoDeAcesso: IContextoDeAcesso | null, dto: Dtos.IBlocoFindOneByIdInputDto) {
const bloco = await this.blocoFindById(contextoDeAcesso, dto);

if (!bloco) {
Expand Down Expand Up @@ -229,6 +233,23 @@ export class BlocoService {

//

async blocoGetImagemCapa(contextoDeAcesso: IContextoDeAcesso | null, id: string) {
const bloco = await this.blocoFindByIdStrict(contextoDeAcesso, { id: id });

if (bloco.imagemCapa) {
const [imagemArquivo] = bloco.imagemCapa.imagemArquivo;

if (imagemArquivo) {
const { arquivo } = imagemArquivo;
return this.arquivoService.getStreamableFile(null, arquivo.id, null);
}
}

throw new NotFoundException();
}

//

async blocoCreate(contextoDeAcesso: IContextoDeAcesso, dto: Dtos.IBlocoInputDto) {
// =========================================================

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { InputType, ObjectType } from '@nestjs/graphql';
import * as yup from 'yup';
import * as Dto from '../../../(spec)';
import { IImagemFindOneResultDto } from '../../../(spec)/base/imagem/operations';
import { DtoProperty, ValidationContractUuid, createDtoOperationOptions, createValidationContract, getSchemaField } from '../../../../../infrastructure';
import { BlocoDto, BlocoDtoProperties, BlocoDtoValidationContract } from './bloco.dto';

Expand All @@ -21,6 +22,9 @@ export class BlocoFindOneResultDto implements Dto.IBlocoFindOneResultDto {
//
@DtoProperty(BlocoDtoProperties.BLOCO_CAMPUS_OUTPUT)
campus!: Dto.ICampusFindOneResultDto;

//
imagemCapa!: IImagemFindOneResultDto | null;
}

// ======================================================
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ValidationContractUuid, createDtoOperationOptions } from '../../../../../infrastructure';

// ======================================================

export const BLOCO_GET_IMAGEM_CAPA = createDtoOperationOptions({
description: 'Realiza a consulta a um bloco por ID.',

gql: null,

swagger: {
returnType: {
schema: {
type: 'string',
format: 'binary',
},
},

params: [
{
name: 'id',
description: 'ID do bloco.',
validationContract: ValidationContractUuid,
},
],
},
});

// ======================================================
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ObjectType } from '@nestjs/graphql';
import * as yup from 'yup';
import * as Dto from '../../../(spec)';
import { IImagemModel } from '../../../(spec)/base/imagem';
import {
CommonPropertyUuid,
DtoProperty,
Expand Down Expand Up @@ -103,6 +104,7 @@ export class BlocoDto implements Dto.IBlocoModel {
//

ambientes!: Dto.IAmbienteModel[];
imagemCapa!: IImagemModel | null;

//

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { BLOCO_CREATE } from './bloco-create.operation';
import { BLOCO_DELETE_ONE_BY_ID } from './bloco-delete-one.operation';
import { BLOCO_FIND_ALL } from './bloco-find-all.operation';
import { BLOCO_FIND_ONE_BY_ID } from './bloco-find-one.operation';
import { BLOCO_GET_IMAGEM_CAPA } from './bloco-get-imagem-capa.operation';
import { BLOCO_UPDATE } from './bloco-update.operation';

export const BlocoOperations = {
// ===============================
BLOCO_FIND_ALL: BLOCO_FIND_ALL,
// ===============================
BLOCO_FIND_ONE_BY_ID: BLOCO_FIND_ONE_BY_ID,
BLOCO_GET_IMAGEM_CAPA: BLOCO_GET_IMAGEM_CAPA,
// ===============================
BLOCO_CREATE: BLOCO_CREATE,
// ===============================
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Controller, Get, Res, ServiceUnavailableException, StreamableFile } from '@nestjs/common';
import { Controller, Get, StreamableFile } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { IContextoDeAcesso } from '../../../../domain';
import { ContextoDeAcessoHttp, DtoOperationFindOne, HttpDtoParam } from '../../../../infrastructure';
import { HttpDtoQuery } from '../../../../infrastructure/api-documentate/HttpDtoQuery';
Expand All @@ -15,26 +14,14 @@ export class ArquivoController {
@Get(':id')
@DtoOperationFindOne(ArquivoOperations.ARQUIVO_GET_FILE)
async getFile(
@Res({ passthrough: true }) res: Response,
@ContextoDeAcessoHttp() contextoDeAcesso: IContextoDeAcesso,
@HttpDtoParam(ArquivoOperations.ARQUIVO_GET_FILE, 'id') id: string,
@HttpDtoQuery(ArquivoOperations.ARQUIVO_GET_FILE, 'acesso.recurso.nome') acessoRecursoNome: string,
@HttpDtoQuery(ArquivoOperations.ARQUIVO_GET_FILE, 'acesso.recurso.id') acessoRecursoId: string,
): Promise<StreamableFile> {
const file = await this.arquivoService.getFile(contextoDeAcesso, id, {
return this.arquivoService.getStreamableFile(contextoDeAcesso, id, {
id: acessoRecursoId,
nome: acessoRecursoNome,
});

if (!file.stream) {
throw new ServiceUnavailableException();
}

res.set({
'Content-Type': file.mimeType,
'Content-Disposition': `attachment; filename="${encodeURIComponent(file.nome ?? file.id)}"`,
});

return new StreamableFile(file.stream);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ForbiddenException, Injectable, NotFoundException, ServiceUnavailableException } from '@nestjs/common';
import { ForbiddenException, Injectable, NotFoundException, ServiceUnavailableException, StreamableFile } from '@nestjs/common';
import jetpack, { createReadStream } from 'fs-jetpack';
import { writeFile } from 'node:fs/promises';
import { Readable } from 'node:stream';
Expand Down Expand Up @@ -38,7 +38,7 @@ export class ArquivoService {
return jetpack.exists(fileFullPath);
}

async dataReadAsStream(id: Dto.IArquivoModel['id']) {
async dataReadAsStream(id: Dto.IArquivoModel['id']): Promise<Readable | null> {
if (await this.dataExists(id)) {
const fileFullPath = this.datGetFilePath(id);
const fileReadStream = createReadStream(fileFullPath);
Expand All @@ -48,7 +48,7 @@ export class ArquivoService {
return null;
}

async getFile(contextoDeAcesso: IContextoDeAcesso, id: Dto.IArquivoModel['id'], acesso: IGetFileAcesso | null) {
async getFile(contextoDeAcesso: IContextoDeAcesso | null, id: Dto.IArquivoModel['id'], acesso: IGetFileAcesso | null) {
const qb = this.arquivoRepository.createQueryBuilder('arquivo');

qb.whereInIds([id]);
Expand All @@ -71,7 +71,9 @@ export class ArquivoService {
qb.andWhere('blocoCapa.id = :blocoCapa', { blocoCapa: acesso.id });
}

await contextoDeAcesso.aplicarFiltro('bloco:find', qb, 'blocoCapa', null);
if (contextoDeAcesso) {
await contextoDeAcesso.aplicarFiltro('bloco:find', qb, 'blocoCapa', null);
}
} else {
qb.andWhere('FALSE');
}
Expand All @@ -97,6 +99,19 @@ export class ArquivoService {
};
}

async getStreamableFile(contextoDeAcesso: IContextoDeAcesso | null, id: Dto.IArquivoModel['id'], acesso: IGetFileAcesso | null) {
const file = await this.getFile(contextoDeAcesso, id, acesso);

if (!file.stream) {
throw new ServiceUnavailableException();
}

return new StreamableFile(file.stream, {
type: file.mimeType ?? undefined,
disposition: `attachment; filename="${encodeURIComponent(file.nome ?? file.id)}"`,
});
}

async dataSave(id: Dto.IArquivoModel['id'], data: NodeJS.ArrayBufferView | Readable) {
const fileFullPath = this.datGetFilePath(id);
await writeFile(fileFullPath, data);
Expand Down
Loading

0 comments on commit 69240d4

Please sign in to comment.