From 4ecb1a9185b4986d9206f67cf9e4e36130ae83ef Mon Sep 17 00:00:00 2001 From: Andrew Davidson Date: Sun, 15 Nov 2015 03:07:13 +0000 Subject: [PATCH] Initial commit, post creation and build is just barely working. --- .gitignore | 13 ++ app.js | 312 +++++++++++++++++++++++++++++++ build.js | 113 +++++++++++ build/.gitignore | 1 + data/logo.png | Bin 0 -> 98485 bytes db.js | 353 +++++++++++++++++++++++++++++++++++ helper.js | 64 +++++++ package.json | 22 +++ public/stylesheets/style.css | 66 +++++++ schema.sql | 123 ++++++++++++ views/admin-dashboard.jade | 75 ++++++++ views/admin-error.jade | 6 + views/admin-index.jade | 10 + views/admin-layout.jade | 20 ++ views/admin-login.jade | 14 ++ views/admin-messages.jade | 23 +++ views/admin-navbar.jade | 34 ++++ views/admin-post-edit.jade | 39 ++++ views/admin-post-list.jade | 27 +++ views/admin-post-new.jade | 36 ++++ views/admin-sidebar.jade | 25 +++ views/render-index.jade | 7 + views/render-layout.jade | 13 ++ views/render-post.jade | 6 + 24 files changed, 1402 insertions(+) create mode 100644 .gitignore create mode 100644 app.js create mode 100644 build.js create mode 100644 build/.gitignore create mode 100644 data/logo.png create mode 100644 db.js create mode 100644 helper.js create mode 100644 package.json create mode 100644 public/stylesheets/style.css create mode 100644 schema.sql create mode 100644 views/admin-dashboard.jade create mode 100644 views/admin-error.jade create mode 100644 views/admin-index.jade create mode 100644 views/admin-layout.jade create mode 100644 views/admin-login.jade create mode 100644 views/admin-messages.jade create mode 100644 views/admin-navbar.jade create mode 100644 views/admin-post-edit.jade create mode 100644 views/admin-post-list.jade create mode 100644 views/admin-post-new.jade create mode 100644 views/admin-sidebar.jade create mode 100644 views/render-index.jade create mode 100644 views/render-layout.jade create mode 100644 views/render-post.jade diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6787bcf --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.DS_Store +config.js + +logs +*.log +npm-debug.log* + +pids +*.pid + +node_modules + +preload.sql diff --git a/app.js b/app.js new file mode 100644 index 0000000..1f03ae4 --- /dev/null +++ b/app.js @@ -0,0 +1,312 @@ +var express = require('express'); +var flash = require('express-flash'); +var path = require('path'); +var passport = require('passport'); +var Strategy = require('passport-local').Strategy; +var async = require('async'); + +var helper = require('./helper.js'); +var db = require('./db.js'); +var build = require('./build.js'); + +var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +// Make HTML pretty while we're setting up our jade templates +// but it doesn't need to be pretty in production. +if (app.get('env') === 'development') { + app.locals.pretty = true; +}; + + +// uncomment after placing your favicon in /public +//app.use(require('serve-favicon')(path.join(__dirname, 'public', +// 'favicon.ico'))); +app.use(flash()); +app.use(require('morgan')('dev')); +app.use(require('cookie-parser')()); +app.use(require('body-parser').urlencoded({ extended: true })); +app.use(require('express-session')({ secret: 'amdasdfasdfamd', + resave: true, saveUninitialized: true })); +app.use(express.static(path.join(__dirname, 'public'))); + +// Get config variables +var config = require('./config'); + +// Setup authentication via twitter. +passport.use(new Strategy( + function(username, password, done) { + db.getUser(username, password, function(user) { + if (!user) { return done(null, false); } + return done(null, user); + }); + } +)); + +passport.serializeUser(function(user, done) { + done(null, user.id); +}); + +passport.deserializeUser(function(id, done) { + db.getUserById(id, function (user) { + if (!user) { return done(false); } + done(null, user); + }); +}); + +app.use(passport.initialize()); +app.use(passport.session()); + +app.get('/login', function(req, res) { + res.render('admin-login', {user: req.user}); +}); + +app.post('/login', + passport.authenticate('local', { successReturnToOrRedirect: '/admin', failureRedirect: '/login' }) +); + +app.get('/logout', function(req, res) { + req.logout(); + res.redirect('/'); +}); + +app.get('/admin/post/list/:start?', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + var count = 25; + if (req.params.start) { + var start = req.params.start; + } else { + var start = 0; + } + db.listPosts(count, start, function(posts){ + for (post in posts) { + var date = new Date(posts[post].postDate); + posts[post].dateString = date.getFullYear() + '-' + + ("0" + (date.getMonth()+1)).slice(-2) + '-' + + ("0" + date.getDate()).slice(-2); + } + res.render('admin-post-list', {posts, user: req.user}); + }); +}); + +app.get('/admin/photo/new', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + res.render('admin-photo-new', { user: req.user }); +}); + +app.get('/admin/post/new', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + db.listCategories(function(rows){ + res.render('admin-post-new', { categories: rows, user: req.user }); + }); +}); + +app.post('/admin/post/new', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + var title = req.body.title; + if (req.body.slug != "") { + slug = req.body.slug; + } else { + slug = helper.makeSlug(title); + } + var markdown = req.body.markdown; + var postDate = helper.dateToEpoch(new Date(req.body.postDate)); + var updatedDate = postDate; + var createDate = helper.dateToEpoch(new Date()); + var categoryName = req.body.category; + + db.createPost(title, slug, markdown, postDate, updatedDate, createDate, function(err, row) { + db.setPostCategory(row.id, categoryName, function(category) { + req.flash('successNotice', 'Post created.'); + res.redirect('/admin/post/edit/'+row.id); + }); + }); +}); + +app.get('/admin/post/edit/:id', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + var id = req.params.id; + async.parallel({ + categories: function(callback) { + db.listCategories(function(categories) { + callback(null, categories); + }) + }, + postCategory: function(callback) { + db.getPostCategory(id, function(category) { + callback(null, category); + }) + }, + postTags: function(callback) { + db.getPostTagsAsString(id, function(tagString) { + callback(null, tagString); + }) + }, + post: function(callback) { + db.getPostById(id, function(post) { + callback(null, post); + }) + } + }, + function(err, results) { + res.render('admin-post-edit', { + successNotice: req.flash('successNotice'), + failureNotice: req.flash('failureNotice'), + categories: results.categories, + postCategory: results.postCategory, + post: results.post, + postTags: results.postTags, + formattedDate: helper.epochToDateString(results.post.postDate), + user: req.user + }); + }); +}); + +app.post('/admin/post/edit/:id', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + var id = req.params.id; + var title = req.body.title; + var slug = helper.makeSlug(title); + var markdown = req.body.markdown; + var postDate = helper.dateToEpoch(new Date(req.body.postDate)); + var categoryName = req.body.category; + var tags = helper.parseTags(req.body.tags); + db.tagPost(id, tags); + db.updatePost(id, title, slug, markdown, postDate, function(err, row) { + db.setPostCategory(id, categoryName, function(err) { + req.flash('successNotice', 'Post updated.'); + res.redirect('/admin/post/edit/'+id); + }); + }); +}); + +app.get('/admin/post/rebuild/:id?', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + if (req.params.id) { + build.buildPost(req.params.id, function(err) { + if (!err) { + req.flash('successNotice', 'Post rebuilt successfully.'); + res.redirect('/admin/post/edit/'+req.params.id); + } + else { + req.flash('failureNotice', 'Post rebuild failed, check logs.'); + res.redirect('/admin/post/edit/'+req.params.id); + } + }); + } + else { + res.redirect('/admin/post/list'); + } + +}); + +app.get('/admin', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + async.parallel({ + categories: function(callback) { + db.countCategories(function(count) { + callback(null, count); + }); + }, + posts: function(callback) { + db.countPosts(function(count) { + callback(null, count); + }); + }, + galleries: function(callback) { + db.countGalleries(function(count) { + callback(null, count); + }); + }, + photos: function(callback) { + db.countPhotos(function(count) { + callback(null, count); + }); + }, + tags: function(callback) { + db.countTags(function(count) { + callback(null, count); + }); + }, + rebuildDate: function(callback) { + db.getLastRebuildDate(function(date) { + var dateString = helper.epochToDateString(date.date).slice(0,-14); + callback(null, dateString); + }); + }, + uploadDate: function(callback) { + db.getLastUploadDate(function(date) { + var dateString = helper.epochToDateString(date.date).slice(0,-14); + callback(null, dateString); + }); + } + }, + function(err, results) { + res.render('admin-dashboard', { + categories: results.categories, + posts: results.posts, + galleries: results.galleries, + photos: results.photos, + tags: results.tags, + rebuildDate: results.rebuildDate, + uploadDate: results.uploadDate, + user: req.user}); + } + ); +}); + +app.get('/', function(req, res, next) { + res.render('admin-index', { title: 'AMDavidson.com', user: req.user }); +}); + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handlers + +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.render('admin-error', { + message: err.message, + error: err, + user: req.user + }); + }); +} + +// production error handler +// no stacktraces leaked to user +app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + user: req.user, + error: {} + }); +}); + + +app.set('port', process.env.PORT || 3000) +var server = require('http').createServer(app) + +server.listen(app.get('port'), function() { + console.log("Server listening on port " + app.get('port')); +}); diff --git a/build.js b/build.js new file mode 100644 index 0000000..ae40001 --- /dev/null +++ b/build.js @@ -0,0 +1,113 @@ +var fs = require('fs'); +var mkdirp = require('mkdirp'); +var jade = require('jade'); +var markdown = require( "markdown" ).markdown; +var async = require('async'); + +var helper = require('./helper.js'); +var db = require('./db.js'); + +// Build all archive pages associated with a particular post ID +// This currently calls the functions to make the yearly and monthly archives. +var buildPostArchives = function (id, cb) { + db.getPostById(id, function(post) { + console.log('Building dependencies for Post: '+id); + var date = new Date(post.postDate); + var year = date.getFullYear(); + console.log('Building archive for year: '+year); + var month = date.getMonth()+1; + async.parallel({ + monthArchiveErr: function(callback) { + buildPostMonthArchive(year, function(err) { + callback(null, err); + }); + }, + yearArchiveErr: function(callback) { + buildPostYearArchive(month, function(err) { + callback(null, err); + }); + } + }, function(err, results) { + if (!yearArchiveErr && !monthArchiveErr) { + cb(null); + } + else if (yearArchiveErr) { + cb(yearArchiveErr); + } + else if (monthArchiveErr) { + cb(monthArchiveErr); + } + else { + cb(null); + } + }); + + }); +} +exports.buildPostArchives = buildPostArchives; + + +// Function that builds the yearly archive pages. +// TODO: make this not a skeleton. +// TODO: create pagination. +var buildPostYearArchive = function (year, cb) { + console.log('Building archive for year: '+year); + cb(null); +} +exports.buildPostYearArchive = buildPostYearArchive; + + +// Function that builds the monthly archive pages. +// TODO: Make this not a skeleton. +// TODO: create pagination. +var buildPostMonthArchive = function (month, cb) { + console.log('Building archive for month: '+month); + cb(null); +} +exports.buildPostMonthArchive = buildPostMonthArchive; + + +// Function to build a single post page. +// TODO: (re)build images as required. +var buildPost = function (id, cb) { + db.getPostById(id, function(post) { + console.log('Fetching post id: '+id); + var title = post.title; + var content = markdown.toHTML(post.markdown); + var slug = post.slug; + var postDate = helper.epochToShortDateString(post.postDate); + var url = '/blog/'+postDate.slice(0,4)+'/'+postDate.slice(5,7)+'/'+slug+'/'; + var filepath = 'build'+url; + var filename = filepath+'index.html'; + var options = { + pretty: false, + title: title, + content: content, + slug: slug, + url: url, + postDate: postDate + }; + + console.log('Rendering post: '+title); + var jadeOut = jade.renderFile('views/render-post.jade', options); + + console.log('Creating directory: '+filepath); + mkdirp(filepath, function(err) { + if (err) { + console.log(err); + } + else { + console.log('Writing to file: '+filename); + + //console.log(jadeOut); + + fs.writeFile(filename, jadeOut, 'utf-8', function(err) { + if (err) console.log(err); + cb(err); + }); + } + }); + }); +} + +exports.buildPost = buildPost; diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..f2c4ee5 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1 @@ +*.* diff --git a/data/logo.png b/data/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..44c731597f0154702d33fefc89ae97bc5992942a GIT binary patch literal 98485 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 li > a { + padding-right: 20px; + padding-left: 20px; +} +.nav-sidebar > form > button { + margin-left: 20px; +} + +.nav-sidebar > .active > a, +.nav-sidebar > .active > a:hover, +.nav-sidebar > .active > a:focus { + color: #fff; + background-color: #428bca; +} diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..7c3a4cb --- /dev/null +++ b/schema.sql @@ -0,0 +1,123 @@ +-- SQL Schema for Crunch + +-- Note all dates must be in epoch seconds to allow for sqlite comparison + +-- User table + +DROP TABLE IF EXISTS "users"; + +CREATE TABLE "users" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "username" TEXT NOT NULL UNIQUE, + "password" TEXT NOT NULL, -- sha256 hash of plaintext password + salt + "salt" TEXT NOT NULL, -- salt that is appended to the password + "email" TEXT UNIQUE, + "displayName" TEXT, + "createDate" TEXT +); + +-- Content Tables + +DROP TABLE IF EXISTS "posts"; + +CREATE TABLE "posts" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "title" TEXT, -- The title of the post + "slug" TEXT NOT NULL, -- A slug form of the title or id + "markdown" TEXT NOT NULL, -- The post content in markdown format + "postDate" INTEGER, -- The date that the post should go live and be sorted by + "updatedDate" INTEGER, -- The date that the post was last updated + "createDate" INTEGER NOT NULL, -- The date the post was created + "lastBuildDate" INTEGER, -- The date this post was last built + "lastUpload" INTEGER -- The date the post was last uploaded +); + +DROP TABLE IF EXISTS "galleries"; + +CREATE TABLE "galleries" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "title" TEXT, -- The title of the gallery + "slug" TEXT NOT NULL UNIQUE, -- A slug form of the title or id + "description" TEXT NOT NULL, -- The gallery description in markdown format + "postDate" INTEGER, -- The date that the gallery should go live and be sorted by + "updatedDate" INTEGER, -- The date that the gallery was last updated + "createDate" INTEGER NOT NULL, -- The date the gallery was created + "lastBuildDate" INTEGER, -- The date this gallery was last built + "lastUpload" INTEGER -- The date the gallery was last uploaded +); + +DROP TABLE IF EXISTS "photos"; + +CREATE TABLE "photos" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "path" TEXT NOT NULL, -- The path of the photo location on disk + "title" TEXT, -- The title of the photo + "slug" TEXT NOT NULL UNIQUE, -- A slug form of the title or id + "description" TEXT NOT NULL, -- The photo description in markdown format + "photoDate" INTEGER, -- The date that the photo should go live and be sorted by + "updatedDate" INTEGER, -- The date that the photo was last updated + "createDate" INTEGER NOT NULL, -- The date the photo was created + "lastBuildDate" INTEGER, -- The date this photo was last built + "lastUpload" INTEGER -- The date the photo was last uploaded +); + +DROP TABLE IF EXISTS "galleryPhotos"; + +CREATE TABLE "galleryPhotos" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "galleryId" INTEGER NOT NULL, -- the id of the gallery + "photoId" INTEGER NOT NULL, -- the id of the photo + FOREIGN KEY(galleryId) REFERENCES galleries(id), + FOREIGN KEY(photoId) REFERENCES photos(id) +); + +DROP TABLE IF EXISTS "categories"; + +CREATE TABLE "categories" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL, -- The name of this category + "slug" TEXT NOT NULL UNIQUE, -- A slug form of the name or id + "description" TEXT, -- A brief description of the category in markdown + "createDate" INTEGER NOT NULL -- The date the category was created +); + +INSERT INTO "categories" VALUES (1, "Uncategorized", "uncategorized", "Uncategorized posts", (strftime('%s','now')*1000)); + +DROP TABLE IF EXISTS "categoryPosts"; + +CREATE TABLE "categoryPosts" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "categoryId" INTEGER NOT NULL, -- the id of the category + "postId" INTEGER NOT NULL, -- the id of the post + FOREIGN KEY(categoryId) REFERENCES categories(id), + FOREIGN KEY(postId) REFERENCES posts(id) +); + +DROP TABLE IF EXISTS "tags"; + +CREATE TABLE "tags" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL, -- The name of this tag + "slug" TEXT NOT NULL UNIQUE, -- A slug form of the name or id + "createDate" INTEGER NOT NULL -- The date the tag was created +); + +DROP TABLE IF EXISTS "postTags"; + +CREATE TABLE "postTags" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "postId" INTEGER NOT NULL, -- the id of the post + "tagId" INTEGER NOT NULL, -- the id of the tag + FOREIGN KEY(postId) REFERENCES posts(id), + FOREIGN KEY(tagId) REFERENCES tags(id) +); + +DROP TABLE IF EXISTS "photoTags"; + +CREATE TABLE "photoTags" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "photoId" INTEGER NOT NULL, -- the id of the photo + "tagId" INTEGER NOT NULL, -- the id of the tag + FOREIGN KEY(photoId) REFERENCES photos(id), + FOREIGN KEY(tagId) REFERENCES tags(id) +); diff --git a/views/admin-dashboard.jade b/views/admin-dashboard.jade new file mode 100644 index 0000000..27a29ab --- /dev/null +++ b/views/admin-dashboard.jade @@ -0,0 +1,75 @@ +extends admin-layout + +block content + div(class="row") + include ./admin-sidebar.jade + + div(class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main") + h1(class="page-header") Crunch Dashboard + + include ./admin-messages.jade + + div(class="row") + div(class="col-md-6") + div(class="panel panel-success") + div(class="panel-heading") + h3(class="panel-title") Last Upload (UTC) + + div(class="panel-body") + h3 #{uploadDate} + + div(class="col-md-6") + div(class="panel panel-danger") + div(class="panel-heading") + h3(class="panel-title") Last Rebuild (UTC) + + div(class="panel-body") + h3 #{rebuildDate} + + div(class="row") + div(class="col-md-4") + div(class="panel panel-info") + div(class="panel-heading") + h3(class="panel-title") Number of Posts + div(class="panel-body") + h3: a(href="/admin/post/list") #{posts} + form(action="/admin/post/new", method="get") + button(class="btn btn-sm btn-primary") New Post + + + div(class="col-md-4") + div(class="panel panel-info") + div(class="panel-heading") + h3(class="panel-title") Number of Galleries + + div(class="panel-body") + h3: a(href="/admin/gallery/list") #{galleries} + form(action="/admin/gallery/new", method="get") + button(class="btn btn-sm btn-primary") New Gallery + + div(class="col-md-4") + div(class="panel panel-info") + div(class="panel-heading") + h3(class="panel-title") Number of Photos + + div(class="panel-body") + h3: a(href="/admin/photo/list") #{photos} + form(action="/admin/photo/new", method="get") + button(class="btn btn-sm btn-primary") New Photo + + div(class="row") + div(class="col-md-6") + div(class="panel panel-info") + div(class="panel-heading") + h3(class="panel-title") Number of Tags + + div(class="panel-body") + h3 #{tags} + + div(class="col-md-6") + div(class="panel panel-info") + div(class="panel-heading") + h3(class="panel-title") Number of Categories + + div(class="panel-body") + h3: a(href="/admin/category/list") #{categories} diff --git a/views/admin-error.jade b/views/admin-error.jade new file mode 100644 index 0000000..d5ee170 --- /dev/null +++ b/views/admin-error.jade @@ -0,0 +1,6 @@ +extends admin-layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/views/admin-index.jade b/views/admin-index.jade new file mode 100644 index 0000000..253e799 --- /dev/null +++ b/views/admin-index.jade @@ -0,0 +1,10 @@ +extends admin-layout + +block content + div(class="page-header row col-sm-10") + h1 Crunch + div(class="row col-sm-10") + include ./admin-messages.jade + + div + p If you don't know why you're here, please head #[a(href='http://youtube.com') somewhere else] diff --git a/views/admin-layout.jade b/views/admin-layout.jade new file mode 100644 index 0000000..ddb99b6 --- /dev/null +++ b/views/admin-layout.jade @@ -0,0 +1,20 @@ +doctype html +html + head + title= title + meta(charset="utf-8") + meta(http-equiv="X-UA-Compatible", content="IE=edge") + meta(name="viewport", content="width=device-width, initial-scale=1") + //-link(href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css", rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous") + link(href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/yeti/bootstrap.min.css", rel="stylesheet" integrity="sha256-gJ9rCvTS5xodBImuaUYf1WfbdDKq54HCPz9wk8spvGs= sha512-weqt+X3kGDDAW9V32W7bWc6aSNCMGNQsdOpfJJz/qD/Yhp+kNeR+YyvvWojJ+afETB31L0C4eO0pcygxfTgjgw==" crossorigin="anonymous") + link(rel='stylesheet', href='/stylesheets/style.css') + block head-addition + body(role="document") + include ./admin-navbar.jade + div(class="container-fluid", role="main") + block content + + script(src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js") + script(src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha256-Sk3nkD6mLTMOF0EOpNtsIry+s1CsaqQC1rVLTAy+0yc= sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous") + + block footer diff --git a/views/admin-login.jade b/views/admin-login.jade new file mode 100644 index 0000000..f43d05a --- /dev/null +++ b/views/admin-login.jade @@ -0,0 +1,14 @@ +extends admin-layout + +block content + div(class="page-header row col-sm-6 col-sm-offset-3") + h1 Login + div(class="row col-sm-6 col-sm-offset-3") + form(action="/login", method="post") + div(class="form-group form-horizontal") + label(class="control-label", for="username") Username: + input(class="form-control", type="text", name="username") + div(class="form-group") + label(class="control-label", for="password") Password: + input(class="form-control", type="password", name="password") + button(class="btn btn-success", type="submit") Log In diff --git a/views/admin-messages.jade b/views/admin-messages.jade new file mode 100644 index 0000000..8335390 --- /dev/null +++ b/views/admin-messages.jade @@ -0,0 +1,23 @@ +if (failureNotice) + if (failureNotice.length > 0) + div(class="alert alert-danger alert-dismissible" role="alert") + button(type="button" class="close" data-dismiss="alert" aria-label="Close") + span(aria-hidden="true") × + strong Failure! + | #{failureNotice} + +if (warningNotice) + if (warningNotice.length > 0) + div(class="alert alert-warning alert-dismissible" role="alert") + button(type="button" class="close" data-dismiss="alert" aria-label="Close") + span(aria-hidden="true") × + strong Warning! + | #{warningNotice} + +if (successNotice) + if (successNotice.length > 0) + div(class="alert alert-success alert-dismissible" role="alert") + button(type="button" class="close" data-dismiss="alert" aria-label="Close") + span(aria-hidden="true") × + strong Success! + | #{successNotice} diff --git a/views/admin-navbar.jade b/views/admin-navbar.jade new file mode 100644 index 0000000..582d414 --- /dev/null +++ b/views/admin-navbar.jade @@ -0,0 +1,34 @@ +nav(class="navbar navbar-inverse navbar-fixed-top") + div(class="container-fluid") + div(class="navbar-header") + button(type="button", class="navbar-toggle collapsed", data-toggle="collapse", data-target="#navbar", aria-expanded="false", aria-controls="navbar") + span(class="sr-only") Toggle Navbar + span(class="icon-bar") + span(class="icon-bar") + span(class="icon-bar") + a(class="navbar-brand", href="#") Crunch + div(id="navbar", class="collapse navbar-collapse") + ul(class="nav navbar-nav") + if(!user) + li + a(href="/") + span(class="glyphicon glyphicon-home") Home + li + a(href="/login") + span(class="glyphicon glyphicon-log-in") Login + if(user) + li + a(href="/admin") + span(class="glyphicon glyphicon-home") Dashboard + li + a(href="/admin/post/new") + span(class="glyphicon glyphicon-file") Post + li + a(href="/admin/photo/new") + span(class="glyphicon glyphicon-picture") Photo + li + a(href="/admin/gallery/new") + span(class="glyphicon glyphicon-th-large") Gallery + li + a(href="/logout") + span(class="glyphicon glyphicon-log-out") Logout diff --git a/views/admin-post-edit.jade b/views/admin-post-edit.jade new file mode 100644 index 0000000..8bce4c6 --- /dev/null +++ b/views/admin-post-edit.jade @@ -0,0 +1,39 @@ +extends admin-layout + +block content + div(class="row") + include ./admin-sidebar.jade + + div(class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main") + h1(class="page-header") Edit Post + + include ./admin-messages.jade + + form(method="post", action="/admin/post/edit/#{post.id}") + div(class="row page-header") + div(class="input-group input-group-lg col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(class="form-control", type="text", name="title", placeholder="Enter title", value="#{post.title}") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(class="form-control", type="text", name="slug", placeholder="Enter slug (optional)", value="#{post.slug}") + div(class="row page-header") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + div(class="input-group-btn") + button(type="button", class="btn btn-primary dropdown-toggle", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Category + ul(class="dropdown-menu") + each row in categories + li: a(href="#", onClick="document.getElementById('category').value = '#{row.name}'") #{row.name} + input(type="text", class="form-control", aria-label="Post category", name="category", id="category" value="#{postCategory.name}") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(type="text", class="form-control", placeholder="Publish Date", name="postDate", value="#{formattedDate}") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(type="text", class="form-control", placeholder="Tags", name="tags" value="#{postTags}") + div(class="row page-header") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + textarea(class="form-control", rows="12", name="markdown") + | #{post.markdown} + div(class="row") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + div(class="pull-left") + button(type="submit", class="btn btn-lg btn-success", name="submit") Update Post + div(class="pull-right") + button(type="submit", class="btn btn-lg btn-danger", name="submit") Delete Post diff --git a/views/admin-post-list.jade b/views/admin-post-list.jade new file mode 100644 index 0000000..606d872 --- /dev/null +++ b/views/admin-post-list.jade @@ -0,0 +1,27 @@ +extends admin-layout + +block content + div(class="row") + include ./admin-sidebar.jade + + div(class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main") + h1(class="page-header") Posts + + include ./admin-messages.jade + + table(class="table table-striped") + each post in posts + tr + td #{post.id} + td #{post.title} + td #{post.dateString} + td + a(href="/admin/post/edit/#{post.id}") Edit Post + | - + a(href="/admin/post/delete/#{post.id}") Delete Post + | - + a(href="/admin/post/rebuild/#{post.id}") Force Rebuild + | - + a(href="/admin/post/publish/#{post.id}") Force Publish + + diff --git a/views/admin-post-new.jade b/views/admin-post-new.jade new file mode 100644 index 0000000..fdc00e0 --- /dev/null +++ b/views/admin-post-new.jade @@ -0,0 +1,36 @@ +extends admin-layout + +block content + div(class="row") + include ./admin-sidebar.jade + + div(class="col-sm-10 col-sm-offset-2 col-md-10 col-md-offset-2 main") + h1(class="page-header") New Post + + include ./admin-messages.jade + + form(method="post", action="/admin/post/new") + div(class="row page-header") + div(class="input-group input-group-lg col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(class="form-control", type="text", name="title", placeholder="Enter title") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(class="form-control", type="text", name="slug", placeholder="Enter slug (optional)") + div(class="row page-header") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + div(class="input-group-btn") + button(type="button", class="btn btn-primary dropdown-toggle", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Category + ul(class="dropdown-menu") + each row in categories + li: a(href="#", onClick="document.getElementById('category').value = '#{row.name}'") #{row.name} + input(type="text", class="form-control", aria-label="Post category", name="category", id="category", value="Uncategorized") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(type="text", class="form-control", placeholder="Publish Date", name="postDate") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + input(type="text", class="form-control", placeholder="Tags", name="tags") + div(class="row page-header") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1") + textarea(class="form-control", rows="12", name="markdown", placeholder="Markdown formatted content") + div(class="row") + div(class="input-group col-xs-10 col-xs-offset-1 col-md-10 col-md-offset-1 centern") + div(class="pull-left") + button(type="submit", class="btn btn-lg btn-success", name="submit") Create Post diff --git a/views/admin-sidebar.jade b/views/admin-sidebar.jade new file mode 100644 index 0000000..ee47512 --- /dev/null +++ b/views/admin-sidebar.jade @@ -0,0 +1,25 @@ +div(class="col-sm-3 col-md-2 sidebar") + ul(class="nav nav-sidebar") + li: a(href="/admin/") Dashboard + + ul(class="nav nav-sidebar") + li: a(href="/admin/post/new") New Post + li: a(href="/admin/post/list") Edit Post + + ul(class="nav nav-sidebar") + li: a(href="/admin/category/new") New Category + li: a(href="/admin/category/list") Edit Category + + ul(class="nav nav-sidebar") + li: a(href="/admin/gallery/new") New Gallery + li: a(href="/admin/gallery/list") Edit Gallery + + ul(class="nav nav-sidebar") + form(action="/admin/rebuild/", method="get") + button(class="btn btn-lg btn-success") + span(class="glyphicon glyphicon-repeat") Build + + ul(class="nav nav-sidebar") + form(action="/admin/publish/", method="get") + button(class="btn btn-lg btn-warning") + span(class="glyphicon glyphicon-upload") Upload diff --git a/views/render-index.jade b/views/render-index.jade new file mode 100644 index 0000000..11b2400 --- /dev/null +++ b/views/render-index.jade @@ -0,0 +1,7 @@ +extends render-layout + +block content + each post in posts + h3: a(href="#{url}") #{title} + p #{postDate} + div !{content} diff --git a/views/render-layout.jade b/views/render-layout.jade new file mode 100644 index 0000000..32bc023 --- /dev/null +++ b/views/render-layout.jade @@ -0,0 +1,13 @@ +doctype html +html + head + title #{title} + meta(charset="utf-8") + meta(http-equiv="X-UA-Compatible", content="IE=edge") + meta(name="viewport", content="width=device-width, initial-scale=1") + link(href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css", rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous") + link(rel='stylesheet', href='/stylesheets/style.css') + block head-addition + body(role="document") + div(class="container-fluid", role="main") + block content diff --git a/views/render-post.jade b/views/render-post.jade new file mode 100644 index 0000000..ae775bf --- /dev/null +++ b/views/render-post.jade @@ -0,0 +1,6 @@ +extends render-layout + +block content + h3: a(href="#{url}") #{title} + p #{postDate} + div !{content}