Skip to content
Snippets Groups Projects
Commit 88d9569a authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Project model refactored. Modularity gem

parent bae4efa7
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -34,6 +34,7 @@ gem "omniauth-ldap"
gem 'bootstrap-sass', "1.4.4"
gem "colored"
gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
gem 'modularity'
 
group :assets do
gem "sass-rails", "3.2.3"
Loading
Loading
Loading
Loading
@@ -149,6 +149,7 @@ GEM
treetop (~> 1.4.8)
method_source (0.7.0)
mime-types (1.17.2)
modularity (0.6.1)
multi_json (1.0.4)
multi_xml (0.4.1)
mysql2 (0.3.11)
Loading
Loading
@@ -326,6 +327,7 @@ DEPENDENCIES
kaminari
launchy
letter_opener
modularity
mysql2
omniauth-ldap
pry
Loading
Loading
Loading
Loading
@@ -3,6 +3,11 @@ require "grit"
class Project < ActiveRecord::Base
belongs_to :owner, :class_name => "User"
 
does "project/validations"
does "project/repository"
does "project/permissions"
does "project/hooks"
has_many :users, :through => :users_projects
has_many :events, :dependent => :destroy
has_many :merge_requests, :dependent => :destroy
Loading
Loading
@@ -15,32 +20,6 @@ class Project < ActiveRecord::Base
has_many :wikis, :dependent => :destroy
has_many :protected_branches, :dependent => :destroy
 
validates :name,
:uniqueness => true,
:presence => true,
:length => { :within => 0..255 }
validates :path,
:uniqueness => true,
:presence => true,
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 0..255 }
validates :description,
:length => { :within => 0..2000 }
validates :code,
:presence => true,
:uniqueness => true,
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 3..255 }
validates :owner, :presence => true
validate :check_limit
validate :repo_name
attr_protected :private_flag, :owner_id
 
scope :public_only, where(:private_flag => false)
Loading
Loading
@@ -66,89 +45,6 @@ class Project < ActiveRecord::Base
[GIT_HOST['host'], code].join("/")
end
 
def observe_push(oldrev, newrev, ref, author_key_id)
data = web_hook_data(oldrev, newrev, ref, author_key_id)
Event.create(
:project => self,
:action => Event::Pushed,
:data => data,
:author_id => data[:user_id]
)
end
def update_merge_requests(oldrev, newrev, ref, author_key_id)
return true unless ref =~ /heads/
branch_name = ref.gsub("refs/heads/", "")
user = Key.find_by_identifier(author_key_id).user
c_ids = self.commits_between(oldrev, newrev).map(&:id)
# Update code for merge requests
mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
mrs.each { |merge_request| merge_request.reload_code }
# Close merge requests
mrs = self.merge_requests.opened.where(:target_branch => branch_name).all
mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
mrs.each { |merge_request| merge_request.merge!(user.id) }
true
end
def execute_web_hooks(oldrev, newrev, ref, author_key_id)
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
data = web_hook_data(oldrev, newrev, ref, author_key_id)
web_hooks.each { |web_hook| web_hook.execute(data) }
end
def web_hook_data(oldrev, newrev, ref, author_key_id)
key = Key.find_by_identifier(author_key_id)
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: key.user.id,
user_name: key.user_name,
repository: {
name: name,
url: web_url,
description: description,
homepage: web_url,
private: private?
},
commits: []
}
commits_between(oldrev, newrev).each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
data
end
def open_branches
if protected_branches.empty?
self.repo.heads
else
pnames = protected_branches.map(&:name)
self.repo.heads.reject { |h| pnames.include?(h.name) }
end.sort_by(&:name)
end
def team_member_by_name_or_email(email = nil, name = nil)
user = users.where("email like ? or name like ?", email, name).first
users_projects.find_by_user_id(user.id) if user
Loading
Loading
@@ -174,71 +70,6 @@ class Project < ActiveRecord::Base
notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null")
end
 
