updated living space added
This commit is contained in:
@@ -2,10 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
import { BuildIbanResolver } from './build-iban.resolver';
|
||||
import { BuildIbanService } from './build-iban.service';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { BuildIban, BuildIbanSchema } from '@/models/build.model';
|
||||
import { BuildIban, BuildIbanSchema, Build, BuildSchema } from '@/models/build.model';
|
||||
|
||||
@Module({
|
||||
imports: [MongooseModule.forFeature([{ name: BuildIban.name, schema: BuildIbanSchema }])],
|
||||
imports: [MongooseModule.forFeature([
|
||||
{ name: BuildIban.name, schema: BuildIbanSchema }, { name: Build.name, schema: BuildSchema }
|
||||
])],
|
||||
providers: [BuildIbanResolver, BuildIbanService]
|
||||
})
|
||||
export class BuildIbanModule { }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Types, Model } from 'mongoose';
|
||||
import { BuildIban, BuildIbanDocument } from '@/models/build.model';
|
||||
import { Build, BuildDocument, BuildIban, BuildIbanDocument } from '@/models/build.model';
|
||||
import { ListBuildIbanResponse } from './dto/list-build-ibans.response';
|
||||
import { CreateBuildIbanInput } from './dto/create-build-ibans.input';
|
||||
import { UpdateBuildIbanInput } from './dto/update-build-ibans.input';
|
||||
@@ -9,10 +9,14 @@ import { UpdateBuildIbanInput } from './dto/update-build-ibans.input';
|
||||
@Injectable()
|
||||
export class BuildIbanService {
|
||||
|
||||
constructor(@InjectModel(BuildIban.name) private readonly buildIbanModel: Model<BuildIbanDocument>) { }
|
||||
constructor(
|
||||
@InjectModel(BuildIban.name) private readonly buildIbanModel: Model<BuildIbanDocument>,
|
||||
@InjectModel(Build.name) private readonly buildModel: Model<BuildDocument>
|
||||
) { }
|
||||
|
||||
async findAll(projection: any, skip: number, limit: number, sort?: Record<string, 1 | -1>, filters?: Record<string, any>): Promise<ListBuildIbanResponse> {
|
||||
const query: any = {}; if (filters && Object.keys(filters).length > 0) { Object.assign(query, filters) };
|
||||
if (!!query?.buildId) { query.buildId = new Types.ObjectId(query?.buildId) };
|
||||
const totalCount = await this.buildIbanModel.countDocuments(query).exec();
|
||||
const data = await this.buildIbanModel.find(query, projection, { lean: true }).skip(skip).limit(limit).sort(sort).exec();
|
||||
return { data, totalCount };
|
||||
@@ -22,17 +26,21 @@ export class BuildIbanService {
|
||||
return this.buildIbanModel.findById(id, projection, { lean: false }).populate({ path: 'buildIban', select: projection?.buildIban }).exec();
|
||||
}
|
||||
|
||||
async create(input: CreateBuildIbanInput): Promise<BuildIbanDocument> { const buildIban = new this.buildIbanModel(input); return buildIban.save() }
|
||||
async create(input: CreateBuildIbanInput): Promise<BuildIbanDocument> {
|
||||
const build = await this.buildModel.findOne({ _id: new Types.ObjectId(input.buildId) });
|
||||
if (!build) { throw new Error('Build not found') }
|
||||
const buildIban = new this.buildIbanModel({ ...input, buildId: build._id }); return buildIban.save()
|
||||
}
|
||||
|
||||
async update(uuid: string, input: UpdateBuildIbanInput): Promise<BuildIbanDocument> { const buildIban = await this.buildIbanModel.findOne({ uuid }); if (!buildIban) { throw new Error('BuildIban not found') }; buildIban.set(input); return buildIban.save() }
|
||||
async update(uuid: string, input: UpdateBuildIbanInput): Promise<BuildIbanDocument> {
|
||||
const buildIban = await this.buildIbanModel.findOne({ uuid }); if (!buildIban) { throw new Error('BuildIban not found') }; buildIban.set(input); return buildIban.save()
|
||||
}
|
||||
|
||||
async delete(uuid: string): Promise<boolean> { const buildIban = await this.buildIbanModel.deleteMany({ uuid }); return buildIban.deletedCount > 0 }
|
||||
|
||||
buildProjection(fields: Record<string, any>): any {
|
||||
const projection: any = {};
|
||||
for (const key in fields) {
|
||||
if (key === 'buildIban' && typeof fields[key] === 'object') { for (const subField of Object.keys(fields[key])) { projection[`buildIban.${subField}`] = 1 } } else { projection[key] = 1 }
|
||||
}; return projection;
|
||||
for (const key in fields) { if (key === 'buildIban' && typeof fields[key] === 'object') { for (const subField of Object.keys(fields[key])) { projection[`buildIban.${subField}`] = 1 } } else { projection[key] = 1 } }; return projection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import { InputType, Field } from "@nestjs/graphql";
|
||||
@InputType()
|
||||
export class CreateBuildIbanInput extends ExpiryBaseInput {
|
||||
|
||||
@Field()
|
||||
buildId: string;
|
||||
|
||||
@Field()
|
||||
iban: string;
|
||||
|
||||
|
||||
8
backend/src/lib/generateToken.ts
Normal file
8
backend/src/lib/generateToken.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { randomBytes, createHash } from "crypto";
|
||||
|
||||
export function generateResetToken(length: number = 128) {
|
||||
const resetToken = randomBytes(length).toString("hex");
|
||||
const hashedToken = createHash("sha256").update(resetToken).digest("hex");
|
||||
const expires = Date.now() + 1000 * 60 * 60 * 24 * 3;
|
||||
return { resetToken, hashedToken, expires };
|
||||
}
|
||||
@@ -13,8 +13,8 @@ export class CreateLivingSpaceInput extends ExpiryBaseInput {
|
||||
@Field()
|
||||
userTypeID: string;
|
||||
|
||||
@Field()
|
||||
companyID: string;
|
||||
@Field({ nullable: true })
|
||||
companyID?: string;
|
||||
|
||||
@Field()
|
||||
personID: string;
|
||||
|
||||
12
backend/src/living-space/dto/get-living-space.input.ts
Normal file
12
backend/src/living-space/dto/get-living-space.input.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { InputType, Field } from '@nestjs/graphql';
|
||||
|
||||
@InputType()
|
||||
export class GetLivingSpaceInput {
|
||||
|
||||
@Field()
|
||||
buildID: string;
|
||||
|
||||
@Field()
|
||||
uuid: string;
|
||||
|
||||
}
|
||||
@@ -4,11 +4,13 @@ import { LivingSpaceResolver } from './living-space.resolver';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { LivingSpaces, LivingSpacesSchema } from '@/models/living-spaces.model';
|
||||
import { UserType, UserTypeSchema } from '@/models/user-type.model';
|
||||
import { Build, BuildSchema } from '@/models/build.model';
|
||||
|
||||
@Module({
|
||||
imports: [MongooseModule.forFeature([
|
||||
{ name: LivingSpaces.name, schema: LivingSpacesSchema },
|
||||
{ name: UserType.name, schema: UserTypeSchema },
|
||||
{ name: Build.name, schema: BuildSchema },
|
||||
])],
|
||||
providers: [LivingSpaceService, LivingSpaceResolver]
|
||||
})
|
||||
|
||||
@@ -8,6 +8,7 @@ import { UpdateLivingSpaceInput } from './dto/update-living-space.input';
|
||||
import { LivingSpaceService } from './living-space.service';
|
||||
import type { GraphQLResolveInfo } from 'graphql';
|
||||
import graphqlFields from 'graphql-fields';
|
||||
import { GetLivingSpaceInput } from './dto/get-living-space.input';
|
||||
|
||||
@Resolver()
|
||||
export class LivingSpaceResolver {
|
||||
@@ -25,6 +26,9 @@ export class LivingSpaceResolver {
|
||||
const fields = graphqlFields(info); const projection = this.livingSpaceService.buildProjection(fields); return this.livingSpaceService.findById(buildID, new Types.ObjectId(id), projection);
|
||||
}
|
||||
|
||||
@Query(() => LivingSpaces, { name: 'getLivingSpaceDetail', nullable: true })
|
||||
async getLivingSpaceDetail(@Args('uuid') uuid: string, @Args('buildID') buildID: string): Promise<LivingSpaces | null> { return this.livingSpaceService.getDetail(buildID, uuid) }
|
||||
|
||||
@Mutation(() => LivingSpaces, { name: 'createLivingSpace' })
|
||||
async createLivingSpace(@Args('input') input: CreateLivingSpaceInput): Promise<LivingSpaces> { return this.livingSpaceService.create(input) }
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { CreateLivingSpaceInput } from './dto/create-living-space.input';
|
||||
import { UpdateLivingSpaceInput } from './dto/update-living-space.input';
|
||||
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
|
||||
import { UserTypeDocument } from '@/models/user-type.model';
|
||||
import { BuildDocument } from '@/models/build.model';
|
||||
|
||||
interface UpdateInput {
|
||||
userType?: Types.ObjectId;
|
||||
@@ -21,17 +22,30 @@ export class LivingSpaceService {
|
||||
|
||||
constructor(
|
||||
@InjectConnection() private readonly connection: Connection,
|
||||
@InjectModel('UserType') private readonly userTypeModel: Model<UserTypeDocument>
|
||||
@InjectModel('UserType') private readonly userTypeModel: Model<UserTypeDocument>,
|
||||
@InjectModel('Build') private readonly buildModel: Model<BuildDocument>
|
||||
) { }
|
||||
|
||||
async findAll(buildID: string, projection: any, skip: number, limit: number, sort?: Record<string, 1 | -1>, filters?: Record<string, any>): Promise<ListLivingSpaceResponse> {
|
||||
const selectedModel = getDynamicLivingSpaceModel(buildID, this.connection);
|
||||
const query: any = {}; if (filters && Object.keys(filters).length > 0) { Object.assign(query, filters) };
|
||||
const totalCount = await selectedModel.countDocuments(query).exec();
|
||||
const data = await selectedModel.find(query, projection, { lean: true }).skip(skip).limit(limit).sort(sort).exec();
|
||||
const data = await selectedModel.find(query, projection, { lean: false })
|
||||
.populate({ path: 'build', select: { ...projection?.build, _id: 0 } })
|
||||
.populate({ path: 'person', select: { ...projection?.person, _id: 0 } })
|
||||
.populate({ path: 'company', select: { ...projection?.company, _id: 0 } })
|
||||
.populate({ path: 'userType', select: { ...projection?.userType, _id: 0 } })
|
||||
.populate({ path: 'part', select: { ...projection?.part, _id: 0 } })
|
||||
.skip(skip).limit(limit).sort(sort).exec();
|
||||
return { data, totalCount };
|
||||
}
|
||||
|
||||
async getDetail(buildID: string, uuid: string): Promise<any | null> {
|
||||
const buildObjectID = new Types.ObjectId(buildID); const build = await this.buildModel.findById(buildObjectID); if (!build) { throw new Error('Build not found') };
|
||||
const selectedModel = getDynamicLivingSpaceModel(buildID, this.connection); const data = await selectedModel.findOne({ uuid }, { lean: false }).exec();
|
||||
if (!data) { throw new Error('Living space not found') }; return data;
|
||||
}
|
||||
|
||||
async findById(buildID: string, id: Types.ObjectId, projection?: any): Promise<LivingSpacesDocument | null> {
|
||||
const selectedModel = getDynamicLivingSpaceModel(buildID, this.connection);
|
||||
return selectedModel.findById(id, projection, { lean: false }).populate({ path: 'company', select: projection?.company }).exec();
|
||||
@@ -42,7 +56,7 @@ export class LivingSpaceService {
|
||||
const LivingSpaceModel = getDynamicLivingSpaceModel(input.buildID, this.connection);
|
||||
const docInput: Partial<LivingSpacesDocument> = {
|
||||
build: new Types.ObjectId(input.buildID), part: new Types.ObjectId(input.partID), userType: new Types.ObjectId(input.userTypeID),
|
||||
company: new Types.ObjectId(input.companyID), person: new Types.ObjectId(input.personID),
|
||||
company: !!input.companyID ? new Types.ObjectId(input.companyID) : undefined, person: new Types.ObjectId(input.personID),
|
||||
expiryStarts: input.expiryStarts ? new Date(input.expiryStarts) : new Date(), expiryEnds: input.expiryEnds ? new Date(input.expiryEnds) : new Date('2099-12-31'),
|
||||
}; const doc = new LivingSpaceModel(docInput); return await doc.save()
|
||||
}
|
||||
@@ -51,10 +65,10 @@ export class LivingSpaceService {
|
||||
if (!buildID) { throw new Error('Build ID is required') }
|
||||
const selectedModel = getDynamicLivingSpaceModel(buildID, this.connection);
|
||||
const livingSpace = await selectedModel.findOne({ uuid }); const userTypeSelected = await this.userTypeModel.findById(new Types.ObjectId(input.userTypeID)).exec(); const newInput: UpdateInput = {}
|
||||
if (userTypeSelected?.isProperty) { if (input?.partID) { newInput.part = new Types.ObjectId(input.partID) } } else { newInput.part = null }
|
||||
if (input?.companyID) { newInput.company = new Types.ObjectId(input.companyID) }
|
||||
if (input?.personID) { newInput.person = new Types.ObjectId(input.personID) }; if (input?.userTypeID) { newInput.userType = new Types.ObjectId(input.userTypeID) }
|
||||
if (input?.expiryStarts) { newInput.expiryStarts = input.expiryStarts }; if (input?.expiryEnds) { newInput.expiryEnds = input.expiryEnds }
|
||||
if (userTypeSelected?.isProperty) { if (!!input?.partID) { newInput.part = new Types.ObjectId(input.partID) } } else { newInput.part = null }
|
||||
if (!!input?.companyID) { newInput.company = new Types.ObjectId(input.companyID) }
|
||||
if (!!input?.personID) { newInput.person = new Types.ObjectId(input.personID) }; if (!!input?.userTypeID) { newInput.userType = new Types.ObjectId(input.userTypeID) }
|
||||
if (!!input?.expiryStarts) { newInput.expiryStarts = input.expiryStarts }; if (!!input?.expiryEnds) { newInput.expiryEnds = input.expiryEnds }
|
||||
if (!livingSpace) { throw new Error('Company not found') }; livingSpace.set(newInput); return livingSpace.save();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,17 @@ export class BuildParts extends Base {
|
||||
@Field(() => ID)
|
||||
readonly _id: string;
|
||||
|
||||
@Field(() => ID)
|
||||
@Prop({ type: Types.ObjectId, ref: 'Build', required: true })
|
||||
buildId: Types.ObjectId;
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'Build', required: false })
|
||||
buildId?: Types.ObjectId;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'ApiEnumDropdown', required: false })
|
||||
directionId?: Types.ObjectId;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'ApiEnumDropdown', required: false })
|
||||
typeId?: Types.ObjectId;
|
||||
|
||||
@Field()
|
||||
@Prop({ required: true })
|
||||
@@ -50,14 +58,6 @@ export class BuildParts extends Base {
|
||||
@Prop({ required: true })
|
||||
key: string;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'ApiEnumDropdown', required: false })
|
||||
directionId: Types.ObjectId;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'ApiEnumDropdown', required: false })
|
||||
typeId: Types.ObjectId;
|
||||
|
||||
}
|
||||
|
||||
export type BuildPartsDocument = BuildParts & Document;
|
||||
|
||||
@@ -2,8 +2,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import { Document, Types } from 'mongoose';
|
||||
import { ObjectType, Field, ID, Int } from '@nestjs/graphql';
|
||||
import { Base, CreatedBase } from '@/models/base.model';
|
||||
import { Person } from '@/models/person.model';
|
||||
import { Company } from '@/models/company.model';
|
||||
import { BuildTypes } from './build-types.model';
|
||||
|
||||
@ObjectType()
|
||||
@@ -13,6 +11,10 @@ export class BuildIban extends Base {
|
||||
@Field(() => ID)
|
||||
readonly _id: string;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: 'Build', required: false })
|
||||
buildId?: Types.ObjectId;
|
||||
|
||||
@Field()
|
||||
@Prop({ required: true })
|
||||
iban: string;
|
||||
@@ -144,6 +146,7 @@ export class Build extends CreatedBase {
|
||||
@Prop({ type: [String], default: [] })
|
||||
areas?: string[];
|
||||
|
||||
// collect String(ObjectID) to
|
||||
@Field(() => [String], { nullable: true, defaultValue: [] })
|
||||
@Prop({ type: [String], default: [] })
|
||||
ibans?: string[];
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Person } from '@/models/person.model';
|
||||
import { Company } from '@/models/company.model';
|
||||
import { UserType } from '@/models/user-type.model';
|
||||
|
||||
|
||||
@ObjectType()
|
||||
@Schema({ timestamps: true })
|
||||
export class LivingSpaces extends Base {
|
||||
@@ -16,23 +15,23 @@ export class LivingSpaces extends Base {
|
||||
@Field(() => ID)
|
||||
readonly _id: string
|
||||
|
||||
@Field(() => ID)
|
||||
@Field(() => Build)
|
||||
@Prop({ type: Types.ObjectId, ref: Build.name, required: true })
|
||||
build: Types.ObjectId;
|
||||
|
||||
@Field(() => ID, { nullable: true })
|
||||
@Field(() => BuildParts, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: BuildParts.name, required: false })
|
||||
part?: Types.ObjectId | null;
|
||||
|
||||
@Field(() => ID)
|
||||
@Field(() => UserType)
|
||||
@Prop({ type: Types.ObjectId, ref: UserType.name, required: true })
|
||||
userType: Types.ObjectId;
|
||||
|
||||
@Field(() => ID)
|
||||
@Prop({ type: Types.ObjectId, ref: Company.name, required: true })
|
||||
company: Types.ObjectId;
|
||||
@Field(() => Company, { nullable: true })
|
||||
@Prop({ type: Types.ObjectId, ref: Company.name, required: false })
|
||||
company?: Types.ObjectId;
|
||||
|
||||
@Field(() => ID)
|
||||
@Field(() => Person)
|
||||
@Prop({ type: Types.ObjectId, ref: Person.name, required: true })
|
||||
person: Types.ObjectId;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ObjectType, Field, ID } from '@nestjs/graphql';
|
||||
import { Document, Types } from 'mongoose';
|
||||
import { Base } from '@/models/base.model';
|
||||
import { Person } from '@/models/person.model';
|
||||
import { generateResetToken } from '@/lib/generateToken';
|
||||
|
||||
@ObjectType()
|
||||
export class CollectionToken {
|
||||
@@ -35,12 +36,12 @@ export class User extends Base {
|
||||
expiresAt?: Date;
|
||||
|
||||
@Field({ nullable: true })
|
||||
@Prop()
|
||||
@Prop({ required: false, default: () => generateResetToken().hashedToken })
|
||||
resetToken?: string;
|
||||
|
||||
@Field()
|
||||
@Prop({ required: true })
|
||||
password: string;
|
||||
@Field({ nullable: true })
|
||||
@Prop({ required: false, default: '' })
|
||||
password?: string;
|
||||
|
||||
@Field(() => [String], { nullable: 'itemsAndList' })
|
||||
@Prop({ type: [String], default: [], validate: [(val: string[]) => val.length <= 3, 'History can have max 3 items'] })
|
||||
|
||||
@@ -20,11 +20,8 @@ export class CreateUserInput {
|
||||
@Field({ nullable: true })
|
||||
avatar?: string;
|
||||
|
||||
@Field()
|
||||
password: string;
|
||||
|
||||
@Field(() => [String], { nullable: true })
|
||||
history?: string[];
|
||||
// @Field()
|
||||
// password: string;
|
||||
|
||||
@Field()
|
||||
tag: string;
|
||||
|
||||
@@ -6,8 +6,9 @@ mutation {
|
||||
email: "test@example.com",
|
||||
phone: "555123456",
|
||||
collectionTokens: {
|
||||
default: "default-token",
|
||||
tokens: [{ prefix: "main", token: "abc123" }]
|
||||
defaultSelection: "default-token",
|
||||
selectedBuildIDS: ["64f8b2a4e1234567890abcdef"],
|
||||
selectedCompanyIDS: ["64f8b2a4e1234567890abcdef"]
|
||||
},
|
||||
person: "64f8b2a4e1234567890abcdef"
|
||||
}) {
|
||||
@@ -18,11 +19,9 @@ mutation {
|
||||
phone
|
||||
tag
|
||||
collectionTokens {
|
||||
default
|
||||
tokens {
|
||||
prefix
|
||||
token
|
||||
}
|
||||
defaultSelection
|
||||
selectedBuildIDS
|
||||
selectedCompanyIDS
|
||||
}
|
||||
person
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user