Compare commits

..

103 Commits

Author SHA1 Message Date
Skud
78ee229205 Merge pull request #321 from Growstuff/dev
Production push: order referral codes and some CSS fixes
2013-09-18 18:23:22 -07:00
Skud
9af9d2ac04 Merge pull request #320 from Skud/order_referral_code
Order referral code
2013-09-18 18:16:00 -07:00
Skud
2ee11e19e5 removed spurious puts 2013-09-19 10:57:11 +10:00
Skud
e425a3f7f4 added error message if your referral code has invalid chars 2013-09-19 10:57:00 +10:00
Skud
3d42e4bce9 Merge pull request #319 from Skud/css-fixes
Css fixes
2013-09-16 17:55:17 -07:00
Skud
4e03e5abbd Merge pull request #318 from Skud/order_referral_code
Order referral code
2013-09-16 00:15:50 -07:00
Skud
9e374779c0 Fixed navbar display CSS
1) Made sure padding is applied to the body *only* for the larger screen
sizes (by doing so before the responsive CSS is loaded)

2) Fixed indentation on the footer, which was incorrectly putting it
inside the main body container, and thus making it do this weird
narrowing thing at smaller screen sizes.
2013-09-16 11:09:52 +10:00
Skud
df3254135f Made li list style dots more specific
We set all li elements to use list-style disc, but it was affecting our
navbar.  Changed it to use a specific class in the crop hierarchy (where
we actually cared about it).
2013-09-16 10:49:02 +10:00
Skud
ab588bd21b add referral code to order admin table 2013-09-16 10:39:12 +10:00
Skud
a250bc162f Fixed up db/schema to remove spurious payments table 2013-09-16 10:22:42 +10:00
Skud
fef92f0d14 Added tests for admin order controller 2013-09-13 14:19:46 +10:00
Skud
faea1904c2 Added referral code search to admin forms 2013-09-13 13:47:46 +10:00
Skud
1adcedb534 moved admin order search into a model method 2013-09-13 13:38:11 +10:00
Skud
0ce821aacf added referral_code to order form/checkout code 2013-09-13 13:12:11 +10:00
Skud
2422182aa8 Added referral_code to Order
Also added validation (alphanumeric), but we're fairly lax about
whitespace and case, and clean up for them if they make minor errors.
2013-09-13 12:14:17 +10:00
Skud
065005395f Merge pull request #317 from Skud/crop-hierarchy-caching
Hotfix: Added caching of full crop hierarchy
2013-09-12 18:30:36 -07:00
Skud
950a333ac7 Merge pull request #316 from Skud/crop-hierarchy-caching
Added caching of full crop hierarchy
2013-09-12 18:30:15 -07:00
Skud
8994b5f5fc Added caching of full crop hierarchy
... as that page is really slow to load at present.
2013-09-13 11:24:03 +10:00
Skud
22cb6d2ad5 Merge pull request #315 from Skud/one-more-places-fix
(hotfix) Removed deploy script reminders, as no longer necessary
2013-09-12 05:07:21 -07:00
Skud
dbe542f3d2 Merge pull request #314 from Skud/one-more-places-fix
Removed deploy script reminders, as no longer necessary
2013-09-12 05:06:32 -07:00
Skud
c64499881d Removed deploy script reminders, as no longer necessary 2013-09-12 22:05:35 +10:00
Skud
b02091bc00 Merge pull request #313 from Growstuff/dev
Production push: places
2013-09-12 05:03:21 -07:00
Skud
32e49355ff Merge pull request #312 from Skud/one-more-places-fix
removed marker bounds on hover
2013-09-12 04:46:35 -07:00
Skud
f753211096 removed marker bounds on hover 2013-09-12 21:44:42 +10:00
Skud
32614da4ea Merge pull request #311 from Skud/pretty-maps
use a different, greener cloudmade tileset for maps
2013-09-11 02:19:58 -07:00
Skud
d345a082c8 use a different, greener cloudmade tileset for maps 2013-09-11 19:19:23 +10:00
Skud
191c86f0d5 Merge pull request #310 from Skud/final-places-fixes-really-truly
Final places fixes really truly
2013-09-11 01:22:23 -07:00
Skud
35f3ee8948 limit things-to-map to those with locations (duh) 2013-09-11 18:20:43 +10:00
Skud
e3c736927f removed spurious debug message from places/index 2013-09-11 18:17:19 +10:00
Skud
8f15b30eb7 Merge branch 'master' of heroku.growstuff:growstuff-dev into dev
Conflicts:
	app/assets/javascripts/places.js.erb
2013-09-11 18:12:15 +10:00
Skud
f6c6aa1051 Merge pull request #309 from Skud/places3
Places - one more try!
2013-09-11 01:10:37 -07:00
Skud
e7436de1e1 Merge branch 'places3' of github.com:Skud/growstuff into places3
Conflicts:
	app/assets/javascripts/places.js.erb
2013-09-11 18:08:46 +10:00
Skud
7e65af532d Set Leaflet icon path explicitly.
When we tried to deploy maps on staging, we got the following error
message in our Javascript console:

Error: Couldn't autodetect L.Icon.Default.imagePath, set it manually.

... so we did. The end.
2013-09-11 18:05:38 +10:00
Skud
a75ed5090a Hardcode Cloudmade API key.
Ugh, I know. But it's not any less secure than having it out there in
our Javascript, and it turns out Heroku just downright *refuses* to read
it from an environment variable during asset compilation. I even tried
an experimental Heroku addon
(https://devcenter.heroku.com/articles/labs-user-env-compile) but it
didn't work, so for now let's just do this and get it out there. I'm
sick of messing with it.
2013-09-11 18:03:19 +10:00
Skud
9cd9fa02f6 Merge branch 'master' of heroku.growstuff:growstuff-dev into places3 2013-09-11 17:33:57 +10:00
Skud
8a203deb19 Use experimental user-env-compile heroku addon
It seems that heroku generally denies us access to ENV['...'] during asset
compilation. They have reasonably good reasons for this, and yet I don't
know how else we're meant to get at our API keys (other than hardcoding
them into our config files, which we don't want to do).

So, to work around this, I'm recommending the use of the (experimental,
subject to removal/change, sigh) user-env-compile heroku addon.  This
lets us use ENV during asset compilation.

For more info see
https://devcenter.heroku.com/articles/labs-user-env-compile
2013-09-11 17:32:31 +10:00
Skud
f929f33844 experimenting with tainted vars, again. revert this later. 2013-09-11 16:58:52 +10:00
Skud
8b65ad5b8f experimenting with tainted vars. revert this later. 2013-09-11 16:54:03 +10:00
Skud
75d8b472d1 do env vars show up in the js? 2013-09-11 16:47:11 +10:00
Skud
90f3f0e17c still trying to get cloudmade key working (should be reverted later) 2013-09-11 16:35:20 +10:00
Skud
3582abab73 debugging output for cloudmade key (needs to be reverted later) 2013-09-11 16:29:04 +10:00
Skud
481ef2c4d1 further adventures in finding the cloudmade_key 2013-09-11 16:23:27 +10:00
Skud
541031707f Merge branch 'master' of heroku.growstuff:growstuff-dev into places3 2013-09-11 16:16:27 +10:00
Skud
67a0af3d87 Moved all ERB processing to the outside of functions
I'm not sure if this will do anything or not, but I can't figure out why
else the email address would have been getting inserted by ERB but the
cloudmade key wouldn't be.
2013-09-11 16:14:53 +10:00
Skud
af9023f87e Merge pull request #308 from Skud/places3
Made a config variable for cloudmade_key
2013-09-10 21:28:44 -07:00
Skud
c58a24f851 Made a config variable for cloudmade_key
(because the assets pipeline doesn't seem to want to deal direct with
ENV variables.)
2013-09-11 14:26:56 +10:00
Skud
b39df447b6 Merge pull request #307 from Skud/places3
Places - finally fixed?
2013-09-10 21:00:54 -07:00
Skud
7a57b4818f fixed js == vs === as per sabreuse's recommendation 2013-09-11 14:00:30 +10:00
Skud
80b9285727 reinstate @place instance variable for title 2013-09-11 13:19:51 +10:00
Skud
138318e5f4 Moved searching for nearby members into the model 2013-09-11 13:14:52 +10:00
Skud
7d5643e30d Sort nearby members by distance
Also removed distance/units from the places/show search, since you can
adjust nearness by zooming etc.

