open_porch 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (223) hide show
  1. data/Gemfile +41 -0
  2. data/Gemfile.lock +130 -0
  3. data/README.md +170 -0
  4. data/Rakefile +19 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/areas/base_controller.rb +11 -0
  7. data/app/controllers/admin/areas/issues_controller.rb +67 -0
  8. data/app/controllers/admin/areas/memberships_controller.rb +7 -0
  9. data/app/controllers/admin/areas/posts_controller.rb +44 -0
  10. data/app/controllers/admin/areas_controller.rb +89 -0
  11. data/app/controllers/admin/base_controller.rb +16 -0
  12. data/app/controllers/admin/user_activity_controller.rb +29 -0
  13. data/app/controllers/admin/users_controller.rb +57 -0
  14. data/app/controllers/application_controller.rb +15 -0
  15. data/app/controllers/areas/base_controller.rb +25 -0
  16. data/app/controllers/areas/issues_controller.rb +35 -0
  17. data/app/controllers/areas/posts_controller.rb +28 -0
  18. data/app/controllers/areas_controller.rb +30 -0
  19. data/app/controllers/passwords_controller.rb +42 -0
  20. data/app/controllers/registrations_controller.rb +42 -0
  21. data/app/controllers/sessions_controller.rb +33 -0
  22. data/app/controllers/users_controller.rb +77 -0
  23. data/app/helpers/open_porch_helper.rb +24 -0
  24. data/app/mailers/user_mailer.rb +35 -0
  25. data/app/models/address.rb +57 -0
  26. data/app/models/area.rb +171 -0
  27. data/app/models/area_activity.rb +24 -0
  28. data/app/models/email_message.rb +104 -0
  29. data/app/models/issue.rb +66 -0
  30. data/app/models/issue_number.rb +22 -0
  31. data/app/models/membership.rb +27 -0
  32. data/app/models/post.rb +64 -0
  33. data/app/models/session_user.rb +69 -0
  34. data/app/models/user.rb +140 -0
  35. data/app/models/user_activity.rb +31 -0
  36. data/app/models/user_authority_check.rb +14 -0
  37. data/app/views/admin/areas/_form.html.haml +8 -0
  38. data/app/views/admin/areas/_nav.html.haml +12 -0
  39. data/app/views/admin/areas/edit.html.haml +22 -0
  40. data/app/views/admin/areas/edit_borders.html.haml +44 -0
  41. data/app/views/admin/areas/index.html.haml +61 -0
  42. data/app/views/admin/areas/issues/_post.html.haml +15 -0
  43. data/app/views/admin/areas/issues/add_posts.js.rjs +3 -0
  44. data/app/views/admin/areas/issues/edit.html.haml +37 -0
  45. data/app/views/admin/areas/issues/index.html.haml +31 -0
  46. data/app/views/admin/areas/issues/remove_posts.js.rjs +3 -0
  47. data/app/views/admin/areas/issues/show.html.haml +13 -0
  48. data/app/views/admin/areas/memberships/index.html.haml +17 -0
  49. data/app/views/admin/areas/new.html.haml +6 -0
  50. data/app/views/admin/areas/new.js.haml +4 -0
  51. data/app/views/admin/areas/posts/_edit.html.haml +6 -0
  52. data/app/views/admin/areas/posts/_post_status.html.haml +1 -0
  53. data/app/views/admin/areas/posts/destroy.js.rjs +1 -0
  54. data/app/views/admin/areas/posts/edit.js.rjs +1 -0
  55. data/app/views/admin/areas/posts/show.js.rjs +1 -0
  56. data/app/views/admin/areas/posts/toggle_reviewed_by.js.rjs +1 -0
  57. data/app/views/admin/areas/posts/update.js.rjs +5 -0
  58. data/app/views/admin/areas/show.html.haml +5 -0
  59. data/app/views/admin/user_activity/show.html.haml +5 -0
  60. data/app/views/admin/users/_form.html.haml +21 -0
  61. data/app/views/admin/users/edit.html.haml +5 -0
  62. data/app/views/admin/users/index.html.haml +31 -0
  63. data/app/views/admin/users/new.html.haml +5 -0
  64. data/app/views/areas/issues/index.html.haml +31 -0
  65. data/app/views/areas/issues/show.html.haml +22 -0
  66. data/app/views/areas/posts/_post.html.haml +8 -0
  67. data/app/views/areas/posts/_posts_search_form.html.haml +8 -0
  68. data/app/views/areas/posts/index.html.haml +27 -0
  69. data/app/views/areas/posts/new.html.haml +10 -0
  70. data/app/views/areas/show.html.haml +47 -0
  71. data/app/views/layouts/_account_nav.html.haml +18 -0
  72. data/app/views/layouts/_flash_message.html.haml +4 -0
  73. data/app/views/layouts/_footer.html.haml +9 -0
  74. data/app/views/layouts/_head.html.haml +16 -0
  75. data/app/views/layouts/admin/_nav.html.haml +13 -0
  76. data/app/views/layouts/admin.html.haml +15 -0
  77. data/app/views/layouts/application.html.haml +14 -0
  78. data/app/views/layouts/area_editor.html.haml +11 -0
  79. data/app/views/passwords/edit.html.haml +9 -0
  80. data/app/views/passwords/new.html.haml +13 -0
  81. data/app/views/registrations/_address_form.html.haml +7 -0
  82. data/app/views/registrations/create.html.haml +49 -0
  83. data/app/views/registrations/index.html.haml +30 -0
  84. data/app/views/registrations/new.html.haml +17 -0
  85. data/app/views/sessions/new.html.haml +18 -0
  86. data/app/views/stylesheets/common.sass +239 -0
  87. data/app/views/stylesheets/content.sass +193 -0
  88. data/app/views/stylesheets/reset.sass +46 -0
  89. data/app/views/stylesheets/structure.sass +11 -0
  90. data/app/views/stylesheets/typography.sass +57 -0
  91. data/app/views/user_mailer/email_verification.html.erb +5 -0
  92. data/app/views/user_mailer/email_verification.text.erb +7 -0
  93. data/app/views/user_mailer/new_issue.html.erb +32 -0
  94. data/app/views/user_mailer/new_issue.text.erb +26 -0
  95. data/app/views/user_mailer/password_reset.html.erb +7 -0
  96. data/app/views/user_mailer/password_reset.text.erb +6 -0
  97. data/app/views/users/_form.html.haml +5 -0
  98. data/app/views/users/edit.html.haml +11 -0
  99. data/app/views/users/new.html.haml +41 -0
  100. data/app/views/users/show.html.haml +30 -0
  101. data/bin/open_porch_engine +135 -0
  102. data/config/application.rb +43 -0
  103. data/config/boot.rb +13 -0
  104. data/config/database_example.yml +59 -0
  105. data/config/environment.rb +5 -0
  106. data/config/environments/development.rb +26 -0
  107. data/config/environments/production.rb +49 -0
  108. data/config/environments/test.rb +35 -0
  109. data/config/initializers/backtrace_silencers.rb +7 -0
  110. data/config/initializers/email_regex.rb +38 -0
  111. data/config/initializers/geokit_config.rb +61 -0
  112. data/config/initializers/inflections.rb +20 -0
  113. data/config/initializers/meta_search.rb +7 -0
  114. data/config/initializers/mime_types.rb +5 -0
  115. data/config/initializers/open_porch.rb +41 -0
  116. data/config/initializers/sass.rb +1 -0
  117. data/config/initializers/secret_token.rb +7 -0
  118. data/config/initializers/session_store.rb +8 -0
  119. data/config/initializers/states_provinces.rb +2 -0
  120. data/config/initializers/will_paginate.rb +2 -0
  121. data/config/locales/en.yml +5 -0
  122. data/config/open_porch_example.yml +23 -0
  123. data/config/routes.rb +54 -0
  124. data/config/schedule.rb +9 -0
  125. data/config.ru +4 -0
  126. data/db/migrate/01_create_areas.rb +21 -0
  127. data/db/migrate/02_create_users.rb +28 -0
  128. data/db/migrate/03_create_memberships.rb +14 -0
  129. data/db/migrate/04_create_posts.rb +20 -0
  130. data/db/migrate/05_create_issue_numbers.rb +13 -0
  131. data/db/migrate/06_create_issues.rb +21 -0
  132. data/db/migrate/20110204173301_add_published_to_areas.rb +10 -0
  133. data/db/migrate/20110204194840_create_user_activities.rb +13 -0
  134. data/db/migrate/20110208163604_add_zip_to_areas.rb +11 -0
  135. data/db/migrate/20110209175723_add_counters_to_areas.rb +11 -0
  136. data/db/migrate/20110209182244_remove_subject_from_issues.rb +9 -0
  137. data/db/migrate/20110209190146_add_reviewer_info_to_posts.rb +9 -0
  138. data/db/migrate/20110215173144_add_email_validation_key_to_users.rb +13 -0
  139. data/db/migrate/20110215182716_remove_published_from_areas.rb +10 -0
  140. data/db/migrate/20110215211012_create_area_activities.rb +19 -0
  141. data/db/migrate/20110215213802_create_email_messages.rb +19 -0
  142. data/db/migrate/20110217165018_change_send_mode_to_string.rb +17 -0
  143. data/db/migrate/20110223160609_denormalize_user_info_in_posts.rb +19 -0
  144. data/db/seeds.rb +7 -0
  145. data/doc/README_FOR_APP +2 -0
  146. data/lib/generators/open_porch_generator.rb +37 -0
  147. data/lib/open_porch/engine.rb +20 -0
  148. data/lib/open_porch.rb +3 -0
  149. data/lib/tasks/.gitkeep +0 -0
  150. data/lib/tasks/open_porch.rake +10 -0
  151. data/lib/tasks/postageapp_tasks.rake +78 -0
  152. data/open_porch.gemspec +335 -0
  153. data/public/404.html +26 -0
  154. data/public/422.html +26 -0
  155. data/public/500.html +26 -0
  156. data/public/favicon.ico +0 -0
  157. data/public/images/icons/ajax-loader.gif +0 -0
  158. data/public/images/icons/calendar.png +0 -0
  159. data/public/images/icons/post_new.png +0 -0
  160. data/public/images/icons/post_reviewed.png +0 -0
  161. data/public/javascripts/application.js +3 -0
  162. data/public/javascripts/google_maps.js +153 -0
  163. data/public/javascripts/highcharts.js +162 -0
  164. data/public/javascripts/highcharts_init.js +30 -0
  165. data/public/javascripts/issue_edit.js +57 -0
  166. data/public/javascripts/jquery-ui.min.js +191 -0
  167. data/public/javascripts/jquery.js +154 -0
  168. data/public/javascripts/rails.js +137 -0
  169. data/public/javascripts/region_editor.js +616 -0
  170. data/public/javascripts/user_activity.js +29 -0
  171. data/public/robots.txt +5 -0
  172. data/public/stylesheets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  173. data/public/stylesheets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  174. data/public/stylesheets/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  175. data/public/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  176. data/public/stylesheets/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  177. data/public/stylesheets/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  178. data/public/stylesheets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  179. data/public/stylesheets/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  180. data/public/stylesheets/images/ui-icons_222222_256x240.png +0 -0
  181. data/public/stylesheets/images/ui-icons_2e83ff_256x240.png +0 -0
  182. data/public/stylesheets/images/ui-icons_454545_256x240.png +0 -0
  183. data/public/stylesheets/images/ui-icons_888888_256x240.png +0 -0
  184. data/public/stylesheets/images/ui-icons_cd0a0a_256x240.png +0 -0
  185. data/public/stylesheets/jquery-ui.css +362 -0
  186. data/script/rails +6 -0
  187. data/test/dummy/area.rb +5 -0
  188. data/test/dummy/area_activity.rb +7 -0
  189. data/test/dummy/issue.rb +4 -0
  190. data/test/dummy/membership.rb +4 -0
  191. data/test/dummy/post.rb +12 -0
  192. data/test/dummy/user.rb +29 -0
  193. data/test/dummy/user_activity.rb +11 -0
  194. data/test/functional/admin/areas/issues_controller_test.rb +48 -0
  195. data/test/functional/admin/areas/memberships_controller_test.rb +45 -0
  196. data/test/functional/admin/areas/posts_controller_test.rb +54 -0
  197. data/test/functional/admin/areas_controller_test.rb +134 -0
  198. data/test/functional/admin/base_controller_test.rb +8 -0
  199. data/test/functional/admin/user_activity_controller_test.rb +28 -0
  200. data/test/functional/admin/users_controller_test.rb +144 -0
  201. data/test/functional/areas/issues_controller_test.rb +33 -0
  202. data/test/functional/areas/posts_controller_test.rb +50 -0
  203. data/test/functional/areas_controller_test.rb +12 -0
  204. data/test/functional/passwords_controller_test.rb +64 -0
  205. data/test/functional/registrations_controller_test.rb +64 -0
  206. data/test/functional/sessions_controller_test.rb +120 -0
  207. data/test/functional/users_controller_test.rb +144 -0
  208. data/test/performance/browsing_test.rb +9 -0
  209. data/test/test_helper.rb +92 -0
  210. data/test/unit/address_test.rb +25 -0
  211. data/test/unit/area_activity_test.rb +57 -0
  212. data/test/unit/area_test.rb +92 -0
  213. data/test/unit/email_message_test.rb +8 -0
  214. data/test/unit/issue_number_test.rb +25 -0
  215. data/test/unit/issue_test.rb +154 -0
  216. data/test/unit/membership_test.rb +20 -0
  217. data/test/unit/post_test.rb +69 -0
  218. data/test/unit/session_user_test.rb +65 -0
  219. data/test/unit/user_activity_test.rb +31 -0
  220. data/test/unit/user_mailer_test.rb +20 -0
  221. data/test/unit/user_test.rb +61 -0
  222. data/vendor/plugins/.gitkeep +0 -0
  223. metadata +456 -0
