Commit 0a70aca3b177cffccd2e04579712665d10b8fd69

Authored by Dmitriy Zaporozhets
1 parent 98b84166

Models Refactoring: Move methods to roles

app/models/event.rb
1 class Event < ActiveRecord::Base 1 class Event < ActiveRecord::Base
  2 + include PushEvent
  3 +
2 default_scope where("author_id IS NOT NULL") 4 default_scope where("author_id IS NOT NULL")
3 5
4 Created = 1 6 Created = 1
@@ -9,8 +11,6 @@ class Event &lt; ActiveRecord::Base @@ -9,8 +11,6 @@ class Event &lt; ActiveRecord::Base
9 Commented = 6 11 Commented = 6
10 Merged = 7 12 Merged = 7
11 13
12 - does "event/push"  
13 -  
14 belongs_to :project 14 belongs_to :project
15 belongs_to :target, :polymorphic => true 15 belongs_to :target, :polymorphic => true
16 16
app/models/event/push_trait.rb
@@ -1,92 +0,0 @@ @@ -1,92 +0,0 @@
1 -module Event::PushTrait  
2 - as_trait do  
3 - def valid_push?  
4 - data[:ref]  
5 - rescue => ex  
6 - false  
7 - end  
8 -  
9 - def tag?  
10 - data[:ref]["refs/tags"]  
11 - end  
12 -  
13 - def new_branch?  
14 - commit_from =~ /^00000/  
15 - end  
16 -  
17 - def new_ref?  
18 - commit_from =~ /^00000/  
19 - end  
20 -  
21 - def rm_ref?  
22 - commit_to =~ /^00000/  
23 - end  
24 -  
25 - def md_ref?  
26 - !(rm_ref? || new_ref?)  
27 - end  
28 -  
29 - def commit_from  
30 - data[:before]  
31 - end  
32 -  
33 - def commit_to  
34 - data[:after]  
35 - end  
36 -  
37 - def ref_name  
38 - if tag?  
39 - tag_name  
40 - else  
41 - branch_name  
42 - end  
43 - end  
44 -  
45 - def branch_name  
46 - @branch_name ||= data[:ref].gsub("refs/heads/", "")  
47 - end  
48 -  
49 - def tag_name  
50 - @tag_name ||= data[:ref].gsub("refs/tags/", "")  
51 - end  
52 -  
53 - # Max 20 commits from push DESC  
54 - def commits  
55 - @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse  
56 - end  
57 -  
58 - def commits_count  
59 - data[:total_commits_count] || commits.count || 0  
60 - end  
61 -  
62 - def ref_type  
63 - tag? ? "tag" : "branch"  
64 - end  
65 -  
66 - def push_action_name  
67 - if new_ref?  
68 - "pushed new"  
69 - elsif rm_ref?  
70 - "removed #{ref_type}"  
71 - else  
72 - "pushed to"  
73 - end  
74 - end  
75 -  
76 - def parent_commit  
77 - project.commit(commit_from)  
78 - rescue => ex  
79 - nil  
80 - end  
81 -  
82 - def last_commit  
83 - project.commit(commit_to)  
84 - rescue => ex  
85 - nil  
86 - end  
87 -  
88 - def push_with_commits?  
89 - md_ref? && commits.any? && parent_commit && last_commit  
90 - end  
91 - end  
92 -end  
app/models/issue.rb
1 class Issue < ActiveRecord::Base 1 class Issue < ActiveRecord::Base
  2 + include Upvote
  3 +
2 belongs_to :project 4 belongs_to :project
3 belongs_to :milestone 5 belongs_to :milestone
4 belongs_to :author, :class_name => "User" 6 belongs_to :author, :class_name => "User"
@@ -53,11 +55,6 @@ class Issue &lt; ActiveRecord::Base @@ -53,11 +55,6 @@ class Issue &lt; ActiveRecord::Base
53 def new? 55 def new?
54 today? && created_at == updated_at 56 today? && created_at == updated_at
55 end 57 end
56 -  
57 - # Return the number of +1 comments (upvotes)  
58 - def upvotes  
59 - notes.select(&:upvote?).size  
60 - end  
61 end 58 end
62 # == Schema Information 59 # == Schema Information
63 # 60 #
app/models/key.rb
1 require 'digest/md5' 1 require 'digest/md5'
2 2
3 class Key < ActiveRecord::Base 3 class Key < ActiveRecord::Base
  4 + include SshKey
