Skip to content

Commit

Permalink
Merge pull request hngprojects#80 from PreciousIfeaka/feat/4-create_o…
Browse files Browse the repository at this point in the history
…rganisation

[feat] Create organisation resource
  • Loading branch information
incredible-phoenix246 authored Jul 22, 2024
2 parents fde1a1f + c656d26 commit 62bd6e6
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 5 deletions.
24 changes: 24 additions & 0 deletions src/controllers/createorgController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NextFunction, Request, Response } from "express";
import { OrganisationService } from "../services/createOrg.services";

export const createOrganisation = async (req: Request, res: Response, next: NextFunction) => {
try {
const payload = req.body;
const user = req.user;
const userId = user.id;

const organisationService = new OrganisationService();
const newOrganisation = await organisationService.createOrganisation(payload, userId);

const respObj = {
status: "success",
message: "organisation created successfully",
data: newOrganisation,
status_code: 201
}

return res.status(201).json(respObj);
} catch (error) {
return next(error);
}
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { routeNotFound, errorHandler } from "./middleware";
import { orgRouter } from "./routes/organisation";
import swaggerUi from "swagger-ui-express";
import swaggerSpec from "./swaggerConfig";
import { organisationRoute } from "./routes/createOrg";

dotenv.config();

Expand All @@ -43,7 +44,7 @@ server.use(express.json());
server.get("/", (req: Request, res: Response) => {
res.send("Hello world");
});
server.use("/api/v1", userRouter, orgRouter);
server.use("/api/v1", userRouter, orgRouter, organisationRoute);
server.use("/api/v1/auth", authRoute);
server.use("/api/v1/help-center", helpRouter);
server.use("/api/v1/sms", smsRouter);
Expand Down
47 changes: 44 additions & 3 deletions src/models/organization.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm";
import { User } from "./user";
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToMany, BeforeInsert, UpdateDateColumn } from "typeorm";
import { User } from ".";
import {v4 as uuidv4} from "uuid"
import { UserOrganization } from "./user-organisation";
import ExtendedBaseEntity from "./extended-base-entity";

@Entity()
export class Organization extends ExtendedBaseEntity {
@PrimaryGeneratedColumn("uuid")
id: string;

@Column({ unique: true })
slug: string;

@Column()
name: string;

@Column()
@Column({ nullable: true })
email: string;

@Column({ nullable: true })
industry: string;

@Column({ nullable: true })
type: string;

@Column({ nullable: true })
country: string;

@Column({ nullable: true })
address: string;

@Column({ nullable: true })
state: string;

@Column('text', { nullable: true })
description: string;

@UpdateDateColumn()
created_at: Date;

@UpdateDateColumn()
updated_at: Date;

@Column('uuid')
owner_id: string;

@OneToMany(() => UserOrganization, userOrganization => userOrganization.organization)
userOrganizations: UserOrganization[];

@ManyToMany(() => User, (user) => user.organizations)
users: User[];

@BeforeInsert()
generateSlug() {
this.slug = uuidv4();
}
}

28 changes: 28 additions & 0 deletions src/models/user-organisation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Entity, ManyToOne, Column, PrimaryColumn, JoinColumn } from 'typeorm';
import { User } from "./user";
import { Organization } from "./organization";
import { UserRole } from '../enums/userRoles';
import ExtendedBaseEntity from './extended-base-entity';

@Entity()
export class UserOrganization extends ExtendedBaseEntity {
@PrimaryColumn()
userId: string;

@PrimaryColumn()
organizationId: string;

@ManyToOne(() => User, user => user.userOrganizations)
@JoinColumn({ name: 'userId' })
user: User;

@ManyToOne(() => Organization, organization => organization.userOrganizations)
@JoinColumn({ name: 'organizationId' })
organization: Organization;

@Column({
type: "enum",
enum: UserRole,
})
role: UserRole;
}
6 changes: 5 additions & 1 deletion src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
UpdateDateColumn,
} from "typeorm";
import { Profile, Product, Organization, Sms, Blog } from ".";
import { UserOrganization } from "./user-organisation";
import { IsEmail } from "class-validator";
import ExtendedBaseEntity from "./extended-base-entity";
import { getIsInvalidMessage } from "../utils";
Expand Down Expand Up @@ -62,7 +63,10 @@ export class User extends ExtendedBaseEntity {
@OneToMany(() => Blog, (blog) => blog.author)
blogs: Blog[];

@OneToMany(() => Sms, (sms) => sms.sender)
@OneToMany(() => UserOrganization, userOrganization => userOrganization.user)
userOrganizations: UserOrganization[];

@OneToMany(() => Sms, (sms) => sms.sender, { cascade: true })
sms: Sms[];

@ManyToMany(() => Organization, (organization) => organization.users, {
Expand Down
9 changes: 9 additions & 0 deletions src/routes/createOrg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Router } from "express";
import { authMiddleware } from "../middleware";
import { createOrganisation } from "../controllers/createorgController"

const organisationRoute = Router();

organisationRoute.post("/organisations", authMiddleware, createOrganisation);

export { organisationRoute }
38 changes: 38 additions & 0 deletions src/services/createOrg.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import AppDataSource from "../data-source";
import { Organization, User } from "../models";
import { UserRole } from "../enums/userRoles";
import { ICreateOrganisation, IOrganisationService } from "../types";
import { HttpError } from "../middleware";
import { UserOrganization } from "../models/user-organisation";

export class OrganisationService implements IOrganisationService {
public async createOrganisation(payload: ICreateOrganisation, userId: string): Promise<{
newOrganisation: Partial<Organization>;
}> {
try {
const organisation = new Organization();
organisation.owner_id = userId;
Object.assign(organisation, payload);

const newOrganisation = await AppDataSource.manager.save(organisation);

const userOrganization = new UserOrganization();
userOrganization.userId = userId;
userOrganization.organizationId = newOrganisation.id;
userOrganization.role = UserRole.ADMIN;

await AppDataSource.manager.save(userOrganization);

const user = await AppDataSource
.getRepository(User)
.findOne({ where: { id: userId }, relations: ["userOrganizations", "userOrganizations.organization"] });

user.userOrganizations.push(userOrganization);
await AppDataSource.getRepository(User).save(user);

return { newOrganisation };
} catch (error) {
throw new HttpError(error.status || 500, error.message || error);
}
}
}
15 changes: 15 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ export interface IAuthService {
verifyEmail(token: string, otp: number): Promise<{ message: string }>;
}

export interface ICreateOrganisation {
name: string;
description: string;
email: string;
industry: string;
type: string;
country: string;
address: string;
state: string;
}

export interface IOrganisationService {
createOrganisation(payload: ICreateOrganisation, userId: string): Promise<unknown>;
}

declare module "express-serve-static-core" {
interface Request {
user?: User;
Expand Down

0 comments on commit 62bd6e6

Please sign in to comment.