summaryrefslogtreecommitdiffstats
path: root/app/models/group.rb
blob: 7607c04a9a0364d1a7a17708e6fb0082e507cb3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# encoding: utf-8
#--
#   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#++

class Group < ActiveRecord::Base
  has_many :committerships, :as => :committer, :dependent => :destroy
  has_many :participated_repositories, :through => :committerships,
    :source => :repository, :class_name => 'Repository'
  belongs_to :creator, :class_name => "User", :foreign_key => "user_id"
  has_many :memberships, :dependent => :destroy
  has_many :members, :through => :memberships, :source => :user
  has_many :repositories, :as => :owner, :conditions => ["kind NOT IN (?)",
                                                         Repository::KINDS_INTERNAL_REPO],
    :dependent => :destroy
  has_many :projects, :as => :owner

  attr_protected :public, :role_id, :user_id

  NAME_FORMAT = /[a-z0-9\-]+/.freeze
  validates_presence_of :name
  validates_uniqueness_of :name
  validates_format_of :name, :with => /^#{NAME_FORMAT}$/,
    :message => "Must be alphanumeric, and optional dash"

  before_validation :downcase_name

  Paperclip::Attachment.interpolations['group_name'] = lambda{|attachment,style| attachment.instance.name}

  avatar_local_path = '/system/group_avatars/:group_name/:style/:basename.:extension'
  has_attached_file :avatar,
    :default_url  =>'/images/default_group_avatar.png',
    :styles => { :normal => "300x300>", :medium => "64x64>", :thumb => '32x32>', :icon => '16x16>' },
    :url => avatar_local_path,
    :path => ":rails_root/public#{avatar_local_path}"


  def self.human_name
    I18n.t("activerecord.models.group")
  end

  def self.all_participating_in_projects(projects)
    mainline_ids = projects.map do |project|
      project.repositories.mainlines.map{|r| r.id }
    end.flatten
    Committership.groups.find(:all,
      :conditions => { :repository_id => mainline_ids }).map{|c| c.committer }.uniq
  end

  # Finds the most active groups by activity in repositories they're committers in
  def self.most_active(limit = 10, cutoff = 5)
    Rails.cache.fetch("groups:most_active:#{limit}:#{cutoff}", :expires_in => 1.hour) do
      # FIXME: there's a certain element of approximation in here
      find(:all, :joins => [{:committerships => {:repository => :events}}],
        :select => %Q{groups.*, committerships.repository_id,
          repositories.id, events.id, events.target_id, events.target_type,
          count(events.id) as event_count},
        :group => "groups.id",
        :conditions => ["committerships.repository_id = events.target_id and " +
                        "events.target_type = ? AND events.created_at > ?",
                        "Repository", cutoff.days.ago],
        :order => "event_count desc",
        :limit => limit)
    end
  end

  def all_related_project_ids
    all_project_ids = projects.map{|p| p.id }
    all_project_ids << repositories.map{|r| r.project_id }
    all_project_ids << committerships.map{|p| p.repository.project_id }
    all_project_ids.flatten!.uniq!
    all_project_ids
  end

  def to_param
    name
  end

  def to_param_with_prefix
    "+#{to_param}"
  end

  def title
    name
  end

  def breadcrumb_parent
    nil
  end

  # is this +user+ a member of this group?
  def member?(user)
    members.include?(user)
  end

  # returns the Role of +user+ in this group
  def role_of_user(candidate)
    if !candidate || candidate == :false
      return
    end
    membership = memberships.find_by_user_id(candidate.id)
    return unless membership
    membership.role
  end

  # is +candidate+ an admin in this group?
  def admin?(candidate)
    role_of_user(candidate) == Role.admin
  end

  # is +candidate+ a committer (or admin) in this group?
  def committer?(candidate)
    [Role.admin, Role.member].include?(role_of_user(candidate))
  end

  # Adds +a_user+ as a member to this group with a role of +a_role+
  def add_member(a_user, a_role)
    memberships.create!(:user => a_user, :role => a_role)
  end

  def deletable?
    members.count <= 1 && projects.blank?
  end

  protected
    def downcase_name
      name.downcase! if name
    end
end