Use repository committerships in TransferProjectOwnershipCommand
[gitorious:mainline.git] / app / models / committership.rb
1 # encoding: utf-8
2 #--
3 #   Copyright (C) 2012-2013 Gitorious AS
4 #   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
5 #   Copyright (C) 2007 Johan Sørensen <johan@johansorensen.com>
6 #   Copyright (C) 2008 David A. Cuadrado <krawek@gmail.com>
7 #   Copyright (C) 2008 Tor Arne Vestbø <tavestbo@trolltech.com>
8 #
9 #   This program is free software: you can redistribute it and/or modify
10 #   it under the terms of the GNU Affero General Public License as published by
11 #   the Free Software Foundation, either version 3 of the License, or
12 #   (at your option) any later version.
13 #
14 #   This program is distributed in the hope that it will be useful,
15 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 #   GNU Affero General Public License for more details.
18 #
19 #   You should have received a copy of the GNU Affero General Public License
20 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 #++
22
23 class Committership < ActiveRecord::Base
24
25   CAN_REVIEW = 1 << 4
26   CAN_COMMIT = 1 << 5
27   CAN_ADMIN = 1 << 6
28
29   PERMISSION_TABLE = {
30     :review => CAN_REVIEW,
31     :commit => CAN_COMMIT,
32     :admin => CAN_ADMIN
33   }
34
35   belongs_to :committer, :polymorphic => true
36   belongs_to :repository
37   belongs_to :creator, :class_name => "User"
38   has_many :messages, :as => :notifiable
39
40   validates_presence_of :committer_id, :committer_type, :repository_id
41   validates_uniqueness_of :committer_id, :scope => [:committer_type, :repository_id],
42     :message => "is already a committer to this repository"
43
44   attr_accessible :committer, :repository, :creator, :creator_id
45
46   after_create :notify_repository_owners
47   after_create :add_new_committer_event
48   after_destroy :add_removed_committer_event
49   before_destroy :nullify_messages
50
51   scope :groups, :conditions => { :committer_type => "Group" }
52   scope :users,  :conditions => { :committer_type => "User" }
53   scope :reviewers, :conditions => ["(permissions & ?) != 0", CAN_REVIEW]
54   scope :committers, :conditions => ["(permissions & ?) != 0", CAN_COMMIT]
55   scope :admins, :conditions => ["(permissions & ?) != 0", CAN_ADMIN]
56
57   def self.create_for_owner!(an_owner, creator = nil)
58     cs = new({:committer => an_owner})
59     cs.creator = creator
60     cs.permissions = (CAN_REVIEW | CAN_COMMIT | CAN_ADMIN)
61     cs.save!
62     cs
63   end
64
65   def self.create_with_permissions!(attrs, perms)
66     cs = new(attrs)
67     cs.permissions = perms
68     cs.save!
69     cs
70   end
71
72   def permission_mask_for(*perms)
73     perms.inject(0) do |memo, perm_symbol|
74       memo | PERMISSION_TABLE[perm_symbol]
75     end
76   end
77
78   def build_permissions(*perms)
79     perms = perms.flatten.compact.map{|p| p.to_sym }
80     self.permissions = permission_mask_for(*perms)
81   end
82
83   def permitted?(wants_to)
84     raise "unknown permission: #{wants_to.inspect}" if !PERMISSION_TABLE[wants_to]
85     (self.permissions & PERMISSION_TABLE[wants_to]) != 0
86   end
87
88   def reviewer?
89     permitted?(:review)
90   end
91
92   def committer?
93     permitted?(:commit)
94   end
95
96   def admin?
97     permitted?(:admin)
98   end
99
100   def permission_list
101     PERMISSION_TABLE.keys.select{|perm| permitted?(perm) }
102   end
103
104   def title
105     new_record? ? "New collaborator" : "Collaborator"
106   end
107
108   # returns all the users in this committership, eg if it's a group it'll
109   # return an array of the group members, otherwise a single-member array of
110   # the user
111   def members
112     case committer
113     when Group
114       committer.members
115     when LdapGroup
116       committer.members
117     else
118       [committer]
119     end
120   end
121
122   protected
123   def notify_repository_owners
124     return unless creator
125     SendMessage.call(
126       :sender => creator,
127       :recipients => repository.owners,
128       :subject => I18n.t("committership.notification_subject"),
129       :body => I18n.t("committership.notification_body", {
130         :inviter => creator.title,
131         :user => committer.title,
132         :repository => repository.name,
133         :project => repository.project.title
134       }),
135       :notifiable => self)
136   end
137
138   def add_new_committer_event
139     repository.project.create_event(Action::ADD_COMMITTER, repository,
140                                     creator, committer.title)
141   end
142
143   def add_removed_committer_event
144     return unless repository
145     repository.project.create_event(Action::REMOVE_COMMITTER, repository,
146                                     creator, committer.title)
147   end
148
149   def nullify_messages
150     messages.update_all({:notifiable_id => nil, :notifiable_type => nil})
151   end
152 end