Skip to content

Commit

Permalink
Added what-wg url validation and create shortcut endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ashrash committed Oct 15, 2022
1 parent 5286703 commit 1cdac12
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 12 deletions.
3 changes: 2 additions & 1 deletion DDL.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ CREATE TABLE `shortcuts`
(
`short_link` varchar(60) NOT NULL ,
`email_id` varchar(100) NOT NULL ,
`url` varchar(100) NOT NULL ,
`description` varchar(250) NOT NULL ,
`created_dttm` datetime NOT NULL ,
`update_dttm` datetime NOT NULL ,
`updated_dttm` datetime NOT NULL ,

PRIMARY KEY (`short_link`),
KEY `FK_2` (`email_id`),
Expand Down
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
},
"dependencies": {
"@types/bcrypt": "^5.0.0",
"@types/whatwg-url": "^11.0.0",
"bcrypt": "^5.1.0",
"class-validator": "^0.13.2",
"compression": "^1.7.4",
Expand All @@ -61,6 +62,7 @@
"sequelize": "^6.25.1",
"swagger-jsdoc": "^6.2.1",
"swagger-ui-express": "^4.1.6",
"whatwg-url": "^5.0.0",
"winston": "^3.7.2",
"winston-daily-rotate-file": "^4.6.1"
}
Expand Down
15 changes: 14 additions & 1 deletion src/controllers/shortcut.controller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ShortcutData } from '@/interfaces/shortcuts.interface';
import { NextFunction, Request, Response } from 'express';
import { CreatedUserData, UserData } from '../interfaces/user.interface';
import shortcutService from '../services/shortcut.service';
Expand All @@ -8,7 +9,19 @@ class ShortcutController {
public getShortcutsByEmail = async (req: Request, res: Response, next: NextFunction) => {
try {
const email: string = req.params.email;
const findOneUserData: UserData = await this.shortcutService.findUserDataByEmail(email);
const findOneUserData: UserData = await this.shortcutService.findShortcutDataByEmail(email);

res.status(200).json({ data: findOneUserData, message: 'findOne' });
} catch (error) {
next(error);
}
};

public createShortcut = async (req: Request, res: Response, next: NextFunction) => {
try {
const email: string = req.params.email;
const shortcut: ShortcutData = req.body;
const findOneUserData: UserData = await this.shortcutService.createShortcut(email, shortcut);

res.status(200).json({ data: findOneUserData, message: 'findOne' });
} catch (error) {
Expand Down
17 changes: 17 additions & 0 deletions src/dtos/shortcut.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { IsString, IsNotEmpty } from 'class-validator';

export class CreateShortcutDto {

@IsString()
@IsNotEmpty()
public short_link: string;

@IsString()
@IsNotEmpty()
public description: string;

@IsString()
@IsNotEmpty()
public url: string;

}
1 change: 1 addition & 0 deletions src/interfaces/shortcuts.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface ShortcutData {
short_link: string;
email_id: string;
description: string;
url: string;
created_dttm: string;
update_dttm: string;
}
Expand Down
9 changes: 5 additions & 4 deletions src/models/shortcut.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ const Shortcut = (sequelize, Sequelize, DataTypes) => {
email_id: {
type: DataTypes.STRING,
},
description: {
type: DataTypes.STRING
url: {
type: DataTypes.STRING,
},
created_dttm: {
description: {
type: DataTypes.STRING
}
},
{
timestamps: false
createdAt: "created_dttm",
updatedAt: "updated_dttm"
}
);
return Shortcut;
Expand Down
3 changes: 2 additions & 1 deletion src/models/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const User = (sequelize, Sequelize, DataTypes) => {
}
},
{
timestamps: false
createdAt: "created_dttm",
updatedAt: "updated_dttm"
}
);
return User;
Expand Down
4 changes: 1 addition & 3 deletions src/routes/shortcut.route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Router } from 'express';
import ShortcutController from '../controllers/shortcut.controller';
import { Routes } from '../interfaces/routes.interface';
import validationMiddleware from '../middleware/validation.middleware';
import { verifyToken } from '../middleware/jwt.middleware';

import { CreateUserDto, LoginUserDto } from '../dtos/users.dto';

class ShortcutRoute implements Routes {
public route = '/shortcuts';
public router = Router();
Expand All @@ -17,6 +14,7 @@ class ShortcutRoute implements Routes {

private initializeRoutes() {
this.router.get(`${this.route}/:email`, verifyToken, this.shortcutController.getShortcutsByEmail);
this.router.post(`${this.route}/:email`, verifyToken, this.shortcutController.createShortcut);
}
}

Expand Down
31 changes: 29 additions & 2 deletions src/services/shortcut.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { UserShortcut } from '../interfaces/user.interface';
import { HttpException } from '../utils/exception';
import * as R from 'ramda';
import * as whatwg from 'whatwg-url';
import Db from '../models';
import { nullCheck } from '../utils/ramda';
import { ShortcutData } from '@/interfaces/shortcuts.interface';
import { logger } from '../utils/logger';

class ShortcutService {

public async findUserDataByEmail(email: string): Promise<UserShortcut| null> {
public async findShortcutDataByEmail(email: string): Promise<UserShortcut| null> {
if (nullCheck(email)) throw new HttpException(400, "email is undefined");

const resultData: UserShortcut = await Db.User.findAll({
Expand All @@ -17,8 +21,31 @@ class ShortcutService {
email,
}
});
const userShortcuts: UserShortcut = R.head(resultData);
if(!nullCheck(userShortcuts)) {
return userShortcuts;
}
throw new HttpException(204, "Shortcuts not found");
}

return resultData;
public async createShortcut(email: string, shortcut: ShortcutData): Promise<UserShortcut| null> {
if (nullCheck(email)) throw new HttpException(400, "email is undefined");
try {
const { short_link, description, url } = shortcut;
const validateResult = whatwg.parseURL(url);
if(R.equals(validateResult, 'failure')) {
throw new HttpException(400, "invalid url, please follow the what-wg url standard")
}
const createdShortcut = await Db.Shortcut.create({
short_link, description, url, email_id: email,
created_dttm: new Date(),
}, { fields: ['short_link', 'description', 'url', 'email_id', 'created_dttm'] });

return createdShortcut;
} catch(e){
logger.error(`Something went wrong ${e}`);
throw new HttpException(500, `Something went wrong ${e}`);
}
}


Expand Down

0 comments on commit 1cdac12

Please sign in to comment.