Huge commit
- Update all deps - Apply midwest changes - Convert all templates to JSX - Preact instead of Marko - Babel & Eslint
This commit is contained in:
parent
ddc1d5bf5a
commit
47ce0a2a33
24
.babelrc
24
.babelrc
@ -1,15 +1,31 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"server": {
|
"node": {
|
||||||
"presets": [ "es2015-node6" ],
|
"presets": [ "es2015-node6" ],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"add-module-exports"
|
"add-module-exports"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"client": {
|
"node-jsx": {
|
||||||
"presets": [ "es2015", "react" ],
|
"presets": [ "es2015-node6" ],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"add-module-exports"
|
"add-module-exports",
|
||||||
|
["transform-react-jsx", { "pragma": "h" }],
|
||||||
|
["jsx-node/babel/alias", {
|
||||||
|
"lowline": "lodash",
|
||||||
|
"preact": "jsx-node"
|
||||||
|
}],
|
||||||
|
["jsx-node/babel/stringify"]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rollup": {
|
||||||
|
"include": [
|
||||||
|
"node_modules/preact/**",
|
||||||
|
"client/**"
|
||||||
|
],
|
||||||
|
"presets": [ "es2015-rollup" ],
|
||||||
|
"plugins": [
|
||||||
|
["transform-react-jsx", { "pragma":"h" }]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
.eslintrc
54
.eslintrc
@ -1,52 +1,14 @@
|
|||||||
{
|
{
|
||||||
"extends": "airbnb-base",
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"sourceType": "strict"
|
|
||||||
},
|
|
||||||
|
|
||||||
"env": {
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"semi": [ 2, "never" ],
|
"arrow-parens": [2, "always"],
|
||||||
"import/no-extraneous-dependencies": ["error", {"devDependencies": true, "optionalDependencies": false, "peerDependencies": false}],
|
"class-methods-use-this": 0,
|
||||||
"new-cap": 0,
|
|
||||||
"no-mixed-operators": 0,
|
|
||||||
"no-cond-assign": 0,
|
|
||||||
"guard-for-in": 0,
|
|
||||||
"global-require": 0,
|
|
||||||
"no-underscore-dangle": 0,
|
|
||||||
"object-shorthand": 0,
|
|
||||||
"default-case": 0,
|
|
||||||
"one-var": 0,
|
|
||||||
"prefer-rest-params": 0,
|
|
||||||
"no-unused-vars": [ 2, { "args": "none" } ],
|
|
||||||
"no-alert": 0,
|
|
||||||
"quote-props": 0,
|
|
||||||
"no-nested-ternary": 0,
|
|
||||||
"no-use-before-define": [2, { "functions": false, "classes": true }],
|
|
||||||
"consistent-return": 0,
|
|
||||||
"no-eval": 0,
|
|
||||||
"prefer-arrow-callback": 0,
|
|
||||||
"array-bracket-spacing": 0,
|
|
||||||
"no-console": 0,
|
|
||||||
"indent": [ 2, 2, { "SwitchCase": 1 }],
|
|
||||||
"max-len": 0,
|
|
||||||
"comma-dangle": 0,
|
|
||||||
"no-param-reassign": 0,
|
|
||||||
"prefer-template": 0,
|
|
||||||
"curly": 0,
|
|
||||||
"func-names": 0,
|
"func-names": 0,
|
||||||
|
"import/no-unresolved": [2, { "ignore": ["^[^./]"] }],
|
||||||
|
"no-console": [1, { "allow": ["warn", "error", "info"] }],
|
||||||
|
"no-empty": [2, { "allowEmptyCatch": true }],
|
||||||
|
"no-mixed-operators": 0,
|
||||||
|
"no-param-reassign": 0,
|
||||||
"no-shadow": 0,
|
"no-shadow": 0,
|
||||||
"spaced-comment": 0,
|
"no-underscore-dangle": 0
|
||||||
"strict": [ 2, "global" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"globals": {
|
|
||||||
"PWD": true,
|
|
||||||
"ENV": true,
|
|
||||||
"location": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -31,7 +31,9 @@ npm-debug.log
|
|||||||
# Bower dependency directory
|
# Bower dependency directory
|
||||||
bower_components
|
bower_components
|
||||||
|
|
||||||
*.marko.js
|
.tern-port
|
||||||
|
|
||||||
|
/build
|
||||||
|
|
||||||
/dump
|
/dump
|
||||||
|
|
||||||
|
|||||||
@ -1,49 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "airbnb",
|
"extends": [
|
||||||
|
"airbnb",
|
||||||
|
"../.eslintrc"
|
||||||
|
],
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"semi": [ 2, "never" ],
|
"react/react-in-jsx-scope": 0,
|
||||||
"no-confusing-arrow": 0,
|
|
||||||
"react/prop-types": 0,
|
"react/prop-types": 0,
|
||||||
"guard-for-in": 0,
|
"react/no-unknown-property": 0,
|
||||||
"global-require": 0,
|
"jsx-a11y/label-has-for": 0
|
||||||
"no-underscore-dangle": 0,
|
|
||||||
"object-shorthand": 0,
|
|
||||||
"default-case": 0,
|
|
||||||
"one-var": 0,
|
|
||||||
"prefer-rest-params": 0,
|
|
||||||
"no-unused-vars": [ 2, { "args": "none" } ],
|
|
||||||
"no-alert": 0,
|
|
||||||
"quote-props": 0,
|
|
||||||
"no-nested-ternary": 0,
|
|
||||||
"no-use-before-define": [2, { "functions": false, "classes": true }],
|
|
||||||
"consistent-return": 0,
|
|
||||||
"no-eval": 0,
|
|
||||||
"prefer-arrow-callback": 0,
|
|
||||||
"array-bracket-spacing": 0,
|
|
||||||
"no-console": 0,
|
|
||||||
"indent": [ 2, 2, { "SwitchCase": 1 }],
|
|
||||||
"max-len": 0,
|
|
||||||
"comma-dangle": 0,
|
|
||||||
"no-param-reassign": 0,
|
|
||||||
"prefer-template": 0,
|
|
||||||
"curly": 0,
|
|
||||||
"func-names": 0,
|
|
||||||
"no-shadow": 0,
|
|
||||||
"spaced-comment": 0,
|
|
||||||
"strict": [ 2, "global" ]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"ENV": true,
|
"ga": true,
|
||||||
"google": true,
|
"$": true,
|
||||||
"INITIAL_STATE": true,
|
"_": true,
|
||||||
"INITIAL_CONTEXT": true,
|
"Backbone": true,
|
||||||
"PWD": true,
|
"INITIAL_CONTEXT": true
|
||||||
"$": true
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
import { $ } from 'dollr'
|
|
||||||
|
|
||||||
import './process'
|
|
||||||
|
|
||||||
import Timer from './components/Timer'
|
|
||||||
|
|
||||||
$(() => {
|
|
||||||
// request permission on page load
|
|
||||||
if (!Notification) {
|
|
||||||
alert('Desktop notifications not available in your browser. Try Chromium, Chrome or Firefox.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Notification.permission !== 'granted')
|
|
||||||
Notification.requestPermission()
|
|
||||||
|
|
||||||
const timer = $('.timer')
|
|
||||||
|
|
||||||
Timer.render().replace(timer).getWidget()
|
|
||||||
})
|
|
||||||
15
client/app.jsx
Normal file
15
client/app.jsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { h, render } from 'preact';
|
||||||
|
import Layout from './components/Layout.jsx';
|
||||||
|
|
||||||
|
// request permission on page load
|
||||||
|
if (!Notification) {
|
||||||
|
alert('Desktop notifications not available in your browser. Try Chromium, Chrome or Firefox.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Notification.permission !== 'granted') {
|
||||||
|
Notification.requestPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
render((
|
||||||
|
<Layout />
|
||||||
|
), null, document.getElementById('app'));
|
||||||
12
client/components/Layout.jsx
Normal file
12
client/components/Layout.jsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { h } from 'preact';
|
||||||
|
|
||||||
|
import Timer from './Timer.jsx';
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<div id="app">
|
||||||
|
<main>
|
||||||
|
<h1>Pomodoro Time!</h1>
|
||||||
|
<Timer />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
109
client/components/Timer.jsx
Normal file
109
client/components/Timer.jsx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
|
||||||
|
import { bindAll } from 'lowline';
|
||||||
|
|
||||||
|
import timeFilter from '../util/time-filter';
|
||||||
|
|
||||||
|
const length = 25 * 60 * 1000;
|
||||||
|
|
||||||
|
export default class Timer extends Component {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
time: length,
|
||||||
|
totalTime: length,
|
||||||
|
startTime: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
bindAll(this, ['start', 'pause', 'reset', 'updateTimer', 'end']);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.setState({
|
||||||
|
startTime: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.interval = setInterval(this.updateTimer.bind(this), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
pause() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
time: length,
|
||||||
|
totalTime: length,
|
||||||
|
startTime: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTimer() {
|
||||||
|
let time = this.state.totalTime - (Date.now() - this.state.startTime);
|
||||||
|
|
||||||
|
if (time <= 0) {
|
||||||
|
this.pause();
|
||||||
|
|
||||||
|
this.end();
|
||||||
|
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = timeFilter(time).slice(0, 5);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
end() {
|
||||||
|
const data = {
|
||||||
|
startTime: this.state.startTime,
|
||||||
|
endTime: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
document.title = 'Pling!';
|
||||||
|
|
||||||
|
if (Notification.permission !== 'granted') {
|
||||||
|
Notification.requestPermission();
|
||||||
|
} else {
|
||||||
|
const notification = new Notification('Pomodoro complete!', {
|
||||||
|
icon: 'https://www.planetnatural.com/wp-content/uploads/2014/03/tomato-supplies.jpg',
|
||||||
|
body: 'Time for a break!',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/api/pomodoros', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
console.log('succes');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render(props, state) {
|
||||||
|
return (
|
||||||
|
<div class="timer">
|
||||||
|
<div class="time">{timeFilter(state.time || 0)}</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<button onClick={this.start}>Start</button>
|
||||||
|
<button>Pause</button>
|
||||||
|
<button>Reset</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,93 +0,0 @@
|
|||||||
import markoWidgets from 'marko-widgets'
|
|
||||||
import template from './template.marko'
|
|
||||||
|
|
||||||
import timeFilter from '../../util/time-filter'
|
|
||||||
|
|
||||||
const length = 25 * 60 * 1000
|
|
||||||
|
|
||||||
export default markoWidgets.defineComponent({
|
|
||||||
template,
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.reset()
|
|
||||||
},
|
|
||||||
|
|
||||||
start(e) {
|
|
||||||
this.setState({
|
|
||||||
startTime: Date.now()
|
|
||||||
})
|
|
||||||
|
|
||||||
this.interval = setInterval(this.updateTimer.bind(this), 10)
|
|
||||||
},
|
|
||||||
|
|
||||||
pause(e) {
|
|
||||||
clearInterval(this.interval)
|
|
||||||
},
|
|
||||||
|
|
||||||
reset(e) {
|
|
||||||
clearInterval(this.interval)
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
time: length,
|
|
||||||
totalTime: length,
|
|
||||||
startTime: undefined
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
updateTimer() {
|
|
||||||
let time = this.state.totalTime - (Date.now() - this.state.startTime)
|
|
||||||
|
|
||||||
if (time <= 0) {
|
|
||||||
this.pause()
|
|
||||||
|
|
||||||
this.end()
|
|
||||||
|
|
||||||
time = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
document.title = timeFilter(time).slice(0, 5)
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
time
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
end(time) {
|
|
||||||
const data = {
|
|
||||||
startTime: this.state.startTime,
|
|
||||||
endTime: new Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
document.title = 'Pling!'
|
|
||||||
|
|
||||||
if (Notification.permission !== 'granted')
|
|
||||||
Notification.requestPermission()
|
|
||||||
else {
|
|
||||||
const notification = new Notification('Pomodoro complete!', {
|
|
||||||
icon: 'https://www.planetnatural.com/wp-content/uploads/2014/03/tomato-supplies.jpg',
|
|
||||||
body: 'Time for a break!',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch('/api/pomodoros', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((json) => {
|
|
||||||
console.log('succes')
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState(input) {
|
|
||||||
return {
|
|
||||||
time: length,
|
|
||||||
totalTime: length,
|
|
||||||
startTime: undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
<script marko-init>
|
|
||||||
const time = require('../../util/time-filter');
|
|
||||||
</script>
|
|
||||||
<div class="timer" w-bind>
|
|
||||||
<div class="time">${time(data.time || 0)}</div>
|
|
||||||
<div class="buttons">
|
|
||||||
<button w-onClick="start">Start</button>
|
|
||||||
<button>Pause</button>
|
|
||||||
<button>Reset</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
5
client/error.jsx
Normal file
5
client/error.jsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default function () {
|
||||||
|
<section>
|
||||||
|
<h1>Error!</h1>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
@ -1,3 +0,0 @@
|
|||||||
<section>
|
|
||||||
<h1>Error!</h1>
|
|
||||||
</section>
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"tags-dir": [ "./components" ]
|
|
||||||
}
|
|
||||||
25
client/master.jsx
Normal file
25
client/master.jsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import Layout from './components/Layout.jsx';
|
||||||
|
|
||||||
|
export default ({ css, js }) => (
|
||||||
|
'<!doctype html>' + (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Pomodoro</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<meta name="robots" content="index, follow" />
|
||||||
|
<meta name="description" content="Beta Pomodoro timer that stores your pomodors." />
|
||||||
|
<meta name="keywords" content="pomodoro,gtd,productivity" />
|
||||||
|
<meta name="author" content="Linus Miller" />
|
||||||
|
|
||||||
|
<link type="text/css" rel="stylesheet" href={`/css/public${css ? css.suffix : ''}.css`} />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Layout />
|
||||||
|
|
||||||
|
<script src={`/js/app${js ? js.suffix : ''}.js`} />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
);
|
||||||
@ -1,31 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html xml:lang="sv" lang="sv">
|
|
||||||
<head>
|
|
||||||
<title>Pomodoro</title>
|
|
||||||
|
|
||||||
<!-- Meta Tags -->
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
||||||
<meta name="robots" content="index, follow" />
|
|
||||||
<meta name="description" content="Beta Pomodoro timer that stores your pomodors." />
|
|
||||||
<meta name="keywords" content="pomodoro,gtd,productivity" />
|
|
||||||
<meta name="author" content="Linus Miller" />
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="/css/main${data.css && data.css.suffix}.css">
|
|
||||||
|
|
||||||
<!--[if IE]>
|
|
||||||
<link rel="stylesheet" type="text/css" href="css/default-IE.css" />
|
|
||||||
<![endif]-->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<h1>Pomodoro Time!</h1>
|
|
||||||
<Timer />
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script src="/js/app${data.js && data.js.suffix}.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
window.process = {
|
|
||||||
browser: true,
|
|
||||||
env: {},
|
|
||||||
nextTick: (fnc) => {
|
|
||||||
setTimeout(fnc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
export default {
|
|
||||||
'': {
|
|
||||||
name: '',
|
|
||||||
//view: PageView,
|
|
||||||
template: require('./pages/index.marko'),
|
|
||||||
//subviews: {
|
|
||||||
// newsletterForm: [ '.newsletter', require('./views/newsletter-form') ]
|
|
||||||
//}
|
|
||||||
widget: require('./pages/index')
|
|
||||||
},
|
|
||||||
|
|
||||||
'samarbetspartners': {
|
|
||||||
//view: 'Page'
|
|
||||||
},
|
|
||||||
|
|
||||||
'om-oss': {
|
|
||||||
name: 'om-oss',
|
|
||||||
template: require('./pages/om-oss.marko'),
|
|
||||||
//view: PageView,
|
|
||||||
widget: require('./pages/om-oss')
|
|
||||||
},
|
|
||||||
|
|
||||||
'nyhetsbrev': {
|
|
||||||
name: 'nyhetsbrev',
|
|
||||||
template: require('./pages/nyhetsbrev.marko'),
|
|
||||||
//view: PageView,
|
|
||||||
widget: require('./pages/nyhetsbrev'),
|
|
||||||
//subviews: {
|
|
||||||
// newsletterForm: [ '.newsletter-form', require('./components/newsletter-form/view') ]
|
|
||||||
//},
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
'kontakt': {
|
|
||||||
name: 'kontakt',
|
|
||||||
//view: PageView,
|
|
||||||
template: require('./pages/kontakt.marko'),
|
|
||||||
widget: require('./pages/kontakt'),
|
|
||||||
//subviews: {
|
|
||||||
// googleMap: [ '#map-canvas', require('./views/google-map') ],
|
|
||||||
// contactForm: [ '.contact-form', require('./components/contact-form/view') ],
|
|
||||||
// newsletterForm: [ '.nyhetsbrev', require('./views/newsletter-form') ]
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,17 +1,17 @@
|
|||||||
const divs = [ 60, 100, 10 ]
|
const divs = [60, 100, 10];
|
||||||
|
|
||||||
export default function (time) {
|
export default function (time) {
|
||||||
const arr = []
|
const arr = [];
|
||||||
for (let i = 0; i < divs.length; i++) {
|
for (let i = 0; i < divs.length; i++) {
|
||||||
const nbr = divs.slice(i).reduce((a, b) => a * b)
|
const nbr = divs.slice(i).reduce((a, b) => a * b);
|
||||||
|
|
||||||
const result = Math.floor(time / nbr)
|
const result = Math.floor(time / nbr);
|
||||||
|
|
||||||
arr.push(result)
|
arr.push(result);
|
||||||
|
|
||||||
time = time - result * nbr
|
time = time - result * nbr;
|
||||||
//this.timerElements[i].textContent = result
|
// this.timerElements[i].textContent = result
|
||||||
}
|
}
|
||||||
|
|
||||||
return arr
|
return arr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import splitTime from './split-time'
|
import splitTime from './split-time';
|
||||||
import twoDigits from './two-digits'
|
import twoDigits from './two-digits';
|
||||||
|
|
||||||
export default function (time) {
|
export default function (time) {
|
||||||
const arr = splitTime(time).map(twoDigits)
|
const arr = splitTime(time).map(twoDigits);
|
||||||
|
|
||||||
return arr.join(':')
|
return arr.join(':');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export default function twoDigits(val) {
|
export default function twoDigits(val) {
|
||||||
return val >= 10 ? val : '0' + val
|
return val >= 10 ? val : `0${val}`;
|
||||||
}
|
}
|
||||||
|
|||||||
2
gulp
2
gulp
@ -1 +1 @@
|
|||||||
Subproject commit f69b4494ab2bc55edb09d503396f94bf8b457496
|
Subproject commit 349bb1f3a91a4675b5ec3e8b907d8ae2daf39129
|
||||||
13
gulpconfig.js
Normal file
13
gulpconfig.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// modules > native
|
||||||
|
module.exports = {
|
||||||
|
rollup: {
|
||||||
|
entries: [
|
||||||
|
'client/app.jsx',
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
'app.js',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1 +1 @@
|
|||||||
gulp/index.js
|
gulp/gulpfile.js
|
||||||
71
package.json
71
package.json
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "budbilar",
|
"name": "pomodoro",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "När du vill få något budat till rätt pris.",
|
"description": "När du vill få något budat till rätt pris.",
|
||||||
"main": "server/server.js",
|
"main": "server/server.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@gitlab.thecodebureau.com:axel/budbilar.git"
|
"url": "git@gitlab.bitmill.co:lohfu/pomodoro.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"gulp": "gulp",
|
"gulp": "gulp",
|
||||||
@ -16,67 +16,30 @@
|
|||||||
"start": "node server/server.js"
|
"start": "node server/server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-preset-es2015-node6": "^0.3.0",
|
"babel-preset-es2015-node6": "^0.4.0",
|
||||||
"babel-register": "^6.14.0",
|
"babel-register": "^6.18.0",
|
||||||
"body-parser": "^1.15.2",
|
"body-parser": "^1.15.2",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^1.1.3",
|
||||||
"connect-redis": "^3.1.0",
|
"connect-redis": "^3.1.0",
|
||||||
"cookie-parser": "^1.4.3",
|
"cookie-parser": "^1.4.3",
|
||||||
"dollr": "0.0.9",
|
"dollr": "^0.1.1",
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
"express-service-errors": "github:thecodebureau/express-service-errors",
|
"express-service-errors": "github:thecodebureau/express-service-errors",
|
||||||
"express-session": "^1.14.1",
|
"express-session": "^1.14.2",
|
||||||
"lodash": "^4.15.0",
|
"hyperscript-jsx": "0.0.2",
|
||||||
"marko": "^3.10.1",
|
"jsx-node": "^0.1.0",
|
||||||
"marko-widgets": "^6.3.4",
|
"lodash": "^4.16.6",
|
||||||
"midwest": "0.0.2",
|
"lowline": "^0.1.1",
|
||||||
"midwest-module-membership": "github:thebitmill/midwest-module-membership",
|
"midwest": "^0.2.1",
|
||||||
"midwest-service-errors": "github:thebitmill/midwest-service-errors",
|
"midwest-module-membership": "^0.1.0",
|
||||||
"mongoose": "^4.6.0",
|
"midwest-service-errors": "^0.0.3",
|
||||||
|
"mongoose": "^4.6.6",
|
||||||
"mongopot": "github:lohfu/mongopot",
|
"mongopot": "github:lohfu/mongopot",
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"nodemailer": "^2.6.0",
|
"nodemailer": "^2.6.4",
|
||||||
"passport": "^0.3.2",
|
"passport": "^0.3.2",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"require-dir": "^0.3.0"
|
"preact": "^6.4.0",
|
||||||
},
|
"require-dir": "^0.3.1"
|
||||||
"devDependencies": {
|
|
||||||
"autoprefixer": "^6.4.1",
|
|
||||||
"babel-plugin-add-module-exports": "^0.2.1",
|
|
||||||
"babel-preset-es2015": "^6.14.0",
|
|
||||||
"babel-preset-react": "^6.11.1",
|
|
||||||
"browser-sync": "^2.16.0",
|
|
||||||
"chalk": "^1.1.3",
|
|
||||||
"csswring": "^5.1.0",
|
|
||||||
"eslint": "^3.5.0",
|
|
||||||
"eslint-config-airbnb": "^11.1.0",
|
|
||||||
"eslint-config-airbnb-base": "^7.1.0",
|
|
||||||
"eslint-plugin-import": "^1.15.0",
|
|
||||||
"eslint-plugin-jsx-a11y": "^2.2.2",
|
|
||||||
"eslint-plugin-react": "^6.2.2",
|
|
||||||
"event-stream": "^3.3.4",
|
|
||||||
"gulp": "github:gulpjs/gulp#4.0",
|
|
||||||
"gulp-less": "^3.1.0",
|
|
||||||
"gulp-postcss": "^6.2.0",
|
|
||||||
"gulp-rename": "^1.2.2",
|
|
||||||
"gulp-sourcemaps": "^1.6.0",
|
|
||||||
"gulp-svgmin": "^1.2.2",
|
|
||||||
"gulp-uglify": "^2.0.0",
|
|
||||||
"gulp-util": "^3.0.7",
|
|
||||||
"marko": "^3.10.1",
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"nodemon": "^1.10.2",
|
|
||||||
"postcss": "^5.2.0",
|
|
||||||
"pretty-hrtime": "^1.0.2",
|
|
||||||
"rimraf": "^2.5.4",
|
|
||||||
"rollup": "^0.35.10",
|
|
||||||
"rollup-plugin-babel": "^2.6.1",
|
|
||||||
"rollup-plugin-commonjs": "^3.3.0",
|
|
||||||
"rollup-plugin-marko": "0.0.2",
|
|
||||||
"rollup-plugin-node-resolve": "^2.0.0",
|
|
||||||
"rollup-plugin-replace": "^1.1.1",
|
|
||||||
"through2": "^2.0.1",
|
|
||||||
"vinyl-buffer": "^1.0.0",
|
|
||||||
"vinyl-source-stream": "^1.1.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
server/.eslintrc
Normal file
24
server/.eslintrc
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"airbnb-base",
|
||||||
|
"../.eslintrc"
|
||||||
|
],
|
||||||
|
|
||||||
|
"parserOptions": {
|
||||||
|
"sourceType": "strict"
|
||||||
|
},
|
||||||
|
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
"global-require": 0
|
||||||
|
},
|
||||||
|
|
||||||
|
"globals": {
|
||||||
|
"ENV": true,
|
||||||
|
"LOGIN_USER": true,
|
||||||
|
"PWD": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const p = require('path')
|
const p = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
static: p.join(PWD, 'public'),
|
static: p.join(PWD, 'public'),
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,47 +1,47 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash');
|
||||||
|
|
||||||
const errorTemplate = require('../templates/error.marko')
|
const errorTemplate = require('../../build/error.jsx');
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
post: (req, res, next) => {
|
post: (req, res, next) => {
|
||||||
res.template = errorTemplate
|
res.template = errorTemplate;
|
||||||
|
|
||||||
next()
|
next();
|
||||||
},
|
},
|
||||||
|
|
||||||
mystify: {
|
mystify: {
|
||||||
properties: ['errors', 'message', 'name', 'status', 'statusText']
|
properties: ['errors', 'message', 'name', 'status', 'statusText'],
|
||||||
},
|
},
|
||||||
|
|
||||||
log: {
|
log: {
|
||||||
// if database = true there has to be a mongoose model name ErrorModel
|
// if database = true there has to be a mongoose model name ErrorModel
|
||||||
ignore: [],
|
ignore: [],
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const ErrorModel = require('midwest-service-errors/model')
|
const ErrorModel = require('midwest-service-errors/model');
|
||||||
|
|
||||||
function store(error) {
|
function store(error) {
|
||||||
ErrorModel.create(error, (err) => {
|
ErrorModel.create(error, (err) => {
|
||||||
// TODO handle errors in error handler better
|
// TODO handle errors in error handler better
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('ERROR WRITING TO DATABASE')
|
console.error('ERROR WRITING TO DATABASE');
|
||||||
console.error(err)
|
console.error(err);
|
||||||
console.log(err.errors)
|
console.error(err.errors);
|
||||||
console.error('ORIGINAL ERROR')
|
console.error('ORIGINAL ERROR');
|
||||||
console.error(error)
|
console.error(error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = _.merge(defaults, {
|
module.exports = _.merge(defaults, {
|
||||||
development: {
|
development: {
|
||||||
log: {
|
log: {
|
||||||
store: store,
|
store,
|
||||||
console: true,
|
console: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
testing: {
|
testing: {
|
||||||
log: {
|
log: {
|
||||||
@ -51,8 +51,8 @@ module.exports = _.merge(defaults, {
|
|||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
log: {
|
log: {
|
||||||
store: store,
|
store,
|
||||||
console: false,
|
console: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
}[ENV])
|
}[ENV]);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
global.LOGIN_USER = 'lohfu@lohfu.io'
|
global.LOGIN_USER = 'lohfu@lohfu.io';
|
||||||
//global.LOGIN_USER = 'zarac@zarac.se'
|
// global.LOGIN_USER = 'zarac@zarac.se'
|
||||||
|
|||||||
@ -1,39 +1,40 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
site: require('./site')
|
site: require('./site'),
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
invite: {
|
invite: {
|
||||||
from: config.site.title + ' Robot <' + config.site.emails.robot + '>',
|
from: `${config.site.title} Robot <${config.site.emails.robot}>`,
|
||||||
subject: 'You have been invited to ' + config.site.title
|
subject: `You have been invited to ${config.site.title}`,
|
||||||
},
|
},
|
||||||
|
|
||||||
timeouts: {
|
timeouts: {
|
||||||
// 1 day
|
// 1 day
|
||||||
changePassword: 24 * 60 * 60 * 1000,
|
changePassword: 24 * 60 * 60 * 1000,
|
||||||
// verify email
|
// verify email
|
||||||
verifyEmail: 7 * 24 * 60 * 60 * 1000
|
verifyEmail: 7 * 24 * 60 * 60 * 1000,
|
||||||
},
|
},
|
||||||
|
|
||||||
paths: {
|
paths: {
|
||||||
register: '/register',
|
register: '/admin/register',
|
||||||
login: '/login',
|
login: '/admin/login',
|
||||||
forgotPassword: '/forgot-password',
|
forgotPassword: '/admin/forgot-password',
|
||||||
updatePassword: '/change-password'
|
updatePassword: '/admin/change-password',
|
||||||
|
verifyEmail: '/admin/verify-email',
|
||||||
},
|
},
|
||||||
|
|
||||||
redirects: {
|
redirects: {
|
||||||
login: '/admin',
|
login: '/admin',
|
||||||
logout: '/',
|
logout: '/',
|
||||||
register: '/admin'
|
register: '/admin',
|
||||||
},
|
},
|
||||||
|
|
||||||
remember: {
|
remember: {
|
||||||
// if expires is defined, it will be used. otherwise maxage
|
// if expires is defined, it will be used. otherwise maxage
|
||||||
expires: new Date('2038-01-19T03:14:07.000Z'),
|
expires: new Date('2038-01-19T03:14:07.000Z'),
|
||||||
//expires: Date.now() - 1,
|
// expires: Date.now() - 1,
|
||||||
maxAge: 30 * 24 * 60 * 60 * 1000,
|
maxAge: 30 * 24 * 60 * 60 * 1000,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -46,22 +47,22 @@ module.exports = {
|
|||||||
externalLoginFailed: 'External login failed.',
|
externalLoginFailed: 'External login failed.',
|
||||||
unverified: 'This account has not been verified.',
|
unverified: 'This account has not been verified.',
|
||||||
banned: 'User is banned.',
|
banned: 'User is banned.',
|
||||||
blocked: 'User is blocked due to too many login attempts.'
|
blocked: 'User is blocked due to too many login attempts.',
|
||||||
},
|
},
|
||||||
|
|
||||||
register: {
|
register: {
|
||||||
missingProperties: 'Oh no missing stuff',
|
missingProperties: 'Oh no missing stuff',
|
||||||
notAuthorized: 'The email is not authorized to create an account.',
|
notAuthorized: 'The email is not authorized to create an account.',
|
||||||
duplicateEmail: 'The email has already been registered.'
|
duplicateEmail: 'The email has already been registered.',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
passport: {
|
passport: {
|
||||||
local: {
|
local: {
|
||||||
usernameField: 'email'
|
usernameField: 'email',
|
||||||
},
|
},
|
||||||
|
|
||||||
scope: [ 'email' ],
|
scope: ['email'],
|
||||||
|
|
||||||
//providers: {
|
//providers: {
|
||||||
// facebook: {
|
// facebook: {
|
||||||
@ -76,5 +77,5 @@ module.exports = {
|
|||||||
// needs to be even
|
// needs to be even
|
||||||
tokenLength: 64,
|
tokenLength: 64,
|
||||||
// needs to be even
|
// needs to be even
|
||||||
saltLength: 16
|
saltLength: 16,
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
uri: 'mongodb://pomodoro-supreme:lets-work-our-asses-off-poop-poop@mongo.bitmill.co/pomodoro'
|
uri: 'mongodb://pomodoro-supreme:lets-work-our-asses-off-poop-poop@mongo.bitmill.co/pomodoro',
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = Object.assign(defaults, {
|
module.exports = Object.assign(defaults, {
|
||||||
production: {
|
production: {
|
||||||
//uri: 'mongodb://pomodoro-supreme:lets-work-our-asses-off-poop-poop@localhost/pomodoro'
|
// uri: 'mongodb://pomodoro-supreme:lets-work-our-asses-off-poop-poop@localhost/pomodoro'
|
||||||
}
|
},
|
||||||
}[ENV])
|
}[ENV]);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const basePort = 3050
|
const basePort = 3050;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
development: basePort,
|
development: basePort,
|
||||||
testing: basePort + 1,
|
testing: basePort + 1,
|
||||||
staging: basePort + 2,
|
staging: basePort + 2,
|
||||||
production: basePort + 3
|
production: basePort + 3,
|
||||||
}[ENV]
|
}[ENV];
|
||||||
|
|||||||
@ -1,37 +1,38 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const session = require('express-session')
|
const chalk = require('chalk');
|
||||||
|
const session = require('express-session');
|
||||||
|
|
||||||
let redisStore
|
let redisStore;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
secret: 'asdf1h918798&(*&ijh21kj4hk123j45h2k34jh52k3g45)thisisacompletelyrandomgeneratedstring...whatastrangecoincidence...',
|
secret: 'sometimespoopfeelslikeheaveninawarmbun.:L:AKJSHFKJh12349087ashabbasbasbbasdbfas w',
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true
|
saveUninitialized: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
const redisConfig = {
|
const redisConfig = {
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 6379
|
port: 6379,
|
||||||
}
|
};
|
||||||
|
|
||||||
if (ENV === 'production') {
|
if (ENV === 'production') {
|
||||||
const RedisStore = require('connect-redis')(require('express-session'))
|
const RedisStore = require('connect-redis')(require('express-session'));
|
||||||
|
|
||||||
redisStore = new RedisStore(redisConfig)
|
redisStore = new RedisStore(redisConfig);
|
||||||
|
|
||||||
redisStore.on('connect', function () {
|
redisStore.on('connect', () => {
|
||||||
console.info('Redis connected succcessfully')
|
console.info(`[${chalk.cyan('INIT')}] Redis connected succcessfully`);
|
||||||
})
|
});
|
||||||
|
|
||||||
redisStore.on('disconnect', function () {
|
redisStore.on('disconnect', () => {
|
||||||
throw new Error('Unable to connect to redis. Has it been started?')
|
throw new Error('Unable to connect to redis. Has it been started?');
|
||||||
})
|
});
|
||||||
|
|
||||||
config.store = redisStore
|
config.store = redisStore;
|
||||||
} else {
|
} else {
|
||||||
config.store = new session.MemoryStore()
|
config.store = new session.MemoryStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config
|
module.exports = config;
|
||||||
|
|
||||||
|
|||||||
59
server/config/shim.js
Normal file
59
server/config/shim.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js': [
|
||||||
|
'chrome <= 12',
|
||||||
|
'chrome mobile <= 12',
|
||||||
|
'chrome mobile ios <= 12',
|
||||||
|
'firefox <= 20',
|
||||||
|
'firefox mobile <= 20',
|
||||||
|
'ie <= 9',
|
||||||
|
'ie mobile <= 9',
|
||||||
|
'opera <= 12',
|
||||||
|
'safari <= 5',
|
||||||
|
'mobile safari <= 5',
|
||||||
|
'samsung internet <= 1',
|
||||||
|
],
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.min.js': [
|
||||||
|
'chrome <= 51',
|
||||||
|
'chrome mobile <= 51',
|
||||||
|
'chrome mobile ios <= 51',
|
||||||
|
'edge <= 13',
|
||||||
|
'edge mobile <= 13',
|
||||||
|
'firefox <= 44',
|
||||||
|
'firefox mobile <= 44',
|
||||||
|
'ie <= 11',
|
||||||
|
'ie mobile <= 11',
|
||||||
|
'safari <= 9',
|
||||||
|
'mobile safari <= 9',
|
||||||
|
'samsung internet <= 2',
|
||||||
|
],
|
||||||
|
'https://unpkg.com/es7-shim@latest/dist/es7-shim.min.js': [
|
||||||
|
'chrome <= 50',
|
||||||
|
'chrome mobile <= 50',
|
||||||
|
'chrome mobile ios <= 50',
|
||||||
|
'edge <= 14',
|
||||||
|
'edge mobile <= 14',
|
||||||
|
'firefox <= 46',
|
||||||
|
'firefox mobile <= 46',
|
||||||
|
'ie <= 11',
|
||||||
|
'ie mobile <= 11',
|
||||||
|
'safari <= 10',
|
||||||
|
'mobile safari <= 10',
|
||||||
|
'samsung internet <= 3',
|
||||||
|
],
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js': [
|
||||||
|
'chrome <= 41',
|
||||||
|
'chrome mobile <= 41',
|
||||||
|
'chrome mobile ios <= 41',
|
||||||
|
'edge <= 13',
|
||||||
|
'edge mobile <= 13',
|
||||||
|
'firefox <= 38',
|
||||||
|
'firefox mobile <= 38',
|
||||||
|
'ie <= 11',
|
||||||
|
'ie mobile <= 11',
|
||||||
|
'safari <= 9',
|
||||||
|
'mobile safari <= 9',
|
||||||
|
'samsung internet <= 3',
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -1,51 +1,51 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash');
|
||||||
|
|
||||||
const domain = 'pomodoro.bitmill.co'
|
const domain = 'pomodoro.bitmill.co';
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
domain: domain,
|
domain,
|
||||||
title: 'Pomodoro',
|
title: 'Pomodoro',
|
||||||
name: 'pomodoro',
|
name: 'pomdoro',
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
get host() {
|
get host() {
|
||||||
return this.port ? this.hostname + ':' + this.port : this.hostname
|
return this.port ? `${this.hostname}:${this.port}` : this.hostname;
|
||||||
},
|
},
|
||||||
get url() {
|
get url() {
|
||||||
return this.protocol + '://' + this.host + '/'
|
return `${this.protocol}://${this.host}/`;
|
||||||
},
|
},
|
||||||
emails: {
|
emails: {
|
||||||
robot: 'no-reply@thecodebureau.com',
|
robot: 'no-reply@thecodebureau.com',
|
||||||
info: 'info@thecodebureau.com',
|
info: 'info@thecodebureau.com',
|
||||||
webmaster: 'webmaster@thecodebureau.com',
|
webmaster: 'webmaster@thecodebureau.com',
|
||||||
order: 'info@thecodebureau.com'
|
order: 'info@thecodebureau.com',
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = _.merge(defaults, {
|
module.exports = _.merge(defaults, {
|
||||||
development: {
|
development: {
|
||||||
hostname: 'localhost',
|
hostname: 'localhost',
|
||||||
port: process.env.EXTERNAL_PORT || process.env.PORT || require('./port')
|
port: process.env.EXTERNAL_PORT || process.env.PORT || require('./port'),
|
||||||
},
|
},
|
||||||
|
|
||||||
testing: {
|
testing: {
|
||||||
hostname: 'localhost',
|
hostname: 'localhost',
|
||||||
port: process.env.PORT || require('./port')
|
port: process.env.PORT || require('./port'),
|
||||||
},
|
},
|
||||||
|
|
||||||
staging: {
|
staging: {
|
||||||
hostname: 'staging.' + domain
|
hostname: 'staging.pomodoro.bitmill.co',
|
||||||
},
|
},
|
||||||
|
|
||||||
production: {
|
production: {
|
||||||
hostname: domain,
|
hostname: domain,
|
||||||
protocol: 'https',
|
// protocol: 'https',
|
||||||
emails: {
|
// emails: {
|
||||||
robot: 'no-reply@bitmill.co',
|
// robot: `no-reply@${domain}`,
|
||||||
info: 'info@bitmill.co',
|
// info: `info@${domain}`,
|
||||||
webmaster: 'webmaster@bitmill.co',
|
// webmaster: `webmaster@${domain}`,
|
||||||
order: 'order@bitmill.co'
|
// order: `order@${domain}`,
|
||||||
}
|
// },
|
||||||
}
|
},
|
||||||
}[ENV])
|
}[ENV]);
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash');
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
auth: {
|
auth: {
|
||||||
user: 'SMTP_Injection',
|
user: 'SMTP_Injection',
|
||||||
// dev key
|
// dev key
|
||||||
pass: '2eec390c5b3f5d593c9f152179bf51e90b073784'
|
pass: '2eec390c5b3f5d593c9f152179bf51e90b073784',
|
||||||
},
|
},
|
||||||
host: 'smtp.sparkpostmail.com',
|
host: 'smtp.sparkpostmail.com',
|
||||||
port: 587
|
port: 587,
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = _.merge(defaults, {}[ENV])
|
module.exports = _.merge(defaults, {}[ENV]);
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const masterTemplate = require('../client/master.marko')
|
|
||||||
|
|
||||||
const router = new (require('express')).Router()
|
|
||||||
|
|
||||||
router.get('/', (req, res, next) => {
|
|
||||||
res.template = masterTemplate
|
|
||||||
|
|
||||||
next()
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = router
|
|
||||||
31
server/render.jsx
Normal file
31
server/render.jsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module.exports = function (Component, Master) {
|
||||||
|
const locals = Object.assign({}, this.app.locals, this.locals);
|
||||||
|
|
||||||
|
let preamble = '';
|
||||||
|
let html;
|
||||||
|
|
||||||
|
if (typeof Master === 'function') {
|
||||||
|
preamble = '<!doctype html>';
|
||||||
|
|
||||||
|
if (typeof Component === 'function') {
|
||||||
|
return this.send(preamble + (
|
||||||
|
<Master {...locals}>
|
||||||
|
<Component {...locals}/>
|
||||||
|
</Master>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Component = Master;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Component !== 'function') {
|
||||||
|
throw new Error('Not a Component');
|
||||||
|
} else if (Component.prototype && Component.prototype.render) {
|
||||||
|
const instance = new Component(locals);
|
||||||
|
html = instance.render(instance.props, instance.state);
|
||||||
|
} else {
|
||||||
|
html = Component(locals);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send(preamble ? preamble + html : html);
|
||||||
|
};
|
||||||
13
server/routers/index.js
Normal file
13
server/routers/index.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const masterTemplate = require('../../build/master.jsx');
|
||||||
|
|
||||||
|
const router = new (require('express')).Router();
|
||||||
|
|
||||||
|
router.get('/', (req, res, next) => {
|
||||||
|
res.template = masterTemplate;
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
166
server/server.js
166
server/server.js
@ -1,6 +1,5 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
require('babel-register')
|
|
||||||
/*
|
/*
|
||||||
* The main file that sets up the Express instance and node
|
* The main file that sets up the Express instance and node
|
||||||
*
|
*
|
||||||
@ -9,58 +8,55 @@ require('babel-register')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// set up some globals (these are also set in Epiphany if not already set)
|
// set up some globals (these are also set in Epiphany if not already set)
|
||||||
global.ENV = process.env.NODE_ENV || 'development'
|
global.ENV = process.env.NODE_ENV || 'development';
|
||||||
global.PWD = process.env.NODE_PWD || process.cwd()
|
global.PWD = process.env.NODE_PWD || process.cwd();
|
||||||
|
|
||||||
// make node understand `*.marko` files
|
|
||||||
require('marko/node-require').install()
|
|
||||||
|
|
||||||
// modules > native
|
// modules > native
|
||||||
const p = require('path')
|
const p = require('path');
|
||||||
|
|
||||||
|
if (ENV === 'development') {
|
||||||
|
// output filename in console log and colour console.dir
|
||||||
|
require('midwest/util/console');
|
||||||
|
// needed so symlinked modules get access to main projects node_modules/
|
||||||
|
require('app-module-path').addPath(p.join(PWD, 'node_modules'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// make node understand `*.jsx` files
|
||||||
|
require('jsx-node').install({
|
||||||
|
replace: {
|
||||||
|
lowline: 'lodash',
|
||||||
|
preact: 'jsx-node',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// modules > 3rd party
|
// modules > 3rd party
|
||||||
const requireDir = require('require-dir')
|
const _ = require('lodash');
|
||||||
const _ = require('lodash')
|
const chalk = require('chalk');
|
||||||
const express = require('express')
|
const express = require('express');
|
||||||
const mongoose = require('mongoose')
|
const mongoose = require('mongoose');
|
||||||
const passport = require('passport')
|
const passport = require('passport');
|
||||||
|
const requireDir = require('require-dir');
|
||||||
|
|
||||||
// modules > express middlewares
|
// modules > express middlewares
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser');
|
||||||
const session = require('express-session')
|
const session = require('express-session');
|
||||||
const cookieParser = require('cookie-parser')
|
const cookieParser = require('cookie-parser');
|
||||||
|
|
||||||
// modules > 3rd party
|
|
||||||
const chalk = require('chalk')
|
|
||||||
|
|
||||||
// modules > midwest
|
// modules > midwest
|
||||||
const colorizeStack = require('midwest/util/colorize-stack')
|
const colorizeStack = require('midwest/util/colorize-stack');
|
||||||
|
|
||||||
const config = requireDir('./config')
|
const config = requireDir('./config', { camelcase: true });
|
||||||
|
|
||||||
// make error output stack pretty
|
// make error output stack pretty
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
console.error(chalk.red('UNCAUGHT EXCEPTION'))
|
console.error(chalk.red('UNCAUGHT EXCEPTION'));
|
||||||
if (err.stack) {
|
if (err.stack) {
|
||||||
console.error(colorizeStack(err.stack))
|
console.error(colorizeStack(err.stack));
|
||||||
} else {
|
} else {
|
||||||
console.error(err)
|
console.error(err);
|
||||||
}
|
}
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
})
|
});
|
||||||
|
|
||||||
// mongoose mpromise library is being deprecated
|
|
||||||
mongoose.Promise = Promise
|
|
||||||
|
|
||||||
// connect to mongodb
|
|
||||||
mongoose.connect(config.mongo.uri, _.omit(config.mongo, 'uri'), (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err)
|
|
||||||
process.exit()
|
|
||||||
}
|
|
||||||
|
|
||||||
console.info('[' + chalk.cyan('INIT') + '] Mongoose is connected.')
|
|
||||||
})
|
|
||||||
|
|
||||||
const prewares = [
|
const prewares = [
|
||||||
express.static(config.dir.static, ENV === 'production' ? { maxAge: '1 year' } : null),
|
express.static(config.dir.static, ENV === 'production' ? { maxAge: '1 year' } : null),
|
||||||
@ -70,70 +66,86 @@ const prewares = [
|
|||||||
session(config.session),
|
session(config.session),
|
||||||
passport.initialize(),
|
passport.initialize(),
|
||||||
passport.session(),
|
passport.session(),
|
||||||
]
|
];
|
||||||
|
|
||||||
if (ENV === 'development') {
|
if (ENV === 'development') {
|
||||||
// only log requests to console in development mode
|
// only log requests to console in development mode
|
||||||
prewares.unshift(require('morgan')('dev'))
|
prewares.unshift(require('morgan')('dev'));
|
||||||
prewares.push(require('midwest-module-membership/passport/automatic-login'))
|
// automatically login global.LOGIN_USER
|
||||||
|
prewares.push(require('midwest-module-membership/passport/automatic-login'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const postwares = [
|
const postwares = [
|
||||||
require('midwest/middleware/ensure-found'),
|
require('midwest/middleware/ensure-found'),
|
||||||
// transform and log error
|
// transform and log error
|
||||||
require('midwest/middleware/error-handler'),
|
require('midwest/factories/error-handler')(config.errorHandler),
|
||||||
// respond
|
// respond
|
||||||
require('midwest/middleware/responder'),
|
require('midwest/middleware/responder'),
|
||||||
]
|
];
|
||||||
|
|
||||||
const server = express()
|
const server = express();
|
||||||
|
|
||||||
// get IP & whatnot from nginx proxy
|
// get IP & whatnot from nginx proxy
|
||||||
server.set('trust proxy', true)
|
server.set('trust proxy', true);
|
||||||
|
|
||||||
server.locals.site = require('./config/site')
|
Object.assign(server.locals, {
|
||||||
|
site: require('./config/site'),
|
||||||
if (ENV === 'production') {
|
});
|
||||||
Object.assign(server.locals, {
|
|
||||||
js: require(p.join(PWD, 'public/js.json')),
|
|
||||||
css: require(p.join(PWD, 'public/css.json'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// override default response render method for
|
// override default response render method for
|
||||||
// more convenient use with marko
|
// more convenient use with jsx
|
||||||
server.response.render = function (template) {
|
server.response.render = require('./render.jsx');
|
||||||
const locals = _.extend({}, server.locals, this.locals)
|
|
||||||
|
|
||||||
template.render(locals, this)
|
try {
|
||||||
}
|
server.locals.js = require(p.join(PWD, 'public/js.json'));
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.locals.css = require(p.join(PWD, 'public/css.json'));
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
// load all prewares
|
// load all prewares
|
||||||
server.use(...prewares)
|
server.use(...prewares);
|
||||||
|
|
||||||
// routes > pages
|
// routes > pages
|
||||||
server.use(require('./pages'))
|
server.use(require('./routers/index'));
|
||||||
|
|
||||||
// routes > authentication
|
// routes > authentication
|
||||||
server.use('/auth', require('midwest-module-membership/passport/router'))
|
server.use('/auth', require('midwest-module-membership/passport/router'));
|
||||||
|
|
||||||
// routes > api > membership
|
|
||||||
server.use('/api/roles', require('midwest-module-membership/services/roles/router'))
|
|
||||||
server.use('/api/permissions', require('midwest-module-membership/services/permissions/router'))
|
|
||||||
server.use('/api/invites', require('midwest-module-membership/services/invites/router'))
|
|
||||||
server.use('/api/users', require('midwest-module-membership/services/users/router'))
|
|
||||||
|
|
||||||
// routes > api > errors
|
|
||||||
server.use('/api/errors', require('midwest-service-errors/router'))
|
|
||||||
|
|
||||||
// routes > api > pomodoro
|
// routes > api > pomodoro
|
||||||
server.use('/api/pomodoros', require('./services/pomodoros/router'))
|
server.use('/api/pomodoros', require('./services/pomodoros/router'));
|
||||||
|
|
||||||
|
// routes > api > errors
|
||||||
|
server.use('/api/errors', require('midwest-service-errors/router'));
|
||||||
|
|
||||||
|
// routes > api > membership
|
||||||
|
server.use('/api/roles', require('midwest-module-membership/services/roles/router'));
|
||||||
|
server.use('/api/permissions', require('midwest-module-membership/services/permissions/router'));
|
||||||
|
server.use('/api/invites', require('midwest-module-membership/services/invites/router'));
|
||||||
|
server.use('/api/users', require('midwest-module-membership/services/users/router'));
|
||||||
|
|
||||||
// load all postwares
|
// load all postwares
|
||||||
server.use(...postwares)
|
server.use(...postwares);
|
||||||
|
|
||||||
server.listen(config.port, () => {
|
// mpromise (built in mongoose promise library) is deprecated,
|
||||||
console.info('[' + chalk.cyan('INIT') + '] HTTP Server listening on port ' + chalk.magenta('%s') + ' (' + chalk.yellow('%s') + ')', config.port, ENV)
|
// tell mongoose to use native Promises instead
|
||||||
})
|
mongoose.Promise = Promise;
|
||||||
|
// connect to mongodb
|
||||||
|
mongoose.connect(config.mongo.uri, _.omit(config.mongo, 'uri'), (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = server
|
console.info(`[${chalk.cyan('INIT')}] Mongoose is connected.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only start Express server when it is the main module (ie not required by test)
|
||||||
|
if (require.main === module) {
|
||||||
|
server.http = server.listen(config.port, () => {
|
||||||
|
console.info(`[${chalk.cyan('INIT')}] HTTP Server listening on port ${chalk.magenta(config.port)} (${chalk.yellow(server.get('env'))})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = server;
|
||||||
|
|||||||
@ -1,48 +1,48 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const rest = require('midwest/middleware/rest')
|
const rest = require('midwest/factories/rest');
|
||||||
const formatQuery = require('midwest/middleware/format-query')
|
const formatQuery = require('midwest/factories/format-query');
|
||||||
const paginate = require('midwest/middleware/paginate')
|
const paginate = require('midwest/factories/paginate');
|
||||||
|
|
||||||
const Pomodoro = require('./model')
|
const Pomodoro = require('./model');
|
||||||
|
|
||||||
function create(req, res, next) {
|
function create(req, res, next) {
|
||||||
Pomodoro.create(Object.assign(req.body, {
|
Pomodoro.create(Object.assign(req.body, {
|
||||||
user: req.user && req.user.id || '57b04f50a1eaaf354f3b96a6',
|
user: req.user && req.user.id || '57b04f50a1eaaf354f3b96a6',
|
||||||
ip: req.ip,
|
ip: req.ip,
|
||||||
userAgent: req.headers['user-agent']
|
userAgent: req.headers['user-agent'],
|
||||||
}), (err, pomodoro) => {
|
}), (err, pomodoro) => {
|
||||||
res.locals.pomodoro = pomodoro
|
res.locals.pomodoro = pomodoro;
|
||||||
|
|
||||||
next(err)
|
next(err);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function end(req, res, next) {
|
function end(req, res, next) {
|
||||||
Pomodoro.findByIdAndUpdate(req.params.id, { endDate: new Date() }, (err, pomodoro) => {
|
Pomodoro.findByIdAndUpdate(req.params.id, { endDate: new Date() }, (err, pomodoro) => {
|
||||||
if (err) return next(err)
|
if (err) return next(err);
|
||||||
|
|
||||||
res.locals.pomodoro = pomodoro
|
res.locals.pomodoro = pomodoro;
|
||||||
|
|
||||||
next()
|
next();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActive(req, res, next) {
|
function getActive(req, res, next) {
|
||||||
Pomodoro.find({ user: req.user.id, endDate: { $eq: null } }, (err, pomodoros) => {
|
Pomodoro.find({ user: req.user.id, endDate: { $eq: null } }, (err, pomodoros) => {
|
||||||
res.locals.pomodoros = pomodoros
|
res.locals.pomodoros = pomodoros;
|
||||||
|
|
||||||
return next(err)
|
return next(err);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Object.assign(rest(Pomodoro), {
|
module.exports = Object.assign(rest(Pomodoro), {
|
||||||
create,
|
create,
|
||||||
end,
|
end,
|
||||||
formatQuery: formatQuery([ 'limit', 'sort' ], {
|
formatQuery: formatQuery(['limit', 'sort'], {
|
||||||
endDate: 'exists'
|
endDate: 'exists',
|
||||||
}),
|
}),
|
||||||
getActive,
|
getActive,
|
||||||
paginate: paginate(Pomodoro, 50)
|
paginate: paginate(Pomodoro, 50),
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const mongoose = require('mongoose')
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
const PomodoroSchema = new mongoose.Schema({
|
const PomodoroSchema = new mongoose.Schema({
|
||||||
startTime: {
|
startTime: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
endTime: {
|
endTime: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
name: String,
|
name: String,
|
||||||
location: String,
|
location: String,
|
||||||
user: {
|
user: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'User',
|
ref: 'User',
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
ip: {
|
ip: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
userAgent: {
|
userAgent: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports = mongoose.model('Pomodoro', PomodoroSchema)
|
module.exports = mongoose.model('Pomodoro', PomodoroSchema);
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const router = new (require('express')).Router()
|
const router = new (require('express')).Router();
|
||||||
|
|
||||||
const mw = require('./middleware')
|
const mw = require('./middleware');
|
||||||
|
|
||||||
const { isAuthenticated } = require('midwest-module-membership/passport/authorization-middleware')
|
const { isAuthenticated } = require('midwest-module-membership/passport/authorization-middleware');
|
||||||
|
|
||||||
router.route('/')
|
router.route('/')
|
||||||
.get(isAuthenticated, mw.formatQuery, mw.paginate, mw.query)
|
.get(isAuthenticated, mw.formatQuery, mw.paginate, mw.query)
|
||||||
.post(isAuthenticated, mw.create)
|
.post(isAuthenticated, mw.create);
|
||||||
|
|
||||||
router.route('/:id')
|
router.route('/:id')
|
||||||
.get(isAuthenticated, mw.findById)
|
.get(isAuthenticated, mw.findById)
|
||||||
.patch(isAuthenticated, mw.update)
|
.patch(isAuthenticated, mw.update)
|
||||||
.put(isAuthenticated, mw.replace)
|
.put(isAuthenticated, mw.replace)
|
||||||
.delete(isAuthenticated, mw.remove)
|
.delete(isAuthenticated, mw.remove);
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user