At this point the "members near here" stuff at the bottom of the page
exists mostly for accessibility and to give additional detail that we
don't currently show in the popups on the map.

So we're not using distance/units to search for members near here
anymore, but instead are just finding the 30 nearest members to the
specified location, and showing them in order of nearness.
2013-09-11 12:41:01 +10:00
Skud
3cd48f751e Redid places/show using the all-javascript method.
Moved JSON for "what's here?" from members/index to places/index -- we
can improve this later if we want to show things other than members.
2013-09-11 12:14:18 +10:00
Skud
f201f357da reinstated map attribution 2013-09-11 10:28:19 +10:00
Skud
c02772d219 Spike: use pure javascript and JSON API to draw map 2013-09-09 22:15:47 +10:00
pozorvlak
658d46ccf0 Merge pull request #304 from Skud/crop-hierarchy-page
Crop hierarchy page
2013-09-05 05:42:47 -07:00
pozorvlak
0d922acd56 Merge pull request #305 from Skud/explanatory-text
Added explanatory text to the top of the crops/seeds pages
2013-09-05 05:42:26 -07:00
Miles Gould
0bb482d181 Use Leaflet marker clusters.
Doesn't work - clusters don't spiderfy at max zoom, show their
boundaries on hover or split when you get close to them.
2013-09-05 13:40:20 +01:00
Miles Gould
d6972da84f Speed up geocoding/deal better with slow geocoding.
- set limit=1
 - set timeout=10s
2013-09-05 13:10:47 +01:00
Miles Gould
67ed1e2170 Set map height in CSS; smaller for phones.
In future we should consider making classes for different sizes of maps.
2013-09-05 12:25:45 +01:00
Skud
be6d6fd6bd Added a crop hierarchy link to the crop wrangler page 2013-09-02 12:07:58 +10:00
Skud
9e190d7345 Show new hierarchical varieties on crop page 2013-09-02 12:03:28 +10:00
Skud
cf9c1d7aa3 Make all list items use disc style (filled-in circle) 2013-09-02 12:02:34 +10:00
Skud
995f9b2d60 Display crop hierarchy (recursively!) 2013-09-02 12:01:58 +10:00
Skud
4dbfecd315 Added toplevel scope for crops without a parent 2013-09-02 11:52:01 +10:00
Skud
772eec77a7 added routes and controller stuff for crop hierarchy 2013-09-02 11:13:02 +10:00
Skud
a0e81b4570 Added explanatory text to the top of the crops/seeds pages 2013-09-02 11:04:49 +10:00
pozorvlak
3beb2e27f2 Merge pull request #292 from pozorvlak/places2
Added "places" pages to show maps of where members are
2013-08-31 08:12:27 -07:00
Miles Gould
71ea2b0485 Remove "\/" from escaped JavaScript to prevent test errors.
We were getting annoying "couldn't close <p> with </script>" messages
when running tests, because escape_javascript was turning </p> into
<\/p>. We fixed this by gsub'ing \/ to / after calling
escape_javascript. What could possibly go wrong? :-)
2013-08-31 16:07:27 +01:00
Miles Gould
4701bd1b2e Merge branch 'dev' into places2
Conflicts:
	Gemfile.lock
	config/application.rb
	credentials.example
2013-08-31 15:49:30 +01:00
martyhines
b49d548240 Escape pop-up text in place/show 2013-08-31 15:43:25 +01:00
pozorvlak
fd24680a16 Merge pull request #301 from attlebish/hidecrops
Hidecrops
2013-08-31 06:21:00 -07:00
Miles Gould
d9cb1cba89 Merge branch 'bulb' into dev 2013-08-30 12:01:43 +01:00
Miles Gould
087c2c5834 Remove extra whitespace. 2013-08-30 11:59:59 +01:00
pozorvlak
b211e34cd6 Merge pull request #302 from Skud/planting-help
added help text/links to planting form
2013-08-30 03:51:32 -07:00
Skud
ffeda3007a added help text/links to planting form 2013-08-30 16:37:59 +10:00
Lilly
0c45fde749 Hide members when in mobile view 2013-08-30 15:53:16 +10:00
Lilly
310b40aace Hide crops when in mobile view 2013-08-30 15:47:36 +10:00
Lilly
5c4ee581cc Added 'bulb' as a 'planted_from' option. 2013-08-30 15:08:23 +10:00
Miles Gould
2c6e2ee2d7 Merge branch 'dev' into places2
Conflicts:
	app/views/members/_popover.html.haml
2013-08-28 13:02:25 +01:00
Miles Gould
ca236ce7fd Improve readability of controllers/places slightly. 2013-08-28 12:24:12 +01:00
Miles Gould
24f306e8ef Set User-Agent in Geocoder requests; delete custom nominatim lib.
Nominatim-the-service's license requires that we identify ourselves.
The custom nominatim lib is no longer required since Geocoder is now
Fast Enough.
2013-08-28 12:08:19 +01:00
Miles Gould
c955504ad7 Reinstate Geocoder lookup
Direct Nominatim lookups were playing badly with "nearby" method in
testing. The slowness is largely fixed in the HEAD revision of Geocoder.
2013-08-28 12:00:58 +01:00
Skud
af3d6a50a3 Fixed CSS problem with popup tip
The little triangle underneath the popup was looking weird.  Turns out
it was mostly because of some of the leaflet_ie.css stuff, so we made
sure that the non-IE CSS took precedence, and wrote in a little override
for an unwanted border as well.
2013-08-26 11:06:21 +10:00
Miles Gould
bce0fe23c0 Replace string keys with symbols in Nominatim spec.
We're using symbol keys in the actual code, and hence should probably
use test data of the same format.
2013-08-23 17:19:20 +01:00
Miles Gould
ef73e712ba Remove nominatum.rb's dependence on Rails
The user_agent and user_agent_email are now set as class instance
variables in config/initializers/nominatim.rb.
2013-08-23 17:00:19 +01:00
Miles Gould
aa73a07e5f Add in_testing config option to Nominatum
Checking against Rails.env.test? fails on Travis.
2013-08-23 16:37:43 +01:00
Miles Gould
dfa3c410fc Show names of members in popovers in places/ 2013-08-23 14:37:29 +01:00
Miles Gould
60ddc82d9f Credit OpenStreetMap under ODbL.
- broke map attributions into a partial
2013-08-23 14:36:30 +01:00
Miles Gould
8ce2798fb3 Fail gracefully if location is not found. 2013-08-23 14:12:04 +01:00
Miles Gould
89fa16f5b3 Re-add member name to popups; fix escaping problems. 2013-08-23 14:04:43 +01:00
Miles Gould
251a45a441 Add a User-Agent to Nominatum requests
- unified repeated config into config/application.rb
 - removed superfluous calls to Growstuff::Application.config
2013-08-23 14:03:46 +01:00
Miles Gould
7857bfd0df Merge branch 'dev' into places2
Fix up broken indentation on navbar.
Conflicts:
	app/views/layouts/_header.html.haml
2013-08-23 13:29:37 +01:00
Miles Gould
4e62991f22 Replace Geocoder lookups with direct calls to Nominatim.
This is because Geocoder-via-Nominatim was really really slow (up to
10s).
2013-08-23 13:11:02 +01:00
Skud
57fe663675 Merge branch 'dev' of https://github.com/Growstuff/growstuff into places2
Conflicts:
	app/controllers/members_controller.rb
	app/models/member.rb
	app/views/members/_popover.html.haml
	spec/models/member_spec.rb
2013-08-21 17:35:31 +10:00
Skud
e54697189f look up nominatim directly 2013-08-13 12:31:19 +10:00
Skud
afc57db8d3 Added links to places pages
Committing with broken tests and pushing to github just so people can
take a look at what we're doing.
2013-08-12 13:38:20 +10:00
Skud
5cc1ab2ab5 switched geocoding from google to openstreetmaps 2013-08-12 13:00:54 +10:00
Skud
d30f8e443e added popovers, added map on places/show page 2013-08-12 12:36:09 +10:00
Skud
be9bc4ba4d added 'Places' to top nav 2013-08-12 10:48:06 +10:00
Skud
32f2830df5 changed located scope to ignore blank lat/long 2013-08-12 10:46:35 +10:00
Ryan Clark
23f8848773 Added markers for member locations 2013-08-06 19:52:29 -07:00
Ryan Clark
fe00146f22 Added map to places/index 2013-08-06 19:38:11 -07:00
Joseph Caudle
a43d3a1ce7 Add places pages
This commit builds off of @Skud's spike on locations and largely takes
off from the `nearby_members` feature which previously existed on
members.

