diff --git a/backend/src/entities/education.entity.ts b/backend/src/entities/education.entity.ts new file mode 100644 index 00000000..79a4a0f2 --- /dev/null +++ b/backend/src/entities/education.entity.ts @@ -0,0 +1,121 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + } from "typeorm"; + import { Field, ID, ObjectType } from "type-graphql"; +import { Length } from "class-validator"; + + @ObjectType() + @Entity() + export class Education { + @Field(() => ID) + @PrimaryGeneratedColumn() + id: number; + + @Field() + @Column({ length: 100 }) + @Length(1, 100, { + message: "TitleFR must have between 1 to 100 characters", + }) + titleFR: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "TtitleEN must have between 1 to 50 characters", + }) + titleEN: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "DiplomateFR must have between 1 to 50 characters", + }) + diplomaLevelFR: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "DiplomateEN must have between 1 to 50 characters", + }) + diplomaLevelEN: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "Shool must have between 1 to 50 characters", + }) + school: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "Location must have between 1 to 50 characters", + }) + location: string; + + @Field() + @Column({ type: "int" }) + year: number; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "StartDateEN must have between 1 to 20 characters", + }) + startDateEN: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "StartDateFR must have between 1 to 20 characters", + }) + startDateFR: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "EndDateEN must have between 1 to 20 characters", + }) + endDateEN: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "EndDateFR must have between 1 to 20 characters", + }) + endDateFR: string; + + @Field({ nullable: true }) + @Column({ nullable: true, type: "int" }) + month: number | null; + + @Field() + @Column({ length: 30 }) + @Length(1, 30, { + message: "TypeEN must have between 1 to 30 characters", + }) + typeEN: string; + + @Field() + @Column({ length: 30 }) + @Length(1, 30, { + message: "TypeFR must have between 1 to 30 characters", + }) + typeFR: string; + + @Field() + @CreateDateColumn({ default: () => "CURRENT_TIMESTAMP" }) + created_at: Date; + + @Field() + @UpdateDateColumn({ + name: "updated_at", + default: () => "CURRENT_TIMESTAMP", + onUpdate: "CURRENT_TIMESTAMP", + }) + updated_at: Date; + } \ No newline at end of file diff --git a/backend/src/entities/experience.entity.ts b/backend/src/entities/experience.entity.ts new file mode 100644 index 00000000..4ce111c5 --- /dev/null +++ b/backend/src/entities/experience.entity.ts @@ -0,0 +1,110 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + } from "typeorm"; + import { Field, ID, ObjectType } from "type-graphql"; +import { Length } from "class-validator"; + + @ObjectType() + @Entity() + export class Experience { + @Field(() => ID) + @PrimaryGeneratedColumn() + id: number; + + @Field() + @Column({ length: 100 }) + @Length(1, 40, { + message: "JobEN must have between 1 to 40 characters", + }) + jobEN: string; + + @Field() + @Column({ length: 100 }) + @Length(1, 40, { + message: "JobFR must have between 1 to 40 characters", + }) + jobFR: string; + + @Field() + @Column({ length: 25 }) + @Length(1, 25, { + message: "Business must have between 1 to 25 characters", + }) + business: string; + + @Field({ nullable: true }) + @Column({ length: 50, nullable: true }) + @Length(1, 50, { + message: "EmploymentContractEN must have between 1 to 50 characters", + }) + employmentContractEN: string | null; + + @Field({ nullable: true }) + @Column({ length: 100, nullable: true }) + @Length(1, 50, { + message: "EmploymentContractFR must have between 1 to 50 characters", + }) + employmentContractFR: string | null; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "StartDateEN must have between 1 to 20 characters", + }) + startDateEN: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "StartDateFR must have between 1 to 20 characters", + }) + startDateFR: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "EndDateEN must have between 1 to 20 characters", + }) + endDateEN: string; + + @Field() + @Column({ length: 20 }) + @Length(1, 20, { + message: "EndDateFR must have between 1 to 20 characters", + }) + endDateFR: string; + + @Field({ nullable: true }) + @Column({ nullable: true, type: "int" }) + month: number | null; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "TypeEN must have between 1 to 50 characters", + }) + typeEN: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "TypeFR must have between 1 to 50 characters", + }) + typeFR: string; + + @Field() + @CreateDateColumn({ default: () => "CURRENT_TIMESTAMP" }) + created_at: Date; + + @Field() + @UpdateDateColumn({ + name: "updated_at", + default: () => "CURRENT_TIMESTAMP", + onUpdate: "CURRENT_TIMESTAMP", + }) + updated_at: Date; + } \ No newline at end of file diff --git a/backend/src/entities/project.entity.ts b/backend/src/entities/project.entity.ts new file mode 100644 index 00000000..a3d168a9 --- /dev/null +++ b/backend/src/entities/project.entity.ts @@ -0,0 +1,67 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToMany, + JoinTable, + CreateDateColumn, + UpdateDateColumn, + } from "typeorm"; + import { Field, ID, ObjectType } from "type-graphql"; + import { SkillSubItem } from "./skillSubItem.entity"; +import { Length } from "class-validator"; + + @ObjectType() + @Entity() + export class Project { + @Field(() => ID) + @PrimaryGeneratedColumn() + id: number; + + @Field() + @Column({ length: 100 }) + @Length(1, 100, { + message: "Title must have between 1 to 100 characters", + }) + title: string; + + @Field() + @Column("text") + descriptionFR: string; + + @Field() + @Column("text") + descriptionEN: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "TypeDisplay must have between 1 to 50 characters", + }) + typeDisplay: string; + + @Field({ nullable: true }) + @Column({ nullable: true }) + github: string | null; + + @Field() + @Column("text") + contentDisplay: string; + + @Field(() => [SkillSubItem]) + @ManyToMany(() => SkillSubItem, { cascade: true }) + @JoinTable() + skills: SkillSubItem[]; + + @Field() + @CreateDateColumn({ default: () => "CURRENT_TIMESTAMP" }) + created_at: Date; + + @Field() + @UpdateDateColumn({ + name: "updated_at", + default: () => "CURRENT_TIMESTAMP", + onUpdate: "CURRENT_TIMESTAMP", + }) + updated_at: Date; + } \ No newline at end of file diff --git a/backend/src/entities/skill.entity.ts b/backend/src/entities/skill.entity.ts new file mode 100644 index 00000000..4ac7009b --- /dev/null +++ b/backend/src/entities/skill.entity.ts @@ -0,0 +1,51 @@ +import { + Entity, + PrimaryGeneratedColumn, + CreateDateColumn, + Column, + UpdateDateColumn, + OneToMany, + } from "typeorm"; + import { Length } from "class-validator"; + import { Field, ID, ObjectType } from "type-graphql"; + import { SkillSubItem } from "./skillSubItem.entity"; + + @ObjectType() + @Entity() + export class Skill { + @Field(() => ID) + @PrimaryGeneratedColumn() + id: number; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "Category must have between 1 to 50 characters", + }) + categoryFR: string; + + @Field() + @Column({ length: 50 }) + @Length(1, 50, { + message: "Category must have between 1 to 50 characters", + }) + categoryEN: string; + + @Field(() => [SkillSubItem]) + @OneToMany(() => SkillSubItem, (skillSubItem) => skillSubItem.skill, { + cascade: true, + }) + skills: SkillSubItem[]; + + @Field() + @CreateDateColumn({ default: () => "CURRENT_TIMESTAMP" }) + created_at: Date; + + @Field() + @UpdateDateColumn({ + name: "updated_at", + default: () => "CURRENT_TIMESTAMP", + onUpdate: "CURRENT_TIMESTAMP", + }) + update_at: Date; + } \ No newline at end of file diff --git a/backend/src/entities/skillSubItem.entity.ts b/backend/src/entities/skillSubItem.entity.ts new file mode 100644 index 00000000..2392d71b --- /dev/null +++ b/backend/src/entities/skillSubItem.entity.ts @@ -0,0 +1,32 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + } from "typeorm"; + import { Field, ID, ObjectType } from "type-graphql"; + import { Skill } from "./skill.entity"; + + @ObjectType() + @Entity() + export class SkillSubItem { + @Field(() => ID) + @PrimaryGeneratedColumn() + id: number; + + @Field() + @Column({ length: 50 }) + name: string; + + @Field() + @Column({ nullable: true }) + image: string; + + @Field() + @Column({ length: 50 }) + category: string; + + @Field(() => Skill) + @ManyToOne(() => Skill, (skill) => skill.skills) + skill: Skill; + } \ No newline at end of file diff --git a/backend/src/entities/user.entity.ts b/backend/src/entities/user.entity.ts deleted file mode 100644 index 5acfc37d..00000000 --- a/backend/src/entities/user.entity.ts +++ /dev/null @@ -1 +0,0 @@ -// User Entity.... \ No newline at end of file diff --git a/backend/src/resolvers/contact.resolver.ts b/backend/src/resolvers/contact.resolver.ts index 264929e2..2c1b2fbd 100644 --- a/backend/src/resolvers/contact.resolver.ts +++ b/backend/src/resolvers/contact.resolver.ts @@ -23,19 +23,13 @@ import { checkRegex, emailRegex } from "../regex"; @Resolver() export class ContactResolver { - @Query(() => String) - async contact(@Ctx() context: MyContext): Promise { - console.log(context) - return "ok"; - } - @Mutation(() => MessageType) async sendContact(@Arg("data", () => ContactFrom) data: ContactFrom, @Ctx() context: MyContext): Promise { - // if (!context.apiKey) - // throw new Error('Unauthorized TOKEN API'); + if (!context.apiKey) + throw new Error('Unauthorized TOKEN API'); - // await checkApiKey(context.apiKey); + await checkApiKey(context.apiKey); if (!checkRegex(emailRegex, data.email)) throw new Error("Invaid format email."); diff --git a/backend/src/services/user.service.ts b/backend/src/services/user.service.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/src/types/contact.types.ts b/backend/src/types/contact.types.ts index 3fe2a7e2..1180c146 100644 --- a/backend/src/types/contact.types.ts +++ b/backend/src/types/contact.types.ts @@ -10,7 +10,6 @@ export class ContactFrom { @Field() message: string; - } @ObjectType() @@ -23,5 +22,4 @@ export class ContactResponse { @Field() message: string; - } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f0a20fb5..06f43fd6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,29 +10,29 @@ services: - WDS_SOCKET_HOST=127.0.0.1 - CHOKIDAR_USEPOLLING=true - WATCHPACK_POLLING=true - depends_on: - db: - condition: service_healthy + # depends_on: + # db: + # condition: service_healthy env_file: - ./backend/.env - db: - image: postgres:15 - ports: - - 5432:5432 - restart: always - healthcheck: - test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB} -U ${POSTGRES_USER}"] - interval: 5s - timeout: 5s - retries: 10 - environment: - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} - env_file: - - ./.env - volumes: - - portfolio-data:/var/lib/postgresql/data + # db: + # image: postgres:15 + # ports: + # - 5432:5432 + # restart: always + # healthcheck: + # test: ["CMD-SHELL", "pg_isready -d ${POSTGRES_DB} -U ${POSTGRES_USER}"] + # interval: 5s + # timeout: 5s + # retries: 10 + # environment: + # - POSTGRES_USER=${POSTGRES_USER} + # - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + # - POSTGRES_DB=${POSTGRES_DB} + # env_file: + # - ./.env + # volumes: + # - portfolio-data:/var/lib/postgresql/data frontend: # build: ./frontend build: