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