One thing to note is that we needed to add a search route and action to
`PlacesController` to account for requests of new places as they could
not be redirected to properly from within `PlacesController#show`.

[Story #53848631]
2013-08-02 00:15:51 -04:00
74 changed files with 703 additions and 435 deletions

View File

@@ -6,6 +6,8 @@ gem 'rails', '3.2.13'
gem 'rack', '~>1.4.5'
gem 'json', '~>1.7.7'
gem 'haml'
gem 'leaflet-rails'
gem 'leaflet-markercluster-rails'
gem 'unicorn' # http server
gem 'cancan' # for checking member privileges
@@ -87,7 +89,9 @@ gem 'friendly_id'
gem 'gravatar-ultimate'
# For geolocation
gem 'geocoder'
gem 'geocoder',
:git => 'https://github.com/alexreisner/geocoder.git',
:ref => '104d46'
# For easy calendar selection
gem 'bootstrap-datepicker-rails'

View File

@@ -1,3 +1,10 @@
GIT
remote: https://github.com/alexreisner/geocoder.git
revision: 104d466ba7097b7dce5ba19f8e4091b7f69ccdf6
ref: 104d46
specs:
geocoder (1.1.8)
GIT
remote: https://github.com/seyhunak/twitter-bootstrap-rails.git
revision: 2c7c527c354d9068ce49346d4fd8389328d32ce6
@@ -105,7 +112,6 @@ GEM
flickraw (0.9.6)
friendly_id (4.0.9)
fssm (0.2.10)
geocoder (1.1.8)
gibbon (1.0.0)
httparty
multi_json (>= 1.3.4)
@@ -129,6 +135,9 @@ GEM
thor (>= 0.14, < 2.0)
json (1.7.7)
kgio (2.8.0)
leaflet-markercluster-rails (0.6.0)
railties (>= 3.1)
leaflet-rails (0.6.2)
less (2.3.2)
commonjs (~> 0.2.6)
less-rails (2.3.3)
@@ -257,13 +266,15 @@ DEPENDENCIES
factory_girl_rails (~> 4.0)
flickraw
friendly_id
geocoder
geocoder!
gibbon
gravatar-ultimate
haml
haml-rails
jquery-rails
json (~> 1.7.7)
leaflet-markercluster-rails
leaflet-rails
less-rails
memcachier
newrelic_rpm

View File

@@ -10,6 +10,8 @@
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require leaflet
//= require leaflet.markercluster
//= require jquery
//= require jquery_ujs
//= require twitter/bootstrap

View File

@@ -0,0 +1,48 @@
places_base_path = "/places";
things_to_map = location.pathname + '.json';
cloudmade_key = "<%= Growstuff::Application.config.cloudmade_key %>";
cloudmade_url = "http://{s}.tile.cloudmade.com/" + cloudmade_key + "/73038/256/{z}/{x}/{y}.png";
nominatim_base_url = 'http://nominatim.openstreetmap.org/search/';
nominatim_user_agent_email = "<%= Growstuff::Application.config.user_agent_email %>";
L.Icon.Default.imagePath = '/assets'
if (location.pathname === places_base_path) { //places index page
map = L.map('map').setView([0.0, -0.0], 2);
showMap(map);
} else { // specific place page
place = location.pathname.replace(places_base_path + "/", '');
nominatim_query_url = nominatim_base_url + place;
nominatim_options = {
format: "json",
callback: "placeholder",
limit: 1,
email: nominatim_user_agent_email
};
$.getJSON(nominatim_query_url, nominatim_options, function(data) {
map = L.map('map').setView([data[0].lat, data[0].lon], 5);
showMap(map);
})
}
function showMap(map) {
L.tileLayer(cloudmade_url, {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors under <a href="http://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="http://cloudmade.com">Cloudmade</a>',
maxZoom: 18
}).addTo(map);
markers = new L.MarkerClusterGroup({showCoverageOnHover: false});
$.getJSON(things_to_map, function(members) {
$.each(members, function(i, m) {
if (m.latitude && m.longitude) {
marker = new L.Marker(new L.LatLng(m.latitude, m.longitude));
link = "<p><a href='/members/" + m.login_name + "'>" + m.login_name + "</a></p>";
where = "<p><i>" + m.location + "</i></p>";
marker.bindPopup(link + where).openPopup();
markers.addLayer(marker);
}
});
});
map.addLayer(markers);
}

View File

@@ -3,6 +3,10 @@
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require_tree .
*= require bootstrap-datepicker
*= require leaflet.ie
*= require leaflet
*= require leaflet.markercluster
*= require leaflet.markercluster.default
*= require_tree .
*/

View File

@@ -1,4 +1,11 @@
@import "twitter/bootstrap/bootstrap";
// this padding needs to be done before the responsive stuff is imported
body {
padding-top: @navbarHeight + 10px;
padding-bottom: @navbarHeight + 10px;
}
@import "twitter/bootstrap/responsive";
// Set the correct sprite paths
@@ -77,10 +84,7 @@
@dropdownLinkColorHover: @brown;
@dropdownLinkBackgroundHover: lighten(@green, 50%);
body {
padding-top: @navbarHeight + 10px;
padding-bottom: @navbarHeight + 10px;
}
ul.inline > li.first {
padding-left: 0px;
}
@@ -147,6 +151,10 @@ p.stats {
margin-left: 0px;
}
#map {
height: 500px;
}
// Overrides applying only to mobile view
@media only screen and (max-width: 767px) {
@@ -155,4 +163,12 @@ p.stats {
border-left: none;
padding-left: 0;
}
#map {
height: 300px;
}
}
li.crop-hierarchy {
list-style-type: disc;
}

View File

@@ -0,0 +1,3 @@
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
border: none;
}

View File

@@ -8,34 +8,10 @@ class Admin::OrdersController < ApplicationController
def search
authorize! :manage, :all
@orders = []
@orders = Order.search({:by => params[:search_by], :for => params[:search_text]})
if params[:search_text]
case params[:search_by]
when "member"
member = Member.find_by_login_name(params[:search_text])
if member
@orders = member.orders
end
when "order_id"
order = Order.find_by_id(params[:search_text])
if order
@orders = [order]
end
when "paypal_token"
order = Order.find_by_paypal_express_token(params[:search_text])
if order
@orders = [order]
end
when "paypal_payer_id"
order = Order.find_by_paypal_express_payer_id(params[:search_text])
if order
@orders = [order]
end
end
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
respond_to do |format|

View File

@@ -1,5 +1,6 @@
class CropsController < ApplicationController
load_and_authorize_resource
skip_authorize_resource :only => :hierarchy
cache_sweeper :crop_sweeper
@@ -15,7 +16,7 @@ class CropsController < ApplicationController
end
end
# GET /wrangle
# GET /crops/wrangle
def wrangle
@crops = Crop.recent.paginate(:page => params[:page])
@@ -24,6 +25,14 @@ class CropsController < ApplicationController
end
end
# GET /crops/hierarchy
def hierarchy
@crops = Crop.toplevel
respond_to do |format|
format.html
end
end
# GET /crops/1
# GET /crops/1.json
def show

View File

@@ -32,31 +32,4 @@ class MembersController < ApplicationController
end
end
def nearby
if !params[:location].blank?
@location = params[:location]
elsif current_member
@location = current_member.location
else
@location = nil
end
if !params[:distance].blank?
@distance = params[:distance]
else
@distance = 100
end
if params[:units] == "mi"
@units = :mi
else
@units = :km
end
@nearby_members = @location ? Member.near(@location, @distance, :units => @units) : []
respond_to do |format|
format.html # nearby.html.haml
end
end
end

View File

