Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add delete customer route #38

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions datasource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { DataSource } = require("typeorm");
const dotenv = require("dotenv");

dotenv.config()

const AppDataSource = new DataSource({
type: "postgres",
port: 5432,
port: process.env.DB_PORT,
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
host: process.env.DB_HOST,
entities: [
],
migrations: [
"dist/migrations/*.js",
],
})

module.exports = {
datasource: AppDataSource,
}
Binary file modified dump.rdb
Binary file not shown.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"seed": "medusa seed -f ./data/seed.json",
"start": "npm run build && medusa migrations run && medusa develop -p=8080",
"dev": "npm run build && medusa develop",
"build:admin": "medusa-admin build"
"build:admin": "medusa-admin build",
"migration:run": "npm run build && npx typeorm migration:run -d datasource.js",
"migration:generate": "npx typeorm migration:generate -d datasource.js"
},
"dependencies": {
"@babel/preset-typescript": "^7.21.5",
Expand Down Expand Up @@ -92,4 +94,4 @@
"engines": {
"node": ">=18.0.0"
}
}
}
10 changes: 7 additions & 3 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Router } from "express"
import express, { Router } from "express"
import {
getConfigFile,
} from "medusa-core-utils";
import { ConfigModule } from "@medusajs/medusa";
import cors from 'cors'
import { restrictUser } from "./routes/admin/restrict-user";
import validateUserNotDeactivated from "./middlewares/user-deactivation";
import { deleteCustomer } from "./routes/admin/delete-customer";

export default (rootDirectory: string): Router | Router[] => {
const { configModule: { projectConfig } } = getConfigFile<ConfigModule>(rootDirectory, "medusa-config")
Expand All @@ -16,9 +18,11 @@ export default (rootDirectory: string): Router | Router[] => {
const router = Router();
router.use(cors(storefrontCorsConfig))

const endpointHandlers = [restrictUser]

// middlewares
router.use('/store/auth', express.json(), validateUserNotDeactivated);

// endpoints
const endpointHandlers = [restrictUser, deleteCustomer]
endpointHandlers.forEach(endpointHandle => endpointHandle(router))

return router
Expand Down
15 changes: 15 additions & 0 deletions src/api/middlewares/user-deactivation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CustomerService } from "@medusajs/medusa";
import { NextFunction, Request, Response } from "express";

const validateUserNotDeactivated = async (req: Request, res: Response, next: NextFunction) => {
const customerService = req.scope.resolve('customerService') as CustomerService;

if (req.method.toLowerCase() === 'post' && req.body.email) {
const customer = await customerService.retrieveRegisteredByEmail(req.body.email);
console.log(customer);
}

next();
}

export default validateUserNotDeactivated;
18 changes: 18 additions & 0 deletions src/api/routes/admin/delete-customer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { authenticate } from "@medusajs/medusa"
import express, { Router } from "express";
import DeletedCustomerService from "../../../services/deleted-customer";

export const deleteCustomer = (router: Router) => {
router.use('/admin/delete-customer', express.json());

router.post('/admin/delete-customer', authenticate(), async (req, res) => {
const deletedCustomerService = req.scope.resolve('deletedCustomerService') as DeletedCustomerService;
try {
await deletedCustomerService.deleteCustomer(req.body.email);
return res.json({ status: 200, message: 'User has been deleted!' })
} catch (error) {
return res.status(500).json({ status: 500, message: 'An error occurred!', error: error instanceof Error ? error.message : error })
}

})
}
26 changes: 26 additions & 0 deletions src/migrations/1696512365971-DeletedCustomer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class DeletedCustomer1696512365971 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE IF NOT EXISTS "deleted_customer" (
"id" character varying NOT NULL,
"email" character varying NOT NULL,
"first_name" character varying NOT NULL,
"last_name" character varying NOT NULL,
"billing_address_id" character varying NOT NULL,
"password_hash" character varying NOT NULL,
"phone" character varying NOT NULL,
"has_account" boolean NOT NULL,
"created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"metadata" jsonb,
PRIMARY KEY ("id"),
CONSTRAINT "FK_deleted_customer_billing_address_id" FOREIGN KEY ("billing_address_id") REFERENCES "address"("id"))`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
}

}
15 changes: 15 additions & 0 deletions src/migrations/1696513431383-UpdateFieldDeleteCustomer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class UpdateFieldDeleteCustomer1696513431383 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "deleted_customer" ADD COLUMN "deleted_at" TIMESTAMP WITH TIME ZONE`
);
}


