Revision 1297:0a574315af3e .svn/pristine/7e

View differences:

.svn/pristine/7e/7e201503be1ce8b8b84fe7dac732a30710d1b5ae.svn-base
1
/* Danish initialisation for the jQuery UI date picker plugin. */
2
/* Written by Jan Christensen ( deletestuff@gmail.com). */
3
jQuery(function($){
4
    $.datepicker.regional['da'] = {
5
		closeText: 'Luk',
6
        prevText: '<Forrige',
7
		nextText: 'Næste>',
8
		currentText: 'Idag',
9
        monthNames: ['Januar','Februar','Marts','April','Maj','Juni',
10
        'Juli','August','September','Oktober','November','December'],
11
        monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun',
12
        'Jul','Aug','Sep','Okt','Nov','Dec'],
13
		dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],
14
		dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'],
15
		dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],
16
		weekHeader: 'Uge',
17
        dateFormat: 'dd-mm-yy',
18
		firstDay: 1,
19
		isRTL: false,
20
		showMonthAfterYear: false,
21
		yearSuffix: ''};
22
    $.datepicker.setDefaults($.datepicker.regional['da']);
23
});
.svn/pristine/7e/7e2f3b607d692519463808260150f029a9664509.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../test_helper', __FILE__)
19

  
20
class JournalObserverTest < ActiveSupport::TestCase
21
  fixtures :issues, :issue_statuses, :journals, :journal_details, :projects,
22
           :projects_trackers, :trackers, :enabled_modules, :enumerations,
23
           :users, :roles
24

  
25
  def setup
26
    ActionMailer::Base.deliveries.clear
27
    @journal = Journal.find 1
28
  end
29

  
30
  # context: issue_updated notified_events
31
  def test_create_should_send_email_notification_with_issue_updated
32
    issue = Issue.find(:first)
33
    user = User.find(:first)
34
    journal = issue.init_journal(user, issue)
35

  
36
    with_settings :notified_events => %w(issue_updated) do
37
      assert journal.save
38
    end
39
    assert_equal 1, ActionMailer::Base.deliveries.size
40
  end
41

  
42
  def test_create_should_not_send_email_notification_with_notify_set_to_false
43
    issue = Issue.find(:first)
44
    user = User.find(:first)
45
    journal = issue.init_journal(user, issue)
46
    journal.notify = false
47

  
48
    with_settings :notified_events => %w(issue_updated) do
49
      assert journal.save
50
    end
51
    assert_equal 0, ActionMailer::Base.deliveries.size
52
  end
53

  
54
  def test_create_should_not_send_email_notification_without_issue_updated
55
    issue = Issue.find(:first)
56
    user = User.find(:first)
57
    journal = issue.init_journal(user, issue)
58

  
59
    with_settings :notified_events => [] do
60
      assert journal.save
61
    end
62
    assert_equal 0, ActionMailer::Base.deliveries.size
63
  end
64

  
65
  # context: issue_note_added notified_events
66
  def test_create_should_send_email_notification_with_issue_note_added
67
    issue = Issue.find(:first)
68
    user = User.find(:first)
69
    journal = issue.init_journal(user, issue)
70
    journal.notes = 'This update has a note'
71

  
72
    with_settings :notified_events => %w(issue_note_added) do
73
      assert journal.save
74
    end
75
    assert_equal 1, ActionMailer::Base.deliveries.size
76
  end
77

  
78
  def test_create_should_not_send_email_notification_without_issue_note_added
79
    issue = Issue.find(:first)
80
    user = User.find(:first)
81
    journal = issue.init_journal(user, issue)
82
    journal.notes = 'This update has a note'
83

  
84
    with_settings :notified_events => [] do
85
      assert journal.save
86
    end
87
    assert_equal 0, ActionMailer::Base.deliveries.size
88
  end
89

  
90
  # context: issue_status_updated notified_events
91
  def test_create_should_send_email_notification_with_issue_status_updated
92
    issue = Issue.find(:first)
93
    user = User.find(:first)
94
    issue.init_journal(user, issue)
95
    issue.status = IssueStatus.last
96

  
97
    with_settings :notified_events => %w(issue_status_updated) do
98
      assert issue.save
99
    end
100
    assert_equal 1, ActionMailer::Base.deliveries.size
101
  end
102

  
103
  def test_create_should_not_send_email_notification_without_issue_status_updated
104
    issue = Issue.find(:first)
