Compare commits
No commits in common. "gbianco/todo-backend-rewrite" and "master" have entirely different histories.
gbianco/to
...
master
18 changed files with 342 additions and 7809 deletions
2
todo-backend/.gitignore
vendored
2
todo-backend/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
# https://github.com/sclorg/s2i-nodejs-container
|
|
||||||
FROM registry.access.redhat.com/ubi8/nodejs-14
|
|
||||||
|
|
||||||
LABEL version="1.0"
|
|
||||||
LABEL description="To Do List application backend"
|
|
||||||
LABEL creationDate="2017-12-25"
|
|
||||||
LABEL updatedDate="2021-05-19"
|
|
||||||
|
|
||||||
USER 0
|
|
||||||
|
|
||||||
COPY . /opt/app-root/src
|
|
||||||
|
|
||||||
RUN cd /opt/app-root/src && \
|
|
||||||
npm install && \
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
ENV DATABASE_SVC=192.168.0.10
|
|
||||||
ENV DATABASE_PORT=3306
|
|
||||||
ENV DATABASE_PASSWORD=secret-pass
|
|
||||||
ENV DATABASE_INIT=true
|
|
||||||
ENV PORT=3000
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
USER 1001
|
|
||||||
|
|
||||||
CMD npm start
|
|
||||||
36
todo-backend/app.js
Normal file
36
todo-backend/app.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
var restify = require('restify');
|
||||||
|
|
||||||
|
var controller = require('./controllers/items');
|
||||||
|
var serverinfo = require('./controllers/serverinfo');
|
||||||
|
|
||||||
|
var db = require('./models/db');
|
||||||
|
var model = require('./models/items');
|
||||||
|
|
||||||
|
model.connect(db.params, function(err) {
|
||||||
|
if (err) throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
var server = restify.createServer()
|
||||||
|
.use(restify.fullResponse())
|
||||||
|
.use(restify.queryParser())
|
||||||
|
.use(restify.bodyParser())
|
||||||
|
.use(restify.CORS());;
|
||||||
|
|
||||||
|
controller.context(server, '/todo/api', model);
|
||||||
|
serverinfo.context(server, '/todo/api');
|
||||||
|
|
||||||
|
var port = process.env.PORT || 8080;
|
||||||
|
server.listen(port, function (err) {
|
||||||
|
if (err)
|
||||||
|
console.error(err);
|
||||||
|
else
|
||||||
|
console.log('App is ready at : ' + port);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
process.on('uncaughtException', function (err) {
|
||||||
|
console.error(JSON.parse(JSON.stringify(err, ['stack', 'message', 'inner'], 2)))
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import fs from "fs-extra";
|
|
||||||
import childProcess from "child_process";
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
// Remove current build
|
|
||||||
await remove("./dist/");
|
|
||||||
// Copy back-end files
|
|
||||||
await exec("tsc --build tsconfig.prod.json", "./");
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
function remove(loc: string): Promise<void> {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
return fs.remove(loc, (err) => {
|
|
||||||
return !!err ? rej(err) : res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function exec(cmd: string, loc: string): Promise<void> {
|
|
||||||
return new Promise((res, rej) => {
|
|
||||||
return childProcess.exec(cmd, { cwd: loc }, (err, stdout, stderr) => {
|
|
||||||
if (!!stdout) {
|
|
||||||
console.log(stdout);
|
|
||||||
}
|
|
||||||
if (!!stderr) {
|
|
||||||
console.warn(stderr);
|
|
||||||
}
|
|
||||||
return !!err ? rej(err) : res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
131
todo-backend/controllers/items.js
Normal file
131
todo-backend/controllers/items.js
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
var model = undefined;
|
||||||
|
|
||||||
|
exports.context = function(server, path, itemsModel) {
|
||||||
|
if (!server)
|
||||||
|
done('has to provide a restify server object');
|
||||||
|
|
||||||
|
var context = "/items";
|
||||||
|
if (path)
|
||||||
|
context = path + context;
|
||||||
|
|
||||||
|
server.get(context + '/', this.list);
|
||||||
|
server.get(context + '/:id', this.read);
|
||||||
|
server.get(context + '-count', this.count);
|
||||||
|
server.post(context + '/', this.save);
|
||||||
|
server.del(context + '/:id', this.destroy);
|
||||||
|
|
||||||
|
model = itemsModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.list = function(req, res, next) {
|
||||||
|
var page_no = req.query.page || 1;
|
||||||
|
var sortField = req.query.sortFields || "id";
|
||||||
|
var sortDirection = req.query.sortDirections || "asc";
|
||||||
|
|
||||||
|
model.listAll(page_no, sortField, sortDirection, function(err, items) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (items) {
|
||||||
|
model.countAll(function(err, n) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (n) {
|
||||||
|
var page = {
|
||||||
|
"currentPage" : page_no,
|
||||||
|
"list" : items,
|
||||||
|
"pageSize" : 10,
|
||||||
|
"sortDirections" : sortDirection,
|
||||||
|
"sortFields" : sortField,
|
||||||
|
"totalResults" : n
|
||||||
|
};
|
||||||
|
res.json(page);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.read = function(req, res, next) {
|
||||||
|
var key = req.params.id;
|
||||||
|
model.read(key, function(err, item) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (item) {
|
||||||
|
res.json(item);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.count = function(req, res, next) {
|
||||||
|
model.countAll(function(err, n) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var page = {
|
||||||
|
count: n
|
||||||
|
};
|
||||||
|
res.json(page)
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.save = function(req, res, next) {
|
||||||
|
if (req.params.id) {
|
||||||
|
model.update(req.params.id, req.params.description, req.params.done, function(err, item) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.json(item);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
model.create(req.params.description, req.params.done, function(err, item) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.json(item);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.destroy = function(req, res, next) {
|
||||||
|
if (req.params.id) {
|
||||||
|
model.destroy(req.params.id, function(err, item) {
|
||||||
|
if (err) {
|
||||||
|
res.send(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.json(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
29
todo-backend/controllers/serverinfo.js
Normal file
29
todo-backend/controllers/serverinfo.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
var os = require('os');
|
||||||
|
|
||||||
|
exports.context = function(server, path) {
|
||||||
|
if (!server)
|
||||||
|
done('has to provide a restify server object');
|
||||||
|
|
||||||
|
server.get(path + '/host', this.serverInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.serverInfo = function(req, res, next) {
|
||||||
|
var address;
|
||||||
|
var ifaces = os.networkInterfaces();
|
||||||
|
|
||||||
|
for (var dev in ifaces) {
|
||||||
|
var iface = ifaces[dev].filter(function(details) {
|
||||||
|
return details.family === 'IPv4' && details.internal === false;
|
||||||
|
});
|
||||||
|
if (iface.length > 0)
|
||||||
|
address = iface[0].address;
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply = {
|
||||||
|
ip: address,
|
||||||
|
hostname: os.hostname()
|
||||||
|
};
|
||||||
|
res.json(reply);
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
10
todo-backend/models/db.js
Normal file
10
todo-backend/models/db.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
module.exports.params = {
|
||||||
|
dbname: process.env.DATABASE_NAME,
|
||||||
|
username: process.env.DATABASE_USER,
|
||||||
|
password: process.env.DATABASE_PASSWORD,
|
||||||
|
params: {
|
||||||
|
host: process.env.DATABASE_SVC,
|
||||||
|
dialect: 'mysql',
|
||||||
|
}
|
||||||
|
};
|
||||||
127
todo-backend/models/items.js
Normal file
127
todo-backend/models/items.js
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
var Sequelize = require("sequelize");
|
||||||
|
|
||||||
|
var Item = undefined;
|
||||||
|
|
||||||
|
module.exports.connect = function(params, callback) {
|
||||||
|
var sequlz = new Sequelize(
|
||||||
|
params.dbname, params.username, params.password,
|
||||||
|
params.params);
|
||||||
|
Item = sequlz.define('Item', {
|
||||||
|
id: { type: Sequelize.BIGINT,
|
||||||
|
primaryKey: true, unique: true, allowNull: false,
|
||||||
|
autoIncrement: true },
|
||||||
|
description: { type: Sequelize.STRING,
|
||||||
|
allowNull: true },
|
||||||
|
done: { type: Sequelize.BOOLEAN,
|
||||||
|
allowNull: true }
|
||||||
|
}, {
|
||||||
|
timestamps: false,
|
||||||
|
freezeTableName: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.DATABASE_INIT == 'true') {
|
||||||
|
Item.sync({ force: true }).then(function() {
|
||||||
|
callback();
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.disconnect = function(callback) {
|
||||||
|
//XXX shouln'd to something to close or release the db connection?
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create = function(description, done, callback) {
|
||||||
|
Item.create({
|
||||||
|
//id: id,
|
||||||
|
description: description,
|
||||||
|
done: (done) ? true : false
|
||||||
|
}).then(function(item) {
|
||||||
|
callback(null, item);
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.update = function(key, description, done, callback) {
|
||||||
|
Item.find({ where:{ id: key } }).then(function(item) {
|
||||||
|
if (!item) {
|
||||||
|
callback(new Error("Nothing found for key " + key));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.updateAttributes({
|
||||||
|
description: description,
|
||||||
|
done: (done) ? true : false
|
||||||
|
}).then(function() {
|
||||||
|
callback(null, item);
|
||||||
|
}).error(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.read = function(key, callback) {
|
||||||
|
Item.find({ where:{ id: key } }).then(function(item) {
|
||||||
|
if (!item) {
|
||||||
|
callback(new Error("Nothing found for key " + key));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//XXX why recreating the item object?
|
||||||
|
callback(null, {
|
||||||
|
id: item.id,
|
||||||
|
description: item.description,
|
||||||
|
done: item.done
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.destroy = function(key, callback) {
|
||||||
|
Item.find({ where:{ id: key } }).then(function(item) {
|
||||||
|
if (!item) {
|
||||||
|
callback(new Error("Nothing found for " + key));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.destroy().then(function() {
|
||||||
|
callback(null, item);
|
||||||
|
}).error(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.countAll = function(callback) {
|
||||||
|
Item.findAll({
|
||||||
|
attributes: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'no_items']]
|
||||||
|
}).then(function(n) {
|
||||||
|
callback(null, n[0].get('no_items'));
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.listAll = function(page, sortField, sortDirection, callback) {
|
||||||
|
Item.findAll({ offset: 10 * (page - 1), limit: 10, order: [[sortField, sortDirection]] }).then(function(items) {
|
||||||
|
var theitems = [];
|
||||||
|
items.forEach(function(item) {
|
||||||
|
//XXX why recreating the item objects for theitems?
|
||||||
|
theitems.push({
|
||||||
|
id: item.id, description: item.description, done: item.done });
|
||||||
|
});
|
||||||
|
callback(null, theitems);
|
||||||
|
}).catch(function(err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
7461
todo-backend/package-lock.json
generated
7461
todo-backend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,92 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "todo-backend",
|
"name": "todo-backend",
|
||||||
"version": "2.0.0",
|
"description": "multi-container version of the todoapp",
|
||||||
|
"version": "0.0.2",
|
||||||
|
"private": true,
|
||||||
|
"author": "Red Hat Training",
|
||||||
|
"license": "ASL",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "./node_modules/.bin/ts-node build.ts",
|
"start": "node app.js"
|
||||||
"lint": "eslint . --ext .ts",
|
|
||||||
"start": "node -r module-alias/register ./dist",
|
|
||||||
"start:dev": "nodemon"
|
|
||||||
},
|
},
|
||||||
"nodemonConfig": {
|
|
||||||
"watch": [
|
|
||||||
"src"
|
|
||||||
],
|
|
||||||
"ext": "ts, html",
|
|
||||||
"ignore": [
|
|
||||||
"src/public"
|
|
||||||
],
|
|
||||||
"exec": "./node_modules/.bin/ts-node -r tsconfig-paths/register ./src"
|
|
||||||
},
|
|
||||||
"_moduleAliases": {
|
|
||||||
"@daos": "dist/daos",
|
|
||||||
"@entities": "dist/entities",
|
|
||||||
"@shared": "dist/shared",
|
|
||||||
"@server": "dist/Server"
|
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
|
||||||
],
|
|
||||||
"parserOptions": {
|
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"max-len": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"code": 100
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-extra-boolean-cast": 0,
|
|
||||||
"@typescript-eslint/restrict-plus-operands": 0,
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
|
||||||
"@typescript-eslint/no-explicit-any": 0,
|
|
||||||
"@typescript-eslint/no-floating-promises": 0,
|
|
||||||
"@typescript-eslint/no-unsafe-member-access": 0,
|
|
||||||
"@typescript-eslint/no-unsafe-assignment": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"eslintIgnore": [
|
|
||||||
"src/public/",
|
|
||||||
"build.ts"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"command-line-args": "^5.1.1",
|
"restify": "4.3.0",
|
||||||
"cookie-parser": "^1.4.5",
|
"sequelize": "3.14.2",
|
||||||
"cors": "^2.8.5",
|
"mysql": "2.9.0"
|
||||||
"express": "^4.17.1",
|
|
||||||
"express-async-errors": "^3.1.1",
|
|
||||||
"jsonfile": "^6.1.0",
|
|
||||||
"module-alias": "^2.2.2",
|
|
||||||
"mysql2": "^2.2.5",
|
|
||||||
"sequelize": "^6.6.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/command-line-args": "^5.0.0",
|
|
||||||
"@types/cookie-parser": "^1.4.2",
|
|
||||||
"@types/cors": "^2.8.10",
|
|
||||||
"@types/express": "^4.17.11",
|
|
||||||
"@types/find": "^0.2.1",
|
|
||||||
"@types/fs-extra": "^9.0.11",
|
|
||||||
"@types/jasmine": "^3.6.10",
|
|
||||||
"@types/jsonfile": "^6.0.0",
|
|
||||||
"@types/node": "^15.0.1",
|
|
||||||
"@types/supertest": "^2.0.11",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
|
||||||
"@typescript-eslint/parser": "^4.22.0",
|
|
||||||
"eslint": "^7.25.0",
|
|
||||||
"find": "^0.3.0",
|
|
||||||
"fs-extra": "^9.1.0",
|
|
||||||
"nodemon": "^2.0.7",
|
|
||||||
"supertest": "^6.1.3",
|
|
||||||
"ts-node": "^9.1.1",
|
|
||||||
"tsconfig-paths": "^3.9.0",
|
|
||||||
"typescript": "^4.2.4"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import cookieParser from "cookie-parser";
|
|
||||||
import express, { Request, Response } from "express";
|
|
||||||
import "express-async-errors";
|
|
||||||
import cors from "cors";
|
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
|
|
||||||
import BaseRouter from "./routes";
|
|
||||||
import { dbConnectionOptions } from "./entities/db";
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
// DO NOT USE in production as this allows any site to use our backend
|
|
||||||
// you will need to configure cors separately for your application
|
|
||||||
app.use(cors());
|
|
||||||
|
|
||||||
app.use(express.json());
|
|
||||||
app.use(express.urlencoded({ extended: true }));
|
|
||||||
app.use(cookieParser());
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConnectionOptions);
|
|
||||||
sequelize
|
|
||||||
.authenticate()
|
|
||||||
.then(() => {
|
|
||||||
console.log("Connection has been established successfully.");
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("Unable to connect to the database:", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add APIs
|
|
||||||
app.use("/api", BaseRouter);
|
|
||||||
|
|
||||||
// Print API errors
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
app.use((err: Error, req: Request, res: Response) => {
|
|
||||||
console.error(err, true);
|
|
||||||
return res.status(500).json({
|
|
||||||
error: err.message,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Export express instance
|
|
||||||
export default app;
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
import { Sequelize, DataTypes, Model, Optional } from "sequelize";
|
|
||||||
import { dbConnectionOptions } from "./db";
|
|
||||||
|
|
||||||
export interface TodoItemAttributes {
|
|
||||||
id: number;
|
|
||||||
description: string;
|
|
||||||
done: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
type TodoItemCreationAttributes = Optional<TodoItemAttributes, "id">;
|
|
||||||
|
|
||||||
interface TodoItemInstance
|
|
||||||
extends Model<TodoItemAttributes, TodoItemCreationAttributes> {
|
|
||||||
createdAt: Date;
|
|
||||||
updatedAt: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConnectionOptions);
|
|
||||||
|
|
||||||
export const TodoItem = sequelize.define<TodoItemInstance>(
|
|
||||||
"TodoItem",
|
|
||||||
{
|
|
||||||
id: {
|
|
||||||
type: DataTypes.BIGINT,
|
|
||||||
primaryKey: true,
|
|
||||||
unique: true,
|
|
||||||
allowNull: false,
|
|
||||||
autoIncrement: true,
|
|
||||||
},
|
|
||||||
description: { type: DataTypes.STRING, allowNull: true },
|
|
||||||
done: { type: DataTypes.BOOLEAN, allowNull: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timestamps: false,
|
|
||||||
freezeTableName: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// (re-)creates table (NOT database)
|
|
||||||
if (process.env.DATABASE_INIT === "true") {
|
|
||||||
TodoItem.sync({ force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createTodoItem(todoItem: TodoItemCreationAttributes) {
|
|
||||||
return TodoItem.create(todoItem).then((item) => item.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteTodoItem(id: number) {
|
|
||||||
return TodoItem.destroy({ where: { id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listAllTodoItems(): Promise<TodoItemAttributes[]> {
|
|
||||||
return TodoItem.findAll({}).then((items) => items.map((i) => i.get()));
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { Options } from "sequelize";
|
|
||||||
|
|
||||||
const {
|
|
||||||
DATABASE_NAME,
|
|
||||||
DATABASE_USER,
|
|
||||||
DATABASE_PASSWORD,
|
|
||||||
DATABASE_SVC,
|
|
||||||
DATABASE_PORT,
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
export const dbConnectionOptions: Options = {
|
|
||||||
database: DATABASE_NAME ?? "todo",
|
|
||||||
username: DATABASE_USER ?? "root",
|
|
||||||
password: DATABASE_PASSWORD ?? "",
|
|
||||||
host: DATABASE_SVC ?? "localhost",
|
|
||||||
port: Number(DATABASE_PORT) ?? 3306,
|
|
||||||
dialect: "mysql",
|
|
||||||
};
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import app from "@server";
|
|
||||||
|
|
||||||
// Start the server
|
|
||||||
const port = Number(process.env.PORT || 8080);
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log("Express server started on port: " + port);
|
|
||||||
});
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import {
|
|
||||||
createTodoItem,
|
|
||||||
deleteTodoItem,
|
|
||||||
listAllTodoItems,
|
|
||||||
} from "@entities/Item";
|
|
||||||
import { Request, Response } from "express";
|
|
||||||
|
|
||||||
export function handleCreate(req: Request, res: Response) {
|
|
||||||
const { description, done } = req.body;
|
|
||||||
|
|
||||||
// NOTE production applications should use a validation framework
|
|
||||||
if (typeof description !== "string" || typeof done !== "boolean") {
|
|
||||||
res
|
|
||||||
.status(400)
|
|
||||||
.send("required parameters were either missing or the wrong type");
|
|
||||||
} else {
|
|
||||||
createTodoItem({ description, done }).then((item) => res.json(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleReadAll(req: Request, res: Response) {
|
|
||||||
listAllTodoItems().then((items) => res.json(items));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleDelete(req: Request, res: Response) {
|
|
||||||
deleteTodoItem(Number(req.params.id)).then(() => res.json({}));
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
import { handleCreate, handleReadAll, handleDelete } from "./Items";
|
|
||||||
|
|
||||||
// Item routes
|
|
||||||
const itemRouter = Router();
|
|
||||||
itemRouter.get("/", handleReadAll);
|
|
||||||
itemRouter.post("/", handleCreate);
|
|
||||||
itemRouter.delete("/:id", handleDelete);
|
|
||||||
|
|
||||||
// Export the base-router
|
|
||||||
const baseRouter = Router();
|
|
||||||
baseRouter.use("/items", itemRouter);
|
|
||||||
export default baseRouter;
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es6",
|
|
||||||
"module": "commonjs",
|
|
||||||
"checkJs": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"removeComments": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"alwaysStrict": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"baseUrl": "./",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"paths": {
|
|
||||||
"@daos/*": ["src/daos/*"],
|
|
||||||
"@entities/*": ["src/entities/*"],
|
|
||||||
"@shared/*": ["src/shared/*"],
|
|
||||||
"@server": ["src/Server"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["src/**/*.ts", "spec/**/*.ts"],
|
|
||||||
"exclude": ["src/public/"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"sourceMap": false
|
|
||||||
},
|
|
||||||
"exclude": [
|
|
||||||
"spec",
|
|
||||||
"src/**/*.mock.ts",
|
|
||||||
"src/public/"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue