Commit 02c35b4f3048f20a0d7cfd255437199da3c0e222

added user_stat_generator script

Commit diff

app/models/repository.rb

 
55 has_many :committerships, :dependent => :destroy
66 has_many :committers, :through => :committerships, :source => :user
77 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',
99 :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',
1111 :class_name => 'MergeRequest', :order => "id desc", :dependent => :destroy
12 has_many :cloners, :dependent => :destroy
13
12
1413 validates_presence_of :user_id, :project_id, :name
1514 validates_format_of :name, :with => /^[a-z0-9_\-]+$/i,
1615 :message => "is invalid, must match something like /[a-z0-9_\\-]+/"
1716 validates_uniqueness_of :name, :scope => :project_id, :case_sensitive => false
18
17
1918 before_save :set_as_mainline_if_first
2019 after_create :add_user_as_committer, :create_new_repos_task
2120 after_destroy :create_delete_repos_task
22
21
2322 def self.new_by_cloning(other, username=nil)
2423 suggested_name = username ? "#{username}s-clone" : nil
2524 new(:parent => other, :project => other.project, :name => suggested_name)
2625 end
27
26
2827 def self.find_by_name!(name)
2928 find_by_name(name) || raise(ActiveRecord::RecordNotFound)
3029 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
4031 def self.create_git_repository(path)
4132 git_backend.create(full_path_from_partial_path(path))
4233 end
43
34
4435 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),
4637 full_path_from_partial_path(source_path))
4738 end
48
39
4940 def self.delete_git_repository(path)
5041 git_backend.delete!(full_path_from_partial_path(path))
5142 end
52
43
5344 def gitdir
5445 File.join(project.slug, "#{name}.git")
5546 end
56
47
5748 def clone_url
5849 "git://#{GitoriousConfig['gitorious_host']}/#{gitdir}"
5950 end
60
51
6152 def http_clone_url
6253 "http://git.#{GitoriousConfig['gitorious_host']}/#{gitdir}"
6354 end
64
55
6556 def push_url
6657 "git@#{GitoriousConfig['gitorious_host']}:#{gitdir}"
6758 end
68
59
6960 def full_repository_path
7061 self.class.full_path_from_partial_path(gitdir)
7162 end
72
63
7364 def git
7465 Grit::Repo.new(full_repository_path)
7566 end
76
67
7768 def has_commits?
7869 return false if new_record? || !ready?
7970 !git.heads.empty?
8071 end
81
72
8273 def self.git_backend
8374 RAILS_ENV == "test" ? MockGitBackend : GitBackend
8475 end
85
76
8677 def git_backend
8778 RAILS_ENV == "test" ? MockGitBackend : GitBackend
8879 end
89
80
9081 def to_param
9182 name
9283 end
93
84
9485 def to_xml(opts = {})
9586 super({:methods => [:gitdir, :clone_url, :push_url]}.merge(opts))
9687 end
97
88
9889 def add_committer(user)
9990 unless user.can_write_to?(self)
10091 committers << user
10192 end
10293 end
103
94
10495 def head_candidate
10596 return nil unless has_commits?
10697 @head_candidate ||= git.heads.find{|h| h.name == "master"} || git.heads.first
10798 end
108
99
109100 def last_commit
110101 if has_commits?
111102 @last_commit ||= git.commits(head_candidate.name, 1).first
112103 end
113104 @last_commit
114105 end
115
106
116107 def can_be_deleted_by?(candidate)
117108 !mainline? && (candidate == user)
118109 end
119
110
120111 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],
124115 :target_id => self.id)
125116 end
126
117
127118 def create_delete_repos_task
128 Task.create!(:target_class => self.class.name,
119 Task.create!(:target_class => self.class.name,
129120 :command => "delete_git_repository", :arguments => [gitdir])
130121 end
131
122
132123 def paginated_commits(tree_name, page, per_page = 30)
133124 page = (page || 1).to_i
134125 total = git.commit_count(tree_name)
127127 commits = WillPaginate::Collection.new(page, per_page, total)
128128 commits.replace git.commits(tree_name, per_page, offset)
129129 end
130
130
131131 def count_commits_from_last_week_by_user(user)
132132 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)
137142 commits_by_email.size
138143 end
139
144
140145 # TODO: cache
141 def commit_graph_data(head = "master")
146 def commit_graph_data(head = "master")
142147 commits = git.commits_since(head, "24 weeks ago")
143148 commits_by_week = commits.group_by{|c| c.committed_date.strftime("%W") }
144
149
145150 # 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]
147152 23.times{|w| weeks << weeks.last-1.week }
148153 week_numbers = weeks.map{|d| d.strftime("%W") }
149154 commits = (0...24).to_a.map{|i| 0 }
150
155
151156 commits_by_week.each do |week, commits_in_week|
152157 if week_pos = week_numbers.index(week)
153158 commits[week_pos+1] = commits_in_week.size
161161 commits = [] if commits.max == 0
162162 [week_numbers.reverse, commits.reverse]
163163 end
164
164
165165 # TODO: refactor into simpler approach
166166 # TODO: caching
167 def commit_graph_data_by_author(head = "master")
167 def commit_graph_data_by_author(head = "master")
168168 h = Hash.new
169
169
170170 data = self.git.git.rev_list({:pretty => "format:name:%cn", :since => "1 years ago" }, head)
171171 data.each_line do |line|
172172 if line =~ /^name:(.*)$/ then
173173 author = $1
174
174
175175 if h[author]
176176 h[author] += 1
177177 else
179179 end
180180 end
181181 end
182
182
183183 sorted = h.sort_by do |author, commits|
184184 commits
185185 end
186
186
187187 labels = []
188188 data = []
189
189
190190 max = 8
191191 others = []
192192 top = sorted
193
194
193
194
195195 if sorted.size > max
196196 top = sorted[sorted.size-max, sorted.size]
197197 others = sorted[0, sorted.size-max]
198198 end
199
199
200200 top.each do |entry|
201201 author = entry.first
202202 v = entry.last
203
203
204204 data << v
205205 labels << author
206206 end
207
207
208208 unless others.empty?
209209 others_v = others.inject { |v, acum| [v.last + acum.last] }
210210 labels << "others"
211211 data << others_v.last
212212 end
213
213
214214 #[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)]
217217 hash
218218 end
219219 end
220
220
221221 # Returns a Hash {email => user}, where email is selected from the +commits+
222222 def users_by_commits(commits)
223223 emails = commits.map { |commit| commit.author.email }.uniq
224224 users = User.find(:all, :conditions => ["email in (?)", emails])
225
225
226226 users_by_email = users.inject({}){|hash, user| hash[user.email] = user; hash }
227227 users_by_email
228228 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
234230 protected
235231 def set_as_mainline_if_first
236232 unless project.repositories.size >= 1
237233 self.mainline = true
238234 end
239235 end
240
236
241237 def add_user_as_committer
242238 committers << user
243239 end
244
240
245241 def self.full_path_from_partial_path(path)
246242 File.expand_path(File.join(GitoriousConfig["repository_base_path"], path))
247243 end
toggle raw diff