@@ -32,24 +32,28 @@ class OrdersController < ApplicationController
def checkout
@order = Order.find(params[:id])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
:items => @order.activemerchant_items,
:currency => Growstuff::Application.config.currency,
:no_shipping => true,
:ip => request.remote_ip,
:return_url => complete_order_url,
:cancel_return_url => shop_url
)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
respond_to do |format|
if @order.update_attributes(:referral_code => params[:referral_code])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
:items => @order.activemerchant_items,
:currency => Growstuff::Application.config.currency,
:no_shipping => true,
:ip => request.remote_ip,
:return_url => complete_order_url,
:cancel_return_url => shop_url
)
format.html { redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token) }
else
format.html { render action: "show" }
end
end
end
def complete
@order = Order.find(params[:id])
@order.save
if (params[:token] && params['PayerID'])
purchase = EXPRESS_GATEWAY.purchase(
@order.total,

View File

@@ -0,0 +1,31 @@
class PlacesController < ApplicationController
skip_authorize_resource
def index
respond_to do |format|
format.html
# json response is whatever we want to map here
format.json { render :json => Member.located.to_json(:only => [:id, :login_name, :location, :latitude, :longitude]) }
end
end
# GET /places/london
# GET /places/london.json
def show
@place = params[:place] # used for page title
@nearby_members = Member.nearest_to(params[:place])
respond_to do |format|
format.html # show.html.haml
format.json { render :json => @nearby_members.to_json(:only => [:id, :login_name, :location, :latitude, :longitude]) }
end
end
def search
respond_to do |format|
format.html do
redirect_to place_path(params[:new_place])
end
end
end
end

View File

@@ -14,6 +14,7 @@ class Crop < ActiveRecord::Base
default_scope order("lower(system_name) asc")
scope :recent, reorder("created_at desc")
scope :toplevel, where(:parent_id => nil)
scope :randomized, reorder('random()') # ok on sqlite and psql, but not on mysql
validates :en_wikipedia_url,

View File

@@ -4,6 +4,7 @@ class CropSweeper < ActionController::Caching::Sweeper
def after_create(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
def after_update(crop)
@@ -13,6 +14,7 @@ class CropSweeper < ActionController::Caching::Sweeper
def after_destroy(crop)
expire_fragment('homepage_stats')
expire_fragment('recent_crops')
expire_fragment('full_crop_hierarchy')
end
end

View File

@@ -26,7 +26,7 @@ class Member < ActiveRecord::Base
default_scope order("lower(login_name) asc")
scope :confirmed, where('confirmed_at IS NOT NULL')
scope :located, where("location <> ''")
scope :located, where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL")
scope :recently_signed_in, reorder('updated_at DESC')
scope :wants_newsletter, where(:newsletter => true)
@@ -204,10 +204,28 @@ class Member < ActiveRecord::Base
return interesting_members
end
def Member.nearest_to(place)
nearby_members = []
if place
latitude, longitude = Geocoder.coordinates(place, params: {limit: 1})
if latitude && longitude
nearby_members = Member.located.sort_by { |x| x.distance_from([latitude, longitude]) }
end
end
return nearby_members
end
private
def geocode
unless self.location.blank?
self.latitude, self.longitude =
Geocoder.coordinates(location, params: {limit: 1})
end
end
def empty_unwanted_geocodes
if self.location.to_s == ''
if self.location.blank?
self.latitude = nil
self.longitude = nil
end

View File

@@ -1,11 +1,18 @@
class Order < ActiveRecord::Base
attr_accessible :member_id, :completed_at
attr_accessible :member_id, :completed_at, :referral_code
belongs_to :member
has_many :order_items, :dependent => :destroy
default_scope order('created_at DESC')
validates :referral_code, :format => {
:with => /\A[a-zA-Z0-9 ]*\z/,
:message => "may only include letters and numbers"
}
before_save :standardize_referral_code
# total price of an order
def total
sum = 0
@@ -45,4 +52,46 @@ class Order < ActiveRecord::Base
end
end
# removes whitespace and forces to uppercase (we're somewhat liberal
# in what we accept, but we clean it up anyway.)
def standardize_referral_code
if referral_code
self.referral_code = referral_code.upcase.gsub /\s/, ''
end
end
# search orders (used by admin/orders)
# usage: Order.search({ :by => 'member', :for => 'Skud' })
# can search by: member, order_id, paypal_token, paypal_payer_id,
def Order.search(args={})
if args[:for]
case args[:by]
when "member"
member = Member.find_by_login_name(args[:for])
if member
return member.orders
end
when "order_id"
order = Order.find_by_id(args[:for])
if order
return [order]
end
when "paypal_token"
order = Order.find_by_paypal_express_token(args[:for])
if order
return [order]
end
when "paypal_payer_id"
order = Order.find_by_paypal_express_payer_id(args[:for])
if order
return [order]
end
when "referral_code"
# coerce to uppercase
return Order.where(:referral_code => args[:for].upcase)
end
end
return []
end
end

View File

@@ -39,6 +39,7 @@ class Planting < ActiveRecord::Base
'cutting',
'root division',
'runner',
'bulb',
'bare root plant',
'advanced plant',
'graft',

View File

@@ -1,5 +1,5 @@
= form_tag(url_for(:controller => 'admin/orders', :action => 'search'), :method => :get, :class => 'form-inline') do
= label_tag :distance, "Search orders:", :class => 'control-label'
= text_field_tag :search_text
= select_tag :search_by, options_for_select({'Member' => 'member', 'Order ID' => 'order_id', 'Paypal Token' => 'paypal_token', 'Paypal Payer ID' => 'paypal_payer_id' })
= select_tag :search_by, options_for_select({'Member' => 'member', 'Referral code' => 'referral_code', 'Order ID' => 'order_id', 'Paypal Token' => 'paypal_token', 'Paypal Payer ID' => 'paypal_payer_id' })
= submit_tag "Search", :class => 'btn btn-primary'

View File

@@ -12,6 +12,7 @@
%th Member
%th Order number
%th Date completed
%th Referral code
%th Items
%th
@@ -24,6 +25,8 @@
= order.completed_at.to_s
- else
In progress
%td
= order.referral_code
%td
- if order.order_items.count > 0
- order.order_items.each do |o|

View File

@@ -0,0 +1,7 @@
%ul
- display_crops.each do |c|
%li.crop-hierarchy
= link_to c, c
- if c.varieties.present?
- c.varieties.each do |v|
= render :partial => 'hierarchy', :locals => { :display_crops => [ v ] }

View File

@@ -6,7 +6,5 @@
= link_to crop.parent, crop.parent
- if crop.varieties.count > 0
%p
Varieties of
= succeed ":" do
= crop.system_name
!= crop.varieties.map{ |c| link_to c, c }.join(", ")
Varieties:
= render :partial => 'hierarchy', :locals => { :display_crops => [ crop ] }

View File

@@ -0,0 +1,9 @@
- content_for :title, "Crop Hierarchy"
%p
This page shows the hierarchical tree of all crops in our
= succeed "." do
= link_to "crops database", crops_path
- cache("full_crop_hierarchy") do
= render :partial => "hierarchy", :locals => { :display_crops => @crops }

View File

@@ -1,5 +1,10 @@
- content_for :title, "Crops"
%p
#{Growstuff::Application.config.site_name} tracks who's growing what, where.
View any crop page to see which of our members have planted it and find
information on how to grow it yourself.
%div.pagination
= page_entries_info @crops, :model => "crops"
= will_paginate @crops

View File

@@ -5,6 +5,7 @@
%li= link_to "Requests for new crops", 'http://growstuff.org/posts/skud-20130319-requests-for-new-crops'
%li= link_to "Crop wrangler guidelines", "http://wiki.growstuff.org/index.php/Crop_wrangling"
%li= link_to "crop-wranglers mailing list", "http://lists.growstuff.org/listinfo/crop-wranglers"
%li= link_to "Full crop hierarchy", crops_hierarchy_path
%li= link_to "Add Crop", new_crop_path
%h2 Recently added crops

View File

@@ -1,5 +1,5 @@
.row-fluid
.span6
.span6.hidden-phone
- cache "interesting_crops", :expires_in => 1.day do
%h2 Some of our crops
- Crop.interesting.each do |c|

View File

@@ -1,17 +1,13 @@
- cache "interesting_members" do
- members = Member.interesting.first(6)
- if members.present?
%h2 Some of our members
.visible-desktop.visible-tablet
- members = Member.interesting.first(6)
- if members.present?
%h2 Some of our members
.visible-desktop.visible-tablet
.row-fluid
- members.each do |m|
.span6.homepage-members
= render :partial => "members/thumbnail", :locals => { :member => m }
.visible-phone
- members.each do |m|
= render :partial => "members/thumbnail", :locals => { :member => m }
%p.text-right
= link_to "View all members »", members_path
%p.text-right
= link_to "View all members »", members_path

View File

@@ -1,12 +1,11 @@
.container
.navbar.navbar-fixed-bottom
.navbar-inner
.container
%ul.nav
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
%li= link_to "Support/FAQ", url_for(:controller => '/support')
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"
.navbar.navbar-fixed-bottom
.navbar-inner
.container
%ul.nav
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
%li= link_to "Support/FAQ", url_for(:controller => '/support')
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"

View File

@@ -10,6 +10,7 @@
%ul.nav
%li= link_to "Crops", crops_path
%li= link_to "Seeds", seeds_path
%li= link_to "Places", places_path
%li.dropdown<
%a.dropdown-toggle{'data-toggle' => 'dropdown', :href => members_path}
Community
@@ -19,7 +20,7 @@
%li= link_to "Posts", posts_path
%li= link_to "Forums", forums_path
%li.divider-vertical
%li.divider-vertical
- if member_signed_in?
%li.dropdown<
@@ -29,24 +30,24 @@
- else
Your Stuff
%b.caret
%ul.dropdown-menu
%li= link_to "Profile", member_path(current_member)
%li= link_to "Gardens", gardens_by_owner_path(:owner => current_member.slug)
%li= link_to "Plantings", plantings_by_owner_path(:owner => current_member.slug)
%li= link_to "Seeds", seeds_by_owner_path(:owner => current_member.slug)
%li= link_to "Posts", posts_by_author_path(:author => current_member.slug)
%li= link_to "Account", orders_path
%li
- if current_member.notifications.unread_count > 0
= link_to("Inbox (#{current_member.notifications.unread_count})", notifications_path)
- else
= link_to("Inbox", notifications_path)
%ul.dropdown-menu
%li= link_to "Profile", member_path(current_member)
%li= link_to "Gardens", gardens_by_owner_path(:owner => current_member.slug)
%li= link_to "Plantings", plantings_by_owner_path(:owner => current_member.slug)
%li= link_to "Seeds", seeds_by_owner_path(:owner => current_member.slug)
%li= link_to "Posts", posts_by_author_path(:author => current_member.slug)
%li= link_to "Account", orders_path
%li
- if current_member.notifications.unread_count > 0
= link_to("Inbox (#{current_member.notifications.unread_count})", notifications_path)
- else
= link_to("Inbox", notifications_path)
%li= link_to "Shop", shop_path
- if current_member.has_role?(:crop_wrangler)
%li= link_to "Crop Wrangling", wrangle_crops_path
- if current_member.has_role?(:admin)
%li= link_to "Admin", admin_path
%li= link_to "Shop", shop_path
- if current_member.has_role?(:crop_wrangler)
%li= link_to "Crop Wrangling", wrangle_crops_path
- if current_member.has_role?(:admin)
%li= link_to "Admin", admin_path
%li= link_to "Sign out", destroy_member_session_path, :method => :delete

View File

@@ -17,8 +17,8 @@
= alert
= yield
%footer
= render :partial => "layouts/footer"
%footer
= render :partial => "layouts/footer"
/
Javascripts
\==================================================

View File

@@ -13,4 +13,3 @@
= pluralize(member.plantings.size, "planting")
%br/
= pluralize(member.seeds.size, "seed")

View File

@@ -1,11 +1,5 @@
= content_for :title, "#{Growstuff::Application.config.site_name} members"
%p
- if member_signed_in? && current_member.location
= link_to "Find members near you", nearby_members_path
- else
= link_to "Find members by location", nearby_members_path
%div.pagination
= page_entries_info @members, :model => "members"
= will_paginate @members

View File

@@ -44,12 +44,9 @@
- if @member.location.to_s != ''
%h4 Location
%p
= image_tag("http://maps.google.com/maps/api/staticmap?size=200x200&maptype=roadmap&sensor=false&markers=color:green|label:A|#{@member.latitude},#{@member.longitude}&zoom=12", :alt => "Map showing #{@member.location}", :width => 200, :height => 200 )
= link_to image_tag("http://maps.google.com/maps/api/staticmap?size=200x200&maptype=roadmap&sensor=false&markers=color:green|label:A|#{@member.latitude},#{@member.longitude}&zoom=12", :alt => "Map showing #{@member.location}", :width => 200, :height => 200 ), place_path(@member.location)
%br/
Location:
= @member.location
%br/
= link_to 'Find members near here', nearby_members_path(:location => @member.location)
= link_to @member.location, place_path(@member.location)
.span9
%p

View File

@@ -12,18 +12,23 @@
%strong Date begun:
= @order.created_at.to_s
%p
- if @order.completed_at
- if @order.completed_at
%p
%strong Date completed:
= @order.completed_at.to_s
- if current_member.has_role? :admin
%p
%strong Paypal Express token:
= @order.paypal_express_token
%p
%strong Paypal Express payer ID:
= @order.paypal_express_payer_id
- if @order.referral_code
%p
%strong Referral code:
= @order.referral_code
- if current_member.has_role? :admin
%p
%strong Paypal Express token:
= @order.paypal_express_token
%p
%strong Paypal Express payer ID:
= @order.paypal_express_payer_id
%h2 Order items
@@ -53,12 +58,24 @@
= price_with_currency(@order.total)
= forex_link(@order.total)
%p
- if can? :destroy, @order
= link_to 'Delete this order', @order, method: :delete, |
data: { confirm: 'Are you sure?' }, :class => 'btn'
- if can? :complete, @order
= link_to 'Checkout with PayPal', checkout_order_path(@order), :class => 'btn btn-primary'
- if @order.errors.any?
.alert
#error_explanation
%h3= "#{pluralize(@order.errors.count, "error")} stopped you from checking out:"
%ul
- @order.errors.full_messages.each do |msg|
%li= msg
- if can? :complete, @order or can? :destroy, @order
= form_tag(checkout_order_path(@order), :method => :get, :class => 'form-inline') do
%p
- if can? :complete, @order
= label_tag :referral_code, "Do you have a referral code?"
= text_field_tag :referral_code, @order.referral_code, :class => 'input-medium'
= submit_tag "Checkout with PayPal", :class => 'btn btn-primary'
- if can? :destroy, @order
= link_to 'Delete this order', @order, method: :delete, |
data: { confirm: 'Are you sure?' }, :class => 'btn'
= link_to "View other orders/order history", orders_path, :class => 'btn'
%p
= link_to "View other orders/order history", orders_path

View File

@@ -0,0 +1,6 @@
Map data &copy;
= link_to "OpenStreetMap", "http://openstreetmap.org"
contributors under
= link_to "ODbL", "http://www.openstreetmap.org/copyright"
| Imagery &copy;
= link_to "CloudMade", "http://cloudmade.com"

View File

@@ -0,0 +1,4 @@
-content_for :title, "Places"
%div#map

View File

@@ -0,0 +1,20 @@
-content_for :title, @place
= form_tag(search_places_path, :method => :get, :class => 'form-inline') do
= label_tag :place, "Change location:", :class => 'control-label'
= text_field_tag :new_place
= submit_tag "Search", :class => 'btn btn-primary'
%div#map{ :style => "height:300px"}
%h3
= Growstuff::Application.config.site_name
members near #{@place}
- if !@nearby_members.empty?
%ul.thumbnails
- @nearby_members.first(30).each do |member|
%li.span4.three-across
= render :partial => "members/thumbnail", :locals => { :member => member }
- elsif @place
%p No results found

View File

@@ -8,11 +8,17 @@
.control-group
= f.label 'What did you plant?', :class => 'control-label'
.controls= collection_select(:planting, :crop_id, Crop.all, :id, :system_name, :selected => @planting.crop_id || @crop.id)
.controls
= collection_select(:planting, :crop_id, Crop.all, :id, :system_name, :selected => @planting.crop_id || @crop.id)
%span.help-inline
Can't find what you're looking for?
= link_to "Request new crops.", Growstuff::Application.config.new_crops_request_link
.control-group
= f.label 'Where did you plant it?', :class => 'control-label'
.controls= collection_select(:planting, :garden_id,
Garden.where(:owner_id => current_member), :id, :name, :selected => @planting.garden_id || @garden.id)
.controls
= collection_select(:planting, :garden_id, Garden.where(:owner_id => current_member), :id, :name, :selected => @planting.garden_id || @garden.id)
%span.help-inline
= link_to "Add a garden.", new_garden_path
.control-group
= f.label 'When?', :class => 'control-label'
.controls= f.text_field :planted_at, :value => @planting.planted_at ? @planting.planted_at.to_s(:ymd) : '', :class => 'add-datepicker'

View File

@@ -32,7 +32,7 @@
- else
from
=succeed "." do
= current_member.location
= link_to current_member.location, place_path(current_member.location)
=link_to "Change your location.", edit_member_registration_path
%span.help-block
Are you interested in trading or swapping seeds with other

View File

@@ -1,5 +1,9 @@
- content_for :title, @owner ? "#{@owner}'s seeds" : "Everyone's seeds"
%p
#{Growstuff::Application.config.site_name} helps you track your seed
stash or trade seeds with other members.
%p
- if can? :create, Seed
- if @owner
@@ -43,7 +47,10 @@
%td= seed.tradable? ? seed.tradable_to : ''
%td
- if seed.tradable?
= seed.owner.location.blank? ? "unspecified" : seed.owner.location
- if seed.owner.location.blank?
unspecified
- else
= link_to seed.owner.location, place_path(seed.owner.location)
%td= link_to 'Details', seed, :class => 'btn btn-mini'
%div.pagination

View File

@@ -23,7 +23,7 @@
- else
(from
= succeed ")" do
= @seed.owner.location
= link_to @seed.owner.location, place_path(@seed.owner.location)
%p
%b Description:

View File

@@ -78,10 +78,27 @@ module Growstuff
:openssl_verify_mode => 'none'
}
# Growstuff-specific configuration variables
config.currency = 'AUD'
config.bot_email = "noreply@growstuff.org"
config.user_agent = 'Growstuff'
config.user_agent_email = "info@growstuff.org"
Gibbon::API.api_key = ENV['MAILCHIMP_APIKEY']
Gibbon::API.timeout = 10
Gibbon::API.throws_exceptions = false
config.newsletter_list_id = ENV['MAILCHIMP_NEWSLETTER_ID']
config.cloudmade_key = '29a2d9e3cb3d429490a8f338b2388b1d'
# This is Growstuff's global Cloudmade key. If you fork Growstuff for
# another project/website not run by the folks at http://growstuff.org/,
# then please change this key. (You can get one of your own at
# http://account.cloudmade.com/ and it's free/gratis for up to 500k tiles.)
# We'd much prefer to set this as an environment variable (as we do
# with most other things) but it turns out those aren't available at
# asset compile time on Heroku, when we need this to insert into our
# Javascript. Sigh. And yes, we know about user-env-compile but it
# didn't work for us.
config.cloudmade_key = '29a2d9e3cb3d429490a8f338b2388b1d'
end
end

View File

@@ -39,6 +39,7 @@ Growstuff::Application.configure do
config.assets.debug = true
# Growstuff config
config.new_crops_request_link = "http://example.com/not-a-real-url"
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
@@ -51,12 +52,8 @@ Growstuff::Application.configure do
}
config.action_mailer.delivery_method = :smtp
Growstuff::Application.configure do
config.site_name = "Growstuff (dev)"
config.analytics_code = ''
config.currency = 'AUD'
config.bot_email = "noreply@growstuff.org"
end
config.site_name = "Growstuff (dev)"
config.analytics_code = ''
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :test

View File

@@ -66,6 +66,7 @@ Growstuff::Application.configure do
# config.active_record.auto_explain_threshold_in_seconds = 0.5
# Growstuff configuration
config.new_crops_request_link = "http://growstuff.org/posts/skud-20130319-requests-for-new-crops"
config.action_mailer.default_url_options = { :host => 'growstuff.org' }
config.action_mailer.smtp_settings = {
@@ -78,16 +79,12 @@ Growstuff::Application.configure do
}
config.action_mailer.delivery_method = :smtp
Growstuff::Application.configure do
config.site_name = "Growstuff"
config.analytics_code = <<-eos
<script src="//static.getclicky.com/js" type="text/javascript"></script>
<script type="text/javascript">try{ clicky.init(100594260); }catch(e){}</script>
<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/100594260ns.gif" /></p></noscript>
eos
config.currency = 'AUD'
config.bot_email = "noreply@growstuff.org"
end
config.site_name = "Growstuff"
config.analytics_code = <<-eos
<script src="//static.getclicky.com/js" type="text/javascript"></script>
<script type="text/javascript">try{ clicky.init(100594260); }catch(e){}</script>
<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/100594260ns.gif" /></p></noscript>
eos
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :production

View File

@@ -66,6 +66,7 @@ Growstuff::Application.configure do
# config.active_record.auto_explain_threshold_in_seconds = 0.5
# Growstuff configuration
config.new_crops_request_link = "http://example.com/not-a-real-url"
config.action_mailer.default_url_options = { :host => 'dev.growstuff.org' }
config.action_mailer.smtp_settings = {
@@ -78,12 +79,8 @@ Growstuff::Application.configure do
}
config.action_mailer.delivery_method = :smtp
Growstuff::Application.configure do
config.site_name = "Growstuff (staging)"
config.analytics_code = ''
config.currency = 'AUD'
config.bot_email = "noreply@growstuff.org"
end
config.site_name = "Growstuff (staging)"
config.analytics_code = ''
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :test

View File

@@ -38,13 +38,13 @@ Growstuff::Application.configure do
config.active_support.deprecation = :stderr
# Growstuff config
config.new_crops_request_link = "http://example.com/not-a-real-url"
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
Growstuff::Application.configure do
config.site_name = "Growstuff (test)"
config.analytics_code = ''
config.currency = 'AUD'
config.bot_email = "noreply@growstuff.org"
end
config.after_initialize do
@@ -84,3 +84,5 @@ Geocoder::Lookup::Test.add_stub(
]
)
# Unknown location
Geocoder::Lookup::Test.add_stub( "Tatooine", [])

