db, starting cms pages
This commit is contained in:
		
							parent
							
								
									71e7b0f54f
								
							
						
					
					
						commit
						d4f976cd43
					
				
							
								
								
									
										1
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| SESSION_SECRET= | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,3 +4,4 @@ | ||||
| yarn-error.log | ||||
| /cypress/screenshots/ | ||||
| /__sapper__/ | ||||
| .env | ||||
|  | ||||
| @ -1,12 +1,15 @@ | ||||
| # HowFeed.biz | ||||
| 
 | ||||
| A satirical blog and lightweight CMS that runs on [Sapper](https://sapper.svelte.dev). | ||||
| A satirical blog with its own lightweight CMS, which all runs on [Sapper](https://sapper.svelte.dev). | ||||
| 
 | ||||
| ## Setup | ||||
| 
 | ||||
| Requires Node.js | ||||
| Requires Node.js and SQLite | ||||
| 
 | ||||
| Set up `.env.example` as `.env` | ||||
| 
 | ||||
| ```sh | ||||
| sqlite3 storage/howfeed.db < storage/init.sql | ||||
| npm i | ||||
| npm run dev | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										857
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										857
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										19
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								package.json
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| { | ||||
|   "name": "HowFeed.biz", | ||||
|   "name": "howfeed", | ||||
|   "description": "HowFeed.biz", | ||||
|   "version": "0.1.0", | ||||
|   "scripts": { | ||||
| @ -12,9 +12,18 @@ | ||||
|     "test": "run-p --race dev cy:run" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "bcrypt": "^4.0.1", | ||||
|     "body-parser": "^1.19.0", | ||||
|     "compression": "^1.7.1", | ||||
|     "polka": "next", | ||||
|     "sirv": "^0.4.0" | ||||
|     "connect-flash": "^0.1.1", | ||||
|     "cookie-parser": "^1.4.5", | ||||
|     "dotenv": "^8.2.0", | ||||
|     "express": "^4.17.1", | ||||
|     "express-session": "^1.17.1", | ||||
|     "passport": "^0.4.1", | ||||
|     "passport-local": "^1.0.0", | ||||
|     "sirv": "^0.4.0", | ||||
|     "sqlite3": "^4.2.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "npm-run-all": "^4.1.5", | ||||
| @ -22,5 +31,9 @@ | ||||
|     "svelte": "^3.0.0", | ||||
|     "svelte-loader": "^2.9.0", | ||||
|     "webpack": "^4.7.0" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git@github.com:scoliono/howfeed.git" | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,3 @@ | ||||
| <script> | ||||
| 	export let segment; | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|     nav { | ||||
|         font-weight: bold; | ||||
| @ -11,6 +7,7 @@ | ||||
|         z-index: 100; | ||||
|         background-color: #fff; | ||||
|         top: 0; | ||||
|         box-shadow: 0 -2px 5px #000; | ||||
|     } | ||||
|     div.items { | ||||
|         margin: 0; | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
| 
 | ||||
| 	p { | ||||
| 		margin: 1em auto; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
| 	@media (min-width: 640px) { | ||||
| 		h1 { | ||||
| @ -28,13 +28,13 @@ | ||||
| </style> | ||||
| 
 | ||||
| <svelte:head> | ||||
| 	<title>{status}</title> | ||||
| 	<title>Error {status} | HOWFEED.BIZ</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <h1>{status}</h1> | ||||
| 
 | ||||
| <p>{error.message}</p> | ||||
| 
 | ||||
| {#if dev && error.stack} | ||||
| 	<pre>{error.stack}</pre> | ||||
| {/if} | ||||
| <div class="content"> | ||||
|     <h1>Error {status}</h1> | ||||
|     <p>{error.message}</p> | ||||
|     {#if dev && error.stack} | ||||
|         <pre>{error.stack}</pre> | ||||
|     {/if} | ||||
| </div> | ||||
|  | ||||
| @ -1,13 +1,10 @@ | ||||
| <script> | ||||
|     import Nav from '../components/Nav.svelte'; | ||||
| 
 | ||||
|     export let segment; | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|     main { | ||||
|         max-width: 100vw; | ||||
|         background: #fff; | ||||
|         box-sizing: border-box; | ||||
|     } | ||||
|     footer { | ||||
| @ -17,12 +14,13 @@ | ||||
|         bottom: 0; | ||||
|         width: 100%; | ||||
|         background: #fff; | ||||
|         box-shadow: 0 2px 5px #000; | ||||
|         padding: 1rem; | ||||
|         z-index: 1; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <Nav {segment}/> | ||||
| <Nav /> | ||||
| 
 | ||||
| <main> | ||||
|     <slot></slot> | ||||
|  | ||||
| @ -52,11 +52,10 @@ | ||||
|         margin: 0 0 0.5em 0; | ||||
|     } | ||||
| 
 | ||||
|     .content { | ||||
|         position: absolute; | ||||
|         background: #fff; | ||||
|         margin: 8rem; | ||||
|         padding: 2rem; | ||||
|     @media (min-width: 640px) { | ||||
|         .content { | ||||
|             width: 75vw; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     figure.article-image { | ||||
|  | ||||
							
								
								
									
										33
									
								
								src/routes/cms/login.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/routes/cms/login.svelte
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| <script> | ||||
|     let username, password; | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|     input { | ||||
|         display: block; | ||||
|         padding: 1rem; | ||||
|         font-size: 1.25rem; | ||||
|         width: 70%; | ||||
|         margin-bottom: 2rem; | ||||
|     } | ||||
|     button[type=submit] { | ||||
|         font-size: 1.25rem; | ||||
|         padding: 0.5rem; | ||||
|     } | ||||
|     div.content { | ||||
|         max-width: 40rem; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <svelte:head> | ||||
|     <title>Login | HOWFEED.BIZ</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <div class="content"> | ||||
|     <h1>Login</h1> | ||||
|     <form method="POST" action="/cms/login"> | ||||
|         <input required type="text" name="username" bind:value={username} placeholder="Username"> | ||||
|         <input required type="password" name="password" bind:value={password} placeholder="Password"> | ||||
|         <button type="submit">Submit</button> | ||||
|     </form> | ||||
| </div> | ||||
							
								
								
									
										34
									
								
								src/routes/cms/register.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/routes/cms/register.svelte
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| <script> | ||||
|     let username, password, password_confirm; | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|     input { | ||||
|         display: block; | ||||
|         padding: 1rem; | ||||
|         font-size: 1.25rem; | ||||
|         width: 70%; | ||||
|         margin-bottom: 2rem; | ||||
|     } | ||||
|     button[type=submit] { | ||||
|         font-size: 1.25rem; | ||||
|         padding: 0.5rem; | ||||
|     } | ||||
|     div.content { | ||||
|         max-width: 40rem; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <svelte:head> | ||||
|     <title>Register | HOWFEED.BIZ</title> | ||||
| </svelte:head> | ||||
| 
 | ||||
| <div class="content"> | ||||
|     <h1>Register</h1> | ||||
|     <form method="POST" action="/cms/register"> | ||||
|         <input required type="text" name="username" bind:value={username} placeholder="Username"> | ||||
|         <input required type="password" name="password" bind:value={password} placeholder="Password"> | ||||
|         <input required type="password" name="password_confirm" bind:value={password_confirm} placeholder="Confirm Password"> | ||||
|         <button type="submit">Submit</button> | ||||
|     </form> | ||||
| </div> | ||||
| @ -30,7 +30,7 @@ | ||||
|         margin: 1rem; | ||||
|     } | ||||
|     @media (min-width: 640px) { | ||||
|         div.content { | ||||
|         div.homepage { | ||||
|             padding-top: 5rem !important; | ||||
|         } | ||||
|         h1.welcome { | ||||
| @ -57,8 +57,9 @@ | ||||
|         z-index: 0; | ||||
|         filter: blur(5px); | ||||
|     } | ||||
|     div.content { | ||||
|     div.homepage { | ||||
|         padding-top: 8rem; | ||||
|         padding-bottom: 4rem; | ||||
|         position: absolute; | ||||
|         z-index: 1; | ||||
|         margin: 0 auto; | ||||
| @ -85,7 +86,7 @@ | ||||
| </svelte:head> | ||||
| 
 | ||||
| <div class="background"></div> | ||||
| <div class="content"> | ||||
| <div class="homepage"> | ||||
|     <h1 class="welcome">Welcome</h1> | ||||
|     <h2 class="desc">Find an Article</h2> | ||||
|     <div class="article-list"> | ||||
|  | ||||
| @ -1,17 +1,60 @@ | ||||
| import sirv from 'sirv'; | ||||
| import polka from 'polka'; | ||||
| import express from 'express'; | ||||
| import session from 'express-session'; | ||||
| import compression from 'compression'; | ||||
| import * as sapper from '@sapper/server'; | ||||
| import sqlite3 from 'sqlite3'; | ||||
| import passport from 'passport'; | ||||
| import { Strategy } from 'passport-local'; | ||||
| import bcrypt from 'bcrypt'; | ||||
| 
 | ||||
| const { PORT, NODE_ENV } = process.env; | ||||
| require('dotenv').config(); | ||||
| 
 | ||||
| const { PORT, NODE_ENV, SESSION_SECRET } = process.env; | ||||
| const dev = NODE_ENV === 'development'; | ||||
| 
 | ||||
| polka() // You can also use Express
 | ||||
| const db = new sqlite3.Database('./storage/howfeed.db', (err) => { | ||||
|     if (err) { | ||||
|         console.error(err.message); | ||||
|     } else { | ||||
|         console.log('Connected to the database.'); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| passport.use(new Strategy((username, password, done) => { | ||||
|     const sql = `SELECT password FROM users WHERE username  = ?`; | ||||
|     db.get(sql, [username], async (err, row) => { | ||||
|         if (err) { | ||||
|             return done(err); | ||||
|         } | ||||
|         if (!row) { | ||||
|             return done(null, false, { message: 'Incorrect username.' }); | ||||
|         } | ||||
|         const validPass = await bcrypt.compare(password, row.password); | ||||
|         if (!validPass) { | ||||
|             return done(null, false, { message: 'Incorrect password.' }); | ||||
|         } | ||||
|         return done(null, row); | ||||
|     }); | ||||
| })); | ||||
| 
 | ||||
| express() | ||||
| 	.use( | ||||
|         session({ | ||||
|             secret: SESSION_SECRET, | ||||
|             resave: false, | ||||
|             saveUninitialized: true, | ||||
|             cookie: { secure: true } | ||||
|         }), | ||||
| 		compression({ threshold: 0 }), | ||||
| 		sirv('static', { dev }), | ||||
| 		sapper.middleware() | ||||
| 	) | ||||
|     ) | ||||
|     .post('/cms/login', passport.authenticate('local', { | ||||
|         successRedirect: '/cms', | ||||
|         failureRedirect: '/cms/login', | ||||
|         failureFlash: true, | ||||
|     })) | ||||
| 	.listen(PORT, err => { | ||||
| 		if (err) console.log('error', err); | ||||
| 	}); | ||||
|  | ||||
| @ -36,7 +36,10 @@ code { | ||||
| @media (min-width: 640px) { | ||||
| 	body { | ||||
| 		font-size: 16px; | ||||
| 	} | ||||
|     } | ||||
|     .content { | ||||
|         margin: 8rem auto !important; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| div.article-list { | ||||
| @ -77,3 +80,9 @@ div.article-meta { | ||||
| .article-date { | ||||
|     font-size: 2rem; | ||||
| } | ||||
| 
 | ||||
| .content { | ||||
|     background: #fff; | ||||
|     margin: 8rem 0; | ||||
|     padding: 2rem; | ||||
| } | ||||
|  | ||||
							
								
								
									
										1
									
								
								storage/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								storage/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| *.db | ||||
							
								
								
									
										12
									
								
								storage/init.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								storage/init.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| PRAGMA foreign_keys = ON; | ||||
| CREATE TABLE IF NOT EXISTS users ( | ||||
| 	username TEXT PRIMARY KEY, | ||||
|    	password TEXT NOT NULL | ||||
| ); | ||||
| CREATE TABLE IF NOT EXISTS articles ( | ||||
|     title TEXT PRIMARY KEY, | ||||
|     created_at TEXT NOT NULL, | ||||
|     html BLOB NOT NULL, | ||||
|     author INTEGER NOT NULL, | ||||
|     FOREIGN KEY (author) REFERENCES users (username) | ||||
| ); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user