public async down(queryRunner: QueryRunner): Promise<void> {
}

}
13 changes: 13 additions & 0 deletions src/migrations/1696513616474-UpdateFieldDeleteCustomer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class UpdateFieldDeleteCustomer1696513616474 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "deleted_customer" ALTER COLUMN "billing_address_id" DROP NOT NULL`
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
}

}
14 changes: 14 additions & 0 deletions src/migrations/1696520782799-UpdateFieldDeleteCustomer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class UpdateFieldDeleteCustomer1696520782799 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "deleted_customer" ALTER COLUMN "phone" DROP NOT NULL`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
}

}
12 changes: 12 additions & 0 deletions src/migrations/1696521959509-AddUniqueConstraints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class AddUniqueConstraints1696521959509 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE deleted_customer ADD CONSTRAINT unique_email_id_constraint UNIQUE (email, id);`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
}

}
29 changes: 0 additions & 29 deletions src/migrations/README.md

This file was deleted.

7 changes: 7 additions & 0 deletions src/models/deleted-customer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Customer } from "@medusajs/medusa";
import { Entity } from "typeorm"

@Entity({ name: 'deleted_customer' })
export class DeletedCustomer extends Customer {

}
7 changes: 7 additions & 0 deletions src/repositories/deleted-customer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {
dataSource,
} from "@medusajs/medusa/dist/loaders/database"
import { DeletedCustomer } from "../models/deleted-customer"

export const DeletedCustomerRepository = dataSource.getRepository(DeletedCustomer)
export default DeletedCustomerRepository
53 changes: 53 additions & 0 deletions src/services/deleted-customer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Customer, CustomerService, TransactionBaseService } from '@medusajs/medusa'
import { DeletedCustomer } from '../models/deleted-customer';
import { Repository } from 'typeorm';
import DeletedCustomerRepository from '../repositories/deleted-customer';

export default class DeletedCustomerService extends TransactionBaseService {
protected readonly deletedCustomerRepository: Repository<DeletedCustomer>;
protected readonly customerService: CustomerService;

constructor(container) {
// @ts-ignore
super(container);
this.customerService = container.customerService;
this.deletedCustomerRepository = this.activeManager_.withRepository(DeletedCustomerRepository)
}

async deleteCustomer(email: string) {
try {
// Manually moving customer field to deleted_customer since medusa does not provides password hash in API.
const insertQuery = `
INSERT INTO deleted_customer (id, email, first_name, last_name, billing_address_id, password_hash, phone, has_account, created_at, updated_at, metadata)
SELECT id, email, first_name, last_name, billing_address_id, password_hash, phone, has_account, created_at, updated_at, metadata::jsonb
FROM customer
WHERE email = $1
ON CONFLICT (email, id) DO NOTHING;
`;
await this.activeManager_.query(insertQuery, [email]);


// delete customer from customer table

const customer = await this.customerService.retrieveRegisteredByEmail(email);

await this.customerService.delete(customer.id) as Customer

// update time of delete in deleted_customer

const updateDeleteTimestampQuery = `
UPDATE deleted_customer
SET deleted_at = now()
WHERE email = $1;
`;
const result = await this.activeManager_.query(updateDeleteTimestampQuery, [email])

return result;
} catch (error) {
// Handle any errors that may occur during the query.
console.error(error);
throw error;
}
}

}
Loading