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 | 1 | class Event < ActiveRecord::Base |
| 2 | + include PushEvent | |
| 3 | + | |
| 2 | 4 | default_scope where("author_id IS NOT NULL") |
| 3 | 5 | |
| 4 | 6 | Created = 1 |
| ... | ... | @@ -9,8 +11,6 @@ class Event < ActiveRecord::Base |
| 9 | 11 | Commented = 6 |
| 10 | 12 | Merged = 7 |
| 11 | 13 | |
| 12 | - does "event/push" | |
| 13 | - | |
| 14 | 14 | belongs_to :project |
| 15 | 15 | belongs_to :target, :polymorphic => true |
| 16 | 16 | ... | ... |
app/models/event/push_trait.rb
| ... | ... | @@ -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 | 1 | class Issue < ActiveRecord::Base |
| 2 | + include Upvote | |
| 3 | + | |
| 2 | 4 | belongs_to :project |
| 3 | 5 | belongs_to :milestone |
| 4 | 6 | belongs_to :author, :class_name => "User" |
| ... | ... | @@ -53,11 +55,6 @@ class Issue < ActiveRecord::Base |
| 53 | 55 | def new? |
| 54 | 56 | today? && created_at == updated_at |
| 55 | 57 | end |
| 56 | - | |
| 57 | - # Return the number of +1 comments (upvotes) | |
| 58 | - def upvotes | |
| 59 | - notes.select(&:upvote?).size | |
| 60 | - end | |
| 61 | 58 | end |
| 62 | 59 | # == Schema Information |
| 63 | 60 | # | ... | ... |
app/models/key.rb
| 1 | 1 | require 'digest/md5' |
| 2 | 2 | |
| 3 | 3 | class Key < ActiveRecord::Base |
| 4 | + include SshKey | |
| 4 | 5 | belongs_to :user |
| 5 | 6 | belongs_to :project |
| 6 | 7 | |
| ... | ... | @@ -37,28 +38,11 @@ class Key < ActiveRecord::Base |
| 37 | 38 | end |
| 38 | 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 | 41 | def is_deploy_key |
| 58 | 42 | true if project_id |
| 59 | 43 | end |
| 60 | 44 | |
| 61 | - #projects that has this key | |
| 45 | + # projects that has this key | |
| 62 | 46 | def projects |
| 63 | 47 | if is_deploy_key |
| 64 | 48 | [project] | ... | ... |
app/models/merge_request.rb
| 1 | 1 | require File.join(Rails.root, "app/models/commit") |
| 2 | 2 | |
| 3 | 3 | class MergeRequest < ActiveRecord::Base |
| 4 | + include Upvote | |
| 5 | + | |
| 4 | 6 | UNCHECKED = 1 |
| 5 | 7 | CAN_BE_MERGED = 2 |
| 6 | 8 | CANNOT_BE_MERGED = 3 |
| ... | ... | @@ -128,12 +130,6 @@ class MergeRequest < ActiveRecord::Base |
| 128 | 130 | self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Closed).last |
| 129 | 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 | 133 | def commits |
| 138 | 134 | st_commits || [] |
| 139 | 135 | end | ... | ... |
app/models/project.rb
| 1 | 1 | require "grit" |
| 2 | 2 | |
| 3 | 3 | class Project < ActiveRecord::Base |
| 4 | + include Repository | |
| 5 | + include GitPush | |
| 6 | + include Authority | |
| 7 | + include Team | |
| 8 | + | |
| 9 | + # | |
| 10 | + # Relations | |
| 11 | + # | |
| 4 | 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 | 13 | has_many :users, :through => :users_projects |
| 12 | 14 | has_many :events, :dependent => :destroy |
| 13 | 15 | has_many :merge_requests, :dependent => :destroy |
| ... | ... | @@ -21,8 +23,14 @@ class Project < ActiveRecord::Base |
| 21 | 23 | has_many :wikis, :dependent => :destroy |
| 22 | 24 | has_many :protected_branches, :dependent => :destroy |
| 23 | 25 | |
| 26 | + # | |
| 27 | + # Protected attributes | |
| 28 | + # | |
| 24 | 29 | attr_protected :private_flag, :owner_id |
| 25 | 30 | |
| 31 | + # | |
| 32 | + # Scopes | |
| 33 | + # | |
| 26 | 34 | scope :public_only, where(:private_flag => false) |
| 27 | 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 | 38 | joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") |
| 31 | 39 | end |
| 32 | 40 | |
| 33 | - def self.access_options | |
| 34 | - UsersProject.access_roles | |
| 35 | - end | |
| 36 | - | |
| 37 | 41 | def self.search query |
| 38 | 42 | where("name like :query or code like :query or path like :query", :query => "%#{query}%") |
| 39 | 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 | 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 | 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 | 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 | 98 | end |
| 57 | 99 | |
| 58 | 100 | def common_notes | ... | ... |
app/models/project/hooks_trait.rb
| ... | ... | @@ -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 | -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 | -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 | -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 | 1 | class User < ActiveRecord::Base |
| 2 | + include Account | |
| 3 | + | |
| 2 | 4 | devise :database_authenticatable, :token_authenticatable, |
| 3 | 5 | :recoverable, :rememberable, :trackable, :validatable, :omniauthable |
| 4 | 6 | |
| ... | ... | @@ -65,30 +67,6 @@ class User < ActiveRecord::Base |
| 65 | 67 | where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') |
| 66 | 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 | 70 | def self.find_for_ldap_auth(omniauth_info) |
| 93 | 71 | name = omniauth_info.name.force_encoding("utf-8") |
| 94 | 72 | email = omniauth_info.email.downcase |
| ... | ... | @@ -105,30 +83,6 @@ class User < ActiveRecord::Base |
| 105 | 83 | ) |
| 106 | 84 | end |
| 107 | 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 | 86 | end |
| 133 | 87 | # == Schema Information |
| 134 | 88 | # | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 | ... | ... |