Skip to content

Commit

Permalink
Merge pull request hngprojects#313 from Emeriego/feat/super-admin-del…
Browse files Browse the repository at this point in the history
…ete-an-organisation

feat: super admin delete an organisation
  • Loading branch information
incredible-phoenix246 authored Jul 26, 2024
2 parents b0c6f18 + 3a21397 commit 0116d34
Show file tree
Hide file tree
Showing 6 changed files with 1,017 additions and 792 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ build
issueformat.md
requests.rest
package-lock.json
docker-compose.yml
package-lock.json

111 changes: 111 additions & 0 deletions src/controllers/AdminController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,117 @@ class AdminOrganisationController {
.json({ message: error.message || "Internal Server Error" });
}
}

/**
* @swagger
* /api/v1/admin/organizations/{org_id}/delete:
* delete:
* summary: Admin-Delete an existing organization
* tags: [Admin]
* parameters:
* - in: path
* name: org_id
* required: true
* description: The ID of the organization to delete
* schema:
* type: string
* responses:
* 200:
* description: Organization deleted successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* status_code:
* type: integer
* message:
* type: string
* data:
* type: object
* properties:
* id:
* type: string
* name:
* type: string
* description:
* type: string
* createdAt:
* type: string
* format: date-time
* updatedAt:
* type: string
* format: date-time
* 400:
* description: Valid organization ID must be provided
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* status_code:
* type: integer
* message:
* type: string
* 404:
* description: Organization not found
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* status_code:
* type: integer
* message:
* type: string
* 500:
* description: Failed to delete organization. Please try again later.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* status_code:
* type: integer
* message:
* type: string
*/

// Delete organization
async deleteOrganization(req: Request, res: Response) {
const { org_id } = req.params;

if (!org_id) {
return res.status(400).json({
status: "unsuccessful",
status_code: 400,
message: "Valid organization ID must be provided.",
});
}

try {
await this.adminService.deleteOrganization(org_id);
res.status(200).json({
status: "success",
status_code: 200,
message: "Organization deleted successfully.",
});
} catch (error) {
res.status(500).json({
status: "unsuccessful",
status_code: 500,
message: "Failed to delete organization. Please try again later.",
});
}
}
}

class AdminUserController {
Expand Down
10 changes: 10 additions & 0 deletions src/routes/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ adminRouter.patch(
adminOrganisationController.updateOrg.bind(adminOrganisationController),
);

// Organisation
adminRouter.delete(
"/organizations/:org_id/delete",
authMiddleware,
checkPermissions([UserRole.SUPER_ADMIN]),
adminOrganisationController.deleteOrganization.bind(
adminOrganisationController,
),
);

// User
adminRouter.get(
"/users",
Expand Down
19 changes: 19 additions & 0 deletions src/services/admin.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,25 @@ export class AdminOrganisationService {
}
}

public async deleteOrganization(orgId: string): Promise<Organization> {
const organizationRepository = AppDataSource.getRepository(Organization);
const organization = await organizationRepository.findOne({
where: { id: orgId },
});

if (!organization) {
throw new HttpError(404, "Organization not found");
}

try {
await organizationRepository.remove(organization);
} catch (error) {
throw new HttpError(500, "Deletion failed");
}

return organization; // Return the deleted organization
}

public async setUserRole(req: Request): Promise<User> {
try {
const { role } = req.body;
Expand Down
102 changes: 102 additions & 0 deletions src/test/superadminDeleteOrg.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// @ts-nocheck
import AppDataSource from "../data-source";
import { HttpError } from "../middleware";
import { AdminOrganisationService } from "../services/admin.services";

jest.mock("../data-source");
jest.mock("../utils/index");

describe("AdminUserService", () => {
let consoleErrorMock: jest.SpyInstance;
let adminOrganisationService: AdminOrganisationService;

beforeAll(() => {
consoleErrorMock = jest
.spyOn(console, "error")
.mockImplementation(() => {});
});

afterAll(() => {
consoleErrorMock.mockRestore();
});

beforeEach(() => {
adminOrganisationService = new AdminOrganisationService();
});

describe("deleteOrganisation", () => {
it("should delete the organization successfully", async () => {
const orgId = "org123";
const mockOrganization = {
id: orgId,
name: "Test Organization",
description: "This is a test organization",
createdAt: new Date(),
updatedAt: new Date(),
} as Organization;

const mockRepository = {
findOne: jest.fn().mockResolvedValue(mockOrganization),
remove: jest.fn().mockResolvedValue(mockOrganization),
};

(AppDataSource.getRepository as jest.Mock).mockReturnValue(
mockRepository,
);

const result = await adminOrganisationService.deleteOrganization(orgId);

expect(mockRepository.findOne).toHaveBeenCalledWith({
where: { id: orgId },
});
expect(mockRepository.remove).toHaveBeenCalledWith(mockOrganization);
expect(result).toEqual(mockOrganization); // Ensure this matches the expected return value
});

it("should throw a 404 error if organization is not found", async () => {
const orgId = "nonexistentOrg";

const mockRepository = {
findOne: jest.fn().mockResolvedValue(null),
};

(AppDataSource.getRepository as jest.Mock).mockReturnValue(
mockRepository,
);

await expect(
adminOrganisationService.deleteOrganization(orgId),
).rejects.toThrow(HttpError);
await expect(
adminOrganisationService.deleteOrganization(orgId),
).rejects.toThrow("Organization not found");
});

it("should throw an error if deletion fails", async () => {
const orgId = "org123";
const mockOrganization = {
id: orgId,
name: "Test Organization",
description: "This is a test organization",
createdAt: new Date(),
updatedAt: new Date(),
} as Organization;

const mockRepository = {
findOne: jest.fn().mockResolvedValue(mockOrganization),
remove: jest.fn().mockRejectedValue(new Error("Deletion failed")),
};

(AppDataSource.getRepository as jest.Mock).mockReturnValue(
mockRepository,
);

await expect(
adminOrganisationService.deleteOrganization(orgId),
).rejects.toThrow(HttpError);
await expect(
adminOrganisationService.deleteOrganization(orgId),
).rejects.toThrow("Deletion failed");
});
});
});
Loading

0 comments on commit 0116d34

Please sign in to comment.