4 belongs_to :user 5 belongs_to :user
5 belongs_to :project 6 belongs_to :project
6 7
@@ -37,28 +38,11 @@ class Key &lt; ActiveRecord::Base @@ -37,28 +38,11 @@ class Key &lt; ActiveRecord::Base
37 end 38 end
38 end 39 end
39 40
40 - def update_repository  
41 - Gitlab::GitHost.system.new.configure do |c|  
42 - c.update_keys(identifier, key)  
43 - c.update_projects(projects)  
44 - end  
45 - end  
46 -  
47 - def repository_delete_key  
48 - Gitlab::GitHost.system.new.configure do |c|  
49 - #delete key file is there is no identically deploy keys  
50 - if !is_deploy_key || Key.where(:identifier => identifier).count() == 0  
51 - c.delete_key(identifier)  
52 - end  
53 - c.update_projects(projects)  
54 - end  
55 - end  
56 -  
57 def is_deploy_key 41 def is_deploy_key
58 true if project_id 42 true if project_id
59 end 43 end
60 44
61 - #projects that has this key 45 + # projects that has this key
62 def projects 46 def projects
63 if is_deploy_key 47 if is_deploy_key
64 [project] 48 [project]
app/models/merge_request.rb
1 require File.join(Rails.root, "app/models/commit") 1 require File.join(Rails.root, "app/models/commit")
2 2
3 class MergeRequest < ActiveRecord::Base 3 class MergeRequest < ActiveRecord::Base
  4 + include Upvote
  5 +
4 UNCHECKED = 1 6 UNCHECKED = 1
5 CAN_BE_MERGED = 2 7 CAN_BE_MERGED = 2
6 CANNOT_BE_MERGED = 3 8 CANNOT_BE_MERGED = 3
@@ -128,12 +130,6 @@ class MergeRequest &lt; ActiveRecord::Base @@ -128,12 +130,6 @@ class MergeRequest &lt; ActiveRecord::Base
128 self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Closed).last 130 self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Closed).last
129 end 131 end
130 132
131 -  
132 - # Return the number of +1 comments (upvotes)  
133 - def upvotes  
134 - notes.select(&:upvote?).size  
135 - end  
136 -  
137 def commits 133 def commits
138 st_commits || [] 134 st_commits || []
139 end 135 end
app/models/project.rb
1 require "grit" 1 require "grit"
2 2
3 class Project < ActiveRecord::Base 3 class Project < ActiveRecord::Base
  4 + include Repository
  5 + include GitPush
  6 + include Authority
  7 + include Team
  8 +
  9 + #
  10 + # Relations
  11 + #
4 belongs_to :owner, :class_name => "User" 12 belongs_to :owner, :class_name => "User"
5 -  
6 - does "project/validations"  
7 - does "project/repository"  
8 - does "project/permissions"  
9 - does "project/hooks"  
10 -  
11 has_many :users, :through => :users_projects 13 has_many :users, :through => :users_projects
12 has_many :events, :dependent => :destroy 14 has_many :events, :dependent => :destroy
13 has_many :merge_requests, :dependent => :destroy 15 has_many :merge_requests, :dependent => :destroy
@@ -21,8 +23,14 @@ class Project &lt; ActiveRecord::Base @@ -21,8 +23,14 @@ class Project &lt; ActiveRecord::Base
21 has_many :wikis, :dependent => :destroy 23 has_many :wikis, :dependent => :destroy
22 has_many :protected_branches, :dependent => :destroy 24 has_many :protected_branches, :dependent => :destroy
23 25
  26 + #
  27 + # Protected attributes
  28 + #
24 attr_protected :private_flag, :owner_id 29 attr_protected :private_flag, :owner_id
25 30
  31 + #
  32 + # Scopes
  33 + #
26 scope :public_only, where(:private_flag => false) 34 scope :public_only, where(:private_flag => false)
27 scope :without_user, lambda { |user| where("id not in (:ids)", :ids => user.projects.map(&:id) ) } 35 scope :without_user, lambda { |user| where("id not in (:ids)", :ids => user.projects.map(&:id) ) }
28 36
@@ -30,29 +38,63 @@ class Project &lt; ActiveRecord::Base @@ -30,29 +38,63 @@ class Project &lt; ActiveRecord::Base
30 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") 38 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
31 end 39 end
32 40
33 - def self.access_options  
34 - UsersProject.access_roles  
35 - end  
36 -  
37 def self.search query 41 def self.search query
38 where("name like :query or code like :query or path like :query", :query => "%#{query}%") 42 where("name like :query or code like :query or path like :query", :query => "%#{query}%")
39 end 43 end
40 44
41 - def to_param  
42 - code 45 + #
  46 + # Validations
  47 + #
  48 + validates :name,
  49 + :uniqueness => true,
  50 + :presence => true,
  51 + :length => { :within => 0..255 }
  52 +
  53 + validates :path,
  54 + :uniqueness => true,
  55 + :presence => true,
  56 + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
  57 + :message => "only letters, digits & '_' '-' '.' allowed" },
  58 + :length => { :within => 0..255 }
  59 +
  60 + validates :description,
  61 + :length => { :within => 0..2000 }
  62 +
  63 + validates :code,
  64 + :presence => true,
  65 + :uniqueness => true,
  66 + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
  67 + :message => "only letters, digits & '_' '-' '.' allowed" },
  68 + :length => { :within => 1..255 }
  69 +
  70 + validates :owner, :presence => true
  71 + validate :check_limit
  72 + validate :repo_name
  73 +
  74 + def check_limit
  75 + unless owner.can_create_project?
  76 + errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
  77 + end
  78 + rescue
  79 + errors[:base] << ("Cant check your ability to create project")
