motiro 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. data/LICENSE +280 -0
  2. data/README +28 -0
  3. data/README.en +175 -0
  4. data/README.pt-br +175 -0
  5. data/Rakefile +10 -0
  6. data/app/controllers/account_controller.rb +62 -0
  7. data/app/controllers/application.rb +72 -0
  8. data/app/controllers/edition_controller.rb +13 -0
  9. data/app/controllers/javascript_controller.rb +21 -0
  10. data/app/controllers/report_controller.rb +79 -0
  11. data/app/controllers/root_controller.rb +7 -0
  12. data/app/controllers/wiki_controller.rb +102 -0
  13. data/app/core/cache_reporter.rb +53 -0
  14. data/app/core/cache_reporter_fetcher.rb +33 -0
  15. data/app/core/chief_editor.rb +69 -0
  16. data/app/core/reporter.rb +105 -0
  17. data/app/core/reporter_driver.rb +36 -0
  18. data/app/core/reporter_fetcher.rb +39 -0
  19. data/app/core/settings.rb +43 -0
  20. data/app/core/version.rb +1 -0
  21. data/app/core/wiki_page_not_found.rb +33 -0
  22. data/app/core/wiki_reporter.rb +83 -0
  23. data/app/helpers/account_helper.rb +2 -0
  24. data/app/helpers/application_helper.rb +68 -0
  25. data/app/helpers/default_page_provider.rb +28 -0
  26. data/app/helpers/report_helper.rb +2 -0
  27. data/app/helpers/root_helper.rb +2 -0
  28. data/app/helpers/wiki_helper.rb +3 -0
  29. data/app/models/change.rb +96 -0
  30. data/app/models/diff_table_builder.rb +285 -0
  31. data/app/models/event.rb +18 -0
  32. data/app/models/headline.rb +109 -0
  33. data/app/models/page.rb +114 -0
  34. data/app/models/page_sweeper.rb +26 -0
  35. data/app/models/user.rb +85 -0
  36. data/app/ports/chdir_runner.rb +36 -0
  37. data/app/ports/reporter_loader.rb +9 -0
  38. data/app/ports/runner.rb +64 -0
  39. data/app/reporters/darcs_connection.rb +54 -0
  40. data/app/reporters/darcs_reporter.rb +104 -0
  41. data/app/reporters/darcs_settings.rb +9 -0
  42. data/app/reporters/darcs_temp_repo.rb +40 -0
  43. data/app/reporters/events_reporter.rb +28 -0
  44. data/app/reporters/features_reporter.rb +24 -0
  45. data/app/reporters/subversion_reporter.rb +203 -0
  46. data/app/reporters/svn_connection.rb +62 -0
  47. data/app/reporters/svn_settings.rb +40 -0
  48. data/app/views/account/_authorization.rhtml +54 -0
  49. data/app/views/account/_availability.rhtml +5 -0
  50. data/app/views/account/availability.rhtml +1 -0
  51. data/app/views/account/login.rhtml +22 -0
  52. data/app/views/account/logout.rhtml +10 -0
  53. data/app/views/javascript/motiro.rjs +132 -0
  54. data/app/views/javascript/niftycube.rjs +300 -0
  55. data/app/views/layouts/_bottom.rhtml +5 -0
  56. data/app/views/layouts/_header.rhtml +7 -0
  57. data/app/views/layouts/_top.rhtml +25 -0
  58. data/app/views/layouts/application.rhtml +3 -0
  59. data/app/views/layouts/scaffold.rhtml +13 -0
  60. data/app/views/layouts/wiki_edit.rhtml +26 -0
  61. data/app/views/report/list.rhtml +32 -0
  62. data/app/views/report/older.rhtml +26 -0
  63. data/app/views/report/rss.rxml +29 -0
  64. data/app/views/report/show.rhtml +20 -0
  65. data/app/views/root/index.rhtml +33 -0
  66. data/app/views/wiki/_editbar.rhtml +26 -0
  67. data/app/views/wiki/_properties_edit.rhtml +5 -0
  68. data/app/views/wiki/_properties_show.rhtml +5 -0
  69. data/app/views/wiki/edit.rhtml +56 -0
  70. data/app/views/wiki/properties_edit.rhtml +1 -0
  71. data/app/views/wiki/show.rhtml +9 -0
  72. data/bin/motiro +44 -0
  73. data/config/boot.rb +19 -0
  74. data/config/database.yml +14 -0
  75. data/config/environment.rb +64 -0
  76. data/config/environments/development.rb +20 -0
  77. data/config/environments/production.rb +19 -0
  78. data/config/environments/test.rb +19 -0
  79. data/config/motiro.yml +43 -0
  80. data/config/routes.rb +79 -0
  81. data/db/migrate/005_globalize_migration.rb +11363 -0
  82. data/db/migrate/006_remove_headline_title.rb +14 -0
  83. data/db/migrate/007_stretch_rid.rb +11 -0
  84. data/db/migrate/008_add_page_editors.rb +12 -0
  85. data/db/migrate/009_add_page_original_author.rb +12 -0
  86. data/db/migrate/010_remove_empty_string_defaults_from_pages.rb +17 -0
  87. data/db/migrate/011_add_title_and_kind_to_pages.rb +13 -0
  88. data/db/migrate/012_page_modification_info.rb +13 -0
  89. data/db/migrate/013_nullify_initial_page_attributes.rb +21 -0
  90. data/db/migrate/014_events_are_wiki_pages.rb +13 -0
  91. data/db/migrate/015_migrate_previous_event_data.rb +23 -0
  92. data/db/migrate/1_initial_structure.rb +36 -0
  93. data/db/migrate/2_add_authentication.rb +12 -0
  94. data/db/migrate/3_drop_articles.rb +26 -0
  95. data/db/migrate/4_add_page_editing.rb +14 -0
  96. data/db/motirodb.sqlite.initial +0 -0
  97. data/db/schema_version +1 -0
  98. data/db/translation/pt-BR.rb +76 -0
  99. data/doc/README_FOR_APP +2 -0
  100. data/installer/rails_installer_defaults.yml +5 -0
  101. data/lib/import_translations.rb +154 -0
  102. data/lib/login_system.rb +89 -0
  103. data/lib/relative_time.rb +48 -0
  104. data/lib/string_extensions.rb +10 -0
  105. data/lib/stub_hash.rb +22 -0
  106. data/lib/tasks/packaging.rake +93 -0
  107. data/lib/tasks/testing.rake +32 -0
  108. data/lib/tick_daemon.rb +41 -0
  109. data/lib/translator.rb +67 -0
  110. data/lib/wiki_renderer.rb +42 -0
  111. data/lib/wiki_url_generator.rb +29 -0
  112. data/log/.keepdir +0 -0
  113. data/public/404.html +8 -0
  114. data/public/500.html +8 -0
  115. data/public/dispatch.cgi +10 -0
  116. data/public/dispatch.fcgi +24 -0
  117. data/public/dispatch.rb +10 -0
  118. data/public/favicon.ico +0 -0
  119. data/public/images/calendar.png +0 -0
  120. data/public/images/rss.png +0 -0
  121. data/public/javascripts/controls.js +750 -0
  122. data/public/javascripts/dragdrop.js +584 -0
  123. data/public/javascripts/effects.js +854 -0
  124. data/public/javascripts/prototype.js +1785 -0
  125. data/public/robots.txt +1 -0
  126. data/public/stylesheets/motiro.css +269 -0
  127. data/public/stylesheets/niftyCorners.css +35 -0
  128. data/public/stylesheets/scaffold.css +74 -0
  129. data/script/about +3 -0
  130. data/script/breakpointer +3 -0
  131. data/script/console +3 -0
  132. data/script/destroy +3 -0
  133. data/script/generate +3 -0
  134. data/script/performance/benchmarker +3 -0
  135. data/script/performance/profiler +3 -0
  136. data/script/plugin +3 -0
  137. data/script/process/reaper +3 -0
  138. data/script/process/spawner +3 -0
  139. data/script/process/spinner +3 -0
  140. data/script/runner +3 -0
  141. data/script/server +3 -0
  142. data/script/ticker +29 -0
  143. data/test/acceptance/account_test.rb +186 -0
  144. data/test/acceptance/darcs_test.rb +62 -0
  145. data/test/acceptance/events_test.rb +47 -0
  146. data/test/acceptance/main_page_test.rb +92 -0
  147. data/test/acceptance/subversion_test.rb +319 -0
  148. data/test/acceptance/ts_all_suites.rb +27 -0
  149. data/test/acceptance/wiki_test.rb +202 -0
  150. data/test/contract/darcs_test.rb +51 -0
  151. data/test/contract/remote_darcs_test.rb +61 -0
  152. data/test/contract/svn_test.rb +53 -0
  153. data/test/fixtures/changes.yml +25 -0
  154. data/test/fixtures/headlines.yml +45 -0
  155. data/test/fixtures/pages.yml +98 -0
  156. data/test/fixtures/users.yml +31 -0
  157. data/test/functional/account_controller_test.rb +96 -0
  158. data/test/functional/report_controller_test.rb +113 -0
  159. data/test/functional/report_features_test.rb +38 -0
  160. data/test/functional/report_subversion_test.rb +79 -0
  161. data/test/functional/root_controller_test.rb +127 -0
  162. data/test/functional/wiki_controller_test.rb +280 -0
  163. data/test/lib/acceptance_test_case.rb +43 -0
  164. data/test/lib/configuration.rb +53 -0
  165. data/test/lib/darcs_excerpts.rb +181 -0
  166. data/test/lib/darcs_repo.rb +77 -0
  167. data/test/lib/live_mode_test.rb +51 -0
  168. data/test/lib/local_svn.rb +157 -0
  169. data/test/lib/netutils.rb +42 -0
  170. data/test/lib/platform_thread.rb +62 -0
  171. data/test/lib/repoutils.rb +23 -0
  172. data/test/lib/selenium_extensions.rb +32 -0
  173. data/test/lib/stubio.rb +37 -0
  174. data/test/lib/svn_excerpts.rb +288 -0
  175. data/test/lib/test_configuration.rb +14 -0
  176. data/test/lib/webserver.rb +71 -0
  177. data/test/meta/configuration_test.rb +72 -0
  178. data/test/meta/darcs_repo_test.rb +118 -0
  179. data/test/meta/local_svn_test.rb +125 -0
  180. data/test/meta/platform_thread_test.rb +46 -0
  181. data/test/meta/stubio_test.rb +44 -0
  182. data/test/mocks/headline.rb +34 -0
  183. data/test/mocks/svn_reporter.rb +29 -0
  184. data/test/stubs/svn_settings.rb +19 -0
  185. data/test/stubs/url_generator.rb +24 -0
  186. data/test/test_helper.rb +36 -0
  187. data/test/unit/cache_reporter_fetcher_test.rb +46 -0
  188. data/test/unit/cache_reporter_test.rb +97 -0
  189. data/test/unit/caching_test.rb +78 -0
  190. data/test/unit/change_test.rb +152 -0
  191. data/test/unit/chdir_runner_test.rb +77 -0
  192. data/test/unit/chief_editor_test.rb +234 -0
  193. data/test/unit/darcs_connection_test.rb +109 -0
  194. data/test/unit/darcs_reporter_test.rb +146 -0
  195. data/test/unit/darcs_settings_test.rb +37 -0
  196. data/test/unit/darcs_temp_repo_test.rb +51 -0
  197. data/test/unit/default_page_provider_test.rb +46 -0
  198. data/test/unit/diff_table_builder_test.rb +602 -0
  199. data/test/unit/headline_test.rb +259 -0
  200. data/test/unit/page_test.rb +145 -0
  201. data/test/unit/relative_time_test.rb +56 -0
  202. data/test/unit/reporter_driver_test.rb +85 -0
  203. data/test/unit/reporter_fetcher_test.rb +31 -0
  204. data/test/unit/reporter_test.rb +81 -0
  205. data/test/unit/runner_test.rb +93 -0
  206. data/test/unit/settings_test.rb +55 -0
  207. data/test/unit/string_extensions_test.rb +10 -0
  208. data/test/unit/svn_connection_test.rb +183 -0
  209. data/test/unit/svn_reporter_interaction_test.rb +38 -0
  210. data/test/unit/svn_reporter_test.rb +286 -0
  211. data/test/unit/svn_settings_test.rb +86 -0
  212. data/test/unit/translator_test.rb +96 -0
  213. data/test/unit/user_test.rb +125 -0
  214. data/test/unit/wiki_renderer_test.rb +87 -0
  215. data/test/unit/wiki_reporter_test.rb +94 -0
  216. data/test/unit/wiki_url_generator_test.rb +31 -0
  217. data/vendor/motiro-installer.rb +159 -0
  218. data/vendor/plugins/globalize/LICENSE +9 -0
  219. data/vendor/plugins/globalize/README +49 -0
  220. data/vendor/plugins/globalize/data/country_data.csv +240 -0
  221. data/vendor/plugins/globalize/data/language_data.csv +188 -0
  222. data/vendor/plugins/globalize/data/translation_data.csv +3421 -0
  223. data/vendor/plugins/globalize/generators/globalize/USAGE +10 -0
  224. data/vendor/plugins/globalize/generators/globalize/globalize_generator.rb +42 -0
  225. data/vendor/plugins/globalize/generators/globalize/templates/migration.rb.gz +0 -0
  226. data/vendor/plugins/globalize/generators/globalize/templates/tiny_migration.rb.gz +0 -0
  227. data/vendor/plugins/globalize/init.rb +30 -0
  228. data/vendor/plugins/globalize/lib/globalize/localization/core_ext.rb +170 -0
  229. data/vendor/plugins/globalize/lib/globalize/localization/core_ext_hooks.rb +33 -0
  230. data/vendor/plugins/globalize/lib/globalize/localization/db_translate.rb +494 -0
  231. data/vendor/plugins/globalize/lib/globalize/localization/db_view_translator.rb +152 -0
  232. data/vendor/plugins/globalize/lib/globalize/localization/locale.rb +173 -0
  233. data/vendor/plugins/globalize/lib/globalize/localization/rfc_3066.rb +40 -0
  234. data/vendor/plugins/globalize/lib/globalize/models/country.rb +24 -0
  235. data/vendor/plugins/globalize/lib/globalize/models/currency.rb +188 -0
  236. data/vendor/plugins/globalize/lib/globalize/models/language.rb +84 -0
  237. data/vendor/plugins/globalize/lib/globalize/models/model_translation.rb +4 -0
  238. data/vendor/plugins/globalize/lib/globalize/models/translation.rb +9 -0
  239. data/vendor/plugins/globalize/lib/globalize/models/view_translation.rb +14 -0
  240. data/vendor/plugins/globalize/lib/globalize/rails/action_mailer.rb +125 -0
  241. data/vendor/plugins/globalize/lib/globalize/rails/action_view.rb +79 -0
  242. data/vendor/plugins/globalize/lib/globalize/rails/active_record.rb +129 -0
  243. data/vendor/plugins/globalize/lib/globalize/rails/active_record_helper.rb +33 -0
  244. data/vendor/plugins/globalize/populators/pop_dates.rb +81 -0
  245. data/vendor/plugins/globalize/populators/pop_migration.rb +18 -0
  246. data/vendor/plugins/globalize/populators/pop_pluralization.rb +26 -0
  247. data/vendor/plugins/globalize/populators/pop_seps.rb +32 -0
  248. data/vendor/plugins/globalize/tasks/data.rake +130 -0
  249. data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.en-US.plain.text.rhtml +1 -0
  250. data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.en.plain.text.rhtml +1 -0
  251. data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.he.plain.text.rhtml +1 -0
  252. data/vendor/plugins/globalize/test/action_mailer_test/globalize_mailer/test.plain.text.rhtml +1 -0
  253. data/vendor/plugins/globalize/test/action_mailer_test.rb +54 -0
  254. data/vendor/plugins/globalize/test/config/database.yml.default +16 -0
  255. data/vendor/plugins/globalize/test/config/database.yml.example +22 -0
  256. data/vendor/plugins/globalize/test/core_ext_test.rb +61 -0
  257. data/vendor/plugins/globalize/test/currency_test.rb +141 -0
  258. data/vendor/plugins/globalize/test/date_helper_test.rb +634 -0
  259. data/vendor/plugins/globalize/test/db/schema.rb +90 -0
  260. data/vendor/plugins/globalize/test/db_translation_test.rb +374 -0
  261. data/vendor/plugins/globalize/test/fixtures/globalize_categories.yml +7 -0
  262. data/vendor/plugins/globalize/test/fixtures/globalize_categories_products.yml +7 -0
  263. data/vendor/plugins/globalize/test/fixtures/globalize_countries.yml +41 -0
  264. data/vendor/plugins/globalize/test/fixtures/globalize_languages.yml +64 -0
  265. data/vendor/plugins/globalize/test/fixtures/globalize_manufacturers.yml +5 -0
  266. data/vendor/plugins/globalize/test/fixtures/globalize_products.yml +29 -0
  267. data/vendor/plugins/globalize/test/fixtures/globalize_simples.yml +5 -0
  268. data/vendor/plugins/globalize/test/fixtures/globalize_translations.yml +354 -0
  269. data/vendor/plugins/globalize/test/locale_test.rb +27 -0
  270. data/vendor/plugins/globalize/test/mime_responds_test.rb +358 -0
  271. data/vendor/plugins/globalize/test/model_test.rb +17 -0
  272. data/vendor/plugins/globalize/test/standard_data_test_helper.rb +33 -0
  273. data/vendor/plugins/globalize/test/test_helper.rb +19 -0
  274. data/vendor/plugins/globalize/test/test_standard_data.rb +54 -0
  275. data/vendor/plugins/globalize/test/validation_test.rb +29 -0
  276. data/vendor/plugins/globalize/test/view_picking_test.rb +49 -0
  277. data/vendor/plugins/globalize/test/view_translation_test.rb +237 -0
  278. data/vendor/plugins/globalize/test/views/layouts/standard.rhtml +1 -0
  279. data/vendor/plugins/globalize/test/views/respond_to/all_types_with_layout.rhtml +1 -0
  280. data/vendor/plugins/globalize/test/views/respond_to/all_types_with_layout.rjs +1 -0
  281. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rhtml +1 -0
  282. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rjs +1 -0
  283. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.en.rxml +1 -0
  284. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rhtml +1 -0
  285. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rjs +1 -0
  286. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.fr.rxml +1 -0
  287. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rhtml +1 -0
  288. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rjs +1 -0
  289. data/vendor/plugins/globalize/test/views/respond_to/using_defaults.rxml +1 -0
  290. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rhtml +1 -0
  291. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rjs +1 -0
  292. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.en.rxml +1 -0
  293. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rhtml +1 -0
  294. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rjs +1 -0
  295. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.fr.rxml +1 -0
  296. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rhtml +1 -0
  297. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rjs +1 -0
  298. data/vendor/plugins/globalize/test/views/respond_to/using_defaults_with_type_list.rxml +1 -0
  299. data/vendor/plugins/globalize/test/views/test.he-IL.rhtml +1 -0
  300. data/vendor/plugins/globalize/test/views/test.rhtml +1 -0
  301. data/vendor/plugins/globalize/test/views/test2.he.rhtml +1 -0
  302. data/vendor/plugins/globalize/test/views/test2.rhtml +1 -0
  303. data/vendor/plugins/test_xml/MIT-LICENSE +20 -0
  304. data/vendor/plugins/test_xml/README +20 -0
  305. data/vendor/plugins/test_xml/Rakefile +22 -0
  306. data/vendor/plugins/test_xml/init.rb +7 -0
  307. data/vendor/plugins/test_xml/lib/xml_assertions.rb +22 -0
  308. data/vendor/plugins/test_xml/test/test_xml_test.rb +40 -0
  309. metadata +505 -0
