From 3aa171fbaf05d0ee5b82673443da51ed43719475 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 25 Sep 2015 17:36:53 -0400 Subject: moving things around --- bucky/app/bucky.js | 189 ++++++++++ bucky/app/index.js | 60 ++++ bucky/app/router.js | 150 ++++++++ bucky/db/bookshelf.js | 24 ++ bucky/db/fortune.js | 28 ++ bucky/db/index.js | 156 +++++++++ bucky/util/auth.js | 78 +++++ bucky/util/middleware.js | 23 ++ bucky/util/util.js | 4 + index.js | 2 +- lib/auth.js | 78 ----- lib/bucky.js | 189 ---------- lib/db/bookshelf.js | 24 -- lib/db/index.js | 156 --------- lib/fortune.js | 28 -- lib/index.js | 60 ---- lib/middleware.js | 23 -- lib/router.js | 150 -------- lib/util.js | 4 - public/assets/css/css/lost.css | 14 - public/assets/css/css/poetaster.css | 25 -- public/assets/css/css/style.css | 137 -------- public/assets/css/css/tabs.css | 98 ------ public/assets/css/css/winxp.blue.css | 650 ----------------------------------- 24 files changed, 713 insertions(+), 1637 deletions(-) create mode 100644 bucky/app/bucky.js create mode 100644 bucky/app/index.js create mode 100644 bucky/app/router.js create mode 100644 bucky/db/bookshelf.js create mode 100644 bucky/db/fortune.js create mode 100644 bucky/db/index.js create mode 100644 bucky/util/auth.js create mode 100644 bucky/util/middleware.js create mode 100644 bucky/util/util.js delete mode 100644 lib/auth.js delete mode 100644 lib/bucky.js delete mode 100644 lib/db/bookshelf.js delete mode 100644 lib/db/index.js delete mode 100644 lib/fortune.js delete mode 100644 lib/index.js delete mode 100644 lib/middleware.js delete mode 100644 lib/router.js delete mode 100644 lib/util.js delete mode 100644 public/assets/css/css/lost.css delete mode 100644 public/assets/css/css/poetaster.css delete mode 100755 public/assets/css/css/style.css delete mode 100755 public/assets/css/css/tabs.css delete mode 100755 public/assets/css/css/winxp.blue.css diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js new file mode 100644 index 0000000..43799fe --- /dev/null +++ b/bucky/app/bucky.js @@ -0,0 +1,189 @@ +var db = require('../db') +var util = require('../lib/util') +var _ = require('lodash') + +var bucky = module.exports = { + + /* INDEX */ + + ensureLatestThreads: function (req, res, next){ + db.getLatestThreads().then(function(threads){ + res.threads = threads + res.threads_ids = res.threads.pluck("id").sort() + res.keywords = _.uniq(res.threads.pluck("keyword")) + next() + }) + }, + ensureCommentCountsForThreads: function (req, res, next){ + db.getCommentCounts(res.threads_ids).then(function(counts){ + var lookup = {} + counts.forEach(function(c){ + lookup[c.thread] = c + }) + res.threads.forEach(function(thread){ + thread.set("comment_count", lookup[thread.id].count) + }) + next() + }) + }, + ensureFileCountsForThreads: function (req, res, next){ + db.getFileCounts(res.threads_ids).then(function(counts){ + var lookup = {} + counts.forEach(function(c){ + lookup[c.thread] = c + }) + res.threads.forEach(function(t){ + var c = lookup[t.id] + t.set("file_count", c ? c.count : 0) + }) + next() + }) + }, + ensureKeywordsForThreads: function (req, res, next){ + db.getKeywords(res.keywords).then(function(keywords){ + var lookup = {} + keywords.forEach(function(k){ + lookup[k.get('keyword')] = k + }) + res.threads.forEach(function(t){ + var kw = t.get('keyword') + if (! kw) return + var k = lookup[kw] + if (! k) return + if (! t.get("color")) { + t.set("color", k.get("color")) + } + }) + next() + }) + }, + ensureHootbox: function (req, res, next){ + db.getCommentsForThread(1, 9, 0, "desc").then(function(hootbox){ + res.hootbox = hootbox + next() + }) + }, + ensureLastlog: function (req, res, next){ + db.getLastlog(6).then(function(lastlog){ + res.lastlog = lastlog + next() + }) + }, + + /* DETAILS */ + + ensureThread: function (req, res, next){ + var id = req.params.id.replace(/\D/g, "") + if (! id) { + return res.sendStatus(404) + } + db.getThread(id).then(function(thread){ + if (thread) { + res.thread = thread + next() + } + else { + res.sendStatus(404) + } + }) + }, + ensureKeywordForThread: function (req, res, next){ + var keyword = res.thread.get('keyword') + if (! keyword) return next() + db.getKeyword(keyword).then(function(keyword){ + res.keyword = keyword + next() + }) + }, + ensureCommentsForThread: function (req, res, next){ + db.getCommentsForThread(res.thread.get('id')).then(function(comments){ + res.comments = comments + next() + }) + }, + ensureFilesForThread: function (req, res, next){ + db.getFilesForThread(res.thread.get('id')).then(function(files){ + res.files = files + next() + }) + }, + + /* KEYWORDS */ + + ensureKeyword: function (req, res, next){ + var keyword = req.params.keyword + if (! keyword) { + return res.sendStatus(404) + } + db.getKeyword(keyword).then(function(k){ + if (! k) { + return res.sendStatus(404) + } + res.keyword = k + next() + }) + }, + ensureThreadsForKeyword: function (req, res, next){ + var keyword = req.params.keyword + if (! keyword) { + res.sendStatus(404) + } + db.getThreadsForKeyword(keyword).then(function(threads){ + res.threads = threads + res.threads_ids = res.threads.pluck("id").sort() + res.keywords = _.uniq(res.threads.pluck("keyword")) + next() + }) + }, + + /* MAIL */ + + ensureMailboxes: function (req, res, next){ + var username = req.user.get('username') + var box = req.params.box + var mbox = username + "." + box + if (! box) { + res.sendStatus(404) + } + db.getMailboxes(username).then(function(boxes){ + if (! boxes) { + return res.sendStatus(404) + } + if (! boxes.models.some(function(box){ return box.get('mbox') == mbox })) { + return res.sendStatus(404) + } + res.boxes = boxes + next() + }) + }, + ensureMailboxCounts: function (req, res, next){ + db.getMailboxCounts(res.boxes.pluck("mbox")).then(function(counts){ + var lookup = {} + counts.forEach(function(c){ + lookup[c.mbox] = c + }) + res.boxes.forEach(function(box){ + var count = lookup[box.get('mbox')] ? lookup[box.get('mbox')].count : 0 + box.set("count", count) + }) + next() + }) + }, + ensureMessages: function (req, res, next){ + db.getMessages(req.user.get('username'), req.params.box, 50, 0).then(function(messages){ + res.messages = messages + next() + }) + }, + ensureMessage: function(req, res, next){ + db.getMessage(req.params.id).then(function(message){ + var username = req.user.get('username') + if (username !== message.get('recipient') && username !== message.get('sender')) { + res.sendStatus(404) + return + } + res.message = message + next() + }) + } +} \ No newline at end of file diff --git a/bucky/app/index.js b/bucky/app/index.js new file mode 100644 index 0000000..ad97526 --- /dev/null +++ b/bucky/app/index.js @@ -0,0 +1,60 @@ +require('dotenv').load(); +var fs = require('fs') +var app, express = require('express'); +var http = require('http'); +var https = require('https'); +var bodyParser = require('body-parser') +var cookieParser = require('cookie-parser') +var csurf = require('csurf') +var path = require('path') +var multiparty = require('multiparty') +var ejs = require('ejs') +var passport = require('passport') +var sessionstore = require('sessionstore') +var session = require('express-session') +var multer = require('multer') + +var app, server + +var mongodb = require('mongodb') + +var site = module.exports = {} +site.init = function(){ + app = express() + app.set('port', 5000) + app.set('view engine', 'ejs') + app.set('views', path.join(__dirname, '../views')) + app.use(express.static(path.join(__dirname, '../public'))) + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ extended: false })) + app.use( multer({ dest:'./uploads/' }).single("file") ) + + app.use(session({ + key: 'bucky.sid', + secret: 'argonauts', + cookie: { domain: '.' + process.env.HOST_NAME, maxAge: 43200000000 }, + store: sessionstore.createSessionStore({ + type: 'mongodb', + host: 'localhost', + port: 27017, + dbName: 'sessionDb', + collectionName: 'sessions', + timeout: 10000 + }), + resave: true, + saveUninitialized: false, + })) + app.use(csurf({ cookie: false })) + + app.use(express.query()) + app.use(passport.initialize()) + app.use(passport.session()) + + server = http.createServer(app).listen(5000, function () { + console.log('Bucky listening at http://5.k:%s', server.address().port) + }) + + site.route(app) +} + +site.route = require('./router') diff --git a/bucky/app/router.js b/bucky/app/router.js new file mode 100644 index 0000000..7ac6599 --- /dev/null +++ b/bucky/app/router.js @@ -0,0 +1,150 @@ +var auth = require('../util/auth') +var middleware = require('../util/middleware') +var fortune = require('../db/fortune') +var bucky = require('../app/bucky') +var util = require('../util/util') + +module.exports = function(app){ + app.all('*', middleware.ensureLocals) + + auth.init() + + app.get("/", middleware.ensureAuthenticated, function(req, res){ + res.redirect('/index') + }) + app.get("/login", function(req, res){ + res.render("pages/login", { + title: "login" + }) + }) + app.get("/index", middleware.ensureAuthenticated, function(req, res){ + res.render("pages/index", { + title: fortune("titles"), + hoot_text: fortune("hoots"), + }) + }) + app.get("/details/:id", middleware.ensureAuthenticated, function(req, res){ + res.render("pages/details", {}) + }) + + app.post("/api/login", auth.loggedInLocal) + app.get("/api/index", + middleware.ensureAuthenticated, + bucky.ensureLatestThreads, + bucky.ensureCommentCountsForThreads, + bucky.ensureFileCountsForThreads, + bucky.ensureKeywordsForThreads, + bucky.ensureHootbox, + bucky.ensureLastlog, + function(req, res){ + res.json({ + threads: res.threads, + hootbox: res.hootbox, + lastlog: res.lastlog, + }) + } + ) + app.get("/api/thread/:id", + middleware.ensureAuthenticated, + bucky.ensureThread, + bucky.ensureKeywordForThread, + bucky.ensureCommentsForThread, + bucky.ensureFilesForThread, + function(req, res){ + res.json({ + thread: res.thread, + comments: res.comments, + files: res.files, + keyword: res.keyword, + }) + } + ) + app.post("/api/thread", + middleware.ensureAuthenticated, + function(req, res){ + // make a new thread + }) + app.post("/api/thread/:id/comment", + middleware.ensureAuthenticated, + function(req, res){ + // add comments and files + }) + app.delete("/api/thread/:id", + middleware.ensureAuthenticated, + function(req, res){ + // delete a thread + }) + app.put("/api/comment/:id", + middleware.ensureAuthenticated, + function(req, res){ + // edit a comment + }) + app.delete("/api/comment/:id", + middleware.ensureAuthenticated, + function(req, res){ + // delete a comment + }) + + + app.get("/api/keyword/:keyword", + middleware.ensureAuthenticated, + bucky.ensureKeyword, + bucky.ensureThreadsForKeyword, + bucky.ensureCommentCountsForThreads, + bucky.ensureFileCountsForThreads, + bucky.ensureKeywordsForThreads, + function(req, res){ + res.json({ + keyword: res.keyword, + threads: res.threads, + }) + } + ) + + app.get("/mail/", + middleware.ensureAuthenticated, + function(req, res){ + res.render("pages/mailbox", {title: "inbox" }) + } + ) + app.get("/mail/:box", + middleware.ensureAuthenticated, + function(req, res){ + res.render("pages/mailbox", { title: util.sanitize(req.params.box) }) + } + ) + app.get("/message/:id", + middleware.ensureAuthenticated, + function(req, res){ + res.render("pages/message", { title: util.sanitize(req.params.box) }) + } + ) + app.get("/api/mailbox/:box", + middleware.ensureAuthenticated, + bucky.ensureMailboxes, + bucky.ensureMailboxCounts, + bucky.ensureMessages, + function(req, res){ + res.json({ + user: { id: req.user.get("id"), username: req.user.get("username") }, + messages: res.messages, + boxes: res.boxes, + }) + } + ) + app.get("/api/message/:id", + middleware.ensureAuthenticated, + bucky.ensureMessage, + function(req, res){ + res.json({ + message: res.message, + }) + }) + app.post("/mail/", + middleware.ensureAuthenticated, + function(req, res){ + // send new mail + } + ) + +} diff --git a/bucky/db/bookshelf.js b/bucky/db/bookshelf.js new file mode 100644 index 0000000..69157cc --- /dev/null +++ b/bucky/db/bookshelf.js @@ -0,0 +1,24 @@ +var knex = require('knex')({ + client: 'mysql2', + connection: { + host : process.env.DB_HOST, + user : process.env.DB_USER, + password : process.env.DB_PASS, + database : process.env.DB_NAME, + charset : 'utf8', + typecast : function (field, next) { + console.log(field.type) + if (field.type == 'BLOB') { + return field.string() + } + return next() + } + } +}) + +var bookshelf = require('bookshelf')(knex) + +module.exports = { + bookshelf: bookshelf, + knex: knex, +} diff --git a/bucky/db/fortune.js b/bucky/db/fortune.js new file mode 100644 index 0000000..7adba5a --- /dev/null +++ b/bucky/db/fortune.js @@ -0,0 +1,28 @@ +function choice (a){ return a[ Math.floor(Math.random()*a.length) ] } + +var fs = require("fs"), path = require("path") +var fortunes = {} +var dir = "fortune" + +fs.readdirSync(path.resolve(dir)).forEach(function(fn){ + + var file = dir + '/' + fn + var stat = fs.statSync(file) + + if (stat && ! stat.isDirectory()) { + fortunes[fn] = fs.readFileSync(file) + .toString() + .split("\n") + .filter(function(s){ return !! s }) + } + +}) + +module.exports = function(tag){ + if (tag in fortunes) { + return choice(fortunes[tag]) + } + else { + return "bucky" + } +} \ No newline at end of file diff --git a/bucky/db/index.js b/bucky/db/index.js new file mode 100644 index 0000000..b6fa235 --- /dev/null +++ b/bucky/db/index.js @@ -0,0 +1,156 @@ +var db = module.exports + +var connection = require("./bookshelf") +var bookshelf = connection.bookshelf +var knex = connection.knex + + +/* MODELS */ + +var User = db.User = bookshelf.Model.extend({ + tableName: 'users', + hasTimestamps: false, +}) +var Thread = db.Thread = bookshelf.Model.extend({ + tableName: 'threads', + hasTimestamps: false, +}) +var Comment = db.Comment = bookshelf.Model.extend({ + tableName: 'comments', + hasTimestamps: false, +}) +var File = db.File = bookshelf.Model.extend({ + tableName: 'files', + hasTimestamps: false, +}) +var Keyword = db.Keyword = bookshelf.Model.extend({ + tableName: 'keywords', + hasTimestamps: false, +}) +var Mailbox = db.Mailbox = bookshelf.Model.extend({ + tableName: 'boxes', + hasTimestamps: false, +}) +var Message = db.Message = bookshelf.Model.extend({ + tableName: 'messages', + hasTimestamps: false, +}) + +/* USERS */ + +db.createUser = function(data){ + return new db.User(data).save() +} +db.getUsers = function () { + return User.query(function(qb){ + qb.orderBy("id", "desc") + }).fetchAll() +} +db.getUser = function(id) { + var model = new User({'id': id}) + return model.fetch() +} +db.getUserByUsername = function(username) { + var model = new User({'username': username}) + return model.fetch() +} +db.getLastlog = function(limit){ + return knex.column('username').column('lastseen').select().from('users').orderBy('lastseen', 'desc').limit(limit || 10) +} + + +/* THREADS */ + +db.getLatestThreads = function () { + return Thread.query(function(qb){ + qb.orderBy("id", "desc").limit(50) + }).fetchAll() +} +db.getThreadsForKeyword = function (keyword) { + return Thread.query(function(qb){ + qb.where("keyword", "=", keyword).orderBy("id", "desc") + }).fetchAll() +} +db.getThread = function (id) { + return Thread.query("where", "id", "=", id).fetch() +} + + +/* FILES */ + +db.getFilesForThread = function (id){ + return File.query("where", "thread", "=", id).fetchAll() +} +db.getFileCounts = function(ids){ + return knex.column('thread').count('* as count').select().from('files').where('thread', 'in', ids).groupBy('thread') +} +db.getFileSizes = function(ids){ + return knex.column('thread').sum('size as size').select().from('files').where('thread', 'in', ids).groupBy('thread') +} + + +/* COMMENTS */ + +db.getCommentsForThread = function (id, limit, offset, order){ + order = order || "asc" + return Comment.query(function(qb){ + qb.where("thread", "=", id).orderBy("id", order) + if (limit) { + qb.limit(limit) + } + if (offset) { + qb.offset(offset) + } + }).fetchAll().then(function(comments){ + comments.forEach(function(comment){ + comment.set("comment", comment.get("comment").toString() ) + }) + return comments + }) +} +db.getCommentCounts = function(ids){ + return knex.column('thread').count('* as count').select().from('comments').where('thread', 'in', ids).groupBy('thread') +} + + +/* KEYWORDS */ + +db.getKeywords = function (keywords){ + return Keyword.query("where", "keyword", "in", keywords).fetchAll() +} +db.getKeyword = function (keyword) { + return Keyword.query("where", "keyword", "=", keyword).fetch() +} + + +/* MAILBOXES */ + +db.getMailboxes = function(username){ + return Mailbox.query("where", "owner", "=", username).fetchAll() +} +db.getMailboxCounts = function(boxes){ + return knex.column('mbox').count('* as count').select().from('messages').where('mbox', 'in', boxes).groupBy('mbox') +} + + +/* MESSAGES */ + +db.getMessages = function(username, box, limit, offset){ + var mbox = username + "." + box + return Message.query(function(qb){ + qb.column('id', 'mbox', 'unread', 'sender', 'recipient', 'date', 'subject', knex.raw("CHAR_LENGTH(body) as size")).where("mbox", "=", mbox).orderBy("id", "desc") + if (limit) { + qb.limit(limit) + } + if (offset) { + qb.offset(offset) + } + }).fetchAll() +} +db.getMessage = function (id){ + var model = new Message({'id': id}) + return model.fetch().then(function(message){ + message.set("body", message.get("body").toString() ) + return message + }) +} diff --git a/bucky/util/auth.js b/bucky/util/auth.js new file mode 100644 index 0000000..436d5e6 --- /dev/null +++ b/bucky/util/auth.js @@ -0,0 +1,78 @@ + +var passport = require('passport'), + LocalStrategy = require('passport-local').Strategy, + crypto = require('crypto'), + db = require('../db'); + + +var auth = module.exports = { + + init: function(){ + passport.serializeUser(auth.serializeUser) + passport.deserializeUser(auth.deserializeUser) + + passport.use(new LocalStrategy(auth.verifyLocalUser)) + }, + + serializeUser: function (user, done) { + done(null, user.id); + }, + + deserializeUser: function (id, done) { + db.getUser(id).then(function(user){ + done(! user, user) + }) + }, + + validPassword: function(user, pw){ + var shasum = crypto.createHash('sha1') + shasum.update(pw) + return user.get('password') === shasum.digest('hex'); + }, + + verifyLocalUser: function (username, password, done) { + // handle passwords!! + db.getUserByUsername(username).then(function(user){ + + // if (err) { return done(err); } + if (! user) { return done("no user") } + + return done(null, user) + + if (! user) { + return done(null, false, { error: { errors: { username: { message: 'No such username.' } }}}) + } + if (! auth.validPassword(user, password)) { + return done(null, false, { error: { errors: { password: { message: 'Incorrect password.' } }}}) + } + return done(null, user); + }) + }, + + loggedInLocal: function (req, res, next) { + passport.authenticate("local", function(err, user, info){ + if (err) { + return res.json({ error: err }); + } + if (! user) { + return info ? res.json(info) : res.redirect("/login"); + } + + // user.last_seen = new Date () + // user.save(function(err, data){ if (err) console.err('error setting ip for user') }) + + req.logIn(user, function(err) { + if (err) { return next(err); } + var returnTo = req.session.returnTo + delete req.session.returnTo + return res.json({ status: "OK", returnTo: returnTo || "/index" }) + }); + })(req, res, next) + }, + + logout: function (req, res) { + req.logout(); + res.redirect('/'); + }, + +} \ No newline at end of file diff --git a/bucky/util/middleware.js b/bucky/util/middleware.js new file mode 100644 index 0000000..a744c89 --- /dev/null +++ b/bucky/util/middleware.js @@ -0,0 +1,23 @@ +var middleware = module.exports = { + + ensureAuthenticated: function (req, res, next) { + if (! req.isAuthenticated()) { + req.session.returnTo = req.path + return res.redirect('/login') + } + next() + }, + + ensureLocals: function (req, res, next) { + res.locals.csrfToken = req.csrfToken() + res.locals.title = "bucky" + if (req.isAuthenticated()) { + res.locals.show_header = true + } + else { + res.locals.show_header = false + } + next() + }, + +} \ No newline at end of file diff --git a/bucky/util/util.js b/bucky/util/util.js new file mode 100644 index 0000000..e67488b --- /dev/null +++ b/bucky/util/util.js @@ -0,0 +1,4 @@ +var util = module.exports = {} + +util.sanitizeName = function (s){ return (s || "").replace(new RegExp("[^-_a-zA-Z0-9]", 'g'), "") } +util.sanitize = function (s){ return (s || "").replace(/<>&/g, "") } diff --git a/index.js b/index.js index 3cb2b31..650188f 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,2 @@ -var app = require('./lib') +var app = require('./bucky/app/index') app.init() diff --git a/lib/auth.js b/lib/auth.js deleted file mode 100644 index 38901e4..0000000 --- a/lib/auth.js +++ /dev/null @@ -1,78 +0,0 @@ - -var passport = require('passport'), - LocalStrategy = require('passport-local').Strategy, - crypto = require('crypto'), - db = require('./db'); - - -var auth = module.exports = { - - init: function(){ - passport.serializeUser(auth.serializeUser) - passport.deserializeUser(auth.deserializeUser) - - passport.use(new LocalStrategy(auth.verifyLocalUser)) - }, - - serializeUser: function (user, done) { - done(null, user.id); - }, - - deserializeUser: function (id, done) { - db.getUser(id).then(function(user){ - done(! user, user) - }) - }, - - validPassword: function(user, pw){ - var shasum = crypto.createHash('sha1') - shasum.update(pw) - return user.get('password') === shasum.digest('hex'); - }, - - verifyLocalUser: function (username, password, done) { - // handle passwords!! - db.getUserByUsername(username).then(function(user){ - - // if (err) { return done(err); } - if (! user) { return done("no user") } - - return done(null, user) - - if (! user) { - return done(null, false, { error: { errors: { username: { message: 'No such username.' } }}}) - } - if (! auth.validPassword(user, password)) { - return done(null, false, { error: { errors: { password: { message: 'Incorrect password.' } }}}) - } - return done(null, user); - }) - }, - - loggedInLocal: function (req, res, next) { - passport.authenticate("local", function(err, user, info){ - if (err) { - return res.json({ error: err }); - } - if (! user) { - return info ? res.json(info) : res.redirect("/login"); - } - - // user.last_seen = new Date () - // user.save(function(err, data){ if (err) console.err('error setting ip for user') }) - - req.logIn(user, function(err) { - if (err) { return next(err); } - var returnTo = req.session.returnTo - delete req.session.returnTo - return res.json({ status: "OK", returnTo: returnTo || "/index" }) - }); - })(req, res, next) - }, - - logout: function (req, res) { - req.logout(); - res.redirect('/'); - }, - -} \ No newline at end of file diff --git a/lib/bucky.js b/lib/bucky.js deleted file mode 100644 index bfc4b6f..0000000 --- a/lib/bucky.js +++ /dev/null @@ -1,189 +0,0 @@ -var db = require('./db') -var util = require('./util') -var _ = require('lodash') - -var bucky = module.exports = { - - /* INDEX */ - - ensureLatestThreads: function (req, res, next){ - db.getLatestThreads().then(function(threads){ - res.threads = threads - res.threads_ids = res.threads.pluck("id").sort() - res.keywords = _.uniq(res.threads.pluck("keyword")) - next() - }) - }, - ensureCommentCountsForThreads: function (req, res, next){ - db.getCommentCounts(res.threads_ids).then(function(counts){ - var lookup = {} - counts.forEach(function(c){ - lookup[c.thread] = c - }) - res.threads.forEach(function(thread){ - thread.set("comment_count", lookup[thread.id].count) - }) - next() - }) - }, - ensureFileCountsForThreads: function (req, res, next){ - db.getFileCounts(res.threads_ids).then(function(counts){ - var lookup = {} - counts.forEach(function(c){ - lookup[c.thread] = c - }) - res.threads.forEach(function(t){ - var c = lookup[t.id] - t.set("file_count", c ? c.count : 0) - }) - next() - }) - }, - ensureKeywordsForThreads: function (req, res, next){ - db.getKeywords(res.keywords).then(function(keywords){ - var lookup = {} - keywords.forEach(function(k){ - lookup[k.get('keyword')] = k - }) - res.threads.forEach(function(t){ - var kw = t.get('keyword') - if (! kw) return - var k = lookup[kw] - if (! k) return - if (! t.get("color")) { - t.set("color", k.get("color")) - } - }) - next() - }) - }, - ensureHootbox: function (req, res, next){ - db.getCommentsForThread(1, 9, 0, "desc").then(function(hootbox){ - res.hootbox = hootbox - next() - }) - }, - ensureLastlog: function (req, res, next){ - db.getLastlog(6).then(function(lastlog){ - res.lastlog = lastlog - next() - }) - }, - - /* DETAILS */ - - ensureThread: function (req, res, next){ - var id = req.params.id.replace(/\D/g, "") - if (! id) { - return res.sendStatus(404) - } - db.getThread(id).then(function(thread){ - if (thread) { - res.thread = thread - next() - } - else { - res.sendStatus(404) - } - }) - }, - ensureKeywordForThread: function (req, res, next){ - var keyword = res.thread.get('keyword') - if (! keyword) return next() - db.getKeyword(keyword).then(function(keyword){ - res.keyword = keyword - next() - }) - }, - ensureCommentsForThread: function (req, res, next){ - db.getCommentsForThread(res.thread.get('id')).then(function(comments){ - res.comments = comments - next() - }) - }, - ensureFilesForThread: function (req, res, next){ - db.getFilesForThread(res.thread.get('id')).then(function(files){ - res.files = files - next() - }) - }, - - /* KEYWORDS */ - - ensureKeyword: function (req, res, next){ - var keyword = req.params.keyword - if (! keyword) { - return res.sendStatus(404) - } - db.getKeyword(keyword).then(function(k){ - if (! k) { - return res.sendStatus(404) - } - res.keyword = k - next() - }) - }, - ensureThreadsForKeyword: function (req, res, next){ - var keyword = req.params.keyword - if (! keyword) { - res.sendStatus(404) - } - db.getThreadsForKeyword(keyword).then(function(threads){ - res.threads = threads - res.threads_ids = res.threads.pluck("id").sort() - res.keywords = _.uniq(res.threads.pluck("keyword")) - next() - }) - }, - - /* MAIL */ - - ensureMailboxes: function (req, res, next){ - var username = req.user.get('username') - var box = req.params.box - var mbox = username + "." + box - if (! box) { - res.sendStatus(404) - } - db.getMailboxes(username).then(function(boxes){ - if (! boxes) { - return res.sendStatus(404) - } - if (! boxes.models.some(function(box){ return box.get('mbox') == mbox })) { - return res.sendStatus(404) - } - res.boxes = boxes - next() - }) - }, - ensureMailboxCounts: function (req, res, next){ - db.getMailboxCounts(res.boxes.pluck("mbox")).then(function(counts){ - var lookup = {} - counts.forEach(function(c){ - lookup[c.mbox] = c - }) - res.boxes.forEach(function(box){ - var count = lookup[box.get('mbox')] ? lookup[box.get('mbox')].count : 0 - box.set("count", count) - }) - next() - }) - }, - ensureMessages: function (req, res, next){ - db.getMessages(req.user.get('username'), req.params.box, 50, 0).then(function(messages){ - res.messages = messages - next() - }) - }, - ensureMessage: function(req, res, next){ - db.getMessage(req.params.id).then(function(message){ - var username = req.user.get('username') - if (username !== message.get('recipient') && username !== message.get('sender')) { - res.sendStatus(404) - return - } - res.message = message - next() - }) - } -} \ No newline at end of file diff --git a/lib/db/bookshelf.js b/lib/db/bookshelf.js deleted file mode 100644 index 69157cc..0000000 --- a/lib/db/bookshelf.js +++ /dev/null @@ -1,24 +0,0 @@ -var knex = require('knex')({ - client: 'mysql2', - connection: { - host : process.env.DB_HOST, - user : process.env.DB_USER, - password : process.env.DB_PASS, - database : process.env.DB_NAME, - charset : 'utf8', - typecast : function (field, next) { - console.log(field.type) - if (field.type == 'BLOB') { - return field.string() - } - return next() - } - } -}) - -var bookshelf = require('bookshelf')(knex) - -module.exports = { - bookshelf: bookshelf, - knex: knex, -} diff --git a/lib/db/index.js b/lib/db/index.js deleted file mode 100644 index b6fa235..0000000 --- a/lib/db/index.js +++ /dev/null @@ -1,156 +0,0 @@ -var db = module.exports - -var connection = require("./bookshelf") -var bookshelf = connection.bookshelf -var knex = connection.knex - - -/* MODELS */ - -var User = db.User = bookshelf.Model.extend({ - tableName: 'users', - hasTimestamps: false, -}) -var Thread = db.Thread = bookshelf.Model.extend({ - tableName: 'threads', - hasTimestamps: false, -}) -var Comment = db.Comment = bookshelf.Model.extend({ - tableName: 'comments', - hasTimestamps: false, -}) -var File = db.File = bookshelf.Model.extend({ - tableName: 'files', - hasTimestamps: false, -}) -var Keyword = db.Keyword = bookshelf.Model.extend({ - tableName: 'keywords', - hasTimestamps: false, -}) -var Mailbox = db.Mailbox = bookshelf.Model.extend({ - tableName: 'boxes', - hasTimestamps: false, -}) -var Message = db.Message = bookshelf.Model.extend({ - tableName: 'messages', - hasTimestamps: false, -}) - -/* USERS */ - -db.createUser = function(data){ - return new db.User(data).save() -} -db.getUsers = function () { - return User.query(function(qb){ - qb.orderBy("id", "desc") - }).fetchAll() -} -db.getUser = function(id) { - var model = new User({'id': id}) - return model.fetch() -} -db.getUserByUsername = function(username) { - var model = new User({'username': username}) - return model.fetch() -} -db.getLastlog = function(limit){ - return knex.column('username').column('lastseen').select().from('users').orderBy('lastseen', 'desc').limit(limit || 10) -} - - -/* THREADS */ - -db.getLatestThreads = function () { - return Thread.query(function(qb){ - qb.orderBy("id", "desc").limit(50) - }).fetchAll() -} -db.getThreadsForKeyword = function (keyword) { - return Thread.query(function(qb){ - qb.where("keyword", "=", keyword).orderBy("id", "desc") - }).fetchAll() -} -db.getThread = function (id) { - return Thread.query("where", "id", "=", id).fetch() -} - - -/* FILES */ - -db.getFilesForThread = function (id){ - return File.query("where", "thread", "=", id).fetchAll() -} -db.getFileCounts = function(ids){ - return knex.column('thread').count('* as count').select().from('files').where('thread', 'in', ids).groupBy('thread') -} -db.getFileSizes = function(ids){ - return knex.column('thread').sum('size as size').select().from('files').where('thread', 'in', ids).groupBy('thread') -} - - -/* COMMENTS */ - -db.getCommentsForThread = function (id, limit, offset, order){ - order = order || "asc" - return Comment.query(function(qb){ - qb.where("thread", "=", id).orderBy("id", order) - if (limit) { - qb.limit(limit) - } - if (offset) { - qb.offset(offset) - } - }).fetchAll().then(function(comments){ - comments.forEach(function(comment){ - comment.set("comment", comment.get("comment").toString() ) - }) - return comments - }) -} -db.getCommentCounts = function(ids){ - return knex.column('thread').count('* as count').select().from('comments').where('thread', 'in', ids).groupBy('thread') -} - - -/* KEYWORDS */ - -db.getKeywords = function (keywords){ - return Keyword.query("where", "keyword", "in", keywords).fetchAll() -} -db.getKeyword = function (keyword) { - return Keyword.query("where", "keyword", "=", keyword).fetch() -} - - -/* MAILBOXES */ - -db.getMailboxes = function(username){ - return Mailbox.query("where", "owner", "=", username).fetchAll() -} -db.getMailboxCounts = function(boxes){ - return knex.column('mbox').count('* as count').select().from('messages').where('mbox', 'in', boxes).groupBy('mbox') -} - - -/* MESSAGES */ - -db.getMessages = function(username, box, limit, offset){ - var mbox = username + "." + box - return Message.query(function(qb){ - qb.column('id', 'mbox', 'unread', 'sender', 'recipient', 'date', 'subject', knex.raw("CHAR_LENGTH(body) as size")).where("mbox", "=", mbox).orderBy("id", "desc") - if (limit) { - qb.limit(limit) - } - if (offset) { - qb.offset(offset) - } - }).fetchAll() -} -db.getMessage = function (id){ - var model = new Message({'id': id}) - return model.fetch().then(function(message){ - message.set("body", message.get("body").toString() ) - return message - }) -} diff --git a/lib/fortune.js b/lib/fortune.js deleted file mode 100644 index 7adba5a..0000000 --- a/lib/fortune.js +++ /dev/null @@ -1,28 +0,0 @@ -function choice (a){ return a[ Math.floor(Math.random()*a.length) ] } - -var fs = require("fs"), path = require("path") -var fortunes = {} -var dir = "fortune" - -fs.readdirSync(path.resolve(dir)).forEach(function(fn){ - - var file = dir + '/' + fn - var stat = fs.statSync(file) - - if (stat && ! stat.isDirectory()) { - fortunes[fn] = fs.readFileSync(file) - .toString() - .split("\n") - .filter(function(s){ return !! s }) - } - -}) - -module.exports = function(tag){ - if (tag in fortunes) { - return choice(fortunes[tag]) - } - else { - return "bucky" - } -} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index ad97526..0000000 --- a/lib/index.js +++ /dev/null @@ -1,60 +0,0 @@ -require('dotenv').load(); -var fs = require('fs') -var app, express = require('express'); -var http = require('http'); -var https = require('https'); -var bodyParser = require('body-parser') -var cookieParser = require('cookie-parser') -var csurf = require('csurf') -var path = require('path') -var multiparty = require('multiparty') -var ejs = require('ejs') -var passport = require('passport') -var sessionstore = require('sessionstore') -var session = require('express-session') -var multer = require('multer') - -var app, server - -var mongodb = require('mongodb') - -var site = module.exports = {} -site.init = function(){ - app = express() - app.set('port', 5000) - app.set('view engine', 'ejs') - app.set('views', path.join(__dirname, '../views')) - app.use(express.static(path.join(__dirname, '../public'))) - app.use(bodyParser.json()) - app.use(bodyParser.urlencoded({ extended: false })) - app.use( multer({ dest:'./uploads/' }).single("file") ) - - app.use(session({ - key: 'bucky.sid', - secret: 'argonauts', - cookie: { domain: '.' + process.env.HOST_NAME, maxAge: 43200000000 }, - store: sessionstore.createSessionStore({ - type: 'mongodb', - host: 'localhost', - port: 27017, - dbName: 'sessionDb', - collectionName: 'sessions', - timeout: 10000 - }), - resave: true, - saveUninitialized: false, - })) - app.use(csurf({ cookie: false })) - - app.use(express.query()) - app.use(passport.initialize()) - app.use(passport.session()) - - server = http.createServer(app).listen(5000, function () { - console.log('Bucky listening at http://5.k:%s', server.address().port) - }) - - site.route(app) -} - -site.route = require('./router') diff --git a/lib/middleware.js b/lib/middleware.js deleted file mode 100644 index a744c89..0000000 --- a/lib/middleware.js +++ /dev/null @@ -1,23 +0,0 @@ -var middleware = module.exports = { - - ensureAuthenticated: function (req, res, next) { - if (! req.isAuthenticated()) { - req.session.returnTo = req.path - return res.redirect('/login') - } - next() - }, - - ensureLocals: function (req, res, next) { - res.locals.csrfToken = req.csrfToken() - res.locals.title = "bucky" - if (req.isAuthenticated()) { - res.locals.show_header = true - } - else { - res.locals.show_header = false - } - next() - }, - -} \ No newline at end of file diff --git a/lib/router.js b/lib/router.js deleted file mode 100644 index 66aa1bf..0000000 --- a/lib/router.js +++ /dev/null @@ -1,150 +0,0 @@ -var auth = require('./auth') -var middleware = require('./middleware') -var fortune = require('./fortune') -var bucky = require('./bucky') -var util = require('./util') - -module.exports = function(app){ - app.all('*', middleware.ensureLocals) - - auth.init() - - app.get("/", middleware.ensureAuthenticated, function(req, res){ - res.redirect('/index') - }) - app.get("/login", function(req, res){ - res.render("pages/login", { - title: "login" - }) - }) - app.get("/index", middleware.ensureAuthenticated, function(req, res){ - res.render("pages/index", { - title: fortune("titles"), - hoot_text: fortune("hoots"), - }) - }) - app.get("/details/:id", middleware.ensureAuthenticated, function(req, res){ - res.render("pages/details", {}) - }) - - app.post("/api/login", auth.loggedInLocal) - app.get("/api/index", - middleware.ensureAuthenticated, - bucky.ensureLatestThreads, - bucky.ensureCommentCountsForThreads, - bucky.ensureFileCountsForThreads, - bucky.ensureKeywordsForThreads, - bucky.ensureHootbox, - bucky.ensureLastlog, - function(req, res){ - res.json({ - threads: res.threads, - hootbox: res.hootbox, - lastlog: res.lastlog, - }) - } - ) - app.get("/api/thread/:id", - middleware.ensureAuthenticated, - bucky.ensureThread, - bucky.ensureKeywordForThread, - bucky.ensureCommentsForThread, - bucky.ensureFilesForThread, - function(req, res){ - res.json({ - thread: res.thread, - comments: res.comments, - files: res.files, - keyword: res.keyword, - }) - } - ) - app.post("/api/thread", - middleware.ensureAuthenticated, - function(req, res){ - // make a new thread - }) - app.post("/api/thread/:id/comment", - middleware.ensureAuthenticated, - function(req, res){ - // add comments and files - }) - app.delete("/api/thread/:id", - middleware.ensureAuthenticated, - function(req, res){ - // delete a thread - }) - app.put("/api/comment/:id", - middleware.ensureAuthenticated, - function(req, res){ - // edit a comment - }) - app.delete("/api/comment/:id", - middleware.ensureAuthenticated, - function(req, res){ - // delete a comment - }) - - - app.get("/api/keyword/:keyword", - middleware.ensureAuthenticated, - bucky.ensureKeyword, - bucky.ensureThreadsForKeyword, - bucky.ensureCommentCountsForThreads, - bucky.ensureFileCountsForThreads, - bucky.ensureKeywordsForThreads, - function(req, res){ - res.json({ - keyword: res.keyword, - threads: res.threads, - }) - } - ) - - app.get("/mail/", - middleware.ensureAuthenticated, - function(req, res){ - res.render("pages/mailbox", {title: "inbox" }) - } - ) - app.get("/mail/:box", - middleware.ensureAuthenticated, - function(req, res){ - res.render("pages/mailbox", { title: util.sanitize(req.params.box) }) - } - ) - app.get("/message/:id", - middleware.ensureAuthenticated, - function(req, res){ - res.render("pages/message", { title: util.sanitize(req.params.box) }) - } - ) - app.get("/api/mailbox/:box", - middleware.ensureAuthenticated, - bucky.ensureMailboxes, - bucky.ensureMailboxCounts, - bucky.ensureMessages, - function(req, res){ - res.json({ - user: { id: req.user.get("id"), username: req.user.get("username") }, - messages: res.messages, - boxes: res.boxes, - }) - } - ) - app.get("/api/message/:id", - middleware.ensureAuthenticated, - bucky.ensureMessage, - function(req, res){ - res.json({ - message: res.message, - }) - }) - app.post("/mail/", - middleware.ensureAuthenticated, - function(req, res){ - // send new mail - } - ) - -} diff --git a/lib/util.js b/lib/util.js deleted file mode 100644 index e67488b..0000000 --- a/lib/util.js +++ /dev/null @@ -1,4 +0,0 @@ -var util = module.exports = {} - -util.sanitizeName = function (s){ return (s || "").replace(new RegExp("[^-_a-zA-Z0-9]", 'g'), "") } -util.sanitize = function (s){ return (s || "").replace(/<>&/g, "") } diff --git a/public/assets/css/css/lost.css b/public/assets/css/css/lost.css deleted file mode 100644 index 699a7a9..0000000 --- a/public/assets/css/css/lost.css +++ /dev/null @@ -1,14 +0,0 @@ -body { background-color: #EFEFEF; } -body,div,.wl { font-family: "courier new",monospace; font-size: small; white-space: pre;} - -.h { background-color: yellow; } -.s { background-color: #DFDFDF; } - -.m { color: darkgreen; } /* mode */ -.j { color: darkgreen; } /* join */ -.p { color: darkgreen; } /* part */ -.q { color: darkblue; } /* quit */ -.k { color: darkblue; } /* kick */ -.t { color: darkblue; } /* topic */ -.a { color: darkred; } /* action */ -.n { color: darkred; } /* nick */ diff --git a/public/assets/css/css/poetaster.css b/public/assets/css/css/poetaster.css deleted file mode 100644 index ce0efc8..0000000 --- a/public/assets/css/css/poetaster.css +++ /dev/null @@ -1,25 +0,0 @@ -* - { - margin: 0; - padding: 0; - } -body - { - } -textarea - { - width: 300px; - height: 100px; - } -pre - { - white-space: pre; - font-family: georgia, serif; - font-size: 16px; - } -#container - { - width: 400px; - margin: 0 auto; - } - diff --git a/public/assets/css/css/style.css b/public/assets/css/css/style.css deleted file mode 100755 index 2d38361..0000000 --- a/public/assets/css/css/style.css +++ /dev/null @@ -1,137 +0,0 @@ -table - { - width: 100%; - border-collapse: collapse; - background-color: white; - color: black; - font: 10pt verdana, arial; - margin-bottom: 25%; /* %, px, em, ex ? */ - } - -tr.subhead - { - background-color: #cccccc; - } - -th - { - padding: 0 3%; - } - -th.alt - { - background-color: black; - color: white; - padding: 3% 3% 2%; - } - -td - { - padding: 0 3%; - } - -tr.alt - { - background-color: #eeeeee; - } - -h1 - { - font: 24pt verdana, arial; - margin: 0; - } - -h2 - { - font: 18pt verdana, arial; - margin: 0; - } - -h3 - { - font: 12pt verdana, arial; - margin: 0; - } - -th a - { - color: #00008b; - font: 8pt verdana, arial; - } - -a - { - color: #00008b; - text-decoration: none; - } - -a:hover - { - color: #00008b; - text-decoration: underline; - } - -div.outer - { - width: 90%; - margin: 15%; - } - -table.viewmenu td - { - background-color: #006699; - color: white; - padding: 0 5%; - } - -table.viewmenu td.end - { - padding: 0; - } - -table.viewmenu a - { - color: white; - font: 8pt verdana, arial; - } - -table.viewmenu a:hover - { - color: white; - font: 8pt verdana, arial; - } - -a.tinylink - { - color: #00008b; - font: 8pt verdana, arial; - text-decoration: underline; - } - -a.link - { - color: #00008b; - text-decoration: underline; - } - -div.buffer - { - padding-top: 7%; - padding-bottom: 17%; - } - -.small - { - font: 8pt verdana, arial; - } - -table td - { - padding-right: 20%; - } - -table td.nopad - { - padding-right: 5%; - } - diff --git a/public/assets/css/css/tabs.css b/public/assets/css/css/tabs.css deleted file mode 100755 index 3b7250e..0000000 --- a/public/assets/css/css/tabs.css +++ /dev/null @@ -1,98 +0,0 @@ -#screenTabs { -float:left; -width: 100%; -min-height: 1px; -height: 1px; -background:#ffffff url("../img/icons/tabs/bg.gif") repeat-x bottom; -} - -td > #screenTabs { -height: auto; -} - -#tabs { -float:left; -width:620px; -line-height:normal; -white-space: nowrap; -background:#ffffff url("../img/icons/tabs/bg.gif") repeat-x bottom; -} - -#tabs ul { -margin:0; -padding: 0px 10px 10px 10px; -list-style:none; -} - -#tabs a { -display: block; -background:url("../img/icons/tabs/right.gif") no-repeat right top; -padding:5px 9px 4px 4px; -vertical-align: baseline; -text-decoration: none; -color: #000000; -width:.1em; -} - -#tabs > ul a { -width: auto; -} - -#tabs a:hover, -#tabs a:visited, -#tabs a:active { -text-decoration: none; -color: #000000; -} - -#tabs li { -float:left; -background:url("../img/icons/tabs/left.gif") no-repeat left top; -margin:0; -padding:0 0 0 2px; -border-bottom: solid 1px #776655; -} - -#tabs li#current { -border-width: 0; -} - -#tabs #current { -background-image:url("../img/icons/tabs/left_on.gif"); -margin-left: -3px; -} -#tabs #current a { -background-image:url("../img/icons/tabs/right_on.gif"); -padding:3px 9px 7px 6px; -vertical-align: baseline; -} - -#tabs .last a { -background-image:url("../img/icons/tabs/right_last.gif"); -} - -#tabs .first { -background-image:url("../img/icons/tabs/left_first.gif"); -} - -#tabs .first#current { -margin-left: 0; -} - -#tabs li:hover { -background-position: 0% -150px; -cursor: pointer; -} - -#tabs li:hover a { -background-position: 100% -150px; -} - -#tabs li.first:hover { -background-position: top left; -} - -#tabs a:hover { -background-position: 100% -150px; -} - diff --git a/public/assets/css/css/winxp.blue.css b/public/assets/css/css/winxp.blue.css deleted file mode 100755 index 476e415..0000000 --- a/public/assets/css/css/winxp.blue.css +++ /dev/null @@ -1,650 +0,0 @@ -html - { - height: 100%; - min-height: 100%; - border-width: 0px; - } - -body - { - height: 100%; - min-height: 100%; - margin: 0px; - padding: 0px; - font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; - font-size: 11px; - font-weight: normal; - background-color: #F9F8F8; - color: #000000; - } - -p, div, span { - font-size: 11px; -} - -.screenLayout { - position: relative; - min-height: 100%; - margin-bottom: 0; -} -* html .screenLayout { - height: 100%; -} - -.headerContainer - { - background-image: url('../img/common/top_bg.jpg'); - background-repeat: repeat-x; - background-position: left bottom; - background-color: #FEFEFE; - margin: 0px; - } - -.pageHeader - { - background-image: url('../img/common/top_body_bg.jpg'); - background-position: top right; - background-repeat: no-repeat; - text-align: left; - margin: 0px; - height: 50px; - } - -.pageHeader img - { - margin-left: 0px; - margin-top: 0px; - } - -.footerContainer - { - position: absolute; -/* visibility:hidden; */ - bottom: 0px; - height: 40px; - width: 100%; - border-top: solid 1px #6E89DD; - background-color: #8EA5EC; - margin-bottom: 0; - } - -.contentLayout - { - text-align: center; - padding-bottom: 120px; - } - -.contentContainer - { - width: 620px; - text-align: left; - margin-left: auto; - margin-right: auto; - /* - border-left: solid 1px #dddddd; - border-right: solid 1px #dddddd; - */ - } - -.pageContent - { - margin-top: 49px; - } - -.mainPageBanner - { - background-color: #ffffff; - background-image: url('../img/common/banner.gif'); - background-repeat: no-repeat; - border: solid 2px #A6BDDA; - padding: 20px 20px 10px 215px; - margin-bottom: 10px; -} - -.mainPageBanner p, -.mainPageBanner li - { - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 12px; -} - -.mainPageBanner li - { - margin-bottom: 3px; -} - -.mainPageBanner ul - { - margin: 5px 0 10px 22px; - padding: 0; -} - -.mainPageBanner .welcomeText - { - font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; - color: #4A78B3; - font-size: 18px; - font-weight: bold; - margin-top: 0; - border-bottom: 1px solid #cccccc; - } - -.mainPageBanner hr { - height: 0; - border: 0; - border-bottom: 1px solid #cccccc; -} - -p.descriptionText - { - color: #555555; - font-weight: bold; - } - -.domainName - { - color: #000000; - } - -.pageContent p - { - margin: 0px; - margin-top: 10px; - padding: 5px; - } - -.pageContent li - { - padding: 2px; - } - -.formContainer - { - padding: 5px; - } - -form - { - margin: 0px; - padding: 0px; - } - -.buttonsContainer - { - margin-top: 10px; - text-align: right; - } - -.buttonsContainer .commonButton span - { - display: none; - } - -.buttonsContainer .commonButton button - { - width: 91px; - height: 21px; - text-align: center; - } - -.buttonsContainer .commonButton button - { - white-space: nowrap; - } - -.buttonsContainer .commonButton - { - margin-left: 14px; - } - -.buttonsContainer .commonButton span - { - background-position: 0 1px; - background-repeat: no-repeat; - background-color: transparent; - padding-left: 20px; - text-decoration: underline; - cursor: pointer; - padding-top: 1px; - padding-bottom: 4px; - } - -.commonButton - { - display: inline; - } - -.commonButton button - { - background-image: url('../img/glyph/btn_bg.gif'); - border: 0 solid white; - background-repeat: no-repeat; - } - -.commonButton button[disabled] - { - background-image: url('../img/glyph/btn_bg-disabled.gif'); - color: #999999; - } - -.commonButton button, -.commonButton - { - font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; - font-size: 11px; - color: #000000; - background-color: transparent; - } - -#bid-ok button - { - background-image: url('../img/glyph/btn_ok_bg.gif'); - padding-left: 8px; - } - -.formFields td.name - { - font-size: 11px; - vertical-align: top; - padding-left: 0; - padding-right: 10px; - padding-bottom: 10px; - width: 200px; - } - -.name - { - font-weight: bold; - color: #555555; - } - -legend - { - color: #0046D5; - margin-bottom: 5px; - margin-left: 0px; - padding-right: 3px; - vertical-align: middle; - padding-bottom: 3px; - } - -.testRelults - { - height: 26px; - margin-top: 5px; - margin-bottom: 10px; - border: solid 1px #999999; - padding: 5px; - padding-left: 26px; - background-repeat: no-repeat; - background-position: 5px 50%; - vertical-align: middle; - line-height: 26px; - } - -.testRelults#testSuccessful - { - background-color: #eeffee; - background-image: url('../img/icons/success.gif'); - } - -.testRelults#testFailed - { - background-color: #ffeeee; - background-image: url('../img/icons/fail.gif'); - } - -.testResult - { - vertical-align: middle; - font-weight: bold; - } - -.pageNavigation - { - padding: 5px; - background-color: #eeeeee; - } - -.pageNavigation ul - { - list-style: none; - padding: 0px; - margin: 0px; - } - -.pageNavigation li - { - display: inline; - padding: 5px; - padding-right: 0px; - white-space: nowrap; - } - -.pageNavigation a, -.pageNavigation a:link, -.pageNavigation a:visited, -.pageNavigation a:active, -.pageNavigation a:hover - { - color: #000000; - text-decoration: none; - font-weight: bold; - padding-left: 5px; - } - -.pageNavigation a:hover - { - color: #666666; - text-decoration: underline; - } - -.pathBar - { - color: #444444; - padding: 5px; - padding-top: 15px; - } - -.pathBar a:link, -.pathBar a:visited - { - color: #444444; - } - -.screenTitle - { - font-size: 18px; - font-family: "Franklin Gothic Medium", Verdana, Geneva, Arial, Helvetica, sans-serif; - color: #000000; - padding: 5px; - } - -.tabContent - { - border-left: solid 1px #999999; - border-right: solid 1px #999999; - border-bottom: solid 1px #999999; - padding: 5px; - background-color: #f9f9f9; - margin-top: 10px; - } - -.poweredBy - { - float: right; - padding: 5px; - padding-left: 0px; - } - -a img - { - border-width: 0px; - } - -.footDescription - { - float: left; - padding: 5px; - color: #2A3D9E; - height: 30px; - line-height: 30px; - vertical-align: middle; - } - -a, -a:link, -a:visited, -a:active, -a:hover - { - text-decoration: underline; - color: #324290; - } - -a:hover - { - color: #6F85F0; - } - -.iconsArea - { - padding-top: 20px; - white-space: normal; - } - -.iconsArea a, -.iconsArea a:link, -.iconsArea a:visited, -.iconsArea a:hover - { - color: #000000; - text-decoration: none; - white-space: nowrap; - } - -.icon - { - margin: 0 20px 5px 0; - display: -moz-inline-box; - display: inline-block; - width: 70px; - height: 15px; - background-image: url('../img/common/1x1.gif'); - background-repeat: no-repeat; - background-position: 50% 0%; - text-align: center; - padding-top: 35px; - cursor: pointer; - } -.icon span { - display: block; - width: 70px; - text-align: center; -} - -#asp - { - background-image: url('../img/glyph/btn_asp_bg.gif'); - } - -#aspnet - { - background-image: url('../img/glyph/btn_aspdotnet_bg.gif'); - } - -#coldfusion - { - background-image: url('../img/glyph/btn_coldfusion_bg.gif'); - } - -#perl - { - background-image: url('../img/glyph/btn_perl_bg.gif'); - } - -#php - { - background-image: url('../img/glyph/btn_php_bg.gif'); - } - -#python - { - background-image: url('../img/glyph/btn_python_bg.gif'); - } - -#ssi { - background-image: url('../img/glyph/btn_ssi_bg.gif'); -} - -#fcgi { - background-image: url('../img/glyph/btn_fast_cgi_bg.gif'); -} - -#miva { - background-image: url('../img/glyph/btn_miva_bg.gif'); -} - -.footDescription a:hover - { - color: #000066; - } -/* NewsFeeds Add */ -.dLayout { -table-layout: fixed; -border-collapse: collapse; -} - -.dColumn { -width: 50%; -vertical-align: top; -padding: 0; -} - -.dColumn.expanded { -width: 100% !important; -} - -.dBox { -margin: 10px 0 0 10px; -border-bottom: solid 1px #6f8add; -} -.first .dBox { -margin-left: 0; -} -.dBoxHeaderLayout { -height: 21px; -padding-left: 3px; -background: transparent url('../img/glyph/dBox-header-left.gif') no-repeat top left; -} -.dBoxHeaderArea { -height: 21px; -line-height: 21px; -vertical-align: middle; -overflow: hidden; -background: transparent url('../img/glyph/dBox-header-right.gif') no-repeat top right; -} -.dBoxFooterArea, -.dBoxHeaderArea { -padding: 0 5px; -white-space: nowrap; -} -.dBoxHeaderArea { -font-family: Tahoma, Arial, Helvetica, sans-serif; -font-size: 11px; -color: #fff; -font-weight: bold; -} -.dBoxHeaderArea .misc { -} -.dBoxFooterLayout { -height: 27px; -overflow: hidden; -border-left: solid 1px #6f8add; -border-right: solid 1px #6f8add; -} -.dBoxContent { -border-left: solid 1px #6f8add; -border-right: solid 1px #6f8add; -padding: 10px; -color: #000; -background-color: #ffffff; -} -.dBoxFooterArea { -background: transparent url('../img/glyph/dBox-footer-bg.gif') repeat-x; -height: 27px; -overflow: hidden; -text-align: right; -padding-right: 10px; -} -.wrapper { -clear: both; -height: 0; -overflow: hidden; -} -#refreshList { -display: -moz-inline-box; -display: inline-block; -padding-left: 20px; -background-image: url('../img/glyph/btn_refresh-list_bg.gif'); -background-repeat: no-repeat; -height: 16px; -margin-top: 5px; -} -.NFtitle { -font-weight: bold; -display: block; -} -.NFitem { -display: block; -margin-bottom: 5px; -} -.NFsource { -margin-right: 5px; -} -.NFstatus { -margin-right: 5px; -font-weight: bold; -} -.NFtime { -color: #333; -} -#testPages p { -margin: 0; -padding: 0; -} - - -/* New Top begin */ - -#topTxtBlock { - text-align: right; - margin-right: 30px; - white-space: nowrap; - height: 50px; -} - -#topCopyright { - text-align: right; - display: -moz-inline-box; - display: inline-block; - margin-right: 9px; - margin-top: 11px; -} - -#topTxtBanner { - display: -moz-inline-box; - display: inline-block; - border-left: 1px solid #dce7ff; - background-image: url('../img/common/vz_top.gif'); - background-position: 9px 3px; - background-repeat: no-repeat; - padding-left: 36px; - text-align: left; - -} - -#topCopyright a:link, -#topCopyright a:visited { - display: block; - text-decoration: none; - font-size: 11px; - color: #d6e0ff; - white-space: nowrap; -} - -#topTxtBanner a:link, -#topTxtBanner a:visited { - display: block; - text-decoration: none; - font-size: 11px; - color: #ffffff; - white-space: nowrap; -} - -.topLogo { -float: left; -} - - -/* New Top end */ -- cgit v1.2.3-70-g09d2 From ed083ad3191a5d7d61abb21fa7dafec5121ecaab Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 25 Sep 2015 18:05:37 -0400 Subject: post comment --- bucky/app/bucky.js | 22 ++++++++++++++- bucky/app/index.js | 4 +-- bucky/app/router.js | 8 +++++- bucky/db/index.js | 3 ++ bucky/util/util.js | 2 ++ public/assets/js/lib/views/index/hootbox.js | 23 +++++++++++++-- public/assets/js/vendor/view/formview.js | 44 ++++++++++++++--------------- views/partials/hootbox.ejs | 2 +- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js index 43799fe..008427d 100644 --- a/bucky/app/bucky.js +++ b/bucky/app/bucky.js @@ -1,5 +1,5 @@ var db = require('../db') -var util = require('../lib/util') +var util = require('../util/util') var _ = require('lodash') var bucky = module.exports = { @@ -136,6 +136,26 @@ var bucky = module.exports = { }) }, + /* COMMENTS */ + + createComment: function (req, res, next){ + if (! req.body.comment || ! req.body.comment.length) { + res.json({ error: "no comment" }) + return + } + var data = { + thread: res.thread.get('id'), + parent_id: req.body.parent_id || -1, + username: req.user.get('username'), + date: util.now(), + comment: req.body.comment, + } + db.createComment(data).then(function(comment){ + res.comment = comment + next() + }) + }, + /* MAIL */ ensureMailboxes: function (req, res, next){ diff --git a/bucky/app/index.js b/bucky/app/index.js index ad97526..d06b018 100644 --- a/bucky/app/index.js +++ b/bucky/app/index.js @@ -23,8 +23,8 @@ site.init = function(){ app = express() app.set('port', 5000) app.set('view engine', 'ejs') - app.set('views', path.join(__dirname, '../views')) - app.use(express.static(path.join(__dirname, '../public'))) + app.set('views', path.join(__dirname, '../../views')) + app.use(express.static(path.join(__dirname, '../../public'))) app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: false })) app.use( multer({ dest:'./uploads/' }).single("file") ) diff --git a/bucky/app/router.js b/bucky/app/router.js index 7ac6599..fe7d336 100644 --- a/bucky/app/router.js +++ b/bucky/app/router.js @@ -66,8 +66,14 @@ module.exports = function(app){ }) app.post("/api/thread/:id/comment", middleware.ensureAuthenticated, + bucky.ensureThread, + // ensure thread privacy + bucky.createComment, + // add comments and files function(req, res){ - // add comments and files + res.json({ + comment: res.comment + }) }) app.delete("/api/thread/:id", middleware.ensureAuthenticated, diff --git a/bucky/db/index.js b/bucky/db/index.js index b6fa235..77e94fa 100644 --- a/bucky/db/index.js +++ b/bucky/db/index.js @@ -111,6 +111,9 @@ db.getCommentsForThread = function (id, limit, offset, order){ db.getCommentCounts = function(ids){ return knex.column('thread').count('* as count').select().from('comments').where('thread', 'in', ids).groupBy('thread') } +db.createComment = function(comment){ + return new Comment(comment).save() +} /* KEYWORDS */ diff --git a/bucky/util/util.js b/bucky/util/util.js index e67488b..d4b6b8a 100644 --- a/bucky/util/util.js +++ b/bucky/util/util.js @@ -2,3 +2,5 @@ var util = module.exports = {} util.sanitizeName = function (s){ return (s || "").replace(new RegExp("[^-_a-zA-Z0-9]", 'g'), "") } util.sanitize = function (s){ return (s || "").replace(/<>&/g, "") } + +util.now = function(){ return Math.floor( (+ new Date()) / 1000 ) } diff --git a/public/assets/js/lib/views/index/hootbox.js b/public/assets/js/lib/views/index/hootbox.js index 9d1cc3d..4a23d32 100644 --- a/public/assets/js/lib/views/index/hootbox.js +++ b/public/assets/js/lib/views/index/hootbox.js @@ -5,10 +5,13 @@ var HootBox = FormView.extend({ events: { }, + action: "/api/thread/1/comment", + initialize: function(){ this.__super__.initialize.call(this) this.template = this.$(".template").html() this.$hoots = this.$("#hoots") + this.$comment = this.$("[name=comment]") }, load: function(comments){ @@ -31,7 +34,23 @@ var HootBox = FormView.extend({ this.$hoots.append($el) }, - success: function(){ - this.prependComment(comment) + validate: function(){ + var errors = [] + if (! this.$comment.val()) { + errors.push("no comment") + return errors + } + return null + }, + + beforeSend: function(){ + this.$comment.val("") + }, + + showErrors: function(){ + }, + + success: function(data){ + this.prependComment(data.comment) } }) \ No newline at end of file diff --git a/public/assets/js/vendor/view/formview.js b/public/assets/js/vendor/view/formview.js index 05b1ecb..7e77500 100644 --- a/public/assets/js/vendor/view/formview.js +++ b/public/assets/js/vendor/view/formview.js @@ -80,7 +80,7 @@ var FormView = View.extend({ var action = typeof this.action == "function" ? this.action() : this.action if (! action) return - + var request = $.ajax({ url: action, type: this.method, @@ -90,30 +90,27 @@ var FormView = View.extend({ processData: false, contentType: false, success: function(response){ - - if (response.error) { - var errors = [] - for (var key in response.error.errors) { - errors.push(response.error.errors[key].message); - } - if (errorCallback) { - errorCallback(errors) - } - else { - this.showErrors(errors) - } - return + if (response.error) { + var errors = [] + for (var key in response.error.errors) { + errors.push(response.error.errors[key].message); + } + if (errorCallback) { + errorCallback(errors) } else { - if (successCallback) { - successCallback(response) - } - if (this.success) { - this.success(response) - } + this.showErrors(errors) } - - + return + } + else { + if (successCallback) { + successCallback(response) + } + if (this.success) { + this.success(response) + } + } }.bind(this), error: function(response){ }.bind(this), @@ -127,7 +124,8 @@ var FormView = View.extend({ if (this.useMinotaur) { Minotaur.show() } - + + this.beforeSend && this.beforeSend() }, }) diff --git a/views/partials/hootbox.ejs b/views/partials/hootbox.ejs index c65d264..872ca68 100644 --- a/views/partials/hootbox.ejs +++ b/views/partials/hootbox.ejs @@ -1,6 +1,6 @@
- +
-- cgit v1.2.3-70-g09d2 From 8b22de467dd2d4b08ca5945e07582a80c73aa70e Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 25 Sep 2015 18:08:52 -0400 Subject: serve-favicon --- bucky/app/index.js | 3 +++ package.json | 1 + 2 files changed, 4 insertions(+) diff --git a/bucky/app/index.js b/bucky/app/index.js index d06b018..2260cfe 100644 --- a/bucky/app/index.js +++ b/bucky/app/index.js @@ -9,6 +9,7 @@ var csurf = require('csurf') var path = require('path') var multiparty = require('multiparty') var ejs = require('ejs') +var favicon = require('serve-favicon') var passport = require('passport') var sessionstore = require('sessionstore') var session = require('express-session') @@ -25,6 +26,8 @@ site.init = function(){ app.set('view engine', 'ejs') app.set('views', path.join(__dirname, '../../views')) app.use(express.static(path.join(__dirname, '../../public'))) + + app.use(favicon(__dirname + '../../public/favicon.ico')) app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: false })) app.use( multer({ dest:'./uploads/' }).single("file") ) diff --git a/package.json b/package.json index 98f3f32..fa4f441 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "mysql2": "^0.15.8", "passport": "^0.3.0", "passport-local": "^1.0.0", + "serve-favicon": "^2.3.0", "sessionstore": "^1.2.5", "skipper": "^0.5.5" } -- cgit v1.2.3-70-g09d2 From df674eef8e20c43426c0af5aa3d1a09b5e24c58a Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 25 Sep 2015 18:42:26 -0400 Subject: duh --- public/assets/css/bucky.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/assets/css/bucky.css b/public/assets/css/bucky.css index 24ed78e..9da79e5 100644 --- a/public/assets/css/bucky.css +++ b/public/assets/css/bucky.css @@ -82,7 +82,8 @@ table, tr { width: -webkit-calc(100% - 310px); width: calc(100% - 310px); } -.threads { + +#content .ledger { width: 100%; } -- cgit v1.2.3-70-g09d2