app/models/user.rb

 
66 has_many :repositories, :through => :committerships
77 has_many :ssh_keys, :order => "id desc"
88 has_many :comments
9
9
1010 # Virtual attribute for the unencrypted password
1111 attr_accessor :password, :current_password
12
12
1313 attr_protected :login
1414
15 validates_presence_of :login, :email
15 validates_presence_of :login, :email, :if => :password_required?
1616 validates_format_of :login, :with => /^[a-z0-9\-_\.]+$/i
1717 validates_format_of :email, :with => /^[^@\s]+@([\-a-z0-9]+\.)+[a-z]{2,}$/i
1818 validates_presence_of :password, :if => :password_required?
2222 validates_length_of :login, :within => 3..40
2323 validates_length_of :email, :within => 3..100
2424 validates_uniqueness_of :login, :email, :case_sensitive => false
25
25
2626 before_save :encrypt_password
27 before_create :make_activation_code
28
27 before_create :make_activation_code
28
2929 def self.find_by_login!(name)
3030 find_by_login(name) || raise(ActiveRecord::RecordNotFound )
3131 end
32
32
3333 # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
3434 def self.authenticate(email, password)
3535 u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email] # need to get the salt
4040 def self.encrypt(password, salt)
4141 Digest::SHA1.hexdigest("--#{salt}--#{password}--")
4242 end
43
43
4444 def self.generate_random_password(password_size = 12)
4545 characters = (("a".."z").to_a + ("0".."9").to_a) - %w[0 o i l 1]
4646 (0...password_size).collect do |char|
7575 end
7676
7777 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
7979 end
8080
8181 # These create and unset the fields required for remembering users between browser closes
9898 self.remember_token = nil
9999 save(false)
100100 end
101
101
102102 def reset_password!
103103 generated = User.generate_random_password
104104 self.password = generated
106106 self.save!
107107 generated
108108 end
109
109
110110 def can_write_to?(repository)
111111 !!committerships.find_by_repository_id(repository.id)
112112 end
113
113
114114 def to_param
115115 login
116116 end
117
117
118118 def to_xml(opts = {})
119119 super({:except => [:activation_code, :crypted_password, :remember_token, :remember_token_expires_at, :salt, :ssh_key_id]}.merge(opts))
120120 end
121121
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
122130 protected
123 # before filter
131 # before filter
124132 def encrypt_password
125133 return if password.blank?
126134 self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
127135 self.crypted_password = encrypt(password)
128136 end
129
137
130138 def password_required?
131 crypted_password.blank? || !password.blank?
139 not_openid? && (crypted_password.blank? || !password.blank?)
132140 end
133
141
142 def not_openid?
143 identity_url.blank?
144 end
145
134146 def make_activation_code
135147 self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
136 end
148 end
137149end
toggle raw diff

vendor/grit/lib/grit/commit.rb

 
8383 #
8484 # Returns Grit::Commit[] (baked)
8585 def self.find_all(repo, ref, options = {})
86 allowed_options = [:max_count, :skip, :since]
86 allowed_options = [:max_count, :skip, :since, :author]
8787
8888 default_options = {:pretty => "raw"}
8989 actual_options = default_options.merge(options)
toggle raw diff

vendor/grit/lib/grit/repo.rb

 
9292 # +extra_options+ is a hash of extra options
9393 #
9494 # Returns Grit::Commit[] (baked)
95 def commits_since(start = 'master', since = '1970-01-01', extra_options = {})
96 options = {:since => since}.merge(extra_options)
97
95 def commits_since(start = 'master', since = '1970-01-01', author='', extra_options = {})
96 options = {:since => since, :author => author}.merge(extra_options)
9897 Commit.find_all(self, start, options)
9998 end
10099
toggle raw diff