View File

@@ -1 +1,15 @@
Geocoder.configure(:units => :km)
Geocoder.configure(
:units => :km,
:timeout => 10,
:http_headers => {
"User-Agent" =>
"#{Growstuff::Application.config.user_agent} #{Growstuff::Application.config.user_agent_email}",
"From" => Growstuff::Application.config.user_agent_email
}
)
# This configuration takes precedence over environment/test.rb
# Reported as https://github.com/alexreisner/geocoder/issues/509
if Geocoder.config.lookup != :test
Geocoder.configure(:lookup => :nominatim)
end

View File

@@ -22,6 +22,7 @@ Growstuff::Application.routes.draw do
resources :scientific_names
match 'crops/wrangle' => 'crops#wrangle', :as => 'wrangle_crops'
match 'crops/hierarchy' => 'crops#hierarchy', :as => 'crops_hierarchy'
resources :crops
resources :comments
@@ -29,6 +30,10 @@ Growstuff::Application.routes.draw do
resources :forums
resources :notifications
get '/places' => 'places#index'
get '/places/search' => 'places#search', :as => 'search_places'
get '/places/:place' => 'places#show', :as => 'place'
# everything for paid accounts etc
resources :account_types
resources :accounts
@@ -41,67 +46,10 @@ Growstuff::Application.routes.draw do
resources :products
get "home/index"
match 'search/members/nearby' => 'members#nearby', :as => :nearby_members
root :to => 'home#index'
match 'auth/:provider/callback' => 'authentications#create'
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => 'home#index'
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
match '/policy/:action' => 'policy#:action'

