Commit 0a70aca3b177cffccd2e04579712665d10b8fd69
1 parent
98b84166
Exists in
master
and in
4 other branches
Models Refactoring: Move methods to roles
Showing
20 changed files
with
531 additions
and
524 deletions
Show diff stats
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 < ActiveRecord::Base | @@ -9,8 +11,6 @@ class Event < 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 < ActiveRecord::Base | @@ -53,11 +55,6 @@ class Issue < 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 < ActiveRecord::Base | @@ -37,28 +38,11 @@ class Key < 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 < ActiveRecord::Base | @@ -128,12 +130,6 @@ class MergeRequest < 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 < ActiveRecord::Base | @@ -21,8 +23,14 @@ class Project < 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 < ActiveRecord::Base | @@ -30,29 +38,63 @@ class Project < 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 < ActiveRecord::Base | @@ -65,30 +67,6 @@ class User < 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 < ActiveRecord::Base | @@ -105,30 +83,6 @@ class User < 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 | # |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |