Browse Source

some restructuring, deliting collections now works

master
mort 8 years ago
parent
commit
4b3b34a465

+ 1
- 0
.gitignore View File

imgs imgs
!imgs/.placeholder !imgs/.placeholder
.currentRun .currentRun
.sessions
favicon.ico favicon.ico

+ 29
- 11
lib/context.js View File

var formidable = require("formidable"); var formidable = require("formidable");
var crypto = require("crypto"); var crypto = require("crypto");
var zlib = require("zlib"); var zlib = require("zlib");
var fs = require("fs");
var preprocess = require("./preprocess.js"); var preprocess = require("./preprocess.js");


var sessions = {}; var sessions = {};
var sessionTimeouts = {};

if (fs.existsSync(".sessions")) {
sessions = JSON.parse(fs.readFileSync(".sessions", "utf8"));

//Set appropriate timeouts.
Object.keys(sessions).forEach(function(i) {
sessionTimeouts[i] = setTimeout(function() {
delete sessions[i];
}, 1000*60*10);
});
}

function saveSessions() {
fs.writeFileSync(".sessions", JSON.stringify(sessions));
process.exit();
}

process.on("SIGINT", saveSessions);
process.on("SIGTERM", saveSessions);


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


str = preprocess(str, {
var env = {
session: function(key) { session: function(key) {
ctx.cachable = false; ctx.cachable = false;
return ctx.session[key]; return ctx.session[key];
noescape: args, noescape: args,
env: env, env: env,
template: function(key) { template: function(key) {
return ctx.template(key);
return ctx.template(key, args);
} }
});
}

str = preprocess(str, env);


return str; return str;
} }


sessions[key] = {}; sessions[key] = {};
this.res.setHeader("Set-Cookie", "session="+key); this.res.setHeader("Set-Cookie", "session="+key);

//Delete session after a while
setTimeout(function() {
delete sessions[key];
}, this.conf.session_timeout);
} }
this.session = sessions[key]; this.session = sessions[key];


//Reset session delete timer //Reset session delete timer
if (this.session._timeout)
clearTimeout(this.session._timeout);
if (sessionTimeouts[key])
clearTimeout(sessionTimeouts[key]);


this.session._timeout = setTimeout(function() {
sessionTimeouts[key] = setTimeout(function() {
delete sessions[key]; delete sessions[key];
}, this.conf.session_timeout); }, this.conf.session_timeout);
} }

+ 2
- 1
package.json View File

"pg": "^4.4.0", "pg": "^4.4.0",
"scrypt": "^4.0.7", "scrypt": "^4.0.7",
"uglify-js": "^2.4.24", "uglify-js": "^2.4.24",
"uglifycss": "0.0.15"
"uglifycss": "0.0.15",
"wrench": "^1.5.8"
} }
} }

+ 11
- 1
server.js View File

var fs = require("fs"); var fs = require("fs");
var domain = require("domain"); var domain = require("domain");
var zlib = require("zlib"); var zlib = require("zlib");
var wrench = require("wrench");
var loader = require("./lib/loader.js"); var loader = require("./lib/loader.js");
var pg = require("pg"); var pg = require("pg");
var Context = require("./lib/context.js"); var Context = require("./lib/context.js");
"/api/template": "api/template.node.js", "/api/template": "api/template.node.js",
"/api/image_create": "api/image_create.node.js", "/api/image_create": "api/image_create.node.js",
"/api/collection_create": "api/collection_create.node.js", "/api/collection_create": "api/collection_create.node.js",
"/api/collection_delete": "api/collection_delete.node.js",
"/api/account_create": "api/account_create.node.js", "/api/account_create": "api/account_create.node.js",
"/api/account_login": "api/account_login.node.js", "/api/account_login": "api/account_login.node.js",
"/api/account_logout": "api/account_logout.node.js", "/api/account_logout": "api/account_logout.node.js",
db.query( db.query(
"DELETE FROM collections "+ "DELETE FROM collections "+
"WHERE user_id IS NULL "+ "WHERE user_id IS NULL "+
"AND date_created < NOW() - INTERVAL '"+timeout+"'",
"AND date_created < NOW() - INTERVAL '"+timeout+"' "+
"RETURNING id",
function(err, res) { function(err, res) {
if (err) if (err)
throw err; throw err;


res.rows.forEach(function(row) {
wrench.rmdirSyncRecursive(
conf.dir.imgs+"/"+
row.id
);
});

if (res.rowCount > 0) { if (res.rowCount > 0) {
console.log( console.log(
"Deleted "+res.rowCount+" collections "+ "Deleted "+res.rowCount+" collections "+

+ 2
- 2
templates/collection.html View File

<div class="collection">
<div class="collection" data-id="{{arg#id}}">
<span class="date-created">{{arg#date_created}}</span> <span class="date-created">{{arg#date_created}}</span>
<a class="name" href="/view?{{arg#id}}">{{arg#name}}</a> <a class="name" href="/view?{{arg#id}}">{{arg#name}}</a>
{{arg#own_profile ? '<button class="delete btn btn-default">X</button>' : ''}}
{{arg#own_profile ? template#delete-button : ''}}
</div> </div>

+ 1
- 0
templates/delete-button.html View File

<button class="delete btn btn-default" data-id="{{arg#id}}">X</button>

+ 3
- 3
templates/image.html View File

<div class="image small-width bordered"> <div class="image small-width bordered">
<div class="title">{{arg#title}}</div> <div class="title">{{arg#title}}</div>
<a href="/i?{{arg#id}}.{{arg#extension}}">
<img class="img-rounded" src="/i?{{arg#id}}.{{arg#extension}}">
<a href="/i?{{arg#collection}}/{{arg#id}}.{{arg#extension}}">
<img class="img-rounded" src="/i?{{arg#collection}}/{{arg#id}}.{{arg#extension}}">
</a> </a>
<div class="description">{{arg#description}}</div> <div class="description">{{arg#description}}</div>
<input class="url" type="text" value="{{conf#base_url}}/i?{{arg#id}}.{{arg#extension}}" onclick="select()">
<input class="url" type="text" value="{{conf#base_url}}/i?{{arg#collection}}/{{arg#id}}.{{arg#extension}}" onclick="select()">
</div> </div>

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

var fs = require("fs");

module.exports = function(ctx) { module.exports = function(ctx) {
ctx.getPostData(function(err, data) { ctx.getPostData(function(err, data) {
if (err) if (err)
if (err) if (err)
return ctx.fail(err); return ctx.fail(err);


ctx.session.collectionId = res.rows[0].id;
var id = res.rows[0].id;

fs.mkdir(ctx.conf.dir.imgs+"/"+id, function(err) {
if (err)
return ctx.fail(err);

ctx.session.lastCollectionId = id;


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

+ 56
- 0
web/api/collection_delete.node.js View File

var wrench = require("wrench");

module.exports = function(ctx) {
ctx.getPostData(function(err, data) {
var id = parseInt(data.id);

if (isNaN(id))
return ctx.fail("Invalid ID.");

if (id === ctx.session.lastCollectionId)
return deleteQuery();

if (!ctx.session.loggedIn)
return ctx.fail("You're not logged in.");

ctx.db.query(
"SELECT FROM collections "+
"WHERE user_id = $1",
[ctx.session.userId],
function(err, res) {
if (err)
return ctx.fail(err);

if (res.rows[0] === undefined)
return ctx.fail("You don't own that collection.");

deleteQuery();
}
);
});

function deleteQuery() {
ctx.db.query(
"DELETE FROM collections "+
"WHERE id = $1",
[ctx.postData.data.id],
queryCallback
);
}

function queryCallback(err, res) {
if (err)
return ctx.fail(err);

try {
wrench.rmdirSyncRecursive(
ctx.conf.dir.imgs+"/"+
ctx.postData.data.id
);
} catch (err) {
return ctx.fail(err);
}

ctx.succeed();
}
}

+ 9
- 3
web/api/image_create.node.js View File



data.collectionId = parseInt(data.collectionId); data.collectionId = parseInt(data.collectionId);


if (data.collectionId !== ctx.session.collectionId)
if (data.lastCollectionId !== ctx.session.collectionId)
return ctx.fail("You don't own that collection."); return ctx.fail("You don't own that collection.");


//We want all extensions to be lower case. //We want all extensions to be lower case.
ctx.db.query( ctx.db.query(
"INSERT INTO images (name, description, extension, collection_id) "+ "INSERT INTO images (name, description, extension, collection_id) "+
"VALUES ($1, $2, $3, $4) "+ "VALUES ($1, $2, $3, $4) "+
"RETURNING id",
"RETURNING id, collection_id",
[data.name, data.description, data.extension, data.collectionId], [data.name, data.description, data.extension, data.collectionId],
queryCallback queryCallback
); );
return ctx.fail(err); return ctx.fail(err);


var id = res.rows[0].id; var id = res.rows[0].id;
var collectionId = res.rows[0].collection_id;
var file = ctx.postData.files.file; var file = ctx.postData.files.file;


var readStream = fs.createReadStream(file.path); var readStream = fs.createReadStream(file.path);
var writeStream = fs.createWriteStream(ctx.conf.dir.imgs+"/"+id);
var writeStream = fs.createWriteStream(
ctx.conf.dir.imgs+"/"+
collectionId+"/"+
id
);

readStream.pipe(writeStream); readStream.pipe(writeStream);


readStream.on("end", function() { readStream.on("end", function() {

+ 1
- 0
web/global.css View File

border: 1px solid #CCC; border: 1px solid #CCC;
border-radius: 4px; border-radius: 4px;
padding: 10px !important; padding: 10px !important;
margin-bottom: 10px;
} }


.title { .title {

+ 9
- 3
web/i/index.node.js View File

var fs = require("fs"); var fs = require("fs");


module.exports = function(ctx) { module.exports = function(ctx) {
var id = ctx.query.replace(/\..*/, "");
if (!id)
var q = ctx.query.replace(/\..*/, "");
var collection = parseInt(q.split("/")[0]);
var id = parseInt(q.split("/")[1]);
if (!id || !collection)
return ctx.err404(); return ctx.err404();


ctx.res.setHeader( ctx.res.setHeader(
"public, max-age="+ctx.conf.cache_max_age_images "public, max-age="+ctx.conf.cache_max_age_images
); );


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


readStream.on("error", function(err){ readStream.on("error", function(err){

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



var collectionId = res.id; var collectionId = res.id;


//Go to collection once files are uploaded
//Go to collection once files are uploaded, or
//delete the collection if it failed
var a = util.async(files.length, function(res) { var a = util.async(files.length, function(res) {
if (res.error)
util.redirect("/", 5000);
else
if (res.error) {
util.api("collection_delete", {
id: collectionId
}, function(err, res) {
if (err)
return util.error(err);

util.redirect("/", 5000);
});
} else {
util.redirect("/view?"+collectionId); util.redirect("/view?"+collectionId);
}
}); });


//Loop through files, uploading them //Loop through files, uploading them

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

$("#collections .date-created").each(function() { $("#collections .date-created").each(function() {
this.innerHTML = util.dateToString(new Date(this.innerHTML)); this.innerHTML = util.dateToString(new Date(this.innerHTML));
}); });

var collections = [];
$("#collections .collection").each(function() {
collections[this.getAttribute("data-id")] = $(this);
});

$("#collections .delete").on("click", function(evt) {
var id = evt.target.getAttribute("data-id");
var collection = collections[id];
var name = collection.children(".name").html();

if (!confirm("Are you sure you want to delete collection "+name+"?"))
return;

util.api("collection_delete", {
id: id
}, function(err, res) {
if (err)
return util.error(err);

collection.remove();
});
});
}); });

+ 2
- 2
web/profile/style.css View File

} }


.collection .date-created { .collection .date-created {
width: 45%;
width: 190px;
} }
.collection .name { .collection .name {
width: calc(55% - 43px);
width: calc(100% - 43px - 190px);
} }

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

res.rows.forEach(function(row) { res.rows.forEach(function(row) {
images += ctx.template("image", { images += ctx.template("image", {
title: row.name, title: row.name,
collection: id,
id: row.id, id: row.id,
extension: row.extension, extension: row.extension,
description: row.description description: row.description

Loading…
Cancel
Save