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(routes): adjust pages routing #4

Merged
merged 5 commits into from
Sep 13, 2023
Merged
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
1 change: 0 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
/coverage/
/dist/
/node_modules/
/gulpfile.js
/package-lock.json
/src/_headers
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ Configuration is performed through Cloudflare Pages' Environment variables.

### Settings

| Environment Variable | Required | Default | Description |
| -------------------- | -------- | ------- | ---------------------------------------------------------- |
| `short-code-length` | No | 4 | The length to use for automatically generated short-codes. |
| `link-to-dash` | No | false | Set to true to show a link to your |
| Environment Variable | Required | Default | Description |
| -------------------- | -------- | ------- | ------------------------------------------------------------------------------------- |
| `DOMAIN` | **YES** | | The domain for your URL shortener. This will be used as the base for your short URLs. |
| `SHORT_CODE_LENGTH` | No | 4 | The length to use for automatically generated short-codes. |
| `LINK_TO_DASH` | No | false | Set to true to show a link to your dashboard on the public home page. |

## Application Data

Expand Down
10 changes: 7 additions & 3 deletions functions/url.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Env, CreateUrlFormData, UrlRow, DeleteUrlFormData } from '../src/ts/types'
import { Env, CreateUrlFormData, UrlRow, DeleteUrlFormData, UrlDatatableResponse } from '../src/ts/types'
import { createUrl, deleteUrl, getRowByLongUrl, getRowByShortCode, getUrls } from '../src/ts/data'
import { DEFAULT_RESPONSE_HEADERS } from '../src/ts/const'
import { generateShortCode, isValidShortCode, isValidUrl } from '../src/ts/url'
Expand All @@ -11,7 +11,7 @@ import { convertFormDataToJson } from '../src/ts/form'
* @returns {Promise<Response>} Response object.
*/
export const onRequestGet: PagesFunction<Env> = async function (context) {
const output = { data: [{}] }
const output: UrlDatatableResponse = { data: [] }
const allRows: UrlRow[] = await getUrls(context)
for (const row of allRows) {
output.data.push({ s: row.short, l: row.long, c: row.created })
Expand Down Expand Up @@ -110,7 +110,11 @@ export const onRequestPost: PagesFunction<Env> = async function (context) {
let count = 0
do {
const toShorten = requestDetails.long + (count > 0 ? count.toString() : '')
requestDetails.short = await generateShortCode(toShorten, context)
const shortCodeEnvLength = context.env.SHORT_CODE_LENGTH
requestDetails.short = await generateShortCode(
toShorten,
shortCodeEnvLength != null ? parseInt(shortCodeEnvLength) : undefined
)
// Make sure the auto-generated short code does not collide with an existing record.
shortRow = await getRowByShortCode(requestDetails.short, context)
count++
Expand Down
60 changes: 38 additions & 22 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import webpack from 'webpack-stream'
import replace from 'gulp-replace'
const sass = gulpSass(dartSass)
let packageJson
let domain

const paths = {
html: {
Expand All @@ -29,33 +30,43 @@ const paths = {
src: 'src/assets/js/app.js',
dest: 'dist/assets/js/'
},
json: {
src: 'src/*.json',
dest: 'dist/'
},
scss: {
src: 'src/assets/scss/*.scss',
dest: 'dist/assets/css/'
}
}

// Get Package information from package.json
async function getPackageInfo () {
async function getPackageInfo() {
packageJson = JSON.parse(fs.readFileSync('package.json'))
domain = process.env.DOMAIN || ''
if (domain.startsWith('https://')) {
domain = domain.substring(8)
}

return Promise.resolve()
}

// Wipe the dist directory
export async function clean () {
export async function clean() {
return deleteSync(['dist/'])
}

// Minify HTML
async function html () {
return gulp.src(paths.html.src)
async function html() {
return gulp
.src(paths.html.src)
.pipe(fileinclude({ prefix: '@@', basepath: 'src/include/' }))
.pipe(replace('{{commit-hash}}', process.env.CF_PAGES_COMMIT_SHA))
.pipe(replace('{{branch-name}}', process.env.CF_PAGES_BRANCH))
.pipe(replace('{{environment}}', process.env.CF_PAGES_BRANCH === 'main' ? 'production' : 'development'))
.pipe(replace('{{sentry-dsn}}', process.env.SENTRY_DSN))
.pipe(replace('{{domain}}', process.env.CF_PAGES_URL))
.pipe(replace('{{link-to-dash}}', (process.env.LINK_TO_DASH ? '<a href="dash">Manage</a>' : '')))
.pipe(replace('{{domain}}', domain))
.pipe(replace('{{link-to-dash}}', process.env.LINK_TO_DASH ? '<a href="dash">Manage</a>' : ''))
.pipe(replace('{{package-name}}', packageJson.name))
.pipe(replace('{{package-version}}', packageJson.version))
.pipe(
Expand All @@ -76,8 +87,9 @@ async function html () {
}

// Minify JavaScript
async function js () {
return gulp.src(paths.js.src)
async function js() {
return gulp
.src(paths.js.src)
.pipe(named())
.pipe(
webpack({
Expand All @@ -92,9 +104,12 @@ async function js () {
multiple: [
{ search: '{{commit-hash}}', replace: process.env.CF_PAGES_COMMIT_SHA },
{ search: '{{branch-name}}', replace: process.env.CF_PAGES_BRANCH },
{ search: '{{environment}}', replace: process.env.CF_PAGES_BRANCH === 'main' ? 'production' : 'development' },
{
search: '{{environment}}',
replace: process.env.CF_PAGES_BRANCH === 'main' ? 'production' : 'development'
},
{ search: '{{sentry-dsn}}', replace: process.env.SENTRY_DSN },
{ search: '{{domain}}', replace: process.env.CF_PAGES_URL },
{ search: '{{domain}}', replace: domain },
{ search: '{{package-name}}', replace: packageJson.name },
{ search: '{{package-version}}', replace: packageJson.version }
]
Expand All @@ -119,34 +134,35 @@ async function js () {
}

// Compile SCSS
async function scss () {
return gulp.src(paths.scss.src)
async function scss() {
return gulp
.src(paths.scss.src)
.pipe(sass({ outputStyle: 'compressed' }))
.pipe(gulp.dest(paths.scss.dest))
}

// Move JSON
async function json() {
return gulp.src(paths.json.src).pipe(gulp.dest(paths.json.dest))
}

// Compress images
async function img () {
return gulp.src(paths.img.src)
async function img() {
return gulp
.src(paths.img.src)
.pipe(imagemin([imageminSvgo()]))
.pipe(gulp.dest(paths.img.dest))
}

// Watch for changes
function watchSrc () {
function watchSrc() {
console.warn('Watching for changes... Press [CTRL+C] to stop.')
gulp.watch([paths.html.src, paths.htmlinclude], html)
gulp.watch(paths.scss.src, scss)
gulp.watch(paths.img.src, img)
gulp.watch(paths.js.src, js)
}

export default gulp.series(
getPackageInfo,
js,
img,
scss,
html
)
export default gulp.series(getPackageInfo, js, img, scss, json, html)

export const watch = gulp.series(getPackageInfo, watchSrc)
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@
"ts-standard": {
"globals": [],
"ignore": [
"/tests/**/*.ts"
"/tests/**/*.ts",
"/gulpfile.js"
]
},
"prettier": {
Expand Down
20 changes: 20 additions & 0 deletions src/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
@@include('meta.html')
<link rel="stylesheet" href="assets/css/min.css" />
</head>
<body>
<main>
<h1>404 - Not Found</h1>
<p>The page you requested could not be found.<br />Please check your link and try again.</p>
<p>&nbsp;</p>
<h1>{{domain}}</h1>
<p>@@include('attribution.html')</p>
<p>
<a href="https://github.com/aensley/bus"><img src="assets/img/logo.svg" alt="bus logo" id="tinyLogo" /></a>
</p>
</main>
<footer>{{link-to-dash}}</footer>
</body>
</html>
5 changes: 5 additions & 0 deletions src/_routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": 1,
"include": ["/*"],
"exclude": ["/dash", "/"]
}
12 changes: 6 additions & 6 deletions src/assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const setSelectors = () => {
})
}

const getShortUrlA = (short, copy) => {
const getShortUrl = (short, copy) => {
return (
'<a' +
(copy ? ' title="Copy Short URL"' : '') +
Expand All @@ -80,7 +80,7 @@ const getShortUrlA = (short, copy) => {
)
}

const getLongUrlA = (long, copy) => {
const getLongUrl = (long, copy) => {
return '<a' + (copy ? ' class="copy" title="Copy Long URL"' : '') + ' href="' + long + '">' + long + '</a>'
}

Expand Down Expand Up @@ -124,8 +124,8 @@ const updateTable = () => {

const handleDeleteClick = function () {
const data = listTable.row($(this).parents('tr')[0]).data()
$deleteConfirmShort.html(getShortUrlA(data.s, false))
$deleteConfirmLong.html(getLongUrlA(data.l, false))
$deleteConfirmShort.html(getShortUrl(data.s, false))
$deleteConfirmLong.html(getLongUrl(data.l, false))
dcModal.show()
$deleteConfirmButton.data('short', data.s)
}
Expand Down Expand Up @@ -157,7 +157,7 @@ const setupDataTable = () => {
className: 'text-nowrap',
render: (data, type) => {
if (type === 'display') {
return getShortUrlA(data, true)
return getShortUrl(data, true)
}

return data
Expand All @@ -168,7 +168,7 @@ const setupDataTable = () => {
className: 'dt-overflow align-middle',
render: (data, type) => {
if (type === 'display') {
return '<span>' + getLongUrlA(data, true) + '</span>'
return '<span>' + getLongUrl(data, true) + '</span>'
}

return data
Expand Down
11 changes: 11 additions & 0 deletions src/ts/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface Env {
URLKV: KVNamespace
URLD1: D1Database
SHORT_CODE_LENGTH: string
}

export interface UrlRow {
Expand All @@ -17,3 +18,13 @@ export interface CreateUrlFormData {
export interface DeleteUrlFormData {
short: string
}

export interface UrlDatatableResponse {
data: UrlDatatableRow[]
}

interface UrlDatatableRow {
s: string
l: string
c: number
}
8 changes: 2 additions & 6 deletions src/ts/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@ import { DEFAULT_SHORT_CODE_LENGTH, RESERVED_CODES } from './const'
* @param {any} [context] The request context.
* @returns {Promise<string>} The short code.
*/
export const generateShortCode = async function (long: string, context?: any): Promise<string> {
const shortCodeLength: number =
context != null
? ((await context.env.default.get('SHORT_CODE_LENGTH')) as number) ?? DEFAULT_SHORT_CODE_LENGTH
: DEFAULT_SHORT_CODE_LENGTH

export const generateShortCode = async function (long: string, shortCodeEnvLength?: number): Promise<string> {
const shortCodeLength: number = shortCodeEnvLength != null ? shortCodeEnvLength : DEFAULT_SHORT_CODE_LENGTH
return bytesToHex(blake3(long)).substring(0, shortCodeLength)
}

Expand Down