105
    user = User.find(:first)
106
    issue.init_journal(user, issue)
107
    issue.status = IssueStatus.last
108

  
109
    with_settings :notified_events => [] do
110
      assert issue.save
111
    end
112
    assert_equal 0, ActionMailer::Base.deliveries.size
113
  end
114

  
115
  # context: issue_priority_updated notified_events
116
  def test_create_should_send_email_notification_with_issue_priority_updated
117
    issue = Issue.find(:first)
118
    user = User.find(:first)
119
    issue.init_journal(user, issue)
120
    issue.priority = IssuePriority.last
121

  
122
    with_settings :notified_events => %w(issue_priority_updated) do
123
      assert issue.save
124
    end
125
    assert_equal 1, ActionMailer::Base.deliveries.size
126
  end
127

  
128
  def test_create_should_not_send_email_notification_without_issue_priority_updated
129
    issue = Issue.find(:first)
130
    user = User.find(:first)
131
    issue.init_journal(user, issue)
132
    issue.priority = IssuePriority.last
133

  
134
    with_settings :notified_events => [] do
135
      assert issue.save
136
    end
137
    assert_equal 0, ActionMailer::Base.deliveries.size
138
  end
139
end
.svn/pristine/7e/7e73ff3802954a96975f8bef9c7ea4c0ded85956.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
require File.expand_path('../../test_helper', __FILE__)
19

  
20
class RepositoryTest < ActiveSupport::TestCase
21
  fixtures :projects,
22
           :trackers,
23
           :projects_trackers,
24
           :enabled_modules,
25
           :repositories,
26
           :issues,
27
           :issue_statuses,
28
           :issue_categories,
29
           :changesets,
30
           :changes,
31
           :users,
32
           :members,
33
           :member_roles,
34
           :roles,
35
           :enumerations
36

  
37
  include Redmine::I18n
38

  
39
  def setup
40
    @repository = Project.find(1).repository
41
  end
42

  
43
  def test_blank_log_encoding_error_message
44
    set_language_if_valid 'en'
45
    repo = Repository::Bazaar.new(
46
                        :project      => Project.find(3),
47
                        :url          => "/test",
48
                        :log_encoding => ''
49
                      )
50
    assert !repo.save
51
    assert_include "Commit messages encoding can't be blank",
52
                   repo.errors.full_messages
53
  end
54

  
55
  def test_blank_log_encoding_error_message_fr
56
    set_language_if_valid 'fr'
57
    str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
58
    str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59
    repo = Repository::Bazaar.new(
60
                        :project      => Project.find(3),
61
                        :url          => "/test"
62
                      )
63
    assert !repo.save
64
    assert_include str, repo.errors.full_messages
65
  end
66

  
67
  def test_create
68
    repository = Repository::Subversion.new(:project => Project.find(3))
69
    assert !repository.save
70

  
71
    repository.url = "svn://localhost"
72
    assert repository.save
73
    repository.reload
74

  
75
    project = Project.find(3)
76
    assert_equal repository, project.repository
77
  end
78

  
79
  def test_first_repository_should_be_set_as_default
80
    repository1 = Repository::Subversion.new(
81
                      :project => Project.find(3),
82
                      :identifier => 'svn1',
83
                      :url => 'file:///svn1'
84
                    )
85
    assert repository1.save
86
    assert repository1.is_default?
87

  
88
    repository2 = Repository::Subversion.new(
89
                      :project => Project.find(3),
90
                      :identifier => 'svn2',
91
                      :url => 'file:///svn2'
92
                    )
93
    assert repository2.save
94
    assert !repository2.is_default?
95

  
96
    assert_equal repository1, Project.find(3).repository
97
    assert_equal [repository1, repository2], Project.find(3).repositories.sort
98
  end
99

  
100
  def test_identifier_should_accept_letters_digits_dashes_and_underscores
101
    r = Repository::Subversion.new(
102
      :project_id => 3,
103
      :identifier => 'svn-123_45',
104
      :url => 'file:///svn'
105
    )
106
    assert r.save
107
  end
108
  
109
  def test_identifier_should_not_be_frozen_for_a_new_repository
110
    assert_equal false, Repository.new.identifier_frozen?
111
  end
112

  
113
  def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
114
    Repository.update_all(["identifier = ''"], "id = 10")
115

  
116
    assert_equal false, Repository.find(10).identifier_frozen?
117
  end
118

  
119
  def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
