diff --git a/PyRIGS/urls.py b/PyRIGS/urls.py index 9821ae20..a0c9ceba 100644 --- a/PyRIGS/urls.py +++ b/PyRIGS/urls.py @@ -18,6 +18,8 @@ urlpatterns = patterns('', url('^user/', include('registration.backends.default.urls')), url(r'^admin/', include(admin.site.urls)), + + url(r'^forms/', include('rigForms.urls')), ) if settings.DEBUG: diff --git a/rigForms/migrations/0001_initial.py b/rigForms/migrations/0001_initial.py index a0d076c8..b3ec3ec0 100644 --- a/rigForms/migrations/0001_initial.py +++ b/rigForms/migrations/0001_initial.py @@ -49,11 +49,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='schema', name='schema_type', - field=models.ForeignKey(related_name='schemas', to='forms.Type'), + field=models.ForeignKey(related_name='schemas', to='rigForms.Type'), ), migrations.AddField( model_name='form', name='schema', - field=models.ForeignKey(related_name='forms', to='forms.Schema'), + field=models.ForeignKey(related_name='forms', to='rigForms.Schema'), ), ] diff --git a/rigForms/models.py b/rigForms/models.py index 8cee001d..fea53f3d 100644 --- a/rigForms/models.py +++ b/rigForms/models.py @@ -2,6 +2,8 @@ from django.db import models from django.utils.encoding import python_2_unicode_compatible import reversion +import datetime + from RIGS.models import RevisionMixin @@ -45,3 +47,9 @@ class Form(models.Model, RevisionMixin): schema = models.ForeignKey('Schema', related_name='forms', blank=False) data = models.TextField(blank=False, null=False, default="{}") + + class Meta: + permissions = ( + ('create_form', 'Can complete a form'), + ) + \ No newline at end of file diff --git a/rigForms/static/js/angular-schema-form/ObjectPath.js b/rigForms/static/js/angular-schema-form/ObjectPath.js new file mode 100644 index 00000000..5b4457de --- /dev/null +++ b/rigForms/static/js/angular-schema-form/ObjectPath.js @@ -0,0 +1,103 @@ +'use strict'; + +;!function(undefined) { + + var ObjectPath = { + parse: function(str){ + if(typeof str !== 'string'){ + throw new TypeError('ObjectPath.parse must be passed a string'); + } + + var i = 0; + var parts = []; + var d, b, q, c; + while (i < str.length){ + d = str.indexOf('.', i); + b = str.indexOf('[', i); + + // we've reached the end + if (d === -1 && b === -1){ + parts.push(str.slice(i, str.length)); + i = str.length; + } + + // dots + else if (b === -1 || (d !== -1 && d < b)) { + parts.push(str.slice(i, d)); + i = d + 1; + } + + // brackets + else { + if (b > i){ + parts.push(str.slice(i, b)); + i = b; + } + q = str.slice(b+1, b+2); + if (q !== '"' && q !=='\'') { + c = str.indexOf(']', b); + if (c === -1) c = str.length; + parts.push(str.slice(i + 1, c)); + i = (str.slice(c + 1, c + 2) === '.') ? c + 2 : c + 1; + } else { + c = str.indexOf(q+']', b); + if (c === -1) c = str.length; + while (str.slice(c - 1, c) === '\\' && b < str.length){ + b++; + c = str.indexOf(q+']', b); + } + parts.push(str.slice(i + 2, c).replace(new RegExp('\\'+q,'g'), q)); + i = (str.slice(c + 2, c + 3) === '.') ? c + 3 : c + 2; + } + } + } + return parts; + }, + + // root === true : auto calculate root; must be dot-notation friendly + // root String : the string to use as root + stringify: function(arr, quote){ + + if(!Array.isArray(arr)) + arr = [arr.toString()]; + + quote = quote === '"' ? '"' : '\''; + + return arr.map(function(n){ return '[' + quote + (n.toString()).replace(new RegExp(quote, 'g'), '\\' + quote) + quote + ']'; }).join(''); + }, + + normalize: function(data, quote){ + return ObjectPath.stringify(Array.isArray(data) ? data : ObjectPath.parse(data), quote); + }, + + // Angular + registerModule: function(angular) { + angular.module('ObjectPath', []).provider('ObjectPath', function(){ + this.parse = ObjectPath.parse; + this.stringify = ObjectPath.stringify; + this.normalize = ObjectPath.normalize; + this.$get = function(){ + return ObjectPath; + }; + }); + } + }; + + // AMD + if (typeof define === 'function' && define.amd) { + define(function() { + return {ObjectPath: ObjectPath}; + }); + } + + // CommonJS + else if (typeof exports === 'object') { + exports.ObjectPath = ObjectPath; + } + + // Browser global + else { + window.ObjectPath = ObjectPath; + } + +}(); \ No newline at end of file diff --git a/rigForms/static/js/angular-schema-form/angular-sanitize.js b/rigForms/static/js/angular-schema-form/angular-sanitize.js new file mode 100644 index 00000000..918ac819 --- /dev/null +++ b/rigForms/static/js/angular-schema-form/angular-sanitize.js @@ -0,0 +1,679 @@ +/** + * @license AngularJS v1.3.17 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Any commits to this file should be reviewed with security in mind. * + * Changes to this file can potentially create security vulnerabilities. * + * An approval from 2 Core members with history of modifying * + * this file is required. * + * * + * Does the change somehow allow for arbitrary javascript to be executed? * + * Or allows for someone to change the prototype of built-in objects? * + * Or gives undesired access to variables likes document or window? * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +var $sanitizeMinErr = angular.$$minErr('$sanitize'); + +/** + * @ngdoc module + * @name ngSanitize + * @description + * + * # ngSanitize + * + * The `ngSanitize` module provides functionality to sanitize HTML. + * + * + *
+ * + * See {@link ngSanitize.$sanitize `$sanitize`} for usage. + */ + +/* + * HTML Parser By Misko Hevery (misko@hevery.com) + * based on: HTML Parser By John Resig (ejohn.org) + * Original code by Erik Arvidsson, Mozilla Public License + * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js + * + * // Use like so: + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + */ + + +/** + * @ngdoc service + * @name $sanitize + * @kind function + * + * @description + * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are + * then serialized back to properly escaped html string. This means that no unsafe input can make + * it into the returned string, however, since our parser is more strict than a typical browser + * parser, it's possible that some obscure input, which would be recognized as valid HTML by a + * browser, won't make it through the sanitizer. The input may also contain SVG markup. + * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and + * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. + * + * @param {string} html HTML input. + * @returns {string} Sanitized HTML. + * + * @example +| Directive | +How | +Source | +Rendered | +
| ng-bind-html | +Automatically uses $sanitize | +<div ng-bind-html="snippet"> |
+ + |
| ng-bind-html | +Bypass $sanitize by explicitly trusting the dangerous value | +
+ <div ng-bind-html="deliberatelyTrustDangerousSnippet()"> +</div>+ |
+ + |
| ng-bind | +Automatically escapes | +<div ng-bind="snippet"> |
+ + |
an html\nclick here\nsnippet
'); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). + toBe("an html\n" + + "click here\n" + + "snippet
"); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getInnerHtml()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +| Filter | +Source | +Rendered | +
| linky filter | +
+ <div ng-bind-html="snippet | linky">+ |
+ + + | +
| linky target | +
+ <div ng-bind-html="snippetWithTarget | linky:'_blank'">+ |
+ + + | +
| no filter | +<div ng-bind="snippet"> |
+ + |