open_porch 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +41 -0
- data/Gemfile.lock +130 -0
- data/README.md +170 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/app/controllers/admin/areas/base_controller.rb +11 -0
- data/app/controllers/admin/areas/issues_controller.rb +67 -0
- data/app/controllers/admin/areas/memberships_controller.rb +7 -0
- data/app/controllers/admin/areas/posts_controller.rb +44 -0
- data/app/controllers/admin/areas_controller.rb +89 -0
- data/app/controllers/admin/base_controller.rb +16 -0
- data/app/controllers/admin/user_activity_controller.rb +29 -0
- data/app/controllers/admin/users_controller.rb +57 -0
- data/app/controllers/application_controller.rb +15 -0
- data/app/controllers/areas/base_controller.rb +25 -0
- data/app/controllers/areas/issues_controller.rb +35 -0
- data/app/controllers/areas/posts_controller.rb +28 -0
- data/app/controllers/areas_controller.rb +30 -0
- data/app/controllers/passwords_controller.rb +42 -0
- data/app/controllers/registrations_controller.rb +42 -0
- data/app/controllers/sessions_controller.rb +33 -0
- data/app/controllers/users_controller.rb +77 -0
- data/app/helpers/open_porch_helper.rb +24 -0
- data/app/mailers/user_mailer.rb +35 -0
- data/app/models/address.rb +57 -0
- data/app/models/area.rb +171 -0
- data/app/models/area_activity.rb +24 -0
- data/app/models/email_message.rb +104 -0
- data/app/models/issue.rb +66 -0
- data/app/models/issue_number.rb +22 -0
- data/app/models/membership.rb +27 -0
- data/app/models/post.rb +64 -0
- data/app/models/session_user.rb +69 -0
- data/app/models/user.rb +140 -0
- data/app/models/user_activity.rb +31 -0
- data/app/models/user_authority_check.rb +14 -0
- data/app/views/admin/areas/_form.html.haml +8 -0
- data/app/views/admin/areas/_nav.html.haml +12 -0
- data/app/views/admin/areas/edit.html.haml +22 -0
- data/app/views/admin/areas/edit_borders.html.haml +44 -0
- data/app/views/admin/areas/index.html.haml +61 -0
- data/app/views/admin/areas/issues/_post.html.haml +15 -0
- data/app/views/admin/areas/issues/add_posts.js.rjs +3 -0
- data/app/views/admin/areas/issues/edit.html.haml +37 -0
- data/app/views/admin/areas/issues/index.html.haml +31 -0
- data/app/views/admin/areas/issues/remove_posts.js.rjs +3 -0
- data/app/views/admin/areas/issues/show.html.haml +13 -0
- data/app/views/admin/areas/memberships/index.html.haml +17 -0
- data/app/views/admin/areas/new.html.haml +6 -0
- data/app/views/admin/areas/new.js.haml +4 -0
- data/app/views/admin/areas/posts/_edit.html.haml +6 -0
- data/app/views/admin/areas/posts/_post_status.html.haml +1 -0
- data/app/views/admin/areas/posts/destroy.js.rjs +1 -0
- data/app/views/admin/areas/posts/edit.js.rjs +1 -0
- data/app/views/admin/areas/posts/show.js.rjs +1 -0
- data/app/views/admin/areas/posts/toggle_reviewed_by.js.rjs +1 -0
- data/app/views/admin/areas/posts/update.js.rjs +5 -0
- data/app/views/admin/areas/show.html.haml +5 -0
- data/app/views/admin/user_activity/show.html.haml +5 -0
- data/app/views/admin/users/_form.html.haml +21 -0
- data/app/views/admin/users/edit.html.haml +5 -0
- data/app/views/admin/users/index.html.haml +31 -0
- data/app/views/admin/users/new.html.haml +5 -0
- data/app/views/areas/issues/index.html.haml +31 -0
- data/app/views/areas/issues/show.html.haml +22 -0
- data/app/views/areas/posts/_post.html.haml +8 -0
- data/app/views/areas/posts/_posts_search_form.html.haml +8 -0
- data/app/views/areas/posts/index.html.haml +27 -0
- data/app/views/areas/posts/new.html.haml +10 -0
- data/app/views/areas/show.html.haml +47 -0
- data/app/views/layouts/_account_nav.html.haml +18 -0
- data/app/views/layouts/_flash_message.html.haml +4 -0
- data/app/views/layouts/_footer.html.haml +9 -0
- data/app/views/layouts/_head.html.haml +16 -0
- data/app/views/layouts/admin/_nav.html.haml +13 -0
- data/app/views/layouts/admin.html.haml +15 -0
- data/app/views/layouts/application.html.haml +14 -0
- data/app/views/layouts/area_editor.html.haml +11 -0
- data/app/views/passwords/edit.html.haml +9 -0
- data/app/views/passwords/new.html.haml +13 -0
- data/app/views/registrations/_address_form.html.haml +7 -0
- data/app/views/registrations/create.html.haml +49 -0
- data/app/views/registrations/index.html.haml +30 -0
- data/app/views/registrations/new.html.haml +17 -0
- data/app/views/sessions/new.html.haml +18 -0
- data/app/views/stylesheets/common.sass +239 -0
- data/app/views/stylesheets/content.sass +193 -0
- data/app/views/stylesheets/reset.sass +46 -0
- data/app/views/stylesheets/structure.sass +11 -0
- data/app/views/stylesheets/typography.sass +57 -0
- data/app/views/user_mailer/email_verification.html.erb +5 -0
- data/app/views/user_mailer/email_verification.text.erb +7 -0
- data/app/views/user_mailer/new_issue.html.erb +32 -0
- data/app/views/user_mailer/new_issue.text.erb +26 -0
- data/app/views/user_mailer/password_reset.html.erb +7 -0
- data/app/views/user_mailer/password_reset.text.erb +6 -0
- data/app/views/users/_form.html.haml +5 -0
- data/app/views/users/edit.html.haml +11 -0
- data/app/views/users/new.html.haml +41 -0
- data/app/views/users/show.html.haml +30 -0
- data/bin/open_porch_engine +135 -0
- data/config/application.rb +43 -0
- data/config/boot.rb +13 -0
- data/config/database_example.yml +59 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +26 -0
- data/config/environments/production.rb +49 -0
- data/config/environments/test.rb +35 -0
- data/config/initializers/backtrace_silencers.rb +7 -0
- data/config/initializers/email_regex.rb +38 -0
- data/config/initializers/geokit_config.rb +61 -0
- data/config/initializers/inflections.rb +20 -0
- data/config/initializers/meta_search.rb +7 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/open_porch.rb +41 -0
- data/config/initializers/sass.rb +1 -0
- data/config/initializers/secret_token.rb +7 -0
- data/config/initializers/session_store.rb +8 -0
- data/config/initializers/states_provinces.rb +2 -0
- data/config/initializers/will_paginate.rb +2 -0
- data/config/locales/en.yml +5 -0
- data/config/open_porch_example.yml +23 -0
- data/config/routes.rb +54 -0
- data/config/schedule.rb +9 -0
- data/config.ru +4 -0
- data/db/migrate/01_create_areas.rb +21 -0
- data/db/migrate/02_create_users.rb +28 -0
- data/db/migrate/03_create_memberships.rb +14 -0
- data/db/migrate/04_create_posts.rb +20 -0
- data/db/migrate/05_create_issue_numbers.rb +13 -0
- data/db/migrate/06_create_issues.rb +21 -0
- data/db/migrate/20110204173301_add_published_to_areas.rb +10 -0
- data/db/migrate/20110204194840_create_user_activities.rb +13 -0
- data/db/migrate/20110208163604_add_zip_to_areas.rb +11 -0
- data/db/migrate/20110209175723_add_counters_to_areas.rb +11 -0
- data/db/migrate/20110209182244_remove_subject_from_issues.rb +9 -0
- data/db/migrate/20110209190146_add_reviewer_info_to_posts.rb +9 -0
- data/db/migrate/20110215173144_add_email_validation_key_to_users.rb +13 -0
- data/db/migrate/20110215182716_remove_published_from_areas.rb +10 -0
- data/db/migrate/20110215211012_create_area_activities.rb +19 -0
- data/db/migrate/20110215213802_create_email_messages.rb +19 -0
- data/db/migrate/20110217165018_change_send_mode_to_string.rb +17 -0
- data/db/migrate/20110223160609_denormalize_user_info_in_posts.rb +19 -0
- data/db/seeds.rb +7 -0
- data/doc/README_FOR_APP +2 -0
- data/lib/generators/open_porch_generator.rb +37 -0
- data/lib/open_porch/engine.rb +20 -0
- data/lib/open_porch.rb +3 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/open_porch.rake +10 -0
- data/lib/tasks/postageapp_tasks.rake +78 -0
- data/open_porch.gemspec +335 -0
- data/public/404.html +26 -0
- data/public/422.html +26 -0
- data/public/500.html +26 -0
- data/public/favicon.ico +0 -0
- data/public/images/icons/ajax-loader.gif +0 -0
- data/public/images/icons/calendar.png +0 -0
- data/public/images/icons/post_new.png +0 -0
- data/public/images/icons/post_reviewed.png +0 -0
- data/public/javascripts/application.js +3 -0
- data/public/javascripts/google_maps.js +153 -0
- data/public/javascripts/highcharts.js +162 -0
- data/public/javascripts/highcharts_init.js +30 -0
- data/public/javascripts/issue_edit.js +57 -0
- data/public/javascripts/jquery-ui.min.js +191 -0
- data/public/javascripts/jquery.js +154 -0
- data/public/javascripts/rails.js +137 -0
- data/public/javascripts/region_editor.js +616 -0
- data/public/javascripts/user_activity.js +29 -0
- data/public/robots.txt +5 -0
- data/public/stylesheets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/public/stylesheets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/public/stylesheets/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/public/stylesheets/images/ui-icons_222222_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_2e83ff_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_454545_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_888888_256x240.png +0 -0
- data/public/stylesheets/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/public/stylesheets/jquery-ui.css +362 -0
- data/script/rails +6 -0
- data/test/dummy/area.rb +5 -0
- data/test/dummy/area_activity.rb +7 -0
- data/test/dummy/issue.rb +4 -0
- data/test/dummy/membership.rb +4 -0
- data/test/dummy/post.rb +12 -0
- data/test/dummy/user.rb +29 -0
- data/test/dummy/user_activity.rb +11 -0
- data/test/functional/admin/areas/issues_controller_test.rb +48 -0
- data/test/functional/admin/areas/memberships_controller_test.rb +45 -0
- data/test/functional/admin/areas/posts_controller_test.rb +54 -0
- data/test/functional/admin/areas_controller_test.rb +134 -0
- data/test/functional/admin/base_controller_test.rb +8 -0
- data/test/functional/admin/user_activity_controller_test.rb +28 -0
- data/test/functional/admin/users_controller_test.rb +144 -0
- data/test/functional/areas/issues_controller_test.rb +33 -0
- data/test/functional/areas/posts_controller_test.rb +50 -0
- data/test/functional/areas_controller_test.rb +12 -0
- data/test/functional/passwords_controller_test.rb +64 -0
- data/test/functional/registrations_controller_test.rb +64 -0
- data/test/functional/sessions_controller_test.rb +120 -0
- data/test/functional/users_controller_test.rb +144 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +92 -0
- data/test/unit/address_test.rb +25 -0
- data/test/unit/area_activity_test.rb +57 -0
- data/test/unit/area_test.rb +92 -0
- data/test/unit/email_message_test.rb +8 -0
- data/test/unit/issue_number_test.rb +25 -0
- data/test/unit/issue_test.rb +154 -0
- data/test/unit/membership_test.rb +20 -0
- data/test/unit/post_test.rb +69 -0
- data/test/unit/session_user_test.rb +65 -0
- data/test/unit/user_activity_test.rb +31 -0
- data/test/unit/user_mailer_test.rb +20 -0
- data/test/unit/user_test.rb +61 -0
- data/vendor/plugins/.gitkeep +0 -0
- 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,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
|