Browse Source

changed framework related things, made profile and register pages work

master
mort 8 years ago
parent
commit
6e4d7d6caa

+ 45
- 10
lib/context.js View File

@@ -4,21 +4,18 @@ var preprocess = require("./preprocess.js");

var sessions = {};

function templatify(str, args, ctx) {
function templatify(str, args, ctx, env) {
env.url = ctx.req.url;

str = preprocess(str, {
session: ctx.session,
arg: args,
env: env,
template: function(key) {
return ctx.template(key);
}
});

if (args == undefined)
return str;

for (var i in args) {
str = str.split("{{"+i+"}}").join(args[i]);
}

return str;
}

@@ -29,6 +26,9 @@ module.exports = function(options) {
this.views = options.views;
this.db = options.db;
this.conf = options.conf;
this.query = this.req.url.split("?")[1] || "";
if (this.conf.debug)
this.startTime = new Date();

//Handle cookies
this.cookies = {};
@@ -61,6 +61,17 @@ module.exports = function(options) {

module.exports.prototype = {
end: function(str) {
if (this.conf.debug) {
var ms = (new Date().getTime() - this.startTime.getTime());
console.log(
ms+" millisecond(s)\t"+
(this.statusCode || 200)+"\t"+
this.req.url
);
} else {
conole.log(this.req.url);
}

if (this.statusCode)
this.res.writeHead(this.statusCode);

@@ -93,7 +104,7 @@ module.exports.prototype = {
if (!str)
throw new Error("No such template: "+name);

return templatify(str, args, this);
return templatify(str, args, this, {template: name});
},

view: function(name, args) {
@@ -101,7 +112,7 @@ module.exports.prototype = {
if (!str)
throw new Error("No such view: "+name);

return templatify(str, args, this);
return templatify(str, args, this, {view: name});
},

getPostData: function(cb) {
@@ -138,5 +149,29 @@ module.exports.prototype = {
this.session.loggedIn = false;
delete this.session.username;
delete this.session.userId;
},

async: function(n, cb) {
if (typeof n !== "number")
throw new Error("Expected number, got "+typeof n);

if (n < 1)
return cb();

var res = {};
var errs = {};
var errnum = 0;

return function(key, val, err) {
if (key)
res[key] = val;
if (err)
errs[key] = err;

if (n === 1)
cb((errnum ? errs : null), res);
else
n -= 1;
}
}
}

+ 42
- 2
server.js View File

@@ -26,6 +26,11 @@ var endpoints = {
"/register/style.css": "register/style.css",
"/register/script.js": "register/script.js",

//Profile
"/profile": "profile/index.node.js",
"/profile/style.css": "profile/style.css",
"/profile/script.js": "profile/script.js",

//Viewer
"/view": "view/index.node.js",
"/view/style.css": "view/style.css",
@@ -48,8 +53,6 @@ var db = new pg.Client(conf.db);

//Function to run on each request
function onRequest(req, res) {
console.log("Request for "+req.url);

var ctx = new Context({
req: req,
res: res,
@@ -100,3 +103,40 @@ if (!conf.debug) {
console.trace(err);
});
}

function command(tokens) {
switch(tokens[0]) {

//Reload configuration
case "reload-conf":
var c = JSON.parse(fs.readFileSync("conf.json"));
for (var i in c)
conf[i] = c[i];
break;

//Reload HTML
case "reload-html":
var l = loader.load(endpoints, conf);
for (var i in l)
loaded[i] = l[i];
break;

//Reload everything
case "reload":
command(["reload-conf"]);
command(["reload-html"]);
break;

default: return false;
}
return true;
}

process.stdin.on("data", function(line) {
var tokens = line.toString().split(/\s+/);
if (command(tokens)) {
return console.log(tokens[0]+" completed successfully.");
} else {
return console.log("Command not found: "+tokens[0]);
}
});

templates/global.html → templates/body.html View File


+ 4
- 0
templates/collection.html View File

@@ -0,0 +1,4 @@
<div class="collection">
<a class="name" href="/view?{{arg#id}}">{{arg#name}}</a>
<span class="date-created">{{arg#date_created}}</span>
</div>

+ 4
- 0
templates/head.html View File

@@ -1,8 +1,12 @@
<title>{{conf#title}}</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">

<link rel="stylesheet" href="/global.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="/{{env#view}}/style.css">

<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="/global.js"></script>
<script src="/{{env#view}}/script.js"></script>

+ 4
- 4
templates/image.html View File

@@ -1,6 +1,6 @@
<div class="image">
<div class="title">{{title}}</div>
<img class="img-rounded" src="/i?{{id}}.{{extension}}">
<div class="description">{{description}}</div>
<input class="url" type="text" value="{{conf#base_url}}/i?{{id}}.{{extension}}" onclick="select()">
<div class="title">{{arg#title}}</div>
<img class="img-rounded" src="/i?{{arg#id}}.{{arg#extension}}">
<div class="description">{{arg#description}}</div>
<input class="url" type="text" value="{{conf#base_url}}/i?{{arg#id}}.{{arg#extension}}" onclick="select()">
</div>

+ 1
- 1
templates/navbar-loggedin.html View File

@@ -1,3 +1,3 @@
<li>
<a href="/profile?{{session#userId}}">{{session#username}}</a>
<a id="navbar-button" href="/profile?{{session#userId}}">{{session#username}}</a>
</li>

+ 1
- 1
templates/navbar-login.html View File

@@ -1,5 +1,5 @@
<li class="dropdown" id="login-dropdown">
<a href="#" data-toggle="dropdown" class="dropdown-toggle" style="float: right">
<a href="#" data-toggle="dropdown" class="dropdown-toggle" id="navbar-button">
Log In
<b class="caret"></b>
</a>

+ 2
- 1
views/404.html View File

@@ -4,6 +4,7 @@
<meta charset="utf-8">
</head>
<body>
404, file not found.
404, file not found.<br>
{{env#url}}
</body>
</html>

+ 1
- 4
views/index.html View File

@@ -2,10 +2,9 @@
<html>
<head>
{{template#head}}
<link rel="stylesheet" href="/index/style.css">
</head>
<body>
{{template#global}}
{{template#body}}

<div id="uploader" class="container">
<input type="file" accept="image/*" id="uploader-input" class="hidden" multiple>
@@ -19,7 +18,5 @@

<ul class="list-group" id="uploader-list"></ul>
</div>

<script src="/index/script.js"></script>
</body>
</html>

+ 16
- 0
views/profile.html View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
{{template#head}}
</head>
<body>
{{template#body}}

<div id="profile" class="container">
<div id="collections" class="container">
<div class="name">{{arg#username}}</div>
{{arg#collections}}
</div>
</div>
</body>
</html>

+ 2
- 5
views/register.html View File

@@ -2,10 +2,9 @@
<html>
<head>
{{template#head}}
<link rel="stylesheet" href="/register/style.css">
</head>
<body>
{{template#global}}
{{template#body}}

<div class="container" id="register">
<form id="register-form">
@@ -21,7 +20,7 @@
</div>
<div class="form-group">
<label>Repeat Password<br>
<input type="psasword" id="register-password-repeat">
<input type="password" id="register-password-repeat">
</label>
</div>
<div class="submit-container">
@@ -29,7 +28,5 @@
</div>
</form>
</div>

<script src="/index/script.js"></script>
</body>
</html>

+ 2
- 5
views/view.html View File

@@ -2,15 +2,12 @@
<html>
<head>
{{template#head}}
<link rel="stylesheet" href="/view/style.css">
</head>
<body>
{{template#global}}
{{template#body}}

<div id="viewer" class="container">
{{images}}
{{arg#images}}
</div>

<script src="/index/script.js"></script>
</body>
</html>

+ 1
- 1
web/api/account_create.node.js View File

@@ -27,7 +27,7 @@ module.exports = function(ctx) {
if (err)
return ctx.fail(err);

ctx.login(ctx.postData.username, res.rows[0].id);
ctx.login(ctx.postData.data.username, res.rows[0].id);

ctx.succeed({
id: res.rows[0].id

+ 2
- 2
web/api/account_login.node.js View File

@@ -23,11 +23,11 @@ module.exports = function(ctx) {

var user = res.rows[0];

ctx.login(user.username, user.id);

if (!user)
return ctx.fail("Wrong username or password.");

ctx.login(user.username, user.id);

scrypt.verify(
new Buffer(user.pass_hash, "hex"),
new Buffer(ctx.postData.data.password),

+ 3
- 3
web/api/collection_create.node.js View File

@@ -4,10 +4,10 @@ module.exports = function(ctx) {
return ctx.fail(err);

ctx.db.query(
"INSERT INTO collections (name) "+
"VALUES ($1) "+
"INSERT INTO collections (name, user_id) "+
"VALUES ($1, $2) "+
"RETURNING id",
[data.name],
[data.name, ctx.session.userId],
queryCallback
);
});

+ 1
- 1
web/api/template.node.js View File

@@ -1,5 +1,5 @@
module.exports = function(ctx) {
var name = ctx.req.url.split("?")[1];
var name = ctx.query;
if (!name)
return ctx.fail("You must supply a template name.");


+ 4
- 0
web/global.css View File

@@ -10,6 +10,10 @@
padding: 10px;
}

#navbar-button {
float: right;
}

#login-dropdown label,
#login-dropdown input {
width: 100%;

+ 38
- 2
web/global.js View File

@@ -1,4 +1,19 @@
(function() {
var months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]

window.util = {};

util.notify = function notify(title, body) {
@@ -69,8 +84,8 @@

var res = {};

return function(key, val) {
if (key !== undefined)
return function(key, val, err) {
if (key)
res[key] = val;

if (n === 1)
@@ -80,6 +95,25 @@
}
}

util.pad = function(str, length, padChar) {
var missing = (length - str.length) + 1;

if (missing <= 0)
return str;

return new Array(missing).join(padChar) + str;
}

util.dateToString = function(date) {
var day = util.pad(date.getDate().toString(), 2, "0");
var month = months[date.getMonth()];

return day+". of "+month+" "+
date.getFullYear()+", "+
util.pad(date.getHours().toString(), 2, "0")+":"+
util.pad(date.getMinutes().toString(), 2, "0");
}

window.display = {};

window.display.loggedIn = function() {
@@ -88,6 +122,8 @@
return util.error(err);

$("#navbar-profile-container").html(res.html);

util.notify("Logged In", "You are now logged in.");
});
}


+ 2
- 5
web/i/index.node.js View File

@@ -1,12 +1,9 @@
var fs = require("fs");

module.exports = function(ctx) {
var id;
try {
id = ctx.req.url.split("?")[1].replace(/\..*/, "");
} catch (err) {
var id = ctx.query.replace(/\..*/, "");
if (!id)
return ctx.end(ctx.view("404"));
}

var readStream = fs.createReadStream(ctx.conf.dir.imgs+"/"+id);
readStream.pipe(ctx.res);

+ 4
- 3
web/index/script.js View File

@@ -1,4 +1,4 @@
(function() {
$(document).on("ready", function() {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
notify("Your Browser Sucks.");
}
@@ -21,9 +21,10 @@
var files = [];

$("#uploader-input").on("change", function(evt) {
console.log(evt);

//Enable upload button
$("#uploader-upload").removeAttr("disabled")
$("#uploader-upload").removeAttr("disabled");

var inputFiles = evt.target.files;

@@ -115,4 +116,4 @@
});
});
});
})();
});

+ 44
- 0
web/profile/index.node.js View File

@@ -0,0 +1,44 @@
module.exports = function(ctx) {
var id = ctx.query;

ctx.db.query(
"SELECT name, date_created, id "+
"FROM collections "+
"WHERE user_id = $1",
[id],
function(err, res) { a("collections", res.rows, err) }
);

ctx.db.query(
"SELECT username "+
"FROM users "+
"WHERE id = $1",
[id],
function(err, res) { a("users", res.rows, err) }
);

var a = ctx.async(2, function(err, res) {
if (err)
return ctx.fail(err);

var user = res.users[0];
if (!user)
return ctx.end(ctx.view("404"));

var collections = "";
res.collections.forEach(function(row) {
var d = new Date(row.date_created);

collections += ctx.template("collection", {
name: row.name,
date_created: d.toString(),
id: row.id
});
});

ctx.end(ctx.view("profile", {
username: user.username,
collections: collections
}));
});
}

+ 5
- 0
web/profile/script.js View File

@@ -0,0 +1,5 @@
$(document).on("ready", function() {
$("#collections .date-created").each(function() {
this.innerHTML = util.dateToString(new Date(this.innerHTML));
});
});

+ 9
- 0
web/profile/style.css View File

@@ -0,0 +1,9 @@
#profile {
text-align: center;
}

#collections {
text-align: left;
width: auto;
display: inline-block;
}

+ 34
- 0
web/register/script.js View File

@@ -0,0 +1,34 @@
$(document).on("ready", function() {
$("#register-form").on("submit", function(evt) {
console.log(evt);
evt.preventDefault();
evt.stopPropagation();

var username = $("#register-username").val();
var password = $("#register-password").val();
var password2 = $("#register-password-repeat").val();

if (password !== password2)
return util.error("Paswords don't match.");

if (!username)
return util.error("You must supply a username.");

if (!password)
return util.error("You must supply a password.");

util.api("account_create", {
username: username,
password: password
}, function(err, res) {
if (err)
return util.error(err);

display.loggedIn();

setTimeout(function() {
location.href = "/profile?"+res.id;
}, 1000);
});
});
});

+ 4
- 1
web/view/index.node.js View File

@@ -1,5 +1,5 @@
module.exports = function(ctx) {
var id = parseInt(ctx.req.url.split("?")[1]);
var id = parseInt(ctx.query);

if (isNaN(id))
return ctx.end(ctx.view("404"));
@@ -16,6 +16,9 @@ module.exports = function(ctx) {
if (err)
return ctx.fail(err);

if (!res.rows[0])
return ctx.end(ctx.view("404"));

var images = "";
res.rows.forEach(function(row) {
images += ctx.template("image", {

Loading…
Cancel
Save