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 | ||||
| 
 | ||||
| Create a MongoDB database for howfeed | ||||
| Create a MongoDB database for howfeed: | ||||
| 
 | ||||
| ```sh | ||||
| $ mongo | ||||
| > use howfeed; | ||||
| ``` | ||||
| 
 | ||||
| Set up `.env.example` as `.env` | ||||
| 
 | ||||
| Then install dependencies and start a local server: | ||||
| 
 | ||||
| ```sh | ||||
| npm i | ||||
| npm run dev | ||||
| $ npm i | ||||
| $ 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'; | ||||
| 
 | ||||
| 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} | ||||
|             <div class="link"><a href="mailto:the_katze@naver.com">Contact Us</a></div> | ||||
|         {:else} | ||||
|             <div class="link"><a href="/cms">Dashboard</a></div> | ||||
|             <div class="filler"></div> | ||||
|             <div class="link"><a href="/cms/logout">Logout</a></div> | ||||
|         {/if} | ||||
|     </div> | ||||
|  | ||||
| @ -8,7 +8,8 @@ const { Schema } = mongoose; | ||||
| const UserSchema = new Schema({ | ||||
|     username: { type: String, required: true, index: { unique: 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> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <script> | ||||
|     import FakeTweet from '../../components/FakeTweet.svelte'; | ||||
| 
 | ||||
|     export let user; | ||||
| </script> | ||||
| 
 | ||||
| <div class="content"> | ||||
|     <h1>HowFeed Publisher Dashboard</h1> | ||||
|     <p><a href="/cms/create">Publish a new article</a></p> | ||||
|     <p><a href="/cms/update">Edit an existing article</a></p> | ||||
|     <p><a href="/cms/delete">Delete an article</a></p> | ||||
|     {#if user.author} | ||||
|         <h1>HowFeed Publisher Dashboard</h1> | ||||
|         <p><a href="/cms/create">Publish a new 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> | ||||
|  | ||||
| @ -8,6 +8,7 @@ import mongoose from 'mongoose'; | ||||
| import passport from 'passport'; | ||||
| import { Strategy } from 'passport-local'; | ||||
| import sessionFileStore from 'session-file-store'; | ||||
| import Article from './models/article.js'; | ||||
| import User from './models/user.js'; | ||||
| 
 | ||||
| require('dotenv').config(); | ||||
| @ -52,7 +53,6 @@ passport.use(new Strategy((username, password, done) => { | ||||
| })); | ||||
| 
 | ||||
| express() | ||||
|     .use(passport.initialize()) | ||||
|     .use(bodyParser.json()) | ||||
|     .use(bodyParser.urlencoded({ extended: true })) | ||||
|     .use(session({ | ||||
| @ -67,9 +67,11 @@ express() | ||||
|             path: '.sessions' | ||||
|         }) | ||||
|     })) | ||||
|     .use(passport.initialize()) | ||||
|     .use(passport.session()) | ||||
| 
 | ||||
|     .post('/cms/register', | ||||
|         (req, res, next) => { | ||||
|         function(req, res, next) { | ||||
|             if (!req.user) { | ||||
|                 next(); | ||||
|             } else { | ||||
| @ -109,6 +111,15 @@ express() | ||||
|                 })); | ||||
|                 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 { | ||||
|                 const user = await User.findOne({ username: req.body.username }); | ||||
|                 if (user) { | ||||
| @ -167,7 +178,27 @@ express() | ||||
|     }) | ||||
| 
 | ||||
|     .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) { | ||||
|             res.writeHead(200, { | ||||
|                 'Content-Type': 'application/json' | ||||
| @ -175,15 +206,6 @@ express() | ||||
|             res.end(JSON.stringify({ | ||||
|                 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> | ||||
| 	<meta charset='utf-8'> | ||||
| 	<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% | ||||
| 	<link rel='stylesheet' href='global.css'> | ||||
| 	<link rel='icon' type='image/png' href='favicon.png'> | ||||
| @ -11,7 +13,7 @@ | ||||
| 	%sapper.head% | ||||
| </head> | ||||
| <body> | ||||
| 	<div id='sapper'>%sapper.html%</div> | ||||
| 	<div id='hydrate'>%sapper.html%</div> | ||||
| 	%sapper.scripts% | ||||
| </body> | ||||
| </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: { | ||||
| 							dev, | ||||
| 							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) | ||||
| 			}), | ||||
| 		].filter(Boolean), | ||||
| 		devtool: dev && 'inline-source-map' | ||||
| 		devtool: dev && 'inline-source-map', | ||||
| 	}, | ||||
| 
 | ||||
| 	server: { | ||||
| @ -66,7 +66,7 @@ module.exports = { | ||||
| 		mode: process.env.NODE_ENV, | ||||
| 		performance: { | ||||
| 			hints: false // it doesn't matter if server.js is large
 | ||||
| 		} | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	serviceworker: { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user