Initial commit
parent
990dd9d413
commit
0559058dc2
|
@ -0,0 +1 @@
|
||||||
|
{"rules": {"indent": ["error", "tab"], "no-tabs": "off", "react/jsx-indent": ["error", "tab"]}, "extends": "airbnb", "env": {"browser": true, "node": true}}
|
|
@ -0,0 +1,81 @@
|
||||||
|
module.exports = function (grunt) {
|
||||||
|
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
webpack: {
|
||||||
|
app: {
|
||||||
|
entry: './app/index.jsx',
|
||||||
|
output: {
|
||||||
|
filename: 'bundle.js',
|
||||||
|
path: './dist/app/'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
query: {
|
||||||
|
sourceMap: true,
|
||||||
|
presets: ['env', 'react']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
app: {
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
cwd: './app/',
|
||||||
|
src: ['index.html'],
|
||||||
|
dest: './dist/app/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
cwd: './app/',
|
||||||
|
src: ['assets/**'],
|
||||||
|
dest: './dist/app/assets/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
babel: {
|
||||||
|
options: {
|
||||||
|
sourceMap: true,
|
||||||
|
presets: [
|
||||||
|
['env', {
|
||||||
|
targets: {
|
||||||
|
node: 'current'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
cwd: './server/',
|
||||||
|
src: ['*.js'],
|
||||||
|
dest: './dist/server/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eslint: {
|
||||||
|
app: ['./app/*.js*'],
|
||||||
|
server: ['./server/*.js']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.loadNpmTasks('grunt-webpack');
|
||||||
|
grunt.loadNpmTasks('grunt-babel');
|
||||||
|
grunt.loadNpmTasks('grunt-eslint');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||||
|
|
||||||
|
grunt.registerTask('all', ['eslint', 'webpack', 'copy', 'babel']);
|
||||||
|
grunt.registerTask('default', ['all']);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Chronos</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script src="bundle.js"></script>
|
||||||
|
</body>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<h1>Hello, world!</h1>,
|
||||||
|
document.getElementById('root'),
|
||||||
|
);
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"name": "Chronos",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "A school event planner and timetable",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node dist/server/index.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/ambrosechua/chronos.git"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "proprietary",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/ambrosechua/chronos/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/ambrosechua/chronos#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-loader": "^6.3.2",
|
||||||
|
"babel-preset-env": "^1.1.10",
|
||||||
|
"babel-preset-react": "^6.23.0",
|
||||||
|
"eslint": "^3.16.1",
|
||||||
|
"eslint-config-airbnb": "^14.1.0",
|
||||||
|
"eslint-plugin-import": "^2.2.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^4.0.0",
|
||||||
|
"eslint-plugin-react": "^6.10.0",
|
||||||
|
"grunt": "^1.0.1",
|
||||||
|
"grunt-babel": "^6.0.0",
|
||||||
|
"grunt-contrib-copy": "^1.0.0",
|
||||||
|
"grunt-eslint": "^19.0.0",
|
||||||
|
"grunt-webpack": "^2.0.1",
|
||||||
|
"webpack": "^2.2.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.14.1",
|
||||||
|
"mysql": "^2.13.0",
|
||||||
|
"react": "^15.4.2",
|
||||||
|
"react-dom": "^15.4.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Router from 'express';
|
||||||
|
|
||||||
|
export default class API {
|
||||||
|
constructor() {
|
||||||
|
this.router = Router({
|
||||||
|
strict: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.router.get('/', (req, res) => {
|
||||||
|
res.end('API v1');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
import mysql from 'mysql';
|
||||||
|
import { fatal, getVersion } from './utils';
|
||||||
|
|
||||||
|
const DATABASE = 'chronos';
|
||||||
|
|
||||||
|
export default class Database {
|
||||||
|
constructor(options) {
|
||||||
|
this.connection = mysql.createConnection(options);
|
||||||
|
this.connection.connect();
|
||||||
|
|
||||||
|
this.checkAndMigrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
query(query, values) {
|
||||||
|
console.log('QUERY:', query);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.connection.query(query, values, (err, results, fields) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(results, fields);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAndMigrate() {
|
||||||
|
this.query(`CREATE DATABASE IF NOT EXISTS ${DATABASE}`, [])
|
||||||
|
.then(() => this.query(`USE ${DATABASE}`, []))
|
||||||
|
.then(() => this.query('SELECT value FROM options WHERE option = "version"', (err, result) => {
|
||||||
|
if (err || result === undefined || getVersion() !== result[0].value) {
|
||||||
|
return this.migrate(result).catch(e => fatal(e));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}))
|
||||||
|
.catch(err => fatal(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
async migrate(oldVersion) {
|
||||||
|
if (!oldVersion) {
|
||||||
|
// create tables
|
||||||
|
const tables = [
|
||||||
|
`CREATE TABLE options (
|
||||||
|
option VARCHAR(12) NOT NULL,
|
||||||
|
value VARCHAR(64) NOT NULL,
|
||||||
|
PRIMARY KEY (option)
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE school (
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
domain VARCHAR(32),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE auth (
|
||||||
|
school INT NOT NULL,
|
||||||
|
id INT NOT NULL,
|
||||||
|
type CHAR(3) NOT NULL,
|
||||||
|
oid_meta VARCHAR(128),
|
||||||
|
oid_cid VARCHAR(64),
|
||||||
|
oid_csecret VARCHAR(64),
|
||||||
|
PRIMARY KEY (school, id),
|
||||||
|
FOREIGN KEY (school) REFERENCES school(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE holiday (
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
start DATETIME NOT NULL,
|
||||||
|
end DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE observes (
|
||||||
|
school INT NOT NULL,
|
||||||
|
holiday INT NOT NULL,
|
||||||
|
FOREIGN KEY (school) REFERENCES school(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (holiday) REFERENCES holiday(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE user (
|
||||||
|
school INT NOT NULL,
|
||||||
|
id INT AUTO_INCREMENT NOT NULL,
|
||||||
|
name VARCHAR(64),
|
||||||
|
email VARCHAR(64),
|
||||||
|
oid_id VARCHAR(64),
|
||||||
|
pwd_hash VARCHAR(64),
|
||||||
|
role CHAR(3),
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (school) REFERENCES school(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE group_ (
|
||||||
|
id INT AUTO_INCREMENT NOT NULL,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
type CHAR(3),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE group_mentor (
|
||||||
|
id INT NOT NULL,
|
||||||
|
level TINYINT NOT NULL,
|
||||||
|
year YEAR NOT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (id) REFERENCES group_(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE member (
|
||||||
|
user INT NOT NULL,
|
||||||
|
group_ INT NOT NULL,
|
||||||
|
FOREIGN KEY (user) REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (group_) REFERENCES group_(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE event_once (
|
||||||
|
group_ INT NOT NULL,
|
||||||
|
id INT AUTO_INCREMENT NOT NULL,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
start DATETIME NOT NULL,
|
||||||
|
end DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (group_) REFERENCES group_(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE attachment (
|
||||||
|
event_once INT NOT NULL,
|
||||||
|
id INT NOT NULL,
|
||||||
|
PRIMARY KEY (event_once, id),
|
||||||
|
FOREIGN KEY (event_once) REFERENCES event_once(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE event_weekly (
|
||||||
|
group_ INT NOT NULL,
|
||||||
|
id INT AUTO_INCREMENT NOT NULL,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
day TINYINT NOT NULL,
|
||||||
|
starttime TIME NOT NULL,
|
||||||
|
endtime TIME NOT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (group_) REFERENCES group_(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
`CREATE TABLE ignored (
|
||||||
|
user INT NOT NULL,
|
||||||
|
event_weekly INT NOT NULL,
|
||||||
|
FOREIGN KEY (user) REFERENCES user(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY (event_weekly) REFERENCES event_weekly(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
)`,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < tables.length; i += 1) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await this.query(tables[i], []);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.query(`
|
||||||
|
INSERT INTO options (option, value)
|
||||||
|
VALUES ('version', '${getVersion()}')
|
||||||
|
`);
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// for now
|
||||||
|
return this.query(`DROP DATABASE ${DATABASE}`, [])
|
||||||
|
.then(() => this.checkAndMigrate());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import path from 'path';
|
||||||
|
import express from 'express';
|
||||||
|
import Database from './database';
|
||||||
|
import API from './api';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const database = new Database({
|
||||||
|
host: 'localhost',
|
||||||
|
user: 'root',
|
||||||
|
password: '',
|
||||||
|
});
|
||||||
|
const api = new API(database);
|
||||||
|
|
||||||
|
app.use('/', express.static(path.join(__dirname, '..', 'app')));
|
||||||
|
app.use('/api/v1', api.router);
|
||||||
|
|
||||||
|
app.listen(8080);
|
|
@ -0,0 +1,13 @@
|
||||||
|
const getVersion = () => {
|
||||||
|
if (process.env.npm_package_version) {
|
||||||
|
return process.env.npm_package_version;
|
||||||
|
}
|
||||||
|
throw new Error('Unable to obtain running version');
|
||||||
|
};
|
||||||
|
|
||||||
|
const fatal = (e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getVersion, fatal };
|
Loading…
Reference in New Issue