redmine_version_priorities 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ jQuery(function($) {
2
+ $("#ajax-indicator").ajaxStart(function(){ $(this).show(); });
3
+ $("#ajax-indicator").ajaxStop(function(){ $(this).hide(); });
4
+
5
+ attachSortables = function() {
6
+ if (window.admin != true) {
7
+ return false;
8
+ }
9
+
10
+ attachPrioritizedSortables();
11
+ attachUnPrioritizedSortables();
12
+ },
13
+
14
+ attachPrioritizedSortables = function() {
15
+ $('#prioritized-versions ol').sortable({
16
+ cancel: 'a',
17
+ connectWith: ["#unprioritized-versions ul"],
18
+ placeholder: 'drop-accepted',
19
+ dropOnEmpty: true,
20
+ // Allow drag and drop inside the list
21
+ update: function (event, ui) {
22
+ if (ui.sender == null && event.target == this) {
23
+ saveOrder();
24
+ }
25
+ },
26
+ receive: function (event, ui) {
27
+ saveOrder();
28
+ }
29
+ });
30
+ },
31
+
32
+ attachUnPrioritizedSortables = function() {
33
+ $('#unprioritized-versions ul').sortable({
34
+ cancel: 'a',
35
+ connectWith: ["#prioritized-versions ol"],
36
+ placeholder: 'drop-accepted',
37
+ dropOnEmpty: true
38
+ });
39
+
40
+ },
41
+
42
+ saveOrder = function() {
43
+ var data = $('#prioritized-versions ol').sortable('serialize')
44
+
45
+ $.ajaxQueue.put('version_priorities.js', {
46
+ data: addAuthenticityToken(data),
47
+ success: function(response) {
48
+ $('#prioritized-versions').html(response);
49
+ attachPrioritizedSortables();
50
+ },
51
+ error: function(response) {
52
+ $("div.error").html("Error saving lists. Please refresh the page and try again.").show();
53
+
54
+ }
55
+ });
56
+ },
57
+
58
+ addAuthenticityToken = function(data) {
59
+ return data + '&authenticity_token=' + encodeURIComponent(window._token);
60
+ },
61
+
62
+ attachSortables();
63
+ });
@@ -0,0 +1,17 @@
1
+
2
+ .version {}
3
+ li.version { clear: both; }
4
+ .ui-sortable {cursor: move;}
5
+
6
+ #prioritized-versions ol { padding-left: 35px; }
7
+ #unprioritized-versions ul { list-style: none; padding-left: 15px;}
8
+
9
+ /* item elements */
10
+ li.version span.due_date { font-size: smaller; }
11
+ li.version table.progress { display: inline; position: relative; float: right; }
12
+ li.version p.pourcent { display: inline; position: relative; float: right; }
13
+
14
+ h1.version-priority-title { margin-bottom: 15px; }
15
+
16
+
17
+ .drop-accepted { background-color:#FFFFEE; height: 16px; margin-bottom:5px; border: 1px dashed #000000; }
@@ -0,0 +1,5 @@
1
+ en:
2
+ version_priorities_title: "Version Priorities"
3
+ version_priorities_text_prioritized_versions: "Prioritized Versions"
4
+ version_priorities_text_unprioritized_versions: "Unprioritized Versions"
5
+ field_fixed_version_priority: "Version priority"
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.resource :version_priorities
3
+ end
data/init.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'redmine'
2
+
3
+ Redmine::Plugin.register :redmine_version_priorities do
4
+ name 'Version Priorities'
5
+ author 'Eric Davis'
6
+ url 'https://projects.littlestreamsoftware.com/projects/version-priorities'
7
+ author_url 'http://www.littlestreamsoftware.com'
8
+ description 'Allows versions to be prioritized'
9
+ version '0.1.0'
10
+
11
+ requires_redmine :version_or_higher => '0.9.0'
12
+
13
+ menu(:top_menu,
14
+ :version_priorities,
15
+ {:controller => 'version_priorities', :action => 'show'},
16
+ :caption => :version_priorities_title,
17
+ :if => Proc.new {
18
+ User.current.logged?
19
+ })
20
+
21
+ permission(:view_version_priorities, {:version_priorities => [:show]}, :public => true)
22
+
23
+ end
24
+
25
+ require 'dispatcher'
26
+ Dispatcher.to_prepare :redmine_version_priorities do
27
+
28
+ require_dependency 'issue'
29
+ Issue.send(:include, RedmineVersionPriorities::Patches::IssuePatch)
30
+
31
+ require_dependency 'query'
32
+ unless Query.included_modules.include?(RedmineVersionPriorities::Patches::QueryPatch)
33
+ Query.send(:include, RedmineVersionPriorities::Patches::QueryPatch)
34
+ end
35
+
36
+ require_dependency 'version'
37
+ Version.send(:include, RedmineVersionPriorities::Patches::VersionPatch)
38
+ end
data/lang/en.yml ADDED
@@ -0,0 +1,2 @@
1
+ # English strings go here
2
+ my_label: "My label"
@@ -0,0 +1,27 @@
1
+ module RedmineVersionPriorities
2
+ module Patches
3
+ module IssuePatch
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+
7
+ base.send(:include, InstanceMethods)
8
+ base.class_eval do
9
+ unloadable
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+ end
15
+
16
+ module InstanceMethods
17
+ def fixed_version_priority
18
+ if fixed_version && fixed_version.priority.present?
19
+ fixed_version
20
+ else
21
+ l(:label_none)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module RedmineVersionPriorities
2
+ module Patches
3
+ module QueryPatch
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+
7
+ base.send(:include, InstanceMethods)
8
+ base.class_eval do
9
+ unloadable
10
+
11
+ add_available_column(QueryColumn.new(:fixed_version_priority,
12
+ :sortable => ["#{Version.table_name}.priority IS NULL",
13
+ "#{Version.table_name}.priority",
14
+ "#{Version.table_name}.effective_date",
15
+ "#{Version.table_name}.name"],
16
+ :default_order => 'asc'))
17
+
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ # Setter for +available_columns+ that isn't provided by the core.
23
+ def available_columns=(v)
24
+ self.available_columns = (v)
25
+ end
26
+
27
+ # Method to add a column to the +available_columns+ that isn't provided by the core.
28
+ def add_available_column(column)
29
+ self.available_columns << (column)
30
+ end
31
+ end
32
+
33
+ module InstanceMethods
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ module RedmineVersionPriorities
2
+ module Patches
3
+ module VersionPatch
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+
7
+ base.send(:include, InstanceMethods)
8
+ base.class_eval do
9
+ unloadable
10
+ acts_as_list :column => 'priority'
11
+
12
+ named_scope :prioritized, :conditions => ["priority != 0 AND priority IS NOT NULL"], :order => 'priority ASC'
13
+ named_scope :unprioritized, :conditions => ["priority = 0 OR priority IS NULL"]
14
+
15
+ private
16
+
17
+ # Override acts_as_list to allow nil priorities
18
+ def add_to_list_bottom
19
+ self
20
+ end
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ def reprioritize(order)
26
+ ordered_ids = order.collect(&:to_i) if order.present?
27
+ ordered_ids ||= []
28
+
29
+ # Removed versions
30
+ Version.visible.prioritized.each do |version|
31
+ unless ordered_ids.include?(version.id)
32
+ version.remove_from_list
33
+ end
34
+ end
35
+
36
+ # Sort
37
+ ordered_ids.each_with_index do |version_id, index|
38
+ version = Version.find_by_id(version_id)
39
+ version.insert_at( index + 1) if version
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ module InstanceMethods
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class VersionPrioritiesController < ActionController::TestCase
4
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ class EditVersionPrioritiesTest < ActionController::IntegrationTest
4
+ context "as a logged in user" do
5
+ setup do
6
+ @user = login_as_user
7
+ end
8
+
9
+ should_be_unauthorized("as a logged in user") {
10
+ put "/version_priorities.js"
11
+ }
12
+ end
13
+
14
+ context "as an administrator" do
15
+ setup do
16
+ @user = login_as_user
17
+ @user.update_attribute(:admin, true)
18
+
19
+ @project1 = Project.generate!
20
+ @project2 = Project.generate!
21
+ @version1 = Version.generate!(:project => @project1)
22
+ @version2 = Version.generate!(:project => @project2)
23
+ end
24
+
25
+ should "reprioritize the versions with a :html request" do
26
+ put "/version_priorities", :version => [@version2.id.to_s, @version1.id.to_s]
27
+
28
+ assert_response :redirect
29
+ follow_redirect!
30
+ assert_template 'version_priorities/show'
31
+
32
+ assert_equal 2, @version1.reload.priority
33
+ assert_equal 1, @version2.reload.priority
34
+ end
35
+
36
+ should "reprioritize the versions with a :js request" do
37
+ put "/version_priorities.js", :version => [@version2.id.to_s, @version1.id.to_s]
38
+ assert_response :success
39
+
40
+ assert_equal 2, @version1.reload.priority
41
+ assert_equal 1, @version2.reload.priority
42
+ end
43
+
44
+ should "remove versions not in the list anymore" do
45
+ @version2.insert_at(1)
46
+ assert_equal 1, @version2.reload.priority
47
+
48
+ put "/version_priorities.js", :version => [@version1.id.to_s]
49
+ assert_response :success
50
+
51
+ assert_equal nil, @version2.reload.priority
52
+ end
53
+
54
+ should "remove all versions when the list is empty" do
55
+ @version2.insert_at(1)
56
+ assert_equal 1, @version2.reload.priority
57
+ @version1.insert_at(2)
58
+ assert_equal 2, @version1.reload.priority
59
+
60
+ put "/version_priorities.js"
61
+ assert_response :success
62
+
63
+ assert_equal nil, @version1.reload.priority
64
+ assert_equal nil, @version2.reload.priority
65
+ end
66
+ end
67
+
68
+ def login_as_user
69
+ user = User.generate!(:login => 'existing', :password => 'existing', :password_confirmation => 'existing', :admin => false)
70
+ visit "/login"
71
+ fill_in 'Login', :with => 'existing'
72
+ fill_in 'Password', :with => 'existing'
73
+ click_button 'login'
74
+ assert_response :success
75
+ assert User.current.logged?
76
+
77
+ user
78
+ end
79
+ end
@@ -0,0 +1,90 @@
1
+ require 'test_helper'
2
+
3
+ class ViewVersionPrioritiesTest < ActionController::IntegrationTest
4
+ should "not show the menu item to users not logged in" do
5
+ visit "/"
6
+ assert_response :success
7
+ assert_select "#top-menu a.version-priorities", :count => 0
8
+ end
9
+
10
+ should "show the menu item to logged in users" do
11
+ login_as_user
12
+
13
+ visit "/"
14
+ assert_response :success
15
+ assert_select "#top-menu a.version-priorities", :count => 1
16
+ end
17
+
18
+ should "allow all logged in users to visit the prioritized versions panel" do
19
+ login_as_user
20
+
21
+ visit '/'
22
+ click_link "Version Priorities"
23
+ assert_response :success
24
+ assert_equal "/version_priorities", current_url
25
+ end
26
+
27
+ should "allow all logged in users to see the unprioritized versions" do
28
+ @user = login_as_user
29
+ @project1 = Project.generate!
30
+ @project2 = Project.generate!
31
+ @version1 = Version.generate!(:project => @project1)
32
+ @version2 = Version.generate!(:project => @project2)
33
+ @role = Role.generate!(:permissions => [:view_issues])
34
+ Member.generate!(:principal => @user, :roles => [@role], :project => @project1)
35
+ Member.generate!(:principal => @user, :roles => [@role], :project => @project2)
36
+
37
+ visit "/version_priorities"
38
+
39
+ assert_select "#unprioritized-versions" do
40
+ assert_select "li" do
41
+ assert_select "a", :text => /#{@version1.name}/
42
+ assert_select "span", :text => /#{@version1.description}/
43
+ end
44
+
45
+ assert_select "li" do
46
+ assert_select "a", :text => /#{@version2.name}/
47
+ assert_select "span", :text => /#{@version2.description}/
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ should "allow all logged in users to see the prioritized versions" do
54
+ @user = login_as_user
55
+ @project1 = Project.generate!
56
+ @project2 = Project.generate!
57
+ @version1 = Version.generate!(:project => @project1, :priority => 1)
58
+ @version2 = Version.generate!(:project => @project2, :priority => 2)
59
+ @role = Role.generate!(:permissions => [:view_issues])
60
+ Member.generate!(:principal => @user, :roles => [@role], :project => @project1)
61
+ Member.generate!(:principal => @user, :roles => [@role], :project => @project2)
62
+
63
+ visit "/version_priorities"
64
+
65
+ assert_select "#prioritized-versions" do
66
+ assert_select "li" do
67
+ assert_select "a", :text => /#{@version1.name}/
68
+ assert_select "span", :text => /#{@version1.description}/
69
+ end
70
+
71
+ assert_select "li" do
72
+ assert_select "a", :text => /#{@version2.name}/
73
+ assert_select "span", :text => /#{@version2.description}/
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ def login_as_user
80
+ user = User.generate!(:login => 'existing', :password => 'existing', :password_confirmation => 'existing', :admin => false)
81
+ visit "/login"
82
+ fill_in 'Login', :with => 'existing'
83
+ fill_in 'Password', :with => 'existing'
84
+ click_button 'login'
85
+ assert_response :success
86
+ assert User.current.logged?
87
+
88
+ user
89
+ end
90
+ end
@@ -0,0 +1,52 @@
1
+ # Load the normal Rails helper
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
3
+
4
+ # Ensure that we are using the temporary fixture path
5
+ Engines::Testing.set_fixture_path
6
+
7
+ require "webrat"
8
+
9
+ Webrat.configure do |config|
10
+ config.mode = :rails
11
+ end
12
+
13
+ class Test::Unit::TestCase
14
+ def setup
15
+ setup_anonymous_role
16
+ setup_non_member_role
17
+ end
18
+
19
+ def setup_anonymous_role
20
+ begin
21
+ @anon_role = Role.anonymous
22
+ rescue
23
+ @anon_role = Role.generate!
24
+ @anon_role.update_attribute(:builtin, Role::BUILTIN_ANONYMOUS)
25
+ end
26
+ end
27
+
28
+ def setup_non_member_role
29
+ begin
30
+ @anon_role = Role.non_member
31
+ rescue
32
+ @non_member_role = Role.generate!
33
+ @non_member_role.update_attribute(:builtin, Role::BUILTIN_NON_MEMBER)
34
+ end
35
+ end
36
+
37
+ def self.should_be_unauthorized(description, &block)
38
+ context description do
39
+ should "render the unauthorized template" do
40
+ instance_eval &block
41
+ assert_template 'common/403'
42
+ end
43
+
44
+ should "respond with unauthorized" do
45
+ instance_eval &block
46
+ assert_response 403
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ end