authoring restrictions
This commit is contained in:
parent
41718caa46
commit
ffa8b5322a
25
README.md
25
README.md
@ -6,11 +6,30 @@ A satirical blog with its own lightweight CMS, which all runs on [Sapper](https:
|
|||||||
|
|
||||||
Requires Node.js and MongoDB
|
Requires Node.js and MongoDB
|
||||||
|
|
||||||
Create a MongoDB database for howfeed
|
Create a MongoDB database for howfeed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ mongo
|
||||||
|
> use howfeed;
|
||||||
|
```
|
||||||
|
|
||||||
Set up `.env.example` as `.env`
|
Set up `.env.example` as `.env`
|
||||||
|
|
||||||
|
Then install dependencies and start a local server:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i
|
$ npm i
|
||||||
npm run dev
|
$ npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Anyone can sign up for an account, but to designate a certain account as an author so they can publish articles, you will need to set the `author` field to `true` in Mongo:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ mongo
|
||||||
|
> use howfeed;
|
||||||
|
> db.users.updateOne({username: 'myuser1'}, {$set:{author: true}})
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the user should logout and log back in.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as sapper from '@sapper/app';
|
import * as sapper from '@sapper/app';
|
||||||
|
|
||||||
sapper.start({
|
sapper.start({
|
||||||
target: document.querySelector('#sapper')
|
target: document.querySelector('#hydrate')
|
||||||
});
|
});
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -56,6 +56,8 @@
|
|||||||
{#if !$session.user}
|
{#if !$session.user}
|
||||||
<div class="link"><a href="mailto:the_katze@naver.com">Contact Us</a></div>
|
<div class="link"><a href="mailto:the_katze@naver.com">Contact Us</a></div>
|
||||||
{:else}
|
{:else}
|
||||||
|
<div class="link"><a href="/cms">Dashboard</a></div>
|
||||||
|
<div class="filler"></div>
|
||||||
<div class="link"><a href="/cms/logout">Logout</a></div>
|
<div class="link"><a href="/cms/logout">Logout</a></div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,8 @@ const { Schema } = mongoose;
|
|||||||
const UserSchema = new Schema({
|
const UserSchema = new Schema({
|
||||||
username: { type: String, required: true, index: { unique: true } },
|
username: { type: String, required: true, index: { unique: true } },
|
||||||
password: { type: String, required: true },
|
password: { type: String, required: true },
|
||||||
realname: { type: String, required: true }
|
realname: { type: String, required: true },
|
||||||
|
author: { type: Boolean, default: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,9 +12,19 @@
|
|||||||
<title>Dashboard | HOWFEED.BIZ</title>
|
<title>Dashboard | HOWFEED.BIZ</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import FakeTweet from '../../components/FakeTweet.svelte';
|
||||||
|
|
||||||
|
export let user;
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>HowFeed Publisher Dashboard</h1>
|
{#if user.author}
|
||||||
<p><a href="/cms/create">Publish a new article</a></p>
|
<h1>HowFeed Publisher Dashboard</h1>
|
||||||
<p><a href="/cms/update">Edit an existing article</a></p>
|
<p><a href="/cms/create">Publish a new article</a></p>
|
||||||
<p><a href="/cms/delete">Delete an article</a></p>
|
<p><a href="/cms/update">Edit an existing article</a></p>
|
||||||
|
<p><a href="/cms/delete">Delete an article</a></p>
|
||||||
|
{:else}
|
||||||
|
<FakeTweet message="We're watching you" author="Caltrans HQ" verified likes=0 replies=2 date={new Date(2019, 8, 21)} handle="CaltransHQ" avatar="/ct.jpg" />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ import mongoose from 'mongoose';
|
|||||||
import passport from 'passport';
|
import passport from 'passport';
|
||||||
import { Strategy } from 'passport-local';
|
import { Strategy } from 'passport-local';
|
||||||
import sessionFileStore from 'session-file-store';
|
import sessionFileStore from 'session-file-store';
|
||||||
|
import Article from './models/article.js';
|
||||||
import User from './models/user.js';
|
import User from './models/user.js';
|
||||||
|
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
@ -52,7 +53,6 @@ passport.use(new Strategy((username, password, done) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
express()
|
express()
|
||||||
.use(passport.initialize())
|
|
||||||
.use(bodyParser.json())
|
.use(bodyParser.json())
|
||||||
.use(bodyParser.urlencoded({ extended: true }))
|
.use(bodyParser.urlencoded({ extended: true }))
|
||||||
.use(session({
|
.use(session({
|
||||||
@ -67,9 +67,11 @@ express()
|
|||||||
path: '.sessions'
|
path: '.sessions'
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
.use(passport.initialize())
|
||||||
|
.use(passport.session())
|
||||||
|
|
||||||
.post('/cms/register',
|
.post('/cms/register',
|
||||||
(req, res, next) => {
|
function(req, res, next) {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
@ -109,6 +111,15 @@ express()
|
|||||||
}));
|
}));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!/^[a-z0-9.]+$/i.test(username)) {
|
||||||
|
res.writeHead(422, {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: `The username can only contain letters, numbers, and periods.`
|
||||||
|
}));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const user = await User.findOne({ username: req.body.username });
|
const user = await User.findOne({ username: req.body.username });
|
||||||
if (user) {
|
if (user) {
|
||||||
@ -167,7 +178,27 @@ express()
|
|||||||
})
|
})
|
||||||
|
|
||||||
.post('/cms/article',
|
.post('/cms/article',
|
||||||
passport.authenticate('local'),
|
function(req, res, next) {
|
||||||
|
if (req.user) {
|
||||||
|
if (req.user.author) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
res.writeHead(401, {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: `You are not designated as an author.`
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.writeHead(401, {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
message: `You are not logged in`
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
function(req, res, next) {
|
function(req, res, next) {
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@ -175,15 +206,6 @@ express()
|
|||||||
res.end(JSON.stringify({
|
res.end(JSON.stringify({
|
||||||
message: `ur a faget lol`
|
message: `ur a faget lol`
|
||||||
}));
|
}));
|
||||||
},
|
|
||||||
function(err, req, res, next) {
|
|
||||||
// handle error
|
|
||||||
res.writeHead(err.status || 500, {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
});
|
|
||||||
res.end(JSON.stringify({
|
|
||||||
message: err.message
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8'>
|
<meta charset='utf-8'>
|
||||||
<meta name='viewport' content='width=device-width,initial-scale=1.0'>
|
<meta name='viewport' content='width=device-width,initial-scale=1.0'>
|
||||||
<meta name='theme-color' content='#333333'>
|
<meta name='description' content='HOWFEED.BIZ: Where we break the news.'>
|
||||||
|
<meta name='keywords' content='news, satire, blog'>
|
||||||
|
<meta name='theme-color' content='#508FC3'>
|
||||||
%sapper.base%
|
%sapper.base%
|
||||||
<link rel='stylesheet' href='global.css'>
|
<link rel='stylesheet' href='global.css'>
|
||||||
<link rel='icon' type='image/png' href='favicon.png'>
|
<link rel='icon' type='image/png' href='favicon.png'>
|
||||||
@ -11,7 +13,7 @@
|
|||||||
%sapper.head%
|
%sapper.head%
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id='sapper'>%sapper.html%</div>
|
<div id='hydrate'>%sapper.html%</div>
|
||||||
%sapper.scripts%
|
%sapper.scripts%
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
BIN
static/ct.jpg
Normal file
BIN
static/ct.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -24,7 +24,7 @@ module.exports = {
|
|||||||
options: {
|
options: {
|
||||||
dev,
|
dev,
|
||||||
hydratable: true,
|
hydratable: true,
|
||||||
hotReload: false // pending https://github.com/sveltejs/svelte/issues/2377
|
hotReload: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ module.exports = {
|
|||||||
'process.env.NODE_ENV': JSON.stringify(mode)
|
'process.env.NODE_ENV': JSON.stringify(mode)
|
||||||
}),
|
}),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
devtool: dev && 'inline-source-map'
|
devtool: dev && 'inline-source-map',
|
||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
@ -66,7 +66,7 @@ module.exports = {
|
|||||||
mode: process.env.NODE_ENV,
|
mode: process.env.NODE_ENV,
|
||||||
performance: {
|
performance: {
|
||||||
hints: false // it doesn't matter if server.js is large
|
hints: false // it doesn't matter if server.js is large
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
serviceworker: {
|
serviceworker: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user