def has_commits?
!!commit
end
# Compatible with all access rights
# Should be rewrited for new access rights
def add_access(user, *access)
access = if access.include?(:admin)
{ :project_access => UsersProject::MASTER }
elsif access.include?(:write)
{ :project_access => UsersProject::DEVELOPER }
else
{ :project_access => UsersProject::REPORTER }
end
opts = { :user => user }
opts.merge!(access)
users_projects.create(opts)
end
def reset_access(user)
users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id
end
def repository_readers
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)
keys.map(&:identifier) + deploy_keys.map(&:identifier)
end
def repository_writers
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)
keys.map(&:identifier)
end
def repository_masters
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)
keys.map(&:identifier)
end
def allow_read_for?(user)
!users_projects.where(:user_id => user.id).empty?
end
def guest_access_for?(user)
!users_projects.where(:user_id => user.id).empty?
end
def report_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
end
def dev_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
end
def master_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id
end
def root_ref
default_branch || "master"
end
def public?
!private_flag
end
Loading
Loading
@@ -259,112 +90,9 @@ class Project < ActiveRecord::Base
end
end
 
def check_limit
unless owner.can_create_project?
errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
end
rescue
errors[:base] << ("Cant check your ability to create project")
end
def repo_name
if path == "gitolite-admin"
errors.add(:path, " like 'gitolite-admin' is not allowed")
end
end
def valid_repo?
repo
rescue
errors.add(:path, "Invalid repository path")
false
end
def commit(commit_id = nil)
Commit.find_or_first(repo, commit_id)
end
def fresh_commits(n = 10)
Commit.fresh_commits(repo, n)
end
def commits_with_refs(n = 20)
Commit.commits_with_refs(repo, n)
end
def commits_since(date)
Commit.commits_since(repo, date)
end
def commits(ref, path = nil, limit = nil, offset = nil)
Commit.commits(repo, ref, path, limit, offset)
end
def commits_between(from, to)
Commit.commits_between(repo, from, to)
end
def project_id
self.id
end
def write_hooks
%w(post-receive).each do |hook|
write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
end
end
def write_hook(name, content)
hook_file = File.join(path_to_repo, 'hooks', name)
File.open(hook_file, 'w') do |f|
f.write(content)
end
File.chmod(0775, hook_file)
end
def repo
@repo ||= Grit::Repo.new(path_to_repo)
end
def url_to_repo
Gitlabhq::GitHost.url_to_repo(path)
end
def path_to_repo
File.join(GIT_HOST["base_path"], "#{path}.git")
end
def update_repository
Gitlabhq::GitHost.system.update_project(path, self)
write_hooks if File.exists?(path_to_repo)
end
def destroy_repository
Gitlabhq::GitHost.system.destroy_project(self)
end
def repo_exists?
@repo_exists ||= (repo && !repo.branches.empty?)
rescue
@repo_exists = false
end
def tags
repo.tags.map(&:name).sort.reverse
end
def heads
@heads ||= repo.heads
end
def tree(fcommit, path = nil)
fcommit = commit if fcommit == :head
tree = fcommit.tree
path ? (tree / path) : tree
end
end
 
