diff --git a/src/models/article.js b/src/models/article.js index 550baf4..5cc4c10 100644 --- a/src/models/article.js +++ b/src/models/article.js @@ -11,6 +11,7 @@ const ArticleSchema = new Schema({ slug: { type: String, index: { unique: true } }, image: { type: String, required: true }, created_at: { type: Date, default: Date.now }, + updated_at: { type: Date }, html: { type: String, required: true }, comments: [{ content: { type: String, required: true }, diff --git a/src/routes/a/[slug].json.js b/src/routes/a/[slug].json.js index 22b1771..1abc16d 100644 --- a/src/routes/a/[slug].json.js +++ b/src/routes/a/[slug].json.js @@ -12,7 +12,9 @@ export async function get(req, res, next) { }); if (article) { - article.set({ views: article.views + 1 }); + if (req.query.no_view !== '1') { + article.set({ views: article.views + 1 }); + } await article.save(); res.writeHead(200, { 'Content-Type': 'application/json' diff --git a/src/routes/a/[slug].svelte b/src/routes/a/[slug].svelte index 46d51bd..435a501 100644 --- a/src/routes/a/[slug].svelte +++ b/src/routes/a/[slug].svelte @@ -214,6 +214,9 @@

Author: {article.author.realname} {article.author.realname}

Category: {article.category.name}

Published: {new Date(article.created_at).toLocaleString()}

+ {#if article.updated_at} +

Last Updated: {new Date(article.updated_at).toLocaleString()}

+ {/if}

Views: {article.views}

diff --git a/src/routes/cms/create.svelte b/src/routes/cms/create.svelte index fec1d73..6cf6009 100644 --- a/src/routes/cms/create.svelte +++ b/src/routes/cms/create.svelte @@ -6,7 +6,9 @@ } const res = await this.fetch('/c.json'); const categories = await res.json(); - return { user: session.user, categories }; + const origRes = page.query.edit && await this.fetch(`/a/${page.query.edit}.json?no_view=1`) + const editArticle = origRes && await origRes.json(); + return { user: session.user, categories, editArticle }; } @@ -20,6 +22,7 @@ let editor, form, uploadForm; let loading = false, loadingAttach = false; let title = '', category = ''; + export let editArticle = undefined; export let categories; let actions = [ @@ -55,9 +58,9 @@ ]; onMount(function load() { - title = window.localStorage['title'] || ''; - category = window.localStorage['category'] || ''; - editor.setHtml(window.localStorage['html'] || '', false); + title = editArticle ? editArticle.title : (window.localStorage['title'] || ''); + category = editArticle ? editArticle.category.slug : (window.localStorage['category'] || ''); + editor.setHtml(editArticle ? editArticle.html : (window.localStorage['html'] || ''), false); }); async function submit() @@ -67,7 +70,7 @@ fd.append('html', html); loading = true; try { - const res = await fetch(`/cms/article`, { + const res = await fetch(editArticle ? `/cms/article/${editArticle.slug}` : `/cms/article`, { method: 'POST', headers: { 'Accept': 'application/json' diff --git a/src/routes/cms/edit.svelte b/src/routes/cms/edit.svelte new file mode 100644 index 0000000..f888651 --- /dev/null +++ b/src/routes/cms/edit.svelte @@ -0,0 +1,42 @@ + + + + Edit Article | HOWFEED.BIZ + + + + +
+ < Back to Dashboard +

Edit an Article

+

Choose an article to edit:

+ +
diff --git a/src/routes/cms/index.svelte b/src/routes/cms/index.svelte index 8b5a522..7bc34d0 100644 --- a/src/routes/cms/index.svelte +++ b/src/routes/cms/index.svelte @@ -22,7 +22,7 @@ {#if user.author}

HowFeed Publisher Dashboard

Publish a new article

-

Edit an existing article Coming soon!

+

Edit an existing article

Delete an article

Account Settings

Change your avatar

diff --git a/src/server.js b/src/server.js index 804e4e2..91e12b7 100644 --- a/src/server.js +++ b/src/server.js @@ -251,13 +251,27 @@ express() }); }) - .post('/cms/article', + .post('/cms/article/:edit?', isAuthor, async function(req, res, next) { try { + let editArticle; + if (req.params.edit) { + editArticle = await Article.findOne({ slug: req.params.edit }); + if (!editArticle) { + res.writeHead(404, { + 'Content-Type': 'application/json' + }); + res.end(JSON.stringify({ + message: `Article to edit not found` + })); + return false; + } + } + const { html, title, category } = req.body; - const { image } = req.files; - if (!title || !image || !html || !category) { + const image = req.files && req.files.image; + if (!title || (!editArticle && !image) || !html || !category) { res.writeHead(422, { 'Content-Type': 'application/json' }); @@ -266,23 +280,30 @@ express() })); return false; } - if (!/^image\//.test(image.mimetype)) { - res.writeHead(422, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - message: `Invalid MIME type for the header image file.` - })); - return false; - } - if (image.truncated) { - res.writeHead(422, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - message: `Received truncated image file. Try again with a smaller file.` - })); - return false; + let ext, filename, url; + if (image) { + if (!/^image\//.test(image.mimetype)) { + res.writeHead(422, { + 'Content-Type': 'application/json' + }); + res.end(JSON.stringify({ + message: `Invalid MIME type for the header image file.` + })); + return false; + } + if (image.truncated) { + res.writeHead(422, { + 'Content-Type': 'application/json' + }); + res.end(JSON.stringify({ + message: `Received truncated image file. Try again with a smaller file.` + })); + return false; + } + ext = image.name.match(/(\.[^.]+)$/)[0]; + filename = crypto.randomBytes(20).toString('hex') + ext; + url = `/a/${filename}`; + await image.mv('./static' + url); } const cat = await Category.findOne({ slug: category }); if (!cat) { @@ -294,18 +315,30 @@ express() })); return false; } - const ext = image.name.match(/(\.[^.]+)$/)[0]; - const filename = crypto.randomBytes(20).toString('hex') + ext; - const url = `/a/${filename}`; - await image.mv('./static' + url); - const article = await new Article({ html, title, image: filename, category: cat, author: req.user._id }); - await article.save(); - res.writeHead(200, { - 'Content-Type': 'application/json' - }); - res.end(JSON.stringify({ - slug: article.slug - })); + if (editArticle) { + let newObj = { + html, title, category: cat, updated_at: Date.now() + }; + if (filename) { + newObj.image = filename; + } + await Article.updateOne({ slug: editArticle.slug }, { $set: newObj }); + res.writeHead(200, { + 'Content-Type': 'application/json' + }); + res.end(JSON.stringify({ + slug: editArticle.slug + })); + } else { + const article = await new Article({ html, title, image: filename, category: cat, author: req.user._id }); + await article.save(); + res.writeHead(200, { + 'Content-Type': 'application/json' + }); + res.end(JSON.stringify({ + slug: article.slug + })); + } } catch (err) { res.writeHead(500, { 'Content-Type': 'application/json'