43 end 80 end
44 81
45 - def web_url  
46 - [GIT_HOST['host'], code].join("/") 82 + def repo_name
  83 + if path == "gitolite-admin"
  84 + errors.add(:path, " like 'gitolite-admin' is not allowed")
  85 + end
  86 + end
  87 +
  88 + def self.access_options
  89 + UsersProject.access_roles
47 end 90 end
48 91
49 - def team_member_by_name_or_email(email = nil, name = nil)  
50 - user = users.where("email like ? or name like ?", email, name).first  
51 - users_projects.find_by_user_id(user.id) if user 92 + def to_param
  93 + code
52 end 94 end
53 95
54 - def team_member_by_id(user_id)  
55 - users_projects.find_by_user_id(user_id) 96 + def web_url
  97 + [GIT_HOST['host'], code].join("/")
56 end 98 end
57 99
58 def common_notes 100 def common_notes
app/models/project/hooks_trait.rb
@@ -1,109 +0,0 @@ @@ -1,109 +0,0 @@
1 -module Project::HooksTrait  
2 - as_trait do  
3 - def observe_push(oldrev, newrev, ref, user)  
4 - data = post_receive_data(oldrev, newrev, ref, user)  
5 -  
6 - Event.create(  
7 - :project => self,  
8 - :action => Event::Pushed,  
9 - :data => data,  
10 - :author_id => data[:user_id]  
11 - )  
12 - end  
13 -  
14 - def update_merge_requests(oldrev, newrev, ref, user)  
15 - return true unless ref =~ /heads/  
16 - branch_name = ref.gsub("refs/heads/", "")  
17 - c_ids = self.commits_between(oldrev, newrev).map(&:id)  
18 -  
19 - # Update code for merge requests  
20 - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all  
21 - mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }  
22 -  
23 - # Close merge requests  
24 - mrs = self.merge_requests.opened.where(:target_branch => branch_name).all  
25 - mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }  
26 - mrs.each { |merge_request| merge_request.merge!(user.id) }  
27 -  
28 - true  
29 - end  
30 -  
31 - def execute_web_hooks(oldrev, newrev, ref, user)  
32 - ref_parts = ref.split('/')  
33 -  
34 - # Return if this is not a push to a branch (e.g. new commits)  
35 - return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"  
36 -  
37 - data = post_receive_data(oldrev, newrev, ref, user)  
38 -  
39 - web_hooks.each { |web_hook| web_hook.execute(data) }  
40 - end  
41 -  
42 - def post_receive_data(oldrev, newrev, ref, user)  
43 -  
44 - push_commits = commits_between(oldrev, newrev)  
45 -  
46 - # Total commits count  
47 - push_commits_count = push_commits.size  
48 -  
49 - # Get latest 20 commits ASC  
50 - push_commits_limited = push_commits.last(20)  
51 -  
52 - # Hash to be passed as post_receive_data  
53 - data = {  
54 - before: oldrev,  
55 - after: newrev,  
56 - ref: ref,  
57 - user_id: user.id,  
58 - user_name: user.name,  
59 - repository: {  
60 - name: name,  
61 - url: web_url,  
62 - description: description,  
63 - homepage: web_url,  
64 - },  
65 - commits: [],  
66 - total_commits_count: push_commits_count  
67 - }  
68 -  
69 - # For perfomance purposes maximum 20 latest commits  
70 - # will be passed as post receive hook data.  
71 - #  
72 - push_commits_limited.each do |commit|  
73 - data[:commits] << {  
74 - id: commit.id,  
75 - message: commit.safe_message,  
76 - timestamp: commit.date.xmlschema,  
77 - url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",  
78 - author: {  
79 - name: commit.author_name,  
80 - email: commit.author_email  
81 - }  
82 - }  
83 - end  
84 -  
85 - data  
86 - end  
87 -  
88 -  
89 - # This method will be called after each post receive  
90 - # and only if autor_key_id present in gitlab.  
91 - # All callbacks for post receive should be placed here  
92 - #  
93 - def trigger_post_receive(oldrev, newrev, ref, author_key_id)  
94 - user = Key.find_by_identifier(author_key_id).user  
95 -  
96 - # Create push event  
97 - self.observe_push(oldrev, newrev, ref, user)  
98 -  
99 - # Close merged MR  
100 - self.update_merge_requests(oldrev, newrev, ref, user)  
101 -  
102 - # Execute web hooks  
103 - self.execute_web_hooks(oldrev, newrev, ref, user)  
104 -  
105 - # Create satellite  
106 - self.satellite.create unless self.satellite.exists?  
107 - end  
108 - end  
109 -end  
app/models/project/permissions_trait.rb
@@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@
1 -module Project::PermissionsTrait  
2 - as_trait do  
3 - # Compatible with all access rights  
4 - # Should be rewrited for new access rights  
5 - def add_access(user, *access)  
6 - access = if access.include?(:admin)  
7 - { :project_access => UsersProject::MASTER }  
8 - elsif access.include?(:write)  
9 - { :project_access => UsersProject::DEVELOPER }  
10 - else  
11 - { :project_access => UsersProject::REPORTER }  
12 - end  
13 - opts = { :user => user }  
14 - opts.merge!(access)  
15 - users_projects.create(opts)  
16 - end  
17 -  
18 - def reset_access(user)  
19 - users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id  
20 - end  
21 -  
22 - def repository_readers  
23 - keys = Key.joins({:user => :users_projects}).  
24 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)  
25 - keys.map(&:identifier) + deploy_keys.map(&:identifier)  
26 - end  
27 -  
28 - def repository_writers  
29 - keys = Key.joins({:user => :users_projects}).  
30 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)  
31 - keys.map(&:identifier)  
32 - end  
33 -  
34 - def repository_masters  
35 - keys = Key.joins({:user => :users_projects}).  
36 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)  
37 - keys.map(&:identifier)  
38 - end  
39 -  
40 - def allow_read_for?(user)  
41 - !users_projects.where(:user_id => user.id).empty?  
42 - end  
43 -  
44 - def guest_access_for?(user)  
45 - !users_projects.where(:user_id => user.id).empty?  
46 - end  
47 -  
48 - def report_access_for?(user)  
49 - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?  
50 - end  
51 -  
52 - def dev_access_for?(user)  
53 - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?  
54 - end  
55 -  
56 - def master_access_for?(user)  
57 - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id  
58 - end  
59 - end  
60 -end  
app/models/project/repository_trait.rb
@@ -1,122 +0,0 @@ @@ -1,122 +0,0 @@
1 -module Project::RepositoryTrait  
2 - as_trait do  
3 - def valid_repo?  
4 - repo  
5 - rescue  
6 - errors.add(:path, "Invalid repository path")  
7 - false  
8 - end  
9 -  
10 - def commit(commit_id = nil)  
11 - Commit.find_or_first(repo, commit_id, root_ref)  
12 - end  
13 -  
14 - def fresh_commits(n = 10)  
15 - Commit.fresh_commits(repo, n)  
16 - end  
17 -  
18 - def commits_with_refs(n = 20)  
19 - Commit.commits_with_refs(repo, n)  
20 - end  
21 -  
22 - def commits_since(date)  
23 - Commit.commits_since(repo, date)  
24 - end  
25 -  
26 - def commits(ref, path = nil, limit = nil, offset = nil)  
27 - Commit.commits(repo, ref, path, limit, offset)  
28 - end  
29 -  
30 - def commits_between(from, to)  
31 - Commit.commits_between(repo, from, to)  
32 - end  
33 -  
34 - def write_hooks  
35 - %w(post-receive).each do |hook|  
36 - write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))  
37 - end  
38 - end  
39 -  
40 - def satellite  
41 - @satellite ||= Gitlab::Satellite.new(self)  
42 - end  
43 -  
44 - def write_hook(name, content)  
45 - hook_file = File.join(path_to_repo, 'hooks', name)  
46 -  
47 - File.open(hook_file, 'w') do |f|  
48 - f.write(content)  
49 - end  
50 -  
51 - File.chmod(0775, hook_file)  
52 - end  
53 -  
54 - def has_post_receive_file?  
55 - hook_file = File.join(path_to_repo, 'hooks', 'post-receive')  
56 - File.exists?(hook_file)  
57 - end  
58 -  
59 - def tags  
60 - repo.tags.map(&:name).sort.reverse  
61 - end  
62 -  
63 - def repo  
64 - @repo ||= Grit::Repo.new(path_to_repo)  
65 - end  
66 -  
67 - def url_to_repo  
68 - Gitlab::GitHost.url_to_repo(path)  
69 - end  
70 -  
71 - def path_to_repo  
72 - File.join(GIT_HOST["base_path"], "#{path}.git")  
73 - end  
74 -  
75 - def update_repository  
76 - Gitlab::GitHost.system.update_project(path, self)  
77 -  
78 - write_hooks if File.exists?(path_to_repo)  
79 - end  
80 -  
81 - def destroy_repository  
82 - Gitlab::GitHost.system.destroy_project(self)  
83 - end  
84 -  
85 - def repo_exists?  
86 - @repo_exists ||= (repo && !repo.branches.empty?)  
87 - rescue  
88 - @repo_exists = false  
89 - end  
90 -  
91 - def heads  
92 - @heads ||= repo.heads  
93 - end  
94 -  
95 - def tree(fcommit, path = nil)  
96 - fcommit = commit if fcommit == :head  
97 - tree = fcommit.tree  
98 - path ? (tree / path) : tree  
99 - end  
100 -  
101 - def open_branches  
102 - if protected_branches.empty?  
103 - self.repo.heads  
104 - else  
105 - pnames = protected_branches.map(&:name)  
106 - self.repo.heads.reject { |h| pnames.include?(h.name) }  
107 - end.sort_by(&:name)  
108 - end  
109 -  
110 - def has_commits?  
111 - !!commit  
112 - end  
113 -  
114 - def root_ref  
115 - default_branch || "master"  
116 - end  
117 -  
118 - def root_ref? branch  
119 - root_ref == branch  
120 - end  
121 - end  
122 -end  
app/models/project/validations_trait.rb
@@ -1,43 +0,0 @@ @@ -1,43 +0,0 @@
1 -module Project::ValidationsTrait  
2 - as_trait do  
3 - validates :name,  
4 - :uniqueness => true,  
5 - :presence => true,  
6 - :length => { :within => 0..255 }  
7 -  
8 - validates :path,  
9 - :uniqueness => true,  
10 - :presence => true,  
11 - :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,  
12 - :message => "only letters, digits & '_' '-' '.' allowed" },  
13 - :length => { :within => 0..255 }  
14 -  
15 - validates :description,  
16 - :length => { :within => 0..2000 }  
17 -  
18 - validates :code,  
19 - :presence => true,  
20 - :uniqueness => true,  
21 - :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,  
22 - :message => "only letters, digits & '_' '-' '.' allowed" },  
23 - :length => { :within => 1..255 }  
24 -  
25 - validates :owner, :presence => true  
26 - validate :check_limit  
27 - validate :repo_name  
28 -  
29 - def check_limit  
30 - unless owner.can_create_project?  
31 - errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")  
32 - end  
33 - rescue  
34 - errors[:base] << ("Cant check your ability to create project")  
35 - end  
36 -  
37 - def repo_name  
38 - if path == "gitolite-admin"  
39 - errors.add(:path, " like 'gitolite-admin' is not allowed")  
40 - end  
41 - end  
42 - end  
43 -end  
app/models/user.rb
1 class User < ActiveRecord::Base 1 class User < ActiveRecord::Base
  2 + include Account
  3 +
