Skip to content

Commit

Permalink
[⚡️] - Adding informal, expiring, password and plus pages and rules.
Browse files Browse the repository at this point in the history
Signed-off-by: Binyamin Yawitz <[email protected]>
  • Loading branch information
byawitz committed Mar 17, 2024
1 parent 6fad7d3 commit e5acf04
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 13 deletions.
Binary file modified apps/linkos/bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions apps/linkos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@clickhouse/client-web": "^0.2.10",
"@types/inquirer": "^9.0.7",
"@types/nanoid": "^3.0.0",
"@types/nunjucks": "^3.2.6",
"@types/ua-parser-js": "^0.7.39",
"chalk": "^5.3.0",
"clickhouse": "^2.6.0",
Expand All @@ -23,6 +24,7 @@
"kafkajs": "^2.2.4",
"nanoid": "^5.0.6",
"node-appwrite": "^12.0.0",
"nunjucks": "^3.2.4",
"pg": "^8.11.3",
"redis": "^4.6.13",
"ua-parser-js": "^1.0.37"
Expand Down
82 changes: 82 additions & 0 deletions apps/linkos/src/assets/I.html

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions apps/linkos/src/assets/password.html

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions apps/linkos/src/assets/plus.html

Large diffs are not rendered by default.

98 changes: 85 additions & 13 deletions apps/linkos/src/http/api/LinkAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Log from "@/utils/Log.ts";
import Global from "@/utils/Global.ts";
import Env from "@/utils/Env.ts";
import ClickMessage from "@/models/ClickMessage.ts";

import nunjucks from 'nunjucks';

export default class LinkAPI {
private static producer: Producer | false;
Expand All @@ -27,31 +27,38 @@ export default class LinkAPI {
return LinkAPI.getRedirect(c, true)
}

private static async getRedirect(c: Context, qr: boolean = false) {
public static async getWithPassword(c: Context) {
const {link} = c.req.param();

try {
let shortLink: false | Link;
const body = await c.req.formData()
const password = body.get('password');

const linkFormRedis = await RedisProvider.getClient().get(link);
if (linkFormRedis !== null) {
shortLink = Global.ParseOrFalse(linkFormRedis);
} else {
shortLink = await Link.getLink(link);
let shortLink = await LinkAPI.getLink(link);

await RedisProvider.getClient().set(link, JSON.stringify(shortLink));
}
if (shortLink !== false && shortLink.password === password) {
return LinkAPI.redirect(shortLink.dest, c);
}

return c.redirect(`${Env.MAIN_DOMAIN}/${link}`);
}

private static async getRedirect(c: Context, qr: boolean = false) {
const {link} = c.req.param();

try {
let shortLink = await LinkAPI.getLink(link);

if (shortLink) {
await LinkAPI.missions(shortLink, qr, c);

return LinkAPI.redirect(this.appendQuery(shortLink.dest, c), c);
return LinkAPI.getLinkAction(shortLink, c, link);
}
} catch (e: any) {
Log.debug(e);
}

return c.html(await new Response(Bun.file(LinkAPI.path + "404.html")).text(), 404);

return LinkAPI.its404(c);
}

public static async getPublic(c: Context) {
Expand Down Expand Up @@ -82,6 +89,7 @@ export default class LinkAPI {
const start = +new Date();

if (LinkAPI.producer) {
// TODO: check for informal, password, etc.
await LinkAPI.producer.send({
topic : Analytics.TOPIC_CLICKHOUSE,
messages: [{value: (new AnalyticsMessage(link.id, qr, c.req.header())).toString()}]
Expand Down Expand Up @@ -114,4 +122,68 @@ export default class LinkAPI {
}


private static async getLinkAction(link: Link, c: Context, linkId: string) {
if (link.expiring_link && link.expiration_date !== undefined) {
if (+new Date(link.expiration_date) < +new Date()) {
return LinkAPI.its404(c);
}
}

if (link.password_protected) {
return c.html(LinkAPI.render('password', link));
} else if (link.plus_enabled && linkId.endsWith('+')) {
return c.html(LinkAPI.render('plus', link));
} else if (link.informal_redirection) {
return c.html(LinkAPI.render('i', link));
}

return LinkAPI.redirect(this.appendQuery(link.dest, c), c)
}

private static async render(page: string, link: Link) {
const text = await (new Response(Bun.file(`${LinkAPI.path}${page}.html`))).text();

return nunjucks.renderString(text, LinkAPI.linksContext(link));

}


private static linksContext(link: Link) {
return {
// TODO: Make language dynamic
lang : 'en',
dir : 'lrt',
goto_text : 'Go to',
link_target_text : 'Link destination',
password_placeholder_text: 'e.g. Aa123456',
enter_password_text : 'Password is required to access this short link destination',
form_target : `${Env.MAIN_DOMAIN}/password/${link.id}`,


title : link.title,
description: link.description,
link : link.dest,
};
}

private static async getLink(linkID: string) {
linkID = linkID.replace(/\+$/, '');

let shortLink: false | Link = false;

const linkFormRedis = await RedisProvider.getClient().get(linkID);
if (linkFormRedis !== null) {
shortLink = Global.ParseOrFalse(linkFormRedis);
} else {
shortLink = await Link.getLink(linkID);

await RedisProvider.getClient().set(linkID, JSON.stringify(shortLink));
}

return shortLink;
}

private static async its404(c: Context) {
return c.html(await new Response(Bun.file(LinkAPI.path + "404.html")).text(), 404);
}
}
1 change: 1 addition & 0 deletions apps/linkos/src/services/GetLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default class GetLink {
app.get('/', LinkAPI.getPublic);
app.get('/:link', LinkAPI.get);
app.get('/qr/:link', LinkAPI.getQr);
app.post('/password/:link', LinkAPI.getWithPassword);

Log.info('Starting serving Linkos getlink endpoint')
return app;
Expand Down

0 comments on commit e5acf04

Please sign in to comment.