databases interaction fixed
This commit is contained in:
parent
af6d37c7ca
commit
aeb7a73c4c
|
|
@ -1,9 +1,11 @@
|
|||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Attachment } from './entity/attachment.entity';
|
||||
import { CreateAttachmentDto } from './dto/create_attachment.dto';
|
||||
import { UpdateAttachmentDto } from './dto/update_attachment.dto';
|
||||
import axios from 'axios';
|
||||
import { decode } from 'jsonwebtoken';
|
||||
|
||||
@Injectable()
|
||||
export class AttachmentService {
|
||||
|
|
@ -14,14 +16,44 @@ export class AttachmentService {
|
|||
|
||||
async create(data: CreateAttachmentDto): Promise<Attachment> {
|
||||
try {
|
||||
// Here we send a sample request, in final implementation, there'll be no need for that, we'll get the decoded token
|
||||
const authResponse = await axios.post(
|
||||
'https://auth.didvan.com/realms/didvan/protocol/openid-connect/token',
|
||||
new URLSearchParams({
|
||||
client_id: 'didvan-app',
|
||||
username: 'bob',
|
||||
password: 'developer_password',
|
||||
grant_type: 'password',
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Decode the access token to extract the 'sub' claim
|
||||
const token = authResponse.data.access_token;
|
||||
const decodedToken: any = decode(token);
|
||||
if (!decodedToken || !decodedToken.sub) {
|
||||
throw new InternalServerErrorException('Failed to decode token or extract sub');
|
||||
}
|
||||
|
||||
|
||||
// Create the attachment with ownerId set to sub
|
||||
const attachment = this.attachmentRepository.create({
|
||||
...data,
|
||||
metadata: data.metadata || { entries: [] },
|
||||
ownerId: decodedToken.sub, // Set ownerId to the token's sub
|
||||
metadata: data.metadata
|
||||
? { entries: data.metadata.entries }
|
||||
: { entries: [] },
|
||||
status: data.status || 'active',
|
||||
});
|
||||
|
||||
// Save the attachment to the database
|
||||
return await this.attachmentRepository.save(attachment);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create attachment: ${error.message}`);
|
||||
throw new InternalServerErrorException(`Failed to create attachment: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@ export class CreateAttachmentDto extends BaseDto {
|
|||
storageUrl: string;
|
||||
|
||||
@IsUUID()
|
||||
ownerId: string;
|
||||
@IsOptional()
|
||||
ownerId?: string;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { Column, Entity, ManyToOne } from 'typeorm';
|
|||
import { BaseEntity } from 'src/_core/entity/_base.entity';
|
||||
import { Question } from 'src/question/entity/question.entity';
|
||||
import { FormSection } from '../../formSection/entity/formSection.entity';
|
||||
import { Form } from '../../form/entity/form.entity';
|
||||
|
||||
@Entity({ name: 'attachments' })
|
||||
export class Attachment extends BaseEntity {
|
||||
|
|
@ -30,4 +31,7 @@ export class Attachment extends BaseEntity {
|
|||
|
||||
@ManyToOne(() => FormSection, formSection => formSection.attachments)
|
||||
formSection: FormSection;
|
||||
|
||||
@ManyToOne(() => Form, form => form.attachments)
|
||||
form: Form;
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import { FormSection } from '../formSection/entity/formSection.entity';
|
|||
import { FormPage } from '../formPage/entity/formPage.entity';
|
||||
import { FormResult } from '../formResult/entity/formResult.entity';
|
||||
import { ParticipantGroup } from '../participantGroup/entity/participantGroup.entity';
|
||||
import { BaseEntity } from '../_core/entity/_base.entity';
|
||||
|
||||
export const typeOrmConfig: TypeOrmModuleOptions = {
|
||||
type: 'postgres',
|
||||
|
|
@ -19,8 +20,9 @@ export const typeOrmConfig: TypeOrmModuleOptions = {
|
|||
port: 5433,
|
||||
username: 'postgres',
|
||||
password: '1111',
|
||||
database: 'postgres',
|
||||
database: 'db',
|
||||
entities: [
|
||||
BaseEntity,
|
||||
Participant,
|
||||
Metadata,
|
||||
Form,
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@ export class CreateFormDto extends BaseDto {
|
|||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateFormPageDto)
|
||||
pages: CreateFormPageDto[];
|
||||
@IsOptional()
|
||||
pages?: CreateFormPageDto[];
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateParticipantDto)
|
||||
participants: CreateParticipantDto[];
|
||||
@IsOptional()
|
||||
participants?: CreateParticipantDto[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { BaseEntity } from '../../_core/entity/_base.entity';
|
|||
import { FormPage } from '../../formPage/entity/formPage.entity';
|
||||
import { Participant } from '../../participant/entity/participant.entity';
|
||||
import { Realm } from '../../realm/entity/realm.entity';
|
||||
import { Attachment } from '../../attachment/entity/attachment.entity';
|
||||
|
||||
@Entity()
|
||||
export class Form extends BaseEntity {
|
||||
|
|
@ -20,23 +21,12 @@ export class Form extends BaseEntity {
|
|||
@OneToMany(() => Participant, participant => participant.form, { cascade: true, eager: true })
|
||||
participants: Participant[];
|
||||
|
||||
// Many-to-One relationship with Realm (ADD THIS)
|
||||
@ManyToOne(() => Realm, realm => realm.forms)
|
||||
|
||||
// One-to-Many relationship with Attachment
|
||||
@OneToMany(() => Attachment, attachment => attachment.form, { cascade: true, eager: true })
|
||||
attachments: Attachment[];
|
||||
|
||||
@ManyToOne(() => Realm, realm => realm.forms, { /*cascade: true, eager: true */})
|
||||
realm: Realm;
|
||||
|
||||
// Attachments are typically stored in a separate table and linked via a many-to-many or one-to-many
|
||||
// For simplicity, if attachments are embedded, they would be handled like DisplayCondition in FormSection.
|
||||
// If they are separate entities, they would need a relationship defined here.
|
||||
// Assuming attachments are now handled as a separate entity with a relationship if needed.
|
||||
// If attachments were previously embedded, you'd need to define a class for them and use @Column(() => AttachmentClass)
|
||||
// For now, removing the direct 'attachments' column from Form as it was an array of AttachmentSchema (Mongoose).
|
||||
// If you need attachments directly on Form, please provide the Attachment entity structure.
|
||||
|
||||
|
||||
// @Prop({
|
||||
// type: [AttachmentSchema],
|
||||
// default: [],
|
||||
// })
|
||||
// attachments: Attachment[];
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"token": {
|
||||
"exp": 1753279286,
|
||||
"iat": 1753250486,
|
||||
"jti": "onrtro:4cee0913-cbe6-89c0-d4bb-dac3d8e29b04",
|
||||
"iss": "https://auth.didvan.com/realms/didvan",
|
||||
"aud": "account",
|
||||
"sub": "010be0e5-fe3d-4686-b093-8fe37ccdc3c9",
|
||||
"typ": "Bearer",
|
||||
"azp": "didvan-app",
|
||||
"sid": "be164904-009b-450e-98d5-553073af0fcb",
|
||||
"acr": "1",
|
||||
"allowed-origins": [
|
||||
"https://didvan.com",
|
||||
"https://web.didvan.com",
|
||||
"http://localhost:3000"
|
||||
],
|
||||
"realm_access": {
|
||||
"roles": [
|
||||
"delphi-user",
|
||||
"offline_access",
|
||||
"uma_authorization",
|
||||
"default-roles-didvan"
|
||||
]
|
||||
},
|
||||
"resource_access": {
|
||||
"account": {
|
||||
"roles": [
|
||||
"manage-account",
|
||||
"manage-account-links",
|
||||
"view-profile"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scope": "email profile",
|
||||
"email_verified": true,
|
||||
"name": "alice alice_lastname",
|
||||
"preferred_username": "alice",
|
||||
"given_name": "alice",
|
||||
"family_name": "alice_lastname",
|
||||
"email": "alice@gmail.com"
|
||||
},
|
||||
"data": {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -16,12 +16,12 @@ export class ParticipantService {
|
|||
|
||||
async create(data: CreateParticipantDto): Promise<Participant> {
|
||||
try {
|
||||
// Make the authentication request to get the token
|
||||
// Here we send a sample request, in final implementation, there'll be no need for that, we'll get the decoded token
|
||||
const authResponse = await axios.post(
|
||||
'https://auth.didvan.com/realms/didvan/protocol/openid-connect/token',
|
||||
new URLSearchParams({
|
||||
client_id: 'didvan-app',
|
||||
username: 'alice',
|
||||
username: 'bob',
|
||||
password: 'developer_password',
|
||||
grant_type: 'password',
|
||||
}),
|
||||
|
|
@ -39,16 +39,21 @@ export class ParticipantService {
|
|||
throw new InternalServerErrorException('Failed to decode token or extract sub');
|
||||
}
|
||||
|
||||
// Create the participant with the 'sub' as the ID and userId
|
||||
// Check if participant with this sub already exists
|
||||
const existingParticipant = await this.participantRepository.findOne({ where: { id: decodedToken.sub } });
|
||||
if (existingParticipant) {
|
||||
throw new InternalServerErrorException(`Participant with ID ${decodedToken.sub} already exists`);
|
||||
}
|
||||
|
||||
// Create the participant with the 'sub' as the ID
|
||||
const participant = this.participantRepository.create({
|
||||
...data,
|
||||
id: decodedToken.sub, // Set the ID from the token's sub
|
||||
// id: , let it assign a random id
|
||||
userId: decodedToken.sub, // Set userId to the same sub
|
||||
metadata: data.metadata
|
||||
? { entries: data.metadata.entries } // Ensure metadata is properly formatted
|
||||
? { entries: data.metadata.entries }
|
||||
: { entries: [] },
|
||||
status: data.status || 'active',
|
||||
// Note: form and realm are not set as they are optional (ManyToOne)
|
||||
});
|
||||
|
||||
// Save the participant to the database
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@ export class CreateRealmDto extends BaseDto {
|
|||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateParticipantDto)
|
||||
participants: CreateParticipantDto[]; // Changed from 'participant' to 'participants' for consistency with array
|
||||
@IsOptional()
|
||||
participants?: CreateParticipantDto[];
|
||||
|
||||
@ValidateNested() // Not IsArray, as it's a single owner
|
||||
@Type(() => CreateParticipantDto)
|
||||
owner: CreateParticipantDto;
|
||||
// @ValidateNested() // Not IsArray, as it's a single owner
|
||||
// @Type(() => CreateParticipantDto)
|
||||
// owner: CreateParticipantDto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Entity, Column, OneToMany, OneToOne, JoinColumn } from 'typeorm';
|
||||
import { Entity, Column, OneToMany, OneToOne, JoinColumn} from 'typeorm';
|
||||
import { BaseEntity } from '../../_core/entity/_base.entity';
|
||||
import { Form } from '../../form/entity/form.entity';
|
||||
import { Participant } from '../../participant/entity/participant.entity';
|
||||
|
|
@ -11,17 +11,14 @@ export class Realm extends BaseEntity {
|
|||
@Column()
|
||||
description: string;
|
||||
|
||||
// One-to-Many relationship with Form
|
||||
@OneToMany(() => Form, form => form.realm, { cascade: true, eager: true })
|
||||
forms: Form[];
|
||||
|
||||
// One-to-Many relationship with Participant (for general participants in the realm)
|
||||
@OneToMany(() => Participant, participant => participant.realm, { cascade: true, eager: true })
|
||||
participants: Participant[];
|
||||
|
||||
// One-to-One relationship with Participant (for the owner of the realm)
|
||||
// Assuming 'owner' is a single Participant entity
|
||||
@OneToOne(() => Participant, { cascade: true, eager: true })
|
||||
@JoinColumn() // This column will be added to the Realm table to store the owner's ID
|
||||
@JoinColumn({ name: 'ownerId', referencedColumnName: 'userId' }) // be explicit
|
||||
owner: Participant;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,73 @@
|
|||
// src/realm/realm.service.ts
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException, InternalServerErrorException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Realm } from './entity/realm.entity';
|
||||
import { CreateRealmDto } from './dto/create-realm.dto';
|
||||
import { UpdateRealmDto } from './dto/update-realm.dto';
|
||||
import { Participant } from '../participant/entity/participant.entity';
|
||||
import axios from 'axios';
|
||||
import { decode } from 'jsonwebtoken';
|
||||
|
||||
@Injectable()
|
||||
export class RealmService {
|
||||
constructor(
|
||||
@InjectRepository(Realm)
|
||||
private readonly realmRepo: Repository<Realm>,
|
||||
@InjectRepository(Participant)
|
||||
private readonly participantRepo: Repository<Participant>,
|
||||
) {}
|
||||
|
||||
async create(data: CreateRealmDto): Promise<Realm> {
|
||||
const realm = this.realmRepo.create({ ...data });
|
||||
return await this.realmRepo.save(realm);
|
||||
try {
|
||||
// Here we send a sample request, in final implementation, there'll be no need for that, we'll get the decoded token
|
||||
const authResponse = await axios.post(
|
||||
'https://auth.didvan.com/realms/didvan/protocol/openid-connect/token',
|
||||
new URLSearchParams({
|
||||
client_id: 'didvan-app',
|
||||
username: 'bob',
|
||||
password: 'developer_password',
|
||||
grant_type: 'password',
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Decode the access token to extract the 'sub' claim
|
||||
const token = authResponse.data.access_token;
|
||||
const decodedToken: any = decode(token);
|
||||
if (!decodedToken || !decodedToken.sub) {
|
||||
throw new InternalServerErrorException('Failed to decode token or extract sub');
|
||||
}
|
||||
|
||||
// Find or create a participant with userId set to sub
|
||||
let participant = await this.participantRepo.findOne({ where: { userId: decodedToken.sub } });
|
||||
if (!participant) {
|
||||
participant = this.participantRepo.create({
|
||||
displayName: data.title + ' Owner', // Default displayName
|
||||
role: 'admin', // Default role for owner
|
||||
userId: decodedToken.sub,
|
||||
metadata: data.metadata ? { entries: data.metadata.entries } : { entries: [] },
|
||||
// status: 'active',
|
||||
});
|
||||
participant = await this.participantRepo.save(participant);
|
||||
}
|
||||
|
||||
// Create the realm with the participant as the owner
|
||||
const realm = this.realmRepo.create({
|
||||
...data,
|
||||
owner: participant, // Set owner to the participant with userId = sub
|
||||
});
|
||||
|
||||
return await this.realmRepo.save(realm);
|
||||
} catch (error) {
|
||||
throw new InternalServerErrorException(`Failed to create realm: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Other methods (findAll, findById, update, remove) remain unchanged
|
||||
async findAll(
|
||||
page = 1,
|
||||
limit = 10,
|
||||
|
|
@ -83,10 +133,7 @@ export class RealmService {
|
|||
return realm;
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
data: UpdateRealmDto,
|
||||
): Promise<Realm | null> {
|
||||
async update(id: string, data: UpdateRealmDto): Promise<Realm | null> {
|
||||
const result = await this.realmRepo.update(
|
||||
{ id },
|
||||
{ ...data, updatedAt: new Date() },
|
||||
|
|
|
|||
Loading…
Reference in New Issue