2 devise :database_authenticatable, :token_authenticatable, 4 devise :database_authenticatable, :token_authenticatable,
3 :recoverable, :rememberable, :trackable, :validatable, :omniauthable 5 :recoverable, :rememberable, :trackable, :validatable, :omniauthable
4 6
@@ -65,30 +67,6 @@ class User &lt; ActiveRecord::Base @@ -65,30 +67,6 @@ class User &lt; ActiveRecord::Base
65 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') 67 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
66 end 68 end
67 69
68 - def identifier  
69 - email.gsub /[@.]/, "_"  
70 - end  
71 -  
72 - def is_admin?  
73 - admin  
74 - end  
75 -  
76 - def require_ssh_key?  
77 - keys.count == 0  
78 - end  
79 -  
80 - def can_create_project?  
81 - projects_limit > my_own_projects.count  
82 - end  
83 -  
84 - def last_activity_project  
85 - projects.first  
86 - end  
87 -  
88 - def first_name  
89 - name.split.first unless name.blank?  
90 - end  
91 -  
92 def self.find_for_ldap_auth(omniauth_info) 70 def self.find_for_ldap_auth(omniauth_info)
93 name = omniauth_info.name.force_encoding("utf-8") 71 name = omniauth_info.name.force_encoding("utf-8")
94 email = omniauth_info.email.downcase 72 email = omniauth_info.email.downcase
@@ -105,30 +83,6 @@ class User &lt; ActiveRecord::Base @@ -105,30 +83,6 @@ class User &lt; ActiveRecord::Base
105 ) 83 )
106 end 84 end
107 end 85 end
108 -  
109 - def cared_merge_requests  
110 - MergeRequest.where("author_id = :id or assignee_id = :id", :id => self.id).opened  
111 - end  
112 -  
113 - def project_ids  
114 - projects.map(&:id)  
115 - end  
116 -  
117 - # Remove user from all projects and  
118 - # set blocked attribute to true  
119 - def block  
120 - users_projects.all.each do |membership|  
121 - return false unless membership.destroy  
122 - end  
123 -  
124 - self.blocked = true  
125 - save  
126 - end  
127 -  
128 - def projects_limit_percent  
129 - return 100 if projects_limit.zero?  
130 - (my_own_projects.count.to_f / projects_limit) * 100  
131 - end  
132 end 86 end
133 # == Schema Information 87 # == Schema Information
134 # 88 #
app/roles/account.rb 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +module Account
  2 + def identifier
  3 + email.gsub /[@.]/, "_"
  4 + end
  5 +
  6 + def is_admin?
  7 + admin
  8 + end
  9 +
  10 + def require_ssh_key?
  11 + keys.count == 0
  12 + end
  13 +
  14 + def can_create_project?
  15 + projects_limit > my_own_projects.count
  16 + end
  17 +
  18 + def last_activity_project
  19 + projects.first
  20 + end
  21 +
  22 + def first_name
  23 + name.split.first unless name.blank?
  24 + end
  25 +
  26 + def cared_merge_requests
  27 + MergeRequest.where("author_id = :id or assignee_id = :id", :id => self.id).opened
  28 + end
  29 +
  30 + def project_ids
  31 + projects.map(&:id)
  32 + end
  33 +
  34 + # Remove user from all projects and
  35 + # set blocked attribute to true
  36 + def block
  37 + users_projects.all.each do |membership|
  38 + return false unless membership.destroy
  39 + end
  40 +
  41 + self.blocked = true
  42 + save
  43 + end
  44 +
  45 + def projects_limit_percent
  46 + return 100 if projects_limit.zero?
  47 + (my_own_projects.count.to_f / projects_limit) * 100
  48 + end
  49 +end