# == Schema Information
Loading
Loading
module Project::HooksTrait
as_trait do
def observe_push(oldrev, newrev, ref, author_key_id)
data = web_hook_data(oldrev, newrev, ref, author_key_id)
Event.create(
:project => self,
:action => Event::Pushed,
:data => data,
:author_id => data[:user_id]
)
end
def update_merge_requests(oldrev, newrev, ref, author_key_id)
return true unless ref =~ /heads/
branch_name = ref.gsub("refs/heads/", "")
user = Key.find_by_identifier(author_key_id).user
c_ids = self.commits_between(oldrev, newrev).map(&:id)
# Update code for merge requests
mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
mrs.each { |merge_request| merge_request.reload_code }
# Close merge requests
mrs = self.merge_requests.opened.where(:target_branch => branch_name).all
mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
mrs.each { |merge_request| merge_request.merge!(user.id) }
true
end
def execute_web_hooks(oldrev, newrev, ref, author_key_id)
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
data = web_hook_data(oldrev, newrev, ref, author_key_id)
web_hooks.each { |web_hook| web_hook.execute(data) }
end
def web_hook_data(oldrev, newrev, ref, author_key_id)
key = Key.find_by_identifier(author_key_id)
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: key.user.id,
user_name: key.user_name,
repository: {
name: name,
url: web_url,
description: description,
homepage: web_url,
private: private?
},
commits: []
}
commits_between(oldrev, newrev).each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
data
end
end
end
module Project::PermissionsTrait
as_trait do
# Compatible with all access rights
# Should be rewrited for new access rights
def add_access(user, *access)
access = if access.include?(:admin)
{ :project_access => UsersProject::MASTER }
elsif access.include?(:write)
{ :project_access => UsersProject::DEVELOPER }
else
{ :project_access => UsersProject::REPORTER }
end
opts = { :user => user }
opts.merge!(access)
users_projects.create(opts)
end
def reset_access(user)
users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id
end
def repository_readers
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)
keys.map(&:identifier) + deploy_keys.map(&:identifier)
end
def repository_writers
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)
keys.map(&:identifier)
end
def repository_masters
keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)
keys.map(&:identifier)
end
def allow_read_for?(user)
!users_projects.where(:user_id => user.id).empty?
end
def guest_access_for?(user)
!users_projects.where(:user_id => user.id).empty?
end
def report_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
end
def dev_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
end
def master_access_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id
end
end
end
module Project::RepositoryTrait
as_trait do
def valid_repo?
repo
rescue
errors.add(:path, "Invalid repository path")
false
end
def commit(commit_id = nil)
Commit.find_or_first(repo, commit_id)
end
def fresh_commits(n = 10)
Commit.fresh_commits(repo, n)
end
def commits_with_refs(n = 20)
Commit.commits_with_refs(repo, n)
end
def commits_since(date)
Commit.commits_since(repo, date)
end
def commits(ref, path = nil, limit = nil, offset = nil)
Commit.commits(repo, ref, path, limit, offset)
end
def commits_between(from, to)
Commit.commits_between(repo, from, to)
end
def write_hooks
%w(post-receive).each do |hook|
write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
end
end
def write_hook(name, content)
hook_file = File.join(path_to_repo, 'hooks', name)
File.open(hook_file, 'w') do |f|
f.write(content)
end
File.chmod(0775, hook_file)
end
def tags
repo.tags.map(&:name).sort.reverse
end
def repo
@repo ||= Grit::Repo.new(path_to_repo)
end
def url_to_repo
Gitlabhq::GitHost.url_to_repo(path)
end
def path_to_repo
File.join(GIT_HOST["base_path"], "#{path}.git")
end
def update_repository
Gitlabhq::GitHost.system.update_project(path, self)
write_hooks if File.exists?(path_to_repo)
end
def destroy_repository
Gitlabhq::GitHost.system.destroy_project(self)
end
def repo_exists?
@repo_exists ||= (repo && !repo.branches.empty?)
rescue
@repo_exists = false
end
def heads
@heads ||= repo.heads
end
def tree(fcommit, path = nil)
fcommit = commit if fcommit == :head
tree = fcommit.tree
path ? (tree / path) : tree
end
def open_branches
if protected_branches.empty?
self.repo.heads
else
pnames = protected_branches.map(&:name)
self.repo.heads.reject { |h| pnames.include?(h.name) }
end.sort_by(&:name)
end
def has_commits?
!!commit
end
def root_ref
default_branch || "master"
end
end
end
module Project::ValidationsTrait
as_trait do
validates :name,
:uniqueness => true,
:presence => true,
:length => { :within => 0..255 }
validates :path,
:uniqueness => true,
:presence => true,
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 0..255 }
validates :description,
:length => { :within => 0..2000 }
validates :code,
:presence => true,
:uniqueness => true,
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 3..255 }
validates :owner, :presence => true
validate :check_limit
validate :repo_name
def check_limit
unless owner.can_create_project?
errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
end
rescue
errors[:base] << ("Cant check your ability to create project")
end
def repo_name
if path == "gitolite-admin"
errors.add(:path, " like 'gitolite-admin' is not allowed")
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment