diff --git a/migrations/20181217140321-notifications-add-table.js b/migrations/20181217140321-notifications-add-table.js new file mode 100644 index 000000000..0c2476fe2 --- /dev/null +++ b/migrations/20181217140321-notifications-add-table.js @@ -0,0 +1,25 @@ +'use strict'; + +exports.up = function(db, callback) { + var cmd = 'CREATE TABLE notifications(' + + 'id int NOT NULL AUTO_INCREMENT,' + + 'userId VARCHAR(128) NOT NULL,' + + 'title VARCHAR(512) NOT NULL,' + + 'message TEXT,' + + 'action VARCHAR(512) NOT NULL,' + + 'acknowledged BOOLEAN DEFAULT false,' + + 'creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,' + + 'PRIMARY KEY (id))'; + + db.runSql(cmd, function (error) { + if (error) console.error(error); + callback(error); + }); +}; + +exports.down = function(db, callback) { + db.runSql('DROP TABLE notifications', function (error) { + if (error) console.error(error); + callback(error); + }); +}; diff --git a/migrations/schema.sql b/migrations/schema.sql index 61bc25f2e..58f0d8db4 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -212,5 +212,16 @@ CREATE TABLE IF NOT EXISTS tasks( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id)); - CHARACTER SET utf8 COLLATE utf8_bin; +CREATE TABLE IF NOT EXISTS notifications( + id int NOT NULL AUTO_INCREMENT, + userId VARCHAR(128) NOT NULL, + title VARCHAR(512) NOT NULL, + message TEXT, + action VARCHAR(512) NOT NULL, + acknowledged BOOLEAN DEFAULT false, + creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) +); + +CHARACTER SET utf8 COLLATE utf8_bin; diff --git a/src/notificationdb.js b/src/notificationdb.js new file mode 100644 index 000000000..b4d012a13 --- /dev/null +++ b/src/notificationdb.js @@ -0,0 +1,107 @@ +'use strict'; + +exports = module.exports = { + get: get, + add: add, + update: update, + del: del, + listByUserIdPaged: listByUserIdPaged +}; + +let assert = require('assert'), + database = require('./database.js'), + DatabaseError = require('./databaseerror'); + +const NOTIFICATION_FIELDS = [ 'id', 'userId', 'title', 'message', 'action', 'creationTime', 'acknowledged' ]; + +function postProcess(result) { + assert.strictEqual(typeof result, 'object'); + result.id = String(result.id); + + // convert to boolean + result.acknowledged = !!result.acknowledged; +} + +function add(notification, callback) { + assert.strictEqual(typeof notification, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const query = 'INSERT INTO notifications (userId, title, message, action) VALUES (?, ?, ?, ?)'; + const args = [ notification.userId, notification.title, notification.message, notification.action ]; + + database.query(query, args, function (error, result) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + + callback(null, String(result.insertId)); + }); +} + +function update(id, data, callback) { + assert.strictEqual(typeof id, 'string'); + assert.strictEqual(typeof data, 'object'); + assert.strictEqual(typeof callback, 'function'); + + let args = [ ]; + let fields = [ ]; + for (let k in data) { + fields.push(k + ' = ?'); + args.push(data[k]); + } + args.push(id); + + database.query('UPDATE notifications SET ' + fields.join(', ') + ' WHERE id = ?', args, function (error, result) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (result.affectedRows !== 1) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + + return callback(null); + }); +} + +function get(id, callback) { + assert.strictEqual(typeof id, 'string'); + assert.strictEqual(typeof callback, 'function'); + + database.query('SELECT ' + NOTIFICATION_FIELDS + ' FROM notifications WHERE id = ?', [ id ], function (error, result) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + + postProcess(result[0]); + + callback(null, result[0]); + }); +} + +function del(id, callback) { + assert.strictEqual(typeof id, 'string'); + assert.strictEqual(typeof callback, 'function'); + + database.query('DELETE FROM notifications WHERE id = ?', [ id ], function (error, result) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (result.affectedRows !== 1) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + + callback(null); + }); +} + +function listByUserIdPaged(userId, page, perPage, callback) { + assert.strictEqual(typeof userId, 'string'); + assert.strictEqual(typeof page, 'number'); + assert.strictEqual(typeof perPage, 'number'); + assert.strictEqual(typeof callback, 'function'); + + var data = [ userId ]; + var query = 'SELECT ' + NOTIFICATION_FIELDS + ' FROM notifications WHERE userId=?'; + + query += ' ORDER BY creationTime DESC LIMIT ?,?'; + + data.push((page-1)*perPage); + data.push(perPage); + + database.query(query, data, function (error, results) { + if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + + results.forEach(postProcess); + + callback(null, results); + }); +}