app/roles/authority.rb 0 → 100644
@@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
  1 +module Authority
  2 + # Compatible with all access rights
  3 + # Should be rewrited for new access rights
  4 + def add_access(user, *access)
  5 + access = if access.include?(:admin)
  6 + { :project_access => UsersProject::MASTER }
  7 + elsif access.include?(:write)
  8 + { :project_access => UsersProject::DEVELOPER }
  9 + else
  10 + { :project_access => UsersProject::REPORTER }
  11 + end
  12 + opts = { :user => user }
  13 + opts.merge!(access)
  14 + users_projects.create(opts)
  15 + end
  16 +
  17 + def reset_access(user)
  18 + users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id
  19 + end
  20 +
  21 + def repository_readers
  22 + keys = Key.joins({:user => :users_projects}).
  23 + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)
  24 + keys.map(&:identifier) + deploy_keys.map(&:identifier)
  25 + end
  26 +
  27 + def repository_writers
  28 + keys = Key.joins({:user => :users_projects}).
  29 + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)
  30 + keys.map(&:identifier)
  31 + end
  32 +
  33 + def repository_masters
  34 + keys = Key.joins({:user => :users_projects}).
  35 + where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)
  36 + keys.map(&:identifier)
  37 + end
  38 +
  39 + def allow_read_for?(user)
  40 + !users_projects.where(:user_id => user.id).empty?
  41 + end
  42 +
  43 + def guest_access_for?(user)
  44 + !users_projects.where(:user_id => user.id).empty?
  45 + end
  46 +
  47 + def report_access_for?(user)
  48 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
  49 + end
  50 +
  51 + def dev_access_for?(user)
  52 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
  53 + end
  54 +
  55 + def master_access_for?(user)
  56 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id
  57 + end
  58 +end
app/roles/git_merge.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +module GitMerge
  2 +end
app/roles/git_push.rb 0 → 100644
@@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
  1 +module GitPush
  2 + def observe_push(oldrev, newrev, ref, user)
  3 + data = post_receive_data(oldrev, newrev, ref, user)
  4 +
  5 + Event.create(
  6 + :project => self,
  7 + :action => Event::Pushed,
  8 + :data => data,
  9 + :author_id => data[:user_id]
  10 + )
  11 + end
  12 +
  13 + def update_merge_requests(oldrev, newrev, ref, user)
  14 + return true unless ref =~ /heads/
  15 + branch_name = ref.gsub("refs/heads/", "")
  16 + c_ids = self.commits_between(oldrev, newrev).map(&:id)
  17 +
  18 + # Update code for merge requests
  19 + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
  20 + mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
  21 +
  22 + # Close merge requests
  23 + mrs = self.merge_requests.opened.where(:target_branch => branch_name).all
  24 + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
  25 + mrs.each { |merge_request| merge_request.merge!(user.id) }
  26 +
  27 + true
  28 + end
  29 +
  30 + def execute_web_hooks(oldrev, newrev, ref, user)
  31 + ref_parts = ref.split('/')
  32 +
  33 + # Return if this is not a push to a branch (e.g. new commits)
  34 + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
  35 +
  36 + data = post_receive_data(oldrev, newrev, ref, user)
  37 +
  38 + web_hooks.each { |web_hook| web_hook.execute(data) }
  39 + end
  40 +
  41 + def post_receive_data(oldrev, newrev, ref, user)
  42 +
  43 + push_commits = commits_between(oldrev, newrev)
  44 +
  45 + # Total commits count
  46 + push_commits_count = push_commits.size
  47 +
  48 + # Get latest 20 commits ASC
  49 + push_commits_limited = push_commits.last(20)
  50 +
  51 + # Hash to be passed as post_receive_data
  52 + data = {
  53 + before: oldrev,
  54 + after: newrev,
  55 + ref: ref,
  56 + user_id: user.id,
  57 + user_name: user.name,
  58 + repository: {
  59 + name: name,
  60 + url: web_url,
  61 + description: description,
  62 + homepage: web_url,
  63 + },
  64 + commits: [],
  65 + total_commits_count: push_commits_count
  66 + }
  67 +
  68 + # For perfomance purposes maximum 20 latest commits
  69 + # will be passed as post receive hook data.
  70 + #
  71 + push_commits_limited.each do |commit|
  72 + data[:commits] << {
  73 + id: commit.id,
  74 + message: commit.safe_message,
  75 + timestamp: commit.date.xmlschema,
  76 + url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
  77 + author: {
  78 + name: commit.author_name,
  79 + email: commit.author_email
  80 + }
  81 + }
  82 + end
  83 +
  84 + data
  85 + end
  86 +
  87 +
  88 + # This method will be called after each post receive
  89 + # and only if autor_key_id present in gitlab.
  90 + # All callbacks for post receive should be placed here
  91 + #
  92 + def trigger_post_receive(oldrev, newrev, ref, author_key_id)
  93 + user = Key.find_by_identifier(author_key_id).user
  94 +
  95 + # Create push event
  96 + self.observe_push(oldrev, newrev, ref, user)
  97 +
  98 + # Close merged MR
  99 + self.update_merge_requests(oldrev, newrev, ref, user)
  100 +
  101 + # Execute web hooks
  102 + self.execute_web_hooks(oldrev, newrev, ref, user)
  103 +
  104 + # Create satellite
  105 + self.satellite.create unless self.satellite.exists?
  106 + end
  107 +end
