Commit 273408c2fcc519dd963104262cd5bc5dbac66426

Normalize url fields (eg add http:// if it aint there) on User+Project

Commit diff

TODO.txt

 
4646* improve commenting and comments visibility
4747* handle mising/wrong SHA1s gracefully in browser
4848* parse SHA1s in commits+comments
49* Normalize url fields (eg add http:// if it aint there) on User+Project
5049* Detect renames etc when showing a commit
5150* Always add a "mainline-upstream" branch that track the mainline repos automagically to clones
5251---
toggle raw diff

app/models/project.rb

 
11class Project < ActiveRecord::Base
22 acts_as_taggable
3
3
44 belongs_to :user
55 has_many :comments, :dependent => :destroy
66 has_many :repositories, :order => "repositories.mainline desc, repositories.created_at asc",
77 :dependent => :destroy
8 has_one :mainline_repository, :conditions => ["mainline = ?", true],
8 has_one :mainline_repository, :conditions => ["mainline = ?", true],
99 :class_name => "Repository"
1010 has_many :repository_clones, :conditions => ["mainline = ?", false],
1111 :class_name => "Repository"
12
13 is_indexed :fields => ["title", "description", "slug"],
12
13 is_indexed :fields => ["title", "description", "slug"],
1414 :concatenate => [
15 { :class_name => 'Tag',
16 :field => 'name',
15 { :class_name => 'Tag',
16 :field => 'name',
1717 :as => 'category',
18 :association_sql => "LEFT OUTER JOIN taggings ON taggings.taggable_id = projects.id " +
18 :association_sql => "LEFT OUTER JOIN taggings ON taggings.taggable_id = projects.id " +
1919 "AND taggings.taggable_type = 'Project' LEFT OUTER JOIN tags ON taggings.tag_id = tags.id"
2020 }],
2121 :include => [{
2323 :field => "login",
2424 :as => "user"
2525 }]
26
27
26
27
2828 URL_FORMAT_RE = /^(http|https|nntp):\/\//.freeze
2929 validates_presence_of :title, :user_id, :slug
3030 validates_uniqueness_of :slug, :case_sensitive => false
31 validates_format_of :slug, :with => /^[a-z0-9_\-]+$/i,
31 validates_format_of :slug, :with => /^[a-z0-9_\-]+$/i,
3232 :message => "must match something in the range of [a-z0-9_\-]+"
33 validates_format_of :home_url, :with => URL_FORMAT_RE,
33 validates_format_of :home_url, :with => URL_FORMAT_RE,
3434 :if => proc{|record| !record.home_url.blank? },
3535 :message => "Must begin with http(s)"
3636 validates_format_of :mailinglist_url, :with => URL_FORMAT_RE,
3737 :if => proc{|record| !record.mailinglist_url.blank? },
3838 :message => "Must begin with http(s)"
39 validates_format_of :bugtracker_url, :with => URL_FORMAT_RE,
39 validates_format_of :bugtracker_url, :with => URL_FORMAT_RE,
4040 :if => proc{|record| !record.bugtracker_url.blank? },
4141 :message => "Must begin with http(s)"
42
42
4343 before_validation :downcase_slug
4444 after_create :create_mainline_repository
45
45
4646 LICENSES = [
4747 'Academic Free License v3.0',
4848 'MIT License',
6868 'Other/Proprietary License',
6969 'None',
7070 ]
71
71
7272 def self.find_by_slug!(slug, opts = {})
7373 find_by_slug(slug, opts) || raise(ActiveRecord::RecordNotFound)
7474 end
75
75
7676 def self.per_page() 20 end
77
77
7878 def self.top_tags(limit = 10)
7979 tag_counts(:limit => limit, :order => "count desc")
8080 end
81
81
8282 def to_param
8383 slug
8484 end
85
85
8686 def admin?(candidate)
8787 candidate == user
8888 end
89
89
9090 def can_be_deleted_by?(candidate)
9191 (candidate == user) && (repositories.size == 1)
9292 end
93
93
9494 def tag_list=(tag_list)
9595 tag_list.gsub!(",", "")
96
96
9797 super
9898 end
99
99
100 def home_url=(url)
101 self[:home_url] = clean_url(url)
102 end
103
104 def mailinglist_url=(url)
105 self[:mailinglist_url] = clean_url(url)
106 end
107
108 def bugtracker_url=(url)
109 self[:bugtracker_url] = clean_url(url)
110 end
111
100112 def stripped_description
101113 description.gsub(/<\/?[^>]*>/, "")
102114 # sanitizer = HTML::WhiteListSanitizer.new
103115 # sanitizer.sanitize(description, :tags => %w(str), :attributes => %w(class))
104116 end
105
117
106118 def to_xml(opts = {})
107119 info = Proc.new { |options|
108120 builder = options[:builder]
109121 builder.owner user.login
110
111 builder.repositories :type => "array" do
122
123 builder.repositories :type => "array" do
112124 repositories.each { |repo|
113125 builder.repository do
114126 builder.id repo.id
132132 }
133133 super({:procs => [info]}.merge(opts))
134134 end
135
135
136136 protected
137137 def create_mainline_repository
138138 self.repositories.create!(:user => self.user, :name => "mainline")
139139 end
140
140
141141 def downcase_slug
142142 slug.downcase! if slug
143143 end
144
144
145 # Try our best to guess the url
146 def clean_url(url)
147 begin
148 url = "http://#{url}" if URI.parse(url).class == URI::Generic
149 rescue
150 end
151 url
152 end
145153end
toggle raw diff

spec/models/project_spec.rb

 
11require File.dirname(__FILE__) + '/../spec_helper'
22
33describe Project do
4
4
55 def create_project(options={})
66 Project.new({
7 :title => "foo project",
8 :slug => "foo",
7 :title => "foo project",
8 :slug => "foo",
99 :user => users(:johan)
1010 }.merge(options))
1111 end
12
12
1313 it "should have valid associations" do
1414 create_project.should have_valid_associations
1515 end
16
16
1717 it "should have a title to be valid" do
1818 project = create_project(:title => nil)
1919 project.should_not be_valid
2020 project.title = "foo"
2121 project.should be_valid
2222 end
23
23
2424 it "should have a slug to be valid" do
2525 project = create_project(:slug => nil)
2626 project.should_not be_valid
2727 end
28
28
2929 it "should have a unique slug to be valid" do
3030 p1 = create_project
3131 p1.save!
3333 p2.should_not be_valid
3434 p2.should have(1).error_on(:slug)
3535 end
36
36
3737 it "should have an alphanumeric slug" do
3838 project = create_project(:slug => "asd asd")
3939 project.valid?
4040 project.should_not be_valid
4141 end
42
42
4343 it "should downcase the slug before validation" do
4444 project = create_project(:slug => "FOO")
4545 project.valid?
4646 project.slug.should == "foo"
4747 end
48
48
4949 it "creates an initial repository for itself" do
5050 project = create_project
5151 project.save
5454 project.repositories.first.user.should == project.user
5555 project.user.can_write_to?(project.repositories.first).should == true
5656 end
57
57
5858 it "finds a project by slug or raises" do
5959 Project.find_by_slug!(projects(:johans).slug).should == projects(:johans)
6060 proc{
6161 Project.find_by_slug!("asdasdasd")
6262 }.should raise_error(ActiveRecord::RecordNotFound)
63 end
64
63 end
64
6565 it "has the slug as its params" do
6666 projects(:johans).to_param.should == projects(:johans).slug
6767 end
68
68
6969 it "knows if a user is a admin on a project" do
7070 projects(:johans).admin?(users(:johan)).should == true
7171 projects(:johans).admin?(users(:moe)).should == false
7272 projects(:johans).admin?(:false).should == false
7373 end
74
74
7575 it "knows if a user can delete the project" do
7676 project = projects(:johans)
7777 project.can_be_deleted_by?(users(:moe)).should == false
7979 project.repositories.last.destroy
8080 project.reload.can_be_deleted_by?(users(:johan)).should == true
8181 end
82
82
8383 it "should strip html tags" do
8484 project = create_project(:description => "<h1>Project A</h1>\n<b>Project A</b> is a....")
8585 project.stripped_description.should == "Project A\nProject A is a...."
8686 end
87
87
8888 # it "should strip html tags, except highlights" do
8989 # project = create_project(:description => %Q{<h1>Project A</h1>\n<strong class="highlight">Project A</strong> is a....})
9090 # project.stripped_description.should == %Q(Project A\n<strong class="highlight">Project A</strong> is a....)
9191 # end
92
92
93 it "should have valid urls ( prepending http:// if needed )" do
94 project = projects(:johans)
95 [ :home_url, :mailinglist_url, :bugtracker_url ].each do |attr|
96 project.should be_valid
97 project.send("#{attr}=", 'http://blah.com')
98 project.should be_valid
99 project.send("#{attr}=", 'ftp://blah.com')
100 project.should_not be_valid
101 project.send("#{attr}=", 'blah.com')
102 project.should be_valid
103 project.send(attr).should == 'http://blah.com'
104 end
105 end
106
93107end
toggle raw diff