diff --git a/.drone.yml b/.drone.yml
index 6936437..2d09410 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -1,13 +1,27 @@
pipeline:
test:
- image: node:7.5.0
+ image: viestinta/node:viestinta-test
when:
event: [push,pull_request]
branches: [master, react-start]
+ environment:
+ DATABASE_URL: postgres://postgres:viestintacentos@127.0.0.1:5432
+ NODE_ENV: test
+ COVERALLS_REPO_TOKEN: $$COVERALLS_TOKEN
+ COVERALLS_TOKEN: $$COVERALLS_TOKEN
+ CODECOV_TOKEN: $$CODECOV_TOKEN
+
commands:
- - npm install --silent
+ - cp -a /drone/node_modules /root
+ - npm install --depth=0 --quiet
- npm install standard -g
+ - npm install codecov -g
- npm run test
+ - cat ./coverage/lcov.info | codecov
+ - cp -a /root/node_modules /drone
+ volumes:
+ - "/drone/node_modules"
+
deploy:
image: plugins/ssh
when:
@@ -18,3 +32,20 @@ pipeline:
commands:
- bash /scripts/deploy-viestinta-prod.sh
+services:
+ postgres:
+ image: postgres:9.6
+ container_name: viestinta_postgres
+ ports:
+ - "5432:5432"
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: viestintacentos
+ POSTGRES_DB: viestintadb_dev
+
+cache:
+ mount:
+ - /drone/node_modules
+
+
+
diff --git a/.drone.yml.sig b/.drone.yml.sig
index e3510e9..eacc854 100644
--- a/.drone.yml.sig
+++ b/.drone.yml.sig
@@ -1 +1 @@
-eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDogCiAgICBpbWFnZTogbm9kZTo3LjUuMAogICAgd2hlbjoKICAgICAgZXZlbnQ6IFtwdXNoLHB1bGxfcmVxdWVzdF0KICAgICAgYnJhbmNoZXM6IFttYXN0ZXIsIHJlYWN0LXN0YXJ0XQogICAgY29tbWFuZHM6CiAgICAgIC0gbnBtIGluc3RhbGwgLS1zaWxlbnQKICAgICAgLSBucG0gaW5zdGFsbCBzdGFuZGFyZCAtZwogICAgICAtIG5wbSBydW4gdGVzdAogIGRlcGxveToKICAgIGltYWdlOiBwbHVnaW5zL3NzaAogICAgd2hlbjoKICAgICAgZXZlbnQ6IHB1c2gKICAgICAgYnJhbmNoOiBwcm9kdWN0aW9uCiAgICBob3N0OiBzdG9ra2Vycy5ubwogICAgcG9ydDogMjIwMTQKICAgIGNvbW1hbmRzOgogICAgICAtIGJhc2ggL3NjcmlwdHMvZGVwbG95LXZpZXN0aW50YS1wcm9kLnNoCgo.HUOmcN4jh1vwJ1PEpLPzqjFyuhaL9yEoN-PJfMz4M14
\ No newline at end of file
+eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDogCiAgICBpbWFnZTogdmllc3RpbnRhL25vZGU6dmllc3RpbnRhLXRlc3QKICAgIHdoZW46CiAgICAgIGV2ZW50OiBbcHVzaCxwdWxsX3JlcXVlc3RdCiAgICAgIGJyYW5jaGVzOiBbbWFzdGVyLCByZWFjdC1zdGFydF0KICAgIGVudmlyb25tZW50OgogICAgICBEQVRBQkFTRV9VUkw6IHBvc3RncmVzOi8vcG9zdGdyZXM6dmllc3RpbnRhY2VudG9zQDEyNy4wLjAuMTo1NDMyCiAgICAgIE5PREVfRU5WOiB0ZXN0CiAgICAgIENPVkVSQUxMU19SRVBPX1RPS0VOOiAkJENPVkVSQUxMU19UT0tFTgogICAgICBDT1ZFUkFMTFNfVE9LRU46ICQkQ09WRVJBTExTX1RPS0VOCiAgICAgIENPREVDT1ZfVE9LRU46ICQkQ09ERUNPVl9UT0tFTgoKICAgIGNvbW1hbmRzOgogICAgICAtIGNwIC1hIC9kcm9uZS9ub2RlX21vZHVsZXMgL3Jvb3QKICAgICAgLSBucG0gaW5zdGFsbCAtLWRlcHRoPTAgLS1xdWlldAogICAgICAtIG5wbSBpbnN0YWxsIHN0YW5kYXJkIC1nCiAgICAgIC0gbnBtIGluc3RhbGwgY29kZWNvdiAtZwogICAgICAtIG5wbSBydW4gdGVzdAogICAgICAtIGNhdCAuL2NvdmVyYWdlL2xjb3YuaW5mbyB8IGNvZGVjb3YKICAgICAgLSBjcCAtYSAvcm9vdC9ub2RlX21vZHVsZXMgL2Ryb25lCiAgICB2b2x1bWVzOgogICAgICAtICIvZHJvbmUvbm9kZV9tb2R1bGVzIgoKICBkZXBsb3k6CiAgICBpbWFnZTogcGx1Z2lucy9zc2gKICAgIHdoZW46CiAgICAgIGV2ZW50OiBwdXNoCiAgICAgIGJyYW5jaDogcHJvZHVjdGlvbgogICAgaG9zdDogc3Rva2tlcnMubm8KICAgIHBvcnQ6IDIyMDE0CiAgICBjb21tYW5kczoKICAgICAgLSBiYXNoIC9zY3JpcHRzL2RlcGxveS12aWVzdGludGEtcHJvZC5zaAoKc2VydmljZXM6CiAgICBwb3N0Z3JlczoKICAgICAgaW1hZ2U6IHBvc3RncmVzOjkuNgogICAgICBjb250YWluZXJfbmFtZTogdmllc3RpbnRhX3Bvc3RncmVzCiAgICAgIHBvcnRzOgogICAgICAgIC0gIjU0MzI6NTQzMiIKICAgICAgZW52aXJvbm1lbnQ6CiAgICAgICAgUE9TVEdSRVNfVVNFUjogcG9zdGdyZXMKICAgICAgICBQT1NUR1JFU19QQVNTV09SRDogdmllc3RpbnRhY2VudG9zCiAgICAgICAgUE9TVEdSRVNfREI6IHZpZXN0aW50YWRiX2RldgoKY2FjaGU6CiAgbW91bnQ6CiAgICAtIC9kcm9uZS9ub2RlX21vZHVsZXMKCgoK.Rs-UC3geCk_5gYUXlbmTIsNXGdBYZIsgEVQdYj_TZn0
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 52f2fc1..cdf950c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,3 @@
-src/server/etc/config.json
-src/server/config.json
-*bundle.js
-npm-debug.log
-
-
### Linux ###
*~
@@ -97,11 +91,14 @@ $RECYCLE.BIN/
*.lnk
#Pycharm settingsfile
-.idea/*
+.idea/
workspace.xml
# End of https://www.gitignore.io/api/linux,windows,node
-.idea/
-src/server/etc/
+*config.json
+*bundle.js
+npm-debug.log
src/server/database/migrations/
src/server/database/seeders/
+
+
diff --git a/.sequelizesrc b/.sequelizesrc
index dcf4114..067b363 100644
--- a/.sequelizesrc
+++ b/.sequelizesrc
@@ -1,8 +1,8 @@
var path = require('path');
module.exports = {
- 'config': path.resolve('./', 'config/config.js'),
- 'migrations-path': path.resolve('./', 'server/migrations'),
- 'seeders-path': path.resolve('./', 'server/seeders'),
- 'models-path': path.resolve('./', 'server/models')
-};
+ 'config': path.resolve('./', 'src/server/database/config/config.js'),
+ 'migrations-path': path.resolve('./', 'src/server/database/migrations'),
+ 'seeders-path': path.resolve('./', 'src/server/database/seeders'),
+ 'models-path': path.resolve('./', 'src/server/database/models')
+};
\ No newline at end of file
diff --git a/docker-compose.test.yml b/docker-compose.test.yml
new file mode 100644
index 0000000..39bc318
--- /dev/null
+++ b/docker-compose.test.yml
@@ -0,0 +1,34 @@
+version: '3'
+
+services:
+ postgres:
+ image: postgres:9.6
+ container_name: viestinta_postgres
+ ports:
+ - "5432:5432"
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: viestintacentos
+ POSTGRES_DB: viestintadb_dev
+ tty: true
+ stdin_open: true
+
+ nodejs:
+ build: .
+ image: node:viestinta
+ container_name: viestinta_node
+ depends_on:
+ - postgres
+ command: ["./wait-for-postgres.sh", "--", "npm" , "test"]
+ links:
+ - postgres
+ ports:
+ - "8000:8000"
+ volumes:
+ - .:/srv/app/
+ - /arv/app/node_modules
+ environment:
+ DATABASE_URL: postgres://postgres:viestintacentos@postgres:5432/viestintadb_dev
+ NODE_ENV: test
+ tty: true
+ stdin_open: true
diff --git a/docker-compose.yml b/docker-compose.yml
index 5fe61c8..4472af8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -16,11 +16,11 @@ services:
nodejs:
build: .
- image: nodetest:viestinta
+ image: node:viestinta
container_name: viestinta_node
depends_on:
- postgres
- command: ["./wait-for-postgres.sh", "--", "npm" , "start"]
+ command: bash -c "npm install && ./node_modules/.bin/webpack && sleep 5 && npm start"
links:
- postgres
diff --git a/package.json b/package.json
index 95482d1..720dc61 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"scripts": {
"dev": "grunt && sequelize db:migrate && sequelize db:seed:all && node src/server/app.js",
"test-client": "node src/server/app.js && mocha --compilers js:babel-core/register ./src/client/test",
- "test-server": "node src/server/app.js && node src/tests/init.js",
+ "test": "node src/server/app.js && nyc --check-coverage --lines 60 mocha src/test/server/**.js && nyc report --reporter=text-lcov > ./coverage/lcov.info",
"start": "node src/server/app.js",
"lint": "standard ./server/* ./client/*",
"webpack": "./node_modules/.bin/webpack"
@@ -40,21 +40,30 @@
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.23.0",
"body-parser": "^1.16.0",
+ "codecov": "^1.0.1",
"cookie-parser": "^1.4.3",
"express": "^4.14.1",
"express-session": "^1.15.0",
+ "fs": "0.0.1-security",
+ "istanbul": "^0.4.5",
"latest-version": "^3.0.0",
"loadash": "0.0.1",
+ "mocha": "^3.2.0",
"morgan": "^1.7.0",
"nconf": "^0.8.4",
+ "nyc": "^10.1.2",
"passport": "^0.3.2",
"passport-dataporten": "^1.1.3",
"passport-openid-connect": "^0.1.0",
+ "path": "^0.12.7",
"pg": "^6.1.2",
+ "pg-hstore": "^2.3.2",
"react": "^15.4.2",
"react-dom": "^15.4.2",
+ "react-tap-event-plugin": "^2.0.1",
"sequelize": "^3.30.2",
"sequelize-cli": "^2.5.1",
+ "socket.io-client": "^1.7.3",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.3.0"
},
@@ -65,13 +74,19 @@
"babel-preset-react": "^6.23.0",
"chai": "^3.5.0",
"check-dependencies": "^1.0.1",
+ "codecov": "^1.0.1",
+ "coveralls": "^2.11.16",
"enzyme": "^2.7.1",
"eslint": "^3.15.0",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^2.0.1",
"http": "0.0.0",
+ "material-ui": "^0.17.0",
+ "istanbul": "^0.4.5",
+ "istanbul-coveralls": "^1.0.3",
"mocha": "^3.2.0",
+ "nyc": "^10.1.2",
"react-addons-test-utils": "^15.4.2",
"should": "^11.2.0",
"socket.io": "^1.7.2",
@@ -83,7 +98,14 @@
"presets": [
"es2015",
"react"
- ]
+ ],
+ "env": {
+ "test": {
+ "plugins": [
+ "istanbul"
+ ]
+ }
+ }
},
"standard": {
"globals": [
diff --git a/src/client/client.js b/src/client/client.js
index d5e14ed..e3752e3 100644
--- a/src/client/client.js
+++ b/src/client/client.js
@@ -3,7 +3,14 @@ import ReactDOM from 'react-dom'
import ChatApp from './components/ChatApp'
+import injectTapEventPlugin from 'react-tap-event-plugin';
+
+// Needed for onTouchTap
+injectTapEventPlugin();
+
if (typeof window !== 'undefined') {
ReactDOM.render(
- , document.getElementById('app'))
+ ,
+ document.getElementById('app')
+ )
}
diff --git a/src/client/components/ChatApp.js b/src/client/components/ChatApp.js
index 626cea8..f063249 100644
--- a/src/client/components/ChatApp.js
+++ b/src/client/components/ChatApp.js
@@ -1,58 +1,67 @@
import React, { Component } from 'react'
+import socket from '../../server/socket'
+// Theme
+import {deepOrange500} from 'material-ui/styles/colors'
+import getMuiTheme from 'material-ui/styles/getMuiTheme'
+import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
+
+// Components
import ChatBox from './ChatBox'
-import ChatField from './ChatField'
+import MessageList from './MessageList'
import Header from './Header'
import Login from './Login'
+import FeedbackBox from './FeedbackBox'
+
+const styles = {
+ container: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ paddingTop: 0,
+ height: 'auto',
+ },
+ element: {
+ display: 'flex',
+ }
+};
+
+const muiTheme = getMuiTheme({
+ palette: {
+ primary1Color: '#ec7c2f', // Orange
+ accent1Color: '#2daae4', // Blue
+ }
+})
export default class ChatApp extends Component {
// At beginning there is no msg and the text-field is empty
constructor (props) {
super(props)
- this.state = {
- messages: [],
- text: '',
- socket: io.connect()
- }
-
- this.sendMessage = this.sendMessage.bind(this)
- this.join = this.join.bind(this)
- this.receiveMessage = this.receiveMessage.bind(this)
}
componentDidMount () {
- this.state.socket.on('join', this.join)
- this.state.socket.on('send-message', this.sendMessage)
- this.state.socket.on('receive-message', this.receiveMessage)
+ socket.on('join', this.join)
}
join () {
console.log('join')
- this.state.socket.emit('join', 'Hello world from client')
- }
-
- receiveMessage (msg) {
- console.log('receiveMessage: ', msg.text)
- this.state.messages.push(msg)
- this.setState({ messages: this.state.messages })
- }
-
- // When a message is submitted
- sendMessage (msg) {
- console.log('sendMessage: ', msg.text)
- this.state.socket.emit('new-message', msg)
+ socket.emit('join', 'Hello world from client')
}
render () {
return (
-
-
+
+ }
+ />
)
}
diff --git a/src/client/components/Message.js b/src/client/components/Message.js
index 3847690..405a2b4 100644
--- a/src/client/components/Message.js
+++ b/src/client/components/Message.js
@@ -1,11 +1,37 @@
-import React from 'react'
+import React from 'react';
+import Paper from 'material-ui/Paper';
+import FlatButton from 'material-ui/FlatButton';
+import ActionSchedule from 'material-ui/svg-icons/action/schedule';
+
+const styles = {
+ child: {
+ minHeight: 'auto',
+ width: '100%',
+
+ padding: 10,
+ margin: 5,
+ textAlign: 'left',
+ },
+ time: {
+ fontSize: '13px',
+ lineHeight: '13px',
+ height: '18px',
+ textAlign: 'left',
+ },
+}
export default class Message extends React.Component {
render () {
return (
-
- { this.props.text }
-
+
+ {this.props.text}
+ {this.props.time}}
+ disabled={true}
+ icon={}
+ />
+
)
}
}
diff --git a/src/client/components/MessageList.js b/src/client/components/MessageList.js
new file mode 100644
index 0000000..2a7e57a
--- /dev/null
+++ b/src/client/components/MessageList.js
@@ -0,0 +1,93 @@
+import React, { Component } from 'react'
+import socket from '../../server/socket'
+import Paper from 'material-ui/Paper';
+
+import Message from './Message'
+
+const styles = {
+
+ parent: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+
+ maxWidth: 500,
+ maxHeight: 400,
+ width: '100%',
+ height: '100%',
+
+ marginTop: 10,
+ padding: 15,
+
+ overflowY: 'auto',
+ minHeight: 0,
+ },
+
+ child: {
+ minHeight: 'auto',
+ width: '100%',
+
+ padding: 10,
+ margin: 5,
+ textAlign: 'left',
+ },
+};
+
+export default class MessageList extends Component {
+
+ constructor (props) {
+ super(props)
+ this.state = {
+ messages: []
+ }
+
+ this.receiveMessage = this.receiveMessage.bind(this)
+ this.lastTenMessages = this.lastTenMessages.bind(this)
+ }
+
+ componentDidMount () {
+ socket.on('receive-message', this.receiveMessage)
+ socket.on('last-ten-messages', this.lastTenMessages)
+ }
+
+ receiveMessage (msg) {
+ console.log('receiveMessage: ', msg.text)
+ // Copies the list
+ var messages = this.state.messages.slice()
+ // Adds the message
+ messages.push(msg)
+ this.setState({ messages: messages })
+ }
+
+ lastTenMessages (msgList) {
+ console.log('lastTenMessages: ', msgList)
+ this.setState({
+ messages: msgList
+ })
+ }
+
+ render () {
+ var list = this.state.messages.map((message, i) => {
+ console.log('Looping trought messages in messageList')
+
+ var time = message.time
+ // console.log('Date: ', date)
+ // var time = date.format('dd.MM.yyyy HH:mm')
+ // console.log('Time: ', time)
+ return (
+
+ )
+ })
+
+ return (
+
+ {list}
+
+ )
+ }
+
+}
diff --git a/src/client/index.html b/src/client/index.html
index edecb3d..2efec78 100644
--- a/src/client/index.html
+++ b/src/client/index.html
@@ -3,7 +3,14 @@
-
Viestinta
+
Viestintä
+
+
+
+
@@ -16,6 +23,21 @@
+
+
+
diff --git a/src/server/app.js b/src/server/app.js
index 99b6f32..8b14c67 100644
--- a/src/server/app.js
+++ b/src/server/app.js
@@ -23,6 +23,7 @@ const PDStrategy = require('passport-openid-connect').Strategy
// Initial Server Setup
// ///////////////////////////////////////////////////
+
nconf.argv()
.env('__')
.file({ file: path.resolve(__dirname, './etc/config.json') })
@@ -65,7 +66,7 @@ app.use(passport.initialize())
app.use(passport.session())
// ///////////////////////////////////////////////////
-// Main App
+// Routing
// ///////////////////////////////////////////////////
// URL-specifications
@@ -99,56 +100,110 @@ app.get('/connect', (req, res) => {
app.get('/login', passport.authenticate('passport-openid-connect', {'successReturnToOrRedirect': '/'}))
app.get('/callback', passport.authenticate('passport-openid-connect', {'callback': true, 'successReturnToOrRedirect': '/'}))
-server.listen(app.get('port'), (err) => {
- if (err) throw err
- console.log('Node app is running on port', app.get('port'))
+if (process.env.NODE_ENV !== "test"){
+ server.listen(app.get('port'), (err) => {
+ if (err) throw err
+ console.log('Node app is running on port', app.get('port'))
+ })
+}
+
+// ///////////////////////////////////////////////////
+// Setup for database
+// ///////////////////////////////////////////////////
+
+// TODO: Flytt til annen fil, eller gjør som del av user login/creation. Må bare kjøres før user objektet skal brukes.
+
+const db = require('./database/models/index')
+
+const user = db['User']
+const messageObj = db['Message']
+const feedbackObj = db['Feedback']
+
+const users = require('./database/controllers').users
+const messagesController = require('./database/controllers').messages
+const feedbacksController = require('./database/controllers').feedbacks
+
+// Create tables, and drop them if they allready exists (force: true)
+user.sync({force: true}).then(function () {
+ return user.create({
+ name: 'Pekka Foreleser'
+ })
+})
+
+messageObj.sync().then(function () {
+})
+
+feedbackObj.sync().then(function () {
+
})
// Create a connection
// var socket = io.connect('http://localhost::8000')
var io = require('socket.io')(server)
+// When a new user connects
+io.sockets.on('connect', function (socket) {
+ console.log('[app] connect')
+ // Get feedback status for last x min
+ feedbacksController.getLastIntervalNeg().then(function (resultNeg) {
+ feedbacksController.getLastIntervalPos().then(function (resultPos) {
+ socket.emit('update-feedback-interval', [resultNeg, resultPos])
+ })
+ })
+ // Get last 10 messages
+ messagesController.getLastTen().then(function (result) {
+ socket.emit('last-ten-messages', result.reverse())
+ })
+})
+
// Listen for connections
io.sockets.on('connection', function (socket) {
// Reports when it finds a connection
- console.log('Client connected')
+ console.log('[app] connection')
// Wait for a message from the client for 'join'
socket.on('join', function (data) {
- console.log('New client have joined')
+ console.log('[app] join')
socket.emit('messages', 'Hello from server')
})
// Wait for a message from the client for 'join'
socket.on('leave', function (data) {
- console.log('Client have left')
+ console.log('[app] left')
socket.emit('messages', 'Goodbye from server')
})
// When a new message is sendt from somebody
socket.on('new-message', function (msg) {
- console.log('Message in new-message in app.js: ' + msg.text)
+ console.log('[app] new-message: ' + msg)
+ messagesController.create(msg)
+
io.sockets.emit('receive-message', msg)
})
- socket.on('test', function () {
- console.log('Mounted')
+ // When somebody gives feedback
+ socket.on('new-feedback', function (feedback) {
+ console.log('[app] new-feedback: ' + feedback)
+ feedbacksController.create({
+ value: feedback
+ })
+ console.log('[app] new-feedback: after')
+ io.sockets.emit('receive-feedback', feedback)
})
-})
-
-app.use('/', express.static(path.resolve(__dirname, '../client/')))
-app.use(express.static(path.resolve(__dirname, '../static')))
-app.use('/components', express.static(path.resolve(__dirname, '../client/components')))
-app.use('/css', express.static(path.resolve(__dirname, '../static/css')))
-// SETUP FOR DATABASE
-// TODO: Flytt til annen fil, eller gjør som del av user login/creation. Må bare kjøres før user objektet skal brukes.
-
-const db = require('./database/models/index')
-
-const user = db['User']
-user.sync({force: true}).then(function () {
- return user.create({
- name: 'Pekka Foreleser'
+ // Called every x minuts
+ socket.on('update-feedback-interval', function () {
+ // Get feedback from database for past x minuts
+ feedbacksController.getLastIntervalNeg().then(function (resultNeg) {
+ feedbacksController.getLastIntervalPos().then(function (resultPos) {
+ io.sockets.emit('update-feedback-interval', [resultNeg, resultPos])
+ })
+ })
+ io.sockets.emit('update-feedback-interval')
})
})
+
+// To get static files
+app.use('/', express.static(path.join(__dirname, '../static')))
+app.use('/css', express.static(path.join(__dirname, '../static/css')))
+app.use('/icons', express.static(path.join(__dirname, '../static/icons')))
diff --git a/src/server/database.js b/src/server/database.js
new file mode 100644
index 0000000..8143f84
--- /dev/null
+++ b/src/server/database.js
@@ -0,0 +1,3 @@
+// ///////////////////////////////////////////////////
+// Setup for database
+// ///////////////////////////////////////////////////
diff --git a/src/server/database/config/config.js b/src/server/database/config/config.js
deleted file mode 100644
index f0c378e..0000000
--- a/src/server/database/config/config.js
+++ /dev/null
@@ -1,25 +0,0 @@
-
-module.exports = {
- development: {
- 'username': 'postgres',
- 'password': 'viestintacentos',
- 'database': 'viestintadb_dev',
- 'host': '0.0.0.0',
- 'dialect': 'postgres'
- },
- test: {
- 'username': 'postgres',
- 'password': 'viestintacentos',
- 'database': 'viestintadb_test',
- 'host': '0.0.0.0',
- 'dialect': 'postgres',
- 'logging': false
- },
- production: {
- 'username': 'root',
- 'password': null,
- 'database': 'database_production',
- 'host': '127.0.0.1',
- 'dialect': 'postgres'
- }
-}
diff --git a/src/server/database/controllers/feedbacks.js b/src/server/database/controllers/feedbacks.js
new file mode 100644
index 0000000..86e732f
--- /dev/null
+++ b/src/server/database/controllers/feedbacks.js
@@ -0,0 +1,86 @@
+const Feedback = require('../models/index').Feedback
+
+// Controller for Feedback model
+
+const MIN = 60000
+
+module.exports = {
+
+ // Create a new Feedback using model.create()
+ create (req) {
+ return Feedback.create({
+ value: req.value
+ })
+ .then(function (newFeedback) {
+ console.log('New feedback created with value', newFeedback.value)
+ })
+ },
+
+ // Edit an existing Feedback details using model.update()
+ update (req) {
+ Feedback.update(req.body, {
+ where: {
+ id: req.params.id
+ }
+ })
+ },
+
+ // For last 5 min
+ getLastIntervalNeg () {
+ return Feedback.count({
+ where: {
+ // TODO: just use createdAt?
+ time: {
+ // Set to 5 * MIN
+ $between: [new Date(new Date() - 5 * MIN), new Date()]
+ },
+
+ value: -1
+ }
+ })
+ },
+
+ // For last 5 min
+ getLastIntervalPos () {
+ return Feedback.count({
+ where: {
+ // TODO: just use createdAt?
+ time: {
+ // Set to 5 * MIN
+ $between: [new Date(new Date() - 5 * MIN), new Date()]
+ },
+
+ value: 1
+ }
+ })
+ },
+
+ getAll () {
+ return Feedback.findAll()
+ .then(function (result) {
+ console.log(result)
+ })
+ },
+
+ getAllLecture (req) {
+ Feedback.findAll({
+ where: {
+ // TODO: just use createdAt?
+ time: {
+ $between: [new Date(), new Date(new Date() - 120 * MIN)]
+ }
+ }
+ }).then(function (result) {
+ console.log(result.count)
+ })
+ },
+
+ // Delete an existing Feedback by the unique ID using model.destroy()
+ delete (req) {
+ Feedback.destroy({
+ where: {
+ id: req.params.id
+ }
+ })
+ }
+}
diff --git a/src/server/database/controllers/index.js b/src/server/database/controllers/index.js
new file mode 100644
index 0000000..857d56f
--- /dev/null
+++ b/src/server/database/controllers/index.js
@@ -0,0 +1,9 @@
+const users = require('./users')
+const feedbacks = require('./feedbacks')
+const messages = require('./messages')
+
+module.exports = {
+ users,
+ feedbacks,
+ messages
+}
diff --git a/src/server/database/controllers/messages.js b/src/server/database/controllers/messages.js
new file mode 100644
index 0000000..26ef5d4
--- /dev/null
+++ b/src/server/database/controllers/messages.js
@@ -0,0 +1,51 @@
+// Controller for Message model
+
+var Message = require('../models/index').Message
+
+module.exports = {
+
+ // Create a new Message using model.create()
+ create (req) {
+ return Message.create({
+ time: new Date(),
+ text: req.text
+ })
+ },
+
+ // Edit an existing Message details using model.update()
+ update (req) {
+ return Message.update(req.body, {
+ where: {
+ id: req.params.id
+ }
+ })
+ },
+
+ // Delete an existing Message by the unique ID using model.destroy()
+ delete (req) {
+ Message.destroy({
+ where: {
+ id: req.params.id
+ }
+ })
+ },
+
+ // Get last 10
+ getLastTen (req) {
+ return Message.all({
+ order: '"time" DESC',
+ limit: 10
+ })
+ },
+
+ // Retrive an existing Message by the unique ID
+ retrieve (req) {
+ return Message
+ .findById(req.params.messageId, {
+ include: [{
+ model: Message,
+ as: 'message'
+ }]
+ })
+ }
+}
diff --git a/src/server/database/models/feedback.js b/src/server/database/models/feedback.js
new file mode 100644
index 0000000..105d0f0
--- /dev/null
+++ b/src/server/database/models/feedback.js
@@ -0,0 +1,54 @@
+'use strict'
+
+// Feedback model
+
+module.exports = function (sequelize, DataTypes) {
+ // Definition of Feedback attributes
+
+ var Feedback = sequelize.define('Feedback', {
+ time: {
+ type: DataTypes.DATE,
+ defaultValue: new Date()
+ },
+ value: {
+ type: DataTypes.INTEGER,
+ defaultValue: 0
+ }
+ }, {
+
+ // Definition of methods related to the feedback object
+ // class-wide methods
+ classMethods: {
+
+ // Associations to other models
+ associate: function (models) {
+ // associations can be defined here
+ /*Feedback.belongsTo(models.User, {
+ onDelete: 'CASCADE',
+ foreignKey: {
+ allowNull: true
+ }
+ })*/
+ },
+
+ },
+ /*
+ getterMethods: {
+ getLastInterval: function() {
+ return Feedback.findAll({
+ where: {
+ // TODO: just use createdAt?
+ time: {
+ // Set to 5 * 60000
+ $between: [new Date(), new Date(newDate - 5 * 1000)]
+ }
+ }
+ }).then(function (result) {
+ console.log(result.count)
+ })
+ }
+ }
+ */
+ })
+ return Feedback
+}
diff --git a/src/server/database/models/index.js b/src/server/database/models/index.js
index f1d6c89..d420ead 100644
--- a/src/server/database/models/index.js
+++ b/src/server/database/models/index.js
@@ -1,12 +1,10 @@
'use strict'
-/*
+// ///////////////////////////////////////////////////
+// Setup for Sequalize connection
+// ///////////////////////////////////////////////////
-SETUP FOR SEQUELIZE CONNECTION
-
-exports db object with all relevant references to models
-
- */
+// exports db object with all relevant references to models
const fs = require('fs')
const path = require('path')
@@ -14,17 +12,17 @@ const Sequelize = require('sequelize')
const basename = path.basename(module.filename)
const env = process.env.NODE_ENV || 'development'
-const config = require(path.join(__dirname, '/../config/config.js'))[env]
-let db = {}
-var sequelize = new Sequelize(process.env['DATABASE_URL'])
+let db = {}
-/* if (config.use_env_variable) {
- var sequelize = new Sequelize(process.env[config.use_env_variable])
-} else {
- var sequelize = new Sequelize(config.database, config.username, config.password, config)
+if (process.env['DATABASE_URL']) {
+ var options = {}
+ if (process.env.NODE_ENV == "test"){
+ options = {logging: false}
+ }
+ var sequelize = new Sequelize(process.env['DATABASE_URL'], options)
}
-*/
+
fs
.readdirSync(__dirname)
.filter(function (file) {
@@ -52,12 +50,6 @@ sequelize
.catch(function (err) {
console.log('Unable to connect to the database:', err)
})
-/*
-function logExceptOnTest(string) {
- if (process.env.NODE_ENV !== 'test') {
- console.log(string);
- }
-}
-*/
+
module.exports = db
diff --git a/src/server/database/models/message.js b/src/server/database/models/message.js
new file mode 100644
index 0000000..197c42d
--- /dev/null
+++ b/src/server/database/models/message.js
@@ -0,0 +1,70 @@
+'use strict'
+
+// Message model
+
+module.exports = function (sequelize, DataTypes) {
+ // Definition of Message attributes
+ var Message = sequelize.define('Message', {
+ time: {
+ type: DataTypes.DATE,
+ defaultValue: new Date(),
+ get: function () {
+ var date = new Date(this.getDataValue('time'))
+ // var string = date.getDay() + '.' + date.getMonth() + '.' + date.getYear()
+
+ var hours = date.getHours()
+ if (date.getHours() < 10) {
+ hours = '0' + date.getHours()
+ }else{
+
+ }
+ var mins = date.getMinutes()
+ if (date.getMinutes() < 10) {
+ mins = '0' + date.getMinutes()
+ }
+ return hours + ":" + mins
+ }
+
+ },
+ text: {
+ type: DataTypes.STRING,
+ allowNull: false,
+ validate: {
+ min: {
+ args: [3],
+ msg: 'The message must be at least 3 charaters long'
+ }
+ }
+ },
+ // user: {
+ // }
+ // lecture: {}
+ votesUp: {
+ type: DataTypes.INTEGER,
+ defaultValue: 0
+ },
+ votesDown: {
+ type: DataTypes.INTEGER,
+ defaultValue: 0
+ }
+ }, {
+ classMethods: {
+
+ /*
+ assosiate: function(models) {
+ Message.belongsTo(models.User, {
+ onDelete: 'CASCADE',
+ foreignKey: {
+ allowNull: true
+ }
+ }),
+ // Add lecture
+ } */
+ },
+ instanceMethods: {
+
+ }
+ })
+
+ return Message
+}
diff --git a/src/server/etc/config.json b/src/server/etc/config.json
new file mode 100644
index 0000000..9a87b52
--- /dev/null
+++ b/src/server/etc/config.json
@@ -0,0 +1,13 @@
+
+{
+ "http": {
+ "port": 8000
+ },
+ "dataporten": {
+ "issuerHost": "https://auth.dataporten.no/",
+ "client_id": "",
+ "client_secret": "",
+ "redirect_uri": "http://localhost:8000/callback",
+ "scope": "groups longterm openid userid email profile userid-feide"
+ }
+}
\ No newline at end of file
diff --git a/src/server/routes/index.js b/src/server/routes/index.js
new file mode 100644
index 0000000..c83d36e
--- /dev/null
+++ b/src/server/routes/index.js
@@ -0,0 +1,43 @@
+ // URL-specifications
+
+const path = require('path')
+const passport = require('passport')
+
+const userController = require('./controllers').user
+const messagesController = require('./controllers').messages
+const feedbacskCOntroller = require('./controllers').feedbacks
+
+module.exports = (app) => {
+ // Go to index.html
+ app.get('/', (req, res) => { res.sendFile(path.resolve(__dirname, '../client/index.html')) })
+ app.get('/user', (req, res) => {
+ if (req.user) {
+ res.json({user: req.user})
+ } else {
+ res.status(404)
+ }
+ })
+
+ app.get('/connect', (req, res) => {
+ if (req.user) {
+ let userinfo = req.user.data
+ db['User'].findOrCreate({
+ where: {name: userinfo.name, sub: userinfo.sub, email: userinfo.email, email_verified: userinfo.email_verified}
+ })
+ .spread(function (user, created) {
+ console.log(user)
+ })
+ .catch((err) => {
+ console.error(err)
+ })
+ } else {
+ res.status(403)
+ }
+ })
+
+ app.get('/login', passport.authenticate('passport-openid-connect', {'successReturnToOrRedirect': '/'}))
+ app.get('/callback', passport.authenticate('passport-openid-connect', {'callback': true, 'successReturnToOrRedirect': '/'}))
+
+ // Related to database
+ app.post('/', messages)
+}
diff --git a/src/server/socket.js b/src/server/socket.js
new file mode 100644
index 0000000..d0d32a7
--- /dev/null
+++ b/src/server/socket.js
@@ -0,0 +1 @@
+export default io.connect()
diff --git a/src/static/css/style.css b/src/static/css/style.css
index 39cfb49..2d7fade 100644
--- a/src/static/css/style.css
+++ b/src/static/css/style.css
@@ -1,3 +1,24 @@
+html {
+ font-family: 'Roboto', sans-serif;
+ min-height: 100%;
+}
+
+body {
+ font-size: 13px;
+ line-height: 20px;
+
+ height: 100%;
+
+ background-repeat: no-repeat;
+ /* Maximum browser support */
+ background: -webkit-gradient(linear, center top, center bottom, from(#2DAAE4), to(#15729E));
+ background: -webkit-linear-gradient(#2DAAE4, #15729E);
+ background: -moz-linear-gradient(#2DAAE4, #15729E);
+ background: -o-linear-gradient(#2DAAE4, #15729E);
+ background: -ms-linear-gradient(#2DAAE4, #15729E);
+ background: linear-gradient(#2DAAE4, #15729E);
+}
+
#chat-app {
position: absolute;
margin: auto;
diff --git a/src/static/images/feide_100px_white.png b/src/static/images/feide_100px_white.png
new file mode 100644
index 0000000..e64a04f
Binary files /dev/null and b/src/static/images/feide_100px_white.png differ
diff --git a/src/static/images/feide_32px.png b/src/static/images/feide_32px.png
new file mode 100644
index 0000000..b994932
Binary files /dev/null and b/src/static/images/feide_32px.png differ
diff --git a/src/static/images/logo.png b/src/static/images/logo.png
new file mode 100644
index 0000000..f0041e1
Binary files /dev/null and b/src/static/images/logo.png differ
diff --git a/src/static/images/logo_shadow.png b/src/static/images/logo_shadow.png
new file mode 100644
index 0000000..3b40d40
Binary files /dev/null and b/src/static/images/logo_shadow.png differ
diff --git a/src/static/images/thumb.png b/src/static/images/thumb.png
new file mode 100644
index 0000000..5f03869
Binary files /dev/null and b/src/static/images/thumb.png differ
diff --git a/src/static/images/viestinta_illustration.png b/src/static/images/viestinta_illustration.png
new file mode 100644
index 0000000..f4a7bfc
Binary files /dev/null and b/src/static/images/viestinta_illustration.png differ
diff --git a/src/test/client/test.js b/src/test/client/socket_test.js
similarity index 100%
rename from src/test/client/test.js
rename to src/test/client/socket_test.js
diff --git a/src/test/init.js b/src/test/init.js
deleted file mode 100644
index 29c1881..0000000
--- a/src/test/init.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Created by jacob on 22.02.17.
- */
-
-console.log('Running tests...')
-process.env.NODE_ENV = 'test'
-// const app = require('../server/app')
-
-const Mocha = require('mocha')
-const fs = require('fs')
-const path = require('path')
-
-// Instantiate a Mocha instance.
-const mocha = new Mocha()
-
-const testDir = path.resolve(__dirname, './server')
-
-// Add each .js file to the mocha instance
-fs.readdirSync(testDir).filter(function (file) {
- // Only keep the .js files
- return file.substr(-3) === '.js'
-}).forEach(function (file) {
- mocha.addFile(
- path.join(testDir, file)
- )
-})
-
-// Run the tests.
-mocha.run(function (failures) {
- process.on('exit', function () {
- process.exit(failures) // exit with non-zero status if there were failures
- })
-})
diff --git a/src/test/server/database_test.js b/src/test/server/database_test.js
index aaacb77..8e756c9 100644
--- a/src/test/server/database_test.js
+++ b/src/test/server/database_test.js
@@ -1,91 +1,104 @@
-/**
- * Created by jacob on 20.02.17.
- */
-// Hack for pg issues
-var pg = require('pg')
-delete pg.native
-
-var User = require('./models/').User
-var assert = require('assert')
-var db = require('./models/index')
+const path = require('path')
+const User = require('../../server/database/models/').User
+const assert = require('assert')
+const db = require('../../server/database/models/index')
// Extra test frameworks:
// var should = require('should');
-// Defines alphabet to be used
+// Defines alphabets to be used
var s = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
+var n = '0123456789'
// Defines the function to generate the names to be used for the test
// Returns a random String with N length and based on the alphabet s
-
-var testNameGenerator = function (N) {
+var testStringGenerator = function (N, s) {
return Array(N).join().split(',').map(function () { return s.charAt(Math.floor(Math.random() * s.length)) }).join('')
}
-// Unique firstName and lastName for each test
-var firstName1 = testNameGenerator(10)
-var lastName1 = testNameGenerator(10)
-var firstName2 = testNameGenerator(10)
-var lastName2 = testNameGenerator(10)
-var firstName3 = testNameGenerator(10)
-var lastName3 = testNameGenerator(10)
-
-// Builds the User object with the corresponding name. Does not save the User objects to the database.
-var testUser1 = User.build({firstName: firstName1, lastName: lastName1})
-var testUser2 = User.build({firstName: firstName2, lastName: lastName2})
-var testUser3 = User.build({firstName: firstName3, lastName: lastName3})
-
-// Creates a tuple array for the test
-var testArray = [ [testUser1, firstName1 + ' ' + lastName1],
- [testUser2, firstName2 + ' ' + lastName2],
- [testUser3, firstName3 + ' ' + lastName3]
-]
-
-// Test for local user creation
-describe('Test suite: User build', function () {
- testArray.forEach(function (arrElement, callback) {
- describe('Build test for name: ' + arrElement[0].firstName + ' ' + arrElement[0].lastName, function () {
- it('Name to local User object is identical to name generated', function (done) {
- assert.equal(arrElement[0].firstName + ' ' + arrElement[0].lastName, arrElement[1])
- done()
- })
+
+/**TEST 1 USER MODEL**/
+
+// Unique firstName and lastName for the test
+var name = testStringGenerator(10, s)
+
+describe('Test suite 1: User model', function () {
+
+ /**
+ * @description Test for database user creation
+ */
+ describe('Database creation for name: ' + name, function () {
+ it('Name to User object in database is identical to name generated', function (done) {
+ // Access database and create the user if it doesn't exist
+ db['User']
+ .findOrCreate({
+ where: {name:name},
+ attributes: ['name']
+ })
+
+ // Then compare that user's variables to the variables given
+ .spread(function (user, created) {
+ assert.equal(name, user.name)
+ // Delete the user from the database
+ user.destroy()
+ done()
+ })
})
})
})
-// Get the User object from the database
-// Creates a tuple array for the test
-var test2Array = [
- [firstName1, lastName1],
- [firstName2, lastName2],
- [firstName3, lastName3]
-]
-
-// Test for database user creation
-describe('Test suite: User create', function () {
- // For each element in test2Array
- test2Array.forEach(function (arrElement, callback) {
- describe('Database test for name: ' + arrElement[0] + ' ' + arrElement[1], function () {
- it('Name to User object in database is identical to name generated', function (done) {
- // Access database and create the user if it doesn't exist
- db['User']
- .findOrCreate({
- where: {firstName: arrElement[0], lastName: arrElement[1]},
- attributes: ['id', 'firstName', 'lastName']
- })
-
- // Then compare that user's variables to the variables given
- .spread(function (user, created) {
- assert.equal(
- arrElement[0] + ' ' + arrElement[1],
- user.firstName + ' ' + user.lastName
- )
-
- // Delete the user from the database
- user.destroy()
- done()
- })
+
+/**TEST 2 MESSAGE MODEL**/
+
+var testString = testStringGenerator(30, s)
+
+var testTime = "07:04"
+var testDate = new Date()
+testDate.setHours(7)
+testDate.setMinutes(4)
+
+describe('Test suite 2: Message model', function () {
+
+ /**
+ * @description Test for create message
+ */
+ describe('Database creation for message: ' + testString, function () {
+ it('Text in Message object in database is identical to testString', function (done) {
+ // Access database and create the message if it doesn't exist
+ db['Message']
+ .findOrCreate({
+ where: {text: testString},
+ attributes: ['text']
+ })
+ // Then compare that messages's variables to the variables given
+
+ .spread(function (message, created) {
+ assert.equal(testString, message.text)
+ message.destroy()
+ done()
+ })
+ })
+ })
+ /**
+ * @description Test for message get time
+ */
+ describe('Get formatted time from message model: ' + testTime, function () {
+ it('Get function returns string identical to testTime', function (done) {
+ db['Message']
+ .findOrCreate({
+ where: {
+ text:testString,
+ time:testDate
+ },
+ attributes: ['time']
})
+ // Then compare that messages's variables to the variables given
+
+ .spread(function (message, created) {
+ assert.equal(testTime, message.get('time'))
+ message.destroy()
+ done()
+ })
})
})
})
diff --git a/wait-for-postgres.sh b/wait-for-postgres.sh
index 1fb9452..dd6aee1 100755
--- a/wait-for-postgres.sh
+++ b/wait-for-postgres.sh
@@ -6,6 +6,6 @@ set -e
host="$1"
shift
cmd="$@"
-sleep 7
+sleep 2
>&2 echo "Postgres is up - executing command"
exec $cmd
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
index e962b88..65ed5f1 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,7 +4,7 @@ module.exports = {
entry: './src/client/client.js',
output: {
- filename: './src/client/bundle.js' // path: path.resolve(__dirname, 'dist')
+ filename: './src/static/bundle.js' // path: path.resolve(__dirname, 'dist')
},
devServer: {