feat: refactor storage module (#521)
* feat: refactor storage module * fix: folder need to be kebab case * fix: comment wrong auth
This commit is contained in:
@ -9,8 +9,8 @@ export class CreateManyCommentThreadTargetArgs {
|
|||||||
|
|
||||||
@Field(() => [CommentThreadTargetCreateManyInput], {nullable:false})
|
@Field(() => [CommentThreadTargetCreateManyInput], {nullable:false})
|
||||||
@Type(() => CommentThreadTargetCreateManyInput)
|
@Type(() => CommentThreadTargetCreateManyInput)
|
||||||
@Type(() => CommentThreadTargetCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadTargetCreateManyInput)
|
||||||
data!: Array<CommentThreadTargetCreateManyInput>;
|
data!: Array<CommentThreadTargetCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneCommentThreadTargetArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadTargetCreateInput, {nullable:false})
|
@Field(() => CommentThreadTargetCreateInput, {nullable:false})
|
||||||
@Type(() => CommentThreadTargetCreateInput)
|
@Type(() => CommentThreadTargetCreateInput)
|
||||||
@Type(() => CommentThreadTargetCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadTargetCreateInput)
|
||||||
data!: CommentThreadTargetCreateInput;
|
data!: CommentThreadTargetCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyCommentThreadTargetArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadTargetUpdateManyMutationInput, {nullable:false})
|
@Field(() => CommentThreadTargetUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => CommentThreadTargetUpdateManyMutationInput)
|
@Type(() => CommentThreadTargetUpdateManyMutationInput)
|
||||||
@Type(() => CommentThreadTargetUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadTargetUpdateManyMutationInput)
|
||||||
data!: CommentThreadTargetUpdateManyMutationInput;
|
data!: CommentThreadTargetUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => CommentThreadTargetWhereInput, {nullable:true})
|
@Field(() => CommentThreadTargetWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneCommentThreadTargetArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadTargetUpdateInput, {nullable:false})
|
@Field(() => CommentThreadTargetUpdateInput, {nullable:false})
|
||||||
@Type(() => CommentThreadTargetUpdateInput)
|
@Type(() => CommentThreadTargetUpdateInput)
|
||||||
@Type(() => CommentThreadTargetUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadTargetUpdateInput)
|
||||||
data!: CommentThreadTargetUpdateInput;
|
data!: CommentThreadTargetUpdateInput;
|
||||||
|
|
||||||
@Field(() => CommentThreadTargetWhereUniqueInput, {nullable:false})
|
@Field(() => CommentThreadTargetWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyCommentThreadArgs {
|
|||||||
|
|
||||||
@Field(() => [CommentThreadCreateManyInput], {nullable:false})
|
@Field(() => [CommentThreadCreateManyInput], {nullable:false})
|
||||||
@Type(() => CommentThreadCreateManyInput)
|
@Type(() => CommentThreadCreateManyInput)
|
||||||
@Type(() => CommentThreadCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadCreateManyInput)
|
||||||
data!: Array<CommentThreadCreateManyInput>;
|
data!: Array<CommentThreadCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneCommentThreadArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadCreateInput, {nullable:false})
|
@Field(() => CommentThreadCreateInput, {nullable:false})
|
||||||
@Type(() => CommentThreadCreateInput)
|
@Type(() => CommentThreadCreateInput)
|
||||||
@Type(() => CommentThreadCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadCreateInput)
|
||||||
data!: CommentThreadCreateInput;
|
data!: CommentThreadCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyCommentThreadArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadUpdateManyMutationInput, {nullable:false})
|
@Field(() => CommentThreadUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => CommentThreadUpdateManyMutationInput)
|
@Type(() => CommentThreadUpdateManyMutationInput)
|
||||||
@Type(() => CommentThreadUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadUpdateManyMutationInput)
|
||||||
data!: CommentThreadUpdateManyMutationInput;
|
data!: CommentThreadUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => CommentThreadWhereInput, {nullable:true})
|
@Field(() => CommentThreadWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneCommentThreadArgs {
|
|||||||
|
|
||||||
@Field(() => CommentThreadUpdateInput, {nullable:false})
|
@Field(() => CommentThreadUpdateInput, {nullable:false})
|
||||||
@Type(() => CommentThreadUpdateInput)
|
@Type(() => CommentThreadUpdateInput)
|
||||||
@Type(() => CommentThreadUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentThreadUpdateInput)
|
||||||
data!: CommentThreadUpdateInput;
|
data!: CommentThreadUpdateInput;
|
||||||
|
|
||||||
@Field(() => CommentThreadWhereUniqueInput, {nullable:false})
|
@Field(() => CommentThreadWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyCommentArgs {
|
|||||||
|
|
||||||
@Field(() => [CommentCreateManyInput], {nullable:false})
|
@Field(() => [CommentCreateManyInput], {nullable:false})
|
||||||
@Type(() => CommentCreateManyInput)
|
@Type(() => CommentCreateManyInput)
|
||||||
@Type(() => CommentCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentCreateManyInput)
|
||||||
data!: Array<CommentCreateManyInput>;
|
data!: Array<CommentCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneCommentArgs {
|
|||||||
|
|
||||||
@Field(() => CommentCreateInput, {nullable:false})
|
@Field(() => CommentCreateInput, {nullable:false})
|
||||||
@Type(() => CommentCreateInput)
|
@Type(() => CommentCreateInput)
|
||||||
@Type(() => CommentCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentCreateInput)
|
||||||
data!: CommentCreateInput;
|
data!: CommentCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyCommentArgs {
|
|||||||
|
|
||||||
@Field(() => CommentUpdateManyMutationInput, {nullable:false})
|
@Field(() => CommentUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => CommentUpdateManyMutationInput)
|
@Type(() => CommentUpdateManyMutationInput)
|
||||||
@Type(() => CommentUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentUpdateManyMutationInput)
|
||||||
data!: CommentUpdateManyMutationInput;
|
data!: CommentUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => CommentWhereInput, {nullable:true})
|
@Field(() => CommentWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneCommentArgs {
|
|||||||
|
|
||||||
@Field(() => CommentUpdateInput, {nullable:false})
|
@Field(() => CommentUpdateInput, {nullable:false})
|
||||||
@Type(() => CommentUpdateInput)
|
@Type(() => CommentUpdateInput)
|
||||||
@Type(() => CommentUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CommentUpdateInput)
|
||||||
data!: CommentUpdateInput;
|
data!: CommentUpdateInput;
|
||||||
|
|
||||||
@Field(() => CommentWhereUniqueInput, {nullable:false})
|
@Field(() => CommentWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyCompanyArgs {
|
|||||||
|
|
||||||
@Field(() => [CompanyCreateManyInput], {nullable:false})
|
@Field(() => [CompanyCreateManyInput], {nullable:false})
|
||||||
@Type(() => CompanyCreateManyInput)
|
@Type(() => CompanyCreateManyInput)
|
||||||
@Type(() => CompanyCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CompanyCreateManyInput)
|
||||||
data!: Array<CompanyCreateManyInput>;
|
data!: Array<CompanyCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneCompanyArgs {
|
|||||||
|
|
||||||
@Field(() => CompanyCreateInput, {nullable:false})
|
@Field(() => CompanyCreateInput, {nullable:false})
|
||||||
@Type(() => CompanyCreateInput)
|
@Type(() => CompanyCreateInput)
|
||||||
@Type(() => CompanyCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CompanyCreateInput)
|
||||||
data!: CompanyCreateInput;
|
data!: CompanyCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyCompanyArgs {
|
|||||||
|
|
||||||
@Field(() => CompanyUpdateManyMutationInput, {nullable:false})
|
@Field(() => CompanyUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => CompanyUpdateManyMutationInput)
|
@Type(() => CompanyUpdateManyMutationInput)
|
||||||
@Type(() => CompanyUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CompanyUpdateManyMutationInput)
|
||||||
data!: CompanyUpdateManyMutationInput;
|
data!: CompanyUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => CompanyWhereInput, {nullable:true})
|
@Field(() => CompanyWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneCompanyArgs {
|
|||||||
|
|
||||||
@Field(() => CompanyUpdateInput, {nullable:false})
|
@Field(() => CompanyUpdateInput, {nullable:false})
|
||||||
@Type(() => CompanyUpdateInput)
|
@Type(() => CompanyUpdateInput)
|
||||||
@Type(() => CompanyUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => CompanyUpdateInput)
|
||||||
data!: CompanyUpdateInput;
|
data!: CompanyUpdateInput;
|
||||||
|
|
||||||
@Field(() => CompanyWhereUniqueInput, {nullable:false})
|
@Field(() => CompanyWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyPersonArgs {
|
|||||||
|
|
||||||
@Field(() => [PersonCreateManyInput], {nullable:false})
|
@Field(() => [PersonCreateManyInput], {nullable:false})
|
||||||
@Type(() => PersonCreateManyInput)
|
@Type(() => PersonCreateManyInput)
|
||||||
@Type(() => PersonCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PersonCreateManyInput)
|
||||||
data!: Array<PersonCreateManyInput>;
|
data!: Array<PersonCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOnePersonArgs {
|
|||||||
|
|
||||||
@Field(() => PersonCreateInput, {nullable:false})
|
@Field(() => PersonCreateInput, {nullable:false})
|
||||||
@Type(() => PersonCreateInput)
|
@Type(() => PersonCreateInput)
|
||||||
@Type(() => PersonCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PersonCreateInput)
|
||||||
data!: PersonCreateInput;
|
data!: PersonCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyPersonArgs {
|
|||||||
|
|
||||||
@Field(() => PersonUpdateManyMutationInput, {nullable:false})
|
@Field(() => PersonUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => PersonUpdateManyMutationInput)
|
@Type(() => PersonUpdateManyMutationInput)
|
||||||
@Type(() => PersonUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PersonUpdateManyMutationInput)
|
||||||
data!: PersonUpdateManyMutationInput;
|
data!: PersonUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => PersonWhereInput, {nullable:true})
|
@Field(() => PersonWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOnePersonArgs {
|
|||||||
|
|
||||||
@Field(() => PersonUpdateInput, {nullable:false})
|
@Field(() => PersonUpdateInput, {nullable:false})
|
||||||
@Type(() => PersonUpdateInput)
|
@Type(() => PersonUpdateInput)
|
||||||
@Type(() => PersonUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PersonUpdateInput)
|
||||||
data!: PersonUpdateInput;
|
data!: PersonUpdateInput;
|
||||||
|
|
||||||
@Field(() => PersonWhereUniqueInput, {nullable:false})
|
@Field(() => PersonWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyPipelineProgressArgs {
|
|||||||
|
|
||||||
@Field(() => [PipelineProgressCreateManyInput], {nullable:false})
|
@Field(() => [PipelineProgressCreateManyInput], {nullable:false})
|
||||||
@Type(() => PipelineProgressCreateManyInput)
|
@Type(() => PipelineProgressCreateManyInput)
|
||||||
@Type(() => PipelineProgressCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineProgressCreateManyInput)
|
||||||
data!: Array<PipelineProgressCreateManyInput>;
|
data!: Array<PipelineProgressCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOnePipelineProgressArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineProgressCreateInput, {nullable:false})
|
@Field(() => PipelineProgressCreateInput, {nullable:false})
|
||||||
@Type(() => PipelineProgressCreateInput)
|
@Type(() => PipelineProgressCreateInput)
|
||||||
@Type(() => PipelineProgressCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineProgressCreateInput)
|
||||||
data!: PipelineProgressCreateInput;
|
data!: PipelineProgressCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyPipelineProgressArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineProgressUpdateManyMutationInput, {nullable:false})
|
@Field(() => PipelineProgressUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => PipelineProgressUpdateManyMutationInput)
|
@Type(() => PipelineProgressUpdateManyMutationInput)
|
||||||
@Type(() => PipelineProgressUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineProgressUpdateManyMutationInput)
|
||||||
data!: PipelineProgressUpdateManyMutationInput;
|
data!: PipelineProgressUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => PipelineProgressWhereInput, {nullable:true})
|
@Field(() => PipelineProgressWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOnePipelineProgressArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineProgressUpdateInput, {nullable:false})
|
@Field(() => PipelineProgressUpdateInput, {nullable:false})
|
||||||
@Type(() => PipelineProgressUpdateInput)
|
@Type(() => PipelineProgressUpdateInput)
|
||||||
@Type(() => PipelineProgressUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineProgressUpdateInput)
|
||||||
data!: PipelineProgressUpdateInput;
|
data!: PipelineProgressUpdateInput;
|
||||||
|
|
||||||
@Field(() => PipelineProgressWhereUniqueInput, {nullable:false})
|
@Field(() => PipelineProgressWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyPipelineStageArgs {
|
|||||||
|
|
||||||
@Field(() => [PipelineStageCreateManyInput], {nullable:false})
|
@Field(() => [PipelineStageCreateManyInput], {nullable:false})
|
||||||
@Type(() => PipelineStageCreateManyInput)
|
@Type(() => PipelineStageCreateManyInput)
|
||||||
@Type(() => PipelineStageCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineStageCreateManyInput)
|
||||||
data!: Array<PipelineStageCreateManyInput>;
|
data!: Array<PipelineStageCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOnePipelineStageArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineStageCreateInput, {nullable:false})
|
@Field(() => PipelineStageCreateInput, {nullable:false})
|
||||||
@Type(() => PipelineStageCreateInput)
|
@Type(() => PipelineStageCreateInput)
|
||||||
@Type(() => PipelineStageCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineStageCreateInput)
|
||||||
data!: PipelineStageCreateInput;
|
data!: PipelineStageCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyPipelineStageArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineStageUpdateManyMutationInput, {nullable:false})
|
@Field(() => PipelineStageUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => PipelineStageUpdateManyMutationInput)
|
@Type(() => PipelineStageUpdateManyMutationInput)
|
||||||
@Type(() => PipelineStageUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineStageUpdateManyMutationInput)
|
||||||
data!: PipelineStageUpdateManyMutationInput;
|
data!: PipelineStageUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => PipelineStageWhereInput, {nullable:true})
|
@Field(() => PipelineStageWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOnePipelineStageArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineStageUpdateInput, {nullable:false})
|
@Field(() => PipelineStageUpdateInput, {nullable:false})
|
||||||
@Type(() => PipelineStageUpdateInput)
|
@Type(() => PipelineStageUpdateInput)
|
||||||
@Type(() => PipelineStageUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineStageUpdateInput)
|
||||||
data!: PipelineStageUpdateInput;
|
data!: PipelineStageUpdateInput;
|
||||||
|
|
||||||
@Field(() => PipelineStageWhereUniqueInput, {nullable:false})
|
@Field(() => PipelineStageWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyPipelineArgs {
|
|||||||
|
|
||||||
@Field(() => [PipelineCreateManyInput], {nullable:false})
|
@Field(() => [PipelineCreateManyInput], {nullable:false})
|
||||||
@Type(() => PipelineCreateManyInput)
|
@Type(() => PipelineCreateManyInput)
|
||||||
@Type(() => PipelineCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineCreateManyInput)
|
||||||
data!: Array<PipelineCreateManyInput>;
|
data!: Array<PipelineCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOnePipelineArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineCreateInput, {nullable:false})
|
@Field(() => PipelineCreateInput, {nullable:false})
|
||||||
@Type(() => PipelineCreateInput)
|
@Type(() => PipelineCreateInput)
|
||||||
@Type(() => PipelineCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineCreateInput)
|
||||||
data!: PipelineCreateInput;
|
data!: PipelineCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyPipelineArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineUpdateManyMutationInput, {nullable:false})
|
@Field(() => PipelineUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => PipelineUpdateManyMutationInput)
|
@Type(() => PipelineUpdateManyMutationInput)
|
||||||
@Type(() => PipelineUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineUpdateManyMutationInput)
|
||||||
data!: PipelineUpdateManyMutationInput;
|
data!: PipelineUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => PipelineWhereInput, {nullable:true})
|
@Field(() => PipelineWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOnePipelineArgs {
|
|||||||
|
|
||||||
@Field(() => PipelineUpdateInput, {nullable:false})
|
@Field(() => PipelineUpdateInput, {nullable:false})
|
||||||
@Type(() => PipelineUpdateInput)
|
@Type(() => PipelineUpdateInput)
|
||||||
@Type(() => PipelineUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => PipelineUpdateInput)
|
||||||
data!: PipelineUpdateInput;
|
data!: PipelineUpdateInput;
|
||||||
|
|
||||||
@Field(() => PipelineWhereUniqueInput, {nullable:false})
|
@Field(() => PipelineWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyRefreshTokenArgs {
|
|||||||
|
|
||||||
@Field(() => [RefreshTokenCreateManyInput], {nullable:false})
|
@Field(() => [RefreshTokenCreateManyInput], {nullable:false})
|
||||||
@Type(() => RefreshTokenCreateManyInput)
|
@Type(() => RefreshTokenCreateManyInput)
|
||||||
@Type(() => RefreshTokenCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => RefreshTokenCreateManyInput)
|
||||||
data!: Array<RefreshTokenCreateManyInput>;
|
data!: Array<RefreshTokenCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneRefreshTokenArgs {
|
|||||||
|
|
||||||
@Field(() => RefreshTokenCreateInput, {nullable:false})
|
@Field(() => RefreshTokenCreateInput, {nullable:false})
|
||||||
@Type(() => RefreshTokenCreateInput)
|
@Type(() => RefreshTokenCreateInput)
|
||||||
@Type(() => RefreshTokenCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => RefreshTokenCreateInput)
|
||||||
data!: RefreshTokenCreateInput;
|
data!: RefreshTokenCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyRefreshTokenArgs {
|
|||||||
|
|
||||||
@Field(() => RefreshTokenUpdateManyMutationInput, {nullable:false})
|
@Field(() => RefreshTokenUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => RefreshTokenUpdateManyMutationInput)
|
@Type(() => RefreshTokenUpdateManyMutationInput)
|
||||||
@Type(() => RefreshTokenUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => RefreshTokenUpdateManyMutationInput)
|
||||||
data!: RefreshTokenUpdateManyMutationInput;
|
data!: RefreshTokenUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => RefreshTokenWhereInput, {nullable:true})
|
@Field(() => RefreshTokenWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneRefreshTokenArgs {
|
|||||||
|
|
||||||
@Field(() => RefreshTokenUpdateInput, {nullable:false})
|
@Field(() => RefreshTokenUpdateInput, {nullable:false})
|
||||||
@Type(() => RefreshTokenUpdateInput)
|
@Type(() => RefreshTokenUpdateInput)
|
||||||
@Type(() => RefreshTokenUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => RefreshTokenUpdateInput)
|
||||||
data!: RefreshTokenUpdateInput;
|
data!: RefreshTokenUpdateInput;
|
||||||
|
|
||||||
@Field(() => RefreshTokenWhereUniqueInput, {nullable:false})
|
@Field(() => RefreshTokenWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyUserArgs {
|
|||||||
|
|
||||||
@Field(() => [UserCreateManyInput], {nullable:false})
|
@Field(() => [UserCreateManyInput], {nullable:false})
|
||||||
@Type(() => UserCreateManyInput)
|
@Type(() => UserCreateManyInput)
|
||||||
@Type(() => UserCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => UserCreateManyInput)
|
||||||
data!: Array<UserCreateManyInput>;
|
data!: Array<UserCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneUserArgs {
|
|||||||
|
|
||||||
@Field(() => UserCreateInput, {nullable:false})
|
@Field(() => UserCreateInput, {nullable:false})
|
||||||
@Type(() => UserCreateInput)
|
@Type(() => UserCreateInput)
|
||||||
@Type(() => UserCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => UserCreateInput)
|
||||||
data!: UserCreateInput;
|
data!: UserCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyUserArgs {
|
|||||||
|
|
||||||
@Field(() => UserUpdateManyMutationInput, {nullable:false})
|
@Field(() => UserUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => UserUpdateManyMutationInput)
|
@Type(() => UserUpdateManyMutationInput)
|
||||||
@Type(() => UserUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => UserUpdateManyMutationInput)
|
||||||
data!: UserUpdateManyMutationInput;
|
data!: UserUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => UserWhereInput, {nullable:true})
|
@Field(() => UserWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneUserArgs {
|
|||||||
|
|
||||||
@Field(() => UserUpdateInput, {nullable:false})
|
@Field(() => UserUpdateInput, {nullable:false})
|
||||||
@Type(() => UserUpdateInput)
|
@Type(() => UserUpdateInput)
|
||||||
@Type(() => UserUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => UserUpdateInput)
|
||||||
data!: UserUpdateInput;
|
data!: UserUpdateInput;
|
||||||
|
|
||||||
@Field(() => UserWhereUniqueInput, {nullable:false})
|
@Field(() => UserWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyWorkspaceMemberArgs {
|
|||||||
|
|
||||||
@Field(() => [WorkspaceMemberCreateManyInput], {nullable:false})
|
@Field(() => [WorkspaceMemberCreateManyInput], {nullable:false})
|
||||||
@Type(() => WorkspaceMemberCreateManyInput)
|
@Type(() => WorkspaceMemberCreateManyInput)
|
||||||
@Type(() => WorkspaceMemberCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceMemberCreateManyInput)
|
||||||
data!: Array<WorkspaceMemberCreateManyInput>;
|
data!: Array<WorkspaceMemberCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneWorkspaceMemberArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceMemberCreateInput, {nullable:false})
|
@Field(() => WorkspaceMemberCreateInput, {nullable:false})
|
||||||
@Type(() => WorkspaceMemberCreateInput)
|
@Type(() => WorkspaceMemberCreateInput)
|
||||||
@Type(() => WorkspaceMemberCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceMemberCreateInput)
|
||||||
data!: WorkspaceMemberCreateInput;
|
data!: WorkspaceMemberCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyWorkspaceMemberArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceMemberUpdateManyMutationInput, {nullable:false})
|
@Field(() => WorkspaceMemberUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => WorkspaceMemberUpdateManyMutationInput)
|
@Type(() => WorkspaceMemberUpdateManyMutationInput)
|
||||||
@Type(() => WorkspaceMemberUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceMemberUpdateManyMutationInput)
|
||||||
data!: WorkspaceMemberUpdateManyMutationInput;
|
data!: WorkspaceMemberUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => WorkspaceMemberWhereInput, {nullable:true})
|
@Field(() => WorkspaceMemberWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneWorkspaceMemberArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceMemberUpdateInput, {nullable:false})
|
@Field(() => WorkspaceMemberUpdateInput, {nullable:false})
|
||||||
@Type(() => WorkspaceMemberUpdateInput)
|
@Type(() => WorkspaceMemberUpdateInput)
|
||||||
@Type(() => WorkspaceMemberUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceMemberUpdateInput)
|
||||||
data!: WorkspaceMemberUpdateInput;
|
data!: WorkspaceMemberUpdateInput;
|
||||||
|
|
||||||
@Field(() => WorkspaceMemberWhereUniqueInput, {nullable:false})
|
@Field(() => WorkspaceMemberWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -9,8 +9,8 @@ export class CreateManyWorkspaceArgs {
|
|||||||
|
|
||||||
@Field(() => [WorkspaceCreateManyInput], {nullable:false})
|
@Field(() => [WorkspaceCreateManyInput], {nullable:false})
|
||||||
@Type(() => WorkspaceCreateManyInput)
|
@Type(() => WorkspaceCreateManyInput)
|
||||||
@Type(() => WorkspaceCreateManyInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceCreateManyInput)
|
||||||
data!: Array<WorkspaceCreateManyInput>;
|
data!: Array<WorkspaceCreateManyInput>;
|
||||||
|
|
||||||
@Field(() => Boolean, {nullable:true})
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export class CreateOneWorkspaceArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceCreateInput, {nullable:false})
|
@Field(() => WorkspaceCreateInput, {nullable:false})
|
||||||
@Type(() => WorkspaceCreateInput)
|
@Type(() => WorkspaceCreateInput)
|
||||||
@Type(() => WorkspaceCreateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceCreateInput)
|
||||||
data!: WorkspaceCreateInput;
|
data!: WorkspaceCreateInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateManyWorkspaceArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceUpdateManyMutationInput, {nullable:false})
|
@Field(() => WorkspaceUpdateManyMutationInput, {nullable:false})
|
||||||
@Type(() => WorkspaceUpdateManyMutationInput)
|
@Type(() => WorkspaceUpdateManyMutationInput)
|
||||||
@Type(() => WorkspaceUpdateManyMutationInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceUpdateManyMutationInput)
|
||||||
data!: WorkspaceUpdateManyMutationInput;
|
data!: WorkspaceUpdateManyMutationInput;
|
||||||
|
|
||||||
@Field(() => WorkspaceWhereInput, {nullable:true})
|
@Field(() => WorkspaceWhereInput, {nullable:true})
|
||||||
|
|||||||
@ -10,8 +10,8 @@ export class UpdateOneWorkspaceArgs {
|
|||||||
|
|
||||||
@Field(() => WorkspaceUpdateInput, {nullable:false})
|
@Field(() => WorkspaceUpdateInput, {nullable:false})
|
||||||
@Type(() => WorkspaceUpdateInput)
|
@Type(() => WorkspaceUpdateInput)
|
||||||
@Type(() => WorkspaceUpdateInput)
|
|
||||||
@ValidateNested({each: true})
|
@ValidateNested({each: true})
|
||||||
|
@Type(() => WorkspaceUpdateInput)
|
||||||
data!: WorkspaceUpdateInput;
|
data!: WorkspaceUpdateInput;
|
||||||
|
|
||||||
@Field(() => WorkspaceWhereUniqueInput, {nullable:false})
|
@Field(() => WorkspaceWhereUniqueInput, {nullable:false})
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import { Controller, Get, Param, Res, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Param, Res } from '@nestjs/common';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { checkFilePath, checkFilename } from '../file.utils';
|
import { checkFilePath, checkFilename } from '../file.utils';
|
||||||
import { FileService } from '../services/file.service';
|
import { FileService } from '../services/file.service';
|
||||||
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard)
|
// TODO: Add cookie authentication
|
||||||
@Controller('files')
|
@Controller('files')
|
||||||
export class FileController {
|
export class FileController {
|
||||||
constructor(private readonly fileService: FileService) {}
|
constructor(private readonly fileService: FileService) {}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { FileUploadService } from './file-upload.service';
|
import { FileUploadService } from './file-upload.service';
|
||||||
import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service';
|
|
||||||
import { LocalStorageService } from 'src/integrations/local-storage/local-storage.service';
|
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||||
|
import { FileStorageService } from 'src/integrations/file-storage/file-storage.service';
|
||||||
|
|
||||||
describe('FileUploadService', () => {
|
describe('FileUploadService', () => {
|
||||||
let service: FileUploadService;
|
let service: FileUploadService;
|
||||||
@ -12,11 +11,7 @@ describe('FileUploadService', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
FileUploadService,
|
FileUploadService,
|
||||||
{
|
{
|
||||||
provide: S3StorageService,
|
provide: FileStorageService,
|
||||||
useValue: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: LocalStorageService,
|
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service';
|
|
||||||
import { kebabCase } from 'src/utils/kebab-case';
|
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
|
||||||
import { LocalStorageService } from 'src/integrations/local-storage/local-storage.service';
|
|
||||||
import { getCropSize } from 'src/utils/image';
|
import { getCropSize } from 'src/utils/image';
|
||||||
import { settings } from 'src/constants/settings';
|
import { settings } from 'src/constants/settings';
|
||||||
import { FileFolder } from '../interfaces/file-folder.interface';
|
import { FileFolder } from '../interfaces/file-folder.interface';
|
||||||
|
import { FileStorageService } from 'src/integrations/file-storage/file-storage.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FileUploadService {
|
export class FileUploadService {
|
||||||
constructor(
|
constructor(private readonly fileStorage: FileStorageService) {}
|
||||||
private readonly s3Storage: S3StorageService,
|
|
||||||
private readonly localStorage: LocalStorageService,
|
|
||||||
private readonly environmentService: EnvironmentService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async uploadFile({
|
async uploadFile({
|
||||||
file,
|
file,
|
||||||
@ -27,23 +20,16 @@ export class FileUploadService {
|
|||||||
mimeType: string | undefined;
|
mimeType: string | undefined;
|
||||||
fileFolder: FileFolder;
|
fileFolder: FileFolder;
|
||||||
}) {
|
}) {
|
||||||
const storageType = this.environmentService.getStorageType();
|
await this.fileStorage.write({
|
||||||
|
file,
|
||||||
|
name,
|
||||||
|
mimeType,
|
||||||
|
folder: fileFolder,
|
||||||
|
});
|
||||||
|
|
||||||
switch (storageType) {
|
return {
|
||||||
case 's3': {
|
name: `/${name}`,
|
||||||
await this.uploadFileToS3(file, name, mimeType, fileFolder);
|
};
|
||||||
return {
|
|
||||||
name: `/${name}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'local':
|
|
||||||
default: {
|
|
||||||
await this.uploadToLocal(file, name, fileFolder);
|
|
||||||
return {
|
|
||||||
name: `/${name}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadImage({
|
async uploadImage({
|
||||||
@ -88,48 +74,4 @@ export class FileUploadService {
|
|||||||
name: `/${name}`,
|
name: `/${name}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async uploadToLocal(
|
|
||||||
file: Buffer | Uint8Array | string,
|
|
||||||
name: string,
|
|
||||||
fileFolder: FileFolder,
|
|
||||||
): Promise<void> {
|
|
||||||
const folderName = kebabCase(fileFolder.toString());
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await this.localStorage.uploadFile({
|
|
||||||
file,
|
|
||||||
name,
|
|
||||||
folder: folderName,
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (err) {
|
|
||||||
console.log('uploadFile error: ', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async uploadFileToS3(
|
|
||||||
file: Buffer | Uint8Array | string,
|
|
||||||
name: string,
|
|
||||||
mimeType: string | undefined,
|
|
||||||
fileFolder: FileFolder,
|
|
||||||
) {
|
|
||||||
// Aws only accept bucket with kebab-case name
|
|
||||||
const bucketFolderName = kebabCase(fileFolder.toString());
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await this.s3Storage.uploadFile({
|
|
||||||
Key: `${bucketFolderName}/${name}`,
|
|
||||||
Body: file,
|
|
||||||
ContentType: mimeType,
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (err) {
|
|
||||||
console.log('uploadFile error: ', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { FileService } from './file.service';
|
import { FileService } from './file.service';
|
||||||
import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service';
|
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||||
|
import { FileStorageService } from 'src/integrations/file-storage/file-storage.service';
|
||||||
|
|
||||||
describe('FileService', () => {
|
describe('FileService', () => {
|
||||||
let service: FileService;
|
let service: FileService;
|
||||||
@ -11,7 +11,7 @@ describe('FileService', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
FileService,
|
FileService,
|
||||||
{
|
{
|
||||||
provide: S3StorageService,
|
provide: FileStorageService,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,55 +1,14 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service';
|
import { FileStorageService } from 'src/integrations/file-storage/file-storage.service';
|
||||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
|
||||||
import { createReadStream } from 'fs';
|
|
||||||
import { join } from 'path';
|
|
||||||
import { Readable } from 'stream';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FileService {
|
export class FileService {
|
||||||
constructor(
|
constructor(private readonly fileStorageService: FileStorageService) {}
|
||||||
private readonly s3Storage: S3StorageService,
|
|
||||||
private readonly environmentService: EnvironmentService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async getFileStream(folderPath: string, filename: string) {
|
async getFileStream(folderPath: string, filename: string) {
|
||||||
const storageType = this.environmentService.getStorageType();
|
return this.fileStorageService.read({
|
||||||
|
|
||||||
switch (storageType) {
|
|
||||||
case 's3':
|
|
||||||
return this.getS3FileStream(folderPath, filename);
|
|
||||||
case 'local':
|
|
||||||
default:
|
|
||||||
return this.getLocalFileStream(folderPath, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getLocalFileStream(folderPath: string, filename: string) {
|
|
||||||
const storageLocation = this.environmentService.getStorageLocalPath();
|
|
||||||
|
|
||||||
const filePath = join(
|
|
||||||
process.cwd(),
|
|
||||||
`${storageLocation}/`,
|
|
||||||
folderPath,
|
folderPath,
|
||||||
filename,
|
filename,
|
||||||
);
|
});
|
||||||
|
|
||||||
return createReadStream(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getS3FileStream(folderPath: string, filename: string) {
|
|
||||||
try {
|
|
||||||
const file = await this.s3Storage.getFile({
|
|
||||||
Key: `${folderPath}/${filename}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!file || !file.Body || !(file.Body instanceof Readable)) {
|
|
||||||
throw new Error('Unable to get file stream');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Readable.from(file.Body);
|
|
||||||
} catch (error) {
|
|
||||||
throw new NotFoundException('File not found');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
|
export interface StorageDriver {
|
||||||
|
read(params: { folderPath: string; filename: string }): Promise<Readable>;
|
||||||
|
write(params: {
|
||||||
|
file: Buffer | Uint8Array | string;
|
||||||
|
name: string;
|
||||||
|
folder: string;
|
||||||
|
mimeType: string | undefined;
|
||||||
|
}): Promise<void>;
|
||||||
|
}
|
||||||
57
server/src/integrations/file-storage/drivers/local.driver.ts
Normal file
57
server/src/integrations/file-storage/drivers/local.driver.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import * as fs from 'fs/promises';
|
||||||
|
import { createReadStream, existsSync } from 'fs';
|
||||||
|
import { join, dirname } from 'path';
|
||||||
|
import { StorageDriver } from './interfaces/storage-driver.interface';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import { kebabCase } from 'src/utils/kebab-case';
|
||||||
|
|
||||||
|
export interface LocalDriverOptions {
|
||||||
|
storagePath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LocalDriver implements StorageDriver {
|
||||||
|
private options: LocalDriverOptions;
|
||||||
|
|
||||||
|
constructor(options: LocalDriverOptions) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createFolder(path: string) {
|
||||||
|
if (existsSync(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.mkdir(path, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
async write(params: {
|
||||||
|
file: Buffer | Uint8Array | string;
|
||||||
|
name: string;
|
||||||
|
folder: string;
|
||||||
|
mimeType: string | undefined;
|
||||||
|
}): Promise<void> {
|
||||||
|
const filePath = join(
|
||||||
|
`${this.options.storagePath}/`,
|
||||||
|
kebabCase(params.folder),
|
||||||
|
params.name,
|
||||||
|
);
|
||||||
|
const folderPath = dirname(filePath);
|
||||||
|
|
||||||
|
await this.createFolder(folderPath);
|
||||||
|
|
||||||
|
await fs.writeFile(filePath, params.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
async read(params: {
|
||||||
|
folderPath: string;
|
||||||
|
filename: string;
|
||||||
|
}): Promise<Readable> {
|
||||||
|
const filePath = join(
|
||||||
|
`${this.options.storagePath}/`,
|
||||||
|
params.folderPath,
|
||||||
|
params.filename,
|
||||||
|
);
|
||||||
|
|
||||||
|
return createReadStream(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +1,26 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
|
||||||
import { MODULE_OPTIONS_TOKEN } from './s3-storage.module-definition';
|
|
||||||
import { S3StorageModuleOptions } from './interfaces';
|
|
||||||
import {
|
import {
|
||||||
CreateBucketCommandInput,
|
CreateBucketCommandInput,
|
||||||
GetObjectCommand,
|
GetObjectCommand,
|
||||||
GetObjectCommandInput,
|
|
||||||
GetObjectCommandOutput,
|
|
||||||
HeadBucketCommandInput,
|
HeadBucketCommandInput,
|
||||||
NotFound,
|
NotFound,
|
||||||
PutObjectCommand,
|
PutObjectCommand,
|
||||||
PutObjectCommandInput,
|
|
||||||
PutObjectCommandOutput,
|
|
||||||
S3,
|
S3,
|
||||||
|
S3ClientConfig,
|
||||||
} from '@aws-sdk/client-s3';
|
} from '@aws-sdk/client-s3';
|
||||||
|
import { StorageDriver } from './interfaces/storage-driver.interface';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
import { kebabCase } from 'src/utils/kebab-case';
|
||||||
|
|
||||||
@Injectable()
|
export interface S3DriverOptions extends S3ClientConfig {
|
||||||
export class S3StorageService {
|
bucketName: string;
|
||||||
|
region: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class S3Driver implements StorageDriver {
|
||||||
private s3Client: S3;
|
private s3Client: S3;
|
||||||
private bucketName: string;
|
private bucketName: string;
|
||||||
|
|
||||||
constructor(
|
constructor(options: S3DriverOptions) {
|
||||||
@Inject(MODULE_OPTIONS_TOKEN)
|
|
||||||
private readonly options: S3StorageModuleOptions,
|
|
||||||
) {
|
|
||||||
const { bucketName, region, ...s3Options } = options;
|
const { bucketName, region, ...s3Options } = options;
|
||||||
|
|
||||||
if (!bucketName || !region) {
|
if (!bucketName || !region) {
|
||||||
@ -37,28 +35,39 @@ export class S3StorageService {
|
|||||||
return this.s3Client;
|
return this.s3Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadFile(
|
async write(params: {
|
||||||
params: Omit<PutObjectCommandInput, 'Bucket'>,
|
file: Buffer | Uint8Array | string;
|
||||||
): Promise<PutObjectCommandOutput> {
|
name: string;
|
||||||
|
folder: string;
|
||||||
|
mimeType: string | undefined;
|
||||||
|
}): Promise<void> {
|
||||||
const command = new PutObjectCommand({
|
const command = new PutObjectCommand({
|
||||||
...params,
|
Key: `${kebabCase(params.folder)}/${params.name}`,
|
||||||
|
Body: params.file,
|
||||||
|
ContentType: params.mimeType,
|
||||||
Bucket: this.bucketName,
|
Bucket: this.bucketName,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.createBucket({ Bucket: this.bucketName });
|
await this.createBucket({ Bucket: this.bucketName });
|
||||||
|
|
||||||
return this.s3Client.send(command);
|
await this.s3Client.send(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFile(
|
async read(params: {
|
||||||
params: Omit<GetObjectCommandInput, 'Bucket'>,
|
folderPath: string;
|
||||||
): Promise<GetObjectCommandOutput> {
|
filename: string;
|
||||||
|
}): Promise<Readable> {
|
||||||
const command = new GetObjectCommand({
|
const command = new GetObjectCommand({
|
||||||
...params,
|
Key: `${params.folderPath}/${params.filename}`,
|
||||||
Bucket: this.bucketName,
|
Bucket: this.bucketName,
|
||||||
});
|
});
|
||||||
|
const file = await this.s3Client.send(command);
|
||||||
|
|
||||||
return this.s3Client.send(command);
|
if (!file || !file.Body || !(file.Body instanceof Readable)) {
|
||||||
|
throw new Error('Unable to get file stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Readable.from(file.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkBucketExists(args: HeadBucketCommandInput) {
|
async checkBucketExists(args: HeadBucketCommandInput) {
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export const STORAGE_DRIVER = Symbol('STORAGE_DRIVER');
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
||||||
|
import { FileStorageModuleOptions } from './interfaces';
|
||||||
|
|
||||||
|
export const {
|
||||||
|
ConfigurableModuleClass,
|
||||||
|
MODULE_OPTIONS_TOKEN,
|
||||||
|
OPTIONS_TYPE,
|
||||||
|
ASYNC_OPTIONS_TYPE,
|
||||||
|
} = new ConfigurableModuleBuilder<FileStorageModuleOptions>({
|
||||||
|
moduleName: 'FileStorage',
|
||||||
|
})
|
||||||
|
.setClassMethodName('forRoot')
|
||||||
|
.build();
|
||||||
48
server/src/integrations/file-storage/file-storage.module.ts
Normal file
48
server/src/integrations/file-storage/file-storage.module.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { DynamicModule, Global } from '@nestjs/common';
|
||||||
|
import { FileStorageService } from './file-storage.service';
|
||||||
|
import { LocalDriver } from './drivers/local.driver';
|
||||||
|
import { S3Driver } from './drivers/s3.driver';
|
||||||
|
import {
|
||||||
|
FileStorageModuleAsyncOptions,
|
||||||
|
FileStorageModuleOptions,
|
||||||
|
} from './interfaces';
|
||||||
|
import { STORAGE_DRIVER } from './file-storage.constants';
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
export class FileStorageModule {
|
||||||
|
static forRoot(options: FileStorageModuleOptions): DynamicModule {
|
||||||
|
const provider = {
|
||||||
|
provide: STORAGE_DRIVER,
|
||||||
|
useValue:
|
||||||
|
options.type === 's3'
|
||||||
|
? new S3Driver(options.options)
|
||||||
|
: new LocalDriver(options.options),
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
module: FileStorageModule,
|
||||||
|
providers: [FileStorageService, provider],
|
||||||
|
exports: [FileStorageService],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static forRootAsync(options: FileStorageModuleAsyncOptions): DynamicModule {
|
||||||
|
const provider = {
|
||||||
|
provide: STORAGE_DRIVER,
|
||||||
|
useFactory: async (...args: any[]) => {
|
||||||
|
const config = await options.useFactory(...args);
|
||||||
|
return config?.type === 's3'
|
||||||
|
? new S3Driver(config.options)
|
||||||
|
: new LocalDriver(config.options);
|
||||||
|
},
|
||||||
|
inject: options.inject || [],
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
module: FileStorageModule,
|
||||||
|
imports: options.imports || [],
|
||||||
|
providers: [FileStorageService, provider],
|
||||||
|
exports: [FileStorageService],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,22 +1,22 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { S3StorageService } from './s3-storage.service';
|
import { FileStorageService } from './file-storage.service';
|
||||||
import { MODULE_OPTIONS_TOKEN } from './s3-storage.module-definition';
|
import { STORAGE_DRIVER } from './file-storage.constants';
|
||||||
|
|
||||||
describe('S3StorageService', () => {
|
describe('FileStorageService', () => {
|
||||||
let service: S3StorageService;
|
let service: FileStorageService;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
S3StorageService,
|
FileStorageService,
|
||||||
{
|
{
|
||||||
provide: MODULE_OPTIONS_TOKEN,
|
provide: STORAGE_DRIVER,
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<S3StorageService>(S3StorageService);
|
service = module.get<FileStorageService>(FileStorageService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
22
server/src/integrations/file-storage/file-storage.service.ts
Normal file
22
server/src/integrations/file-storage/file-storage.service.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { STORAGE_DRIVER } from './file-storage.constants';
|
||||||
|
import { StorageDriver } from './drivers/interfaces/storage-driver.interface';
|
||||||
|
import { Readable } from 'stream';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FileStorageService implements StorageDriver {
|
||||||
|
constructor(@Inject(STORAGE_DRIVER) private driver: StorageDriver) {}
|
||||||
|
|
||||||
|
write(params: {
|
||||||
|
file: string | Buffer | Uint8Array;
|
||||||
|
name: string;
|
||||||
|
folder: string;
|
||||||
|
mimeType: string | undefined;
|
||||||
|
}): Promise<void> {
|
||||||
|
return this.driver.write(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
read(params: { folderPath: string; filename: string }): Promise<Readable> {
|
||||||
|
return this.driver.read(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import { StorageType } from 'src/integrations/environment/interfaces/storage.interface';
|
||||||
|
import { S3DriverOptions } from '../drivers/s3.driver';
|
||||||
|
import { LocalDriverOptions } from '../drivers/local.driver';
|
||||||
|
import { FactoryProvider, ModuleMetadata } from '@nestjs/common';
|
||||||
|
|
||||||
|
export interface S3DriverFactoryOptions {
|
||||||
|
type: StorageType.S3;
|
||||||
|
options: S3DriverOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LocalDriverFactoryOptions {
|
||||||
|
type: StorageType.Local;
|
||||||
|
options: LocalDriverOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FileStorageModuleOptions =
|
||||||
|
| S3DriverFactoryOptions
|
||||||
|
| LocalDriverFactoryOptions;
|
||||||
|
|
||||||
|
export type FileStorageModuleAsyncOptions = {
|
||||||
|
useFactory: (
|
||||||
|
...args: any[]
|
||||||
|
) => FileStorageModuleOptions | Promise<FileStorageModuleOptions>;
|
||||||
|
} & Pick<ModuleMetadata, 'imports'> &
|
||||||
|
Pick<FactoryProvider, 'inject'>;
|
||||||
1
server/src/integrations/file-storage/interfaces/index.ts
Normal file
1
server/src/integrations/file-storage/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './file-storage.interface';
|
||||||
@ -1,59 +1,61 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
||||||
import { S3StorageModule } from './s3-storage/s3-storage.module';
|
|
||||||
import { S3StorageModuleOptions } from './s3-storage/interfaces';
|
|
||||||
import { LocalStorageModule } from './local-storage/local-storage.module';
|
|
||||||
import { LocalStorageModuleOptions } from './local-storage/interfaces';
|
|
||||||
import { EnvironmentModule } from './environment/environment.module';
|
import { EnvironmentModule } from './environment/environment.module';
|
||||||
import { EnvironmentService } from './environment/environment.service';
|
import { EnvironmentService } from './environment/environment.service';
|
||||||
|
import { FileStorageModule } from './file-storage/file-storage.module';
|
||||||
|
import { FileStorageModuleOptions } from './file-storage/interfaces';
|
||||||
|
import { StorageType } from './environment/interfaces/storage.interface';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* S3 Storage Module factory
|
* FileStorage Module factory
|
||||||
* @param config
|
|
||||||
* @returns S3ModuleOptions
|
|
||||||
*/
|
|
||||||
const S3StorageModuleFactory = async (
|
|
||||||
environmentService: EnvironmentService,
|
|
||||||
): Promise<S3StorageModuleOptions> => {
|
|
||||||
const bucketName = environmentService.getStorageS3Name();
|
|
||||||
const region = environmentService.getStorageS3Region();
|
|
||||||
|
|
||||||
return {
|
|
||||||
bucketName: bucketName ?? '',
|
|
||||||
credentials: fromNodeProviderChain({
|
|
||||||
clientConfig: { region },
|
|
||||||
}),
|
|
||||||
forcePathStyle: true,
|
|
||||||
region: region ?? '',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LocalStorage Module factory
|
|
||||||
* @param environment
|
* @param environment
|
||||||
* @returns LocalStorageModuleOptions
|
* @returns FileStorageModuleOptions
|
||||||
*/
|
*/
|
||||||
const localStorageModuleFactory = async (
|
const fileStorageModuleFactory = async (
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
): Promise<LocalStorageModuleOptions> => {
|
): Promise<FileStorageModuleOptions> => {
|
||||||
const storagePath = environmentService.getStorageLocalPath();
|
const type = environmentService.getStorageType();
|
||||||
|
|
||||||
return {
|
switch (type) {
|
||||||
storagePath: process.cwd() + '/' + storagePath,
|
case undefined:
|
||||||
};
|
case StorageType.Local: {
|
||||||
|
const storagePath = environmentService.getStorageLocalPath();
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: StorageType.Local,
|
||||||
|
options: {
|
||||||
|
storagePath: process.cwd() + '/' + storagePath,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case StorageType.S3: {
|
||||||
|
const bucketName = environmentService.getStorageS3Name();
|
||||||
|
const region = environmentService.getStorageS3Region();
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: StorageType.S3,
|
||||||
|
options: {
|
||||||
|
bucketName: bucketName ?? '',
|
||||||
|
credentials: fromNodeProviderChain({
|
||||||
|
clientConfig: { region },
|
||||||
|
}),
|
||||||
|
forcePathStyle: true,
|
||||||
|
region: region ?? '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`Invalid storage type (${type}), check your .env file`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
S3StorageModule.forRootAsync({
|
|
||||||
useFactory: S3StorageModuleFactory,
|
|
||||||
inject: [EnvironmentService],
|
|
||||||
}),
|
|
||||||
LocalStorageModule.forRootAsync({
|
|
||||||
useFactory: localStorageModuleFactory,
|
|
||||||
inject: [EnvironmentService],
|
|
||||||
}),
|
|
||||||
EnvironmentModule.forRoot({}),
|
EnvironmentModule.forRoot({}),
|
||||||
|
FileStorageModule.forRootAsync({
|
||||||
|
useFactory: fileStorageModuleFactory,
|
||||||
|
inject: [EnvironmentService],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
exports: [],
|
exports: [],
|
||||||
providers: [],
|
providers: [],
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export * from './local-storage.interface';
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
export interface LocalStorageModuleOptions {
|
|
||||||
storagePath: string;
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
|
||||||
import { LocalStorageModuleOptions } from './interfaces';
|
|
||||||
|
|
||||||
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
|
||||||
new ConfigurableModuleBuilder<LocalStorageModuleOptions>({
|
|
||||||
moduleName: 'LocalStorage',
|
|
||||||
})
|
|
||||||
.setClassMethodName('forRoot')
|
|
||||||
.build();
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
|
||||||
import { LocalStorageService } from './local-storage.service';
|
|
||||||
import { ConfigurableModuleClass } from './local-storage.module-definition';
|
|
||||||
|
|
||||||
@Global()
|
|
||||||
@Module({
|
|
||||||
providers: [LocalStorageService],
|
|
||||||
exports: [LocalStorageService],
|
|
||||||
})
|
|
||||||
export class LocalStorageModule extends ConfigurableModuleClass {}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { LocalStorageService } from './local-storage.service';
|
|
||||||
import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition';
|
|
||||||
|
|
||||||
describe('LocalStorageService', () => {
|
|
||||||
let service: LocalStorageService;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
LocalStorageService,
|
|
||||||
{
|
|
||||||
provide: MODULE_OPTIONS_TOKEN,
|
|
||||||
useValue: {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<LocalStorageService>(LocalStorageService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(service).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
|
||||||
import * as fs from 'fs/promises';
|
|
||||||
import { existsSync } from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition';
|
|
||||||
import { LocalStorageModuleOptions } from './interfaces';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class LocalStorageService {
|
|
||||||
constructor(
|
|
||||||
@Inject(MODULE_OPTIONS_TOKEN)
|
|
||||||
private readonly options: LocalStorageModuleOptions,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async createFolder(path: string) {
|
|
||||||
if (existsSync(path)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fs.mkdir(path, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
async uploadFile(params: {
|
|
||||||
file: Buffer | Uint8Array | string;
|
|
||||||
name: string;
|
|
||||||
folder: string;
|
|
||||||
}) {
|
|
||||||
const filePath = `${this.options.storagePath}/${params.folder}/${params.name}`;
|
|
||||||
const folderPath = path.dirname(filePath);
|
|
||||||
|
|
||||||
await this.createFolder(folderPath);
|
|
||||||
|
|
||||||
return fs.writeFile(filePath, params.file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './s3-storage-module.interface';
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import { S3ClientConfig } from '@aws-sdk/client-s3';
|
|
||||||
|
|
||||||
export interface S3StorageModuleOptions extends S3ClientConfig {
|
|
||||||
bucketName: string;
|
|
||||||
region: string;
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { ConfigurableModuleBuilder } from '@nestjs/common';
|
|
||||||
import { S3StorageModuleOptions } from './interfaces';
|
|
||||||
|
|
||||||
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
|
|
||||||
new ConfigurableModuleBuilder<S3StorageModuleOptions>({
|
|
||||||
moduleName: 'S3Storage',
|
|
||||||
})
|
|
||||||
.setClassMethodName('forRoot')
|
|
||||||
.build();
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
|
||||||
import { S3StorageService } from './s3-storage.service';
|
|
||||||
import { ConfigurableModuleClass } from './s3-storage.module-definition';
|
|
||||||
|
|
||||||
@Global()
|
|
||||||
@Module({
|
|
||||||
providers: [S3StorageService],
|
|
||||||
exports: [S3StorageService],
|
|
||||||
})
|
|
||||||
export class S3StorageModule extends ConfigurableModuleClass {}
|
|
||||||
Reference in New Issue
Block a user