data/Gemfile ADDED
@@ -0,0 +1,41 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rails', '>= 3.0.4'
4
+ gem 'pg', '0.10.1' # See installation notes below
5
+ gem 'haml', '3.0.25'
6
+ gem 'spatial_adapter', '1.2.0', :require => 'spatial_adapter/postgresql'
7
+ gem 'wristband', '>= 1.0.4'
8
+ gem 'formatted_form', '>= 1.0.1'
9
+ gem 'geokit', '1.5.0'
10
+ gem 'active_link_to', '0.0.6'
11
+ gem "meta_where", '1.0.1'
12
+ gem "meta_search", '1.0.1'
13
+ gem "will_paginate", "~> 3.0.pre2"
14
+ gem 'whenever', '0.6.2', :require => false
15
+ gem 'postageapp'
16
+
17
+ group :test do
18
+ gem "bundler"
19
+ gem "jeweler"
20
+ gem 'test_dummy'
21
+ gem 'faker'
22
+ gem 'mocha'
23
+ end
24
+
25
+
26
+ # Initial postgress configuration:
27
+ # http://www.glom.org/wiki/index.php?title=Initial_Postgres_Configuration
28
+
29
+
30
+
31
+ # Installing the pg gem (https://bitbucket.org/ged/ruby-pg/wiki/Home)
32
+ # ------------------------------------------------------------------------
33
+ # 1 - You need to set the path to 'pg_config' in your PATH (i.e. where your postgres was installed )
34
+ # Example:
35
+ # /Library/PostgreSQL/9.0/bin
36
+
37
+ # 2 - On Mac you need to specify the achitecture
38
+ # For Snow Leopard 32-bit build use: '-arch i386'
39
+ # For Snow Leopard 64-bit build use: '-arch x86_64'
40
+ # Example:
41
+ # ARCHFLAGS="-arch x86_64" gem install pg
data/Gemfile.lock ADDED
@@ -0,0 +1,130 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ GeoRuby (1.3.4)
5
+ aaronh-chronic (0.3.9)
6
+ abstract (1.0.0)
7
+ actionmailer (3.0.4)
8
+ actionpack (= 3.0.4)
9
+ mail (~> 2.2.15)
10
+ actionpack (3.0.4)
11
+ activemodel (= 3.0.4)
12
+ activesupport (= 3.0.4)
13
+ builder (~> 2.1.2)
14
+ erubis (~> 2.6.6)
15
+ i18n (~> 0.4)
16
+ rack (~> 1.2.1)
17
+ rack-mount (~> 0.6.13)
18
+ rack-test (~> 0.5.7)
19
+ tzinfo (~> 0.3.23)
20
+ active_link_to (0.0.6)
21
+ activemodel (3.0.4)
22
+ activesupport (= 3.0.4)
23
+ builder (~> 2.1.2)
24
+ i18n (~> 0.4)
25
+ activerecord (3.0.4)
26
+ activemodel (= 3.0.4)
27
+ activesupport (= 3.0.4)
28
+ arel (~> 2.0.2)
29
+ tzinfo (~> 0.3.23)
30
+ activeresource (3.0.4)
31
+ activemodel (= 3.0.4)
32
+ activesupport (= 3.0.4)
33
+ activesupport (3.0.4)
34
+ arel (2.0.8)
35
+ builder (2.1.2)
36
+ erubis (2.6.6)
37
+ abstract (>= 1.0.0)
38
+ faker (0.9.5)
39
+ i18n (~> 0.4)
40
+ formatted_form (1.0.1)
41
+ geokit (1.5.0)
42
+ git (1.2.5)
43
+ haml (3.0.25)
44
+ i18n (0.5.0)
45
+ jeweler (1.5.2)
46
+ bundler (~> 1.0.0)
47
+ git (>= 1.2.5)
48
+ rake
49
+ json (1.5.1)
50
+ mail (2.2.15)
51
+ activesupport (>= 2.3.6)
52
+ i18n (>= 0.4.0)
53
+ mime-types (~> 1.16)
54
+ treetop (~> 1.4.8)
55
+ meta_search (1.0.1)
56
+ actionpack (~> 3.0.2)
57
+ activerecord (~> 3.0.2)
58
+ activesupport (~> 3.0.2)
59
+ arel (~> 2.0.2)
60
+ meta_where (1.0.1)
61
+ activerecord (~> 3.0.2)
62
+ activesupport (~> 3.0.2)
63
+ arel (~> 2.0.2)
64
+ mime-types (1.16)
65
+ mocha (0.9.12)
66
+ pg (0.10.1)
67
+ polyglot (0.3.1)
68
+ postageapp (1.0.10)
69
+ json (>= 1.4.6)
70
+ rack (1.2.1)
71
+ rack-mount (0.6.13)
72
+ rack (>= 1.0.0)
73
+ rack-test (0.5.7)
74
+ rack (>= 1.0)
75
+ rails (3.0.4)
76
+ actionmailer (= 3.0.4)
77
+ actionpack (= 3.0.4)
78
+ activerecord (= 3.0.4)
79
+ activeresource (= 3.0.4)
80
+ activesupport (= 3.0.4)
81
+ bundler (~> 1.0)
82
+ railties (= 3.0.4)
83
+ railties (3.0.4)
84
+ actionpack (= 3.0.4)
85
+ activesupport (= 3.0.4)
86
+ rake (>= 0.8.7)
87
+ thor (~> 0.14.4)
88
+ rake (0.8.7)
89
+ spatial_adapter (1.2.0)
90
+ GeoRuby (>= 1.3.0)
91
+ activerecord (>= 2.2.2)
92
+ test_dummy (0.2.6)
93
+ thor (0.14.6)
94
+ treetop (1.4.9)
95
+ polyglot (>= 0.3.1)
96
+ tzinfo (0.3.24)
97
+ whenever (0.6.2)
98
+ aaronh-chronic (>= 0.3.9)
99
+ activesupport (>= 2.3.4)
100
+ will_paginate (3.0.pre2)
101
+ wristband (1.0.4)
102
+ formatted_form (>= 1.0.0)
103
+ formatted_form
104
+ haml (>= 3.0.25)
105
+ haml (>= 3.0.25)
106
+ rails (>= 3.0.4)
107
+ rails (>= 3.0.4)
108
+
109
+ PLATFORMS
110
+ ruby
111
+
112
+ DEPENDENCIES
113
+ active_link_to (= 0.0.6)
114
+ bundler
115
+ faker
116
+ formatted_form (>= 1.0.1)
117
+ geokit (= 1.5.0)
118
+ haml (= 3.0.25)
119
+ jeweler
120
+ meta_search (= 1.0.1)
121
+ meta_where (= 1.0.1)
122
+ mocha
123
+ pg (= 0.10.1)
124
+ postageapp
125
+ rails (>= 3.0.4)
126
+ spatial_adapter (= 1.2.0)
127
+ test_dummy
128
+ whenever (= 0.6.2)
129
+ will_paginate (~> 3.0.pre2)
130
+ wristband (>= 1.0.4)
data/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # Open Porch
2
+ * * *
3
+
4
+ ## Overview
5
+
6
+ [Open Porch](http://openporch.org) was created by 2010 [Knight News Challenge](http://www.newschallenge.org/) winner [Front Porch Forum](http://frontporchforum.com) thanks to support from the [John S. and James L. Knight Foundation](http://www.knightfoundation.org/).
7
+
8
+ The software was built by [The Working Group, Inc.](http://www.theworkinggroup.ca/).
9
+
10
+ Open Porch design is based on experienced gained by operating the successful Front Porch Forum pilot project in Burlington, Vermont, USA, 2006-2010.
11
+
12
+ Front Porch Forum's mission is to help nearby neighbors connect and build community. It does that by hosting regional networks of small online neighborhood forums. By early 2011, 24,000 households subscribed to its Vermont pilot, including half of those in Burlington. People make great use of FPF to find lost cats, report car break-ins, borrow ladders, recommend plumbers, debate school budgets, announce a blood drive, organize a block party and much more. Since each posting is shared among clearly identified nearby neighbors, people report that over time they feel more connected to neighbors and better informed about what's going on around them. This leads eventually, for many, to get more involved in local issues and fulfills FPF's mission.
13
+
14
+ Front Porch Forum's new platform is based on Open Porch. Open Porch is a Ruby on Rails gem released under an MIT open source license.
15
+
16
+ **The Knight News Challenge:** KNC is a media innovation contest that aims to advance the future of news by funding new ways to digitally inform communities.
17
+
18
+ **The Working Group, Inc.:** Since 2002, TWG has designed and built web sites, web applications, iPhone apps, and system integrations for entrepreneurs, mature businesses, governments, and non-profit organizations.
19
+
20
+
21
+ * * *
22
+ ## Functionality
23
+
24
+ ### Overview
25
+
26
+ * **User registration:**
27
+ * A user can choose his neighbourhood on a map by entering his address. The system uses geolocation to direct the user to the closest neighbourhood.
28
+ * Once the user is logged in he can edit his account.
29
+
30
+ * **User authentication:**
31
+ * This includes the basic login, logout, remember me functionality, forgot password and email verification.
32
+
33
+ * **Neighbourhood forums:**
34
+ * Each user has access to a forum in his neighbourhood.
35
+ * The posts in a Neighborhood Forum are grouped in issues that are emailed periodically to all the members of the neighbourhood.
36
+ * A user can read the current issue on his Neighbourhood Forum or search for older issues.
37
+
38
+ * **User participation:**
39
+ * Users are encouraged to contribute to their Neighbourhood Forum by posting new messages via email of via the website.
40
+
41
+ ### Administration
42
+
43
+ * **Users:**
44
+ * As an administrator you can use the admin interface you can create, edit and delete users in the system.
45
+ * Users can be filtered by name, email or role.
46
+
47
+ * **Areas:**
48
+ * As an administrator you have access to all the areas (Neighbourhoods) in the system.
49
+ * Each area is represented by a polygon on a map. The points of an area can be manipulated directly by using the map editor tool provided.
50
+ * From the admin interface you can manage the area details, memberships and issues.
51
+
52
+ * **Issues:**
53
+ * An area can operate in two distinct modes: immediate and batched.
54
+ * In immediate mode each message posted to a furum is immediatelly send to each user of the forum.
55
+ * In batched mode messages are held back for review by the administrator and can be edited and added to an issue individually. Each issue can then be scheduled individually.
56
+
57
+ * **Reports:**
58
+ * Areas can be searched by name or location using the admin interface.
59
+ * Each area maintains records of it's activity regarding number of new users, quitters, new posts and new issues which can be visualized in a chart and filtered by date.
60
+
61
+
62
+
63
+ * * *
64
+ ## Installation
65
+
66
+ Open Porch uses [Postgres 9.0](http://www.postgresql.org) and [PostGIS](http://postgis.refractions.net) so we'll assume you have these as well as the [pg gem](https://bitbucket.org/ged/ruby-pg/wiki/Home) installed.
67
+
68
+
69
+ ### 1. Add gem definition to your Gemfile:
70
+
71
+ gem 'open_porch'
72
+
73
+ ### 2. Install your gems:
74
+
75
+ bundle install
76
+
77
+ ### 3. Run the generator:
78
+
79
+ rails g open_porch
80
+
81
+ ### 4. Setup your database.yml file using the sample provided database_example_.yml
82
+
83
+ development:
84
+ adapter: postgresql
85
+ encoding: utf8
86
+ schema_search_path: public
87
+ template: template_postgis
88
+ database: open_porch_development
89
+ pool: 5
90
+ username: open_porch
91
+ password:
92
+
93
+ The `template` option is particularly important because it is used on the database creation.
94
+
95
+ ### 5. Create your spacially enabled database
96
+
97
+ rake db:create
98
+
99
+ When you instal the [PostGIS](http://postgis.refractions.net) extension you should make sure you also have the `template_postgis` database generated for you. This database contains all the functions needed for spacial calculations.
100
+
101
+ Once you run `rake db:create`, a copy of `template_postgis` will be used to create your database.
102
+
103
+ ### 6. Run the migrations
104
+
105
+ rake db:migrate
106
+
107
+
108
+
109
+ * * *
110
+ ## The generator
111
+
112
+ rails g open_porch
113
+
114
+ The generator will give you a list of files you need to get started. You can and should change these files to serve the purpose of your website.
115
+
116
+ * **Application controller:** You should use the application controller as a starting point. It calls methods related with user login.
117
+ * **Static files:** These are all the javascripts, stylesheets and images used in Open Porch.
118
+ * **Sample config files:** These are sample config files that will help you setup your own system.
119
+ * **Migrations:** All the migrations needed by Open Porch
120
+
121
+
122
+
123
+ * * *
124
+ ## Configuration
125
+
126
+ Open Porch uses `config/open_porch.yml` aa it's main configuration file.
127
+
128
+ ### Mass mailing with PostageApp
129
+
130
+ To send out the issues newsletter to all users in a forum, Open Porch makes use of [PostageApp](http://postageapp.com).
131
+
132
+ To enable this functionality create a PostageApp account and fill in the respective section in `config/open_porch.yml`
133
+
134
+
135
+ ### POP3 server
136
+
137
+ Open Porch can read emails posted to a POP3 server.
138
+ By looking up the FROM field it can find the user who sent the message. By looking up the TO field it can find the destination furum. This mechanism allows users to communicate directly with their neighbourhood forum via email.
139
+
140
+ To enable this functionality fill in the respective section in `config/open_porch.yml`
141
+
142
+ ### Advertisement with OpenX
143
+
144
+ Open Porch displays ads on each forum page.
145
+
146
+ To enable this functionality create an OpenX account and fill in the respective section in `config/open_porch.yml`
147
+
148
+
149
+
150
+
151
+ * * *
152
+ ## Cronjobs
153
+
154
+ Open Porch uses the `whenever` gem to send issue newsletters and to fetch new messages from the pop3 server.
155
+
156
+ Install `whenever` and create you `schedule.rb` file
157
+
158
+ set :output, "log/cron.log"
159
+ job_type :exec, "cd :path && RAILS_ENV=:environment :task :output"
160
+
161
+ every 5.minutes do
162
+ exec "open_porch_engine"
163
+ end
164
+
165
+
166
+ * * *
167
+ ## License
168
+
169
+ Open Porch is released under the [GNU General Public License, version 3 (GPLv3)](http://www.opensource.org/licenses/gpl-3.0)
170
+
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
+
7
+ OpenPorch::Application.load_tasks
8
+
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gem|
11
+ gem.name = "open_porch"
12
+ gem.homepage = "http://github.com/FrontPorchForum/open_porch"
13
+ gem.license = "MIT"
14
+ gem.summary = 'Open Porch is Rails Engine'
15
+ gem.description = ''
16
+ gem.email = "jack@theworkinggroup.ca"
17
+ gem.authors = ['The Working Group Inc']
18
+ end
19
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,11 @@
1
+ class Admin::Areas::BaseController < Admin::BaseController
2
+ before_filter :require_authority_to_manage_areas
3
+ before_filter :load_area
4
+
5
+ protected
6
+ def load_area
7
+ @area = Area.find(params[:area_id])
8
+ rescue ActiveRecord::RecordNotFound
9
+ render :text => 'Area not found', :status => 404
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ class Admin::Areas::IssuesController < Admin::Areas::BaseController
2
+ before_filter :load_issue,
3
+ :except => [:index, :new]
4
+ before_filter :block_edit_if_sent,
5
+ :except => [:index, :new, :show]
6
+
7
+ def index
8
+ @issues = @area.issues.order("number DESC").paginate(:page => params[:page])
9
+ end
10
+
11
+ def new
12
+ @issue = @area.issues.create!
13
+ redirect_to edit_admin_area_issue_path(@area, @issue)
14
+ end
15
+
16
+ def edit
17
+ load_posts
18
+ end
19
+
20
+ def show
21
+ if @issue.sent_at.blank?
22
+ redirect_to edit_admin_area_issue_path(@area, @issue)
23
+ end
24
+ end
25
+
26
+ def update
27
+ @issue.update_attributes!(params[:issue])
28
+ redirect_to edit_admin_area_issue_path(@area, @issue)
29
+ rescue ActiveRecord::RecordInvalid
30
+ load_posts
31
+ render :action => :edit
32
+ end
33
+
34
+ def add_posts
35
+ return if params[:posts].blank?
36
+ Post.update_all(['issue_id = %d', @issue.id], ['id IN (?)', params[:posts]])
37
+ end
38
+
39
+ def remove_posts
40
+ return if params[:posts].blank?
41
+ Post.update_all('issue_id = NULL', ['id IN (?)', params[:posts]])
42
+ end
43
+
44
+ protected
45
+ def load_area
46
+ @area = Area.find(params[:area_id])
47
+ rescue ActiveRecord::RecordNotFound
48
+ render :text => 'Area not found.', :status => 404
49
+ end
50
+
51
+ def load_issue
52
+ @issue = @area.issues.find(params[:id])
53
+ rescue ActiveRecord::RecordNotFound
54
+ render :text => 'Issue not found.', :status => 404
55
+ end
56
+
57
+ def load_posts
58
+ @new_posts = @area.posts.in_issue(nil).order('created_at DESC')
59
+ @issue_posts = @area.posts.in_issue(@issue).order('position')
60
+ end
61
+
62
+ def block_edit_if_sent
63
+ if @issue.sent_at.present?
64
+ redirect_to admin_area_issue_path(@area, @issue)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,7 @@
1
+ class Admin::Areas::MembershipsController < Admin::Areas::BaseController
2
+
3
+ def index
4
+ @memberships = @area.memberships.includes(:user)
5
+ end
6
+
7
+ end
@@ -0,0 +1,44 @@
1
+ class Admin::Areas::PostsController < Admin::Areas::BaseController
2
+ respond_to :js
3
+ before_filter :load_post,
4
+ :except => :order
5
+
6
+ def edit
7
+ end
8
+
9
+ def update
10
+ @post.update_attributes(params[:post])
11
+ end
12
+
13
+ def show
14
+ end
15
+
16
+ def order
17
+ if params[:post].present?
18
+ params[:post].each_with_index do |post, i|
19
+ Post.update_all(['position = %d', i], ['id = %d', post])
20
+ end
21
+ end
22
+ render :nothing => true
23
+ end
24
+
25
+ def toggle_reviewed_by
26
+ if !@post.reviewed_by
27
+ @post.update_attribute(:reviewed_by, current_user.full_name)
28
+ else
29
+ @post.update_attribute(:reviewed_by, nil)
30
+ end
31
+ render :layout => false
32
+ end
33
+
34
+ def destroy
35
+ @post.destroy
36
+ end
37
+
38
+ protected
39
+ def load_post
40
+ @post = @area.posts.find(params[:id])
41
+ rescue ActiveRecord::RecordNotFound
42
+ render :nothing => true, :status => 404
43
+ end
44
+ end
@@ -0,0 +1,89 @@
1
+ class Admin::AreasController < Admin::BaseController
2
+ before_filter :require_authority_to_manage_areas
3
+ before_filter :build_area,
4
+ :only => [:new, :create]
5
+ before_filter :load_area,
6
+ :except => [:index, :new, :create, :edit_borders, :bulk_update]
7
+
8
+ def index
9
+ params[:search] ||= {}
10
+ params[:search][:meta_sort] ||= 'city'
11
+ @search = Area.search(params[:search])
12
+ @areas = @search.paginate(:page => params[:page])
13
+ @new_posts = Area.newposts_count
14
+
15
+ start_date = Time.parse(params[:activity_start_date]).to_date rescue 30.days.ago.to_date
16
+ end_date = Time.parse(params[:activity_end_date]).to_date rescue Date.today
17
+
18
+ @activities = AreaActivity.grouped_by_day
19
+ .search(:day_between => [start_date, end_date])
20
+ .where(:area_id => @search.all.collect(&:id))
21
+ end
22
+
23
+ def new
24
+ end
25
+
26
+ def create
27
+ @area.save!
28
+ respond_to do |format|
29
+ format.html do
30
+ redirect_to([:admin, :areas], :notice => 'Area has been successfully created.')
31
+ end
32
+ format.js do
33
+ render :text => @area.id
34
+ end
35
+ end
36
+ rescue ActiveRecord::RecordInvalid
37
+ render :action => :new
38
+ end
39
+
40
+ def show
41
+ redirect_to [:edit, :admin, @area, @area.issues.last]
42
+ end
43
+
44
+ def edit
45
+ # ...
46
+ end
47
+
48
+ def edit_borders
49
+ @areas = Area.all
50
+ @area = @selected_area = @areas.detect{|area| area.id == params[:id].to_i}
51
+ if @selected_area.nil?
52
+ @default_area = @areas.first
53
+ end
54
+ end
55
+
56
+ def update
57
+ @area.update_attributes!(params[:area])
58
+ redirect_to([:admin, :areas], :notice => 'Area has been successfully updated.')
59
+ rescue ActiveRecord::RecordInvalid
60
+ render :action => :edit
61
+ end
62
+
63
+ def bulk_update
64
+ params[:areas].each do |index, area_params|
65
+ area = Area.find(area_params[:id])
66
+ area.coordinates = area_params[:coordinates]
67
+ area.save!
68
+ end
69
+ render :nothing => true
70
+ rescue ActiveRecord::RecordInvalid
71
+ render :nothing => true, :status => :bad_request
72
+ end
73
+
74
+ def destroy
75
+ @area.destroy
76
+ redirect_to([:admin, :areas], :notice => 'Area has been successfully deleted.')
77
+ end
78
+
79
+ protected
80
+ def build_area
81
+ @area = Area.new(params[:area])
82
+ end
83
+
84
+ def load_area
85
+ @area = Area.find(params[:id])
86
+ rescue ActiveRecord::RecordNotFound
87
+ render :text => 'Area not found', :status => 404
88
+ end
89
+ end
@@ -0,0 +1,16 @@
1
+ class Admin::BaseController < ApplicationController
2
+ layout 'admin'
3
+
4
+ protected
5
+ def require_authority_to_manage_users
6
+ unless current_user.has_authority_to?(:manage_users)
7
+ redirect_to(area_path(current_user.areas.first), :alert => "You're not authorized to access that page.")
8
+ end
9
+ end
10
+
11
+ def require_authority_to_manage_areas
12
+ unless current_user.has_authority_to?(:manage_areas)
13
+ redirect_to(area_path(current_user.areas.first), :alert => "You're not authorized to access that page.")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ class Admin::UserActivityController < Admin::BaseController
2
+ before_filter :require_authority_to_manage_areas
3
+ before_filter :load_user_activity
4
+
5
+ def index
6
+ end
7
+
8
+ def show
9
+ @user_activities = UserActivity.active_for_page(current_user.full_name, params[:url]).order('name DESC')
10
+ render :layout => false, :object => @user_activities
11
+ rescue ActiveRecord::RecordInvalid
12
+ head :bad_request
13
+ end
14
+
15
+ def edit
16
+ end
17
+
18
+ def update
19
+ @user_activity.set_expiration!
20
+ render :nothing => true
21
+ end
22
+
23
+ protected
24
+
25
+ def load_user_activity
26
+ @user_activity = UserActivity.find_or_create_by_name_and_url(:name => current_user.full_name, :url => params[:url])
27
+ end
28
+
29
+ end
@@ -0,0 +1,57 @@
1
+ class Admin::UsersController < Admin::BaseController
2
+ before_filter :require_authority_to_manage_users
3
+ before_filter :load_user,
4
+ :except => [:index, :new, :create]
5
+ before_filter :build_user,
6
+ :only => [:new, :create]
7
+
8
+ def index
9
+ params[:search] ||= {}
10
+ params[:search][:meta_sort] ||= 'created_at.desc'
11
+ @search = User.search(params[:search])
12
+ @users = @search.paginate(:page => params[:page])
13
+ end
14
+
15
+ def new
16
+ @user.memberships.build
17
+ end
18
+
19
+ def create
20
+ @user.save!
21
+ redirect_to(admin_users_path, :notice => 'User was successfully created.')
22
+ rescue ActiveRecord::RecordInvalid
23
+ render :action => :new
24
+ end
25
+
26
+ def edit
27
+ end
28
+
29
+ def update
30
+ @user.send(:attributes=, params[:user], false)
31
+ @user.save!
32
+ redirect_to(@return_url, :notice => 'User has been successfully updated.')
33
+ rescue ActiveRecord::RecordInvalid
34
+ render :action => :edit
35
+ end
36
+
37
+ def destroy
38
+ @user.destroy
39
+ redirect_to([:admin, :users], :notice => 'User has been successfully deleted.')
40
+ end
41
+
42
+ protected
43
+ def load_user
44
+ @user = User.find(params[:id])
45
+ if params[:area_id]
46
+ @return_url = admin_area_memberships_path(params[:area_id])
47
+ else
48
+ @return_url = admin_users_path
49
+ end
50
+ rescue ActiveRecord::RecordNotFound
51
+ render :text => 'User not found', :status => 404
52
+ end
53
+
54
+ def build_user
55
+ @user = User.new(params[:user])
56
+ end
57
+ end