initial commit

This commit is contained in:
Fady 2016-02-07 16:16:07 -05:00
parent f962b2f9da
commit 5a0501d110
8 changed files with 315 additions and 0 deletions

75
app.js Normal file
View 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
View 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
View 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
View 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
View 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
View 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;
}
}

View 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
View 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>