| |   |
| 5 | 5 | has_many :committerships, :dependent => :destroy |
| 6 | 6 | has_many :committers, :through => :committerships, :source => :user |
| 7 | 7 | has_many :comments, :dependent => :destroy |
| 8 | | has_many :merge_requests, :foreign_key => 'target_repository_id', |
| 8 | has_many :merge_requests, :foreign_key => 'target_repository_id', |
| 9 | 9 | :order => "status, id desc", :dependent => :destroy |
| 10 | | has_many :proposed_merge_requests, :foreign_key => 'source_repository_id', |
| 10 | has_many :proposed_merge_requests, :foreign_key => 'source_repository_id', |
| 11 | 11 | :class_name => 'MergeRequest', :order => "id desc", :dependent => :destroy |
| 12 | | has_many :cloners, :dependent => :destroy |
| 13 | | |
| 12 | |
| 14 | 13 | validates_presence_of :user_id, :project_id, :name |
| 15 | 14 | validates_format_of :name, :with => /^[a-z0-9_\-]+$/i, |
| 16 | 15 | :message => "is invalid, must match something like /[a-z0-9_\\-]+/" |
| 17 | 16 | validates_uniqueness_of :name, :scope => :project_id, :case_sensitive => false |
| 18 | | |
| 17 | |
| 19 | 18 | before_save :set_as_mainline_if_first |
| 20 | 19 | after_create :add_user_as_committer, :create_new_repos_task |
| 21 | 20 | after_destroy :create_delete_repos_task |
| 22 | | |
| 21 | |
| 23 | 22 | def self.new_by_cloning(other, username=nil) |
| 24 | 23 | suggested_name = username ? "#{username}s-clone" : nil |
| 25 | 24 | new(:parent => other, :project => other.project, :name => suggested_name) |
| 26 | 25 | end |
| 27 | | |
| 26 | |
| 28 | 27 | def self.find_by_name!(name) |
| 29 | 28 | find_by_name(name) || raise(ActiveRecord::RecordNotFound) |
| 30 | 29 | end |
| 31 | | |
| 32 | | def self.find_by_path(path) |
| 33 | | base_path = path.gsub(/^#{Regexp.escape(GitoriousConfig['repository_base_path'])}/, "") |
| 34 | | repo_name, project_name = base_path.split("/").reverse |
| 35 | | |
| 36 | | project = Project.find_by_slug!(project_name) |
| 37 | | project.repositories.find_by_name(repo_name.sub(/\.git/, "")) |
| 38 | | end |
| 39 | | |
| 30 | |
| 40 | 31 | def self.create_git_repository(path) |
| 41 | 32 | git_backend.create(full_path_from_partial_path(path)) |
| 42 | 33 | end |
| 43 | | |
| 34 | |
| 44 | 35 | def self.clone_git_repository(target_path, source_path) |
| 45 | | git_backend.clone(full_path_from_partial_path(target_path), |
| 36 | git_backend.clone(full_path_from_partial_path(target_path), |
| 46 | 37 | full_path_from_partial_path(source_path)) |
| 47 | 38 | end |
| 48 | | |
| 39 | |
| 49 | 40 | def self.delete_git_repository(path) |
| 50 | 41 | git_backend.delete!(full_path_from_partial_path(path)) |
| 51 | 42 | end |
| 52 | | |
| 43 | |
| 53 | 44 | def gitdir |
| 54 | 45 | File.join(project.slug, "#{name}.git") |
| 55 | 46 | end |
| 56 | | |
| 47 | |
| 57 | 48 | def clone_url |
| 58 | 49 | "git://#{GitoriousConfig['gitorious_host']}/#{gitdir}" |
| 59 | 50 | end |
| 60 | | |
| 51 | |
| 61 | 52 | def http_clone_url |
| 62 | 53 | "http://git.#{GitoriousConfig['gitorious_host']}/#{gitdir}" |
| 63 | 54 | end |
| 64 | | |
| 55 | |
| 65 | 56 | def push_url |
| 66 | 57 | "git@#{GitoriousConfig['gitorious_host']}:#{gitdir}" |
| 67 | 58 | end |
| 68 | | |
| 59 | |
| 69 | 60 | def full_repository_path |
| 70 | 61 | self.class.full_path_from_partial_path(gitdir) |
| 71 | 62 | end |
| 72 | | |
| 63 | |
| 73 | 64 | def git |
| 74 | 65 | Grit::Repo.new(full_repository_path) |
| 75 | 66 | end |
| 76 | | |
| 67 | |
| 77 | 68 | def has_commits? |
| 78 | 69 | return false if new_record? || !ready? |
| 79 | 70 | !git.heads.empty? |
| 80 | 71 | end |
| 81 | | |
| 72 | |
| 82 | 73 | def self.git_backend |
| 83 | 74 | RAILS_ENV == "test" ? MockGitBackend : GitBackend |
| 84 | 75 | end |
| 85 | | |
| 76 | |
| 86 | 77 | def git_backend |
| 87 | 78 | RAILS_ENV == "test" ? MockGitBackend : GitBackend |
| 88 | 79 | end |
| 89 | | |
| 80 | |
| 90 | 81 | def to_param |
| 91 | 82 | name |
| 92 | 83 | end |
| 93 | | |
| 84 | |
| 94 | 85 | def to_xml(opts = {}) |
| 95 | 86 | super({:methods => [:gitdir, :clone_url, :push_url]}.merge(opts)) |
| 96 | 87 | end |
| 97 | | |
| 88 | |
| 98 | 89 | def add_committer(user) |
| 99 | 90 | unless user.can_write_to?(self) |
| 100 | 91 | committers << user |
| 101 | 92 | end |
| 102 | 93 | end |
| 103 | | |
| 94 | |
| 104 | 95 | def head_candidate |
| 105 | 96 | return nil unless has_commits? |
| 106 | 97 | @head_candidate ||= git.heads.find{|h| h.name == "master"} || git.heads.first |
| 107 | 98 | end |
| 108 | | |
| 99 | |
| 109 | 100 | def last_commit |
| 110 | 101 | if has_commits? |
| 111 | 102 | @last_commit ||= git.commits(head_candidate.name, 1).first |
| 112 | 103 | end |
| 113 | 104 | @last_commit |
| 114 | 105 | end |
| 115 | | |
| 106 | |
| 116 | 107 | def can_be_deleted_by?(candidate) |
| 117 | 108 | !mainline? && (candidate == user) |
| 118 | 109 | end |
| 119 | | |
| 110 | |
| 120 | 111 | def create_new_repos_task |
| 121 | | Task.create!(:target_class => self.class.name, |
| 122 | | :command => parent ? "clone_git_repository" : "create_git_repository", |
| 123 | | :arguments => parent ? [gitdir, parent.gitdir] : [gitdir], |
| 112 | Task.create!(:target_class => self.class.name, |
| 113 | :command => parent ? "clone_git_repository" : "create_git_repository", |
| 114 | :arguments => parent ? [gitdir, parent.gitdir] : [gitdir], |
| 124 | 115 | :target_id => self.id) |
| 125 | 116 | end |
| 126 | | |
| 117 | |
| 127 | 118 | def create_delete_repos_task |
| 128 | | Task.create!(:target_class => self.class.name, |
| 119 | Task.create!(:target_class => self.class.name, |
| 129 | 120 | :command => "delete_git_repository", :arguments => [gitdir]) |
| 130 | 121 | end |
| 131 | | |
| 122 | |
| 132 | 123 | def paginated_commits(tree_name, page, per_page = 30) |
| 133 | 124 | page = (page || 1).to_i |
| 134 | 125 | total = git.commit_count(tree_name) |
| … | … | |
| 127 | 127 | commits = WillPaginate::Collection.new(page, per_page, total) |
| 128 | 128 | commits.replace git.commits(tree_name, per_page, offset) |
| 129 | 129 | end |
| 130 | | |
| 130 | |
| 131 | 131 | def count_commits_from_last_week_by_user(user) |
| 132 | 132 | return 0 unless has_commits? |
| 133 | | |
| 134 | | commits_by_email = git.commits_since("master", "last week").collect do |commit| |
| 135 | | commit.committer.email == user.email |
| 136 | | end |
| 133 | |
| 134 | commits_by_email = git.commits_since("master", "last week", user.email) |
| 135 | commits_by_email.size |
| 136 | end |
| 137 | |
| 138 | def count_commits_from_the_beginning_by_user(user) |
| 139 | return 0 unless has_commits? |
| 140 | |
| 141 | commits_by_email = git.commits_since("master", "1970-01-01", user.email) |
| 137 | 142 | commits_by_email.size |
| 138 | 143 | end |
| 139 | | |
| 144 | |
| 140 | 145 | # TODO: cache |
| 141 | | def commit_graph_data(head = "master") |
| 146 | def commit_graph_data(head = "master") |
| 142 | 147 | commits = git.commits_since(head, "24 weeks ago") |
| 143 | 148 | commits_by_week = commits.group_by{|c| c.committed_date.strftime("%W") } |
| 144 | | |
| 149 | |
| 145 | 150 | # build an initial empty set of 24 week commit data |
| 146 | | weeks = [1.day.from_now-1.week] |
| 151 | weeks = [1.day.from_now-1.week] |
| 147 | 152 | 23.times{|w| weeks << weeks.last-1.week } |
| 148 | 153 | week_numbers = weeks.map{|d| d.strftime("%W") } |
| 149 | 154 | commits = (0...24).to_a.map{|i| 0 } |
| 150 | | |
| 155 | |
| 151 | 156 | commits_by_week.each do |week, commits_in_week| |
| 152 | 157 | if week_pos = week_numbers.index(week) |
| 153 | 158 | commits[week_pos+1] = commits_in_week.size |
| … | … | |
| 161 | 161 | commits = [] if commits.max == 0 |
| 162 | 162 | [week_numbers.reverse, commits.reverse] |
| 163 | 163 | end |
| 164 | | |
| 164 | |
| 165 | 165 | # TODO: refactor into simpler approach |
| 166 | 166 | # TODO: caching |
| 167 | | def commit_graph_data_by_author(head = "master") |
| 167 | def commit_graph_data_by_author(head = "master") |
| 168 | 168 | h = Hash.new |
| 169 | | |
| 169 | |
| 170 | 170 | data = self.git.git.rev_list({:pretty => "format:name:%cn", :since => "1 years ago" }, head) |
| 171 | 171 | data.each_line do |line| |
| 172 | 172 | if line =~ /^name:(.*)$/ then |
| 173 | 173 | author = $1 |
| 174 | | |
| 174 | |
| 175 | 175 | if h[author] |
| 176 | 176 | h[author] += 1 |
| 177 | 177 | else |
| … | … | |
| 179 | 179 | end |
| 180 | 180 | end |
| 181 | 181 | end |
| 182 | | |
| 182 | |
| 183 | 183 | sorted = h.sort_by do |author, commits| |
| 184 | 184 | commits |
| 185 | 185 | end |
| 186 | | |
| 186 | |
| 187 | 187 | labels = [] |
| 188 | 188 | data = [] |
| 189 | | |
| 189 | |
| 190 | 190 | max = 8 |
| 191 | 191 | others = [] |
| 192 | 192 | top = sorted |
| 193 | | |
| 194 | | |
| 193 | |
| 194 | |
| 195 | 195 | if sorted.size > max |
| 196 | 196 | top = sorted[sorted.size-max, sorted.size] |
| 197 | 197 | others = sorted[0, sorted.size-max] |
| 198 | 198 | end |
| 199 | | |
| 199 | |
| 200 | 200 | top.each do |entry| |
| 201 | 201 | author = entry.first |
| 202 | 202 | v = entry.last |
| 203 | | |
| 203 | |
| 204 | 204 | data << v |
| 205 | 205 | labels << author |
| 206 | 206 | end |
| 207 | | |
| 207 | |
| 208 | 208 | unless others.empty? |
| 209 | 209 | others_v = others.inject { |v, acum| [v.last + acum.last] } |
| 210 | 210 | labels << "others" |
| 211 | 211 | data << others_v.last |
| 212 | 212 | end |
| 213 | | |
| 213 | |
| 214 | 214 | #[labels, data] |
| 215 | | labels.inject({}) do |hash, label| |
| 216 | | hash[label] = data[labels.index(label)] |
| 215 | labels.inject({}) do |hash, label| |
| 216 | hash[label] = data[labels.index(label)] |
| 217 | 217 | hash |
| 218 | 218 | end |
| 219 | 219 | end |
| 220 | | |
| 220 | |
| 221 | 221 | # Returns a Hash {email => user}, where email is selected from the +commits+ |
| 222 | 222 | def users_by_commits(commits) |
| 223 | 223 | emails = commits.map { |commit| commit.author.email }.uniq |
| 224 | 224 | users = User.find(:all, :conditions => ["email in (?)", emails]) |
| 225 | | |
| 225 | |
| 226 | 226 | users_by_email = users.inject({}){|hash, user| hash[user.email] = user; hash } |
| 227 | 227 | users_by_email |
| 228 | 228 | end |
| 229 | | |
| 230 | | def cloned_from(ip, country_code = "--", country_name = nil) |
| 231 | | cloners.create(:ip => ip, :date => Time.now.utc, :country_code => country_code, :country => country_name) |
| 232 | | end |
| 233 | | |
| 229 | |
| 234 | 230 | protected |
| 235 | 231 | def set_as_mainline_if_first |
| 236 | 232 | unless project.repositories.size >= 1 |
| 237 | 233 | self.mainline = true |
| 238 | 234 | end |
| 239 | 235 | end |
| 240 | | |
| 236 | |
| 241 | 237 | def add_user_as_committer |
| 242 | 238 | committers << user |
| 243 | 239 | end |
| 244 | | |
| 240 | |
| 245 | 241 | def self.full_path_from_partial_path(path) |
| 246 | 242 | File.expand_path(File.join(GitoriousConfig["repository_base_path"], path)) |
| 247 | 243 | end |
| toggle raw diff |
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -5,130 +5,121 @@ class Repository < ActiveRecord::Base
has_many :committerships, :dependent => :destroy
has_many :committers, :through => :committerships, :source => :user
has_many :comments, :dependent => :destroy
- has_many :merge_requests, :foreign_key => 'target_repository_id',
+ has_many :merge_requests, :foreign_key => 'target_repository_id',
:order => "status, id desc", :dependent => :destroy
- has_many :proposed_merge_requests, :foreign_key => 'source_repository_id',
+ has_many :proposed_merge_requests, :foreign_key => 'source_repository_id',
:class_name => 'MergeRequest', :order => "id desc", :dependent => :destroy
- has_many :cloners, :dependent => :destroy
-
+
validates_presence_of :user_id, :project_id, :name
validates_format_of :name, :with => /^[a-z0-9_\-]+$/i,
:message => "is invalid, must match something like /[a-z0-9_\\-]+/"
validates_uniqueness_of :name, :scope => :project_id, :case_sensitive => false
-
+
before_save :set_as_mainline_if_first
after_create :add_user_as_committer, :create_new_repos_task
after_destroy :create_delete_repos_task
-
+
def self.new_by_cloning(other, username=nil)
suggested_name = username ? "#{username}s-clone" : nil
new(:parent => other, :project => other.project, :name => suggested_name)
end
-
+
def self.find_by_name!(name)
find_by_name(name) || raise(ActiveRecord::RecordNotFound)
end
-
- def self.find_by_path(path)
- base_path = path.gsub(/^#{Regexp.escape(GitoriousConfig['repository_base_path'])}/, "")
- repo_name, project_name = base_path.split("/").reverse
-
- project = Project.find_by_slug!(project_name)
- project.repositories.find_by_name(repo_name.sub(/\.git/, ""))
- end
-
+
def self.create_git_repository(path)
git_backend.create(full_path_from_partial_path(path))
end
-
+
def self.clone_git_repository(target_path, source_path)
- git_backend.clone(full_path_from_partial_path(target_path),
+ git_backend.clone(full_path_from_partial_path(target_path),
full_path_from_partial_path(source_path))
end
-
+
def self.delete_git_repository(path)
git_backend.delete!(full_path_from_partial_path(path))
end
-
+
def gitdir
File.join(project.slug, "#{name}.git")
end
-
+
def clone_url
"git://#{GitoriousConfig['gitorious_host']}/#{gitdir}"
end
-
+
def http_clone_url
"http://git.#{GitoriousConfig['gitorious_host']}/#{gitdir}"
end
-
+
def push_url
"git@#{GitoriousConfig['gitorious_host']}:#{gitdir}"
end
-
+
def full_repository_path
self.class.full_path_from_partial_path(gitdir)
end
-
+
def git
Grit::Repo.new(full_repository_path)
end
-
+
def has_commits?
return false if new_record? || !ready?
!git.heads.empty?
end
-
+
def self.git_backend
RAILS_ENV == "test" ? MockGitBackend : GitBackend
end
-
+
def git_backend
RAILS_ENV == "test" ? MockGitBackend : GitBackend
end
-
+
def to_param
name
end
-
+
def to_xml(opts = {})
super({:methods => [:gitdir, :clone_url, :push_url]}.merge(opts))
end
-
+
def add_committer(user)
unless user.can_write_to?(self)
committers << user
end
end
-
+
def head_candidate
return nil unless has_commits?
@head_candidate ||= git.heads.find{|h| h.name == "master"} || git.heads.first
end
-
+
def last_commit
if has_commits?
@last_commit ||= git.commits(head_candidate.name, 1).first
end
@last_commit
end
-
+
def can_be_deleted_by?(candidate)
!mainline? && (candidate == user)
end
-
+
def create_new_repos_task
- Task.create!(:target_class => self.class.name,
- :command => parent ? "clone_git_repository" : "create_git_repository",
- :arguments => parent ? [gitdir, parent.gitdir] : [gitdir],
+ Task.create!(:target_class => self.class.name,
+ :command => parent ? "clone_git_repository" : "create_git_repository",
+ :arguments => parent ? [gitdir, parent.gitdir] : [gitdir],
:target_id => self.id)
end
-
+
def create_delete_repos_task
- Task.create!(:target_class => self.class.name,
+ Task.create!(:target_class => self.class.name,
:command => "delete_git_repository", :arguments => [gitdir])
end
-
+
def paginated_commits(tree_name, page, per_page = 30)
page = (page || 1).to_i
total = git.commit_count(tree_name)
@@ -136,27 +127,32 @@ class Repository < ActiveRecord::Base
commits = WillPaginate::Collection.new(page, per_page, total)
commits.replace git.commits(tree_name, per_page, offset)
end
-
+
def count_commits_from_last_week_by_user(user)
return 0 unless has_commits?
-
- commits_by_email = git.commits_since("master", "last week").collect do |commit|
- commit.committer.email == user.email
- end
+
+ commits_by_email = git.commits_since("master", "last week", user.email)
+ commits_by_email.size
+ end
+
+ def count_commits_from_the_beginning_by_user(user)
+ return 0 unless has_commits?
+
+ commits_by_email = git.commits_since("master", "1970-01-01", user.email)
commits_by_email.size
end
-
+
# TODO: cache
- def commit_graph_data(head = "master")
+ def commit_graph_data(head = "master")
commits = git.commits_since(head, "24 weeks ago")
commits_by_week = commits.group_by{|c| c.committed_date.strftime("%W") }
-
+
# build an initial empty set of 24 week commit data
- weeks = [1.day.from_now-1.week]
+ weeks = [1.day.from_now-1.week]
23.times{|w| weeks << weeks.last-1.week }
week_numbers = weeks.map{|d| d.strftime("%W") }
commits = (0...24).to_a.map{|i| 0 }
-
+
commits_by_week.each do |week, commits_in_week|
if week_pos = week_numbers.index(week)
commits[week_pos+1] = commits_in_week.size
@@ -165,17 +161,17 @@ class Repository < ActiveRecord::Base
commits = [] if commits.max == 0
[week_numbers.reverse, commits.reverse]
end
-
+
# TODO: refactor into simpler approach
# TODO: caching
- def commit_graph_data_by_author(head = "master")
+ def commit_graph_data_by_author(head = "master")
h = Hash.new
-
+
data = self.git.git.rev_list({:pretty => "format:name:%cn", :since => "1 years ago" }, head)
data.each_line do |line|
if line =~ /^name:(.*)$/ then
author = $1
-
+
if h[author]
h[author] += 1
else
@@ -183,69 +179,65 @@ class Repository < ActiveRecord::Base
end
end
end
-
+
sorted = h.sort_by do |author, commits|
commits
end
-
+
labels = []
data = []
-
+
max = 8
others = []
top = sorted
-
-
+
+
if sorted.size > max
top = sorted[sorted.size-max, sorted.size]
others = sorted[0, sorted.size-max]
end
-
+
top.each do |entry|
author = entry.first
v = entry.last
-
+
data << v
labels << author
end
-
+
unless others.empty?
others_v = others.inject { |v, acum| [v.last + acum.last] }
labels << "others"
data << others_v.last
end
-
+
#[labels, data]
- labels.inject({}) do |hash, label|
- hash[label] = data[labels.index(label)]
+ labels.inject({}) do |hash, label|
+ hash[label] = data[labels.index(label)]
hash
end
end
-
+
# Returns a Hash {email => user}, where email is selected from the +commits+
def users_by_commits(commits)
emails = commits.map { |commit| commit.author.email }.uniq
users = User.find(:all, :conditions => ["email in (?)", emails])
-
+
users_by_email = users.inject({}){|hash, user| hash[user.email] = user; hash }
users_by_email
end
-
- def cloned_from(ip, country_code = "--", country_name = nil)
- cloners.create(:ip => ip, :date => Time.now.utc, :country_code => country_code, :country => country_name)
- end
-
+
protected
def set_as_mainline_if_first
unless project.repositories.size >= 1
self.mainline = true
end
end
-
+
def add_user_as_committer
committers << user
end
-
+
def self.full_path_from_partial_path(path)
File.expand_path(File.join(GitoriousConfig["repository_base_path"], path))
end |
| |   |
| 6 | 6 | has_many :repositories, :through => :committerships |
| 7 | 7 | has_many :ssh_keys, :order => "id desc" |
| 8 | 8 | has_many :comments |
| 9 | | |
| 9 | |
| 10 | 10 | # Virtual attribute for the unencrypted password |
| 11 | 11 | attr_accessor :password, :current_password |
| 12 | | |
| 12 | |
| 13 | 13 | attr_protected :login |
| 14 | 14 | |
| 15 | | validates_presence_of :login, :email |
| 15 | validates_presence_of :login, :email, :if => :password_required? |
| 16 | 16 | validates_format_of :login, :with => /^[a-z0-9\-_\.]+$/i |
| 17 | 17 | validates_format_of :email, :with => /^[^@\s]+@([\-a-z0-9]+\.)+[a-z]{2,}$/i |
| 18 | 18 | validates_presence_of :password, :if => :password_required? |
| … | … | |
| 22 | 22 | validates_length_of :login, :within => 3..40 |
| 23 | 23 | validates_length_of :email, :within => 3..100 |
| 24 | 24 | validates_uniqueness_of :login, :email, :case_sensitive => false |
| 25 | | |
| 25 | |
| 26 | 26 | before_save :encrypt_password |
| 27 | | before_create :make_activation_code |
| 28 | | |
| 27 | before_create :make_activation_code |
| 28 | |
| 29 | 29 | def self.find_by_login!(name) |
| 30 | 30 | find_by_login(name) || raise(ActiveRecord::RecordNotFound ) |
| 31 | 31 | end |
| 32 | | |
| 32 | |
| 33 | 33 | # Authenticates a user by their login name and unencrypted password. Returns the user or nil. |
| 34 | 34 | def self.authenticate(email, password) |
| 35 | 35 | u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email] # need to get the salt |
| … | … | |
| 40 | 40 | def self.encrypt(password, salt) |
| 41 | 41 | Digest::SHA1.hexdigest("--#{salt}--#{password}--") |
| 42 | 42 | end |
| 43 | | |
| 43 | |
| 44 | 44 | def self.generate_random_password(password_size = 12) |
| 45 | 45 | characters = (("a".."z").to_a + ("0".."9").to_a) - %w[0 o i l 1] |
| 46 | 46 | (0...password_size).collect do |char| |
| … | … | |
| 75 | 75 | end |
| 76 | 76 | |
| 77 | 77 | def remember_token? |
| 78 | | remember_token_expires_at && Time.now.utc < remember_token_expires_at |
| 78 | remember_token_expires_at && Time.now.utc < remember_token_expires_at |
| 79 | 79 | end |
| 80 | 80 | |
| 81 | 81 | # These create and unset the fields required for remembering users between browser closes |
| … | … | |
| 98 | 98 | self.remember_token = nil |
| 99 | 99 | save(false) |
| 100 | 100 | end |
| 101 | | |
| 101 | |
| 102 | 102 | def reset_password! |
| 103 | 103 | generated = User.generate_random_password |
| 104 | 104 | self.password = generated |
| … | … | |
| 106 | 106 | self.save! |
| 107 | 107 | generated |
| 108 | 108 | end |
| 109 | | |
| 109 | |
| 110 | 110 | def can_write_to?(repository) |
| 111 | 111 | !!committerships.find_by_repository_id(repository.id) |
| 112 | 112 | end |
| 113 | | |
| 113 | |
| 114 | 114 | def to_param |
| 115 | 115 | login |
| 116 | 116 | end |
| 117 | | |
| 117 | |
| 118 | 118 | def to_xml(opts = {}) |
| 119 | 119 | super({:except => [:activation_code, :crypted_password, :remember_token, :remember_token_expires_at, :salt, :ssh_key_id]}.merge(opts)) |
| 120 | 120 | end |
| 121 | 121 | |
| 122 | def count_commits_from_last_week |
| 123 | repositories.inject(0) { |sum, repo| sum + repo.count_commits_from_last_week_by_user(self)} |
| 124 | end |
| 125 | |
| 126 | def count_commits_from_the_beginning |
| 127 | repositories.inject(0) { |sum, repo| sum + repo.count_commits_from_the_beginning_by_user(self)} |
| 128 | end |
| 129 | |
| 122 | 130 | protected |
| 123 | | # before filter |
| 131 | # before filter |
| 124 | 132 | def encrypt_password |
| 125 | 133 | return if password.blank? |
| 126 | 134 | self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record? |
| 127 | 135 | self.crypted_password = encrypt(password) |
| 128 | 136 | end |
| 129 | | |
| 137 | |
| 130 | 138 | def password_required? |
| 131 | | crypted_password.blank? || !password.blank? |
| 139 | not_openid? && (crypted_password.blank? || !password.blank?) |
| 132 | 140 | end |
| 133 | | |
| 141 | |
| 142 | def not_openid? |
| 143 | identity_url.blank? |
| 144 | end |
| 145 | |
| 134 | 146 | def make_activation_code |
| 135 | 147 | self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ) |
| 136 | | end |
| 148 | end |
| 137 | 149 | end |
| toggle raw diff |
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -6,13 +6,13 @@ class User < ActiveRecord::Base
has_many :repositories, :through => :committerships
has_many :ssh_keys, :order => "id desc"
has_many :comments
-
+
# Virtual attribute for the unencrypted password
attr_accessor :password, :current_password
-
+
attr_protected :login
- validates_presence_of :login, :email
+ validates_presence_of :login, :email, :if => :password_required?
validates_format_of :login, :with => /^[a-z0-9\-_\.]+$/i
validates_format_of :email, :with => /^[^@\s]+@([\-a-z0-9]+\.)+[a-z]{2,}$/i
validates_presence_of :password, :if => :password_required?
@@ -22,14 +22,14 @@ class User < ActiveRecord::Base
validates_length_of :login, :within => 3..40
validates_length_of :email, :within => 3..100
validates_uniqueness_of :login, :email, :case_sensitive => false
-
+
before_save :encrypt_password
- before_create :make_activation_code
-
+ before_create :make_activation_code
+
def self.find_by_login!(name)
find_by_login(name) || raise(ActiveRecord::RecordNotFound )
end
-
+
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
def self.authenticate(email, password)
u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email] # need to get the salt
@@ -40,7 +40,7 @@ class User < ActiveRecord::Base
def self.encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
-
+
def self.generate_random_password(password_size = 12)
characters = (("a".."z").to_a + ("0".."9").to_a) - %w[0 o i l 1]
(0...password_size).collect do |char|
@@ -75,7 +75,7 @@ class User < ActiveRecord::Base
end
def remember_token?
- remember_token_expires_at && Time.now.utc < remember_token_expires_at
+ remember_token_expires_at && Time.now.utc < remember_token_expires_at
end
# These create and unset the fields required for remembering users between browser closes
@@ -98,7 +98,7 @@ class User < ActiveRecord::Base
self.remember_token = nil
save(false)
end
-
+
def reset_password!
generated = User.generate_random_password
self.password = generated
@@ -106,32 +106,44 @@ class User < ActiveRecord::Base
self.save!
generated
end
-
+
def can_write_to?(repository)
!!committerships.find_by_repository_id(repository.id)
end
-
+
def to_param
login
end
-
+
def to_xml(opts = {})
super({:except => [:activation_code, :crypted_password, :remember_token, :remember_token_expires_at, :salt, :ssh_key_id]}.merge(opts))
end
+ def count_commits_from_last_week
+ repositories.inject(0) { |sum, repo| sum + repo.count_commits_from_last_week_by_user(self)}
+ end
+
+ def count_commits_from_the_beginning
+ repositories.inject(0) { |sum, repo| sum + repo.count_commits_from_the_beginning_by_user(self)}
+ end
+
protected
- # before filter
+ # before filter
def encrypt_password
return if password.blank?
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
self.crypted_password = encrypt(password)
end
-
+
def password_required?
- crypted_password.blank? || !password.blank?
+ not_openid? && (crypted_password.blank? || !password.blank?)
end
-
+
+ def not_openid?
+ identity_url.blank?
+ end
+
def make_activation_code
self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
- end
+ end
end |