Skip to content

Commit

Permalink
link model done
Browse files Browse the repository at this point in the history
  • Loading branch information
JaneJeon committed Sep 26, 2019
1 parent e92c517 commit e2964af
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 121 deletions.
3 changes: 2 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ version: 2
jobs:
build:
docker:
- image: circleci/node:lts
- image: circleci/node:10 # test on AWS Lambda supported runtimes
- image: circleci/mongo
- image: localstack/localstack

steps:
Expand Down
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
HASH_MIN_LENGTH=6
HASH_SALT=
HASH_MAX_LENGTH=100
DOMAIN=foo.bar
MONGODB_URI=mongodb://localhost/myURL
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ This aggressive caching of redirects should make requests instantaneous, while t

The feature set is more tuned for internal use:

- [ ] Implement atomic counter on DDB
- [ ] hash(id) => url
- [ ] set of normalized URLs? (one of these have to be global secondary index. Warning: eventual consistency!)
- [ ] ~~Implement atomic counter on DDB~~
- [x] hash(id) => url
- [x] set of normalized URLs? (one of these have to be global secondary index. Warning: eventual consistency!)
- [ ] static page (S3) to actually make these requests
- [ ] Some form of access control
- [ ] Infrastructure as Code (some way to deploy and configure all this)
Expand Down
Empty file removed functions/.gitkeep
Empty file.
12 changes: 12 additions & 0 deletions lib/mongoose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const mongoose = require('mongoose')

mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
mongoose.connection.on('error', err => {
console.error(err)
process.exit(1)
})

module.exports = mongoose
46 changes: 33 additions & 13 deletions models/link.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
const { URL } = require('url')
const normalizeUrl = require('normalize-url')
const HashIds = require('hashids/cjs')
const hash = new HashIds(process.env.HASH_SALT, process.env.HASH_MIN_LENGTH - 0)
const hash = new HashIds(process.env.DOMAIN, process.env.HASH_MIN_LENGTH - 0)

class Link {
constructor(link) {
this.url = normalizeUrl(link, { stripProtocol: true })
}
const mongoose = require('../lib/mongoose')
const AutoIncrement = require('mongoose-sequence')(mongoose)

async exists() {
// TODO: check if this link exists
}
const schema = new mongoose.Schema(
{
_id: {
type: Number,
get: id => hash.encode(id)
},
url: {
type: String,
required: true,
trim: true,
minlength: process.env.HASH_MIN_LENGTH,
maxlength: process.env.HASH_MAX_LENGTH,
validate: [
{
validator: url => new URL(url).host !== process.env.DOMAIN,
msg: `Cannot shorten ${process.env.DOMAIN} URLs`
}
],
set: url => normalizeUrl(url, { forceHttps: true }),
unique: true
}
},
{ _id: false }
)

async save() {
// TODO: fetch next ID
hash.encode(1)
}
schema.plugin(require('mongoose-unique-validator'))
schema.plugin(AutoIncrement)
schema.statics.findByHashId = function(hashId) {
return this.findById(hash.decode(hashId)[0])
}

module.exports = Link
module.exports = mongoose.model('Link', schema)
20 changes: 11 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
"license": "AGPL-3.0",
"scripts": {
"deploy": "node ./bin/deploy",
"lint": "run-s 'lint:all:* {@}' -- --",
"lint:fix": "run-s lint:fix:*",
"lint:all:eslint": "eslint .",
"lint:all:prettier": "prettier --check '**/*.{js,md,json,yml,yaml}'",
"lint:fix:eslint": "yarn lint:all:eslint --fix",
"lint:fix:prettier": "yarn lint:all:prettier --write",
"test": "jest --passWithNoTests",
"lint": "run-s lint:*",
"lint:eslint": "eslint .",
"lint:prettier": "prettier --check '**/*.{js,md,json,yml,yaml}'",
"test": "jest --forceExit",
"coverage": "is-ci && codecov",
"clean": "rimraf build"
},
"jest": {
"testEnvironment": "node"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
Expand Down Expand Up @@ -57,17 +57,19 @@
"singleQuote": true
},
"dependencies": {
"aws-sdk": "^2.536.0",
"chalk": "^2.4.2",
"commander": "^3.0.1",
"dotenv": "^8.1.0",
"hashids": "^2.0.1",
"mongoose": "^5.7.1",
"mongoose-sequence": "^5.2.1",
"mongoose-unique-validator": "^2.0.3",
"normalize-url": "^4.4.1"
},
"devDependencies": {
"@types/jest": "^24.0.18",
"codecov": "^3.6.1",
"cross-env": "^6.0.0",
"dotenv": "^8.1.0",
"eslint": "^6.4.0",
"eslint-config-prettier": "^6.3.0",
"eslint-config-standard": "^14.1.0",
Expand Down
Empty file removed test/.gitkeep
Empty file.
28 changes: 28 additions & 0 deletions test/link.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require('dotenv').config()
const Link = require('../models/link')

describe('Link model', () => {
const url = 'www.nodejs.org'
const normalizedURL = 'https://nodejs.org'
let id

beforeAll(async () => {
return Link.deleteMany({})
})

test('shorten URL', async () => {
const link = new Link({ url })
const doc = await link.save()
id = doc.id

expect(doc.id).toBeDefined()
expect(typeof doc.id).toBe('string')
expect(doc.id.length).toBeGreaterThanOrEqual(6)
})

test('fetch URL', async () => {
const doc = await Link.findByHashId(id)

expect(doc.url).toBe(normalizedURL)
})
})
Loading

0 comments on commit e2964af

Please sign in to comment.