| 1 |
class Project < ActiveRecord::Base |
| 2 |
acts_as_taggable |
| 3 |
|
| 4 |
belongs_to :user |
| 5 |
has_many :comments, :dependent => :destroy |
| 6 |
has_many :repositories, :order => "repositories.mainline desc, repositories.created_at asc", |
| 7 |
:dependent => :destroy |
| 8 |
has_one :mainline_repository, :conditions => ["mainline = ?", true], |
| 9 |
:class_name => "Repository" |
| 10 |
has_many :repository_clones, :conditions => ["mainline = ?", false], |
| 11 |
:class_name => "Repository" |
| 12 |
has_many :events, :order => "created_at asc", :dependent => :destroy |
| 13 |
|
| 14 |
is_indexed :fields => ["title", "description", "slug"], |
| 15 |
:concatenate => [ |
| 16 |
{ :class_name => 'Tag', |
| 17 |
:field => 'name', |
| 18 |
:as => 'category', |
| 19 |
:association_sql => "LEFT OUTER JOIN taggings ON taggings.taggable_id = projects.id " + |
| 20 |
"AND taggings.taggable_type = 'Project' LEFT OUTER JOIN tags ON taggings.tag_id = tags.id" |
| 21 |
}], |
| 22 |
:include => [{ |
| 23 |
:association_name => "user", |
| 24 |
:field => "login", |
| 25 |
:as => "user" |
| 26 |
}] |
| 27 |
|
| 28 |
|
| 29 |
URL_FORMAT_RE = /^(http|https|nntp):\/\//.freeze |
| 30 |
validates_presence_of :title, :user_id, :slug, :description |
| 31 |
validates_uniqueness_of :slug, :case_sensitive => false |
| 32 |
validates_format_of :slug, :with => /^[a-z0-9_\-]+$/i, |
| 33 |
:message => "must match something in the range of [a-z0-9_\-]+" |
| 34 |
validates_format_of :home_url, :with => URL_FORMAT_RE, |
| 35 |
:if => proc{|record| !record.home_url.blank? }, |
| 36 |
:message => "Must begin with http(s)" |
| 37 |
validates_format_of :mailinglist_url, :with => URL_FORMAT_RE, |
| 38 |
:if => proc{|record| !record.mailinglist_url.blank? }, |
| 39 |
:message => "Must begin with http(s)" |
| 40 |
validates_format_of :bugtracker_url, :with => URL_FORMAT_RE, |
| 41 |
:if => proc{|record| !record.bugtracker_url.blank? }, |
| 42 |
:message => "Must begin with http(s)" |
| 43 |
|
| 44 |
before_validation :downcase_slug |
| 45 |
after_create :create_mainline_repository |
| 46 |
|
| 47 |
LICENSES = [ |
| 48 |
'Academic Free License v3.0', |
| 49 |
'MIT License', |
| 50 |
'BSD License', |
| 51 |
'Ruby License', |
| 52 |
'GNU General Public License version 2(GPLv2)', |
| 53 |
'GNU General Public License version 3 (GPLv3)', |
| 54 |
'GNU Lesser General Public License (LGPL)', |
| 55 |
'GNU Affero General Public License (AGPLv3)', |
| 56 |
'Mozilla Public License 1.0 (MPL)', |
| 57 |
'Mozilla Public License 1.1 (MPL 1.1)', |
| 58 |
'Qt Public License (QPL)', |
| 59 |
'Python License', |
| 60 |
'zlib/libpng License', |
| 61 |
'Apache Software License', |
| 62 |
'Apple Public Source License', |
| 63 |
'Perl Artistic License', |
| 64 |
'Microsoft Permissive License (Ms-PL)', |
| 65 |
'ISC License', |
| 66 |
'Lisp Lesser License', |
| 67 |
'Public Domain', |
| 68 |
'Other Open Source Initiative Approved License', |
| 69 |
'Other/Proprietary License', |
| 70 |
'None', |
| 71 |
] |
| 72 |
|
| 73 |
def self.find_by_slug!(slug, opts = {}) |
| 74 |
find_by_slug(slug, opts) || raise(ActiveRecord::RecordNotFound) |
| 75 |
end |
| 76 |
|
| 77 |
def self.per_page() 20 end |
| 78 |
|
| 79 |
def self.top_tags(limit = 10) |
| 80 |
tag_counts(:limit => limit, :order => "count desc") |
| 81 |
end |
| 82 |
|
| 83 |
def to_param |
| 84 |
slug |
| 85 |
end |
| 86 |
|
| 87 |
def admin?(candidate) |
| 88 |
candidate == user |
| 89 |
end |
| 90 |
|
| 91 |
def can_be_deleted_by?(candidate) |
| 92 |
(candidate == user) && (repositories.size == 1) |
| 93 |
end |
| 94 |
|
| 95 |
def tag_list=(tag_list) |
| 96 |
tag_list.gsub!(",", "") |
| 97 |
|
| 98 |
super |
| 99 |
end |
| 100 |
|
| 101 |
def home_url=(url) |
| 102 |
self[:home_url] = clean_url(url) |
| 103 |
end |
| 104 |
|
| 105 |
def mailinglist_url=(url) |
| 106 |
self[:mailinglist_url] = clean_url(url) |
| 107 |
end |
| 108 |
|
| 109 |
def bugtracker_url=(url) |
| 110 |
self[:bugtracker_url] = clean_url(url) |
| 111 |
end |
| 112 |
|
| 113 |
def stripped_description |
| 114 |
description.gsub(/<\/?[^>]*>/, "") |
| 115 |
|
| 116 |
|
| 117 |
end |
| 118 |
|
| 119 |
def to_xml(opts = {}) |
| 120 |
info = Proc.new { |options| |
| 121 |
builder = options[:builder] |
| 122 |
builder.owner user.login |
| 123 |
|
| 124 |
builder.repositories :type => "array" do |
| 125 |
repositories.each { |repo| |
| 126 |
builder.repository do |
| 127 |
builder.id repo.id |
| 128 |
builder.name repo.name |
| 129 |
builder.owner repo.user.login |
| 130 |
end |
| 131 |
} |
| 132 |
end |
| 133 |
} |
| 134 |
super({:procs => [info]}.merge(opts)) |
| 135 |
end |
| 136 |
|
| 137 |
def create_event(action_id, target, user, data = nil, body = nil, date = Time.now.utc) |
| 138 |
events.create(:action => action_id, :target => target, :user => user, |
| 139 |
:body => body, :data => data, :created_at => date) |
| 140 |
end |
| 141 |
|
| 142 |
protected |
| 143 |
def create_mainline_repository |
| 144 |
self.repositories.create!(:user => self.user, :name => "mainline") |
| 145 |
end |
| 146 |
|
| 147 |
def downcase_slug |
| 148 |
slug.downcase! if slug |
| 149 |
end |
| 150 |
|
| 151 |
|
| 152 |
def clean_url(url) |
| 153 |
return if url.blank? |
| 154 |
begin |
| 155 |
url = "http://#{url}" if URI.parse(url).class == URI::Generic |
| 156 |
rescue |
| 157 |
end |
| 158 |
url |
| 159 |
end |
| 160 |
end |