Skip to content

Commit

Permalink
migrate: to v2 (#6)
Browse files Browse the repository at this point in the history
* migrate: to v2

* refactor query filter

* fix title of default value empty string

* fix ordering column
  • Loading branch information
ayocodingit authored Aug 13, 2024
1 parent 09d45d4 commit 92f526b
Show file tree
Hide file tree
Showing 17 changed files with 207 additions and 83 deletions.
3 changes: 2 additions & 1 deletion src/database/sequelize/interface.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ModelStatic, Sequelize } from 'sequelize'
import { ModelStatic, Op, Sequelize } from 'sequelize'

export type Model = ModelStatic<any>

export type Schema = {
short_link: Model
// Add other models if needed
Op: typeof Op
}

export type Connection = Sequelize
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ export async function up(queryInterface: QueryInterface) {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: true,
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
},
short_code: {
type: DataTypes.STRING,
allowNull: false,
Expand Down Expand Up @@ -40,7 +49,12 @@ export async function up(queryInterface: QueryInterface) {
},
})
.then(() => {
return queryInterface.addIndex(tableName, ['short_code'])
return queryInterface.addIndex(tableName, [
'short_code',
'title',
'is_active',
'expired',
])
})
}

Expand Down
9 changes: 9 additions & 0 deletions src/database/sequelize/schemas/short_link.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ const ShortLink = (connection: Connection) => {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: true,
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
},
short_code: {
type: DataTypes.STRING,
allowNull: false,
Expand Down
6 changes: 5 additions & 1 deletion src/database/sequelize/sequelize.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Config } from '../../config/config.interface'
import Logger from '../../pkg/logger'
import { Sequelize as createConnection, Dialect } from 'sequelize'
import { Sequelize as createConnection, Dialect, Op } from 'sequelize'
import { Connection } from './interface'
import ShortLink from './schemas/short_link.schema'