View File

@@ -0,0 +1,5 @@
class AddReferralCodeToOrder < ActiveRecord::Migration
def change
add_column :orders, :referral_code, :string
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130828114516) do
ActiveRecord::Schema.define(:version => 20130913015118) do
create_table "account_types", :force => true do |t|
t.string "name", :null => false
@@ -87,11 +87,6 @@ ActiveRecord::Schema.define(:version => 20130828114516) do
add_index "gardens", ["owner_id"], :name => "index_gardens_on_user_id"
add_index "gardens", ["slug"], :name => "index_gardens_on_slug", :unique => true
create_table "gardens_members", :id => false, :force => true do |t|
t.integer "garden_id"
t.integer "member_id"
end
create_table "members", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
@@ -163,6 +158,7 @@ ActiveRecord::Schema.define(:version => 20130828114516) do
t.integer "member_id"
t.string "paypal_express_token"
t.string "paypal_express_payer_id"
t.string "referral_code"
end
create_table "orders_products", :id => false, :force => true do |t|

View File

@@ -2,4 +2,20 @@ require 'spec_helper'
describe Admin::OrdersController do
login_member(:admin_member)
describe "GET search" do
it "assigns @orders" do
order = FactoryGirl.create(:order)
get :search, {:search_by => 'order_id', :search_text => order.id}
assigns(:orders).should eq([order])
end
it "sets an error message if nothing found" do
order = FactoryGirl.create(:order)
get :search, {:search_by => 'order_id', :search_text => 'foo'}
flash[:alert].should match /Couldn't find order with/
end
end
end

