add url shortner

This commit is contained in:
Simon Larsen 2023-07-01 12:58:59 +01:00
parent d724932660
commit f18bb3a3de
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
4 changed files with 160 additions and 1 deletions

View File

@ -0,0 +1,45 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Model/Models/ShortLink';
import DatabaseService, { OnCreate } from './DatabaseService';
import CreateBy from '../Types/Database/CreateBy';
import Text from 'Common/Types/Text';
import URL from 'Common/Types/API/URL';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
this.hardDeleteItemsOlderThanInDays("createdAt", 3); //expire links in 3 days.
}
protected override async onBeforeCreate(
createBy: CreateBy<Model>
): Promise<OnCreate<Model>> {
createBy.data.shortId = Text.generateRandomText(8);
return { createBy: createBy, carryForward: [] };
}
public async saveShortLinkFor(url: URL): Promise<Model> {
const model: Model = new Model();
model.link = url;
return await this.create({ data: model, props: { isRoot: true } });
}
public async getShortLinkFor(shortLinkId: string): Promise<Model | null> {
return await this.findOneBy({
query: {
shortId: shortLinkId,
},
select: {
_id: true,
link: true,
},
props: {
isRoot: true,
},
});
}
}
export default new Service();

View File

@ -0,0 +1,32 @@
import Express, {
ExpressRequest,
ExpressResponse,
ExpressRouter,
} from 'CommonServer/Utils/Express';
import Response from 'CommonServer/Utils/Response';
import BadDataException from 'Common/Types/Exception/BadDataException';
import ShortLinkService from 'CommonServer/Services/ShortLinkService';
import ShortLink from 'Model/Models/ShortLink';
const router: ExpressRouter = Express.getRouter();
router.get(
'/:id',
async (req: ExpressRequest, res: ExpressResponse) => {
if(!req.params['id']){
return Response.sendErrorResponse(req, res, new BadDataException("id is required"));
}
const link: ShortLink | null = await ShortLinkService.getShortLinkFor(
req.params['id']
);
if (!link || !link.link) {
return Response.sendErrorResponse(req, res, new BadDataException("This URL is invalid or expired"));
}
return Response.redirect(req, res, link.link);
}
);

View File

@ -5,9 +5,11 @@ import App from 'CommonServer/Utils/StartServer';
import { PostgresAppInstance } from 'CommonServer/Infrastructure/PostgresDatabase';
import logger from 'CommonServer/Utils/Logger';
const APP_NAME: string = 'l';
app.use([`/${APP_NAME}/`, '/'], LinkShortnerAPI);
const app: ExpressApplication = Express.getExpressApp();
const init: Function = async (): Promise<void> => {

80
Model/Models/ShortLink.ts Normal file
View File

@ -0,0 +1,80 @@
import { Column, Entity, Index } from 'typeorm';
import BaseModel from 'Common/Models/BaseModel';
import CrudApiEndpoint from 'Common/Types/Database/CrudApiEndpoint';
import Route from 'Common/Types/API/Route';
import TableColumnType from 'Common/Types/Database/TableColumnType';
import TableColumn from 'Common/Types/Database/TableColumn';
import ColumnType from 'Common/Types/Database/ColumnType';
import ColumnLength from 'Common/Types/Database/ColumnLength';
import TableAccessControl from 'Common/Types/Database/AccessControl/TableAccessControl';
import ColumnAccessControl from 'Common/Types/Database/AccessControl/ColumnAccessControl';
import TableMetadata from 'Common/Types/Database/TableMetadata';
import IconProp from 'Common/Types/Icon/IconProp';
import URL from 'Common/Types/API/URL';
@TableAccessControl({
create: [],
read: [
],
delete: [],
update: [],
})
@CrudApiEndpoint(new Route('/short-link'))
@Entity({
name: 'ShortLink',
})
@TableMetadata({
tableName: 'ShortLink',
singularName: 'Short Link',
pluralName: 'Short Links',
icon: IconProp.Link,
tableDescription:
'Short links are used to redirect users to a specific long link in OneUptime.',
})
export default class SmsLog extends BaseModel {
@ColumnAccessControl({
create: [],
read: [
],
update: [],
})
@Index()
@TableColumn({
required: true,
type: TableColumnType.ShortText,
title: 'Short Link ID',
description: 'Random ID for the short link',
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.ShortText,
length: ColumnLength.ShortText,
})
public shortId?: string = undefined;
@ColumnAccessControl({
create: [],
read: [
],
update: [],
})
@TableColumn({
required: true,
type: TableColumnType.LongURL,
title: 'Long URL',
description: 'Long URL to redirect to',
canReadOnRelationQuery: false,
})
@Column({
nullable: false,
type: ColumnType.LongURL,
transformer: URL.getDatabaseTransformer(),
})
public link?: URL = undefined;
}