Expand Down Expand Up @@ -47,6 +47,10 @@ class Sequalize {
return {
short_link,
// Add other models if needed

// Add other require of the driver database
connection,
Op,
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions src/helpers/http.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios'
import { RegexContentTypeImage } from './regex'
import { RegexContentTypeHtml } from './regex'
import error from '../pkg/error'

export const RemoveProcotol = (url: string) => {
return url.replace('http://', '').replace('https://', '')
Expand All @@ -10,20 +11,22 @@ export const GetDomain = (subdomain: string, domain: string) => {
return `${subdomain}.${domain}`
}

export const GetImageUrl = async (url: string) => {
export const GetObjectUrl = async (url: string) => {
try {
const { data, status, headers } = await axios(url, {
responseType: 'arraybuffer',
})
const contentType = headers['content-type'] || ''

if (status === 200 && !RegexContentTypeImage.test(contentType)) return
if (status === 200 && RegexContentTypeHtml.test(contentType)) return

return {
data: data,
content_type: contentType,
}
} catch (error) {
return
} catch (err: any) {
const message = err.message

throw new error(err.status, message)
}
}
13 changes: 13 additions & 0 deletions src/helpers/joi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Joi from 'joi'

export const uriWithSpaces = (
value: string,
helpers: Joi.CustomHelpers<string>
) => {
try {
new URL(value)
return value
} catch (error) {
return helpers.error('string.uri')
}
}
29 changes: 0 additions & 29 deletions src/helpers/regex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
RegexSubdomain,
RegexSanitize,
RegexObjectID,
RegexContentTypeImage,
} from './regex'

describe('RegexWordScript', () => {
Expand Down Expand Up @@ -59,31 +58,3 @@ describe('RegexObjectID Test', () => {
expect(emptyString).not.toMatch(RegexObjectID)
})
})

describe('RegexContentTypeImage', () => {
it('should match valid image content type', () => {
const validContentTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/svg+xml',
]

validContentTypes.forEach((contentType) => {
expect(RegexContentTypeImage.test(contentType)).toBe(true)
})
})

it('should not match invalid content types', () => {
const invalidContentTypes = [
'text/plain',
'application/json',
'image',
'',
]

invalidContentTypes.forEach((contentType) => {
expect(RegexContentTypeImage.test(contentType)).toBe(false)
})
})
})
2 changes: 1 addition & 1 deletion src/helpers/regex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export const RegexSubdomain = /^[ a-z0-9-]+$/
export const RegexPath = /^[ a-zA-Z0-9-_]+$/
export const RegexSanitize = /^[ a-zA-Z0-9_,.()'"&-/]+$/
export const RegexObjectID = /^[0-9a-fA-F]{24}$/
export const RegexContentTypeImage = /^image\//
export const RegexContentTypeHtml = /^text\/html/
10 changes: 5 additions & 5 deletions src/helpers/requestParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export interface RequestParams {
page: number
offset: number
limit: number
order_by: string
sort_by: string
sort_order: string
keyword: string
[key: string]: any
Expand All @@ -12,10 +12,10 @@ export const GetRequestParams = (query: Record<string, any>): RequestParams => {
const limit = Number(query.limit) || 10
const page = Number(query.page) || 1
const offset = limit * (page - 1)
let { q, sort_order, order_by } = query
let { q, sort_order, sort_by } = query

if (!['asc', 'desc'].includes(order_by)) {
order_by = 'asc'
if (!['asc', 'desc'].includes(sort_order)) {
sort_order = 'asc'
}

return {
Expand All @@ -24,7 +24,7 @@ export const GetRequestParams = (query: Record<string, any>): RequestParams => {
offset,
limit,
sort_order,
order_by,
sort_by,
keyword: q,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const main = async () => {
const http = new Http(logger, config)

// Start Load Modules
new ShortLinks(logger, http, config, connection)
new ShortLinks(logger, config, connection).RunHttp(http)
// End Load Modules

http.Run(config.app.port.http)
Expand Down
48 changes: 40 additions & 8 deletions src/modules/short_links/delivery/http/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { NextFunction, Response } from 'express'
import statusCode from '../../../../pkg/statusCode'
import { ValidateFormRequest } from '../../../../helpers/validate'
import { RequestSchema } from '../../entity/schema'
import { GetImageUrl } from '../../../../helpers/http'
import { GetObjectUrl } from '../../../../helpers/http'
import { GetMeta, GetRequestParams } from '../../../../helpers/requestParams'

class Handler {
constructor(
Expand All @@ -25,13 +26,12 @@ class Handler {
req,
statusCode.OK
),
short_links: { FindByShortCode: data },
})

const image = await GetImageUrl(data.url)
if (image) {
res.setHeader('Content-Type', image.content_type)
return res.send(image.data)
const file = await GetObjectUrl(data.url)
if (file) {
res.setHeader('Content-Type', file.content_type)
return res.send(file.data)
}

return res.redirect(data.url)
Expand All @@ -44,7 +44,7 @@ class Handler {
public Show() {
return async (req: any, res: Response, next: NextFunction) => {
try {
const data = await this.usecase.Show(req.params.shortCode)
const data = await this.usecase.Show(req.params.id)

this.logger.Info(statusCode[statusCode.OK], {
additional_info: this.http.AdditionalInfo(
Expand All @@ -60,6 +60,25 @@ class Handler {
}
}

public Delete() {
return async (req: any, res: Response, next: NextFunction) => {
try {
await this.usecase.Delete(req.params.id)

this.logger.Info(statusCode[statusCode.OK], {
additional_info: this.http.AdditionalInfo(
req,
statusCode.OK
),
})

return res.json({ message: 'DELETED' })
} catch (error) {
return next(error)
}
}
}

public Store() {
return async (req: any, res: Response, next: NextFunction) => {
try {
Expand All @@ -70,7 +89,6 @@ class Handler {
req,
statusCode.CREATED
),
short_links: { store: body },
})
return res.status(statusCode.CREATED).json({
data: {
Expand All @@ -83,6 +101,20 @@ class Handler {
}
}
}

public Fetch = async (req: any, res: Response, next: NextFunction) => {
try {
const request = GetRequestParams(req.query)
const { data, count } = await this.usecase.Fetch(request)
this.logger.Info(statusCode[statusCode.OK], {
additional_info: this.http.AdditionalInfo(req, statusCode.OK),
})

return res.json({ data, meta: GetMeta(request, count) })
} catch (error) {
return next(error)
}
}
}

export default Handler
6 changes: 4 additions & 2 deletions src/modules/short_links/entity/interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export interface RequestBody {
export type RequestBody = {
url: string
short_link: string
short_code: string
expired: Date
is_active: boolean
title: string
}
7 changes: 5 additions & 2 deletions src/modules/short_links/entity/schema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Joi from 'joi'
import { RegexPath } from '../../../helpers/regex'
import { uriWithSpaces } from '../../../helpers/joi'

export const RequestSchema = Joi.object({
short_link: Joi.string().regex(RegexPath).optional(),
url: Joi.string().uri().required(),
short_code: Joi.string().min(6).max(255).regex(RegexPath).optional(),
url: Joi.string().custom(uriWithSpaces).required(),
expired: Joi.date().min(new Date()).optional(),
is_active: Joi.boolean().optional(),
title: Joi.string().alphanum().max(255).optional(),
})
Loading

0 comments on commit 92f526b

Please sign in to comment.