diff --git a/app.js b/app.js index 1f03ae4..eafeb63 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,8 @@ var path = require('path'); var passport = require('passport'); var Strategy = require('passport-local').Strategy; var async = require('async'); +var multer = require('multer'); +var fs = require('fs'); var helper = require('./helper.js'); var db = require('./db.js'); @@ -33,8 +35,10 @@ app.use(require('express-session')({ secret: 'amdasdfasdfamd', resave: true, saveUninitialized: true })); app.use(express.static(path.join(__dirname, 'public'))); +var upload = multer({ dest: 'data/uploads/' }) + // Get config variables -var config = require('./config'); +var config = require('./config.js').config; // Setup authentication via twitter. passport.use(new Strategy( @@ -60,6 +64,10 @@ passport.deserializeUser(function(id, done) { app.use(passport.initialize()); app.use(passport.session()); +// Require logins for all admin pages. +app.all('/admin/*', require('connect-ensure-login').ensureLoggedIn()); + +// User management routing app.get('/login', function(req, res) { res.render('admin-login', {user: req.user}); }); @@ -73,8 +81,8 @@ app.get('/logout', function(req, res) { res.redirect('/'); }); +// Post management routing app.get('/admin/post/list/:start?', - require('connect-ensure-login').ensureLoggedIn(), function(req, res, next) { var count = 25; if (req.params.start) { @@ -93,14 +101,7 @@ app.get('/admin/post/list/:start?', }); }); -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 }); @@ -108,22 +109,27 @@ app.get('/admin/post/new', }); 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; + var slug = req.body.slug; } else { - slug = helper.makeSlug(title); + var slug = helper.makeSlug(title); } var markdown = req.body.markdown; - var postDate = helper.dateToEpoch(new Date(req.body.postDate)); + if (req.body.postDate != "") { + var postDate = helper.dateToEpoch(new Date(req.body.postDate)); + } else { + var postDate = helper.dateToEpoch(new Date()); + } var updatedDate = postDate; var createDate = helper.dateToEpoch(new Date()); var categoryName = req.body.category; + var tags = helper.parseTags(req.body.tags); db.createPost(title, slug, markdown, postDate, updatedDate, createDate, function(err, row) { db.setPostCategory(row.id, categoryName, function(category) { + db.tagPost(row.id, tags); req.flash('successNotice', 'Post created.'); res.redirect('/admin/post/edit/'+row.id); }); @@ -131,7 +137,6 @@ app.post('/admin/post/new', }); app.get('/admin/post/edit/:id', - require('connect-ensure-login').ensureLoggedIn(), function(req, res, next) { var id = req.params.id; async.parallel({ @@ -157,11 +162,16 @@ app.get('/admin/post/edit/:id', } }, function(err, results) { + if (results.postCategory) { + var categoryName = results.postCategory.name; + } else { + var categoryName = null; + } res.render('admin-post-edit', { successNotice: req.flash('successNotice'), failureNotice: req.flash('failureNotice'), categories: results.categories, - postCategory: results.postCategory, + postCategory: categoryName, post: results.post, postTags: results.postTags, formattedDate: helper.epochToDateString(results.post.postDate), @@ -171,15 +181,15 @@ app.get('/admin/post/edit/:id', }); 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 slug = req.body.slug; 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); + console.log('Post '+id+' update request received'); db.tagPost(id, tags); db.updatePost(id, title, slug, markdown, postDate, function(err, row) { db.setPostCategory(id, categoryName, function(err) { @@ -190,7 +200,6 @@ app.post('/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) { @@ -210,8 +219,119 @@ app.get('/admin/post/rebuild/:id?', }); +// Photo management Routing +app.get('/admin/photo/list/:start?', + function(req, res, next) { + var count = 25; + if (req.params.start) { + var start = req.params.start; + } else { + var start = 0; + } + db.listPhotos(count, start, function(photos){ + for (photo in photos) { + var date = new Date(photos[photo].photoDate); + photos[photo].dateString = date.getFullYear() + '-' + + ("0" + (date.getMonth()+1)).slice(-2) + '-' + + ("0" + date.getDate()).slice(-2); + } + res.render('admin-photo-list', {photos, user: req.user}); + }); +}); + +app.get('/admin/photo/new', + function(req, res, next) { + res.render('admin-photo-new', { user: req.user }); +}) + +app.post('/admin/photo/new', + upload.single('photo'), + function(req, res, next) { + console.log(req.file); + if ( req.body.title != "") { + var title = req.body.title; + } + else { + var title = req.file.originalname.split('.').slice(0,-1).join(' '); + } + if (req.body.photoDate != "") { + var photoDate = helper.dateToEpoch(new Date(req.body.photoDate)); + } + else { + var photoDate = helper.dateToEpoch(new Date()); + } + if (req.body.slug != "") { + var slug = req.body.slug; + } + else if ( req.body.title != "" ){ + var slug = helper.makeSlug(title); + } + else { + var cleanFileName = req.file.originalname.split('.').slice(0,-1).join('-'); + var slug = helper.makeSlug(cleanFileName+'-'+photoDate); + } + var tags = helper.parseTags(req.body.tags); + var markdown = req.body.markdown; + var updatedDate = photoDate; + var createDate = helper.dateToEpoch(new Date()); + var categoryName = req.body.category; + var path = req.file.path; + + db.createPhoto(title, slug, markdown, photoDate, updatedDate, createDate, path, function(err, row) { + console.log(row); + db.tagPhoto(row.id, tags); + req.flash('successNotice', 'Photo created.'); + res.redirect('/admin/'); + }); +}); + +app.get('/admin/photo/edit/:id', + function(req, res, next) { + var id = req.params.id; + async.parallel({ + photoTags: function(callback) { + db.getPhotoTagsAsString(id, function(tagString) { + callback(null, tagString); + }) + }, + photo: function(callback) { + db.getPhotoById(id, function(photo) { + callback(null, photo); + }) + } + }, + function(err, results) { + res.render('admin-photo-edit', { + successNotice: req.flash('successNotice'), + failureNotice: req.flash('failureNotice'), + photo: results.photo, + photoTags: results.photoTags, + formattedDate: helper.epochToDateString(results.photo.photoDate), + user: req.user + }); + }); +}); + +app.post('/admin/photo/edit/:id', + function(req, res, next) { + var id = req.params.id; + var title = req.body.title; + var slug = req.body.slug; + var markdown = req.body.markdown; + var photoDate = helper.dateToEpoch(new Date(req.body.photoDate)); + var tags = helper.parseTags(req.body.tags); + console.log('Post '+id+' update request received'); + db.tagPhoto(id, tags); + db.updatePhoto(id, title, slug, markdown, photoDate, function(err, row) { + req.flash('successNotice', 'Photo updated.'); + res.redirect('/admin/photo/edit/'+id); + }); +}); + + + +// Admin dashboard page. app.get('/admin', - require('connect-ensure-login').ensureLoggedIn(), function(req, res, next) { async.parallel({ categories: function(callback) { @@ -241,19 +361,21 @@ app.get('/admin', }, rebuildDate: function(callback) { db.getLastRebuildDate(function(date) { - var dateString = helper.epochToDateString(date.date).slice(0,-14); + var dateString = helper.epochToDateString(date.date).slice(0,-12); callback(null, dateString); }); }, uploadDate: function(callback) { db.getLastUploadDate(function(date) { - var dateString = helper.epochToDateString(date.date).slice(0,-14); + var dateString = helper.epochToDateString(date.date).slice(0,-12); callback(null, dateString); }); } }, function(err, results) { res.render('admin-dashboard', { + successNotice: req.flash('successNotice'), + failureNotice: req.flash('failureNotice'), categories: results.categories, posts: results.posts, galleries: results.galleries, @@ -266,6 +388,92 @@ app.get('/admin', ); }); +// Routes for previewing sent versions of the built items. +app.get('/blog/*', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + if (req.params[0] != '') { + var path = __dirname + '/build/blog/' + req.params[0]; + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + else { + console.log(path + ' does not exist...'); + if (path.slice(-1) != '/') path += '/'; + path += 'index.html' + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + }); + } + }); + } + } +); + +app.get('/photos/*', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + if (req.params[0] != '') { + var path = __dirname + '/build/photos/' + req.params[0]; + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + else { + console.log(path + ' does not exist...'); + if (path.slice(-1) != '/') path += '/'; + path += 'index.html' + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + }); + } + }); + } + } +); + +app.get('/galleries/*', + require('connect-ensure-login').ensureLoggedIn(), + function(req, res, next) { + if (req.params[0] != '') { + var path = __dirname + '/build/galleries/' + req.params[0]; + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + else { + console.log(path + ' does not exist...'); + if (path.slice(-1) != '/') path += '/'; + path += 'index.html' + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + }); + } + }); + } + } +); + +// Have to have some sort of home page. app.get('/', function(req, res, next) { res.render('admin-index', { title: 'AMDavidson.com', user: req.user }); }); diff --git a/data/uploads/028f89c0fce0a9b7e7a502463b2ef4ab b/data/uploads/028f89c0fce0a9b7e7a502463b2ef4ab new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/028f89c0fce0a9b7e7a502463b2ef4ab differ diff --git a/data/uploads/079865cad95566595cdf759a8299e583 b/data/uploads/079865cad95566595cdf759a8299e583 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/079865cad95566595cdf759a8299e583 differ diff --git a/data/uploads/56f468c284788419bc512912ffa92a10 b/data/uploads/56f468c284788419bc512912ffa92a10 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/56f468c284788419bc512912ffa92a10 differ diff --git a/data/uploads/5c6ccd44082e66a34054fefee7084bc7 b/data/uploads/5c6ccd44082e66a34054fefee7084bc7 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/5c6ccd44082e66a34054fefee7084bc7 differ diff --git a/data/uploads/8ebac3195e597b01c964632fc654fcd4 b/data/uploads/8ebac3195e597b01c964632fc654fcd4 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/8ebac3195e597b01c964632fc654fcd4 differ diff --git a/data/uploads/9c4f8478bf14d1634210b05150a2c2b8 b/data/uploads/9c4f8478bf14d1634210b05150a2c2b8 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/9c4f8478bf14d1634210b05150a2c2b8 differ diff --git a/data/uploads/adb2d841ac54ded11de821c18624471c b/data/uploads/adb2d841ac54ded11de821c18624471c new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/adb2d841ac54ded11de821c18624471c differ diff --git a/data/uploads/aecb2a9e7f05855a88e40375771722eb b/data/uploads/aecb2a9e7f05855a88e40375771722eb new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/aecb2a9e7f05855a88e40375771722eb differ diff --git a/data/uploads/b4a4ab36382c78301c694781ddcde451 b/data/uploads/b4a4ab36382c78301c694781ddcde451 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/b4a4ab36382c78301c694781ddcde451 differ diff --git a/data/uploads/c71ebc37c19f19793f156ea867759d7b b/data/uploads/c71ebc37c19f19793f156ea867759d7b new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/c71ebc37c19f19793f156ea867759d7b differ diff --git a/data/uploads/c7ff1b41545d5e9fc8ce44393a9e3e86 b/data/uploads/c7ff1b41545d5e9fc8ce44393a9e3e86 new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/c7ff1b41545d5e9fc8ce44393a9e3e86 differ diff --git a/data/uploads/ccf08d5995bbbf617ff70a8496a1497e b/data/uploads/ccf08d5995bbbf617ff70a8496a1497e new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/ccf08d5995bbbf617ff70a8496a1497e differ diff --git a/data/uploads/ea11cb7ee99ea7fa5c67357ab106dd2e b/data/uploads/ea11cb7ee99ea7fa5c67357ab106dd2e new file mode 100644 index 0000000..44c7315 Binary files /dev/null and b/data/uploads/ea11cb7ee99ea7fa5c67357ab106dd2e differ diff --git a/db.js b/db.js index 04c1e4c..ea929ec 100644 --- a/db.js +++ b/db.js @@ -1,8 +1,11 @@ var sqlite = require('sqlite3').verbose(); -var db = new sqlite.Database('./app.db'); -var helper = require('./helper.js'); var async = require('async'); +var config = require('./config.js').config; +var helper = require('./helper.js'); + +var db = new sqlite.Database(config.dbPath); + // Function to get a user record by the username and password // Returns SQL row for that user exports.getUser = function(username, password, cb) { @@ -112,25 +115,45 @@ exports.listPosts = function(count, start, cb) { }); } +// Function to get a list of photos of a certain count and starting at an offset +// Returns a list of photo objects +exports.listPhotos = function(count, start, cb) { + db.all('SELECT * FROM photos ORDER BY photoDate DESC, title ASC \ + LIMIT '+count+' OFFSET '+start+';', + function(err, photos) { + console.log(err); + cb(photos); + }); +} + // NON-EXPORTED function to create a category if it does not exist // Returns a row of category information var getOrCreateCategory = function(name, cb) { db.get('SELECT * FROM categories WHERE name = "'+name+'";', function(err, row) { - if (!err) { + if (!err && row) { + console.log('Category '+name+' exists.'); cb(row); } else { + console.log('Category '+name+' does not exist. Creating...'); epoch = helper.dateToEpoch(new Date()); db.run('INSERT INTO categories (\ - name, slug, description, createDate, updatedDate, \ - lastBuildDate) VALUES (\ - name = "'+name+'", \ - slug = "'+helper.makeSlug('name')+'", \ - createDate = '+epoch+');', + name, slug, createDate \ + ) VALUES (\ + "'+name+'", \ + "'+helper.makeSlug(name)+'", \ + '+epoch+');', function(err, row) { - db.get('SELECT * FROM categories WHERE name = "'+name+'";', - function(err, row){ - cb(row); - }) + if (err) { + console.log(err); + } + else { + console.log('Category '+name+' created.'); + db.get('SELECT * FROM categories WHERE name = "'+name+'";', + function(err, row){ + cb(row); + }) + } + }) } }) @@ -139,26 +162,42 @@ var getOrCreateCategory = function(name, cb) { // Function to set a category for a post given a post id and a category name // Returns error code exports.setPostCategory = function(postId, categoryName, cb) { + console.log('Setting post '+postId+' category to '+categoryName); getOrCreateCategory(categoryName, function(category) { db.get('SELECT categoryId FROM categoryPosts \ WHERE postId = '+postId+';', function(err, row) { if (row) { + console.log('Post '+postId+' has assigned category of '+row.categoryId); if (row.categoryId == category.id) { - cb(err); + console.log('Current post category is the same as new post category, no update necessary.'); + cb(null); } else { + console.log("Current post category ("+row.categoryId+") doesn't match new category ("+category.id+"), updating record."); db.run('UPDATE categoryPosts SET \ - categoryId = '+category.id+'\ + categoryId = '+category.id+' \ WHERE postId = '+postId+';', - function(err, row) { - cb(err); + function(err) { + if (err) { + console.log(err); + } + else { + console.log("Category updated."); + cb(null); + } }); } } else { - db.run('INSERT INTO categoryPosts (postId, categoryId) \ - VALUES ('+postId+', '+category.id+');', - function(err, row) { - cb(err); + console.log('Post '+postId+' has no category assigned. Inserting record.'); + db.run('INSERT INTO categoryPosts (postId, categoryId) VALUES ('+postId+', '+category.id+');', + function(err) { + if (err) { + console.log(err); + } + else { + console.log('Post '+postId+' assigned to category '+category.id); + cb(null); + } }); } @@ -178,6 +217,7 @@ exports.createPost = function(title, slug, markdown, postDate, updatedDate, markdown, \ postDate, \ createDate, \ + updatedDate, \ lastBuildDate, \ lastUpload) \ VALUES (\ @@ -186,9 +226,11 @@ exports.createPost = function(title, slug, markdown, postDate, updatedDate, "'+markdown+'", \ "'+postDate+'", \ "'+createDate+'", \ + "'+updatedDate+'", \ (strftime("%s","1900-01-01 00:00")*1000), \ (strftime("%s","1900-01-01 00:00")*1000));', function(err, row) { + if (err) console.log(err); db.get('SELECT * FROM posts WHERE title = "'+title+'" AND createDate = '+createDate+';', function(err, row){ cb(err, row); }) @@ -229,7 +271,17 @@ exports.getPostCategory = function(id, cb) { db.get('SELECT * FROM categories WHERE id = (\ SELECT categoryId FROM categoryPosts WHERE postId = '+id+');', function(err, row) { - cb(row); + if (err) { + console.log(err); + } + if (row) { + console.log('Post '+id+' category is '+row.name); + cb(row); + } + else { + cb(null); + } + }); } @@ -244,7 +296,6 @@ var getOrCreateTag = function(tag, cb) { } if (row) { console.log(slug+' tag exists'); - console.log(row); cb(row); } else { @@ -255,13 +306,8 @@ var getOrCreateTag = function(tag, cb) { console.log(slug+' tag created'); db.get('SELECT * FROM tags WHERE slug = "'+slug+'" LIMIT 1;', function (err, row) { - if (!err) { - console.log(row); - cb(row); - } - else { - console.log(err); - } + if (err) console.log(err); + if (row) cb(row); }); }; }); @@ -276,6 +322,7 @@ exports.getOrCreateTag = getOrCreateTag; // Inputs: Post ID, List of Tag names // Does not return. exports.tagPost = function (postId, tags) { + console.log('Deleting old tags'); db.run('DELETE FROM postTags WHERE postId = '+postId+';', function(err) { @@ -351,3 +398,145 @@ var getPostTagsAsString = function(postId, cb) { } exports.getPostTagsAsString = getPostTagsAsString; + + +// Function to tag a photo with a list of tag names +// Inputs: Photo ID, List of Tag names +// Does not return. +exports.tagPhoto = function (photoId, tags) { + + console.log('Deleting old tags'); + db.run('DELETE FROM photoTags WHERE photoId = '+photoId+';', + function(err) { + console.log('Old tags deleted'); + for (var i = 0, size = tags.length; i < size; i++) { + getOrCreateTag(tags[i], function(row) { + db.run('INSERT INTO photoTags (photoId, tagId) \ + VALUES ('+photoId+', '+row.id+');', + function(err) { + if (err) { + console.log(err); + } + else { + console.log('Photo '+photoId+' tagged as '+row.name); + } + }); + }); + + } + }); +} + + +// Function to get tag ids associated with a particular photo id +// Inputs: Photo ID +// Returns: Records associated with tags of that photo id +var getPhotoTags = function (photoId, cb) { + db.all('SELECT tagId FROM photoTags WHERE photoId = '+photoId+';', + function(err, rows) { + if (err) { + console.log(err); + } + else { + var tagList = []; + for (row in rows) { + tagList.push(rows[row].tagId); + } + tagList = tagList.join(', '); + console.log('Tag ids for photo '+photoId+': '+tagList); + db.all('SELECT * FROM tags WHERE id IN ('+tagList+');', + function(err, rows) { + if (err) { + console.log(err); + } + else { + cb(rows); + } + }) + } + }) +} + +exports.getPhotoTags = getPhotoTags; + + +// Function that returns all the photo tags as a space separated string. +// Inputs: Photo ID, callback function. +// Returns: callback of string with all tags separated by spaces. +var getPhotoTagsAsString = function(photoId, cb) { + getPhotoTags(photoId, function(tags) { + var str = false; + for (tag in tags) { + if (!str) { + str = tags[tag].name; + } + else { + str = str + ' ' + tags[tag].name; + } + } + console.log("Tags for photo "+photoId+": "+str); + cb(str); + }) +} + +exports.getPhotoTagsAsString = getPhotoTagsAsString; + +// Function to get a photo record by the id of the photo +// Returns the photo record +exports.getPhotoById = function(id, cb) { + db.get('SELECT * FROM photos WHERE id = ?', id, function(err, row) { + cb(row); + }); +} + +// Function to create a new photo +// Returns the photo id +exports.createPhoto = function(title, slug, markdown, photoDate, updatedDate, + createDate, path, cb) { + db.run('INSERT INTO photos (\ + title, \ + slug, \ + description, \ + path, \ + photoDate, \ + createDate, \ + updatedDate, \ + lastBuildDate, \ + lastUpload) \ + VALUES (\ + "'+title+'", \ + "'+slug+'", \ + "'+markdown+'", \ + "'+path+'", \ + "'+photoDate+'", \ + "'+createDate+'", \ + "'+updatedDate+'", \ + (strftime("%s","1900-01-01 00:00")*1000), \ + (strftime("%s","1900-01-01 00:00")*1000));', + function(err, row) { + db.get('SELECT * FROM photos WHERE title = "'+title+'" AND createDate = '+createDate+';', function(err, row){ + if (err) console.log(err); + cb(err, row); + }) + }); +} + +// Function to update an existing post record +// Returns the post object +exports.updatePhoto = function(id, title, slug, markdown, photoDate, cb) { + console.log("updatePost called."); + db.run('UPDATE photos SET \ + title = "'+title+'", \ + slug = "'+slug+'", \ + description = "'+markdown+'", \ + photoDate = '+helper.dateToEpoch(photoDate)+', \ + updatedDate = '+helper.dateToEpoch(new Date())+' \ + WHERE id = '+id+';', + function(err) { + console.log('updatePhoto UPDATE result: '+err); + db.get('SELECT * FROM photos WHERE id = '+id+';', function(err, row) { + console.log('updatePhoto SELECT result: ' + err); + cb(row); + }); + }); +} diff --git a/helper.js b/helper.js index ee4bd9f..ed959af 100644 --- a/helper.js +++ b/helper.js @@ -51,11 +51,8 @@ exports.makeSlug = function(str) { // Parse a string of tags // Returns a list of tags exports.parseTags = function(str) { - console.log('tag parse '+str); str = str.replace(/,/g,''); - console.log('tag parse '+str); var list = str.split(" "); - console.log('tag parse '+list); for (var i = 0, size = list.length; i < size; i++) { list[i] = list[i].trim(); } diff --git a/package.json b/package.json index 9d98304..a8a0f1a 100644 --- a/package.json +++ b/package.json @@ -3,20 +3,21 @@ "version": "0.0.0", "private": true, "dependencies": { + "async": "~1.5.0", "body-parser": "~1.13.2", + "connect-ensure-login": "~0.1.1", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", - "express-session": "~1.12.0", "express-flash": "~0.0.2", + "express-session": "~1.12.0", "jade": "~1.11.0", + "markdown": "~0.5.0", "morgan": "~1.6.1", - "serve-favicon": "~2.3.0", + "multer": "~1.1.0", "passport": "~0.3.0", "passport-local": "~1.0.0", - "connect-ensure-login": "~0.1.1", - "sqlite3": "~3.1.0", - "async": "~1.5.0", - "markdown": "~0.5.0" + "serve-favicon": "~2.3.0", + "sqlite3": "~3.1.0" } } diff --git a/schema.sql b/schema.sql index 7c3a4cb..0180d1d 100644 --- a/schema.sql +++ b/schema.sql @@ -53,7 +53,7 @@ CREATE TABLE "photos" ( "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 + "description" TEXT, -- 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 diff --git a/views/admin-photo-edit.jade b/views/admin-photo-edit.jade new file mode 100644 index 0000000..90652a4 --- /dev/null +++ b/views/admin-photo-edit.jade @@ -0,0 +1,33 @@ +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 Photo + + include ./admin-messages.jade + + form(method="post", action="/admin/photo/edit/#{photo.id}") + div(class="row page-header") + h1 put photo here + 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="#{photo.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="#{photo.slug}") + div(class="row page-header") + 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="photoDate", 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="#{photoTags}") + 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 description") + | #{photo.description} + 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 Photo + div(class="pull-right") + button(type="submit", class="btn btn-lg btn-danger", name="submit") Delete Photo diff --git a/views/admin-photo-list.jade b/views/admin-photo-list.jade new file mode 100644 index 0000000..702c20e --- /dev/null +++ b/views/admin-photo-list.jade @@ -0,0 +1,25 @@ +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") Photos + + include ./admin-messages.jade + + table(class="table table-striped") + each photo in photos + tr + td #{photo.id} + td #{photo.title} + td #{photo.dateString} + td + a(href="/admin/photo/edit/#{photo.id}") Edit + | - + a(href="/admin/photo/delete/#{photo.id}") Delete + | - + a(href="/admin/photo/rebuild/#{photo.id}") Rebuild + | - + a(href="/admin/photo/publish/#{photo.id}") Publish diff --git a/views/admin-photo-new.jade b/views/admin-photo-new.jade new file mode 100644 index 0000000..fd79c19 --- /dev/null +++ b/views/admin-photo-new.jade @@ -0,0 +1,31 @@ +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 Photo + + include ./admin-messages.jade + + form(method="post", action="/admin/photo/new", enctype="multipart/form-data") + 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="file", name="photo", accept="image/*", placeholder="Upload File") + 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") + input(type="text", class="form-control", placeholder="Publish Date", name="photoDate") + 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 description") + 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") Create Photo diff --git a/views/admin-post-edit.jade b/views/admin-post-edit.jade index 8bce4c6..6906cd9 100644 --- a/views/admin-post-edit.jade +++ b/views/admin-post-edit.jade @@ -22,7 +22,7 @@ block content 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}") + input(type="text", class="form-control", aria-label="Post category", name="category", id="category" value="#{categoryName}") 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") diff --git a/views/admin-post-list.jade b/views/admin-post-list.jade index 606d872..98f38d2 100644 --- a/views/admin-post-list.jade +++ b/views/admin-post-list.jade @@ -16,12 +16,12 @@ block content td #{post.title} td #{post.dateString} td - a(href="/admin/post/edit/#{post.id}") Edit Post + a(href="/admin/post/edit/#{post.id}") Edit | - - a(href="/admin/post/delete/#{post.id}") Delete Post + a(href="/admin/post/delete/#{post.id}") Delete | - - a(href="/admin/post/rebuild/#{post.id}") Force Rebuild + a(href="/admin/post/rebuild/#{post.id}") Rebuild | - - a(href="/admin/post/publish/#{post.id}") Force Publish + a(href="/admin/post/publish/#{post.id}") Publish diff --git a/views/admin-sidebar.jade b/views/admin-sidebar.jade index ee47512..cce952e 100644 --- a/views/admin-sidebar.jade +++ b/views/admin-sidebar.jade @@ -4,15 +4,15 @@ div(class="col-sm-3 col-md-2 sidebar") ul(class="nav nav-sidebar") li: a(href="/admin/post/new") New Post - li: a(href="/admin/post/list") Edit Post + li: a(href="/admin/post/list") All Posts ul(class="nav nav-sidebar") - li: a(href="/admin/category/new") New Category - li: a(href="/admin/category/list") Edit Category + li: a(href="/admin/photo/new") New Photo + li: a(href="/admin/photo/list") All Photos ul(class="nav nav-sidebar") li: a(href="/admin/gallery/new") New Gallery - li: a(href="/admin/gallery/list") Edit Gallery + li: a(href="/admin/gallery/list") All Galleries ul(class="nav nav-sidebar") form(action="/admin/rebuild/", method="get") diff --git a/views/render-photo.jade b/views/render-photo.jade new file mode 100644 index 0000000..7c21284 --- /dev/null +++ b/views/render-photo.jade @@ -0,0 +1,7 @@ +extends render-layout + +block content + div: img(src="#{medURL}") + + h3: a(href="#{url}") #{title} + div !{content}