120
    Repository.update_all(["identifier = 'abc123'"], "id = 10")
121

  
122
    assert_equal true, Repository.find(10).identifier_frozen?
123
  end
124

  
125
  def test_identifier_should_not_accept_change_if_frozen
126
    r = Repository.new(:identifier => 'foo')
127
    r.stubs(:identifier_frozen?).returns(true)
128

  
129
    r.identifier = 'bar'
130
    assert_equal 'foo', r.identifier
131
  end
132

  
133
  def test_identifier_should_accept_change_if_not_frozen
134
    r = Repository.new(:identifier => 'foo')
135
    r.stubs(:identifier_frozen?).returns(false)
136

  
137
    r.identifier = 'bar'
138
    assert_equal 'bar', r.identifier
139
  end
140

  
141
  def test_destroy
142
    repository = Repository.find(10)
143
    changesets = repository.changesets.count
144
    changes = repository.filechanges.count
145

  
146
    assert_difference 'Changeset.count', -changesets do
147
      assert_difference 'Change.count', -changes do
148
        Repository.find(10).destroy
149
      end
150
    end
151
  end
152

  
153
  def test_destroy_should_delete_parents_associations
154
    changeset = Changeset.find(102)
155
    changeset.parents = Changeset.find_all_by_id([100, 101])
156

  
157
    assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do
158
      Repository.find(10).destroy
159
    end
160
  end
161

  
162
  def test_destroy_should_delete_issues_associations
163
    changeset = Changeset.find(102)
164
    changeset.issues = Issue.find_all_by_id([1, 2])
165

  
166
    assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do
167
      Repository.find(10).destroy
168
    end
169
  end
170

  
171
  def test_should_not_create_with_disabled_scm
172
    # disable Subversion
173
    with_settings :enabled_scm => ['Darcs', 'Git'] do
174
      repository = Repository::Subversion.new(
175
                      :project => Project.find(3), :url => "svn://localhost")
176
      assert !repository.save
177
      assert_include I18n.translate('activerecord.errors.messages.invalid'),
178
                     repository.errors[:type]
179
    end
180
  end
181

  
182
  def test_scan_changesets_for_issue_ids
183
    Setting.default_language = 'en'
184

  
185
    # choosing a status to apply to fix issues
186
    Setting.commit_fix_status_id = IssueStatus.find(
187
                                     :first,
188
                                     :conditions => ["is_closed = ?", true]).id
189
    Setting.commit_fix_done_ratio = "90"
190
    Setting.commit_ref_keywords = 'refs , references, IssueID'
191
    Setting.commit_fix_keywords = 'fixes , closes'
192
    Setting.default_language = 'en'
193
    ActionMailer::Base.deliveries.clear
194

  
195
    # make sure issue 1 is not already closed
196
    fixed_issue = Issue.find(1)
197
    assert !fixed_issue.status.is_closed?
198
    old_status = fixed_issue.status
199

  
200
    with_settings :notified_events => %w(issue_added issue_updated) do
201
      Repository.scan_changesets_for_issue_ids
202
    end
203
    assert_equal [101, 102], Issue.find(3).changeset_ids
204

  
205
    # fixed issues
206
    fixed_issue.reload
207
    assert fixed_issue.status.is_closed?
208
    assert_equal 90, fixed_issue.done_ratio
209
    assert_equal [101], fixed_issue.changeset_ids
210

  
211
    # issue change
212
    journal = fixed_issue.journals.find(:first, :order => 'created_on desc')
213
    assert_equal User.find_by_login('dlopper'), journal.user
214
    assert_equal 'Applied in changeset r2.', journal.notes
215

  
216
    # 2 email notifications
217
    assert_equal 2, ActionMailer::Base.deliveries.size
218
    mail = ActionMailer::Base.deliveries.first
219
    assert_not_nil mail
220
    assert mail.subject.starts_with?(
221
        "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
222
    assert_mail_body_match(
223
        "Status changed from #{old_status} to #{fixed_issue.status}", mail)
224

  
225
    # ignoring commits referencing an issue of another project
226
    assert_equal [], Issue.find(4).changesets
227
  end
228

  
229
  def test_for_changeset_comments_strip
230
    repository = Repository::Mercurial.create(
231
                    :project => Project.find( 4 ),
232
                    :url => '/foo/bar/baz' )
233
    comment = <<-COMMENT
234
    This is a loooooooooooooooooooooooooooong comment                                                   
235
                                                                                                       
236
                                                                                            
237
    COMMENT
238
    changeset = Changeset.new(
239
      :comments => comment, :commit_date => Time.now,
240
      :revision => 0, :scmid => 'f39b7922fb3c',
241
      :committer => 'foo <foo@example.com>',
242
      :committed_on => Time.now, :repository => repository )
243
    assert( changeset.save )
244
    assert_not_equal( comment, changeset.comments )
245
    assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
246
                  changeset.comments )
