diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4ee6e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +bower_components/ +node_modules/ \ No newline at end of file diff --git a/package.json b/package.json index 72e4955..42dc4f2 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,6 @@ }, "dependencies": { "express": "3.3.4", - "jade": "*", - "ejs": "~0.8.4", "lodash": "~1.3.1", "when": "~2.3.0", "firebase": "~0.6.3" diff --git a/schema/schema.json b/schema/schema.json new file mode 100644 index 0000000..1f8c1ea --- /dev/null +++ b/schema/schema.json @@ -0,0 +1,137 @@ +{ + "users" : { + "joebloggs" : { + "name" : "Joe", + "surname" : "Bloggs", + "reputation" : 0, + "level" : 1, + "twitter" : "@joeblog04", + "email" : "joe@bloggs.za", + "bio" : "A normal dude", + "picture" : "09.jpg" + }, + "bernardone" : { + "name" : "Bernardo", + "surname" : "Bertolucci", + "screen_name" : "bernardone", + "reputation" : 4, + "level" : 1, + "twitter" : "@bernardbert", + "email" : "bbrb@gmail.com", + "bio" : "Professional reporter", + "picture" : "bbernardone.jpg" + } + }, + "updates" : { + "ufo_sighting" : { + "title" : "UFO sighting", + "reporter" : 1, + "description" : "Saw a flying saucepan earlier today", + "time" : 1378743848616, + "timezone" : "BST", + "location" : [51.505300, -0.165477], + "media" : { + "media_video" : [], + "media_pictures" : [], + "media_audio" : [], + "media_links" : [] + }, + "tags" : ["awesome", "UFO"], + "importance" : 1, + "editable" : false, + "upvotes" : 2, + "downvotes" : 2 + }, + "another_ufo_sighting" : { + "title" : "Another UFO sighting", + "reporter" : 1, + "description" : "Really really there was a flying saucepan, ain't kiddin'", + "time" : 1378743849619, + "timezone" : "BST", + "location" : [51.505309, -0.165487], + "media" : { + "media_video" : [], + "media_pictures" : [], + "media_audio" : [], + "media_links" : [] + }, + "tags" : ["awesome", "UFO"], + "importance" : 0, + "editable" : false, + "upvotes" : 0, + "downvotes" : 0 + }, + "strange_light_in_the_sky" : { + "title" : "Strange light in the sky", + "reporter" : 3, + "description" : "There is an UFO hovering over London", + "time" : 1378743848821, + "timezone" : "BST", + "location" : [51.505955, -0.14863], + "media" : { + "media_video" : [], + "media_pictures" : [], + "media_audio" : [], + "media_links" : [] + }, + "tags" : ["strange"], + "importance" : 1, + "editable" : false, + "upvotes" : 2, + "downvotes" : 2 + }, + "topshop_sale" : { + "title" : "Topshop sale", + "reporter" : 1, + "description" : "Oxford Circus's topshop has announced a sale", + "time" : 1378743848616, + "timezone" : "BST", + "location" : [51.505300, -0.165477], + "media" : { + "media_video" : [], + "media_pictures" : [], + "media_audio" : [], + "media_links" : [] + }, + "tags" : ["awesome"], + "importance" : 1, + "editable" : false, + "upvotes" : 0, + "downvotes" : 0 + } + }, + "reports" : { + "london_ufo_sightings_of_sept_2013" : { + "name" : "London ufo sightings of sept 2013", + "description" : "A spate of ufo sightings", + "reporter" : "joebloggs", + "updates" : [2,5,10], + "time_start" : 1378743848616, + "time_end" : null, + "timezone" : "BST", + "location" : [51.505300, -0.165477], + "tags" : ["awesome"], + "importance" : 2, + "upvotes" : 3, + "downvotes" : 2, + "editable" : true, + "category" : "custom" + }, + "topshop_sale" : { + "name" : "Topshop sale", + "description" : "Big sale in town", + "reporter" : "joebloggs", + "updates" : [15], + "time_start" : 1433804400000, + "time_end" : 1381359600000, + "timezone" : "BST", + "location" : [51.515366, -0.141344], + "tags" : ["awesome"], + "importance" : 2, + "upvotes" : 3, + "downvotes" : 2, + "editable" : true, + "category" : "around town" + } + } +} \ No newline at end of file diff --git a/src/Report.js b/src/Report.js index bae027f..e93208d 100644 --- a/src/Report.js +++ b/src/Report.js @@ -8,17 +8,23 @@ var Model = require('./util/Model'); */ module.exports = Model.extend({ + name : 'report', + defaults: { - title: '', - description: '', - location: [0, 0], - timeFrom: 0, - timeTo: Infinity, - timeExceptions: [], - updates: [ - // { contentType, content, ... } - ], - tags: [] + "name" : "Unnamed event", + "description" : "", + "reporter" : 1, + "updates" : [], + "time_start" : 1433804400000, + "time_end" : 1381359600000, + "timezone" : "GMT", + "location" : [0,0], + "tags" : [], + "importance" : 0, + "upvotes" : 0, + "downvotes" : 0, + "editable" : true, + "category" : "" }, init: function() { diff --git a/src/User.js b/src/User.js index ba150f7..a7c6db0 100644 --- a/src/User.js +++ b/src/User.js @@ -2,19 +2,26 @@ var Model = require('./util/Model'); + /** * 1st Class Entity under Yip * A User */ var User = Model.extend({ + name: 'user', + ref: 'https://{firebaseName}.firebaseio.com/users/{id}', defaults: { - id: null, - name: '', - email: '', - twitter: '' + "name" : "", + "surname" : "", + "reputation" : 0, + "level" : 1, + "twitter" : "", + "email" : "", + "bio" : "", + "picture" : "" }, init: function() { diff --git a/src/util/Model.js b/src/util/Model.js index d879d78..49fea36 100644 --- a/src/util/Model.js +++ b/src/util/Model.js @@ -3,6 +3,7 @@ var _ = require('lodash'); var when = require('when'); var Firebase = require('firebase'); +var Validation = require('./Validation'); var hasOwn = {}.hasOwnProperty; var toString = {}.toString; @@ -13,7 +14,9 @@ module.exports = Model; * Model Class */ function Model(data, engine) { + this.data = _.extend({}, this.defaults, data || {}); + this.engine = engine; this._isSynced = false; // is synced to db via engine? @@ -26,6 +29,8 @@ function Model(data, engine) { this.__initPromise__ = this._spawnPromise(function(resolve, reject, notify) { // This }); + + this.validation = new Validation(this); } /** @@ -72,13 +77,22 @@ _.extend(Model.prototype, { defaults: {}, set: function(k, v) { + if (toString.call(k) === '[object Object]') { for (var i in k) { if (hasOwn.call(k, i)) { + if (k[i] && this.rules && this.rules[i] && !this.rules[i].call(this, k[i])) { + console.error("Invalid data for ", k[i]); + continue; + } this.data[i] = k[i]; } } } else { + if (v && this.rules && this.rules[k] && !this.rules[k].call(this, v)) { + console.error("Invalid data for ", v); + return false; + } this.data[k] = v; } }, diff --git a/src/util/validation.js b/src/util/validation.js new file mode 100644 index 0000000..ec50f50 --- /dev/null +++ b/src/util/validation.js @@ -0,0 +1,33 @@ +var rules = require('./validationRules'); + +//TODO: sanitation, error messages +var Validation = function(model) { + + var modelRuleSet = model.name ? rules[model.name] : rules, + hasOwn = {}.hasOwnProperty, + key, ruleString, func = 'var value = arguments[0];\r\n var isValid=true;\r\n', str; + + model.rules = model.rules || {}; + + for (var i in model.defaults) { + if (hasOwn.call(model.defaults, i) && modelRuleSet[i]) { + func = 'var isValid=true;\r\n'; + ruleString = modelRuleSet[i].split(', '); + for (var a = 0, len = ruleString.length ; a < len ; a++) { + str = ruleString[a].trim(); + if(!str.indexOf('is ')) { + func += ' if (typeof value !== "' + str.substr(3) + '"){isValid = false}\r\n'; + } else if (!str.indexOf('test ')) { + func += ' if (!' + str.substr(5) + '.test(value)){isValid = false}\r\n'; + } else if (!str.indexOf('assert ')) { + func += ' if (!value' + str.substr(7) + '){isValid = false}\r\n'; + } + } + func += 'return isValid;'; + + model.rules[i] = new Function('value', func); + } + } +}; + +module.exports = Validation; \ No newline at end of file diff --git a/src/util/validationRules.js b/src/util/validationRules.js new file mode 100644 index 0000000..1d6f4de --- /dev/null +++ b/src/util/validationRules.js @@ -0,0 +1,24 @@ +var validationRules = { + user : { + "name" : "is string, assert .length>0", + "surname" : "is string", + "reputation" : "is number", + "level" : "is number, assert >0", + "twitter" : "is string, test /^@?(\w){1,15}$/", + "email" : "is string", + "bio" : "is string", + "picture" : "is string" + }, + + report : { + "updates" : "is array", + "time_start" : "is number", + "time_end" : "is number", + "location" : "is array", + "tags" : "is array", + "editable" : "is boolean" + } + +}; + +module.exports = validationRules; \ No newline at end of file diff --git a/src/yip.js b/src/yip.js index 36e74ca..231fa6a 100644 --- a/src/yip.js +++ b/src/yip.js @@ -54,16 +54,17 @@ yip.Engine = function YipEngine(config) { console.log('Start'); var y = new yip.Engine({ - firebase: 'jp1990' + //firebase: 'jp1990' + firebase: 'bc2013' }); -var u = y.User.fromId('x43424'); +var u = y.User.fromId('joebloggs'); u.then(function(user) { console.log('Ok got something', user.get()); user.on('change', function() { - console.log('Something has changed!', user.get());; + console.log('Something has changed!', user.get()); }); });