adding content tag url validation
testplan: check to make sure: * nil urls are allowed * surrounding whitespace is stripped * empty urls are not allowed * it parses a wide variety of urls * it adds missing schemes * it ensures a host exists * invalid schemes are rejected Change-Id: I93e89f8e67d847d488693f7dd4f95e52c898054d Reviewed-on: https://gerrit.instructure.com/6659 Tested-by: Hudson <hudson@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
This commit is contained in:
parent
bad37ada4e
commit
3783768a45
|
@ -33,10 +33,11 @@ class ContentTag < ActiveRecord::Base
|
|||
after_save :enforce_unique_in_modules
|
||||
after_save :touch_context_module
|
||||
after_save :touch_context_if_learning_outcome
|
||||
include CustomValidations
|
||||
validates_as_url :url
|
||||
|
||||
attr_accessible :learning_outcome, :context, :tag_type, :mastery_score, :rubric_association, :content_asset_string, :content, :title, :indent, :position, :url, :new_tab
|
||||
|
||||
|
||||
set_policy do
|
||||
given {|user, session| self.context && self.context.grants_right?(user, session, :manage_content)}
|
||||
can :delete
|
||||
|
|
|
@ -39,6 +39,8 @@ class Submission < ActiveRecord::Base
|
|||
serialize :turnitin_data, Hash
|
||||
validates_presence_of :assignment_id, :user_id
|
||||
validates_length_of :body, :maximum => maximum_long_text_length, :allow_nil => true, :allow_blank => true
|
||||
include CustomValidations
|
||||
validates_as_url :url
|
||||
|
||||
named_scope :with_comments, :include => [:submission_comments ]
|
||||
named_scope :after, lambda{|date|
|
||||
|
@ -208,22 +210,6 @@ class Submission < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
validates_each(:url, :allow_nil => true) do |record, attr, value|
|
||||
begin
|
||||
value = value.strip
|
||||
raise ArgumentError if value.empty?
|
||||
uri = URI.parse(value)
|
||||
unless uri.scheme
|
||||
value = "http://#{value}"
|
||||
uri = URI.parse(value)
|
||||
end
|
||||
raise ArgumentError unless %w(http https).include?(uri.scheme)
|
||||
record.url = value
|
||||
rescue URI::InvalidURIError, ArgumentError
|
||||
record.errors.add attr, 'is not a valid URL'
|
||||
end
|
||||
end
|
||||
|
||||
def plaintext_body
|
||||
self.extend TextHelper
|
||||
strip_tags((self.body || "").gsub(/\<\s*br\s*\/\>/, "\n<br/>").gsub(/\<\/p\>/, "</p>\n"))
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module CustomValidations
|
||||
|
||||
module ClassMethods
|
||||
|
||||
def validates_as_url(*fields)
|
||||
fields.each do |field|
|
||||
validates_each(field.to_sym, :allow_nil => true) do |record, attr, value|
|
||||
begin
|
||||
value = value.strip
|
||||
raise ArgumentError if value.empty?
|
||||
uri = URI.parse(value)
|
||||
unless uri.scheme
|
||||
value = "http://#{value}"
|
||||
uri = URI.parse(value)
|
||||
end
|
||||
raise ArgumentError unless uri.host && %w(http https).include?(uri.scheme.downcase)
|
||||
record.url = value
|
||||
rescue URI::InvalidURIError, ArgumentError
|
||||
record.errors.add attr, 'is not a valid URL'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.included(klass)
|
||||
if klass < ActiveRecord::Base
|
||||
klass.send :extend, ClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
shared_examples_for "url validation tests" do
|
||||
|
||||
def test_url_validation(model)
|
||||
# should add http://
|
||||
model.url = "example.com"
|
||||
model.save!
|
||||
model.errors.length.should == 0
|
||||
model.url.should == "http://example.com"
|
||||
|
||||
# should remove whitespace
|
||||
model.url = " example.com "
|
||||
model.save!
|
||||
model.errors.length.should == 0
|
||||
model.url.should == "http://example.com"
|
||||
|
||||
model.url = " http://www.example.com "
|
||||
model.save!
|
||||
model.errors.length.should == 0
|
||||
model.url.should == "http://www.example.com"
|
||||
|
||||
# should not work on invalid urls
|
||||
["/relativepath",
|
||||
"",
|
||||
"invalidscheme://www.example.com",
|
||||
"not a url"].each do |invalid_url|
|
||||
model.url = invalid_url
|
||||
saved = model.save
|
||||
[model.url, saved].should == [invalid_url, false]
|
||||
model.errors.length.should == 1
|
||||
model.errors.first.to_s.should =~ /not a valid URL/
|
||||
end
|
||||
|
||||
# should work on valid urls
|
||||
["http://www.sub.test.example.tld./thing1?query#hash",
|
||||
"https://localhost/test/",
|
||||
"HTTP://localhost/test/",
|
||||
"http://192.168.24.205:1000",
|
||||
"http://user:password@host.tld:5555/path/to/thing",
|
||||
"http://user:password@host.tld/path/to/thing",
|
||||
"http://" + ("a"*300) + ".com",
|
||||
"http://www.example.com"].each do |valid_url|
|
||||
model.url = valid_url
|
||||
model.save!
|
||||
model.errors.length.should == 0
|
||||
model.url.should == valid_url
|
||||
end
|
||||
|
||||
# should support nil urls
|
||||
model.url = nil
|
||||
model.save!
|
||||
model.errors.length.should == 0
|
||||
model.url.should be_nil
|
||||
end
|
||||
|
||||
end
|
|
@ -17,6 +17,7 @@
|
|||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../lib/validates_as_url.rb')
|
||||
|
||||
describe ContentTag do
|
||||
|
||||
|
@ -159,4 +160,10 @@ describe ContentTag do
|
|||
@assignment.reload
|
||||
@assignment.title.should == 'some assignment (renamed)'
|
||||
end
|
||||
|
||||
it_should_behave_like "url validation tests"
|
||||
it "should check url validity" do
|
||||
quiz = course.quizzes.create!
|
||||
test_url_validation(ContentTag.create!(:content => quiz, :context => @course))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../lib/validates_as_url.rb')
|
||||
|
||||
describe Submission do
|
||||
before(:each) do
|
||||
|
@ -38,6 +39,23 @@ describe Submission do
|
|||
Submission.create!(@valid_attributes)
|
||||
end
|
||||
|
||||
it_should_behave_like "url validation tests"
|
||||
it "should check url validity" do
|
||||
test_url_validation(Submission.create!(@valid_attributes))
|
||||
end
|
||||
|
||||
it "should add http:// to the body for long urls, too" do
|
||||
s = Submission.create!(@valid_attributes)
|
||||
s.url.should == 'http://www.instructure.com'
|
||||
|
||||
long_url = ("a"*300 + ".com")
|
||||
s.url = long_url
|
||||
s.save!
|
||||
s.url.should == "http://#{long_url}"
|
||||
# make sure it adds the "http://" to the body for long urls, too
|
||||
s.body.should == "http://#{long_url}"
|
||||
end
|
||||
|
||||
it "should offer the context, if one is available" do
|
||||
@course = Course.new
|
||||
@assignment = Assignment.new(:context => @course)
|
||||
|
@ -252,41 +270,6 @@ describe Submission do
|
|||
end
|
||||
end
|
||||
|
||||
context "URL submissions" do
|
||||
it "should automatically add the 'http://' scheme if none given" do
|
||||
s = Submission.create!(@valid_attributes)
|
||||
s.url.should == 'http://www.instructure.com'
|
||||
|
||||
long_url = ("a"*300 + ".com")
|
||||
s.url = long_url
|
||||
s.save!
|
||||
s.url.should == "http://#{long_url}"
|
||||
# make sure it adds the "http://" to the body for long urls, too
|
||||
s.body.should == "http://#{long_url}"
|
||||
end
|
||||
|
||||
it "should reject invalid urls" do
|
||||
s = Submission.create(@valid_attributes.merge :url => 'bad url')
|
||||
s.new_record?.should be_true
|
||||
s.errors.length.should == 1
|
||||
s.errors.first.to_s.should match(/not a valid URL/)
|
||||
end
|
||||
|
||||
it "should reject empty urls" do
|
||||
s = Submission.create(@valid_attributes.merge :url => '')
|
||||
s.new_record?.should be_true
|
||||
s.errors.length.should == 1
|
||||
s.errors.first.to_s.should match(/not a valid URL/)
|
||||
end
|
||||
|
||||
it "should strip leading/trailing whitespace" do
|
||||
s = Submission.create(@valid_attributes.merge :url => ' http://www.google.com ')
|
||||
s.new_record?.should be_false
|
||||
s.errors.should be_empty
|
||||
s.url.should == 'http://www.google.com'
|
||||
end
|
||||
end
|
||||
|
||||
context "turnitin" do
|
||||
before do
|
||||
@assignment.turnitin_enabled = true
|
||||
|
|
Loading…
Reference in New Issue