redmine_api_helper 0.3.24

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of redmine_api_helper might be problematic. Click here for more details.

Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +2 -0
  3. data/.gitignore +11 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +339 -0
  7. data/README.md +30 -0
  8. data/Rakefile +2 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/lib/date_helper/date.rb +311 -0
  12. data/lib/odf_writer/bookmark.rb +110 -0
  13. data/lib/odf_writer/bookmark_reader.rb +77 -0
  14. data/lib/odf_writer/document.rb +372 -0
  15. data/lib/odf_writer/field.rb +174 -0
  16. data/lib/odf_writer/field_reader.rb +78 -0
  17. data/lib/odf_writer/image.rb +158 -0
  18. data/lib/odf_writer/image_reader.rb +76 -0
  19. data/lib/odf_writer/images.rb +89 -0
  20. data/lib/odf_writer/list_style.rb +331 -0
  21. data/lib/odf_writer/nested.rb +156 -0
  22. data/lib/odf_writer/odf_helper.rb +56 -0
  23. data/lib/odf_writer/parser/default.rb +685 -0
  24. data/lib/odf_writer/path_finder.rb +114 -0
  25. data/lib/odf_writer/section.rb +120 -0
  26. data/lib/odf_writer/section_reader.rb +61 -0
  27. data/lib/odf_writer/style.rb +417 -0
  28. data/lib/odf_writer/table.rb +135 -0
  29. data/lib/odf_writer/table_reader.rb +61 -0
  30. data/lib/odf_writer/template.rb +222 -0
  31. data/lib/odf_writer/text.rb +97 -0
  32. data/lib/odf_writer/text_reader.rb +77 -0
  33. data/lib/odf_writer/version.rb +29 -0
  34. data/lib/redmine_api_helper/api_helper.rb +333 -0
  35. data/lib/redmine_api_helper/args_helper.rb +106 -0
  36. data/lib/redmine_api_helper/attachments_api_helper.rb +52 -0
  37. data/lib/redmine_api_helper/define_api_helpers.rb +78 -0
  38. data/lib/redmine_api_helper/document_categories_api_helper.rb +38 -0
  39. data/lib/redmine_api_helper/groups_api_helper.rb +80 -0
  40. data/lib/redmine_api_helper/helpers.rb +50 -0
  41. data/lib/redmine_api_helper/issue_priorities_api_helper.rb +38 -0
  42. data/lib/redmine_api_helper/issue_relations_api_helper.rb +66 -0
  43. data/lib/redmine_api_helper/issue_statuses_api_helper.rb +36 -0
  44. data/lib/redmine_api_helper/issues_api_helper.rb +124 -0
  45. data/lib/redmine_api_helper/my_account_api_helper.rb +45 -0
  46. data/lib/redmine_api_helper/news_api_helper.rb +73 -0
  47. data/lib/redmine_api_helper/project_memberships_api_helper.rb +77 -0
  48. data/lib/redmine_api_helper/projects_api_helper.rb +73 -0
  49. data/lib/redmine_api_helper/roles_api_helper.rb +52 -0
  50. data/lib/redmine_api_helper/scripts_api_helper.rb +87 -0
  51. data/lib/redmine_api_helper/search_api_helper.rb +38 -0
  52. data/lib/redmine_api_helper/time_entries_api_helper.rb +73 -0
  53. data/lib/redmine_api_helper/time_entry_activities_api_helper.rb +38 -0
  54. data/lib/redmine_api_helper/trackers_api_helper.rb +38 -0
  55. data/lib/redmine_api_helper/users_api_helper.rb +73 -0
  56. data/lib/redmine_api_helper/version.rb +24 -0
  57. data/lib/redmine_api_helper/wiki_pages_api_helper.rb +66 -0
  58. data/lib/redmine_api_helper.rb +88 -0
  59. data/redmine_api_helper.gemspec +35 -0
  60. metadata +148 -0
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "deep_try"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,311 @@
1
+ ##
2
+ # encoding: utf-8
3
+ #
4
+ # Extension for Date to calculate a forward date with compressed syntax
5
+ #
6
+ # Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
7
+ #
8
+ # This program is free software; you can redistribute it and/or
9
+ # modify it under the terms of the GNU General Public License
10
+ # as published by the Free Software Foundation; either version 2
11
+ # of the License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
+ #
22
+
23
+ class Date
24
+
25
+ ####################################################################################
26
+ #
27
+ # Date.today.calc(<rule>) -> [<new_date>, <new_rule>]
28
+ # Date.today.forward(<rule) -> <new_date>
29
+ #
30
+ # <rule>: [DWmMqY][n][FMLWX][-!W*]
31
+ #
32
+ # 1. parameter: epoch-identifier (necessary)
33
+ #
34
+ # D - stands for _D_ays
35
+ # W - stands for _W_eeks
36
+ # m - stands for _m_ondays
37
+ # M - stands for _M_onths
38
+ # q - stands for _q_uarters
39
+ # Y - stands for _Y_ears
40
+ #
41
+ # 2. parameter: integer (necessary)
42
+ #
43
+ # n - stands for the number of epochs
44
+ #
45
+ # 3. position of day within epoch
46
+ #
47
+ # F - stands for _F_irst day of epoch, like first day of month, monday, first day of
48
+ # quarter, or January 1st
49
+ # M - stands for _M_id of epoch, like 15th day of month, wednesday, 15th of
50
+ # mid-of-quarter or June 30th
51
+ # L - stands for _L_ast of epoch, like last day of month, friday (last working day),
52
+ # last day of quarter or December 31st
53
+ # W - stands for _W_eekday (Monday), if calculated day falls on a Saturday or Sunday
54
+ # X - stands for no correction
55
+ #
56
+ # 3. control of date calculation
57
+ #
58
+ # - - the sign "-" is a killswitch. After one date calculation the resubmission rule is
59
+ # deleted, so no further resubmissions happen
60
+ # ! - the sign "!" is a force sign to force date calculation even if a resubmission date
61
+ # present
62
+ # W - the sign "W" in this position corrects the date to the next working day
63
+ # * - the sign "*" is a mock switch. The mock-switch is deleted from the resubmission-rule
64
+ # and no resubmission-date is calculated. Needed for Redmine Attribute-Quickie plugin
65
+ #
66
+ # Example: W1F - one week further, first day, so monday
67
+ # Example: M3M - three months further from today, mid-term, so 15th of month
68
+ # Example: q1- - next quarter, first day of quarter, so 1st Jan., Apr., Jul. or Oct., after
69
+ # one calculation further calculations are stopped, rule is deleted.
70
+ # Example: D1- - tomorrow, then delete rule
71
+ # Example: D1-! - tomorrow!, regardsless of date
72
+ #
73
+ # Resubmission dates are always calculated for the future, never for the past.
74
+ # So W0F would calculate "next monday"", if calculated on a friday, though W0 stands for
75
+ # this week (W0 zero weeks further, first day, monday) and would calculate last monday.
76
+ # In this case, the calculated date is advanced monday further into the future.
77
+ # So q0M would calculate "this quarter mid-term" if calculated near to lapse of current
78
+ # quarter. In this case the calculated date is advanced one quarter into the future.
79
+ ####################################################################################
80
+
81
+ ####################################################################################
82
+ # calc
83
+ ####################################################################################
84
+ def calc( rule )
85
+
86
+ new_date = nil
87
+ new_rule = nil
88
+
89
+ if rule.present?
90
+
91
+ m = parse_rule( rule )
92
+
93
+ if m['mockswitch']
94
+
95
+ # mockswitch does not calculate anything
96
+ # mockswitch is removed from new_rule, however
97
+ new_rule = unmock( rule, m )
98
+
99
+ elsif self <= Date.today || m['force']
100
+
101
+ if( m['epoch'] && m['num'] )
102
+
103
+ new_date = move( m['epoch'], m['num'] )
104
+ new_date = new_date.adjust( m['epoch'], m['pos'], self )
105
+ new_date = new_date.adjust("D", "W", new_date) if m["workingday"] # adjust working day
106
+
107
+ if m['killswitch']
108
+ new_rule = ""
109
+ else
110
+ new_rule = rule
111
+ end
112
+
113
+ end #if
114
+ end #if
115
+ end #if
116
+
117
+ [new_date, new_rule]
118
+
119
+ end #def
120
+
121
+ ####################################################################################
122
+ # forward
123
+ ####################################################################################
124
+ def forward( rule )
125
+ calc( rule ).first
126
+ end #def
127
+
128
+ ####################################################################################
129
+ # calculate num times advance of epoch
130
+ # epoch: D - n days
131
+ # epoch: W - n weeks
132
+ # epoch: M - n months
133
+ # epoch: Y - n years
134
+ #
135
+ # epoch: C - n calendar weeks (absolute, within this year, not relative)
136
+ # epoch: m - n mondays
137
+ # epoch: q - q quarters
138
+ ####################################################################################
139
+ def move( epoch, num )
140
+ case epoch
141
+ when "D"
142
+ self + num.to_i
143
+ when "W"
144
+ self + num.to_i * 7
145
+ when "M"
146
+ self >> num.to_i
147
+ when "Y"
148
+ self >> num.to_i * 12
149
+ when "m"
150
+ (self + num.to_i * 7).monday
151
+ when "q"
152
+ (self >> num.to_i * 3).beginning_of_quarter
153
+ when "C"
154
+ # calendar week 1 is the week containing Jan. 4th
155
+ change(:month => 1, :day => 4).advance( :weeks => (num.to_i - 1))
156
+ else
157
+ self
158
+ end #case
159
+ end #def
160
+
161
+ ####################################################################################
162
+ # calculate time adjustmentfor pos in epoch (_F_irst, _M_id, _L_ast, _W_orking day)
163
+ # epoch: D - day: W - Monday
164
+ # epoch: W - week: F - Monday, M - Wednesday, L - Friday, W - Monday
165
+ # epoch: M - month: F - 1st, M - 15th, L - last, W - Monday
166
+ # epoch: Y - year: F - 01/01, M - 06/30, L - 12/31, W - Monday
167
+ # epoch: q - quarter: W - Monday
168
+ ####################################################################################
169
+ def adjust( epoch, pos, ref=self )
170
+
171
+ case epoch
172
+ when "D"
173
+ case pos
174
+ when "W"
175
+ # if saturday or sunday, fall back to last monday, then add one week for monday coming up
176
+ (wday % 6) != 0 ? self : monday.advance(:days => 7)
177
+ else
178
+ self
179
+ end #case
180
+
181
+ when "W", "C"
182
+ # week
183
+ case pos
184
+ when "F"
185
+ # Monday
186
+ monday < ref ? advance( :weeks => 1).monday : monday
187
+
188
+ when "M"
189
+ # Wednesday = Monday + 2 days
190
+ monday.advance(:days => 2) < ref ? advance( :weeks => 1).monday.advance(:days => 2) : monday.advance(:days => 2)
191
+
192
+ when "L"
193
+ # Friday = Monday + 4 days
194
+ monday.advance(:days => 4) < ref ? advance( :weeks => 1).monday.advance(:days => 4) : monday.advance(:days => 4)
195
+
196
+ when "W"
197
+ # if saturday or sunday, fall back to last monday, then add one week for monday coming up
198
+ (wday % 6) != 0 ? self : monday.advance(:days => 7)
199
+
200
+ else
201
+ self
202
+ end #case
203
+
204
+ when "M"
205
+ # month
206
+ case pos
207
+ when "F"
208
+ # 1st
209
+ change(:day => 1) < ref ? advance( :months => 1).beginning_of_month.change(:day => 1) : change(:day => 1)
210
+
211
+ when "M"
212
+ # 15th
213
+ change(:day => 15) < ref ? advance( :months => 1).beginning_of_month.change(:day => 15) : change(:day => 15)
214
+
215
+ when "L"
216
+ # last day
217
+ end_of_month
218
+
219
+ when "W"
220
+ # if saturday or sunday, fall back to last monday, then add one week for monday coming up
221
+ (wday % 6) != 0 ? self : monday.advance(:days => 7)
222
+ else
223
+ self
224
+ end #case
225
+
226
+ when "Y"
227
+ # year
228
+ case pos
229
+ when "F"
230
+ # Jan. 1st
231
+ beginning_of_year < ref ? advanve(:years => 1).beginning_of_year : beginning_of_year
232
+
233
+ when "M"
234
+ # Jun. 30th
235
+ change(:month => 5, :day => 30) < ref ? advance(:years => 1).change(:month => 5, :day => 30) : change(:month => 5, :day => 30)
236
+
237
+ when "L"
238
+ # Dec. 31st
239
+ change(:month => 12, :day => 31)
240
+
241
+ when "W"
242
+ # if saturday or sunday, fall back to last monday, then add one week for monday coming up
243
+ (wday % 6) != 0 ? self : monday.advance(:days => 7)
244
+ else
245
+ self
246
+ end #case
247
+
248
+ when "q"
249
+ case pos
250
+ when "F"
251
+ # Jan. 1st
252
+ beginning_of_quarter < ref ? advance( :months => 3).beginning_of_quarter : beginning_of_quarter
253
+
254
+ when "M"
255
+ # mid quarter
256
+ beginning_of_quarter.advance(:months => 1).advance(:days => 14) < ref ? advance(:quarters => 1).beginning_of_quarter.advance(:months => 1).advance(:days => 14) : beginning_of_quarter.advance(:months => 1).advance(:days => 14)
257
+
258
+ when "L"
259
+ # end quarter
260
+ end_of_quarter
261
+
262
+ when "W"
263
+ # if saturday or sunday, fall back to last monday, then add one week for monday coming up
264
+ (wday % 6) != 0 ? self : monday.advance(:days => 7)
265
+ else
266
+ self
267
+ end #case
268
+
269
+ else
270
+ self
271
+ end #case epoch
272
+ end #def
273
+
274
+
275
+ ####################################################################################
276
+ # private
277
+ ####################################################################################
278
+ private
279
+
280
+ ####################################################################################
281
+ # parse_rule
282
+ ####################################################################################
283
+ def parse_rule(rule)
284
+
285
+ m = {}
286
+ matches = /(?<epoch>[DWMYCmq])(?<num>[0-9]+)(?<pos>[XFMLW]?)(?<kfmw>[-!W\*]*)(?<trailing_rest>.*)/.match(rule)
287
+
288
+ if matches.present?
289
+ m.merge!(Hash[ matches.names.zip( matches.captures ) ])
290
+ m.merge!('killswitch' => m['kfmw'].match(/-/).to_s.presence)
291
+ m.merge!('force' => m['kfmw'].match(/!/).to_s.presence)
292
+ m.merge!('mockswitch' => m['kfmw'].match(/\*/).to_s.presence)
293
+ m.merge!('workingday' => m['kfmw'].match(/W/).to_s.presence)
294
+ end
295
+ m.compact
296
+ end #def
297
+
298
+ ####################################################################################
299
+ # parse_rule
300
+ ####################################################################################
301
+ def unmock( rule, m=nil )
302
+ m = parse_rule( rule ) unless m
303
+ if m['mockswitch'].present?
304
+ "#{m['epoch']}#{m['num']}#{m['pos']}#{m['killswitch']}#{m['force']}#{m['trailing_rest']}"
305
+ else
306
+ nil
307
+ end
308
+ end #def
309
+
310
+ end #class
311
+
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Ruby Gem to create a self populating Open Document Format (.odf) text file.
4
+ #
5
+ # Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
6
+ #
7
+ # This program is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU General Public License
9
+ # as published by the Free Software Foundation; either version 2
10
+ # of the License, or (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
+ #
21
+
22
+ module ODFWriter
23
+
24
+ ########################################################################################
25
+ #
26
+ # Bookmark: replace bookmarks with given name
27
+ #
28
+ ########################################################################################
29
+ class Bookmark < Field
30
+
31
+ ######################################################################################
32
+ #
33
+ # replace!
34
+ #
35
+ ######################################################################################
36
+ def replace!(doc, item = nil)
37
+
38
+ nodes = find_bookmark_nodes(doc)
39
+ return if nodes.blank?
40
+
41
+ text = value(item)
42
+ text = text.encode(universal_newline: true)
43
+
44
+ text_node_array = text.split(/\n/).map{|a| Nokogiri::XML::Text.new(a, doc) }
45
+ unless text_node_array.length == 1
46
+ text_node_array = text_node_array.inject([]) do |collector, node|
47
+ collector << Nokogiri::XML::Node.new("line-break", doc) unless collector.empty?
48
+ collector << node
49
+ end
50
+ end
51
+
52
+ nodes.each do |node|
53
+
54
+ case node.name
55
+
56
+ when "bookmark"
57
+ text_node_array.each {|tn| node.before(tn)}
58
+
59
+ #
60
+ # find bookmark
61
+ #
62
+ bm = "text:bookmark[@text:name='#{@name}']"
63
+ bmn = doc.xpath(".//.//*[self::#{bm}]")
64
+ #
65
+ # delete bookmark
66
+ #
67
+ bmn.each {|b| b.remove }
68
+
69
+ when "bookmark-start"
70
+ text_node_array.each {|tn| node.before(tn)}
71
+
72
+ #
73
+ # find bookmark-start
74
+ #
75
+ bms = "text:bookmark-start[@text:name='#{@name}']"
76
+ bmsn = doc.xpath(".//.//*[self::#{bms}]")
77
+ #
78
+ # find bookmark text
79
+ #
80
+ bme = "text:bookmark-end[@text:name='#{@name}']"
81
+ bmen = doc.xpath(".//.//*[self::#{bme}]")
82
+ #
83
+ # find bookmark-end
84
+ #
85
+ bmn = doc.xpath(".//text()[preceding-sibling::#{bms} and following-sibling::#{bme}]")
86
+ #
87
+ # delete bookmark -start, text and -end
88
+ #
89
+ bmn.each {|b| b.remove }
90
+ bmsn.each {|b| b.remove }
91
+ bmen.each {|b| b.remove }
92
+
93
+ end #case
94
+ end #each
95
+
96
+ end #def
97
+
98
+ ######################################################################################
99
+ #
100
+ # private
101
+ #
102
+ ######################################################################################
103
+ private
104
+
105
+ def find_bookmark_nodes(doc)
106
+ doc.xpath(".//*[self::text:bookmark[@text:name='#{@name}'] or self::text:bookmark-start[@text:name='#{@name}']]")
107
+ end #def
108
+
109
+ end #class
110
+ end #module