@@ -0,0 +1,18 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ class Event < Page; end
@@ -0,0 +1,109 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ class Headline < ActiveRecord::Base
19
+
20
+ has_many :changes, :dependent => :destroy
21
+
22
+ def initialize(params={})
23
+ params[:description] ||= ''
24
+ if !params[:title].nil? then
25
+ params[:description] = params[:title] + "\n\n" + params[:description]
26
+ params.delete :title
27
+ end
28
+ super(params)
29
+ end
30
+
31
+ def self.latest(num, reporter)
32
+ find(:all,
33
+ :conditions => ["reported_by = ?", reporter],
34
+ :order => 'happened_at DESC',
35
+ :limit => num)
36
+ end
37
+
38
+ def self.latest_filled_headline_rid_for(reporter)
39
+ hls = find(:all, :conditions => ["reported_by = ?", reporter],
40
+ :order => 'happened_at DESC')
41
+ hls.each do |hl|
42
+ return hl.rid if hl.filled?
43
+ end
44
+
45
+ nil
46
+ end
47
+
48
+ def self.find_with_reporter_and_rid(reporter_name, rid)
49
+ find(:first,
50
+ :conditions => ["reported_by = ? and rid = ?",
51
+ reporter_name, rid])
52
+ end
53
+
54
+ def happened_at=(date_components)
55
+ if date_components.is_a? Time
56
+ self[:happened_at] = date_components
57
+ else
58
+ year, month, day, hour, min, sec = date_components
59
+ self[:happened_at] = Time.local(year, month, day, hour, min, sec)
60
+ end
61
+ end
62
+
63
+ def title(translator=Translator.default)
64
+ answer = description(translator).
65
+ split($/).
66
+ first || ''
67
+ answer.strip
68
+ end
69
+
70
+ def description(translator=Translator.default)
71
+ translator.localize(self[:description])
72
+ end
73
+
74
+ # Saves the headline locally, if it isn't already cached
75
+ def cache
76
+ unless self.cached?
77
+ self.class.destroy_all similar_to_self
78
+ self.save
79
+ end
80
+ end
81
+
82
+ def cached?
83
+ cached_lines = Headline.find(:all, :conditions => similar_to_self)
84
+
85
+ return false if cached_lines.empty?
86
+
87
+ cached_lines.each do |hl|
88
+ return true if hl.filled?
89
+ end
90
+
91
+ return false
92
+ end
93
+
94
+ def filled?
95
+ self.changes.each do |c|
96
+ return false if !c.filled?
97
+ end
98
+
99
+ return true
100
+ end
101
+
102
+ private
103
+
104
+ def similar_to_self
105
+ ["author = ? and description = ? and happened_at =?",
106
+ self[:author], self[:description], self[:happened_at]]
107
+ end
108
+
109
+ end
@@ -0,0 +1,114 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ PLACE_HOLDER_TITLE = 'Insert page title here'
19
+
20
+ class Page < ActiveRecord::Base
21
+
22
+ belongs_to :last_editor, :class_name => 'User',
23
+ :foreign_key => 'last_editor_id'
24
+ belongs_to :original_author, :class_name => 'User',
25
+ :foreign_key => 'original_author_id'
26
+
27
+ def after_initialize
28
+ default('', :editors, :text, :name, :title)
29
+ default('common', :kind)
30
+ end
31
+
32
+ def default(value, *attrs)
33
+ attrs.each do |attr|
34
+ cur = send(attr)
35
+ send("#{attr}=".to_sym, value) if cur.nil? || cur.empty?
36
+ end
37
+ end
38
+
39
+ def before_save
40
+ if title == PLACE_HOLDER_TITLE.t
41
+ write_attribute(:title, title_from_kind)
42
+ end
43
+
44
+ write_attribute(:name, self.name)
45
+ end
46
+
47
+ def name; name_before_type_cast; end
48
+ def name_before_type_cast
49
+ result = read_attribute(:name)
50
+ return name_from_title if result.nil? || result.empty?
51
+ return result
52
+ end
53
+
54
+ def title; title_before_type_cast; end
55
+ def title_before_type_cast
56
+ result = read_attribute(:title)
57
+ return title_from_name || PLACE_HOLDER_TITLE.t if result.nil? || result.empty?
58
+ return result
59
+ end
60
+
61
+ def use_parser(parser)
62
+ @parser = parser
63
+ end
64
+
65
+ def is_open_to_all?
66
+ 0 == editors.strip.size
67
+ end
68
+
69
+ private
70
+
71
+ def name_from_title
72
+ sequence(drop_non_alpha(clean(title)).downcase.gsub(/ /, '_').camelize, 'name')
73
+ end
74
+
75
+ def title_from_kind
76
+ sequence(kind.capitalize + ' page ', 'title')
77
+ end
78
+
79
+ def title_from_name
80
+ name = read_attribute(:name)
81
+ name = nil if name.nil? || name.empty?
82
+ name && name.underscore.gsub(/_/, ' ').capitalize
83
+ end
84
+
85
+ def sequence(target, attr)
86
+ result = target.strip
87
+ suffix = 2
88
+ while self.class.find(:first, :conditions => "#{attr} = '#{result}'")
89
+ result = target + suffix.to_s
90
+ suffix += 1
91
+ end
92
+ return result
93
+ end
94
+
95
+ def renderer
96
+ @renderer ||= WikiRenderer.new
97
+ end
98
+
99
+ def my_parser
100
+ @parser ||= WikiParser.new
101
+ end
102
+
103
+ private
104
+
105
+ def clean(text)
106
+ text.tr('ãàáâäÃÀÁÂÄèéêëÈÉÊËĩìíîïĨÌÍÎÏÿýÝŸõòóôöÕÒÓÔÖũùúûüŨÙÚÛÜñńÑŃćçÇĆśŕ埌ŔĹŹ',
107
+ 'aaaaaAAAAAeeeeEEEEiiiiiIIIIIyyYYoooooOOOOOuuuuuUUUUUnnNNccCCsrlzSRLZ')
108
+ end
109
+
110
+ def drop_non_alpha(text)
111
+ text.gsub(%r{[^a-zA-Z0-9]}, ' ').gsub(%r{\s+}, ' ')
112
+ end
113
+
114
+ end
@@ -0,0 +1,26 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ class PageSweeper < ActionController::Caching::Sweeper
19
+
20
+ observe Page
21
+
22
+ def after_save(page)
23
+ expire_fragment(/wiki\/show.*?#{page.name}/)
24
+ end
25
+
26
+ end
@@ -0,0 +1,85 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'digest/sha1'
19
+
20
+ # this model expects a certain database layout and its based on the name/login pattern.
21
+ class User < ActiveRecord::Base
22
+
23
+ # Please change the salt to something else,
24
+ # Every application should use a different one
25
+ @@salt = 'motiro'
26
+ cattr_accessor :salt
27
+
28
+ # Authenticate a user.
29
+ #
30
+ # Example:
31
+ # @user = User.authenticate('bob', 'bobpass')
32
+ #
33
+ def self.authenticate(login, pass)
34
+ find(:first, :conditions => ["login = ? AND password = ?", login, sha1(pass)])
35
+ end
36
+
37
+ def can_edit?(page)
38
+ self == page.original_author ||
39
+ page.is_open_to_all? ||
40
+ page.editors.split.include?(login)
41
+ end
42
+
43
+ def can_change_editors?(page)
44
+ page.original_author.nil? || self == page.original_author
45
+ end
46
+
47
+ protected
48
+
49
+ # Apply SHA1 encryption to the supplied password.
50
+ # We will additionally surround the password with a salt
51
+ # for additional security.
52
+ def self.sha1(pass)
53
+ Digest::SHA1.hexdigest("#{salt}--#{pass}--")
54
+ end
55
+
56
+ before_create :crypt_password
57
+
58
+ # Before saving the record to database we will crypt the password
59
+ # using SHA1.
60
+ # We never store the actual password in the DB.
61
+ def crypt_password
62
+ write_attribute "password", self.class.sha1(password)
63
+ end
64
+
65
+ before_update :crypt_unless_empty
66
+
67
+ # If the record is updated we will check if the password is empty.
68
+ # If its empty we assume that the user didn't want to change his
69
+ # password and just reset it to the old value.
70
+ def crypt_unless_empty
71
+ if password.empty?
72
+ user = self.class.find(self.id)
73
+ self.password = user.password
74
+ else
75
+ write_attribute "password", self.class.sha1(password)
76
+ end
77
+ end
78
+
79
+ validates_uniqueness_of :login, :on => :create
80
+
81
+ validates_confirmation_of :password, :on => :create
82
+ validates_length_of :login, :within => 3..40
83
+ validates_length_of :password, :within => 5..40
84
+ validates_presence_of :login, :password, :password_confirmation
85
+ end
@@ -0,0 +1,36 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'ports/runner'
19
+
20
+ class ChdirRunner
21
+
22
+ def initialize(dir, runner=Runner.new)
23
+ @dir, @runner = dir, runner
24
+ end
25
+
26
+ def run(command, input='', env={})
27
+ prevdir = Dir.pwd
28
+ begin
29
+ Dir.chdir(@dir)
30
+ @runner.run(command, input, env)
31
+ ensure
32
+ Dir.chdir(prevdir)
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,9 @@
1
+ # Loads a reporter from the local filesystem
2
+ class ReporterLoader
3
+
4
+ def create_reporter(reporter_id)
5
+ require "reporters/#{reporter_id}_reporter"
6
+ eval "#{reporter_id.camelize}Reporter.new"
7
+ end
8
+
9
+ end
@@ -0,0 +1,64 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ class Runner
19
+
20
+ def initialize(process_creator=IO)
21
+ @creator = process_creator
22
+ end
23
+
24
+ def run(command, input='', env={})
25
+ commons = {}
26
+ env.each_key do |k|
27
+ commons[k] = ENV[k] if ENV.has_key?(k)
28
+ end
29
+ ENV.update env
30
+
31
+ process = @creator.popen(command, 'r+')
32
+ begin
33
+ process << input
34
+ process.flush
35
+ rescue
36
+ #ignore i/o errors
37
+ end
38
+
39
+ env.each_key do |k|
40
+ ENV.delete k
41
+ end
42
+ commons.each do |k, v|
43
+ ENV[k] = v
44
+ end
45
+
46
+ result = process.read
47
+ process.close
48
+
49
+ return result
50
+ end
51
+
52
+ end
53
+
54
+ class FixedParameterRunner
55
+
56
+ def initialize(underlying_runner, input, env)
57
+ @runner, @input, @env = underlying_runner, input, env
58
+ end
59
+
60
+ def run(command)
61
+ @runner.run(command, @input, @env)
62
+ end
63
+
64
+ end
@@ -0,0 +1,54 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'stringio'
19
+
20
+ require 'ports/runner'
21
+ require 'ports/chdir_runner'
22
+
23
+ require 'reporters/darcs_settings'
24
+ require 'reporters/darcs_temp_repo'
25
+
26
+ class DarcsConnection
27
+
28
+ def initialize(settings=DarcsSettingsProvider.new,
29
+ runner=Runner.new,
30
+ temp_repo = DarcsTempRepo.new)
31
+ @settings = settings
32
+ @runner = ChdirRunner.new(temp_repo.path, runner)
33
+ end
34
+
35
+ def changes(options=nil)
36
+ command = 'darcs changes --xml'
37
+ if options.nil?
38
+ command += " --last=#{@settings.package_size}"
39
+ elsif :all != options
40
+ command += " --from-match=\"hash #{options}\"" +
41
+ " --to-match=\"hash #{options}\""
42
+ end
43
+ @runner.run(command)
44
+ end
45
+
46
+ def pull
47
+ @runner.run("darcs pull -a #{@settings.repo_url}")
48
+ end
49
+
50
+ def diff(patch_hash)
51
+ @runner.run("darcs diff -u --match \"hash #{patch_hash}\"")
52
+ end
53
+
54
+ end
@@ -0,0 +1,104 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'rexml/rexml'
19
+
20
+ require 'models/headline'
21
+ require 'core/reporter'
22
+ require 'reporters/darcs_connection'
23
+
24
+ class DarcsReporter < MotiroReporter
25
+
26
+ def initialize(conn=DarcsConnection.new)
27
+ @connection = conn
28
+ end
29
+
30
+ def latest_headlines
31
+ @connection.pull
32
+ parse_headlines(@connection.changes)
33
+ end
34
+
35
+ def headlines
36
+ parse_headlines(@connection.changes(:all))
37
+ end
38
+
39
+ def headline(rid)
40
+ parse_headlines(@connection.changes(rid)).first
41
+ end
42
+
43
+ def author_from_darcs_id(id)
44
+ md = id.match(/@/)
45
+ return md.pre_match if md
46
+ end
47
+
48
+ def time_from_darcs_date(date)
49
+ md = date.match(/(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/)
50
+ nums = md[1..6].collect do |s| s.to_i end
51
+ Time.utc(nums[0], nums[1], nums[2], nums[3], nums[4], nums[5], nums[6])
52
+ end
53
+
54
+ private
55
+
56
+ def parse_headlines(xml_input)
57
+ patches = REXML::Document.new(xml_input).root.elements || []
58
+ patches.collect do |patch_info|
59
+ parse_headline(patch_info)
60
+ end
61
+ end
62
+
63
+ def parse_headline(info)
64
+ headline = Headline.new
65
+ headline.author = author_from_darcs_id(info.attributes['author'])
66
+
67
+ name = info.elements['name'].text
68
+ comments = info.elements['comment']
69
+ description = if name.strip.empty? then 'Untitled patch'; else name; end
70
+ description += "\n" + comments.text if comments
71
+
72
+ headline.description = description
73
+ headline.happened_at = time_from_darcs_date(info.attributes['date'])
74
+ headline.rid = info.attributes['hash']
75
+ headline.reported_by = self.name
76
+
77
+ parse_changes(headline, @connection.diff(headline.rid))
78
+
79
+ return headline
80
+ end
81
+
82
+ def parse_changes(headline, diffs)
83
+ remain = diffs
84
+
85
+ while(md = remain.match(/^diff[^\n]*\n--- old-[^\/]*\/([^\t]*)/))
86
+ remain, diff = extract_diff(md.post_match)
87
+ headline.changes.push Change.new(:summary => md[1],
88
+ :diff => diff)
89
+ end
90
+ end
91
+
92
+ def extract_diff(text)
93
+ md = text.match(/^\+\+\+ [^\n]*\n/)
94
+
95
+ remain, diff = '', md.post_match
96
+
97
+ if (md = diff.match(/^diff/))
98
+ remain, diff = md[0] + md.post_match, md.pre_match
99
+ end
100
+
101
+ return remain, diff
102
+ end
103
+
104
+ end
@@ -0,0 +1,9 @@
1
+ require 'core/settings'
2
+
3
+ class DarcsSettingsProvider < SettingsProvider
4
+
5
+ def repo_url
6
+ load_confs['darcs']['repo']
7
+ end
8
+
9
+ end
@@ -0,0 +1,40 @@
1
+ # Motiro - A project tracking tool
2
+ # Copyright (C) 2006-2007 Thiago Arrais
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # 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 St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'fileutils'
19
+ require 'ports/chdir_runner'
20
+
21
+ # This class is part of a workaround for darcs bug #250
22
+ # Darcs somehow needs to have a local repo to retrieve the changelog from a
23
+ # repo behind an HTTP server
24
+ #
25
+ # For more details see http://bugs.darcs.net/issue250
26
+ class DarcsTempRepo
27
+
28
+ @@path = File.expand_path(__FILE__ + '../../../../tmp/tmprepo')
29
+
30
+ def initialize(filesystem=File, fileutils=FileUtils,
31
+ runner=ChdirRunner.new(@@path))
32
+ unless filesystem.exists?(path + '/_darcs')
33
+ fileutils.mkdir_p(path)
34
+ runner.run("darcs init")
35
+ end
36
+ end
37
+
38
+ def path; @@path; end
39
+
40
+ end