Skip to content

Commit 02a69e3

Browse files
authored
Merge pull request #62 from basyura/feature/project_pattern
add project pattern
2 parents 18872a9 + 6196f3d commit 02a69e3

File tree

10 files changed

+130
-16
lines changed

10 files changed

+130
-16
lines changed

app/controllers/view_customizes_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,6 @@ def find_view_customize
6868

6969
def view_customize_params
7070
params.require(:view_customize)
71-
.permit(:path_pattern, :customize_type, :code, :is_enabled, :is_private, :insertion_position, :comments)
71+
.permit(:path_pattern, :project_pattern, :customize_type, :code, :is_enabled, :is_private, :insertion_position, :comments)
7272
end
7373
end

app/models/view_customize.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class ViewCustomize < ActiveRecord::Base
33

44
validates_presence_of :path_pattern
55
validates_length_of :path_pattern, :maximum => 255
6+
validates_length_of :project_pattern, :maximum => 255
67

78
validates_presence_of :code
89

@@ -66,6 +67,15 @@ def valid_pattern
6667
rescue
6768
errors.add(:path_pattern, :invalid)
6869
end
70+
71+
unless project_pattern.empty?
72+
begin
73+
Regexp.compile(project_pattern)
74+
rescue
75+
errors.add(:project_pattern, :invalid)
76+
end
77+
end
78+
6979
end
7080

7181
def initialize(attributes=nil, *args)

app/views/view_customizes/_form.html.erb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
<%= l(:text_path_pattern_match_info) %>
99
</em>
1010
</p>
11+
<p>
12+
<%= form.text_field :project_pattern,
13+
:size => 100, :required => false %>
14+
<em class="info">
15+
<%= l(:text_project_pattern_info) %><br />
16+
<%= l(:text_project_pattern_match_info) %>
17+
</em>
18+
</p>
1119
<p>
1220
<%= form.select :insertion_position,
1321
options_for_select(

app/views/view_customizes/index.html.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<tr>
1616
<%= sort_header_tag('id', :caption => '#') %>
1717
<%= sort_header_tag('path_pattern', :caption => l(:field_path_pattern)) %>
18+
<%= sort_header_tag('project_pattern', :caption => l(:field_project_pattern)) %>
1819
<%= sort_header_tag('insertion_position', :caption => l(:field_insertion_position)) %>
1920
<%= sort_header_tag('customize_type', :caption => l(:field_customize_type)) %>
2021
<%= sort_header_tag('comments', :caption => l(:field_comments) + ' / ' + l(:field_code)) %>
@@ -27,6 +28,7 @@
2728
<tr class="<%= cycle('odd', 'even') %><%= ' disable' unless view_customize.is_enabled %><%= ' private' unless !view_customize.is_private %>">
2829
<td class="id"><%= link_to view_customize.id, view_customize_path(view_customize.id) %></td>
2930
<td class="path"><%=h view_customize.path_pattern %></td>
31+
<td class="project_pattern"><%=h view_customize.project_pattern%></td>
3032
<td class="insertion_position"><%=h l(view_customize.insertion_position_label) %></td>
3133
<td><%=h l(view_customize.customize_type_label) %></td>
3234
<td class="comments"><%=h view_customize.comments.present? ? view_customize.comments : truncate(view_customize.code, :length => 80) %></td>

app/views/view_customizes/show.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<th><%=h l(:field_path_pattern) %></th>
1818
<td><%=h @view_customize.path_pattern %></td>
1919
</tr>
20+
<tr>
21+
<th><%=h l(:field_project_pattern) %></th>
22+
<td><%=h @view_customize.project_pattern %></td>
23+
</tr>
2024
<tr>
2125
<th><%=h l(:field_insertion_position) %></th>
2226
<td><%=h l(@view_customize.insertion_position_label) %></td>

config/locales/en.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ en:
1212
label_insertion_position_issue_form: "Bottom of issue form"
1313
label_insertion_position_issue_show: "Bottom of issue detail"
1414
field_path_pattern: "Path pattern"
15+
field_project_pattern: "Project pattern"
1516
field_insertion_position: "Insertion position"
1617
field_customize_type: "Type"
1718
field_code: "Code"
@@ -21,4 +22,6 @@ en:
2122
field_author: "Author"
2223
text_path_pattern_info: "Path pattern is specified with a regular expression. (ex. /issues/[0-9]+)"
2324
text_path_pattern_match_info: "If there is a match with the path of the page, insert the following code and execute it."
25+
text_project_pattern_info: "Project (identifier) pattern is specified with a regular expression (ex. sampleProjA|samplePrjB)"
26+
text_project_pattern_match_info: "If there is a match with the current project, insert the following code and execute it."
2427
option_create_api_access_key: "Automatically create API access key"

config/locales/ja.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ ja:
1111
label_insertion_position_issue_form: "チケット入力欄の下"
1212
label_insertion_position_issue_show: "チケット詳細の下"
1313
field_path_pattern: "パスのパターン"
14+
field_project_pattern: "プロジェクトのパターン"
1415
field_insertion_position: "挿入位置"
1516
field_customize_type: "種別"
1617
field_code: "コード"
@@ -20,4 +21,6 @@ ja:
2021
field_author: "作成者"
2122
text_path_pattern_info: "パスのパターンは正規表現で指定します。 (例 /issues/[0-9]+)"
2223
text_path_pattern_match_info: "ページのパスが一致した場合、以下のコードを挿入し、実行します。"
23-
option_create_api_access_key: "APIアクセスキーを自動的に作成する"
24+
text_project_pattern_info: "プロジェクト(識別子)を正規表現で指定します。 (例 sampleProjA|samplePrjB)"
25+
text_project_pattern_match_info: "選択中のプロジェクトが一致した場合、以下のコードを挿入し、実行します。"
26+
option_create_api_access_key: "APIアクセスキーを自動的に作成する"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class AddProjectPatternToViewCustomizes < ActiveRecord::CompatibleLegacyMigration.migration_class
2+
def up
3+
add_column :view_customizes, :project_pattern, :string, :null => false, :default => ""
4+
end
5+
6+
def down
7+
remove_column :view_customizes, :project_pattern
8+
end
9+
end
10+
11+

lib/view_customize/view_hook.rb

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
module RedmineViewCustomize
44
class ViewHook < Redmine::Hook::ViewListener
55
def view_layouts_base_html_head(context={})
6-
6+
ctx = create_view_customize_context(context)
77
path = Redmine::CodesetUtil.replace_invalid_utf8(context[:request].path_info);
88

99
html = "\n<!-- [view customize plugin] path:#{path} -->\n"
1010
html << stylesheet_link_tag("view_customize", plugin: "view_customize")
1111
html << "<script type=\"text/javascript\">\n//<![CDATA[\n"
12-
html << "ViewCustomize = { context: #{create_view_customize_context(context).to_json} };"
12+
html << "ViewCustomize = { context: #{ctx.to_json} };"
1313
html << "\n//]]>\n</script>"
1414

15-
html << create_view_customize_html(path, ViewCustomize::INSERTION_POSITION_HTML_HEAD)
15+
html << create_view_customize_html(ctx, path, ViewCustomize::INSERTION_POSITION_HTML_HEAD)
1616

1717
return html
1818
end
@@ -37,22 +37,30 @@ def view_issues_show_details_bottom(context={})
3737

3838
private
3939

40-
def create_view_customize_html(path, insertion_position)
40+
def create_view_customize_html(ctx, path, insertion_position)
4141

42-
view_customize_html_parts = match_customize(path, insertion_position).map {|item|
42+
view_customize_html_parts = match_customize(ctx, path, insertion_position).map {|item|
4343
to_html(item)
4444
}
4545
return view_customize_html_parts.join("\n").html_safe
4646

4747
end
4848

49-
def match_customize(path, insertion_position)
49+
def match_customize(ctx, path, insertion_position)
50+
ViewCustomize.all.select {|item| target_customize?(ctx, path, insertion_position, item)}
51+
end
5052

51-
ViewCustomize.all.select {|item|
52-
item.available? \
53-
&& item.insertion_position == insertion_position \
54-
&& path =~ Regexp.new(item.path_pattern)
55-
}
53+
def target_customize?(ctx, path, insertion_position, item)
54+
return false unless item.available?
55+
return false unless item.insertion_position == insertion_position
56+
return false unless path =~ Regexp.new(item.path_pattern)
57+
58+
if item.project_pattern.empty?
59+
return true
60+
end
61+
62+
return false unless ctx["project"]
63+
return ctx["project"]["identifier"] =~ Regexp.new(item.project_pattern)
5664
end
5765

5866
def to_html(view_customize)

test/unit/view_customize_test.rb

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,74 @@
11
require File.expand_path('../../test_helper', __FILE__)
2+
require File.expand_path('../../../lib/view_customize/view_hook', __FILE__)
23

34
class ViewCustomizeTest < ActiveSupport::TestCase
5+
#
6+
#
7+
class Record
8+
attr_accessor :path_pattern, :project_pattern, :insertion_position
9+
def initialize(available, path, project, position)
10+
@available, @path_pattern, @project_pattern, @insertion_position = available, path, project, position
11+
end
12+
13+
def available?
14+
@available
15+
end
16+
17+
def self.store(records)
18+
@records = records
19+
end
20+
21+
def self.get
22+
@records
23+
end
24+
end
25+
#
26+
# Replace records
27+
module ViewCustomizeExt
28+
refine ViewCustomize do
29+
class << ViewCustomize
30+
def all
31+
Record.get
32+
end
33+
end
34+
end
35+
end
36+
#
37+
using ViewCustomizeExt
38+
#
39+
#
40+
def test_hook_match_customize
41+
ctx = {}
42+
path = "/redmine/issues"
43+
pos = "html_head"
44+
45+
Record.store([Record.new(true, ".*", "", "html_head")])
46+
47+
hook = RedmineViewCustomize::ViewHook.instance
48+
matches = hook.send(:match_customize, ctx, path, pos)
49+
assert_equal matches.length, 1
50+
51+
# right project
52+
Record.store([Record.new(true, ".*", "testproject", "html_head")])
53+
matches = hook.send(:match_customize, { "project" => { "identifier" => "testproject" }}, path, pos)
54+
assert matches.length == 1
55+
# wrong proejct
56+
matches = hook.send(:match_customize, { "project" => { "identifier" => "sampleproject" }}, path, pos)
57+
assert matches.length == 0
58+
# no project in ctx, but project is in record
59+
matches = hook.send(:match_customize, {}, path, pos)
60+
assert matches.length == 0
61+
# filter by path
62+
Record.store([Record.new(true, ".*", "", "html_head"), Record.new(true, "/redmine/view_customize", "", "html_head")])
63+
matches = hook.send(:match_customize, {}, path, pos)
64+
assert matches.length == 1
65+
# filter by project and path
66+
Record.store([Record.new(true, ".*", "", "html_head"), Record.new(true, "/redmine/issues", "testproject", "html_head")])
67+
matches = hook.send(:match_customize, { "project" => { "identifier" => "testproject" }}, path, pos)
68+
assert matches.length == 2
69+
70+
71+
472

5-
# Replace this with your real tests.
6-
def test_truth
7-
assert true
873
end
974
end

0 commit comments

Comments
 (0)