247
  end
248

  
249
  def test_for_urls_strip_cvs
250
    repository = Repository::Cvs.create(
251
        :project => Project.find(4),
252
        :url => ' :pserver:login:password@host:/path/to/the/repository',
253
        :root_url => 'foo  ',
254
        :log_encoding => 'UTF-8')
255
    assert repository.save
256
    repository.reload
257
    assert_equal ':pserver:login:password@host:/path/to/the/repository',
258
                  repository.url
259
    assert_equal 'foo', repository.root_url
260
  end
261

  
262
  def test_for_urls_strip_subversion
263
    repository = Repository::Subversion.create(
264
        :project => Project.find(4),
265
        :url => ' file:///dummy   ')
266
    assert repository.save
267
    repository.reload
268
    assert_equal 'file:///dummy', repository.url
269
  end
270

  
271
  def test_for_urls_strip_git
272
    repository = Repository::Git.create(
273
        :project => Project.find(4),
274
        :url => ' c:\dummy   ')
275
    assert repository.save
276
    repository.reload
277
    assert_equal 'c:\dummy', repository.url
278
  end
279

  
280
  def test_manual_user_mapping
281
    assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do
282
      c = Changeset.create!(
283
              :repository => @repository,
284
              :committer => 'foo',
285
              :committed_on => Time.now,
286
              :revision => 100,
287
              :comments => 'Committed by foo.'
288
            )
289
      assert_nil c.user
290
      @repository.committer_ids = {'foo' => '2'}
291
      assert_equal User.find(2), c.reload.user
292
      # committer is now mapped
293
      c = Changeset.create!(
294
              :repository => @repository,
295
              :committer => 'foo',
296
              :committed_on => Time.now,
297
              :revision => 101,
298
              :comments => 'Another commit by foo.'
299
            )
300
      assert_equal User.find(2), c.user
301
    end
302
  end
303

  
304
  def test_auto_user_mapping_by_username
305
    c = Changeset.create!(
306
          :repository   => @repository,
307
          :committer    => 'jsmith',
308
          :committed_on => Time.now,
309
          :revision     => 100,
310
          :comments     => 'Committed by john.'
311
        )
312
    assert_equal User.find(2), c.user
313
  end
314

  
315
  def test_auto_user_mapping_by_email
316
    c = Changeset.create!(
317
          :repository   => @repository,
318
          :committer    => 'john <jsmith@somenet.foo>',
319
          :committed_on => Time.now,
320
          :revision     => 100,
321
          :comments     => 'Committed by john.'
322
        )
323
    assert_equal User.find(2), c.user
324
  end
325

  
326
  def test_filesystem_avaialbe
327
    klass = Repository::Filesystem
328
    assert klass.scm_adapter_class
329
    assert_equal true, klass.scm_available
330
  end
331

  
332
  def test_merge_extra_info
333
    repo = Repository::Subversion.new(:project => Project.find(3))
334
    assert !repo.save
335
    repo.url = "svn://localhost"
336
    assert repo.save
337
    repo.reload
338
    project = Project.find(3)
339
    assert_equal repo, project.repository
340
    assert_nil repo.extra_info
341
    h1 = {"test_1" => {"test_11" => "test_value_11"}}
342
    repo.merge_extra_info(h1)
343
    assert_equal h1, repo.extra_info
344
    h2 = {"test_2" => {
345
                   "test_21" => "test_value_21",
346
                   "test_22" => "test_value_22",
347
                  }}
348
    repo.merge_extra_info(h2)
349
    assert_equal (h = {"test_11" => "test_value_11"}),
350
                 repo.extra_info["test_1"]
351
    assert_equal "test_value_21",
352
                 repo.extra_info["test_2"]["test_21"]
353
    h3 = {"test_2" => {
354
                   "test_23" => "test_value_23",
355
                   "test_24" => "test_value_24",
356
                  }}
357
    repo.merge_extra_info(h3)
