db, starting cms pages

This commit is contained in:
James Shiffer 2020-06-04 21:29:16 -07:00
parent 71e7b0f54f
commit d4f976cd43
No known key found for this signature in database
GPG Key ID: C0DB8774A1B3BA45
16 changed files with 968 additions and 104 deletions

1
.env.example Normal file
View File

@ -0,0 +1 @@
SESSION_SECRET=

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
yarn-error.log
/cypress/screenshots/
/__sapper__/
.env

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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;

View File

@ -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}
<div class="content">
<h1>Error {status}</h1>
<p>{error.message}</p>
{#if dev && error.stack}
<pre>{error.stack}</pre>
{/if}
{/if}
</div>

View File

@ -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>

View File

@ -52,11 +52,10 @@
margin: 0 0 0.5em 0;
}
@media (min-width: 640px) {
.content {
position: absolute;
background: #fff;
margin: 8rem;
padding: 2rem;
width: 75vw;
}
}
figure.article-image {

View 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>

View 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>

View File

@ -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">

View File

@ -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);
});

View File

@ -37,6 +37,9 @@ code {
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
View File

@ -0,0 +1 @@
*.db

12
storage/init.sql Normal file
View 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)
);