add dark theme and preferences

This commit is contained in:
teddit 2020-11-21 13:50:12 +01:00
parent 3edde76303
commit 5e52297481
17 changed files with 872 additions and 76 deletions

3
app.js
View File

@ -42,6 +42,7 @@ const pug = require('pug')
const path = require('path')
const compression = require('compression')
const express = require('express')
const cookieParser = require('cookie-parser')
const r = require('redis')
const redis = r.createClient()
const helmet = require('helmet')
@ -86,6 +87,8 @@ if(use_compression) {
app.use(compression())
}
app.use(cookieParser())
if(use_view_cache) {
app.set('view cache', true)
}

257
dist/css/styles.css vendored
View File

@ -2,7 +2,10 @@
--sm-font: 0.666rem;
--lightgray: #f5f5f5;
--whitebg: #ffffff;
--darkbg: #0F0F0F;
--darkbglight: #252525;
--linkcolor: #000bac;
--darklinkcolor: #599bff;
--graytext: #6f6f6f;
}
* {
@ -10,6 +13,200 @@
margin: 0;
font-family: sans-serif;
}
/* Move themes to the beginning of the file to avoid themes flickering. */
/* DARK THEME */
body.dark {
background: var(--darkbg);
color: #cacaca;
}
body.dark nav {
background: #1f1f1f;
}
body.dark .top-links a {
background: var(--darkbg);
color: #bfbfbf;
}
body.dark header {
background: var(--darkbglight);
color: #f1f1f1;
}
body.dark #post header div a {
color: var(--darklinkcolor);
text-decoration: none;
}
body.dark a {
color: #f5f5f5;
}
body.dark a:hover, body.dark a:focus {
color: #3d8aff;
text-decoration: underline;
}
body.dark #post header div a:hover,
body.dark #post header div a:focus {
text-decoration: underline;
}
body.dark input[type="submit"]:hover,
body.dark input[type="submit"]:focus,
body.dark .btn:hover,
body.dark .btn:focus {
background: white;
color: black;
text-decoration: none;
}
body.dark form legend {
border-bottom: 1px solid #353535;
}
body.dark #post .title a {
color: var(--darklinkcolor);
}
body.dark #post .submitted {
color: #a5a5a5;
}
body.dark #post .usertext-body {
background: #0a0a0a;
border: 1px solid #404040;
}
body.dark #post .infobar {
background-color: #d2d2d2;
color: #2f2f2f;
}
body.dark #post .infobar a {
color: #0356d4;
}
body.dark header .tabmenu li a {
background: #3e3e3e;
}
body.dark header .tabmenu li a:hover, body.dark header .tabmenu li a:focus {
text-decoration: underline;
color: white;
}
body.dark #search {
color: #d2d2d2;
}
body.dark .md {
color: #dadada;
}
body.dark .md blockquote, body.dark .md del {
color: #777777;
}
body.dark .md code, body.dark .md pre {
background: black;
color: white;
}
body.dark .comment .body blockquote {
background: #313131;
color: #afafaf;
border-color: #464646;
}
body.dark .comment {
background: var(--darkbg);
}
body.dark .comment .comment {
background: var(--darkbglight);
border-left: 1px solid #545454;
}
body.dark .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
/* Is there any better way to do this??? send help naow */
body.dark .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbg);
}
body.dark .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--darkbglight);
}
body.dark .comment .meta .created a {
color: #7b7b7b;
}
body.dark .comment details summary {
color: #868686;
}
body.dark .comment details summary::-webkit-details-marker,
body.dark .comment details summary::marker {
color: #868686;
}
body.dark #links .link .entry .title a h2 {
color: #f0f0f0;
}
body.dark #links .link .image .no-image,
body.dark #user .entry .image .no-image {
filter: opacity(0.5);
}
body.dark #links .link .upvotes {
color: #858585;
}
body.dark .upvotes .arrow,
body.dark .score .arrow {
filter: opacity(0.5);
}
body.dark #links .link .entry .meta a {
color: #c7c7c7;
}
body.dark .content .bottom img {
filter: invert(1);
}
body.dark .container .content {
border: 1px solid #5e5e5e;
}
body.dark input[type="submit"],
body.dark .btn {
background: black;
color: white;
}
a {
color: var(--linkcolor);
text-decoration: none;
@ -33,7 +230,7 @@ a:hover, a:focus {
background: url(/css/sprite.png?v=1);
background-position: -84px -1654px;
background-repeat: no-repeat;
margin: 4px 0px 0px 0px;
margin: 2px 0px 2px 0px;
width: 100%;
height: 14px;
display: block;
@ -121,6 +318,15 @@ nav .settings a:hover,nav .settings a:focus {
line-height: 1.4;
padding-bottom: 5px;
}
form legend {
border-bottom: 1px solid #e3e3e3;
margin-bottom: 10px;
padding-bottom: 10px;
}
.container .content p.notice {
padding-top: 20px;
padding-bottom: 20px;
}
.container .content p.version {
text-align: right;
color: #4f4f4f;
@ -137,7 +343,7 @@ header {
width: 100%;
padding-top: 15px;
margin-bottom: 21px;
margin-top: 14px;
margin-top: 2px;
background: gainsboro;
}
header a {
@ -196,7 +402,27 @@ header .tabmenu li.active a {
border-radius: 3px;
font-weight: bold;
}
/*SUBREDDIT LINKS*/
input[type="submit"],
.btn {
padding: 3px;
margin-top: 7px;
margin-right: 10px;
border-radius: 0px;
border: 1px solid #a5a5a5;
background: white;
color: #464646;
font-size: 13px;
}
input[type="submit"]:focus,
input[type="submit"]:hover,
.btn:focus,
.btn:hover {
background: #4c4c4c;
color: white;
cursor: pointer;
text-decoration: none;
}
/* SUBREDDIT LINKS */
#links {
float: left;
width: 100%;
@ -327,7 +553,7 @@ header .tabmenu li.active a {
#links.search .link .meta a.comments {
margin-left: 0px;
}
/*COMMENTS*/
/* COMMENTS */
.comment {
font-size: 0.83rem;
}
@ -473,7 +699,7 @@ header .tabmenu li.active a {
.comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment .comment {
background: var(--lightgray);
}
/*POST*/
/* POST */
#post .info {
float: left;
width: 100%;
@ -635,7 +861,7 @@ header .tabmenu li.active a {
#post .gallery .item small {
font-size: 10px;
}
/*USER*/
/* USER */
#user .entries {
float: left;
width: 80%;
@ -804,7 +1030,7 @@ header .tabmenu li.active a {
#user .entries .entry a.context {
margin-right: 10px;
}
/*SEARCH*/
/* SEARCH */
#search {
margin-left: 30px;
margin-bottom: 50px;
@ -841,20 +1067,7 @@ header .tabmenu li.active a {
border-radius: 0px;
margin-bottom: 11px;
}
#search input[type="submit"] {
padding: 3px;
margin-top: 7px;
border-radius: 0px;
border: 1px solid #a5a5a5;
background: white;
color: #464646;
}
#search input[type="submit"]:focus, #search input[type="submit"]:hover {
background: #4c4c4c;
color: white;
cursor: pointer;
}
/*REDDIT STYLES*/
/* REDDIT STYLES */
.md .md-spoiler-text {
border-radius:2px;
transition:background ease-out 1s;
@ -1065,7 +1278,7 @@ code {
font-size:1em;
line-height:1.25em;
}
/*Fix spoiler texts not showing without JS*/
/* Fix spoiler texts not showing without JS */
.md .md-spoiler-text:not(.revealed):active,.md .md-spoiler-text:not(.revealed):focus,.md .md-spoiler-text:not(.revealed):hover {
color: black;
background: #fff0;

95
node_modules/cookie-parser/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,95 @@
1.4.5 / 2020-03-14
==================
* deps: cookie@0.4.0
1.4.4 / 2019-02-12
==================
* perf: normalize `secret` argument only once
1.4.3 / 2016-05-26
==================
* deps: cookie@0.3.1
- perf: use for loop in parse
1.4.2 / 2016-05-20
==================
* deps: cookie@0.2.4
- perf: enable strict mode
- perf: use for loop in parse
- perf: use string concatenation for serialization
1.4.1 / 2016-01-11
==================
* deps: cookie@0.2.3
* perf: enable strict mode
1.4.0 / 2015-09-18
==================
* Accept array of secrets in addition to a single secret
* Fix `JSONCookie` to return `undefined` for non-string arguments
* Fix `signedCookie` to return `undefined` for non-string arguments
* deps: cookie@0.2.2
1.3.5 / 2015-05-19
==================
* deps: cookie@0.1.3
- Slight optimizations
1.3.4 / 2015-02-15
==================
* deps: cookie-signature@1.0.6
1.3.3 / 2014-09-05
==================
* deps: cookie-signature@1.0.5
1.3.2 / 2014-06-26
==================
* deps: cookie-signature@1.0.4
- fix for timing attacks
1.3.1 / 2014-06-17
==================
* actually export `signedCookie`
1.3.0 / 2014-06-17
==================
* add `signedCookie` export for single cookie unsigning
1.2.0 / 2014-06-17
==================
* export parsing functions
* `req.cookies` and `req.signedCookies` are now plain objects
* slightly faster parsing of many cookies
1.1.0 / 2014-05-12
==================
* Support for NodeJS version 0.8
* deps: cookie@0.1.2
- Fix for maxAge == 0
- made compat with expires field
- tweak maxAge NaN error message
1.0.1 / 2014-02-20
==================
* add missing dependencies
1.0.0 / 2014-02-15
==================
* Genesis from `connect`

23
node_modules/cookie-parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,23 @@
(The MIT License)
Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

102
node_modules/cookie-parser/README.md generated vendored Normal file
View File

@ -0,0 +1,102 @@
# cookie-parser
[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
Parse `Cookie` header and populate `req.cookies` with an object keyed by the
cookie names. Optionally you may enable signed cookie support by passing a
`secret` string, which assigns `req.secret` so it may be used by other
middleware.
## Installation
```sh
$ npm install cookie-parser
```
## API
```js
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
```
### cookieParser(secret, options)
- `secret` a string or array used for signing cookies. This is optional and if
not specified, will not parse signed cookies. If a string is provided, this
is used as the secret. If an array is provided, an attempt will be made to
unsign the cookie with each secret in order.
- `options` an object that is passed to `cookie.parse` as the second option. Se
[cookie](https://www.npmjs.org/package/cookie) for more information.
- `decode` a function to decode the value of the cookie
### cookieParser.JSONCookie(str)
Parse a cookie value as a JSON cookie. This will return the parsed JSON value
if it was a JSON cookie, otherwise, it will return the passed value.
### cookieParser.JSONCookies(cookies)
Given an object, this will iterate over the keys and call `JSONCookie` on each
value, replacing the original value with the parsed value. This returns the
same object that was passed in.
### cookieParser.signedCookie(str, secret)
Parse a cookie value as a signed cookie. This will return the parsed unsigned
value if it was a signed cookie and the signature was valid. If the value was
not signed, the original value is returned. If the value was signed but the
signature could not be validated, `false` is returned.
The `secret` argument can be an array or string. If a string is provided, this
is used as the secret. If an array is provided, an attempt will be made to
unsign the cookie with each secret in order.
### cookieParser.signedCookies(cookies, secret)
Given an object, this will iterate over the keys and check if any value is a
signed cookie. If it is a signed cookie and the signature is valid, the key
will be deleted from the object and added to the new object that is returned.
The `secret` argument can be an array or string. If a string is provided, this
is used as the secret. If an array is provided, an attempt will be made to
unsign the cookie with each secret in order.
## Example
```js
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function (req, res) {
// Cookies that have not been signed
console.log('Cookies: ', req.cookies)
// Cookies that have been signed
console.log('Signed Cookies: ', req.signedCookies)
})
app.listen(8080)
// curl command that sends an HTTP request with two cookies
// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello"
```
### [MIT Licensed](LICENSE)
[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/cookie-parser/master
[coveralls-url]: https://coveralls.io/r/expressjs/cookie-parser?branch=master
[npm-downloads-image]: https://badgen.net/npm/dm/cookie-parser
[npm-url]: https://npmjs.org/package/cookie-parser
[npm-version-image]: https://badgen.net/npm/v/cookie-parser
[travis-image]: https://badgen.net/travis/expressjs/cookie-parser/master
[travis-url]: https://travis-ci.org/expressjs/cookie-parser

182
node_modules/cookie-parser/index.js generated vendored Normal file
View File

@ -0,0 +1,182 @@
/*!
* cookie-parser
* Copyright(c) 2014 TJ Holowaychuk
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var cookie = require('cookie')
var signature = require('cookie-signature')
/**
* Module exports.
* @public
*/
module.exports = cookieParser
module.exports.JSONCookie = JSONCookie
module.exports.JSONCookies = JSONCookies
module.exports.signedCookie = signedCookie
module.exports.signedCookies = signedCookies
/**
* Parse Cookie header and populate `req.cookies`
* with an object keyed by the cookie names.
*
* @param {string|array} [secret] A string (or array of strings) representing cookie signing secret(s).
* @param {Object} [options]
* @return {Function}
* @public
*/
function cookieParser (secret, options) {
var secrets = !secret || Array.isArray(secret)
? (secret || [])
: [secret]
return function cookieParser (req, res, next) {
if (req.cookies) {
return next()
}
var cookies = req.headers.cookie
req.secret = secrets[0]
req.cookies = Object.create(null)
req.signedCookies = Object.create(null)
// no cookies
if (!cookies) {
return next()
}
req.cookies = cookie.parse(cookies, options)
// parse signed cookies
if (secrets.length !== 0) {
req.signedCookies = signedCookies(req.cookies, secrets)
req.signedCookies = JSONCookies(req.signedCookies)
}
// parse JSON cookies
req.cookies = JSONCookies(req.cookies)
next()
}
}
/**
* Parse JSON cookie string.
*
* @param {String} str
* @return {Object} Parsed object or undefined if not json cookie
* @public
*/
function JSONCookie (str) {
if (typeof str !== 'string' || str.substr(0, 2) !== 'j:') {
return undefined
}
try {
return JSON.parse(str.slice(2))
} catch (err) {
return undefined
}
}
/**
* Parse JSON cookies.
*
* @param {Object} obj
* @return {Object}
* @public
*/
function JSONCookies (obj) {
var cookies = Object.keys(obj)
var key
var val
for (var i = 0; i < cookies.length; i++) {
key = cookies[i]
val = JSONCookie(obj[key])
if (val) {
obj[key] = val
}
}
return obj
}
/**
* Parse a signed cookie string, return the decoded value.
*
* @param {String} str signed cookie string
* @param {string|array} secret
* @return {String} decoded value
* @public
*/
function signedCookie (str, secret) {
if (typeof str !== 'string') {
return undefined
}
if (str.substr(0, 2) !== 's:') {
return str
}
var secrets = !secret || Array.isArray(secret)
? (secret || [])
: [secret]
for (var i = 0; i < secrets.length; i++) {
var val = signature.unsign(str.slice(2), secrets[i])
if (val !== false) {
return val
}
}
return false
}
/**
* Parse signed cookies, returning an object containing the decoded key/value
* pairs, while removing the signed key from obj.
*
* @param {Object} obj
* @param {string|array} secret
* @return {Object}
* @public
*/
function signedCookies (obj, secret) {
var cookies = Object.keys(obj)
var dec
var key
var ret = Object.create(null)
var val
for (var i = 0; i < cookies.length; i++) {
key = cookies[i]
val = obj[key]
dec = signedCookie(val, secret)
if (val !== dec) {
ret[key] = dec
delete obj[key]
}
}
return ret
}

85
node_modules/cookie-parser/package.json generated vendored Normal file
View File

@ -0,0 +1,85 @@
{
"_from": "cookie-parser",
"_id": "cookie-parser@1.4.5",
"_inBundle": false,
"_integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
"_location": "/cookie-parser",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "cookie-parser",
"name": "cookie-parser",
"escapedName": "cookie-parser",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
"_shasum": "3e572d4b7c0c80f9c61daf604e4336831b5d1d49",
"_spec": "cookie-parser",
"_where": "/home/teddit/site",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"bugs": {
"url": "https://github.com/expressjs/cookie-parser/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
],
"dependencies": {
"cookie": "0.4.0",
"cookie-signature": "1.0.6"
},
"deprecated": false,
"description": "Parse HTTP request cookies",
"devDependencies": {
"eslint": "6.8.0",
"eslint-config-standard": "14.1.0",
"eslint-plugin-import": "2.20.1",
"eslint-plugin-markdown": "1.0.2",
"eslint-plugin-node": "11.0.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "4.0.1",
"istanbul": "0.4.5",
"mocha": "7.1.0",
"supertest": "4.0.2"
},
"engines": {
"node": ">= 0.8.0"
},
"files": [
"LICENSE",
"HISTORY.md",
"index.js"
],
"homepage": "https://github.com/expressjs/cookie-parser#readme",
"keywords": [
"cookie",
"middleware"
],
"license": "MIT",
"name": "cookie-parser",
"repository": {
"type": "git",
"url": "git+https://github.com/expressjs/cookie-parser.git"
},
"scripts": {
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --reporter spec --bail --check-leaks test/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
},
"version": "1.4.5"
}

11
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "teddit",
"version": "0.0.1",
"version": "0.0.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -233,6 +233,15 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-parser": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
"integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
"requires": {
"cookie": "0.4.0",
"cookie-signature": "1.0.6"
}
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",

View File

@ -5,6 +5,7 @@
"main": "app.js",
"dependencies": {
"compression": "^1.7.4",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"fs": "^0.0.1-security",
"helmet": "^4.2.0",

161
routes.js
View File

@ -29,7 +29,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error('Error getting the frontpage key from redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log('Got frontpage key from redis.');
@ -38,7 +38,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
return res.render('index', {
json: processed_json,
sortby: 'hot',
past: past
past: past,
user_preferences: req.cookies
})
})()
} else {
@ -50,7 +51,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.frontpage, JSON.stringify(json), (error) => {
if(error) {
console.error('Error setting the frontpage key to redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
} else {
console.log('Fetched the frontpage from reddit API.');
(async () => {
@ -58,7 +59,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
return res.render('index', {
json: processed_json,
sortby: 'hot',
past: past
past: past,
user_preferences: req.cookies
})
})()
}
@ -67,7 +69,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error('Error fetching the frontpage JSON file.', error)
@ -77,11 +83,16 @@ module.exports = (app, redis, fetch, RedditAPI) => {
})
app.get('/about', (req, res, next) => {
return res.render('about')
return res.render('about', { user_preferences: req.cookies })
})
app.get('/preferences', (req, res, next) => {
return res.render('preferences')
return res.render('preferences', { user_preferences: req.cookies })
})
app.get('/resetprefs', (req, res, next) => {
res.clearCookie('theme')
return res.redirect('/preferences')
})
app.get('/search', (req, res, next) => {
@ -150,7 +161,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error('Error getting the frontpage with sortby key from redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log('Got frontpage with sortyby key from redis.');
@ -159,7 +170,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
return res.render('index', {
json: processed_json,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
} else {
@ -171,7 +183,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.frontpage, JSON.stringify(json), (error) => {
if(error) {
console.error('Error setting the frontpage with sortby key to redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
} else {
console.log('Fetched the frontpage with sortby from reddit API.');
(async () => {
@ -179,7 +191,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
return res.render('index', {
json: processed_json,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
}
@ -188,7 +201,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error('Error fetching the frontpage with sortby JSON file.', error)
@ -229,7 +246,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error('Error getting the search key from redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log('Got search key from redis.');
@ -242,7 +259,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
nsfw: nsfw,
subreddit: subreddit,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
} else {
@ -254,7 +272,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.searches, JSON.stringify(json), (error) => {
if(error) {
console.error('Error setting the searches key to redis.', error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
} else {
console.log('Fetched search results from reddit API.');
(async () => {
@ -266,7 +284,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
nsfw: nsfw,
subreddit: subreddit,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
}
@ -275,7 +294,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error('Error fetching the frontpage JSON file.', error)
@ -323,7 +346,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error(`Error getting the ${subreddit} key from redis.`, error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log(`Got /r/${subreddit} key from redis.`);
@ -335,10 +358,16 @@ module.exports = (app, redis, fetch, RedditAPI) => {
subreddit: subreddit,
subreddit_front: (!before && !after) ? true : false,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
} else {
return res.render('subreddit', { json: null, error: true, data: processed_json })
return res.render('subreddit', {
json: null,
error: true,
data: processed_json,
user_preferences: req.cookies
})
}
})()
} else {
@ -350,7 +379,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.subreddit, JSON.stringify(json), (error) => {
if(error) {
console.error(`Error setting the ${subreddit} key to redis.`, error)
return res.render('subreddit', { json: null })
return res.render('subreddit', { json: null, user_preferences: req.cookies })
} else {
console.log(`Fetched the JSON from reddit.com/r/${subreddit}.`);
(async () => {
@ -360,7 +389,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
subreddit: subreddit,
subreddit_front: (!before && !after) ? true : false,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
}
@ -373,7 +403,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
}
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error(`Error fetching the JSON file from reddit.com/r/${subreddit}.`, error)
@ -402,7 +436,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(comments_url, (error, json) => {
if(error) {
console.error(`Error getting the ${comments_url} key from redis.`, error)
return res.render('index', { post: null })
return res.render('index', { post: null, user_preferences: req.cookies })
}
if(json) {
console.log(`Got ${comments_url} key from redis.`);
@ -415,21 +449,22 @@ module.exports = (app, redis, fetch, RedditAPI) => {
comments: finalized_json.comments,
viewing_comment: viewing_comment,
post_url: post_url,
subreddit: subreddit
subreddit: subreddit,
user_preferences: req.cookies
})
} else {
let key = `morechildren:${post_url};1`
redis.get(key, (error, json) => {
if(error) {
console.error(`Error getting the ${key} key from redis.`, error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log(`Got ${key} key from redis.`);
redis.get(post_url, (error, post_json) => {
if(error) {
console.error(`Error getting the ${post_url} key from redis.`, error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(post_json) {
redis.get(`morechildren_ids:${post_url}`, (error, morechildren_ids) => {
@ -446,7 +481,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
viewing_comment: false,
post_url: post_url,
subreddit: req.params.subreddit,
more_comments_page: 1
more_comments_page: 1,
user_preferences: req.cookies
})
})()
})
@ -465,7 +501,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(comments_url, setexs.posts, JSON.stringify(json), (error) => {
if(error) {
console.error(`Error setting the ${comments_url} key to redis.`, error)
return res.render('post', { post: null })
return res.render('post', { post: null, user_preferences: req.cookies })
} else {
console.log(`Fetched the JSON from reddit.com${comments_url}.`);
(async () => {
@ -476,7 +512,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
comments: finalized_json.comments,
viewing_comment: viewing_comment,
post_url: post_url,
subreddit: subreddit
subreddit: subreddit,
user_preferences: req.cookies
})
})()
}
@ -489,7 +526,12 @@ module.exports = (app, redis, fetch, RedditAPI) => {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
}
return res.render('index', { json: null, http_status_code: result.status, http_statustext: result.statusText })
return res.render('index', {
json: null,
http_status_code: result.status,
http_statustext: result.statusText,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error(`Error fetching the JSON file from reddit.com${comments_url}.`, error)
@ -551,7 +593,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error(`Error getting the user ${key} key from redis.`, error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log(`Got user ${user} key from redis.`);
@ -560,7 +602,8 @@ module.exports = (app, redis, fetch, RedditAPI) => {
return res.render('user', {
data: processed_json,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
} else {
@ -579,14 +622,15 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.user, JSON.stringify(user_data), (error) => {
if(error) {
console.error(`Error setting the user ${key} key to redis.`, error)
return res.render('index', { post: null })
return res.render('index', { post: null, user_preferences: req.cookies })
} else {
(async () => {
let processed_json = await processJsonUser(user_data, true, after, before)
return res.render('user', {
data: processed_json,
sortby: sortby,
past: past
past: past,
user_preferences: req.cookies
})
})()
}
@ -595,11 +639,19 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error(`Error fetching the overview JSON file from reddit.com/u/${user}`, error)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
})
})
} else {
@ -609,7 +661,12 @@ module.exports = (app, redis, fetch, RedditAPI) => {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
}
return res.render('index', { json: null, http_status_code: result.status, http_statustext: result.statusText })
return res.render('index', {
json: null,
http_status_code: result.status,
http_statustext: result.statusText,
user_preferences: req.cookies
})
}
}).catch(error => {
console.error(`Error fetching the about JSON file from reddit.com/u/${user}`, error)
@ -623,13 +680,19 @@ module.exports = (app, redis, fetch, RedditAPI) => {
* POSTS
*/
app.post('/saveprefs', (req, res, next) => {
let theme = req.body.theme
res.cookie('theme', theme, { maxAge: 900000, httpOnly: true })
return res.redirect('/preferences')
})
app.post('/r/:subreddit/comments/:id/:snippet', (req, res, next) => {
/* morechildren route */
let all_ids = req.body.all_ids
let post_url = req.body.url
if(!all_ids || !post_url || !post_url.startsWith('/r/')) {
return res.render('index', null)
return res.render('index', { json: null, user_preferences: req.cookies })
} else {
let post_id = post_url.split('/')[4]
let ids_to_show = ''
@ -645,7 +708,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.get(key, (error, json) => {
if(error) {
console.error(`Error getting the ${key} key from redis.`, error)
return res.render('index', { json: null })
return res.render('index', { json: null, user_preferences: req.cookies })
}
if(json) {
console.log(`Redirecting to ${post_url} with cursor...`);
@ -661,11 +724,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
redis.setex(key, setexs.posts, JSON.stringify(comments), (error) => {
if(error) {
console.error(`Error setting the ${key} key to redis.`, error)
return res.render('post', { post: null })
return res.render('post', { post: null, user_preferences: req.cookies })
} else {
redis.setex(`morechildren_ids:${post_url}`, setexs.posts, JSON.stringify(all_ids))
console.log(`Fetched the JSON from reddit API (endpoint "morechildren") with url: ${url}.`);
console.log(`Redirecting to ${post_url} with cursor...`);
console.log(`Fetched the JSON from reddit API (endpoint "morechildren") with url: ${url}.`)
console.log(`Redirecting to ${post_url} with cursor...`)
return res.redirect(`${post_url}?cursor=${page}&page=${page}`)
}
})
@ -673,11 +736,19 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else {
console.error(`Something went wrong while fetching data from reddit API. ${result.status} ${result.statusText}`)
console.error(reddit_api_error_text)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
}
}).catch(error => {
console.log(`Error fetching the JSON from reddit API (endpoint "morechildren") with url: ${url}.`, error)
return res.render('index', { json: null, http_status_code: result.status })
return res.render('index', {
json: null,
http_status_code: result.status,
user_preferences: req.cookies
})
})
}
})

View File

@ -3,7 +3,7 @@ html
head
title about - teddit
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
.container
.content

View File

@ -3,7 +3,7 @@ html
head
title teddit
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
if json === null
h2 error

View File

@ -3,7 +3,7 @@ html
head
title #{post.title} : #{subreddit}
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
if post === null
h1 Error occured

View File

@ -3,9 +3,21 @@ html
head
title preferences - teddit
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
.container
.content
h1 Preferences
p nothing here yet
form(action="/saveprefs", method="POST")
legend Display
label(for="theme") Theme:
select(id="theme", name="theme")
if(!user_preferences.theme || user_preferences.theme == '')
option(value="", selected="selected") White
option(value="dark") Dark
if(user_preferences.theme === 'dark')
option(value="") White
option(value="dark", selected="selected") Dark
p(class="notice") Preferences are stored client-side using cookies without any personal information.
input(type="submit", value="Save preferences")
a(href="/resetprefs", class="btn") Reset preferences

View File

@ -3,7 +3,7 @@ html
head
title search results for #{q}
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
#search
form(action="/r/" + subreddit + "/search", method="GET")

View File

@ -3,7 +3,7 @@ html
head
title /r/#{subreddit}
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
if json === null
h1 Error occured

View File

@ -3,7 +3,7 @@ html
head
title overview for #{data.username}
include includes/head.pug
body
body(class=""+ user_preferences.theme +"")
include includes/topbar.pug
if user === null
h1 Error occured