358
    assert_equal (h = {"test_11" => "test_value_11"}),
359
                 repo.extra_info["test_1"]
360
    assert_nil repo.extra_info["test_2"]["test_21"]
361
    assert_equal "test_value_23",
362
                 repo.extra_info["test_2"]["test_23"]
363
  end
364

  
365
  def test_sort_should_not_raise_an_error_with_nil_identifiers
366
    r1 = Repository.new
367
    r2 = Repository.new
368

  
369
    assert_nothing_raised do
370
      [r1, r2].sort
371
    end
372
  end
373
end
.svn/pristine/7e/7e76b4641a50c91dfdb3b47214bfa579f7ab379e.svn-base
1
<%= back_url_hidden_field_tag %>
2
<%= error_messages_for 'version' %>
3

  
4
<div class="box tabular">
5
<p><%= f.text_field :name, :size => 60, :required => true %></p>
6
<p><%= f.text_field :description, :size => 60 %></p>
7
<p><%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %></p>
8
<p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
9
<p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
10
<p><%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %></p>
11

  
12
<% @version.custom_field_values.each do |value| %>
13
  <p><%= custom_field_tag_with_label :version, value %></p>
14
<% end %>
15

  
16
</div>
.svn/pristine/7e/7ed0d1fdf9d439d825a4be4f6bf2f7c9112ea3a3.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2012  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
class Member < ActiveRecord::Base
19
  belongs_to :user
20
  belongs_to :principal, :foreign_key => 'user_id'
21
  has_many :member_roles, :dependent => :destroy
22
  has_many :roles, :through => :member_roles
23
  belongs_to :project
24

  
25
  validates_presence_of :principal, :project
26
  validates_uniqueness_of :user_id, :scope => :project_id
27
  validate :validate_role
28

  
29
  before_destroy :set_issue_category_nil
30
  after_destroy :unwatch_from_permission_change
31

  
32
  def role
33
  end
34

  
35
  def role=
36
  end
37

  
38
  def name
39
    self.user.name
40
  end
41

  
42
  alias :base_role_ids= :role_ids=
43
  def role_ids=(arg)
44
    ids = (arg || []).collect(&:to_i) - [0]
45
    # Keep inherited roles
46
    ids += member_roles.select {|mr| !mr.inherited_from.nil?}.collect(&:role_id)
47

  
48
    new_role_ids = ids - role_ids
49
    # Add new roles
50
    new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) }
51
    # Remove roles (Rails' #role_ids= will not trigger MemberRole#on_destroy)
52
    member_roles_to_destroy = member_roles.select {|mr| !ids.include?(mr.role_id)}
53
    if member_roles_to_destroy.any?
54
      member_roles_to_destroy.each(&:destroy)
55
      unwatch_from_permission_change
56
    end
57
  end
58

  
59
  def <=>(member)
60
    a, b = roles.sort.first, member.roles.sort.first
61
    if a == b
62
      if principal
63
        principal <=> member.principal
64
      else
65
        1
66
      end
67
    elsif a
68
      a <=> b
69
    else
70
      1
71
    end
72
  end
73

  
74
  def deletable?
75
    member_roles.detect {|mr| mr.inherited_from}.nil?
76
  end
77

  
78
  def include?(user)
79
    if principal.is_a?(Group)
80
      !user.nil? && user.groups.include?(principal)
81
    else
82
      self.user == user
83
    end
84
  end
85

  
86
  def set_issue_category_nil
87
    if user
88
      # remove category based auto assignments for this member
89
      IssueCategory.update_all "assigned_to_id = NULL", ["project_id = ? AND assigned_to_id = ?", project.id, user.id]
90
    end
91
  end
92

  
93
  # Find or initilize a Member with an id, attributes, and for a Principal
94
  def self.edit_membership(id, new_attributes, principal=nil)
95
    @membership = id.present? ? Member.find(id) : Member.new(:principal => principal)
96
    @membership.attributes = new_attributes
97
    @membership
98
  end
99

  
100
  protected
101

  
102
  def validate_role
103
    errors.add_on_empty :role if member_roles.empty? && roles.empty?
104
  end
105

  
106
  private
107

  
108
  # Unwatch things that the user is no longer allowed to view inside project
109
  def unwatch_from_permission_change
110
    if user
111
      Watcher.prune(:user => user, :project => project)
112
    end
113
  end
114
end

Also available in: Unified diff