View File

@@ -19,6 +19,14 @@ describe CropsController do
end
end
describe "GET crop hierarchy " do
it 'fetches the crop hierarchy page' do
get :hierarchy
response.should be_success
response.should render_template("crops/hierarchy")
end
end
describe "GET RSS feed" do
it "returns an RSS feed" do
get :index, :format => "rss"

View File

@@ -65,105 +65,4 @@ describe MembersController do
end
end
describe "GET nearby members" do
before(:each) do
@member_london = FactoryGirl.create(:london_member)
@member_south_pole = FactoryGirl.create(:south_pole_member)
end
context "when the user is logged in and has set their location" do
before(:each) do
@member = FactoryGirl.create(:london_member)
controller.stub(:current_member) { @member }
end
it "assigns the current member as nearby" do
get :nearby
assigns(:nearby_members).should include @member
end
it "assigns nearby members as nearby" do
get :nearby
assigns(:nearby_members).should include @member_london
end
it "doesn't assign far-off members as nearby" do
get :nearby
assigns(:nearby_members).should_not include @member_south_pole
end
it "gets members near the specified location if one is set" do
get :nearby, { :location => @member_south_pole.location }
assigns(:nearby_members).should include @member_south_pole
end
it "does not assign members near current_member if a location is set" do
get :nearby, { :location => @member_south_pole.location }
assigns(:nearby_members).should_not include @member_london
end
it "finds faraway members if you increase the distance" do
get :nearby, { :distance => "50000" }
assigns(:nearby_members).should include @member_south_pole
end
# Edinburgh and London are approximately 330mi/530km apart
it "finds London members within 350 miles of Edinburgh" do
get :nearby, { :distance => "350", :units => :mi, :location => "Edinburgh" }
assigns(:nearby_members).should include @member_london
end
it "doesn't find London members within 350 km of Edinburgh" do
get :nearby, { :distance => "350", :units => :km, :location => "Edinburgh" }
assigns(:nearby_members).should_not include @member_london
end
end
context "when the user is logged in but hasn't set their location" do
before(:each) do
@member = FactoryGirl.create(:member)
controller.stub(:current_member) { @member }
end
it "doesn't assign any members as nearby if no location is set" do
get :nearby
assigns(:nearby_members).should == []
end
it "assigns nearby members if a location is set" do
get :nearby, { :location => @member_london.location }
assigns(:nearby_members).should include @member_london
end
it "does not assign far members if a location is set" do
get :nearby, { :location => @member_london.location }
assigns(:nearby_members).should_not include @member_south_pole
end
end
context "when the user is not logged in" do
before(:each) do
controller.stub(:current_member) { nil }
get :nearby
end
it "doesn't assign any members as nearby if no location is set" do
get :nearby
assigns(:nearby_members).should == []
end
it "assigns nearby members if a location is set" do
get :nearby, { :location => @member_london.location }
assigns(:nearby_members).should include @member_london
end
it "does not assign far members if a location is set" do
get :nearby, { :location => @member_london.location }
assigns(:nearby_members).should_not include @member_south_pole
end
end
end
end

View File

@@ -13,6 +13,15 @@ describe OrdersController do
end
describe "GET checkout" do
it 'sets the referral_code' do
member = FactoryGirl.create(:member)
sign_in member
order = Order.create!(:member_id => member.id)
get :checkout, {:id => order.to_param, :referral_code => 'FOOBAR'}
order.reload
order.referral_code.should eq 'FOOBAR'
end
it "redirects to Paypal" do
member = FactoryGirl.create(:member)
sign_in member

View File

@@ -0,0 +1,32 @@
require 'spec_helper'
describe PlacesController do
before :each do
controller.stub(:current_member) { nil }
end
describe "GET show" do
before(:each) do
@member_london = FactoryGirl.create(:london_member)
@member_south_pole = FactoryGirl.create(:south_pole_member)
end
it "assigns place name" do
get :show, { :place => @member_london.location }
assigns(:place).should eq @member_london.location
end
it "assigns nearby members" do
get :show, { :place => @member_london.location }
assigns(:nearby_members).should eq [@member_london, @member_south_pole]
end
end
describe "GET search" do
it "redirects to the new place" do
get :search, { :new_place => "foo" }
response.should redirect_to place_path("foo")
end
end
end

View File

@@ -41,6 +41,12 @@ FactoryGirl.define do
longitude 0.004
end
factory :edinburgh_member do
location 'Edinburgh'
latitude 55.953252
longitude -3.188267
end
factory :south_pole_member do
sequence(:login_name) { |n| "ScottRF#{n}" }
location 'Amundsen-Scott Base, Antarctica'

View File

@@ -6,5 +6,9 @@ FactoryGirl.define do
factory :completed_order do
completed_at '2013-05-08 01:01:01'
end
factory :referred_order do
referral_code 'CAMPAIGN1'
end
end
end

View File

@@ -81,6 +81,12 @@ describe Crop do
@roma.parent.should eq @tomato
@tomato.varieties.should eq [@roma]
end
it 'toplevel scope works' do
@tomato = FactoryGirl.create(:tomato)
@roma = FactoryGirl.create(:roma, :parent_id => @tomato.id)
Crop.toplevel.should eq [ @tomato ]
end
end
context 'photos' do

View File

@@ -86,6 +86,13 @@ describe 'member' do
@member.longitude.should be_nil
end
it 'fails gracefully for unfound locations' do
@member.update_attributes(:location => 'Tatooine')
@member.location.should eq 'Tatooine'
@member.latitude.should be_nil
@member.longitude.should be_nil
end
end
context 'no TOS agreement' do
@@ -224,22 +231,35 @@ describe 'member' do
end
context 'located scope' do
it 'recognises non-blank locations as interesting' do
@m = FactoryGirl.create(:member, :location => 'Greenwich, UK')
Member.located.should include @m
# located members must have location, lat, long
it 'finds members who have locations' do
@london_member = FactoryGirl.create(:london_member)
Member.located.should include @london_member
end
it 'recognises nil locations as uninteresting' do
@m = FactoryGirl.create(:member, :location => nil)
Member.located.should_not include @m
it 'ignores members with blank locations' do
@nowhere_member = FactoryGirl.create(:member)
Member.located.should_not include @nowhere_member
end
it 'recognises empty string locations as uninteresting' do
@m = FactoryGirl.create(:member, :location => '')
Member.located.should_not include @m
it 'ignores members with blank lat/long' do
@london_member = FactoryGirl.create(:london_member)
@london_member.latitude = nil
@london_member.longitude = nil
@london_member.save(:validate => false)
Member.located.should_not include @london_member
end
end
context 'interesting' do
context 'near location' do
it 'finds nearby members and sorts them' do
@edinburgh_member = FactoryGirl.create(:edinburgh_member)
@london_member = FactoryGirl.create(:london_member)
Member.nearest_to('Greenwich, UK').should eq [@london_member, @edinburgh_member]
end
end
context 'interesting scope' do
# interesting members are defined as:
# 1) confirmed
# 2) have a location

