diff --git a/app.js b/app.js index b8663819c9..96bf00053d 100644 --- a/app.js +++ b/app.js @@ -6,9 +6,9 @@ // Module dependencies. var express = require('express'), - fs = require('fs'), admin = require('./core/admin/controllers'), frontend = require('./core/frontend/controllers'), + api = require('./core/shared/api'), flash = require('connect-flash'), Ghost = require('./core/ghost'), I18n = require('./core/lang/i18n'), @@ -46,11 +46,13 @@ /** * API routes.. - * @todo convert these into a RESTful, public, authenticated API! + * @todo auth should be public auth not user auth */ - ghost.app().post('/api/v0.1/posts/create', auth, admin.posts.create); - ghost.app().post('/api/v0.1/posts/edit', auth, admin.posts.edit); - ghost.app().get('/api/v0.1/posts', auth, admin.posts.index); + ghost.app().get('/api/v0.1/posts', auth, api.requestHandler(api.posts.browse)); + ghost.app().get('/api/v0.1/posts/:id', auth, api.requestHandler(api.posts.read)); + ghost.app().post('/api/v0.1/posts/create', auth, api.requestHandler(api.posts.add)); + ghost.app().put('/api/v0.1/posts/edit', auth, api.requestHandler(api.posts.edit)); + ghost.app()['delete']('/api/v0.1/posts/:id', auth, api.requestHandler(api.posts.destroy)); /** * Admin routes.. @@ -75,6 +77,5 @@ ghost.app().listen(3333, function () { console.log("Express server listening on port " + 3333); - console.log('process: ', process.env); }); }()); \ No newline at end of file diff --git a/core/admin/assets/js/editor.js b/core/admin/assets/js/editor.js index 1a56d386e4..31b1ab13e0 100644 --- a/core/admin/assets/js/editor.js +++ b/core/admin/assets/js/editor.js @@ -56,7 +56,7 @@ function save() { var entry = { title: document.getElementById('entry-title').value, - markdown: editor.getValue() + content: editor.getValue() }, urlSegments = window.location.pathname.split('/'); @@ -64,7 +64,7 @@ entry.id = urlSegments[3]; $.ajax({ url: '/api/v0.1/posts/edit', - method: 'POST', + method: 'PUT', data: entry, success: function (data) { console.log('response', data); diff --git a/core/admin/controllers/index.js b/core/admin/controllers/index.js index c5ad0705c7..8db690013d 100644 --- a/core/admin/controllers/index.js +++ b/core/admin/controllers/index.js @@ -1,11 +1,12 @@ +/*global require, module */ (function () { "use strict"; var Ghost = require('../../ghost'), _ = require('underscore'), fs = require('fs'), - Showdown = require('showdown'), - converter = new Showdown.converter(), + when = require('when/node/function'), + api = require('../../shared/api'), ghost = new Ghost(), adminNavbar, @@ -60,14 +61,15 @@ }, 'editor': function (req, res) { if (req.params.id !== undefined) { - ghost.dataProvider().posts.findOne({'id': parseInt(req.params.id, 10)}, function (error, post) { - res.render('editor', { - bodyClass: 'editor', - adminNav: setSelected(adminNavbar, 'blog'), - title: post.title, - content: post.content + api.posts.read(parseInt(req.params.id, 10)) + .then(function (post) { + res.render('editor', { + bodyClass: 'editor', + adminNav: setSelected(adminNavbar, 'blog'), + title: post.title, + content: post.content + }); }); - }); } else { res.render('editor', { bodyClass: 'editor', @@ -76,13 +78,14 @@ } }, 'blog': function (req, res) { - ghost.dataProvider().posts.findAll(function (error, posts) { - res.render('blog', { - bodyClass: 'manage', - adminNav: setSelected(adminNavbar, 'blog'), - posts: posts + api.posts.browse() + .then(function (posts) { + res.render('blog', { + bodyClass: 'manage', + adminNav: setSelected(adminNavbar, 'blog'), + posts: posts + }); }); - }); }, 'settings': function (req, res) { res.render('settings', { @@ -119,47 +122,6 @@ res.redirect('/ghost/debug'); }); } - }, - 'posts': { - 'index': function (req, res) { - - }, - 'create': function (req, res) { - var entry = { - title: req.body.title, - content: req.body.markdown, - contentHtml: '', - language: ghost.config().defaultLang, - status: ghost.statuses().draft, - featured: false - }; - - entry.contentHtml = converter.makeHtml(entry.content); - - ghost.dataProvider().posts.add(entry, function (error, post) { - if (!error) { - console.log('added', post); - res.json({id: post.id}); - } else { - res.json(400, {error: post.errors}); - } - }); - }, - 'edit': function (req, res) { - var entry = { - id: parseInt(req.body.id, 10), - title: req.body.title, - content: req.body.markdown, - contentHtml: '' - }; - - entry.contentHtml = converter.makeHtml(entry.content); - - ghost.dataProvider().posts.edit(entry, function (error, post) { - console.log('edited', post); - res.json({id: parseInt(post.id, 10)}); - }); - } } }; diff --git a/core/shared/api.js b/core/shared/api.js new file mode 100644 index 0000000000..5cc766cad5 --- /dev/null +++ b/core/shared/api.js @@ -0,0 +1,77 @@ +// # Ghost Data API +// Provides access to the data model + +/** + * This is intended to replace the old dataProvider files and should access & manipulate the models directly + */ + +/*global module, require */ +(function () { + "use strict"; + + var Ghost = require('../ghost'), + when = require('when/node/function'), + _ = require('underscore'), + + ghost = new Ghost(), + posts, + users, + requestHandler; + + // # Posts + posts = { + // takes filter / pagination parameters + // returns a list of posts in a json response + browse: function (options) { + return when.call(ghost.dataProvider().posts.findAll); + }, + // takes an identifier (id or slug?) + // returns a single post in a json response + read: function (id) { + return when.call(ghost.dataProvider().posts.findOne, {id: id}); + }, + // takes a json object with all the properties which should be updated + // returns the resulting post in a json response + edit: function (postData) { + console.log('edit data', postData); + return when.call(ghost.dataProvider().posts.edit, postData); + }, + // takes a json object representing a post, + // returns the resulting post in a json response + add: function (postData) { + console.log('data', postData); + return when.call(ghost.dataProvider().posts.add, postData); + }, + // takes an identifier (id or slug?) + // returns a json response with the id of the deleted post + destroy: function (id) { + return when.call(ghost.dataProvider().posts.destroy, id); + } + }; + + // # Users + users = {}; +// settings: {}, +// categories: {}, +// post_categories: {} + + + // requestHandler + // decorator for api functions which are called via an HTTP request + // takes the API method and wraps it so that it gets data from the request and returns a sensible JSON response + requestHandler = function (apiMethod) { + return function (req, res) { + var options = _.extend(req.body, req.params); + return apiMethod(options).then(function (result) { + res.json(result); + }, function (error) { + res.json(400, {error: error}); + }); + }; + }; + + + module.exports.posts = posts; + module.exports.users = users; + module.exports.requestHandler = requestHandler; +}()); \ No newline at end of file diff --git a/core/shared/models/dataProvider.juggling.js b/core/shared/models/dataProvider.juggling.js index e5a147c5da..320eb821bc 100644 --- a/core/shared/models/dataProvider.juggling.js +++ b/core/shared/models/dataProvider.juggling.js @@ -101,6 +101,7 @@ /** * Naive find one where args match + * @param args * @param callback */ DataProvider.prototype.posts.findOne = function (args, callback) { @@ -109,7 +110,7 @@ /** * Naive add - * @param post + * @param _post * @param callback */ DataProvider.prototype.posts.add = function (_post, callback) { @@ -122,7 +123,7 @@ /** * Naive edit - * @param post + * @param _post * @param callback */ DataProvider.prototype.posts.edit = function (_post, callback) { @@ -133,6 +134,13 @@ }); }; + + DataProvider.prototype.posts.destroy = function (_identifier, callback) { + schema.models.Post.findOne({where: {id: _identifier}}, function (error, post) { + schema.models.Post.destroy(post.id, callback); + }); + }; + DataProvider.prototype.populateData = populateData; module.exports = DataProvider; diff --git a/core/shared/models/schema.js b/core/shared/models/schema.js index 4fe9b49b46..a8867f7d85 100644 --- a/core/shared/models/schema.js +++ b/core/shared/models/schema.js @@ -4,7 +4,7 @@ * Vastly incomplete! */ -/*globals module, require */ +/*global module, require */ (function () { "use strict"; @@ -12,6 +12,8 @@ schema = new Schema('sqlite3', { database: __dirname + '/../data/datastore.db' }), + Showdown = require('showdown'), + converter = new Showdown.converter(), Post, User, Setting; @@ -39,16 +41,15 @@ }; Post.prototype.preCreate = function (next) { - console.log('pre create 1', this); + //console.log('pre create 1', this); - if (this.createdAt === undefined) { - this.createdAt = new Date(); - } - if (this.slug === undefined) { - this.slug = this.generateSlug(); - } + this.createdAt = this.createdAt || new Date(); + this.slug = this.slug || this.generateSlug(); +// this.language = this.language || ghost.config().defaultLang; +// this.status = this.status || ghost.statuses().draft + this.featured = false; - console.log('pre create 2', this); + // console.log('pre create 2', this); next(); }; @@ -59,11 +60,12 @@ //Post.validatesUniquenessOf('slug'); //Post.validatesLengthOf('language', {min: 2, max: 5}, "The language code should be between 2 and 5 chars long, E.g. 'en' or 'en_GB' "); - - Post.beforeSave = function (next, data) { + // doesn't get run on update + Post.beforeSave = Post.beforeUpdate = function (next, data) { console.log('before s1', data); // set updated data.updatedAt = new Date(); + data.contentHtml = converter.makeHtml(data.content); next(); }; diff --git a/package.json b/package.json index dfbc2bdea3..04a16aa511 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,9 @@ "moment": "*", "underscore": "*", "showdown": "*", + "when": "*", "sqlite3": "2.1.7", - "jugglingdb": "0.2.x", + "jugglingdb": "0.2.0-29", "jugglingdb-sqlite3": "git+https://github.com/jugglingdb/sqlite3-adapter.git#master" }, "devDependencies": {