initial commit
This commit is contained in:
parent
f962b2f9da
commit
5a0501d110
75
app.js
Normal file
75
app.js
Normal file
@ -0,0 +1,75 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var path = require('path');
|
||||
var bodyParser = require('body-parser');
|
||||
var mongoose = require('mongoose');
|
||||
var config = require('./config');
|
||||
var base58 = require('./base58.js');
|
||||
|
||||
// grab the url model
|
||||
var Url = require('./models/url');
|
||||
|
||||
mongoose.connect('mongodb://' + config.db.host + '/' + config.db.name);
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.sendFile(path.join(__dirname, 'views/index.html'));
|
||||
});
|
||||
|
||||
app.post('/api/shorten', function(req, res){
|
||||
var longUrl = req.body.url;
|
||||
var shortUrl = '';
|
||||
|
||||
// check if url already exists in database
|
||||
Url.findOne({long_url: longUrl}, function (err, doc){
|
||||
if (doc){
|
||||
shortUrl = config.webhost + base58.encode(doc._id);
|
||||
|
||||
// the document exists, so we return it without creating a new entry
|
||||
res.send({'shortUrl': shortUrl});
|
||||
} else {
|
||||
// since it doesn't exist, let's go ahead and create it:
|
||||
var newUrl = Url({
|
||||
long_url: longUrl
|
||||
});
|
||||
|
||||
// save the new link
|
||||
newUrl.save(function(err) {
|
||||
if (err){
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
shortUrl = config.webhost + base58.encode(newUrl._id);
|
||||
|
||||
res.send({'shortUrl': shortUrl});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
app.get('/:encoded_id', function(req, res){
|
||||
|
||||
var base58Id = req.params.encoded_id;
|
||||
|
||||
var id = base58.decode(base58Id);
|
||||
|
||||
// check if url already exists in database
|
||||
Url.findOne({_id: id}, function (err, doc){
|
||||
if (doc) {
|
||||
res.redirect(doc.long_url);
|
||||
} else {
|
||||
res.redirect(config.webhost);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var server = app.listen(3000, function(){
|
||||
console.log('Server listening on port 3000');
|
||||
});
|
26
base58.js
Normal file
26
base58.js
Normal file
@ -0,0 +1,26 @@
|
||||
var alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
var base = alphabet.length;
|
||||
|
||||
function encode(num){
|
||||
var encoded = '';
|
||||
while (num){
|
||||
var remainder = num % base;
|
||||
num = Math.floor(num / base);
|
||||
encoded = alphabet[remainder].toString() + encoded;
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
function decode(str){
|
||||
var decoded = 0;
|
||||
while (str){
|
||||
var index = alphabet.indexOf(str[0]);
|
||||
var power = str.length - 1;
|
||||
decoded += index * (Math.pow(base, power));
|
||||
str = str.substring(1);
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
module.exports.encode = encode;
|
||||
module.exports.decode = decode;
|
9
config.js
Normal file
9
config.js
Normal file
@ -0,0 +1,9 @@
|
||||
var config = {};
|
||||
|
||||
config.db = {};
|
||||
config.webhost = 'http://localhost:3000/';
|
||||
|
||||
config.db.host = 'localhost';
|
||||
config.db.name = 'url_shortener';
|
||||
|
||||
module.exports = config;
|
31
models/url.js
Normal file
31
models/url.js
Normal file
@ -0,0 +1,31 @@
|
||||
var mongoose = require('mongoose');
|
||||
var Schema = mongoose.Schema;
|
||||
|
||||
var CounterSchema = Schema({
|
||||
_id: {type: String, required: true},
|
||||
seq: { type: Number, default: 0 }
|
||||
});
|
||||
|
||||
var counter = mongoose.model('counter', CounterSchema);
|
||||
|
||||
// create a schema for our links
|
||||
var urlSchema = new Schema({
|
||||
_id: {type: Number, index: true},
|
||||
long_url: String,
|
||||
created_at: Date
|
||||
});
|
||||
|
||||
urlSchema.pre('save', function(next){
|
||||
var doc = this;
|
||||
counter.findByIdAndUpdate({_id: 'url_count'}, {$inc: {seq: 1} }, function(error, counter) {
|
||||
if (error)
|
||||
return next(error);
|
||||
doc.created_at = new Date();
|
||||
doc._id = counter.seq;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
var Url = mongoose.model('Url', urlSchema);
|
||||
|
||||
module.exports = Url;
|
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "url-shortener",
|
||||
"version": "1.0.0",
|
||||
"description": "A NodeJS + Express + MongoDB based URL shortener",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "coligo.io",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.14.1",
|
||||
"express": "^4.13.3",
|
||||
"mongoose": "4.2.9"
|
||||
}
|
||||
}
|
87
public/css/styles.css
Normal file
87
public/css/styles.css
Normal file
@ -0,0 +1,87 @@
|
||||
.btn:focus, .btn-shorten:focus{
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: #4791D2;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-family: 'Raleway', sans-serif;
|
||||
}
|
||||
|
||||
.btn-shorten {
|
||||
color: #ffffff;
|
||||
background-color: #F89406;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-shorten:hover,
|
||||
.btn-shorten:focus,
|
||||
.btn-shorten:active,
|
||||
.btn-shorten.active {
|
||||
color: #ffffff;
|
||||
background-color: #FA8900;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.site-wrapper {
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.site-wrapper-inner {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.inner {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.inner h4 {
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.glyphicon-link {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.inner h1 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#link {
|
||||
display: none;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
#link a{
|
||||
color: #F89406;
|
||||
font-size: 1.5em;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.main-container {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.main-container {
|
||||
width: 700px;
|
||||
}
|
||||
}
|
16
public/javascripts/shorten.js
Normal file
16
public/javascripts/shorten.js
Normal file
@ -0,0 +1,16 @@
|
||||
$('.btn-shorten').on('click', function(){
|
||||
|
||||
$.ajax({
|
||||
url: '/api/shorten',
|
||||
type: 'POST',
|
||||
dataType: 'JSON',
|
||||
data: {url: $('#url-field').val()},
|
||||
success: function(data){
|
||||
var resultHTML = '<a class="result" href="' + data.shortUrl + '">'
|
||||
+ data.shortUrl + '</a>';
|
||||
$('#link').html(resultHTML);
|
||||
$('#link').hide().fadeIn('slow');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
55
views/index.html
Normal file
55
views/index.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>URL Shortener - coligo.io</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
|
||||
<link href="css/styles.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="site-wrapper">
|
||||
|
||||
<div class="site-wrapper-inner">
|
||||
|
||||
<div class="main-container">
|
||||
|
||||
<div class="inner cover">
|
||||
<span class="glyphicon glyphicon-link"></span>
|
||||
<h1>URL Shortener</h1>
|
||||
<h4>coligo.io</h4>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="input-group input-group-lg">
|
||||
<input id="url-field" type="text" class="form-control" placeholder="Paste a link...">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-shorten" type="button">SHORTEN</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div id="link"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||
<script src="javascripts/shorten.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user