View File

@@ -84,4 +84,49 @@ describe Order do
end
context "referral codes" do
it "has a referral code" do
referred_order = FactoryGirl.create(:referred_order)
referred_order.referral_code.should_not be nil
end
it "validates referral codes" do
referred_order = FactoryGirl.build(:order, :referral_code => 'CAMP_AIGN1?')
referred_order.should_not be_valid
end
it "cleans up messy referral codes" do
referred_order = FactoryGirl.create(:order, :referral_code => 'CaMpAiGn 1 ')
referred_order.referral_code.should eq 'CAMPAIGN1'
end
end
context 'search' do
it 'finds orders by member' do
order = FactoryGirl.create(:order)
Order.search(:by => 'member', :for => order.member.login_name).should eq [order]
end
it 'finds orders by order_id' do
order = FactoryGirl.create(:order)
Order.search(:by => 'order_id', :for => order.id).should eq [order]
end
it 'finds orders by paypal_token' do
order = FactoryGirl.create(:order, :paypal_express_token => 'foo')
Order.search(:by => 'paypal_token', :for => 'foo').should eq [order]
end
it 'finds orders by paypal_payer_id' do
order = FactoryGirl.create(:order, :paypal_express_payer_id => 'bar')
Order.search(:by => 'paypal_payer_id', :for => 'bar').should eq [order]
end
it 'finds orders by referral_code' do
order = FactoryGirl.create(:order, :referral_code => 'baz')
Order.search(:by => 'referral_code', :for => 'baz').should eq [order]
end
end
end

View File

@@ -110,7 +110,7 @@ describe Planting do
it 'all valid planted_from values should work' do
['seed', 'seedling', 'cutting', 'root division',
'runner', 'bare root plant', 'advanced plant',
'graft', 'layering', nil, ''].each do |p|
'graft', 'layering', 'bulb', nil, ''].each do |p|
@planting = FactoryGirl.build(:planting, :planted_from => p)
@planting.should be_valid
end

View File

@@ -13,4 +13,8 @@ describe 'admin/orders/index.html.haml', :type => "view" do
assert_select "input#search_text"
assert_select "select#search_by"
end
it "lets you search by referral code" do
assert_select "option[value=referral_code]", :text => "Referral code"
end
end

View File

@@ -0,0 +1,15 @@
require 'spec_helper'
describe "crops/hierarchy" do
before(:each) do
controller.stub(:current_user) { nil }
@tomato = FactoryGirl.create(:tomato)
@roma = FactoryGirl.create(:crop, :system_name => 'Roma tomato', :parent => @tomato)
assign(:crops, [@tomato, @roma])
render
end
it "shows crop hierarchy" do
assert_select "ul>li>ul>li", :text => @roma.system_name
end
end

View File

@@ -24,6 +24,10 @@ describe 'layouts/_header.html.haml', :type => "view" do
rendered.should contain "Seeds"
end
it 'has a Places link' do
rendered.should contain "Places"
end
it 'has a Community section' do
rendered.should contain "Community"
end

View File

@@ -1,74 +0,0 @@
require 'spec_helper'
describe "members/nearby" do
before(:each) do
@member = FactoryGirl.create(:london_member)
@nearby_members = [FactoryGirl.create(:member)]
end
context "when the epicentre is the member's location" do
before(:each) do
controller.stub(:current_user) { @member }
controller.stub(:current_member) { @member }
@location = @member.location
render
end
it "shows the member's location in the textbox" do
assert_select "#location", :value => @location
end
it "shows the default distance in the textbox" do
assert_select "#distance", :value => "100"
end
it "shows a dropdown with miles and km" do
assert_select "select#units"
assert_select "select#units option[value=km]"
assert_select "select#units option[value=mi]"
end
it "shows the names of nearby members" do
@nearby_members.each do |m|
rendered.should contain m.login_name
end
end
end
context "when the epicentre is somewhere else" do
before(:each) do
controller.stub(:current_user) { @member }
controller.stub(:current_member) { @member }
@location = "Rothera base, Adelaide Island, Antarctica"
render
end
it "shows the selected location" do
view.content_for(:title).should == "Members near #{@location}"
end
it "shows the selected location in the textbox" do
assert_select "#location", :value => @location
end
it "shows the names of nearby members" do
@nearby_members.each do |m|
rendered.should contain m.login_name
end
end
end
context "when the user is not logged in and no location is given" do
before(:each) do
controller.stub(:current_user) { nil }
controller.stub(:current_member) { nil }
@location = nil
render
end
it "shows 'Find nearby members' as the title" do
view.content_for(:title).should == "Find nearby members"
end
end
end

View File

@@ -189,6 +189,10 @@ describe "members/show" do
it "shows a map" do
assert_select "img", :src => /maps\.google\.com/
end
it 'includes a link to places page' do
assert_select 'a', :href => place_path(@member.location)
end
end
context "no location stated" do

View File

@@ -37,8 +37,12 @@ describe "orders/show" do
assert_select("a[href=http://www.wolframalpha.com/input/?i=198.00+#{currency}]")
end
it "asks for a referral code" do
assert_select "input[id='referral_code']"
end
it "shows a checkout button" do
assert_select "a", :text => "Checkout with PayPal"
assert_select "input[value='Checkout with PayPal']"
end
it "shows a delete order button" do

View File

@@ -0,0 +1,21 @@
require 'spec_helper'
describe "places/_map_attribution.html.haml", :type => :view do
before(:each) do
render
end
it "links to OpenStreetMap" do
assert_select "a", :href => "http://openstreetmap.org",
:text => "OpenStreetMap"
end
it "links to the ODbL" do
assert_select "a", :href => "http://www.openstreetmap.org/copyright",
:text => "ODbL"
end
it "links to CloudMade" do
assert_select "a", :href => "http://cloudmade.com", :text => "CloudMade"
end
end

View File

@@ -0,0 +1,11 @@
require 'spec_helper'
describe "places/index" do
before(:each) do
render
end
it "shows a map" do
assert_select "div#map"
end
end

View File

@@ -0,0 +1,27 @@
require 'spec_helper'
describe "places/show" do
before(:each) do
@member = FactoryGirl.create(:london_member)
@nearby_members = [FactoryGirl.create(:member)]
controller.stub(:current_user) { @member }
controller.stub(:current_member) { @member }
@place = @member.location
render
end
it "shows the selected place" do
view.content_for(:title).should == @place
end
it "shows the selected place in the textbox" do
assert_select "#new_place", :value => @place
end
it "shows the names of nearby members" do
@nearby_members.each do |m|
rendered.should contain m.login_name
end
end
end

View File

@@ -38,6 +38,11 @@ describe "plantings/edit" do
end
end
it 'includes helpful links for crops and gardens' do
assert_select "a[href=#{new_garden_path}]", :text => "Add a garden."
assert_select "a[href=#{Growstuff::Application.config.new_crops_request_link}]", :text => "Request new crops."
end
it "chooses the right crop" do
assert_select "select#planting_crop_id",
:html => /option value="#{@tomato.id}" selected="selected"/

View File

@@ -38,6 +38,11 @@ describe "plantings/new" do
end
end
it 'includes helpful links for crops and gardens' do
assert_select "a[href=#{new_garden_path}]", :text => "Add a garden."
assert_select "a[href=#{Growstuff::Application.config.new_crops_request_link}]", :text => "Request new crops."
end
it "selects a crop given in a param" do
assert_select "select#planting_crop_id",
:html => /option value="#{@crop2.id}" selected="selected"/

View File

@@ -39,6 +39,7 @@ describe "seeds/index" do
it "shows location of seed owner" do
assert_select "tr>td", :text => @owner.location, :count => 2
assert_select 'a', :href => place_path(@owner.location)
end
end
end

View File

@@ -37,6 +37,7 @@ describe "seeds/new" do
it 'shows the location' do
render
rendered.should contain "from #{@member.location}."
assert_select 'a', :href => place_path(@member.location)
end
it 'links to change location' do

View File

@@ -31,6 +31,7 @@ describe "seeds/show" do
it "shows location of seed owner" do
render
rendered.should contain @owner.location
assert_select 'a', :href => place_path(@owner.location)
end
context 'with no location' do