app/roles/push_event.rb 0 → 100644
@@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
  1 +module PushEvent
  2 + def valid_push?
  3 + data[:ref]
  4 + rescue => ex
  5 + false
  6 + end
  7 +
  8 + def tag?
  9 + data[:ref]["refs/tags"]
  10 + end
  11 +
  12 + def new_branch?
  13 + commit_from =~ /^00000/
  14 + end
  15 +
  16 + def new_ref?
  17 + commit_from =~ /^00000/
  18 + end
  19 +
  20 + def rm_ref?
  21 + commit_to =~ /^00000/
  22 + end
  23 +
  24 + def md_ref?
  25 + !(rm_ref? || new_ref?)
  26 + end
  27 +
  28 + def commit_from
  29 + data[:before]
  30 + end
  31 +
  32 + def commit_to
  33 + data[:after]
  34 + end
  35 +
  36 + def ref_name
  37 + if tag?
  38 + tag_name
  39 + else
  40 + branch_name
  41 + end
  42 + end
  43 +
  44 + def branch_name
  45 + @branch_name ||= data[:ref].gsub("refs/heads/", "")
  46 + end
  47 +
  48 + def tag_name
  49 + @tag_name ||= data[:ref].gsub("refs/tags/", "")
  50 + end
  51 +
  52 + # Max 20 commits from push DESC
  53 + def commits
  54 + @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse
  55 + end
  56 +
  57 + def commits_count
  58 + data[:total_commits_count] || commits.count || 0
  59 + end
  60 +
  61 + def ref_type
  62 + tag? ? "tag" : "branch"
  63 + end
  64 +
  65 + def push_action_name
  66 + if new_ref?
  67 + "pushed new"
  68 + elsif rm_ref?
  69 + "removed #{ref_type}"
  70 + else
  71 + "pushed to"
  72 + end
  73 + end
  74 +
  75 + def parent_commit
  76 + project.commit(commit_from)
  77 + rescue => ex
  78 + nil
  79 + end
  80 +
  81 + def last_commit
  82 + project.commit(commit_to)
  83 + rescue => ex
  84 + nil
  85 + end
  86 +
  87 + def push_with_commits?
  88 + md_ref? && commits.any? && parent_commit && last_commit
  89 + end
  90 +end
