Changeset 487
- Timestamp:
- 03/05/14 22:44:48 (11 years ago)
- Location:
- Dev/trunk
- Files:
-
- 471 added
- 3 deleted
- 66 edited
- 5 moved
Legend:
- Unmodified
- Added
- Removed
-
Dev/trunk/Gruntfile.js
r474 r487 13 13 ,'htmlhint:lint' 14 14 ,'coffeelint:lint' 15 //,'tv4:lint' 15 16 ,'less:compile' 16 17 ,'usebanner:generated-css' … … 20 21 //,'amd-check' // too smart about plugins, r.js can't find them 21 22 ]); 22 grunt.registerTask('build', ['clean:build' 23 grunt.registerTask('build', ['compile' 24 ,'clean:build' 23 25 ,'copy:build' 24 26 ,'dojo:build' … … 107 109 } 108 110 }, 111 tv4: { 112 lint: { 113 options: { 114 root: grunt.file.readJSON('json-schema-draft-04.json'), 115 multi: true 116 }, 117 src: [srcDir+'server/config/couchdb-schema.json'] 118 } 119 }, 109 120 usebanner: { 110 121 'generated-css': { options: { position: 'top', … … 129 140 grunt.loadNpmTasks('grunt-dojo'); 130 141 grunt.loadNpmTasks('grunt-htmlhint'); 142 grunt.loadNpmTasks('grunt-tv4'); 131 143 grunt.loadTasks('./grunt-tasks'); 132 144 -
Dev/trunk/package.json
r479 r487 18 18 "grunt-amd-check": "~0.5.2", 19 19 "mocha": "~1.14.0", 20 "should": "~2.1.0" 20 "should": "~2.1.0", 21 "grunt-tv4": "^0.4.0" 21 22 }, 22 23 "dependencies": {} -
Dev/trunk/src/.jshintrc-generated
r479 r487 17 17 "loopfunc": true, 18 18 "shadow": true, 19 "eqnull": true, 19 20 20 21 "devel": true, -
Dev/trunk/src/client/qed-client/app/Router.js
r457 r487 78 78 route.callback(params); 79 79 } catch(err) { 80 console.error("Page change failed with",err .toString());80 console.error("Page change failed with",err,err.toString()); 81 81 } 82 82 return; -
Dev/trunk/src/client/qed-client/model/classes
-
Property
svn:ignore
set to
### begin grunt-svn-ignore managed ignores
### edits will be overwritten when grunt svn-ignore is run
Question.js
Response.js
Survey.js
SurveyRun.js
### end grunt-svn-ignore managed ignores
-
Property
svn:ignore
set to
-
Dev/trunk/src/client/qed-client/model/classes/questions.js
r486 r487 1 define(function(){ 2 return { 3 create: function(){ 4 return { type:'Question' }; 1 define([ 2 "./_Class", 3 "dojo/_base/declare", 4 "dojo/date/stamp" 5 ], function(_Class, declare, stamp) { 6 7 var Questions = declare([_Class],{ 8 _collection: 'questions', 9 _type: 'Question', 10 create: function() { 11 var obj = { 12 type: this._type, 13 categories: [], 14 code: "", 15 content: [], 16 title: "" 17 }; 18 return obj; 5 19 }, 6 DisplayTitle:{7 get: function(q) {8 return q.title || '';20 _deserialize: function(obj) { 21 if (obj.publicationDate) { 22 obj.publicationDate = stamp.fromISOString(obj.publicationDate); 9 23 } 10 24 }, 11 Content: { 12 get: function(q) { 13 return q.content || []; 14 }, 15 set: function(q,content) { 16 q.content = content; 25 _serialize: function(obj) { 26 if (obj.publicationDate) { 27 obj.publicationDate = stamp.toISOString(obj.publicationDate); 17 28 } 18 29 } 19 }; 30 }); 31 32 return new Questions(); 33 20 34 }); -
Dev/trunk/src/client/qed-client/model/classes/responses.js
r486 r487 1 define([],function(){ 2 var SurveyRun = { 3 create: function(){ 4 return { type:'Response' }; 1 define([ 2 "./_Class", 3 "./surveyRuns", 4 "dojo/Deferred", 5 "dojo/_base/declare", 6 "dojo/_base/json", 7 "dojo/_base/lang", 8 "dojo/_base/xhr", 9 "dojo/date/stamp" 10 ], function(_Class, surveyRuns, Deferred, declare, json, lang, xhr, stamp) { 11 12 var Responses = declare([_Class],{ 13 _collection: 'responses', 14 _type: 'Response', 15 create: function() { 16 var obj = { 17 type: this._type, 18 answers: {}, 19 surveyRunId: null 20 }; 21 return obj; 5 22 }, 6 SurveyRun: { 7 get: function(r) { 8 return r.surveyRunId || null; 9 }, 10 set: function(r,sr) { 11 r.surveyRunId = sr; 12 return r; 23 _deserialize: function(obj) { 24 if (obj._surveyRun) { 25 obj._surveyRun = surveyRuns._doDeserialize(obj._surveyRun); 13 26 } 27 if (obj.publicationDate) { 28 obj.publicationDate = stamp.fromISOString(obj.publicationDate); 29 } 30 }, 31 _serialize: function(obj) { 32 if (obj._surveyRun) { 33 obj._surveyRun = surveyRuns._doSerialize(obj._surveyRun); 34 } 35 if (obj.publicationDate) { 36 obj.publicationDate = stamp.toISOString(obj.publicationDate); 37 } 38 }, 39 getWithSecret: function(id,secret) { 40 var query = xhr.objectToQuery({secret:secret}); 41 return xhr('GET',{ 42 url: '/api/open/responses/' + id + '?' + query, 43 handleAs: 'json', 44 contentType: false 45 }).then(lang.hitch(this,'_doDeserialize'),function(err){ 46 return new Deferred().reject(json.fromJson(err.responseText)); 47 }); 48 }, 49 postWithSecret: function(response,secret) { 50 var query = xhr.objectToQuery({secret:secret}); 51 var body = json.toJson(this._doSerialize(response)); 52 return xhr('POST',{ 53 url: '/api/open/responses?' + query, 54 handleAs: 'json', 55 contentType: 'application/json', 56 rawBody: body 57 }).then(lang.hitch(this,'_doDeserialize'),function(err){ 58 return new Deferred().reject(json.fromJson(err.responseText)); 59 }); 60 }, 61 putWithSecret: function(response,secret) { 62 var query = xhr.objectToQuery({secret:secret}); 63 var body = json.toJson(this._doSerialize(response)); 64 return xhr('PUT',{ 65 url: '/api/open/responses/' + this.getId(response) + '?' + query, 66 handleAs: 'json', 67 contentType: 'application/json', 68 rawBody: body 69 }).then(lang.hitch(this,'_doDeserialize'),function(err){ 70 return new Deferred().reject(json.fromJson(err.responseText)); 71 }); 72 }, 73 removeWithSecret: function(response,secret) { 74 var query = xhr.objectToQuery({secret:secret}); 75 var rev = this.getRev(response); 76 var body = json.toJson(this._doSerialize(response)); 77 var headers = {}; 78 if ( rev ) { 79 headers['If-Match'] = '"'+rev+'"'; 80 } 81 return xhr('DELETE',{ 82 url: '/api/open/responses/' + this.getId(response) + '?' + query, 83 headers: headers, 84 handleAs: 'json', 85 contentType: 'application/json', 86 rawBody: body 87 }); 14 88 } 15 }; 16 return SurveyRun; 89 }); 90 91 return new Responses(); 92 17 93 }); -
Dev/trunk/src/client/qed-client/model/classes/surveyRuns.js
r486 r487 1 define(['dojo/_base/lang','dojo/date/locale','dojo/date/stamp'],function(lang,locale,stamp){ 2 var SurveyRun = { 3 create: function(){ 4 return { type:'SurveyRun' }; 1 define([ 2 "./_Class", 3 "./surveys", 4 "dojo/_base/declare", 5 "dojo/date/stamp" 6 ], function(_Class, surveys, declare, stamp) { 7 8 var SurveyRuns = declare([_Class],{ 9 _collection: 'surveyRuns', 10 _type: 'SurveyRun', 11 create: function() { 12 var obj = { 13 type: this._type, 14 description: "", 15 mode: "open", 16 survey: null, 17 title: "" 18 }; 19 return obj; 5 20 }, 6 StartDate: { 7 get: function(sr) { 8 var d; 9 if ( sr.startDate ) { 10 d = lang.isString(sr.startDate) ? stamp.fromISOString(sr.startDate) : sr.startDate; 11 } 12 return d; 13 }, 14 set: function(sr,d) { 15 if ( d ) { 16 sr.startDate = lang.isString(d) ? stamp.toISOString(d) : d; 17 } 21 _deserialize: function(obj) { 22 if (obj.endDate) { 23 obj.endDate = stamp.fromISOString(obj.endDate); 24 } 25 if (obj.startDate) { 26 obj.startDate = stamp.fromISOString(obj.startDate); 27 } 28 if (obj.survey) { 29 obj.survey = surveys._doDeserialize(obj.survey); 18 30 } 19 31 }, 20 EndDate: { 21 get: function(sr) { 22 var d; 23 if ( sr.endDate ) { 24 d = lang.isString(sr.endDate) ? stamp.fromISOString(sr.endDate) : sr.endDate; 25 } 26 return d; 27 }, 28 set: function(sr,d) { 29 if ( d ) { 30 sr.endDate = lang.isString(d) ? stamp.toISOString(d) : d; 31 } 32 _serialize: function(obj) { 33 if (obj.endDate) { 34 obj.endDate = stamp.toISOString(obj.endDate); 32 35 } 33 }, 34 DisplayTitle: { 35 get: function(sr) { 36 var t = "Run of '"+sr.survey.title+"'"; 37 if ( sr.startDate ) { 38 t += " from "+locale.format(SurveyRun.StartDate.get(sr)); 39 } 40 if ( sr.endDate ) { 41 t += " until "+locale.format(SurveyRun.EndDate.get(sr)); 42 } 43 return t; 36 if (obj.startDate) { 37 obj.startDate = stamp.toISOString(obj.startDate); 44 38 } 45 }, 46 Survey: { 47 get: function(sr) { 48 return sr.survey || null; 49 }, 50 set: function(sr,s) { 51 sr.survey = s; 52 return sr; 39 if (obj.survey) { 40 obj.survey = surveys._doSerialize(obj.survey); 53 41 } 54 42 } 55 }; 56 return SurveyRun; 43 }); 44 45 return new SurveyRuns(); 46 57 47 }); -
Dev/trunk/src/client/qed-client/model/classes/surveys.js
r486 r487 1 define(function(){ 2 return { 3 create: function(){ 4 return { type:'Survey' }; 1 define([ 2 "./_Class", 3 "dojo/_base/declare", 4 "dojo/date/stamp", 5 "dojo/store/JsonRest" 6 ], function(_Class, declare, stamp, JsonRest) { 7 8 var Surveys = declare([_Class],{ 9 _collection: 'surveys', 10 _type: 'Survey', 11 create: function() { 12 var obj = { 13 type: this._type, 14 questions: [], 15 title: "" 16 }; 17 return obj; 5 18 }, 6 DisplayTitle:{7 get: function(s) {8 return s.title || '';19 _deserialize: function(obj) { 20 if (obj.publicationDate) { 21 obj.publicationDate = stamp.fromISOString(obj.publicationDate); 9 22 } 10 23 }, 11 Questions: { 12 get: function(s) { 13 return s.questions || []; 14 }, 15 set: function(s,questions) { 16 s.questions = questions; 24 _serialize: function(obj) { 25 if (obj.publicationDate) { 26 obj.publicationDate = stamp.toISOString(obj.publicationDate); 17 27 } 18 28 } 19 }; 29 }); 30 31 return new Surveys(); 32 20 33 }); -
Dev/trunk/src/client/qed-client/model/widgets/QuestionEditorToolkit.js
r443 r487 1 1 define([ 2 "../../store", 2 "../classes/categories", 3 "../classes/topics", 3 4 "./CategoryListView", 4 5 "dijit/_Container", … … 15 16 "require", 16 17 "dojo/text!./templates/QuestionEditorToolkit.html" 17 ], function( store, CategoryListView, _Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, Button, ComboBox, declare, lang, Source, domConstruct, Memory, require, template) {18 ], function(categories, topics, CategoryListView, _Container, _TemplatedMixin, _WidgetBase, _WidgetsInTemplateMixin, Button, ComboBox, declare, lang, Source, domConstruct, Memory, require, template) { 18 19 return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, _Container], { 19 20 … … 107 108 this.inherited(arguments); 108 109 109 store.query("_design/questions/_view/all", {reduce:true, group:false, group_level:1}) 110 .forPairs(lang.hitch(this, function(value, key) { 111 this._categoryStore.put({ id: key[0] }); 110 categories.query().forEach(lang.hitch(this,function(cat){ 111 this._categoryStore.put({ id: cat }); 112 112 })); 113 113 114 store.query("_design/questions/_view/all_topics", {reduce:true, group:true}) 115 .forPairs(lang.hitch(this, function(value, key) { 116 this._topicStore.put({ id: key }); 114 topics.query().forEach(lang.hitch(this,function(topic){ 115 this._categoryStore.put({ id: topic }); 117 116 })); 118 117 }, -
Dev/trunk/src/client/qed-client/model/widgets/SurveyRenderWidget.js
r461 r487 1 1 define([ 2 2 "../../widgets/_ComplexValueWidget", 3 "../classes/Survey",4 3 "./questions/Factory", 5 4 "dojo/_base/array", … … 7 6 "dojo/dom-construct", 8 7 "dojo/text!./templates/SurveyRenderWidget.html" 9 ], function(_ComplexValueWidget, Survey,QuestionWidgetFactory, array, declare, domConstruct, template) {8 ], function(_ComplexValueWidget, QuestionWidgetFactory, array, declare, domConstruct, template) { 10 9 return declare([_ComplexValueWidget],{ 11 10 templateString: template, … … 22 21 this.survey = survey; 23 22 var f = new QuestionWidgetFactory(); 24 array.forEach( Survey.Questions.get(this.survey),function(question,question_index){23 array.forEach(this.survey.questions,function(question,question_index){ 25 24 array.forEach(question.content || [], function(item,item_index){ 26 25 // The dot causes values to be grouped in an object! -
Dev/trunk/src/client/qed-client/model/widgets/SurveySummary.js
r457 r487 1 1 define([ 2 "../../store",3 "../classes/Survey",4 2 "dijit/_TemplatedMixin", 5 3 "dijit/_WidgetBase", … … 7 5 "dojo/dom-attr", 8 6 "dojo/text!./templates/SurveySummary.html" 9 ], function( store, Survey,_TemplatedMixin, _WidgetBase, declare, domAttr, template) {7 ], function(_TemplatedMixin, _WidgetBase, declare, domAttr, template) { 10 8 return declare([_WidgetBase,_TemplatedMixin],{ 11 9 templateString: template, … … 18 16 }, 19 17 _setValueAttr: function(survey) { 20 this.titleNode.innerHTML = Survey.DisplayTitle.get(survey); 21 var id = store.getIdentity(survey); 22 domAttr.set(this.titleNode, "href", id && ("#!/survey/"+id)); 18 this.titleNode.innerHTML = survey.title || ""; 19 domAttr.set(this.titleNode, "href", survey._id && ("#!/survey/"+survey._id)); 23 20 this.descriptionNode.innerHTML = survey.description; 24 this.questionsNode.innerHTML = (survey.questions || []).length;21 this.questionsNode.innerHTML = survey.questions.length; 25 22 } 26 23 }); -
Dev/trunk/src/client/qed-client/model/widgets/TabbedQuestionBrowser.js
r477 r487 1 1 define([ 2 'dojo/_base/declare', 3 'dojo/_base/lang', 4 'dojo/_base/window', 5 'dijit/layout/ContentPane', 6 'dijit/layout/TabContainer', 7 'dojox/widget/Standby', 8 '../../store', 9 '../../widgets/Selector' 10 ],function(declare,lang,win,ContentPane,TabContainer,Standby,store,Selector){ 2 "../../widgets/Selector", 3 "../classes/categories", 4 "../classes/questions", 5 "../classes/topics", 6 "dijit/layout/ContentPane", 7 "dijit/layout/TabContainer", 8 "dojo/_base/declare", 9 "dojo/_base/lang", 10 "dojo/_base/window", 11 "dojox/widget/Standby" 12 ], function(Selector, categories, questions, topics, ContentPane, TabContainer, declare, lang, win, Standby) { 11 13 return declare([TabContainer],{ 12 14 tabPosition: 'left-h', … … 38 40 this._fillCategoryTab(newTab.__category); 39 41 })); 40 store.query(this._query, {reduce:true,group:true,group_level:1})41 .for Pairs(lang.hitch(this,function(value,key){42 this._createCategoryTab( key[0],value);42 categories.query() 43 .forEach(lang.hitch(this,function(cat){ 44 this._createCategoryTab(cat.name,cat.count); 43 45 })); 44 46 }, … … 61 63 this._busy(); 62 64 categoryMap._filled = true; 63 store.query(this._query, {reduce:true,group:true,group_level:2,startkey:[category],endkey:[category,{}]})64 .for Pairs(lang.hitch(this,function(value,key){65 this._createTopicSelector( key[1],category,value);65 topics.query({category:category}) 66 .forEach(lang.hitch(this,function(topic){ 67 this._createTopicSelector(topic.name,category,topic.count); 66 68 })).then(lang.hitch(this,function(){ 67 69 this._done(); … … 101 103 topicMap._filled = true; 102 104 this._busy(); 103 store.query(this._query, { 104 reduce:false, 105 include_docs:true, 106 key:[category,topic] 107 }).forEach(lang.hitch(this,function(value){ 105 questions.query({category:category,topic:topic}) 106 .forEach(lang.hitch(this,function(value){ 108 107 topicMap._widget.addItem(value); 109 108 })).then(lang.hitch(this,function(){ -
Dev/trunk/src/client/qed-client/pages/previewSurvey.js
r443 r487 1 1 define([ 2 2 "../app/Page", 3 "../ store",3 "../model/classes/surveys", 4 4 "dojo/_base/array", 5 5 "dojo/_base/declare", … … 8 8 "require", 9 9 "dojo/text!./templates/previewSurvey.html" 10 ], function(Page, s tore, array, declare, lang, when, require, template) {10 ], function(Page, surveys, array, declare, lang, when, require, template) { 11 11 return declare([Page],{ 12 12 contextRequire: require, … … 16 16 this.inherited(arguments); 17 17 if ( this.surveyId ) { 18 when(s tore.get(this.surveyId))18 when(surveys.load(this.surveyId)) 19 19 .then(lang.hitch(this,function(survey){ 20 this.titleNode.innerHTML = survey.title ;20 this.titleNode.innerHTML = survey.title || ""; 21 21 this.surveyWidget.set('survey',survey); 22 22 })); -
Dev/trunk/src/client/qed-client/pages/question.js
r443 r487 3 3 "../app/Page", 4 4 "../app/Router", 5 "../model/classes/ Question",5 "../model/classes/questions", 6 6 "../model/widgets/QuestionEditorPreview", 7 7 "../model/widgets/QuestionEditorToolkit", 8 "../store",9 8 "../widgets/_ComplexValueMixin", 10 9 "dojo/_base/declare", … … 13 12 "dojo/when", 14 13 "dojo/text!./templates/question.html" 15 ], function(Content, Page, Router, Question, QuestionEditorPreview, QuestionEditorToolkit, store, _ComplexValueMixin, declare, event, lang, when, template) {14 ], function(Content, Page, Router, questions, QuestionEditorPreview, QuestionEditorToolkit, _ComplexValueMixin, declare, event, lang, when, template) { 16 15 return declare([Page,_ComplexValueMixin], { 17 16 templateString: template, … … 43 42 } 44 43 if (this.questionId === "new") { 45 this.set('value', Question.create());44 this.set('value', questions.create()); 46 45 } else { 47 when( store.get(this.questionId))46 when(questions.load(this.questionId)) 48 47 .then(lang.hitch(this, function(value) { 49 48 this.set('value', value); … … 54 53 this.value = value; 55 54 this.inherited(arguments); 56 this.titleNode.innerHTML = Question.DisplayTitle.get(value);55 this.titleNode.innerHTML = value.title || ""; 57 56 }, 58 57 _getValueAttr: function() { … … 63 62 _onSave: function(evt) { 64 63 if ( this.validate() ) { 65 var value = this.get('value'); 66 store.put(value) 64 questions.save(this.get('value')) 67 65 .then(function() { 68 66 Router.go('/questions'); -
Dev/trunk/src/client/qed-client/pages/questions.js
r443 r487 1 1 define([ 2 'dojo/_base/declare',3 'dojo/_base/Deferred',4 'dojo/_base/event',5 'dojo/_base/lang',6 '../store',7 '../app/Content',8 '../app/Router',9 '../app/Page',10 '../model/widgets/TabbedQuestionBrowser',11 'dojo/text!./templates/questions.html'12 ], function(declare,Deferred,event,lang,store,Content,Router,Page,TabbedQuestionBrowser,template) {2 "../app/Content", 3 "../app/Page", 4 "../app/Router", 5 "../model/classes/questions", 6 "../model/widgets/TabbedQuestionBrowser", 7 "dojo/_base/Deferred", 8 "dojo/_base/declare", 9 "dojo/_base/event", 10 "dojo/_base/lang", 11 "dojo/text!./templates/questions.html" 12 ], function(Content, Page, Router, questions, TabbedQuestionBrowser, Deferred, declare, event, lang, template) { 13 13 return declare([Page],{ 14 14 templateString: template, … … 44 44 }, 45 45 onDeleteQuestion: function(question) { 46 store.remove(store.getIdentity(question),store.getRevision(question))46 questions.remove(question) 47 47 .then(function(){ 48 48 Content.notify("Question deleted."); … … 55 55 }, 56 56 onPublishQuestion: function(question) { 57 question.publicationDate = store.timestamp();58 store.put(question)57 question.publicationDate = new Date(); 58 questions.save(question) 59 59 .then(function(){ 60 60 Content.notify("Question published."); -
Dev/trunk/src/client/qed-client/pages/response.js
r478 r487 3 3 "../app/Page", 4 4 "../lib/async", 5 "../model/classes/Response", 6 "../model/classes/Survey", 7 "../model/classes/SurveyRun", 8 "../store", 5 "../model/classes/responses", 9 6 "dojo/_base/declare", 10 7 "dojo/_base/event", … … 16 13 "require", 17 14 "dojo/text!./templates/response.html" 18 ], function(Content, Page, async, Response, Survey, SurveyRun, store, declare, event, json, lang, all, request, when, require, template) {15 ], function(Content, Page, async, responses, declare, event, json, lang, all, request, when, require, template) { 19 16 return declare([Page],{ 20 17 contextRequire: require, … … 28 25 this.inherited(arguments); 29 26 this._disableSubmit(); 30 var surveyRunId = this.surveyRunId; 31 var responseId = this.options && this.options.id; 32 if ( surveyRunId && responseId ) { 33 this._loadSurveyAndResponse(surveyRunId,responseId) 34 .then(lang.hitch(this, function() { 35 if ( this.response.publicationDate ) { 36 this._showInfo("<div>You already submitted your survey and cannot change it anymore. You can still view your answers here.</div>"); 37 this._disableSubmit(); 38 } else { 39 this._enableSubmit(); 40 } 41 }), lang.hitch(this,function() { 42 this._showInfo("<div>The url seems to be incorrect, no survey found.</div>"); 43 })); 27 if ( !this.response ) { 28 this._showInfo("<div>The url seems to be incorrect, no response found.</div>"); 44 29 } else { 45 throw new Error("No valid uid or survey passed!"); 30 this.titleNode.innerHTML = this.response._surveyRun.survey.title || ""; 31 this.surveyWidget.set('survey', this.response._surveyRun.survey); 32 this.surveyWidget.set('value', this.response.answers || {}); 33 if ( this.response.publicationDate ) { 34 this._showInfo("<div>You already submitted your survey and cannot change it anymore. You can still view your answers here.</div>"); 35 this._disableSubmit(); 36 } else { 37 this._enableSubmit(); 38 } 46 39 } 47 },48 _loadSurveyAndResponse: function(surveyRunId,responseId){49 return all([request.get('/api/surveyRuns/'+surveyRunId,{handleAs:'json'}),50 request.get('/api/responses/'+responseId,{handleAs:'json'})])51 .then(lang.hitch(this,function(surveyAndResponse){52 var surveyRun = surveyAndResponse[0];53 this.response = surveyAndResponse[1];54 if ( this.response.surveyRunId !== surveyRunId ) {55 throw "Survey does not match the response...";56 }57 this.titleNode.innerHTML = Survey.DisplayTitle.get(surveyRun.survey);58 this.surveyWidget.set('survey', surveyRun.survey);59 this.surveyWidget.set('value', this.response.answers || {});60 }));61 40 }, 62 41 _enableSubmit: function() { … … 78 57 var answers = this.surveyWidget.get('value'); 79 58 this.response.answers = answers; 80 return request.put('/api/responses/'+store.getIdentity(this.response),{ 81 handleAs:'json', 82 data:json.toJson(this.response), 83 headers:{"Content-Type": "application/json"} 84 }).then(lang.hitch(this,function(res){ 85 this.response._rev = res.rev; 59 return responses.putWithSecret(this.response,this.response.secret) 60 .then(lang.hitch(this,function(response){ 61 this.response = response; 86 62 Content.notify("Your response is saved."); 87 63 }), function(err){ … … 90 66 }, 91 67 _onSubmit: function(e) { 92 this.response.publicationDate = store.timestamp();68 this.response.publicationDate = new Date(); 93 69 this._getAnswersAndSaveResponse() 94 70 .then(lang.hitch(this,function(){ … … 110 86 this._disableSubmit(); 111 87 this.surveyWidget.destroy(); 112 request('/api/responses/'+store.getIdentity(this.response)+'?rev='+store.getRevision(this.response),{ 113 method: 'DELETE', 114 handleAs:'json', 115 data:json.toJson(this.response), 116 headers:{"Content-Type": "application/json"} 117 }).then(lang.hitch(this,function(res){ 88 responses.removeWithSecret(this.response,this.response.secret) 89 .then(lang.hitch(this,function(res){ 118 90 this._showInfo("<div>Your response has been deleted, no answers have been saved.</div>"); 119 91 Content.notify("Your response is deleted."); -
Dev/trunk/src/client/qed-client/pages/session.js
r443 r487 1 1 define([ 2 'dojo/_base/array',2 /*'dojo/_base/array', 3 3 'dojo/_base/declare', 4 4 'dojo/_base/event', … … 12 12 '../model/classes/SessionTemplate', 13 13 '../model/widgets/AccountListView', 14 'dojo/text!./templates/session.html' 14 'dojo/text!./templates/session.html'*/ 15 15 ],function(array,declare,event,lang,when,search,store,Page,Router,ThresholdFilteringSelect,SessionTemplate,AccountListView,template){ 16 return declare([Page],{16 /*return declare([Page],{ 17 17 templateString: template, 18 18 session: null, … … 92 92 93 93 94 }); 94 });*/ 95 95 }); 96 96 -
Dev/trunk/src/client/qed-client/pages/sessions.js
r443 r487 1 1 define([ 2 'dojo/_base/declare',2 /*'dojo/_base/declare', 3 3 'dojo/_base/lang', 4 4 'dojo/date/stamp', … … 7 7 '../app/Page', 8 8 '../widgets/ObjectBox', 9 'dojo/text!./templates/sessions.html' 9 'dojo/text!./templates/sessions.html'*/ 10 10 ],function(declare,lang,dateStamp,store,Router,Page,ObjectBox,template){ 11 return declare([Page],{11 /*return declare([Page],{ 12 12 templateString: template, 13 13 templateActions: null, … … 18 18 this.templateActions = { 19 19 "Edit": function(obj){ 20 Router.go('/session/'+ store.getIdentity(obj));20 Router.go('/session/'+obj.get('id')); 21 21 }, 22 22 "Delete": lang.hitch(this,function(obj){ 23 store.remove(store.getIdentity(obj),store.getRevision(obj))23 obj.remove() 24 24 .then(lang.hitch(this,function(){ 25 25 this._refresh(); … … 30 30 this.sessionActions = { 31 31 "Facilitate": function(obj){ 32 Router.go('run',{uid: store.getIdentity(obj)});32 Router.go('run',{uid: obj.get('id')}); 33 33 }, 34 34 "Delete": lang.hitch(this,function(obj){ 35 store.remove(store.getIdentity(obj),store.getRevision(obj))35 obj.remove() 36 36 .then(lang.hitch(this,function(){ 37 37 this._refresh(); … … 48 48 }, 49 49 _refreshByType: function(type,container,actions) { 50 // FIXME 50 51 store.query("_design/default/_view/by_type",{key:type}) 51 52 .forEach(lang.hitch(this,function(obj){ … … 61 62 }, 62 63 _publishSession: function(sessionTemplate) { 64 // FIXME 63 65 var session = lang.clone(sessionTemplate); 64 66 delete session[store.idProperty]; … … 73 75 })); 74 76 } 75 }); 77 });*/ 76 78 }); -
Dev/trunk/src/client/qed-client/pages/survey.js
r443 r487 2 2 "../app/Page", 3 3 "../app/Router", 4 "../model/classes/ Survey",4 "../model/classes/surveys", 5 5 "../model/widgets/QuestionListView", 6 6 "../model/widgets/TabbedQuestionBrowser", 7 "../store",8 7 "dojo/_base/array", 9 8 "dojo/_base/declare", … … 13 12 "require", 14 13 "dojo/text!./templates/survey.html" 15 ], function(Page, Router, Survey, QuestionListView, TabbedQuestionBrowser, store, array, declare, event, lang, when, require, template) {14 ], function(Page, Router, surveys, QuestionListView, TabbedQuestionBrowser, array, declare, event, lang, when, require, template) { 16 15 return declare([Page],{ 17 16 contextRequire: require, … … 63 62 _loadSurvey: function() { 64 63 if ( this.surveyId === "new" ) { 65 this.survey = Survey.create();64 this.survey = surveys.create(); 66 65 this.refresh(); 67 66 } else { 68 when(s tore.get(this.surveyId))67 when(surveys.load(this.surveyId)) 69 68 .then(lang.hitch(this,function(survey){ 70 69 this.survey = survey; 71 70 this.questionList.set('value', 72 Survey.Questions.get(this.survey));71 this.survey.questions); 73 72 this.refresh(); 74 73 })); … … 79 78 }, 80 79 refresh: function() { 81 this.titleNode.innerHTML = Survey.DisplayTitle.get(this.survey)|| "(set title in properties)";80 this.titleNode.innerHTML = this.survey.title || "(set title in properties)"; 82 81 this.propertiesDialog.set('value',this.survey); 83 82 }, … … 100 99 _onSave: function(evt) { 101 100 this.survey.questions = this.questionList.get('value'); 102 s tore.put(this.survey)101 surveys.save(this.survey) 103 102 .then(function() { 104 103 Router.go('/surveys'); … … 111 110 }, 112 111 _onShowPreview: function() { 113 Router.go('/previewSurvey/'+ store.getIdentity(this.survey),{112 Router.go('/previewSurvey/'+this.survey._id,{ 114 113 preview: true 115 114 }); -
Dev/trunk/src/client/qed-client/pages/surveyRun.js
r466 r487 4 4 "../app/Router", 5 5 "../lib/func", 6 "../model/classes/ SurveyRun",7 "../ store",6 "../model/classes/responses", 7 "../model/classes/surveyRuns", 8 8 "../widgets/LineWithActionsWidget", 9 "dojo/_base/array", 9 10 "dojo/_base/declare", 10 11 "dojo/_base/event", … … 13 14 "require", 14 15 "dojo/text!./templates/surveyRun.html" 15 ], function(Content, Page, Router, func, SurveyRun, store, LineWithActionsWidget, declare, event, lang, when, require, template) {16 ], function(Content, Page, Router, func, responses, surveyRuns, LineWithActionsWidget, array, declare, event, lang, when, require, template) { 16 17 return declare([Page],{ 17 18 contextRequire: require, … … 24 25 if ( this.surveyRunId ) { 25 26 this._loadSurveyRun(); 26 this._loadResponses();27 27 } else { 28 28 throw "No valid uid or survey passed!"; … … 30 30 }, 31 31 _loadSurveyRun: function() { 32 when(s tore.get(this.surveyRunId))32 when(surveyRuns.load(this.surveyRunId)) 33 33 .then(lang.hitch(this,function(surveyRun){ 34 34 this.surveyRun = surveyRun; 35 35 this.refreshSurveyRun(); 36 this._loadResponses(); 36 37 })); 37 38 }, 38 39 refreshSurveyRun: function() { 39 this.titleNode.innerHTML = SurveyRun.DisplayTitle.get(this.surveyRun);40 this.surveySummaryWidget.set('value', SurveyRun.Survey.get(this.surveyRun));40 this.titleNode.innerHTML = this.surveyRun.title || ""; 41 this.surveySummaryWidget.set('value',this.surveyRun.survey); 41 42 this.surveyRunWidget.set('value',this.surveyRun); 42 43 this._onPropChange(); 43 44 }, 44 45 _loadResponses: function() { 45 when(store.query("_design/responses/_view/by_surveyrun",{key:this.surveyRunId})) 46 .forEach(lang.hitch(this,function(response){ 47 var actions = { 48 view: { 49 callback: function(){}, 50 properties: { 51 title: "View response" 52 } 53 } 54 }; 55 if ( !response.publicationDate ) { 56 actions.remove = { 57 callback: function(){}, 58 properties: { 59 title: "Remove response" 46 responses.query({surveyRunId:surveyRuns.getId(this.surveyRun)}) 47 .then(lang.hitch(this,function(allResponses){ 48 array.forEach(allResponses, function(response){ 49 var actions = { 50 view: { 51 callback: function(){}, 52 properties: { 53 title: "View response" 54 } 60 55 } 61 56 }; 62 } 63 var w = new LineWithActionsWidget({ 64 actions: actions 65 }); 66 var responseId = store.getIdentity(response); 67 w.set('title',this._link(this._getResponseURL(this.surveyRunId,responseId),responseId)); 68 w.placeAt(this.responsesNode); 57 if ( !response.publicationDate ) { 58 actions.remove = { 59 callback: function(){}, 60 properties: { 61 title: "Remove response" 62 } 63 }; 64 } 65 var w = new LineWithActionsWidget({ 66 actions: actions 67 }); 68 var rid = responses.getId(response); 69 w.set('title',this._link(this._buildResponseURL(response),rid),rid); 70 w.placeAt(this.responsesNode); 71 }, this); 69 72 })); 70 73 }, … … 73 76 if ( surveyRun.mode === "open" ) { 74 77 this.runURLNode.innerHTML = 75 this._link(this._ getGeneralURL(store.getIdentity(this.surveyRun)));78 this._link(this._buildGeneralURL(this.surveyRun)); 76 79 } else { 77 80 this.runURLNode.innerHTML = … … 79 82 } 80 83 }, 81 _ getGeneralURL: function(surveyRunId) {82 return 'response.html#!/ '+surveyRunId;84 _buildGeneralURL: function(surveyRun) { 85 return 'response.html#!/surveyRuns/'+surveyRuns.getId(surveyRun)+'!secret='+surveyRun.secret; 83 86 }, 84 _ getResponseURL: function(surveyRunId,responseId) {85 return 'response.html#!/ '+surveyRunId+'!id='+responseId;87 _buildResponseURL: function(response) { 88 return 'response.html#!/responses/'+responses.getId(response)+'!secret='+response.secret; 86 89 }, 87 90 _link: function(url,label) { … … 92 95 lang.mixin(this.surveyRun,this.surveyRunWidget.get('value')); 93 96 94 var SD = SurveyRun.StartDate; 95 var ED = SurveyRun.EndDate; 96 SD.set(this.surveyRun, SD.get(this.surveyRun)); 97 ED.set(this.surveyRun, ED.get(this.surveyRun)); 98 99 store.put(this.surveyRun) 97 surveyRuns.save(this.surveyRun) 100 98 .then(function() { 101 99 Router.go('/surveys'); -
Dev/trunk/src/client/qed-client/pages/surveys.js
r443 r487 1 1 define([ 2 'dojo/_base/array', 3 'dojo/_base/declare', 4 'dojo/_base/lang', 5 'dojo/when', 6 '../store', 7 '../app/Content', 8 '../app/Page', 9 '../app/Router', 10 '../model/classes/Survey', 11 '../model/classes/SurveyRun', 12 '../widgets/LineWithActionsWidget', 13 'dojo/text!./templates/surveys.html' 14 ],function(array,declare,lang,when,store,Content,Page,Router,Survey,SurveyRun,LineWithActionsWidget,template){ 2 "../app/Content", 3 "../app/Page", 4 "../app/Router", 5 "../model/classes/surveys", 6 "../model/classes/surveyRuns", 7 "../widgets/LineWithActionsWidget", 8 "dojo/_base/array", 9 "dojo/_base/declare", 10 "dojo/_base/lang", 11 "dojo/when", 12 "dojo/text!./templates/surveys.html" 13 ], function(Content, Page, Router, surveys, surveyRuns, LineWithActionsWidget, array, declare, lang, when, template) { 15 14 return declare([Page],{ 16 15 templateString: template, … … 25 24 _onPublishSurvey:function(survey){ 26 25 var self = this; 27 survey.publicationDate = store.timestamp(); 28 store.put(survey).then(function(){ 26 survey.publicationDate = new Date(); 27 surveys.save(survey) 28 .then(function(){ 29 29 self.refreshDrafts(); 30 30 self.refreshPublished(); … … 35 35 _onDeleteSurvey:function(survey){ 36 36 var self = this; 37 s tore.remove(store.getIdentity(survey),store.getRevision(survey))37 surveys.remove(survey) 38 38 .then(function(){ 39 39 self.refreshDrafts(); … … 43 43 }, 44 44 _onEditSurvey:function(survey){ 45 Router.go('/survey/'+s tore.getIdentity(survey));45 Router.go('/survey/'+survey._id); 46 46 }, 47 47 _onPreviewSurvey:function(survey){ 48 Router.go('/previewSurvey/'+s tore.getIdentity(survey));48 Router.go('/previewSurvey/'+survey._id); 49 49 }, 50 50 _onRunSurvey:function(survey){ 51 var surveyRun = SurveyRun.create();52 SurveyRun.Survey.set(surveyRun,survey);53 s tore.put(surveyRun)51 var surveyRun = surveyRuns.create(); 52 surveyRun.survey = survey; 53 surveyRuns.save(surveyRun) 54 54 .then(lang.hitch(this,function(surveyRun){ 55 55 this._onRunDetails(surveyRun); … … 59 59 }, 60 60 _onRunDetails: function(surveyRun) { 61 Router.go('/surveyRun/'+s tore.getIdentity(surveyRun));61 Router.go('/surveyRun/'+surveyRun._id); 62 62 }, 63 63 refresh: function() { … … 68 68 refreshDrafts: function() { 69 69 this.draftsContainer.set('content',''); 70 when(store.query("_design/surveys/_view/drafts"), 71 lang.hitch(this,function(surveys) { 70 when(surveys.query({drafts:true}), lang.hitch(this,function(surveys) { 72 71 this.draftsTab.set('title','Drafts ('+surveys.length+')'); 73 72 array.forEach(surveys,function(survey){ 74 73 var w = new LineWithActionsWidget({ 75 title: Survey.DisplayTitle.get(survey)|| '(unnamed)',74 title: survey.title || '(unnamed)', 76 75 actions: [{ 77 76 callback: lang.hitch(this,'_onPublishSurvey',survey), … … 110 109 refreshPublished: function() { 111 110 this.publishedContainer.set('content',''); 112 when(store.query("_design/surveys/_view/published"), 113 lang.hitch(this, function(surveys) { 111 when(surveys.query({published:true}), lang.hitch(this, function(surveys) { 114 112 this.publishedTab.set('title','Published ('+surveys.length+')'); 115 113 array.forEach(surveys,function(survey){ 116 114 var w = new LineWithActionsWidget({ 117 title: Survey.DisplayTitle.get(survey),115 title: survey.title || "", 118 116 actions:[{ 119 117 callback: lang.hitch(this,'_onPreviewSurvey',survey), … … 138 136 refreshRuns: function() { 139 137 this.runsContainer.set('content',''); 140 when(store.query("_design/default/_view/by_type",{key:'SurveyRun'}), 141 lang.hitch(this,function(surveyRuns){ 138 when(surveyRuns.query(), lang.hitch(this,function(surveyRuns){ 142 139 this.runsTab.set('title','Runs ('+surveyRuns.length+')'); 143 140 array.forEach(surveyRuns,function(surveyRun){ 144 141 var w = new LineWithActionsWidget({ 145 title: SurveyRun.DisplayTitle.get(surveyRun),142 title: surveyRun.title || "", 146 143 actions:[{ 147 144 callback: lang.hitch(this,'_onRunDetails',surveyRun), -
Dev/trunk/src/client/qed-client/response.js
r477 r487 4 4 "./app/Path", 5 5 "./lib/async", 6 "./model/classes/ Response",7 "./model/classes/ SurveyRun",6 "./model/classes/responses", 7 "./model/classes/surveyRuns", 8 8 "./pages/response", 9 "./store",10 9 "dojo/_base/json", 11 10 "dojo/date", … … 16 15 "./stddeps", 17 16 "dojo/domReady!" 18 ], function(Content, Page, Path, async, Response, SurveyRun, ResponsePage, store, json, date, locale, hash, parser, request) {17 ], function(Content, Page, Path, async, responses, surveyRuns, ResponsePage, json, date, locale, hash, parser, request) { 19 18 parser.parse(); 20 19 Content.startup(); … … 26 25 } 27 26 28 var path = new Path('/: surveyRunId');27 var path = new Path('/:type/:id'); 29 28 var params = path.match(hash()); 30 29 params.options = params.options || {}; 31 32 if ( !params || !params.surveyRunId ) { 30 31 if ( params && params.type === 'surveyRuns' ) { 32 var response = responses.create(); 33 response.surveyRunId = params.id; 34 responses.postWithSecret(response,params.options.secret) 35 .then(setContent,function(err){ error(err.error); }); 36 } else if ( params && params.type === 'responses' ) { 37 responses.getWithSecret(params.id,params.options.secret) 38 .then(setContent,function(err){ error(err.error); }); 39 } else { 33 40 error("Something is wrong with the URL, don't know what survey to show you. Sorry."); 34 return;35 41 } 36 42 37 var surveyRunId = params.surveyRunId; 38 39 function checkDates(surveyRun) { 40 var now = new Date(); 41 var startDate = SurveyRun.StartDate.get(surveyRun); 42 var endDate = SurveyRun.EndDate.get(surveyRun); 43 if ( startDate && date.compare(startDate,now) > 0 ) { 44 error("This survey will start on "+locale.format(startDate,'date')); 45 throw false; 46 } 47 if ( endDate && date.compare(now,endDate) > 0 ) { 48 error("This survey ended on "+locale.format(endDate,'date')); 49 throw false; 50 } 43 function setContent(response) { 44 hash(Path.format("/responses/"+responses.getId(response), 45 {secret:response.secret})); 46 Content.set(new ResponsePage({ 47 response: response 48 })); 51 49 } 52 50 53 request.get('/api/surveyRuns/'+surveyRunId,{handleAs:'json'})54 .then(function(surveyRun){55 checkDates(surveyRun);56 if ( params.options.id ) {57 return params.options.id;58 } else {59 if ( surveyRun.mode === "open") {60 var response = Response.create();61 response.surveyRunId = surveyRunId;62 return request.post('/api/responses',{63 handleAs:'json',64 data:json.toJson(response),65 headers:{"Content-Type": "application/json"}66 }).then(function(res){67 return res.id;68 });69 } else {70 error("Cannot respond to closed survey without response id. Sorry.");71 throw false;72 }73 }74 return surveyRun;75 },function(){76 error("No running survey found for the given id. Sorry.");77 throw false;78 })79 .then(function(responseId){80 hash(Path.format("/"+surveyRunId,{ id: responseId }));81 Content.set(new ResponsePage({82 surveyRunId: surveyRunId,83 options: {84 id: responseId85 }86 }));87 });88 51 }); -
Dev/trunk/src/client/qed-client/routes.js
r443 r487 1 1 define([ 2 './pages/index', 3 './pages/questions', 4 './pages/question', 5 './pages/surveys', 6 './pages/survey', 7 './pages/surveyRun', 8 './pages/sessions', 9 './pages/session', 10 './pages/previewSurvey' 11 ],function(index,questions,question,surveys,survey,surveyRun,sessions,session,previewSurvey){ 2 "./pages/index", 3 "./pages/previewSurvey", 4 "./pages/question", 5 "./pages/questions", 6 "./pages/survey", 7 "./pages/surveyRun", 8 "./pages/surveys" 9 ], function(index, previewSurvey, question, questions, survey, surveyRun, surveys) { 12 10 13 11 return [ -
Dev/trunk/src/client/qed-client/session.coffee
r468 r487 2 2 "dojo/_base/declare", 3 3 "dojo/_base/json", 4 "dojo/Deferred", 4 5 "dojo/Evented", 5 6 "dojo/request" 6 ], (declare, json, Evented, request) ->7 ], (declare, json, Deferred, Evented, request) -> 7 8 Session = declare [Evented], 8 9 info: null … … 18 19 @_set res 19 20 , () => 20 throw(@_set null)21 new Deferred().reject (@_set null) 21 22 22 23 login: (username, password) -> … … 30 31 @_set res 31 32 , () => 32 throw(@_set null)33 new Deferred().reject (@_set null) 33 34 34 35 logout: () -> … … 45 46 @info = newInfo 46 47 @emit 'change', @info 47 48 @info 48 49 49 50 new Session() -
Dev/trunk/src/client/qed-client/stddeps.js
r468 r487 1 1 define([ 2 2 3 // dijit & rft widgets used declaratively in templates 3 4 'dijit/Dialog', … … 43 44 './widgets/Selector', 44 45 './widgets/TitleGroup' 46 45 47 ],function(){}); -
Dev/trunk/src/client/qed-client/ui/LoginDialogWrapper.coffee
r468 r487 17 17 if @_started then return 18 18 @inherited arguments 19 _on session, 'change', (lang.hitch @, @onUserChange)19 _on session, 'change', (lang.hitch @, 'onUserChange') 20 20 @onUserChange session.get() 21 21 onLogin: (evt) -> … … 35 35 else 36 36 @loginDialog.show() 37 null -
Dev/trunk/src/client/qed-client/xhr.js
r486 r487 2 2 "./session", 3 3 "dojo/Deferred", 4 "dojo/_base/lang", 4 5 "dojo/on", 5 "dojo/ request"6 ], function(session, Deferred, on, request) {6 "dojo/_base/xhr" 7 ], function(session, Deferred, lang, on, xhr) { 7 8 8 9 var user = session.get(); 9 10 var queue = []; 10 11 11 on(session, 'change', function(newUser) 12 on(session, 'change', function(newUser){ 12 13 user = newUser; 13 if ( user ) { 14 retry(); 15 } 14 retry(); 16 15 }); 17 16 18 17 function retry() { 19 if ( queue.length > 0) {18 if (user && queue.length > 0) { 20 19 var item = queue.shift(); 21 console.log("Retry",item. url);20 console.log("Retry",item.options.url); 22 21 real_request(item); 23 22 } … … 25 24 26 25 function real_request(item) { 27 var req = request(item.url,item.options); 26 var req = xhr(item.method,lang.mixin(item.options||{},{ 27 failOk: true 28 })); 29 item.promise.ioArgs = req.ioArgs; 28 30 29 // forward successfull response 30 req.then(function(body){ 31 item.dfd.resolve(body); 32 }); 33 34 // handle unauthenticated and queued requests 35 req.response.then(function(response){ 31 req.then(function(result){ 32 item.dfd.resolve(result); 36 33 retry(); 37 }, function(error) 34 }, function(error){ 38 35 if ( error.response.status === 401 ) { 39 36 queue.unshift(item); 40 37 session.restore(); 41 38 } else { 42 item.dfd.reject(error); // this should be error body 43 // not, the request? 39 item.dfd.reject(error); 44 40 retry(); 45 41 } … … 47 43 } 48 44 49 var _request = function( url, options) {45 var _request = function(method, options) { 50 46 var item = { 51 url: url,47 method: method, 52 48 options: options, 53 49 dfd: new Deferred() 54 50 }; 51 item.promise = lang.delegate(item.dfd.promise); 55 52 // only do the request directly if we are authenticated and 56 53 // there are no earlier requests queued. 57 54 if ( user && queue.length === 0 ) { 58 console.log("Request", url);55 console.log("Request",options.url); 59 56 real_request(item); 60 57 } else { 61 console.log("Push", url);58 console.log("Push",options.url); 62 59 queue.push(item); 63 60 } 64 return item. dfd.promise;61 return item.promise; 65 62 }; 66 63 -
Dev/trunk/src/node_modules/express/node_modules/buffer-crc32/package.json
r484 r487 20 20 "main": "index.js", 21 21 "scripts": { 22 "test": " ./node_modules/.bin/tap tests/*.test.js"22 "test": "tap tests/*.test.js" 23 23 }, 24 24 "dependencies": {}, … … 36 36 }, 37 37 "_id": "buffer-crc32@0.2.1", 38 "_from": "buffer-crc32@0.2.1" 38 "dist": { 39 "shasum": "d4831cc88b961550a88d829efbc0b139caf22d8c" 40 }, 41 "_from": "buffer-crc32@0.2.1", 42 "_resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz" 39 43 } -
Dev/trunk/src/node_modules/express/node_modules/commander/package.json
r484 r487 34 34 "url": "https://github.com/visionmedia/commander.js/issues" 35 35 }, 36 "homepage": "https://github.com/visionmedia/commander.js", 36 37 "_id": "commander@0.6.1", 37 "_from": "commander@0.6.1" 38 "dist": { 39 "shasum": "c725ed5e9b2bf532b3fe3cba4f81b552cecf0550" 40 }, 41 "_from": "commander@0.6.1", 42 "_resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz" 38 43 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/bytes/package.json
r484 r487 17 17 "readmeFilename": "Readme.md", 18 18 "_id": "bytes@0.2.0", 19 "_from": "bytes@0.2.0" 19 "dist": { 20 "shasum": "b4c569295d86a498a119945f1d8a26f76e4b5462" 21 }, 22 "_from": "bytes@0.2.0", 23 "_resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz" 20 24 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/cookie/package.json
r484 r487 32 32 "url": "https://github.com/shtylman/node-cookie/issues" 33 33 }, 34 "homepage": "https://github.com/shtylman/node-cookie", 34 35 "_id": "cookie@0.0.5", 35 "_from": "cookie@0.0.5" 36 "dist": { 37 "shasum": "2597397e06ec3eaf53c88851570e97949c1e4dcd" 38 }, 39 "_from": "cookie@0.0.5", 40 "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.0.5.tgz" 36 41 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/formidable/package.json
r484 r487 35 35 "dependencies": {}, 36 36 "_id": "formidable@1.0.14", 37 "_from": "formidable@1.0.14" 37 "dist": { 38 "shasum": "08be7c89a9ebffbe5b2fbd4df0ad3f5cd19c5147" 39 }, 40 "_from": "formidable@1.0.14", 41 "_resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz" 38 42 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/pause/package.json
r484 r487 17 17 "readmeFilename": "Readme.md", 18 18 "_id": "pause@0.0.1", 19 "_from": "pause@0.0.1" 19 "dist": { 20 "shasum": "dc3b2287742f3f6249f2d228e74cff5a3f9fe8da" 21 }, 22 "_from": "pause@0.0.1", 23 "_resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz" 20 24 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/qs/package.json
r484 r487 33 33 "url": "https://github.com/visionmedia/node-querystring/issues" 34 34 }, 35 "homepage": "https://github.com/visionmedia/node-querystring", 35 36 "_id": "qs@0.6.5", 36 "_from": "qs@0.6.5" 37 "dist": { 38 "shasum": "cdaafb6ed1dbcf48405f41ca92bf95361ad923dc" 39 }, 40 "_from": "qs@0.6.5", 41 "_resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz" 37 42 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/README.md
r484 r487 12 12 13 13 ### mime.lookup(path) 14 Get the mime type associated with a file . Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.14 Get the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g. 15 15 16 16 var mime = require('mime'); … … 20 20 mime.lookup('.TXT'); // => 'text/plain' 21 21 mime.lookup('htm'); // => 'text/html' 22 23 ### mime.default_type 24 Sets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.) 22 25 23 26 ### mime.extension(type) -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/mime.js
r484 r487 70 70 */ 71 71 Mime.prototype.lookup = function(path, fallback) { 72 var ext = path.replace(/.*[\.\/ ]/, '').toLowerCase();72 var ext = path.replace(/.*[\.\/\\]/, '').toLowerCase(); 73 73 74 74 return this.types[ext] || fallback || this.default_type; … … 79 79 */ 80 80 Mime.prototype.extension = function(mimeType) { 81 return this.extensions[mimeType]; 81 var type = mimeType.match(/^\s*([^;\s]*)(?:;|\s|$)/)[1].toLowerCase(); 82 return this.extensions[type]; 82 83 }; 83 84 -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/package.json
r484 r487 25 25 "type": "git" 26 26 }, 27 "version": "1.2. 9",28 "readme": "# mime\n\nComprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n npm install mime\n\n## API - Queries\n\n### mime.lookup(path)\nGet the mime type associated with a file . Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.\n\n var mime = require('mime');\n\n mime.lookup('/path/to/file.txt'); // => 'text/plain'\n mime.lookup('file.txt'); // => 'text/plain'\n mime.lookup('.TXT'); // => 'text/plain'\n mime.lookup('htm'); // => 'text/html'\n\n### mime.extension(type)\nGet the default extension for `type`\n\n mime.extension('text/html'); // => 'html'\n mime.extension('application/octet-stream'); // => 'bin'\n\n### mime.charsets.lookup()\n\nMap mime-type to charset\n\n mime.charsets.lookup('text/plain'); // => 'UTF-8'\n\n(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)\n\n## API - Defining Custom Types\n\nThe following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).\n\n### mime.define()\n\nAdd custom mime/extension mappings\n\n mime.define({\n 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],\n 'application/x-my-type': ['x-mt', 'x-mtt'],\n // etc ...\n });\n\n mime.lookup('x-sft'); // => 'text/x-some-format'\n\nThe first entry in the extensions array is returned by `mime.extension()`. E.g.\n\n mime.extension('text/x-some-format'); // => 'x-sf'\n\n### mime.load(filepath)\n\nLoad mappings from an Apache \".types\" format file\n\n mime.load('./my_project.types');\n\nThe .types file format is simple - See the `types` dir for examples.\n",27 "version": "1.2.11", 28 "readme": "# mime\n\nComprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n npm install mime\n\n## API - Queries\n\n### mime.lookup(path)\nGet the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.\n\n var mime = require('mime');\n\n mime.lookup('/path/to/file.txt'); // => 'text/plain'\n mime.lookup('file.txt'); // => 'text/plain'\n mime.lookup('.TXT'); // => 'text/plain'\n mime.lookup('htm'); // => 'text/html'\n\n### mime.default_type\nSets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.)\n\n### mime.extension(type)\nGet the default extension for `type`\n\n mime.extension('text/html'); // => 'html'\n mime.extension('application/octet-stream'); // => 'bin'\n\n### mime.charsets.lookup()\n\nMap mime-type to charset\n\n mime.charsets.lookup('text/plain'); // => 'UTF-8'\n\n(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)\n\n## API - Defining Custom Types\n\nThe following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).\n\n### mime.define()\n\nAdd custom mime/extension mappings\n\n mime.define({\n 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],\n 'application/x-my-type': ['x-mt', 'x-mtt'],\n // etc ...\n });\n\n mime.lookup('x-sft'); // => 'text/x-some-format'\n\nThe first entry in the extensions array is returned by `mime.extension()`. E.g.\n\n mime.extension('text/x-some-format'); // => 'x-sf'\n\n### mime.load(filepath)\n\nLoad mappings from an Apache \".types\" format file\n\n mime.load('./my_project.types');\n\nThe .types file format is simple - See the `types` dir for examples.\n", 29 29 "readmeFilename": "README.md", 30 30 "bugs": { 31 31 "url": "https://github.com/broofa/node-mime/issues" 32 32 }, 33 "_id": "mime@1.2.9", 33 "homepage": "https://github.com/broofa/node-mime", 34 "_id": "mime@1.2.11", 34 35 "_from": "mime@~1.2.9" 35 36 } -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/test.js
r484 r487 5 5 var mime = require('./mime'); 6 6 var assert = require('assert'); 7 var path = require('path'); 7 8 8 9 function eq(a, b) { … … 18 19 // 19 20 20 eq('text/plain', mime.lookup('text.txt')); 21 eq('text/plain', mime.lookup(' .text.txt'));22 eq('text/plain', mime.lookup(' .txt'));23 eq('text/plain', mime.lookup(' txt'));24 eq(' application/octet-stream', mime.lookup('text.nope'));25 eq(' fallback', mime.lookup('text.fallback', 'fallback'));26 eq(' application/octet-stream', mime.lookup('constructor'));27 eq('text/plain', mime.lookup(' TEXT.TXT'));28 eq(' text/event-stream', mime.lookup('text/event-stream'));29 eq(' application/x-web-app-manifest+json', mime.lookup('text.webapp'));21 eq('text/plain', mime.lookup('text.txt')); // normal file 22 eq('text/plain', mime.lookup('TEXT.TXT')); // uppercase 23 eq('text/plain', mime.lookup('dir/text.txt')); // dir + file 24 eq('text/plain', mime.lookup('.text.txt')); // hidden file 25 eq('text/plain', mime.lookup('.txt')); // nameless 26 eq('text/plain', mime.lookup('txt')); // extension-only 27 eq('text/plain', mime.lookup('/txt')); // extension-less () 28 eq('text/plain', mime.lookup('\\txt')); // Windows, extension-less 29 eq('application/octet-stream', mime.lookup('text.nope')); // unrecognized 30 eq('fallback', mime.lookup('text.fallback', 'fallback')); // alternate default 30 31 31 32 // … … 36 37 eq('html', mime.extension(mime.types.htm)); 37 38 eq('bin', mime.extension('application/octet-stream')); 38 eq(undefined, mime.extension('constructor')); 39 eq('bin', mime.extension('application/octet-stream ')); 40 eq('html', mime.extension(' text/html; charset=UTF-8')); 41 eq('html', mime.extension('text/html; charset=UTF-8 ')); 42 eq('html', mime.extension('text/html; charset=UTF-8')); 43 eq('html', mime.extension('text/html ; charset=UTF-8')); 44 eq('html', mime.extension('text/html;charset=UTF-8')); 45 eq('html', mime.extension('text/Html;charset=UTF-8')); 46 eq(undefined, mime.extension('unrecognized')); 39 47 40 48 // 41 // Test node types49 // Test node.types lookups 42 50 // 43 51 52 eq('application/font-woff', mime.lookup('file.woff')); 44 53 eq('application/octet-stream', mime.lookup('file.buffer')); 45 54 eq('audio/mp4', mime.lookup('file.m4a')); 55 eq('font/opentype', mime.lookup('file.otf')); 46 56 47 57 // … … 53 63 eq('fallback', mime.charsets.lookup('application/octet-stream', 'fallback')); 54 64 65 // 66 // Test for overlaps between mime.types and node.types 67 // 68 69 var apacheTypes = new mime.Mime(), nodeTypes = new mime.Mime(); 70 apacheTypes.load(path.join(__dirname, 'types/mime.types')); 71 nodeTypes.load(path.join(__dirname, 'types/node.types')); 72 73 var keys = [].concat(Object.keys(apacheTypes.types)) 74 .concat(Object.keys(nodeTypes.types)); 75 keys.sort(); 76 for (var i = 1; i < keys.length; i++) { 77 if (keys[i] == keys[i-1]) { 78 console.warn('Warning: ' + 79 'node.types defines ' + keys[i] + '->' + nodeTypes.types[keys[i]] + 80 ', mime.types defines ' + keys[i] + '->' + apacheTypes.types[keys[i]]); 81 } 82 } 83 55 84 console.log('\nOK'); -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/types/mime.types
r484 r487 1055 1055 application/x-font-ttf ttf ttc 1056 1056 application/x-font-type1 pfa pfb pfm afm 1057 application/ x-font-woff woff1057 application/font-woff woff 1058 1058 # application/x-font-vfont 1059 1059 application/x-freearc arc -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/node_modules/mime/types/node.types
r484 r487 16 16 text/x-component htc 17 17 18 # What: HTML5 application cache manifes t18 # What: HTML5 application cache manifes ('.manifest' extension) 19 19 # Why: De-facto standard. Required by Mozilla browser when serving HTML5 apps 20 20 # per https://developer.mozilla.org/en/offline_resources_in_firefox 21 21 # Added by: louisremi 22 text/cache-manifest appcachemanifest22 text/cache-manifest manifest 23 23 24 24 # What: node binary buffer format … … 59 59 # Added by: avoidwork 60 60 text/x-markdown markdown md mkd 61 62 # What: ini files 63 # Why: because they're just text files 64 # Added by: Matthew Kastor 65 text/plain ini 66 67 # What: DASH Adaptive Streaming manifest 68 # Why: https://developer.mozilla.org/en-US/docs/DASH_Adaptive_Streaming_for_HTML_5_Video 69 # Added by: eelcocramer 70 application/dash+xml mdp 71 72 # What: OpenType font files - http://www.microsoft.com/typography/otspec/ 73 # Why: Browsers usually ignore the font MIME types and sniff the content, 74 # but Chrome, shows a warning if OpenType fonts aren't served with 75 # the `font/opentype` MIME type: http://i.imgur.com/8c5RN8M.png. 76 # Added by: alrra 77 font/opentype otf -
Dev/trunk/src/node_modules/express/node_modules/connect/node_modules/send/package.json
r484 r487 37 37 "url": "https://github.com/visionmedia/send/issues" 38 38 }, 39 "homepage": "https://github.com/visionmedia/send", 39 40 "_id": "send@0.1.1", 40 "_from": "send@0.1.1" 41 "dist": { 42 "shasum": "40ded726322604c29d7229683f9207bd6d76e217" 43 }, 44 "_from": "send@0.1.1", 45 "_resolved": "https://registry.npmjs.org/send/-/send-0.1.1.tgz" 41 46 } -
Dev/trunk/src/node_modules/express/node_modules/connect/package.json
r484 r487 49 49 "url": "https://github.com/senchalabs/connect/issues" 50 50 }, 51 "homepage": "https://github.com/senchalabs/connect", 51 52 "_id": "connect@2.7.11", 52 "_from": "connect@2.7.11" 53 "dist": { 54 "shasum": "839e3928b727827db859a4b3a1d04ea9a06b6ab1" 55 }, 56 "_from": "connect@2.7.11", 57 "_resolved": "https://registry.npmjs.org/connect/-/connect-2.7.11.tgz" 53 58 } -
Dev/trunk/src/node_modules/express/node_modules/cookie-signature/package.json
r484 r487 21 21 "readmeFilename": "Readme.md", 22 22 "_id": "cookie-signature@1.0.1", 23 "_from": "cookie-signature@1.0.1" 23 "dist": { 24 "shasum": "404efcace10fb30f3451483045d743463ae8602c" 25 }, 26 "_from": "cookie-signature@1.0.1", 27 "_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz" 24 28 } -
Dev/trunk/src/node_modules/express/node_modules/cookie/package.json
r484 r487 32 32 "url": "https://github.com/shtylman/node-cookie/issues" 33 33 }, 34 "homepage": "https://github.com/shtylman/node-cookie", 34 35 "_id": "cookie@0.1.0", 35 "_from": "cookie@0.1.0" 36 "dist": { 37 "shasum": "b56ac6108fcab9073208d405c4fa8aaa35f00810" 38 }, 39 "_from": "cookie@0.1.0", 40 "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz" 36 41 } -
Dev/trunk/src/node_modules/express/node_modules/debug/Readme.md
r484 r487 1 2 1 # debug 3 2 … … 59 58  60 59 61 When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: 60 When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: 61 _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_ 62 62 63 63  64 64 65 65 ## Conventions 66 66 -
Dev/trunk/src/node_modules/express/node_modules/debug/debug.js
r484 r487 18 18 19 19 return function(fmt){ 20 fmt = coerce(fmt); 21 20 22 var curr = new Date; 21 23 var ms = curr - (debug[name] || curr); … … 120 122 }; 121 123 124 /** 125 * Coerce `val`. 126 */ 127 128 function coerce(val) { 129 if (val instanceof Error) return val.stack || val.message; 130 return val; 131 } 132 122 133 // persist 123 134 124 if (window.localStorage) debug.enable(localStorage.debug); 135 try { 136 if (window.localStorage) debug.enable(localStorage.debug); 137 } catch(e){} -
Dev/trunk/src/node_modules/express/node_modules/debug/lib/debug.js
r484 r487 109 109 110 110 function colored(fmt) { 111 fmt = coerce(fmt); 112 111 113 var curr = new Date; 112 114 var ms = curr - (prev[name] || curr); … … 122 124 123 125 function plain(fmt) { 126 fmt = coerce(fmt); 127 124 128 fmt = new Date().toUTCString() 125 129 + ' ' + name + ' ' + fmt; … … 133 137 : plain; 134 138 } 139 140 /** 141 * Coerce `val`. 142 */ 143 144 function coerce(val) { 145 if (val instanceof Error) return val.stack || val.message; 146 return val; 147 } -
Dev/trunk/src/node_modules/express/node_modules/debug/package.json
r484 r487 1 1 { 2 2 "name": "debug", 3 "version": "0.7. 2",3 "version": "0.7.4", 4 4 "repository": { 5 5 "type": "git", … … 21 21 }, 22 22 "main": "lib/debug.js", 23 "browser ify": "debug.js",23 "browser": "./debug.js", 24 24 "engines": { 25 25 "node": "*" 26 26 }, 27 "files": [ 28 "lib/debug.js", 29 "debug.js", 30 "index.js" 31 ], 27 32 "component": { 28 33 "scripts": { … … 31 36 } 32 37 }, 33 "readme": " \n# debug\n\n tiny node.js debugging utility modelled after node core's debugging technique.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Usage\n\n With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n \n\n \n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n \n\n When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n \n \n\n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",38 "readme": "# debug\n\n tiny node.js debugging utility modelled after node core's debugging technique.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Usage\n\n With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n \n\n \n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n \n\n When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_\n \n \n \n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", 34 39 "readmeFilename": "Readme.md", 35 40 "bugs": { 36 41 "url": "https://github.com/visionmedia/debug/issues" 37 42 }, 38 " _id": "debug@0.7.2",39 "_ from": "debug@*",40 " scripts": {}43 "homepage": "https://github.com/visionmedia/debug", 44 "_id": "debug@0.7.4", 45 "_from": "debug@*" 41 46 } -
Dev/trunk/src/node_modules/express/node_modules/fresh/package.json
r484 r487 17 17 "readmeFilename": "Readme.md", 18 18 "_id": "fresh@0.1.0", 19 "_from": "fresh@0.1.0" 19 "dist": { 20 "shasum": "97ce63fda273b033f866d3a29b9920d034aa2074" 21 }, 22 "_from": "fresh@0.1.0", 23 "_resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz" 20 24 } -
Dev/trunk/src/node_modules/express/node_modules/methods/package.json
r484 r487 17 17 "readme": "ERROR: No README data found!", 18 18 "_id": "methods@0.0.1", 19 "_from": "methods@0.0.1" 19 "dist": { 20 "shasum": "c0a484b3e1f28764c5cfd234e1a156d47092ecca" 21 }, 22 "_from": "methods@0.0.1", 23 "_resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz" 20 24 } -
Dev/trunk/src/node_modules/express/node_modules/mkdirp/package.json
r484 r487 32 32 "url": "https://github.com/substack/node-mkdirp/issues" 33 33 }, 34 "homepage": "https://github.com/substack/node-mkdirp", 34 35 "_id": "mkdirp@0.3.4", 35 "_from": "mkdirp@0.3.4" 36 "dist": { 37 "shasum": "8642eb45b73f5cd19824e94b572871013af8a305" 38 }, 39 "_from": "mkdirp@0.3.4", 40 "_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.4.tgz" 36 41 } -
Dev/trunk/src/node_modules/express/node_modules/range-parser/package.json
r484 r487 17 17 "readmeFilename": "Readme.md", 18 18 "_id": "range-parser@0.0.4", 19 "_from": "range-parser@0.0.4" 19 "dist": { 20 "shasum": "a91c03c737187765f0dcdbe32fa824e52b47a9a6" 21 }, 22 "_from": "range-parser@0.0.4", 23 "_resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz" 20 24 } -
Dev/trunk/src/node_modules/express/node_modules/send/node_modules/mime/package.json
r484 r487 31 31 "url": "https://github.com/broofa/node-mime/issues" 32 32 }, 33 "homepage": "https://github.com/broofa/node-mime", 33 34 "_id": "mime@1.2.6", 34 "_from": "mime@1.2.6" 35 "dist": { 36 "shasum": "193c6817fabeefd6a5f29acabd0b6cebc2c0910f" 37 }, 38 "_from": "mime@1.2.6", 39 "_resolved": "https://registry.npmjs.org/mime/-/mime-1.2.6.tgz" 35 40 } -
Dev/trunk/src/node_modules/express/node_modules/send/package.json
r484 r487 31 31 "readmeFilename": "Readme.md", 32 32 "_id": "send@0.1.0", 33 "_from": "send@0.1.0" 33 "dist": { 34 "shasum": "4ea2b3aca167b22699fdbe4eb5bce35fc57ca7d5" 35 }, 36 "_from": "send@0.1.0", 37 "_resolved": "https://registry.npmjs.org/send/-/send-0.1.0.tgz" 34 38 } -
Dev/trunk/src/node_modules/express/package.json
r484 r487 80 80 "url": "https://github.com/visionmedia/express/issues" 81 81 }, 82 "homepage": "https://github.com/visionmedia/express", 82 83 "_id": "express@3.2.6", 83 "_from": "express@~3.2.3" 84 "dist": { 85 "shasum": "4e16430ceaf29ac1f185c6996d50ca6394ec6357" 86 }, 87 "_from": "express@3.2.6", 88 "_resolved": "https://registry.npmjs.org/express/-/express-3.2.6.tgz" 84 89 } -
Dev/trunk/src/node_modules/tv4/README.md
r484 r487 85 85 ## Cyclical JavaScript objects 86 86 87 While they don't occur in proper JSON, JavaScript does support self-referencing objects. Any of the above calls support an optional final argument, checkRecursive. If true, tv4 will handle self-referencing objects properly - this slows down validation slightly, but that's better than a hanging script.87 While they don't occur in proper JSON, JavaScript does support self-referencing objects. Any of the above calls support an optional third argument: `checkRecursive`. If true, tv4 will handle self-referencing objects properly - this slows down validation slightly, but that's better than a hanging script. 88 88 89 89 Consider this data, notice how both `a` and `b` refer to each other: … … 99 99 ``` 100 100 101 If the final checkRecursiveargument were missing, this would throw a "too much recursion" error.102 103 To enable supp rot for thispass `true` as additional argument to any of the regular validation methods:101 If the `checkRecursive` argument were missing, this would throw a "too much recursion" error. 102 103 To enable support for this, pass `true` as additional argument to any of the regular validation methods: 104 104 105 105 ```javascript 106 106 tv4.validate(a, aSchema, true); 107 tv4.validate(a, schema, asynchronousFunction, true);108 109 107 tv4.validateResult(data, aSchema, true); 110 108 tv4.validateMultiple(data, aSchema, true); 111 109 ``` 112 110 111 ## The `banUnknownProperties` flag 112 113 Sometimes, it is desirable to flag all unknown properties as an error. This is especially useful during development, to catch typos and the like, even when extra custom-defined properties are allowed. 114 115 As such, tv4 implements ["ban unknown properties" mode](https://github.com/json-schema/json-schema/wiki/ban-unknown-properties-mode-\(v5-proposal\)), enabled by a fourth-argument flag: 116 117 ```javascript 118 tv4.validate(data, schema, checkRecursive, true); 119 tv4.validateResult(data, schema, checkRecursive, true); 120 tv4.validateMultiple(data, schema, checkRecursive, true); 121 ``` 122 113 123 ## API 114 124 … … 229 239 ##### addFormat(format, validationFunction) 230 240 231 Add a custom format validator. 241 Add a custom format validator. (There are no built-in format validators.) 232 242 233 243 * `format` is a string, corresponding to the `"format"` value in schemas. -
Dev/trunk/src/node_modules/tv4/package.json
r484 r487 1 1 { 2 2 "name": "tv4", 3 "version": "1.0.1 1",3 "version": "1.0.16", 4 4 "author": { 5 5 "name": "Geraint Luff" … … 51 51 "grunt-markdown": "~0.3.0", 52 52 "grunt-component": "~0.1.4", 53 "grunt-push-release": "~0.1.1" 53 "grunt-push-release": "~0.1.1", 54 "grunt-regex-replace": "~0.2.5" 54 55 }, 55 56 "engines": { … … 57 58 }, 58 59 "scripts": { 59 "test": "grunt test" 60 "test": "grunt test", 61 "prepublish": "grunt prepublish" 60 62 }, 61 "readme": "# Tiny Validator (for v4 JSON Schema)\n\n[](http://travis-ci.org/geraintluff/tv4) [](https://gemnasium.com/geraintluff/tv4) [](http://badge.fury.io/js/tv4)\n\nUse [json-schema](http://json-schema.org/) [draft v4](http://json-schema.org/latest/json-schema-core.html) to validate simple values and complex objects using a rich [validation vocabulary](http://json-schema.org/latest/json-schema-validation.html) ([examples](http://json-schema.org/examples.html)).\n\nThere is support for `$ref` with JSON Pointer fragment paths (```other-schema.json#/properties/myKey```).\n\n## Usage 1: Simple validation\n\n```javascript\nvar valid = tv4.validate(data, schema);\n```\n\nIf validation returns ```false```, then an explanation of why validation failed can be found in ```tv4.error```.\n\nThe error object will look something like:\n```json\n{\n \"code\": 0,\n \"message\": \"Invalid type: string\",\n \"dataPath\": \"/intKey\",\n \"schemaKey\": \"/properties/intKey/type\"\n}\n```\n\nThe `\"code\"` property will refer to one of the values in `tv4.errorCodes` - in this case, `tv4.errorCodes.INVALID_TYPE`.\n\nTo enable external schema to be referenced, you use:\n```javascript\ntv4.addSchema(url, schema);\n```\n\nIf schemas are referenced (```$ref```) but not known, then validation will return ```true``` and the missing schema(s) will be listed in ```tv4.missing```. For more info see the API documentation below.\n\n## Usage 2: Multi-threaded validation\n\nStoring the error and missing schemas does not work well in multi-threaded environments, so there is an alternative syntax:\n\n```javascript\nvar result = tv4.validateResult(data, schema);\n```\n\nThe result will look something like:\n```json\n{\n \"valid\": false,\n \"error\": {...},\n \"missing\": [...]\n}\n```\n\n## Usage 3: Multiple errors\n\nNormally, `tv4` stops when it encounters the first validation error. However, you can collect an array of validation errors using:\n\n```javascript\nvar result = tv4.validateMultiple(data, schema);\n```\n\nThe result will look something like:\n```json\n{\n \"valid\": false,\n \"errors\": [\n {...},\n ...\n ],\n \"missing\": [...]\n}\n```\n\n## Asynchronous validation\n\nSupport for asynchronous validation (where missing schemas are fetched) can be added by including an extra JavaScript file. Currently, the only version requires jQuery (`tv4.async-jquery.js`), but the code is very short and should be fairly easy to modify for other libraries (such as MooTools).\n\nUsage:\n\n```javascript\ntv4.validate(data, schema, function (isValid, validationError) { ... });\n```\n\n`validationFailure` is simply taken from `tv4.error`.\n\n## Cyclical JavaScript objects\n\nWhile they don't occur in proper JSON, JavaScript does support self-referencing objects. Any of the above calls support an optional final argument, checkRecursive. If true, tv4 will handle self-referencing objects properly - this slows down validation slightly, but that's better than a hanging script.\n\nConsider this data, notice how both `a` and `b` refer to each other:\n\n```javascript\nvar a = {};\nvar b = { a: a };\na.b = b;\nvar aSchema = { properties: { b: { $ref: 'bSchema' }}};\nvar bSchema = { properties: { a: { $ref: 'aSchema' }}};\ntv4.addSchema('aSchema', aSchema);\ntv4.addSchema('bSchema', bSchema);\n```\n\nIf the final checkRecursive argument were missing, this would throw a \"too much recursion\" error. \n\nTo enable supprot for this pass `true` as additional argument to any of the regular validation methods: \n\n```javascript\ntv4.validate(a, aSchema, true);\ntv4.validate(a, schema, asynchronousFunction, true);\n\ntv4.validateResult(data, aSchema, true); \ntv4.validateMultiple(data, aSchema, true);\n```\n\n## API\n\nThere are additional api commands available for more complex use-cases:\n\n##### addSchema(uri, schema)\nPre-register a schema for reference by other schema and synchronous validation.\n\n````js\ntv4.addSchema('http://example.com/schema', { ... });\n````\n\n* `uri` the uri to identify this schema.\n* `schema` the schema object.\n\nSchemas that have their `id` property set can be added directly.\n\n````js\ntv4.addSchema({ ... });\n````\n\n##### getSchema(uri)\n\nReturn a schema from the cache.\n\n* `uri` the uri of the schema (may contain a `#` fragment)\n\n````js\nvar schema = tv4.getSchema('http://example.com/schema');\n````\n\n##### getSchemaMap()\n\nReturn a shallow copy of the schema cache, mapping schema document URIs to schema objects.\n\n````\nvar map = tv4.getSchemaMap();\n\nvar schema = map[uri];\n````\n\n##### getSchemaUris(filter)\n\nReturn an Array with known schema document URIs.\n\n* `filter` optional RegExp to filter URIs\n\n````\nvar arr = tv4.getSchemaUris();\n\n// optional filter using a RegExp\nvar arr = tv4.getSchemaUris(/^https?://example.com/);\n````\n\n##### getMissingUris(filter)\n\nReturn an Array with schema document URIs that are used as `$ref` in known schemas but which currently have no associated schema data.\n\nUse this in combination with `tv4.addSchema(uri, schema)` to preload the cache for complete synchronous validation with.\n\n* `filter` optional RegExp to filter URIs\n\n````\nvar arr = tv4.getMissingUris();\n\n// optional filter using a RegExp\nvar arr = tv4.getMissingUris(/^https?://example.com/);\n````\n\n##### dropSchemas()\n\nDrop all known schema document URIs from the cache.\n\n````\ntv4.dropSchemas();\n````\n\n##### freshApi()\n\nReturn a new tv4 instance with no shared state.\n\n````\nvar otherTV4 = tv4.freshApi();\n````\n\n##### reset()\n\nManually reset validation status from the simple `tv4.validate(data, schema)`. Although tv4 will self reset on each validation there are some implementation scenarios where this is useful.\n\n````\ntv4.reset();\n````\n\n##### language(code)\n\nSelect the language map used for reporting.\n\n* `code` is a language code, like `'en'` or `'en-gb'`\n\n````\ntv4.language('en-gb');\n````\n\n##### addLanguage(code, map)\n\nAdd a new language map for selection by `tv4.language(code)`\n\n* `code` is new language code\n* `map` is an object mapping error IDs or constant names (e.g. `103` or `\"NUMBER_MAXIMUM\"`) to language strings.\n\n````\ntv4.addLanguage('fr', { ... });\n\n// select for use\ntv4.language('fr')\n````\n\n##### addFormat(format, validationFunction)\n\nAdd a custom format validator.\n\n* `format` is a string, corresponding to the `\"format\"` value in schemas.\n* `validationFunction` is a function that either returns:\n * `null` (meaning no error)\n * an error string (explaining the reason for failure)\n\n````\ntv4.addFormat('decimal-digits', function (data, schema) {\n\tif (typeof data === 'string' && !/^[0-9]+$/.test(data)) {\n\t\treturn null;\n\t}\n\treturn \"must be string of decimal digits\";\n});\n````\n\nAlternatively, multiple formats can be added at the same time using an object:\n````\ntv4.addFormat({\n\t'my-format': function () {...},\n\t'other-format': function () {...}\n});\n````\n\n## Demos\n\n### Basic usage\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo1\">\n<pre class=\"code\" id=\"demo1\">\nvar schema = {\n\t\"items\": {\n\t\t\"type\": \"boolean\"\n\t}\n};\nvar data1 = [true, false];\nvar data2 = [true, 123];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\nalert(\"data 2 error: \" + JSON.stringify(tv4.error, null, 4));\n</pre>\n</div>\n\n### Use of <code>$ref</code>\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo2\">\n<pre class=\"code\" id=\"demo2\">\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"#\"}\n};\nvar data1 = [[], [[]]];\nvar data2 = [[], [true, []]];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\n</pre>\n</div>\n\n### Missing schema\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo3\">\n<pre class=\"code\" id=\"demo3\">\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"http://example.com/schema\" }\n};\nvar data = [1, 2, 3];\n\nalert(\"Valid: \" + tv4.validate(data, schema)); // true\nalert(\"Missing schemas: \" + JSON.stringify(tv4.missing));\n</pre>\n</div>\n\n### Referencing remote schema\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo4\">\n<pre class=\"code\" id=\"demo4\">\ntv4.addSchema(\"http://example.com/schema\", {\n\t\"definitions\": {\n\t\t\"arrayItem\": {\"type\": \"boolean\"}\n\t}\n});\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"http://example.com/schema#/definitions/arrayItem\" }\n};\nvar data1 = [true, false, true];\nvar data2 = [1, 2, 3];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\n</pre>\n</div>\n\n## Supported platforms\n\n* Node.js\n* All modern browsers\n* IE >= 7\n\n## Installation\n\nYou can manually download [`tv4.js`](https://raw.github.com/geraintluff/tv4/master/tv4.js) or the minified [`tv4.min.js`](https://raw.github.com/geraintluff/tv4/master/tv4.min.js) and include it in your html to create the global `tv4` variable.\n\nAlternately use it as a CommonJS module:\n\n````js\nvar tv4 = require('tv4');\n````\n\n#### npm\n\n````\n$ npm install tv4\n````\n\n#### bower\n\n````\n$ bower install tv4\n````\n\n#### component.io\n\n````\n$ component install geraintluff/tv4\n````\n\n## Build and test\n\nYou can rebuild and run the node and browser tests using node.js and [grunt](http://http://gruntjs.com/):\n\nMake sure you have the global grunt cli command:\n````\n$ npm install grunt-cli -g\n````\n\nClone the git repos, open a shell in the root folder and install the development dependencies:\n\n````\n$ npm install\n````\n\nRebuild and run the tests:\n````\n$ grunt\n````\n\nIt will run a build and display one Spec-style report for the node.js and two Dot-style reports for both the plain and minified browser tests (via phantomJS). You can also use your own browser to manually run the suites by opening [`test/index.html`](http://geraintluff.github.io/tv4/test/index.html) and [`test/index-min.html`](http://geraintluff.github.io/tv4/test/index-min.html).\n\n## Contributing\n\nPull-requests for fixes and expansions are welcome. Edit the partial files in `/source` and add your tests in a suitable suite or folder under `/test/tests` and run `grunt` to rebuild and run the test suite. Try to maintain an idiomatic coding style and add tests for any new features. It is recommend to discuss big changes in an Issue.\n\n## Packages using tv4\n\n* [chai-json-schema](http://chaijs.com/plugins/chai-json-schema) is a [Chai Assertion Library](http://chaijs.com) plugin to assert values against json-schema.\n* [grunt-tv4](http://www.github.com/Bartvds/grunt-tv4) is a plugin for [Grunt](http://http://gruntjs.com/) that uses tv4 to bulk validate json files.\n\n## License\n\nThe code is available as \"public domain\", meaning that it is completely free to use, without any restrictions at all. Read the full license [here](http://geraintluff.github.com/tv4/LICENSE.txt).\n\nIt's also available under an [MIT license](http://jsonary.com/LICENSE.txt).\n",63 "readme": "# Tiny Validator (for v4 JSON Schema)\n\n[](http://travis-ci.org/geraintluff/tv4) [](https://gemnasium.com/geraintluff/tv4) [](http://badge.fury.io/js/tv4)\n\nUse [json-schema](http://json-schema.org/) [draft v4](http://json-schema.org/latest/json-schema-core.html) to validate simple values and complex objects using a rich [validation vocabulary](http://json-schema.org/latest/json-schema-validation.html) ([examples](http://json-schema.org/examples.html)).\n\nThere is support for `$ref` with JSON Pointer fragment paths (```other-schema.json#/properties/myKey```).\n\n## Usage 1: Simple validation\n\n```javascript\nvar valid = tv4.validate(data, schema);\n```\n\nIf validation returns ```false```, then an explanation of why validation failed can be found in ```tv4.error```.\n\nThe error object will look something like:\n```json\n{\n \"code\": 0,\n \"message\": \"Invalid type: string\",\n \"dataPath\": \"/intKey\",\n \"schemaKey\": \"/properties/intKey/type\"\n}\n```\n\nThe `\"code\"` property will refer to one of the values in `tv4.errorCodes` - in this case, `tv4.errorCodes.INVALID_TYPE`.\n\nTo enable external schema to be referenced, you use:\n```javascript\ntv4.addSchema(url, schema);\n```\n\nIf schemas are referenced (```$ref```) but not known, then validation will return ```true``` and the missing schema(s) will be listed in ```tv4.missing```. For more info see the API documentation below.\n\n## Usage 2: Multi-threaded validation\n\nStoring the error and missing schemas does not work well in multi-threaded environments, so there is an alternative syntax:\n\n```javascript\nvar result = tv4.validateResult(data, schema);\n```\n\nThe result will look something like:\n```json\n{\n \"valid\": false,\n \"error\": {...},\n \"missing\": [...]\n}\n```\n\n## Usage 3: Multiple errors\n\nNormally, `tv4` stops when it encounters the first validation error. However, you can collect an array of validation errors using:\n\n```javascript\nvar result = tv4.validateMultiple(data, schema);\n```\n\nThe result will look something like:\n```json\n{\n \"valid\": false,\n \"errors\": [\n {...},\n ...\n ],\n \"missing\": [...]\n}\n```\n\n## Asynchronous validation\n\nSupport for asynchronous validation (where missing schemas are fetched) can be added by including an extra JavaScript file. Currently, the only version requires jQuery (`tv4.async-jquery.js`), but the code is very short and should be fairly easy to modify for other libraries (such as MooTools).\n\nUsage:\n\n```javascript\ntv4.validate(data, schema, function (isValid, validationError) { ... });\n```\n\n`validationFailure` is simply taken from `tv4.error`.\n\n## Cyclical JavaScript objects\n\nWhile they don't occur in proper JSON, JavaScript does support self-referencing objects. Any of the above calls support an optional third argument: `checkRecursive`. If true, tv4 will handle self-referencing objects properly - this slows down validation slightly, but that's better than a hanging script.\n\nConsider this data, notice how both `a` and `b` refer to each other:\n\n```javascript\nvar a = {};\nvar b = { a: a };\na.b = b;\nvar aSchema = { properties: { b: { $ref: 'bSchema' }}};\nvar bSchema = { properties: { a: { $ref: 'aSchema' }}};\ntv4.addSchema('aSchema', aSchema);\ntv4.addSchema('bSchema', bSchema);\n```\n\nIf the `checkRecursive` argument were missing, this would throw a \"too much recursion\" error. \n\nTo enable support for this, pass `true` as additional argument to any of the regular validation methods: \n\n```javascript\ntv4.validate(a, aSchema, true);\ntv4.validateResult(data, aSchema, true); \ntv4.validateMultiple(data, aSchema, true);\n```\n\n## The `banUnknownProperties` flag\n\nSometimes, it is desirable to flag all unknown properties as an error. This is especially useful during development, to catch typos and the like, even when extra custom-defined properties are allowed.\n\nAs such, tv4 implements [\"ban unknown properties\" mode](https://github.com/json-schema/json-schema/wiki/ban-unknown-properties-mode-\\(v5-proposal\\)), enabled by a fourth-argument flag:\n\n```javascript\ntv4.validate(data, schema, checkRecursive, true);\ntv4.validateResult(data, schema, checkRecursive, true);\ntv4.validateMultiple(data, schema, checkRecursive, true);\n```\n\n## API\n\nThere are additional api commands available for more complex use-cases:\n\n##### addSchema(uri, schema)\nPre-register a schema for reference by other schema and synchronous validation.\n\n````js\ntv4.addSchema('http://example.com/schema', { ... });\n````\n\n* `uri` the uri to identify this schema.\n* `schema` the schema object.\n\nSchemas that have their `id` property set can be added directly.\n\n````js\ntv4.addSchema({ ... });\n````\n\n##### getSchema(uri)\n\nReturn a schema from the cache.\n\n* `uri` the uri of the schema (may contain a `#` fragment)\n\n````js\nvar schema = tv4.getSchema('http://example.com/schema');\n````\n\n##### getSchemaMap()\n\nReturn a shallow copy of the schema cache, mapping schema document URIs to schema objects.\n\n````\nvar map = tv4.getSchemaMap();\n\nvar schema = map[uri];\n````\n\n##### getSchemaUris(filter)\n\nReturn an Array with known schema document URIs.\n\n* `filter` optional RegExp to filter URIs\n\n````\nvar arr = tv4.getSchemaUris();\n\n// optional filter using a RegExp\nvar arr = tv4.getSchemaUris(/^https?://example.com/);\n````\n\n##### getMissingUris(filter)\n\nReturn an Array with schema document URIs that are used as `$ref` in known schemas but which currently have no associated schema data.\n\nUse this in combination with `tv4.addSchema(uri, schema)` to preload the cache for complete synchronous validation with.\n\n* `filter` optional RegExp to filter URIs\n\n````\nvar arr = tv4.getMissingUris();\n\n// optional filter using a RegExp\nvar arr = tv4.getMissingUris(/^https?://example.com/);\n````\n\n##### dropSchemas()\n\nDrop all known schema document URIs from the cache.\n\n````\ntv4.dropSchemas();\n````\n\n##### freshApi()\n\nReturn a new tv4 instance with no shared state.\n\n````\nvar otherTV4 = tv4.freshApi();\n````\n\n##### reset()\n\nManually reset validation status from the simple `tv4.validate(data, schema)`. Although tv4 will self reset on each validation there are some implementation scenarios where this is useful.\n\n````\ntv4.reset();\n````\n\n##### language(code)\n\nSelect the language map used for reporting.\n\n* `code` is a language code, like `'en'` or `'en-gb'`\n\n````\ntv4.language('en-gb');\n````\n\n##### addLanguage(code, map)\n\nAdd a new language map for selection by `tv4.language(code)`\n\n* `code` is new language code\n* `map` is an object mapping error IDs or constant names (e.g. `103` or `\"NUMBER_MAXIMUM\"`) to language strings.\n\n````\ntv4.addLanguage('fr', { ... });\n\n// select for use\ntv4.language('fr')\n````\n\n##### addFormat(format, validationFunction)\n\nAdd a custom format validator. (There are no built-in format validators.)\n\n* `format` is a string, corresponding to the `\"format\"` value in schemas.\n* `validationFunction` is a function that either returns:\n * `null` (meaning no error)\n * an error string (explaining the reason for failure)\n\n````\ntv4.addFormat('decimal-digits', function (data, schema) {\n\tif (typeof data === 'string' && !/^[0-9]+$/.test(data)) {\n\t\treturn null;\n\t}\n\treturn \"must be string of decimal digits\";\n});\n````\n\nAlternatively, multiple formats can be added at the same time using an object:\n````\ntv4.addFormat({\n\t'my-format': function () {...},\n\t'other-format': function () {...}\n});\n````\n\n## Demos\n\n### Basic usage\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo1\">\n<pre class=\"code\" id=\"demo1\">\nvar schema = {\n\t\"items\": {\n\t\t\"type\": \"boolean\"\n\t}\n};\nvar data1 = [true, false];\nvar data2 = [true, 123];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\nalert(\"data 2 error: \" + JSON.stringify(tv4.error, null, 4));\n</pre>\n</div>\n\n### Use of <code>$ref</code>\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo2\">\n<pre class=\"code\" id=\"demo2\">\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"#\"}\n};\nvar data1 = [[], [[]]];\nvar data2 = [[], [true, []]];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\n</pre>\n</div>\n\n### Missing schema\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo3\">\n<pre class=\"code\" id=\"demo3\">\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"http://example.com/schema\" }\n};\nvar data = [1, 2, 3];\n\nalert(\"Valid: \" + tv4.validate(data, schema)); // true\nalert(\"Missing schemas: \" + JSON.stringify(tv4.missing));\n</pre>\n</div>\n\n### Referencing remote schema\n<div class=\"content inline-demo\" markdown=\"1\" data-demo=\"demo4\">\n<pre class=\"code\" id=\"demo4\">\ntv4.addSchema(\"http://example.com/schema\", {\n\t\"definitions\": {\n\t\t\"arrayItem\": {\"type\": \"boolean\"}\n\t}\n});\nvar schema = {\n\t\"type\": \"array\",\n\t\"items\": {\"$ref\": \"http://example.com/schema#/definitions/arrayItem\" }\n};\nvar data1 = [true, false, true];\nvar data2 = [1, 2, 3];\n\nalert(\"data 1: \" + tv4.validate(data1, schema)); // true\nalert(\"data 2: \" + tv4.validate(data2, schema)); // false\n</pre>\n</div>\n\n## Supported platforms\n\n* Node.js\n* All modern browsers\n* IE >= 7\n\n## Installation\n\nYou can manually download [`tv4.js`](https://raw.github.com/geraintluff/tv4/master/tv4.js) or the minified [`tv4.min.js`](https://raw.github.com/geraintluff/tv4/master/tv4.min.js) and include it in your html to create the global `tv4` variable.\n\nAlternately use it as a CommonJS module:\n\n````js\nvar tv4 = require('tv4');\n````\n\n#### npm\n\n````\n$ npm install tv4\n````\n\n#### bower\n\n````\n$ bower install tv4\n````\n\n#### component.io\n\n````\n$ component install geraintluff/tv4\n````\n\n## Build and test\n\nYou can rebuild and run the node and browser tests using node.js and [grunt](http://http://gruntjs.com/):\n\nMake sure you have the global grunt cli command:\n````\n$ npm install grunt-cli -g\n````\n\nClone the git repos, open a shell in the root folder and install the development dependencies:\n\n````\n$ npm install\n````\n\nRebuild and run the tests:\n````\n$ grunt\n````\n\nIt will run a build and display one Spec-style report for the node.js and two Dot-style reports for both the plain and minified browser tests (via phantomJS). You can also use your own browser to manually run the suites by opening [`test/index.html`](http://geraintluff.github.io/tv4/test/index.html) and [`test/index-min.html`](http://geraintluff.github.io/tv4/test/index-min.html).\n\n## Contributing\n\nPull-requests for fixes and expansions are welcome. Edit the partial files in `/source` and add your tests in a suitable suite or folder under `/test/tests` and run `grunt` to rebuild and run the test suite. Try to maintain an idiomatic coding style and add tests for any new features. It is recommend to discuss big changes in an Issue.\n\n## Packages using tv4\n\n* [chai-json-schema](http://chaijs.com/plugins/chai-json-schema) is a [Chai Assertion Library](http://chaijs.com) plugin to assert values against json-schema.\n* [grunt-tv4](http://www.github.com/Bartvds/grunt-tv4) is a plugin for [Grunt](http://http://gruntjs.com/) that uses tv4 to bulk validate json files.\n\n## License\n\nThe code is available as \"public domain\", meaning that it is completely free to use, without any restrictions at all. Read the full license [here](http://geraintluff.github.com/tv4/LICENSE.txt).\n\nIt's also available under an [MIT license](http://jsonary.com/LICENSE.txt).\n", 62 64 "readmeFilename": "README.md", 63 65 "bugs": { … … 65 67 }, 66 68 "homepage": "https://github.com/geraintluff/tv4", 67 "_id": "tv4@1.0.11", 68 "_from": "tv4@" 69 "_id": "tv4@1.0.16", 70 "dist": { 71 "shasum": "f35372c01e94355b7aaff5860455fd231e2d9802" 72 }, 73 "_from": "tv4@1.0.16", 74 "_resolved": "https://registry.npmjs.org/tv4/-/tv4-1.0.16.tgz" 69 75 } -
Dev/trunk/src/node_modules/tv4/tv4.async-jquery.js
r484 r487 4 4 if (typeof (tv4.asyncValidate) === 'undefined') { 5 5 tv4.syncValidate = tv4.validate; 6 tv4.validate = function (data, schema, callback, checkRecursive ) {6 tv4.validate = function (data, schema, callback, checkRecursive, banUnknownProperties) { 7 7 if (typeof (callback) === 'undefined') { 8 return this.syncValidate(data, schema, checkRecursive );8 return this.syncValidate(data, schema, checkRecursive, banUnknownProperties); 9 9 } else { 10 return this.asyncValidate(data, schema, callback, checkRecursive );10 return this.asyncValidate(data, schema, callback, checkRecursive, banUnknownProperties); 11 11 } 12 12 }; 13 tv4.asyncValidate = function (data, schema, callback, checkRecursive ) {13 tv4.asyncValidate = function (data, schema, callback, checkRecursive, banUnknownProperties) { 14 14 var $ = jQuery; 15 var result = tv4.validate(data, schema, checkRecursive );15 var result = tv4.validate(data, schema, checkRecursive, banUnknownProperties); 16 16 if (!tv4.missing.length) { 17 17 callback(result, tv4.error); … … 28 28 // When all requests done, try again 29 29 $.when.apply($, missingSchemas).done(function () { 30 var result = tv4.asyncValidate(data, schema, callback, checkRecursive );30 var result = tv4.asyncValidate(data, schema, callback, checkRecursive, banUnknownProperties); 31 31 }); 32 32 } -
Dev/trunk/src/node_modules/tv4/tv4.js
r484 r487 133 133 this.scannedFrozen = []; 134 134 this.scannedFrozenSchemas = []; 135 this.key = 'tv4_validation_id'; 135 this.scannedFrozenValidationErrors = []; 136 this.validatedSchemasKey = 'tv4_validation_id'; 137 this.validationErrorsKey = 'tv4_validation_errors_id'; 136 138 } 137 139 if (trackUnknownProperties) { … … 240 242 }; 241 243 ValidatorContext.prototype.searchSchemas = function (schema, url) { 242 if ( typeof schema.id === "string") {243 if ( isTrustedUrl(url, schema.id)) {244 if ( this.schemas[schema.id] === undefined) {245 this.schemas[schema.id] = schema;246 }247 }248 }249 if (typeof schema === "object") {244 if (schema && typeof schema === "object") { 245 if (typeof schema.id === "string") { 246 if (isTrustedUrl(url, schema.id)) { 247 if (this.schemas[schema.id] === undefined) { 248 this.schemas[schema.id] = schema; 249 } 250 } 251 } 250 252 for (var key in schema) { 251 253 if (key !== "enum") { … … 264 266 ValidatorContext.prototype.addSchema = function (url, schema) { 265 267 //overload 266 if (typeof schema === 'undefined') {268 if (typeof url !== 'string' || typeof schema === 'undefined') { 267 269 if (typeof url === 'object' && typeof url.id === 'string') { 268 270 schema = url; … … 331 333 } 332 334 333 if (this.checkRecursive && (typeof data) === 'object') { 335 var startErrorCount = this.errors.length; 336 var frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null; 337 if (this.checkRecursive && data && typeof data === 'object') { 334 338 topLevel = !this.scanned.length; 335 if (data[this.key] && data[this.key].indexOf(schema) !== -1) { return null; } 336 var frozenIndex; 339 if (data[this.validatedSchemasKey]) { 340 var schemaIndex = data[this.validatedSchemasKey].indexOf(schema); 341 if (schemaIndex !== -1) { 342 this.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]); 343 return null; 344 } 345 } 337 346 if (Object.isFrozen(data)) { 338 347 frozenIndex = this.scannedFrozen.indexOf(data); 339 if (frozenIndex !== -1 && this.scannedFrozenSchemas[frozenIndex].indexOf(schema) !== -1) { return null; } 348 if (frozenIndex !== -1) { 349 var frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema); 350 if (frozenSchemaIndex !== -1) { 351 this.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]); 352 return null; 353 } 354 } 340 355 } 341 356 this.scanned.push(data); … … 346 361 this.scannedFrozenSchemas.push([]); 347 362 } 348 this.scannedFrozenSchemas[frozenIndex].push(schema); 363 scannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length; 364 this.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema; 365 this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = []; 349 366 } else { 350 if (!data[this. key]) {367 if (!data[this.validatedSchemasKey]) { 351 368 try { 352 Object.defineProperty(data, this.key, { 369 Object.defineProperty(data, this.validatedSchemasKey, { 370 value: [], 371 configurable: true 372 }); 373 Object.defineProperty(data, this.validationErrorsKey, { 353 374 value: [], 354 375 configurable: true … … 356 377 } catch (e) { 357 378 //IE 7/8 workaround 358 data[this.key] = []; 359 } 360 } 361 data[this.key].push(schema); 379 data[this.validatedSchemasKey] = []; 380 data[this.validationErrorsKey] = []; 381 } 382 } 383 scannedSchemasIndex = data[this.validatedSchemasKey].length; 384 data[this.validatedSchemasKey][scannedSchemasIndex] = schema; 385 data[this.validationErrorsKey][scannedSchemasIndex] = []; 362 386 } 363 387 } … … 376 400 while (this.scanned.length) { 377 401 var item = this.scanned.pop(); 378 delete item[this. key];402 delete item[this.validatedSchemasKey]; 379 403 } 380 404 this.scannedFrozen = []; … … 391 415 this.prefixErrors(errorCount, dataPart, schemaPart); 392 416 } 417 } 418 419 if (scannedFrozenSchemaIndex !== null) { 420 this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount); 421 } else if (scannedSchemasIndex !== null) { 422 data[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount); 393 423 } 394 424 … … 996 1026 } 997 1027 function normSchema(schema, baseUri) { 998 if ( baseUri === undefined) {999 baseUri = schema.id;1000 } else if (typeof schema.id === "string") {1001 baseUri = resolveUrl(baseUri, schema.id);1002 schema.id = baseUri;1003 }1004 if (typeof schema === "object") {1028 if (schema && typeof schema === "object") { 1029 if (baseUri === undefined) { 1030 baseUri = schema.id; 1031 } else if (typeof schema.id === "string") { 1032 baseUri = resolveUrl(baseUri, schema.id); 1033 schema.id = baseUri; 1034 } 1005 1035 if (Array.isArray(schema)) { 1006 1036 for (var i = 0; i < schema.length; i++) { … … 1050 1080 FORMAT_CUSTOM: 500, 1051 1081 // Schema structure 1052 CIRCULAR_REFERENCE: 500,1082 CIRCULAR_REFERENCE: 600, 1053 1083 // Non-standard validation options 1054 1084 UNKNOWN_PROPERTY: 1000 … … 1091 1121 1092 1122 function ValidationError(code, message, dataPath, schemaPath, subErrors) { 1123 Error.call(this); 1093 1124 if (code === undefined) { 1094 1125 throw new Error ("No code supplied for error: "+ message); 1095 1126 } 1127 this.message = message; 1096 1128 this.code = code; 1097 this.message = message;1098 1129 this.dataPath = dataPath || ""; 1099 1130 this.schemaPath = schemaPath || ""; 1100 1131 this.subErrors = subErrors || null; 1101 } 1102 ValidationError.prototype = new Error(); 1132 1133 var err = new Error(this.message); 1134 this.stack = err.stack || err.stacktrace; 1135 if (!this.stack) { 1136 try { 1137 throw err; 1138 } 1139 catch(err) { 1140 this.stack = err.stack || err.stacktrace; 1141 } 1142 } 1143 } 1144 ValidationError.prototype = Object.create(Error.prototype); 1145 ValidationError.prototype.constructor = ValidationError; 1146 ValidationError.prototype.name = 'ValidationError'; 1147 1103 1148 ValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) { 1104 1149 if (dataPrefix !== null) { … … 1265 1310 1266 1311 })(this); 1267 1268 //@ sourceMappingURL=tv4.js.map -
Dev/trunk/src/package.json
r479 r487 4 4 "description": "QED Server", 5 5 "dependencies": { 6 "express": "~3.2. 3",6 "express": "~3.2.6", 7 7 "underscore": "~1.4.4", 8 8 "passport": "~0.1.17", … … 11 11 "request": "~2.21.0", 12 12 "ya-csv": "~0.9.2", 13 "tv4": "~1.0.1 1"13 "tv4": "~1.0.16" 14 14 }, 15 15 "engines": { -
Dev/trunk/src/server/app.js
r481 r487 9 9 , _ = require("underscore") 10 10 , tv4 = require("tv4") 11 , HTTPResult = require("./util/http-result") 12 , etags = require("./util/etags") 13 , cryptoken = require('./util/crypto-token') 11 14 ; 12 15 … … 22 25 exports.App = function(settings) { 23 26 24 assertSetting("couchDbURL", settings, _.isString); 25 var couch = new CouchDB(settings.couchDbURL); 27 assertSetting("couchServerURL", settings, _.isString); 28 assertSetting("dbName", settings, _.isString); 29 var couch = new CouchDB(settings.couchServerURL,settings.dbName); 26 30 27 31 var schema = require("./config/couchdb-schema.json"); … … 69 73 app.use(passport.initialize()); 70 74 app.use(passport.session()); 75 76 // various middlewares 71 77 function ensureAuthenticated(req,res,next){ 72 78 if (!req.user) { … … 78 84 function returnUser(req,res) { 79 85 res.send(200, req.user); 86 } 87 function notImplemented(req,res) { 88 res.send(501,{error:"API not implemented yet."}); 80 89 } 81 90 … … 112 121 }); 113 122 123 var JSON_MIME = 'application/json'; 124 var CSV_MIME = 'application/json'; 125 function ensureMIME(mimeType) { 126 return function(req,res,next) { 127 if (!req.accepts(mimeType)) { 128 res.send(406); 129 } else { 130 res.set({ 131 'Content-Type': mimeType 132 }); 133 next(); 134 } 135 }; 136 } 137 138 function stripAndReturnPrivates(obj) { 139 var priv = {}; 140 _.each(obj||{},function(val,key){ 141 if (key.substring(0,1) === '_') { 142 priv[key] = val; 143 delete obj[key]; 144 } 145 }); 146 return priv; 147 } 148 149 function identity(obj) { return obj; } 150 function handleUnknownResponse(status,error){ 151 return new HTTPResult(500,{error: "Unexpected database response", 152 innerStatus: status, innerResponse: error}); 153 } 154 function handleUnknownError(error){ 155 return new HTTPResult(500, {error: "Unknown error", innerError: error}); 156 } 157 function handleRowValues(result) { 158 return _.map(result.rows, function(item) { return item.value; }); 159 } 160 function handleRowDocs(result) { 161 return _.map(result.rows, function(item) { return item.doc; }); 162 } 163 164 function getDocumentsOfType (type) { 165 var url = '_design/default/_view/by_type?key='+JSON.stringify(type); 166 return HTTPResult.fromResponsePromise(couch.get(url).response, 167 handleUnknownError) 168 .handle({ 169 200: handleRowValues, 170 404: function() { return {error: "Cannot find collection of type "+type}; }, 171 default: handleUnknownResponse 172 }); 173 } 174 function getDocument(id,rev,type) { 175 var opts = {headers:{}}; 176 if (rev) { 177 opts.headers['If-Non-Match'] = '"'+rev+'"'; 178 } 179 return HTTPResult.fromResponsePromise(couch.get(id,opts).response, 180 handleUnknownError) 181 .handle({ 182 200: function(doc){ 183 if ( doc.type !== type ) { 184 return new HTTPResult(404,{error:"Document not found."}); 185 } else { 186 var priv = stripAndReturnPrivates(doc); 187 if ( priv._rev !== rev ) { 188 doc._id = priv._id; 189 doc._rev = priv._rev; 190 return doc; 191 } else { 192 return new HTTPResult(304); 193 } 194 } 195 }, 196 304: identity, 197 default: handleUnknownResponse 198 }); 199 } 200 function putDocument(id,rev,type,doc) { 201 var priv = stripAndReturnPrivates(doc); 202 if ( doc.type === type && tv4.validateResult(doc, schema) ) { 203 var opts = rev ? {headers:{'If-Match':'"'+rev+'"'}} : {}; 204 return HTTPResult.fromResponsePromise(couch.put(id,doc,opts).response, 205 handleUnknownError) 206 .handle({ 207 201: function(res){ 208 doc._id = res.id; 209 doc._rev = res.rev; 210 return doc; 211 }, 212 409: function(error) { 213 return {error: error.reason}; 214 }, 215 default: handleUnknownResponse 216 }); 217 } else { 218 return new HTTPResult(400,{error: "Document failed schema verification."}); 219 } 220 } 221 function deleteDocument(id,rev) { 222 if ( rev ) { 223 var opts = {headers:{'If-Match':'"'+rev+'"'}}; 224 return HTTPResult.fromResponsePromise(couch.delete(id,opts).response, 225 handleUnknownError) 226 .handle({ 227 200: identity, 228 409: function(error) { 229 return {error: error.reason}; 230 }, 231 default: handleUnknownResponse 232 }); 233 } else { 234 return new HTTPResult(409, {error: "Cannot identify document revision to delete."}); 235 } 236 } 237 function postDocument(type,doc) { 238 var priv = stripAndReturnPrivates(doc); 239 if ( doc.type === type && tv4.validateResult(doc, schema) ) { 240 return HTTPResult.fromResponsePromise(couch.post(doc).response, 241 handleUnknownError) 242 .handle({ 243 201: function(response) { 244 doc._id = response.id; 245 doc._rev = response.rev; 246 return doc; 247 }, 248 default: handleUnknownResponse 249 }); 250 } else { 251 return new HTTPResult(400,{error: "Document failed schema verification."}); 252 } 253 } 254 114 255 function makeDocsGet(type) { 115 256 return function(req,res) { 116 var url = '_design/default/_view/by_type?key='+JSON.stringify(type); 117 couch.get(url).then(function(result){ 118 var items = _.map(result.rows, function(item) { return item.value; }); 119 res.send(200, items); 120 }, function(error){ 121 res.send(404, {error: "Cannot find collection"}); 257 getDocumentsOfType(type) 258 .handle(res.send.bind(res)); 259 }; 260 } 261 function makeDocGet_id(type) { 262 return function(req,res) { 263 var id = req.params.id; 264 var rev = etags.parse(req.header('If-Non-Match'))[0]; 265 getDocument(id,rev,type) 266 .handle({ 267 200: function(doc){ 268 res.set({ 269 'ETag': etags.format([doc._rev]) 270 }).send(200, doc); 271 }, 272 default: res.send.bind(res) 122 273 }); 123 274 }; 124 275 } 125 function makeDoc Get_id(type) {276 function makeDocPut_id(type) { 126 277 return function(req,res) { 127 278 var id = req.params.id; 128 couch.get(id).then(function(result){ 129 if ( result.type === type ) { 130 res.send(200, result); 131 } else { 132 res.send(404, {error: "Document "+id+" is not a "+type}); 133 } 134 }, function(error){ 135 res.send(404, {error: "Cannot find survey run "+id}); 279 var doc = req.body; 280 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 281 putDocument(id,rev,type,doc) 282 .handle({ 283 201: function(doc) { 284 res.set({ 285 'ETag': etags.format([doc._rev]) 286 }).send(201, doc); 287 }, 288 default: res.send.bind(res) 136 289 }); 137 290 }; 138 291 } 139 function makeDoc Put_id(type) {292 function makeDocDel_id(type) { 140 293 return function(req,res) { 141 294 var id = req.params.id; 142 295 var doc = req.body; 143 if ( doc.type === type && tv4.validateResult(doc, schema) ) { 144 couch.put(id,doc).then(function(result){ 145 res.send(200, result); 146 }, function(error){ 147 res.send(500, error); 296 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 297 deleteDocument(id,rev) 298 .handle(res.send.bind(res)); 299 }; 300 } 301 function makeDocPost(type) { 302 return function(req,res) { 303 var doc = req.body; 304 postDocument(type,doc) 305 .handle({ 306 201: function(doc) { 307 res.set({ 308 'ETag': etags.format([doc._rev]) 309 }).send(201, doc); 310 }, 311 default: res.send.bind(res) 312 }); 313 }; 314 } 315 316 // Questions 317 function getQuestionsWithCode(code) { 318 var url = '_design/questions/_view/by_code'; 319 var query = {include_docs:true,key:code}; 320 return HTTPResult.fromResponsePromise(couch.get(url,{query:query}).response, 321 handleUnknownError) 322 .handle({ 323 200: handleRowDocs, 324 default: handleUnknownResponse 325 }); 326 } 327 function getQuestionsWithTopic(topic) { 328 var url = '_design/questions/_view/all_topics'; 329 var query = {reduce:false,include_docs:true,key:topic}; 330 return HTTPResult.fromResponsePromise(couch.get(url,{query:query}).response, 331 handleUnknownError) 332 .handle({ 333 200: handleRowDocs, 334 default: handleUnknownResponse 335 }); 336 } 337 function getQuestionsWithCategoryAndTopic(category,topic) { 338 var hasTopic = typeof topic !== 'undefined'; 339 var url = '_design/questions/_view/all'; 340 var query = {reduce:false,include_docs:true, 341 startkey:hasTopic?[category,topic]:[category], 342 endkey:hasTopic?[category,topic]:[category,{}]}; 343 return HTTPResult.fromResponsePromise(couch.get(url,{query:query}).response, 344 handleUnknownError) 345 .handle({ 346 200: handleRowDocs, 347 default: handleUnknownResponse 348 }); 349 } 350 app.get('/api/questions', 351 ensureAuthenticated, 352 ensureMIME(JSON_MIME), 353 function(req,res) { 354 var hr; 355 if ( 'category' in req.query ) { 356 hr = getQuestionsWithCategoryAndTopic(req.query.category,req.query.topic); 357 } else if ( 'topic' in req.query ) { 358 hr = getQuestionsWithTopic(req.query.topic); 359 } else if ( 'code' in req.query ) { 360 hr = getQuestionsWithCode(req.query.code); 361 } 362 hr.handle(res.send.bind(res)); 363 }); 364 app.post('/api/questions', 365 ensureAuthenticated, 366 ensureMIME(JSON_MIME), 367 function (req,res) { 368 var doc = req.body; 369 getQuestionsWithCode(doc.code) 370 .handle({ 371 200: function(others) { 372 if ( others.length > 0 ) { 373 return new HTTPResult(403,{error:"Other question with this code already exists."}); 374 } else { 375 return postDocument('Question',doc); 376 } 377 } 378 }) 379 .handle(res.send.bind(res)); 380 }); 381 app.get('/api/questions/:id', 382 ensureAuthenticated, 383 ensureMIME(JSON_MIME), 384 makeDocGet_id('Question')); 385 app.put('/api/questions/:id', 386 ensureAuthenticated, 387 ensureMIME(JSON_MIME), 388 function (req,res) { 389 var id = req.params.id; 390 var doc = req.body; 391 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 392 getQuestionsWithCode(doc.code) 393 .handle({ 394 200: function(others) { 395 if ( others.length > 0 ) { 396 return new HTTPResult(403,{error:"Other question with this code already exists."}); 397 } else { 398 return putDocument(id,rev,'Question',doc); 399 } 400 } 401 }) 402 .handle(res.send.bind(res)); 403 }); 404 app.delete('/api/questions/:id', 405 ensureAuthenticated, 406 ensureMIME(JSON_MIME), 407 makeDocDel_id('Question')); 408 409 410 // Categories and topics 411 app.get('/api/categories', 412 ensureAuthenticated, 413 ensureMIME(JSON_MIME), 414 function(req,res) { 415 var url = '_design/questions/_view/all'; 416 HTTPResult.fromResponsePromise(couch.get(url,{query:{reduce:true,group:true,group_level:1}}).response, 417 handleUnknownError) 418 .handle({ 419 200: function(result) { 420 return _.map(result.rows, function(item) { 421 return { name:item.key[0], count:item.value }; 422 }); 423 }, 424 default: handleUnknownResponse 425 }) 426 .handle(res.send.bind(res)); 427 }); 428 app.get('/api/categories/:category/topics', 429 ensureAuthenticated, 430 ensureMIME(JSON_MIME), 431 function(req,res) { 432 var category = req.params.category; 433 var url = '_design/questions/_view/all'; 434 HTTPResult.fromResponsePromise(couch.get(url,{query:{reduce:true,group:true,group_level:2,startkey:[category],endkey:[category,{}]}}).response, 435 handleUnknownError) 436 .handle({ 437 200: function(result) { 438 return _.map(result.rows, function(item) { return { name:item.key[1], count:item.value }; }); 439 }, 440 default: handleUnknownResponse 441 }) 442 .handle(res.send.bind(res)); 443 }); 444 app.get('/api/topics', 445 ensureAuthenticated, 446 ensureMIME(JSON_MIME), 447 function(req,res) { 448 var url = '_design/questions/_view/all_topics'; 449 HTTPResult.fromResponsePromise(couch.get(url,{query:{reduce:true,group:true}}).response, 450 handleUnknownError) 451 .handle({ 452 200: function(result) { 453 return _.map(result.rows, function(item) { return {name:item.key, count:item.value}; }); 454 }, 455 default: handleUnknownResponse 456 }) 457 .handle(res.send.bind(res)); 458 }); 459 460 // Surveys 461 app.get('/api/surveys', 462 ensureAuthenticated, 463 ensureMIME(JSON_MIME), 464 function(req,res) { 465 var url; 466 if ( 'drafts' in req.query ) { 467 url = '_design/surveys/_view/drafts'; 468 } else if ( 'published' in req.query ) { 469 url = '_design/surveys/_view/published'; 470 } else { 471 url = '_design/default/_view/by_type?key='+JSON.stringify('Survey'); 472 } 473 HTTPResult.fromResponsePromise(couch.get(url).response, 474 handleUnknownError) 475 .handle({ 476 200: function(result) { 477 return _.map(result.rows, function(item) { return item.value; }); 478 }, 479 default: handleUnknownResponse 480 }) 481 .handle(res.send.bind(res)); 482 }); 483 app.post('/api/surveys', 484 ensureAuthenticated, 485 ensureMIME(JSON_MIME), 486 makeDocPost('Survey')); 487 app.get('/api/surveys/:id', 488 ensureAuthenticated, 489 ensureMIME(JSON_MIME), 490 makeDocGet_id('Survey')); 491 app.put('/api/surveys/:id', 492 ensureAuthenticated, 493 ensureMIME(JSON_MIME), 494 makeDocPut_id('Survey')); 495 app.delete('/api/surveys/:id', 496 ensureAuthenticated, 497 ensureMIME(JSON_MIME), 498 makeDocDel_id('Survey')); 499 500 // SurveyRuns 501 app.get('/api/surveyRuns', 502 ensureAuthenticated, 503 ensureMIME(JSON_MIME), 504 makeDocsGet('SurveyRun')); 505 app.post('/api/surveyRuns', 506 ensureAuthenticated, 507 ensureMIME(JSON_MIME), 508 function(req,res) { 509 var doc = req.body; 510 randomToken() 511 .handle({ 512 201: function(token) { 513 doc.secret = token; 514 return postDocument('SurveyRun',doc); 515 } 516 }) 517 .handle(res.send.bind(res)); 518 }); 519 app.get('/api/surveyRuns/:id', 520 ensureAuthenticated, 521 ensureMIME(JSON_MIME), 522 makeDocGet_id('SurveyRun')); 523 app.put('/api/surveyRuns/:id', 524 ensureAuthenticated, 525 ensureMIME(JSON_MIME), 526 function (req,res) { 527 var id = req.params.id; 528 var doc = req.body; 529 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 530 var hr; 531 if ( typeof doc.secret === 'undefined' ) { 532 hr = randomToken() 533 .handle({ 534 201: function(token) { 535 doc.secret = token; 536 return putDocument(id,rev,'SurveyRun',doc); 537 } 148 538 }); 149 539 } else { 150 res.send(400,{error: "Document failed schema verification."});540 hr = putDocument(id,rev,'SurveyRun',doc); 151 541 } 152 }; 153 } 154 function makeDocDel_id(type) { 155 return function(req,res) { 156 var id = req.params.id; 157 var rev = req.query.rev; 158 couch.delete(id,rev).then(function(result){ 159 res.send(200, result); 160 }, function(error){ 161 res.send(500, error); 542 hr.handle(res.send.bind(res)); 543 }); 544 app.delete('/api/surveyRuns/:id', 545 ensureAuthenticated, 546 ensureMIME(JSON_MIME), 547 makeDocDel_id('SurveyRun')); 548 app.get('/api/surveyRuns/:id/responses', 549 ensureAuthenticated, 550 ensureMIME(JSON_MIME), 551 function(req,res) { 552 var id = req.params.id; 553 getResponsesBySurveyRunId(id) 554 .handle(res.send.bind(res)); 555 }); 556 app.get('/api/surveyRuns/:id/responses.csv', 557 ensureAuthenticated, 558 ensureMIME(CSV_MIME), 559 function(req, res) { 560 var id = req.params.id; 561 getResponsesBySurveyRunId(id) 562 .handle({ 563 200: function(responses) { 564 var flatResponses = responsesToVariables(responses); 565 res.set({ 566 'Content-Disposition': 'attachment; filename=surveyRun-'+id+'-responses.csv' 567 }); 568 res.status(200); 569 writeObjectsToCSVStream(flatResponses, res); 570 res.end(); 571 }, 572 default: res.send.bind(res) 162 573 }); 163 }; 164 } 165 function makeDocPost(type) { 166 return function(req,res) { 167 var doc = req.body; 168 if ( doc.type === type && tv4.validateResult(doc, schema) ) { 169 couch.post(req.body).then(function(result){ 170 res.send(200, result); 171 }, function(error){ 172 res.send(500, error); 574 }); 575 576 // Responses 577 function getResponsesBySurveyRunId(surveyRunId) { 578 var url = '_design/responses/_view/by_surveyrun?key='+JSON.stringify(surveyRunId); 579 return HTTPResult.fromResponsePromise(couch.get(url).response, 580 handleUnknownError) 581 .handle({ 582 200: handleRowValues, 583 default: handleUnknownResponse 584 }); 585 } 586 app.get('/api/responses', 587 ensureAuthenticated, 588 ensureMIME(JSON_MIME), 589 function(req,res){ 590 var hr; 591 if ( 'surveyRunId' in req.query ) { 592 hr = getResponsesBySurveyRunId(req.query.surveyRunId); 593 } else { 594 hr = getDocumentsOfType('Response'); 595 } 596 hr.handle(res.send.bind(res)); 597 }); 598 app.get('/api/responses/:id', 599 ensureAuthenticated, 600 ensureMIME(JSON_MIME), 601 makeDocGet_id('Response')); 602 app.post('/api/responses', 603 ensureAuthenticated, 604 ensureMIME(JSON_MIME), 605 function (req,res) { 606 var doc = req.body; 607 randomToken() 608 .handle({ 609 201: function(token) { 610 doc.secret = token; 611 return postDocument('Response',doc); 612 } 613 }) 614 .handle(res.send.bind(res)); 615 }); 616 app.put('/api/responses/:id', 617 ensureAuthenticated, 618 ensureMIME(JSON_MIME), 619 function (req,res) { 620 var id = req.params.id; 621 var doc = req.body; 622 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 623 var hr; 624 if ( typeof doc.secret === 'undefined' ) { 625 hr = randomToken() 626 .handle({ 627 201: function(token) { 628 doc.secret = token; 629 return putDocument(id,rev,'Response',doc); 630 } 173 631 }); 174 632 } else { 175 res.send(400,{error: "Document failed schema verification."});633 hr = putDocument(id,rev,'Response',doc); 176 634 } 177 }; 178 } 179 function notImplemented(req,res) { 180 res.send(501,{error:"API not implemented yet."}); 181 } 182 183 // Questions 184 app.get('/api/questions', 185 ensureAuthenticated, 186 makeDocsGet('Question')); 187 app.get('/api/questions/:id', 188 ensureAuthenticated, 189 makeDocGet_id('Question')); 190 app.post('/api/questions', 191 ensureAuthenticated, 192 makeDocPost('Question')); 193 app.put('/api/questions/:id', 194 ensureAuthenticated, 195 makeDocPut_id('Question')); 196 app.delete('/api/questions/:id', 197 ensureAuthenticated, 198 makeDocDel_id('Question')); 199 app.get('/api/questions/categories', 200 ensureAuthenticated, 201 notImplemented); 202 203 // Surveys 204 app.get('/api/surveys', 205 ensureAuthenticated, 206 makeDocsGet('Survey')); 207 app.get('/api/surveys/:id', 208 ensureAuthenticated, 209 makeDocGet_id('Survey')); 210 app.post('/api/surveys', 211 ensureAuthenticated, 212 makeDocPost('Survey')); 213 app.put('/api/surveys/:id', 214 ensureAuthenticated, 215 makeDocPut_id('Survey')); 216 app.delete('/api/surveys/:id', 217 ensureAuthenticated, 218 makeDocDel_id('Survey')); 219 220 // SurveyRuns 221 app.get('/api/surveyRuns', 222 ensureAuthenticated, 223 makeDocsGet('SurveyRun')); 224 app.get('/api/surveyRuns/:id', 225 ensureAuthenticated, 226 makeDocGet_id('SurveyRun')); 227 app.get('/api/surveyRuns/:id/responses.csv', 228 ensureAuthenticated, 229 function(req, res) { 230 var id = req.params.id; 231 var url = '_design/responses/_view/by_surveyrun?key='+JSON.stringify(id); 232 couch.get(url).then(function(result){ 233 var responses = _.map(result.rows, function(item) { return item.value; }); 234 var flatResponses = responsesToVariables(responses); 235 res.set({ 236 'Content-Type': 'text/csv', 237 'Content-Disposition': 'attachment; filename=surveyRun-'+id+'-responses.csv' 238 }); 239 res.status(200); 240 writeObjectsToCSVStream(flatResponses, res); 241 res.end(); 242 }, function(error){ 243 res.send(404, {error: "Cannot find responses for survey run "+id}); 244 }); 245 }); 246 app.get('/api/surveyRuns/:id/responses', 247 ensureAuthenticated, 635 hr.handle(res.send.bind(res)); 636 }); 637 app.delete('/api/responses/:id', 638 ensureAuthenticated, 639 ensureMIME(JSON_MIME), 640 makeDocDel_id('Response')); 641 642 //respondents api 643 function isSurveyRunRunning(surveyRun) { 644 var now = new Date(); 645 var afterStart = !surveyRun.startDate || now >= new Date(surveyRun.startDate); 646 var beforeEnd = !surveyRun.endDate || now <= new Date(surveyRun.endDate); 647 return afterStart && beforeEnd; 648 } 649 app.get('/api/open/responses/:id', 650 ensureMIME(JSON_MIME), 248 651 function(req,res) { 249 652 var id = req.params.id; 250 var url = '_design/responses/_view/by_surveyrun?key='+JSON.stringify(id); 251 couch.get(url).then(function(result){ 252 var responses = _.map(result.rows, function(item) { return item.value; }); 253 res.send(200, responses); 254 }, function(error){ 255 res.send(404, {error: "Cannot find responses for survey run "+id}); 256 }); 257 }); 258 259 // Responses 260 app.get('/api/responses', 261 ensureAuthenticated, 262 makeDocsGet('Response')); 263 app.get('/api/responses/:id', 264 ensureAuthenticated, 265 makeDocGet_id('Response')); 266 app.post('/api/responses', 267 ensureAuthenticated, 268 makeDocPost('Response')); 269 app.put('/api/responses/:id', 270 ensureAuthenticated, 271 makeDocPut_id('Response')); 272 app.delete('/api/responses/:id', 273 ensureAuthenticated, 274 makeDocDel_id('Response')); 653 var rev = etags.parse(req.header('If-Non-Match'))[0]; 654 var secret = req.query.secret; 655 getDocument(id,rev,'Response') 656 .handle({ 657 200: function(response) { 658 if ( response.secret === secret ) { 659 return getDocument(response.surveyRunId,[],'SurveyRun') 660 .handle({ 661 200: function(surveyRun) { 662 if ( !isSurveyRunRunning(surveyRun) ) { 663 return new HTTPResult(404,{error:"Survey is not running anymore."}); 664 } else { 665 response._surveyRun = surveyRun; 666 return response; 667 } 668 } 669 }); 670 } else { 671 return new HTTPResult(403,{error: "Wrong secret for response"}); 672 } 673 } 674 }) 675 .handle(res.send.bind(res)); 676 }); 677 app.post('/api/open/responses', 678 ensureMIME(JSON_MIME), 679 function(req,res) { 680 var secret = req.query.secret; 681 var response = req.body; 682 delete response._surveyRun; 683 getDocument(response.surveyRunId,[],'SurveyRun') 684 .handle({ 685 200: function(surveyRun) { 686 if ( surveyRun.secret !== secret ) { 687 return new HTTPResult(403,{error:"Wrong secret for surveyRun."}); 688 } else if ( !isSurveyRunRunning(surveyRun) ) { 689 return new HTTPResult(404,{error:"Survey is not running anymore."}); 690 } else if ( surveyRun.mode === 'closed' ) { 691 return new HTTPResult(403,{error:"Survey is closed and doesn't allow new responses."}); 692 } else { 693 return randomToken() 694 .handle({ 695 201: function(token) { 696 response.secret = token; 697 return postDocument('Response',response) 698 .handle({ 699 201: function(doc){ 700 doc._surveyRun = surveyRun; 701 return doc; 702 } 703 }); 704 } 705 }); 706 } 707 } 708 }) 709 .handle(res.send.bind(res)); 710 }); 711 app.put('/api/open/responses/:id', 712 ensureMIME(JSON_MIME), 713 function(req,res){ 714 var id = req.params.id; 715 var doc = req.body; 716 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 717 var secret = req.query.secret || doc.secret; 718 delete doc._surveyRun; 719 getDocument(id,[],'Response') 720 .handle({ 721 200: function(prev) { 722 if ( prev.secret !== secret ) { 723 return new HTTPResult(403,{error: "Secrets are not the same."}); 724 } else if ( prev.surveyRunId !== doc.surveyRunId ) { 725 return new HTTPResult(400,{error:"Response cannot change it's surveyRunId."}); 726 } else { 727 doc.secret = secret; // restore in case it got lost or was changed 728 return getDocument(doc.surveyRunId,[],'SurveyRun') 729 .handle({ 730 200: function(surveyRun) { 731 if ( !isSurveyRunRunning(surveyRun) ) { 732 return new HTTPResult(404,{error:"Survey is not running anymore."}); 733 } else { 734 return putDocument(id,rev,'Response',doc) 735 .handle({ 736 200: function(doc) { 737 doc._surveyRun = surveyRun; 738 return new HTTPResult(201,doc); 739 } 740 }); 741 } 742 } 743 }); 744 } 745 } 746 }) 747 .handle(res.send.bind(res)); 748 }); 749 app.delete('/api/open/responses/:id', 750 ensureMIME(JSON_MIME), 751 function(req,res){ 752 var id = req.params.id; 753 var doc = req.body; 754 var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); 755 var secret = req.query.secret || doc.secret; 756 delete doc._surveyRun; 757 getDocument(id,[],'Response') 758 .handle({ 759 200: function(prev) { 760 if ( prev.secret !== secret ) { 761 return new HTTPResult(403,{error: "Secrets are not the same."}); 762 } else { 763 return deleteDocument(id,rev,doc); 764 } 765 } 766 }) 767 .handle(res.send.bind(res)); 768 }); 769 770 // uuids 771 app.get('/api/uuids', 772 ensureAuthenticated, 773 ensureMIME(JSON_MIME), 774 function(req,res){ 775 var count = (req.query.count && parseInt(req.query.count,10)) || 1; 776 HTTPResult.fromResponsePromise(couch.uuids({query:{count:count}}).response, 777 handleUnknownError) 778 .handle({ 779 200: function(res) { 780 return res.uuids; 781 }, 782 default: handleUnknownResponse 783 }) 784 .handle(res.send.bind(res)); 785 }); 275 786 276 787 return app; 277 278 788 } 279 789 … … 341 851 }); 342 852 } 853 854 function randomToken() { 855 var result = new HTTPResult(); 856 cryptoken(8) 857 .then(function(token){ 858 result.set(201,token); 859 }, function(ex){ 860 result.set(500,{error:"Cannot generate secrets.", innerError: ex}); 861 }); 862 return result; 863 } -
Dev/trunk/src/server/bin/check-db.js
r479 r487 1 1 var env = require('../env') 2 , checkCouch = require('../config/check-couchdb'); 3 checkCouch(env.couchDbURL) 2 , checkCouch = require('../config/check-couchdb') 3 ; 4 checkCouch(env.couchServerURL,env.dbName) 4 5 .then(function(res){ 5 6 console.log("done",res); -
Dev/trunk/src/server/bin/config-db.js
r479 r487 1 1 var env = require('../env') 2 , checkCouch = require('../config/config-couchdb'); 3 checkCouch(env.couchServerURL) 2 , configCouch = require('../config/config-couchdb') 3 , designDocs = require('../config/couchdb-design-docs') 4 ; 5 configCouch(env.couchServerURL,env.dbName,designDocs) 4 6 .then(function(res){ 5 7 console.log("done",res); -
Dev/trunk/src/server/bin/heroku.js
r481 r487 1 var env = require('../env'); 2 var configCouch = require('../config/config-couchdb'); 1 var env = require('../env') 2 , configCouch = require('../config/config-couchdb') 3 , designDocs = require('../config/config-couchdb') 4 ; 3 5 4 6 console.log("Running on",env.couchServerURL); 5 7 6 8 require('../app').App({ 7 couchDbURL: env.couchDbURL 9 couchServerURL: env.couchServerURL, 10 dbName: env.dbName 8 11 }).then(function(app){ 9 configCouch(env.couchServerURL );12 configCouch(env.couchServerURL,env.dbName,designDocs); 10 13 return app; 11 14 }).then(function(app){ -
Dev/trunk/src/server/config/check-couchdb.js
r479 r487 7 7 var schema = require('./couchdb-schema'); 8 8 9 module.exports = function(couch DbURL) {10 var server = new CouchDB(couch DbURL);9 module.exports = function(couchServerURL,dbName) { 10 var server = new CouchDB(couchServerURL,dbName); 11 11 var designRe = /^_design\//; 12 12 return server.get('/_all_docs') -
Dev/trunk/src/server/config/config-couchdb.js
r479 r487 5 5 ; 6 6 7 var designDocs = require('./couchdb-design-docs'); 7 module.exports = function(couchServerURL, dbName, designDocs) { 8 var server = new CouchDB(couchServerURL); 8 9 9 module.exports = function(couchServerURL) { 10 var server = new CouchDB(couchServerURL); 10 if ( !designDocs ) { throw new Error("Forgot to pass design docs to checkCouch."); } 11 11 12 12 console.log("Configuring CouchDB for QED"); … … 14 14 return server.get('') 15 15 .then(function(info){ 16 if (info.version !== "1. 2.0" ) {16 if (info.version !== "1.4.0" ) { 17 17 console.log("Found "+info.version+", only tested with CouchDB 1.2.0"); 18 18 } else { 19 console.log("CouchDB 1. 2.0 found");19 console.log("CouchDB 1.4.0 found"); 20 20 } 21 21 }).then(function(res){ -
Dev/trunk/src/server/config/couchdb-design-docs.js
r480 r487 11 11 12 12 "qed/schemaInfo": { 13 version: " 1"13 version: "2" 14 14 }, 15 15 … … 31 31 language: "javascript", 32 32 validate_doc_update: function(newDoc, oldDoc, userCtx, secObj) { 33 if ( oldDoc && oldDoc.publicationDate ) { throw({forbidden:'Published documents cannot be modified.'}); } 33 if ( oldDoc && oldDoc.publicationDate ) { 34 throw({forbidden:'Published documents cannot be modified.'}); 35 } 34 36 }, 35 37 views: { … … 59 61 if ( doc.categories && doc.categories.length > 0 ) { 60 62 for ( var i = 0; i < doc.categories.length; i++ ) { 61 emit([doc.categories[i],doc.topic|| null],1);63 emit([doc.categories[i],doc.topic||"(default)"],1); 62 64 } 63 65 } else { 64 emit([ null,null],1);66 emit(["(default)","(default)"],1); 65 67 } 66 68 }, … … 72 74 if ( doc.categories && doc.categories.length > 0 ) { 73 75 for ( var i = 0; i < doc.categories.length; i++ ) { 74 emit([doc.categories[i],doc.topic|| null],1);76 emit([doc.categories[i],doc.topic||"(default)"],1); 75 77 } 76 78 } else { 77 emit([ null,null],1);79 emit(["(default)","(default)"],1); 78 80 } 79 81 }, … … 83 85 map: function(doc){ 84 86 if( doc.type !== 'Question' ){ return; } 85 emit(doc.topic );87 emit(doc.topic||"(default)",1); 86 88 }, 87 reduce: function(key, values, rereduce) { return null; }89 reduce: function(key, values, rereduce) { return sum(values); } 88 90 }, 89 91 published_topics: { 90 92 map: function(doc){ 91 93 if ( doc.type !== 'Question' || !doc.publicationDate ) { return; } 92 emit(doc.topic );94 emit(doc.topic||"(default)",1); 93 95 }, 94 reduce: function(key, values, rereduce) { return null; } 96 reduce: function(key, values, rereduce) { return sum(values); } 97 }, 98 by_code: { 99 map: function(doc){ 100 if ( doc.type !== 'Question' ) { return; } 101 emit(doc.code,doc); 102 } 95 103 } 96 104 } -
Dev/trunk/src/server/config/couchdb-schema.json
r481 r487 1 1 { 2 "$schema": "http://json-schema.org/draft-04/schema#", 2 3 "title": "QED Object Schema", 3 "version": " 1",4 "version": "2", 4 5 "type": "object", 5 6 "oneOf": [ 6 { "$ref": "#/ schemaInfo" },7 { "$ref": "#/d ocTypes/any" }7 { "$ref": "#/definitions/schemaInfo" }, 8 { "$ref": "#/definitions/docs/any" } 8 9 ], 9 "schemaInfo": { 10 "type": "object", 11 "properties": { 12 "_id": { "type": "string", "pattern": "schemaInfo" }, 13 "_rev": { "type": "string", "optional": true }, 14 "version": { "type": "string" } 15 }, 16 "additionalProperties": false 17 }, 18 "docTypes": { 19 "any": { 10 "definitions": { 11 "schemaInfo": { 20 12 "type": "object", 21 "oneOf": [22 { "$ref": "#/docTypes/Question" },23 { "$ref": "#/docTypes/Survey" },24 { "$ref": "#/docTypes/SurveyRun" },25 { "$ref": "#/docTypes/Response" }26 ]27 },28 "Question": {29 13 "properties": { 30 "type": { "type": "string", "pattern": "Question" }, 31 "_id": { "type": "string", "optional": true }, 32 "_rev": { "type": "string", "optional": true }, 33 "categories": { "type": "array", "items": { "type": "string" } }, 34 "code": { "type": "string" }, 35 "content": { "type": "array", "items": { "$ref": "#/contentTypes/any" } }, 36 "description": { "type": "string", "optional": true }, 37 "publicationDate": { "type": "string", "pattern": "", "optional": true }, 38 "title": { "type": "string" }, 39 "topic": { "type": "string", "optional": true } 14 "_id": { "type": "string", "pattern": "schemaInfo" }, 15 "_rev": { "type": "string" }, 16 "version": { "type": "string" } 40 17 }, 18 "required": ["_id","version"], 41 19 "additionalProperties": false 42 20 }, 43 " Survey": {44 " type": "object",45 "properties": {46 " type": { "type": "string", "pattern": "Survey" },47 "_id": { "type": "string", "optional": true},48 "_rev": { "type": "string", "optional": true},49 "publicationDate": { "type": "string", "pattern": "", "optional": true},50 "questions": { "type": "array", "items": { "$ref": "#/docTypes/Question" } },51 "title": { "type": "string" }21 "docs": { 22 "any": { 23 "type": "object", 24 "oneOf":[ 25 { "$ref": "#/definitions/docs/Question" }, 26 { "$ref": "#/definitions/docs/Survey" }, 27 { "$ref": "#/definitions/docs/SurveyRun" }, 28 { "$ref": "#/definitions/docs/Response" } 29 ] 52 30 }, 53 "additionalProperties": false 54 }, 55 "SurveyRun": { 56 "type": "object", 57 "properties": { 58 "type": { "type": "string", "pattern": "SurveyRun" }, 59 "_id": { "type": "string", "optional": true }, 60 "_rev": { "type": "string", "optional": true }, 61 "description": { "type": "string" }, 62 "endDate": { "type": "string", "pattern": "" }, 63 "mode": { "type": "string", "enum": [ "open", "closed" ] }, 64 "startDate": { "type": "string", "pattern": "" }, 65 "survey": { "$ref": "#/docTypes/Survey" }, 66 "title": { "type": "string" } 67 }, 68 "additionalProperties": false 69 }, 70 "Response": { 71 "type": "object", 72 "properties": { 73 "type": { "type": "string", "pattern": "Response" }, 74 "_id": { "type": "string", "optional": true }, 75 "_rev": { "type": "string", "optional": true }, 76 "answers": { "type": "object" }, 77 "publicationDate": { "type": "string", "pattern": "", "optional": true }, 78 "surveyRunId": { "type": "string" } 79 }, 80 "additionalProperties": false 81 } 82 }, 83 "contentTypes": { 84 "any": { 85 "type": "object", 86 "oneOf": [ 87 { "$ref": "#/contentTypes/Text" }, 88 { "$ref": "#/contentTypes/StringInput" }, 89 { "$ref": "#/contentTypes/ScaleInput" } 90 ] 91 }, 92 "Text": { 31 "Question": { 93 32 "type": "object", 94 33 "properties": { 95 "type": { "type": "string", "pattern": "Text" }, 96 "text": { "type": "string" } 34 "type": { "type": "string", "pattern": "Question" }, 35 "_id": { "type": "string" }, 36 "_rev": { "type": "string" }, 37 "categories": { "type": "array", "items": { "type": "string" } }, 38 "code": { "type": "string" }, 39 "content": { "type": "array", "items": { "$ref": "#/definitions/content/any" } }, 40 "description": { "type": "string" }, 41 "publicationDate": { "type": "string", "format": "datetime" }, 42 "title": { "type": "string" }, 43 "topic": { "type": "string" } 97 44 }, 45 "required": ["type","categories","code","content","title"], 98 46 "additionalProperties": false 99 },100 "StringInput": {47 }, 48 "Survey": { 101 49 "type": "object", 102 50 "properties": { 103 "type": { "type": "string", "pattern": "StringInput" }, 104 "text": { "type": "string" } 51 "type": { "type": "string", "pattern": "Survey" }, 52 "_id": { "type": "string" }, 53 "_rev": { "type": "string" }, 54 "publicationDate": { "type": "string", "format": "datetime" }, 55 "questions": { "type": "array", "items": { "$ref": "#/definitions/docs/Question" } }, 56 "title": { "type": "string" } 105 57 }, 58 "required": ["type","questions","title"], 106 59 "additionalProperties": false 107 },108 "ScaleInput": {60 }, 61 "SurveyRun": { 109 62 "type": "object", 110 63 "properties": { 111 "type": { "type": "string", "pattern": "ScaleInput" }, 112 "minLabel": { "type": "string", "optional": true }, 113 "min": { "type": "integer" }, 114 "max": { "type": "integer" }, 115 "maxLabel": { "type": "string", "optional": true }, 116 "naLabel": { "type": "string", "optional": true }, 117 "items": { "type": "array", "items": { 118 "type": "object", 119 "properties": { 120 "text": { "type": "string" }, 121 "minLabel": { "type": "string", "optional": true }, 122 "maxLabel": { "type": "string", "optional": true } 123 }, 124 "additionalProperties": false 125 } } 64 "type": { "type": "string", "pattern": "SurveyRun" }, 65 "_id": { "type": "string" }, 66 "_rev": { "type": "string" }, 67 "description": { "type": "string" }, 68 "endDate": { "type": "string", "format": "datetime" }, 69 "mode": { "type": "string", "enum": [ "open", "closed" ] }, 70 "secret": { "type": "string", "minLength": 8 }, 71 "startDate": { "type": "string", "format": "datetime" }, 72 "survey": { "$ref": "#/definitions/docs/Survey" }, 73 "title": { "type": "string" } 126 74 }, 75 "required": ["type","description","mode","secret","survey","title"], 127 76 "additionalProperties": false 77 }, 78 "Response": { 79 "type": "object", 80 "properties": { 81 "type": { "type": "string", "pattern": "Response" }, 82 "_id": { "type": "string" }, 83 "_rev": { "type": "string" }, 84 "answers": { "type": "object" }, 85 "publicationDate": { "type": "string", "format": "datetime" }, 86 "secret": { "type": "string", "minLength": 8 }, 87 "surveyRunId": { "type": "string" } 88 }, 89 "required": ["type","answers","secret","surveyRunId"], 90 "additionalProperties": false 91 } 92 }, 93 "content":{ 94 "any": { 95 "type": "object", 96 "oneOf": [ 97 { "$ref": "#/definitions/content/Text" }, 98 { "$ref": "#/definitions/content/StringInput" }, 99 { "$ref": "#/definitions/content/ScaleInput" } 100 ] 101 }, 102 "Text": { 103 "type": "object", 104 "properties": { 105 "type": { "type": "string", "pattern": "Text" }, 106 "text": { "type": "string" } 107 }, 108 "required": ["type","text"], 109 "additionalProperties": false 110 }, 111 "StringInput": { 112 "type": "object", 113 "properties": { 114 "type": { "type": "string", "pattern": "StringInput" }, 115 "text": { "type": "string" } 116 }, 117 "required":["type","text"], 118 "additionalProperties": false 119 }, 120 "ScaleInput": { 121 "type": "object", 122 "properties": { 123 "type": { "type": "string", "pattern": "ScaleInput" }, 124 "minLabel": { "type": "string" }, 125 "min": { "type": "integer" }, 126 "max": { "type": "integer" }, 127 "maxLabel": { "type": "string" }, 128 "naLabel": { "type": "string" }, 129 "items": { "type": "array", "items": { 130 "type": "object", 131 "properties": { 132 "text": { "type": "string" }, 133 "minLabel": { "type": "string" }, 134 "maxLabel": { "type": "string" } 135 }, 136 "required":["text"], 137 "additionalProperties": false 138 } } 139 }, 140 "required":["type","min","max","items"], 141 "additionalProperties": false 142 } 128 143 } 129 144 } -
Dev/trunk/src/server/env.js
r479 r487 3 3 port: process.env.PORT || 5000, 4 4 couchServerURL: couchServerURL, 5 couchDbURL: couchServerURL+'qed',5 dbName: 'qed' 6 6 }; -
Dev/trunk/src/server/util/couch.coffee
r479 r487 6 6 7 7 class CouchDB 8 constructor: (url) -> 9 @url = normalizeURL url 10 get: (id) -> 8 constructor: (url,db) -> 9 @serverURL = normalizeURL url 10 @db = db 11 if @db 12 @url = "#{@serverURL}/#{@db}" 13 else 14 @url = "#{@serverURL}" 15 get: (id, opts) -> 11 16 url = "#{@url}/#{id}" 12 couchRequest 'GET', url 13 post: (doc ) ->14 url = "#{@url} "15 couchRequest 'POST', url, doc 16 put: (id, doc ) ->17 couchRequest 'GET', url, null, opts 18 post: (doc, opts) -> 19 url = "#{@url}/" 20 couchRequest 'POST', url, doc, opts 21 put: (id, doc, opts) -> 17 22 url = "#{@url}/#{id}" 18 couchRequest 'PUT', url, doc 19 delete: (id, rev) -> 20 url = "#{@url}/#{id}?rev=#{rev}" 21 couchRequest 'DELETE', url 23 couchRequest 'PUT', url, doc, opts 24 delete: (id, opts) -> 25 url = "#{@url}/#{id}" 26 couchRequest 'DELETE', url, null, opts 27 uuids: (opts) -> 28 url = "#{@serverURL}/_uuids" 29 couchRequest 'GET', url, null, opts 22 30 23 31 normalizeURL = (url) -> 24 32 url.replace /\/$/, '' 25 33 26 couchRequest = (method, url, data) ->34 couchRequest = (method, url, body, opts) -> 27 35 options = 28 36 method: method, 29 37 headers: 30 'content-type': 'application/json; charset=utf-8' 31 'accept': 'application/json' 32 body: JSON.stringify (stringifyFunctions (data || {})) 38 'Content-Type': 'application/json; charset=utf-8' 39 'Accept': 'application/json' 40 body: JSON.stringify (stringifyFunctions (body || {})) 41 if opts 42 options.qs = createQueryObj opts.query if opts.query 43 _.extend options.headers, opts.headers if opts.headers 33 44 req = request(url, options) 34 req.response 35 .then (res) => 45 res = req.response.then (res) => 36 46 req.then (res) => 37 47 JSON.parse res … … 40 50 , (err) => 41 51 Q.reject err 52 res.response = req.response.then (res) => 53 statusCode: res.statusCode 54 headers: res.headers 55 body: JSON.parse res.body 56 , (err) => 57 Q.reject err 58 res 42 59 60 createQueryObj = (obj) -> 61 newObj = {} 62 _.each obj, (val,key) -> 63 newObj[key] = JSON.stringify val 64 newObj 65 43 66 stringifyFunctions = (value) -> 44 67 if value is null
Note: See TracChangeset
for help on using the changeset viewer.