app/roles/repository.rb 0 → 100644
@@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
  1 +module Repository
  2 + def valid_repo?
  3 + repo
  4 + rescue
  5 + errors.add(:path, "Invalid repository path")
  6 + false
  7 + end
  8 +
  9 + def commit(commit_id = nil)
  10 + Commit.find_or_first(repo, commit_id, root_ref)
  11 + end
  12 +
  13 + def fresh_commits(n = 10)
  14 + Commit.fresh_commits(repo, n)
  15 + end
  16 +
  17 + def commits_with_refs(n = 20)
  18 + Commit.commits_with_refs(repo, n)
  19 + end
  20 +
  21 + def commits_since(date)
  22 + Commit.commits_since(repo, date)
  23 + end
  24 +
  25 + def commits(ref, path = nil, limit = nil, offset = nil)
  26 + Commit.commits(repo, ref, path, limit, offset)
  27 + end
  28 +
  29 + def commits_between(from, to)
  30 + Commit.commits_between(repo, from, to)
  31 + end
  32 +
  33 + def write_hooks
  34 + %w(post-receive).each do |hook|
  35 + write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
  36 + end
  37 + end
  38 +
  39 + def satellite
  40 + @satellite ||= Gitlab::Satellite.new(self)
  41 + end
  42 +
  43 + def write_hook(name, content)
  44 + hook_file = File.join(path_to_repo, 'hooks', name)
  45 +
  46 + File.open(hook_file, 'w') do |f|
  47 + f.write(content)
  48 + end
  49 +
  50 + File.chmod(0775, hook_file)
  51 + end
  52 +
  53 + def has_post_receive_file?
  54 + hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
  55 + File.exists?(hook_file)
  56 + end
  57 +
  58 + def tags
  59 + repo.tags.map(&:name).sort.reverse
  60 + end
  61 +
  62 + def repo
  63 + @repo ||= Grit::Repo.new(path_to_repo)
  64 + end
  65 +
  66 + def url_to_repo
  67 + Gitlab::GitHost.url_to_repo(path)
  68 + end
  69 +
  70 + def path_to_repo
  71 + File.join(GIT_HOST["base_path"], "#{path}.git")
  72 + end
  73 +
  74 + def update_repository
  75 + Gitlab::GitHost.system.update_project(path, self)
  76 +
  77 + write_hooks if File.exists?(path_to_repo)
  78 + end
  79 +
  80 + def destroy_repository
  81 + Gitlab::GitHost.system.destroy_project(self)
  82 + end
  83 +
  84 + def repo_exists?
  85 + @repo_exists ||= (repo && !repo.branches.empty?)
  86 + rescue
  87 + @repo_exists = false
  88 + end
  89 +
  90 + def heads
  91 + @heads ||= repo.heads
  92 + end
  93 +
  94 + def tree(fcommit, path = nil)
  95 + fcommit = commit if fcommit == :head
  96 + tree = fcommit.tree
  97 + path ? (tree / path) : tree
  98 + end
  99 +
  100 + def open_branches
  101 + if protected_branches.empty?
  102 + self.repo.heads
  103 + else
  104 + pnames = protected_branches.map(&:name)
  105 + self.repo.heads.reject { |h| pnames.include?(h.name) }
  106 + end.sort_by(&:name)
  107 + end
  108 +
  109 + def has_commits?
  110 + !!commit
  111 + end
  112 +
  113 + def root_ref
  114 + default_branch || "master"
  115 + end
  116 +
  117 + def root_ref? branch
  118 + root_ref == branch
  119 + end
  120 +end
app/roles/ssh_key.rb 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +module SshKey
  2 + def update_repository
  3 + Gitlab::GitHost.system.new.configure do |c|
  4 + c.update_keys(identifier, key)
  5 + c.update_projects(projects)
  6 + end
  7 + end
  8 +
  9 + def repository_delete_key
  10 + Gitlab::GitHost.system.new.configure do |c|
  11 + #delete key file is there is no identically deploy keys
  12 + if !is_deploy_key || Key.where(:identifier => identifier).count() == 0
  13 + c.delete_key(identifier)
  14 + end
  15 + c.update_projects(projects)
  16 + end
  17 + end
  18 +end
app/roles/team.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +module Team
  2 + def team_member_by_name_or_email(email = nil, name = nil)
  3 + user = users.where("email like ? or name like ?", email, name).first
  4 + users_projects.find_by_user_id(user.id) if user
  5 + end
  6 +
  7 + def team_member_by_id(user_id)
  8 + users_projects.find_by_user_id(user_id)
  9 + end
  10 +end
app/roles/upvote.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +module Upvote
  2 + # Return the number of +1 comments (upvotes)
  3 + def upvotes
  4 + notes.select(&:upvote?).size
  5 + end
  6 +end