Merge remote-tracking branch 'upstream/dev' into api-docs

Conflicts:
	app/resources/api/v1/planting_resource.rb
This commit is contained in:
Brenda Wallace
2019-11-18 10:26:05 +13:00
14 changed files with 149 additions and 57 deletions

View File

@@ -493,7 +493,7 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
scout_apm (2.6.3)
scout_apm (2.6.4)
parser
searchkick (4.1.0)
activemodel (>= 5)

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="48pt" height="48pt" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g id="surface7" transform="matrix(0.701232, -0.712932, 0.712932, 0.701232, -9.812447, 24.226824)">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(32.941176%,43.137255%,47.843137%);fill-opacity:1;" d="M 25.554688 33.894531 C 25.554688 33.894531 22.074219 37.398438 20.546875 38.933594 C 19.027344 40.46875 12.011719 43.109375 6.960938 41.089844 C 4.402344 35.449219 7.585938 28.945312 9.109375 27.414062 C 10.632812 25.882812 14.113281 22.378906 14.113281 22.378906 Z M 38.425781 15.179688 L 32.703125 9.421875 L 35.5625 6.539062 L 41.285156 12.300781 Z M 38.425781 15.179688 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,75.686275%,2.745098%);fill-opacity:1;" d="M 29.84375 15.179688 L 18.402344 26.695312 C 17.84375 27.257812 12.792969 32.574219 14.21875 34 C 15.644531 35.425781 20.703125 30.136719 21.261719 29.574219 L 32.703125 18.058594 L 31.988281 17.335938 Z M 29.84375 15.179688 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,75.686275%,2.745098%);fill-opacity:1;" d="M 31.132812 18.488281 L 30.84375 16.476562 L 31.84375 16.332031 C 31.890625 16.324219 36.574219 15.601562 39.855469 12.300781 L 40.570312 11.578125 L 42 13.019531 L 41.285156 13.738281 C 37.511719 17.535156 32.347656 18.316406 32.132812 18.347656 Z M 31.132812 18.488281 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,75.686275%,2.745098%);fill-opacity:1;" d="M 31.414062 17.050781 L 29.414062 16.761719 L 29.558594 15.753906 C 29.589844 15.535156 30.363281 10.335938 34.132812 6.539062 L 34.847656 5.820312 L 36.277344 7.261719 L 35.5625 7.980469 C 32.28125 11.285156 31.566406 15.996094 31.558594 16.042969 Z M 31.414062 17.050781 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -9,12 +9,20 @@ function showCropMap(cropmap) {
}).addTo(cropmap);
var markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });
var crop_icon = L.icon({
iconUrl: location.pathname + '.svg',
iconSize: [24, 24],
iconAnchor: [12, 12],
popupAnchor: [0, -12],
});
var things_to_map = location.pathname + '.json';
$.getJSON(things_to_map, function(crop) {
$.each(crop.plantings, function(i, planting) {
var owner = planting.owner;
if (owner.latitude && owner.longitude) {
var marker = new L.Marker(new L.LatLng(owner.latitude, owner.longitude));
var marker = new L.Marker(new L.LatLng(owner.latitude, owner.longitude),
{'icon': crop_icon});
var planting_url = "/plantings/" + planting.id;
var planting_link = "<a href='" + planting_url + "'>" + owner.login_name + "'s " + crop.name + "</a>";
@@ -44,7 +52,6 @@ function showCropMap(cropmap) {
$(document).ready(function() {
if (document.getElementById("cropmap") !== null) {
L.Icon.Default.imagePath = '/assets';
var cropmap = L.map('cropmap').setView([0.0, -0.0], 2);

View File

@@ -7,6 +7,13 @@ if (document.getElementById("membermap") !== null) {
L.Icon.Default.imagePath = '/assets';
var default_marker_icon = L.icon({
iconUrl: "<%=image_url('spade-marker.svg')%>",
iconSize: [48, 48],
iconAnchor: [24, 48],
popupAnchor: [0, -46],
});
$.getJSON(location.pathname + '.json', function(member) {
if (member.latitude && member.longitude) {
var membermap = L.map('membermap').setView([member.latitude, member.longitude], 4);
@@ -15,7 +22,8 @@ if (document.getElementById("membermap") !== null) {
attribution: 'Map data &copy; <a href="https://openstreetmap.org">OpenStreetMap</a> contributors under <a href="https://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="https://mapbox.com">Mapbox</a>',
maxZoom: 18
}).addTo(membermap);
var marker = new L.Marker(new L.LatLng(member.latitude, member.longitude));
var marker = new L.Marker(new L.LatLng(member.latitude, member.longitude),
{'icon': default_marker_icon});
var member_url = "/members/" + member.slug;
var member_link = "<a href='" + member_url + "'>" + member.login_name + "</a>";

View File

@@ -1,20 +1,23 @@
if (document.getElementById("placesmap") !== null) {
places_base_path = "/places";
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_map_id %>";
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_access_token %>";
mapbox_base_url = "https://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
nominatim_base_url = 'https://nominatim.openstreetmap.org/search/';
nominatim_user_agent_email = "<%= Rails.env == 'test' ? 0 : Rails.application.config.user_agent_email %>";
var places_base_path = "/places";
var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_map_id %>";
var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_access_token %>";
var mapbox_base_url = "https://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
var nominatim_base_url = 'https://nominatim.openstreetmap.org/search/';
var nominatim_user_agent_email = "<%= Rails.env == 'test' ? 0 : Rails.application.config.user_agent_email %>";
L.Icon.Default.imagePath = '/assets'
if (location.pathname === places_base_path) { //places index page
var placesmap;
if (location.pathname === places_base_path || location.pathname === '/') { //places index page
placesmap = L.map('placesmap').setView([0.0, -0.0], 2);
showMap(placesmap);
} else { // specific place page
place = location.pathname.replace(places_base_path + "/", '');
nominatim_query_url = nominatim_base_url + place;
nominatim_options = {
}
else { // specific place page
var place = location.pathname.replace(places_base_path + "/", '');
var nominatim_query_url = nominatim_base_url + place;
var nominatim_options = {
format: "json",
callback: "placeholder",
limit: 1,
@@ -32,20 +35,58 @@ function showMap(placesmap) {
attribution: 'Map data &copy; <a href="https://openstreetmap.org">OpenStreetMap</a> contributors under <a href="https://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="https://mapbox.com">Mapbox</a>',
maxZoom: 18
}).addTo(placesmap);
markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });
things_to_map = location.pathname + '.json';
$.getJSON(things_to_map, function(members) {
var markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });
var members_url = location.pathname + '.json';
// Icon documentation: https://leafletjs.com/reference-1.5.0.html#icon
var default_marker_icon = L.icon({
iconUrl: "<%=image_url('spade-marker.svg')%>",
iconSize: [48, 48],
iconAnchor: [24, 48],
popupAnchor: [0, -46],
});
$.getJSON(members_url, 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.slug + "'>" + m.login_name + "</a></p>";
where = "<p><i>" + m.location + "</i></p>";
var marker = new L.Marker(new L.LatLng(m.latitude, m.longitude), {icon: default_marker_icon});
var link = "<p><a href='/members/" + m.slug + "'>" + m.login_name + "</a></p>";
var where = "<p><i>" + m.location + "</i></p>";
marker.bindPopup(link + where).openPopup();
markers.addLayer(marker);
}
});
});
function fetchCropsForMap(url) {
$.getJSON(url, function(crop_data) {
$.each(crop_data['data'], function(i, p) {
if (p.attributes.latitude && p.attributes.longitude) {
var crop_marker = L.icon({
iconUrl: "/crops/" + p.attributes['crop-slug'] + '.svg',
iconSize: [48, 48],
iconAnchor: [24, 48],
popupAnchor: [0, -46],
});
var marker = new L.Marker(new L.LatLng(p.attributes.latitude, p.attributes.longitude),
{icon: crop_marker});
var link = "<p><a href='/plantings/" + p.attributes.slug + "'>" + p.attributes['crop-name'] + "</a></p>";
var where = "<p><i>" + p.attributes.location + "</i></p>";
if (p.attributes['thumbnail']) {
where += '<img src="' + p.attributes['thumbnail'] + '" alt="photo of planting">';
}
marker.bindPopup(link + where).openPopup();
markers.addLayer(marker);
}
});
if (crop_data['links']['next']) {
fetchCropsForMap(crop_data['links']['next'])
}
return crop_data;
});
}
fetchCropsForMap('/api/v1/plantings.json?filter[finished]=false&sort=-planted-at');
placesmap.addLayer(markers);
}

View File

@@ -1,13 +1,13 @@
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
border: none;
border: 0;
}
.thumbnail {
background: #fff !important;
border: solid 1px whitesmoke;
}
background: $white;
border: solid 1px $white;
.thumbnail .crop-thumbnail .cropinfo {
padding-top: 14px;
.crop-thumbnail .cropinfo {
padding-top: 14px;
}
}

View File

@@ -66,7 +66,10 @@ class CropsController < ApplicationController
respond_to do |format|
format.html
format.svg { send_data(@crop.svg_icon, type: "image/svg+xml", disposition: "inline") }
format.svg do
icon_data = @crop.svg_icon.presence || File.read(Rails.root.join('app', 'assets', 'images', 'icons', 'sprout.svg'))
send_data(icon_data, type: "image/svg+xml", disposition: "inline")
end
format.json { render json: @crop.to_json(crop_json_fields) }
end
end

View File

@@ -19,7 +19,10 @@ module OpenFarmData
end
def svg_icon
fetch_attr('svg_icon')
icon = fetch_attr('svg_icon')
return icon if icon.present?
parent.svg_icon if parent.present?
end
def tags_array

View File

@@ -45,10 +45,12 @@ class Planting < ApplicationRecord
##
## Delegations
delegate :name, :en_wikipedia_url, :default_scientific_name, :plantings_count,
delegate :name, :slug, :en_wikipedia_url, :default_scientific_name, :plantings_count,
to: :crop, prefix: true
delegate :annual?, to: :crop
delegate :annual?, :svg_icon, to: :crop
delegate :location, :longitude, :latitude, to: :garden
##
## Validations
validates :garden, presence: true
@@ -77,11 +79,6 @@ class Planting < ApplicationRecord
].join('-').tr(' ', '-').downcase
end
# location = garden owner + garden name, i.e. "Skud's backyard"
def location
I18n.t("gardens.location", garden: garden.name, owner: garden.owner.login_name)
end
# stringify as "beet in Skud's backyard" or similar
def to_s
I18n.t('plantings.string', crop: crop.name, garden: garden.name, owner: owner)

View File

@@ -3,17 +3,26 @@ class PlantingResource < BaseResource
has_one :garden
has_one :crop
# has_one :owner, class_name: 'Member'
has_one :owner, class_name: 'Member'
has_many :photos
has_many :harvests
attribute :slug, :planted_at, :finished, :finished_at, :quantity, :description, :sunniness, :planted_from
attribute :slug
attribute :planted_at
attribute :finished
attribute :finished_at
attribute :quantity
attribute :description
attribute :sunniness
attribute :planted_from
# Predictions
# attribute :expected_lifespan
# attribute :finish_predicted_at
# attribute :first_harvest_date
# attribute :last_harvest_date
attribute :expected_lifespan
attribute :finish_predicted_at
attribute :first_harvest_date
attribute :last_harvest_date
attributes :longitude, :latitude, :location
filter :slug
filter :crop
@@ -22,18 +31,16 @@ class PlantingResource < BaseResource
filter :owner
filter :finished
# attribute :percentage_grown
# def percentage_grown
# @model.percentage_grown
# end
attribute :percentage_grown
def percentage_grown
@model.percentage_grown
end
# attribute :crop_name
# def crop_name
# @model.crop.name
# end
attribute :crop_name
attribute :crop_slug
# attribute :thumbnail
# def thumbnail
# @model.default_photo&.thumbnail_url
# end
attribute :thumbnail
def thumbnail
@model.default_photo&.thumbnail_url
end
end

View File

@@ -1,3 +1,6 @@
- content_for :title, t(".title", site_name: ENV['GROWSTUFF_SITE_NAME'])
%h2=t(".title", site_name: ENV['GROWSTUFF_SITE_NAME'])
= render partial: 'search_form'
#placesmap.map

View File

@@ -16,6 +16,7 @@ RSpec.describe Api::V1::PlantingsController, type: :controller do
let(:expected_attributes) do
{
'crop-name' => my_planting.crop.name,
'crop-slug' => my_planting.crop.slug,
'description' => my_planting.description,
'expected-lifespan' => nil,
'finish-predicted-at' => nil,
@@ -23,6 +24,9 @@ RSpec.describe Api::V1::PlantingsController, type: :controller do
'finished-at' => my_planting.finished_at,
'first-harvest-date' => nil,
'last-harvest-date' => nil,
'latitude' => my_planting.garden.latitude,
'longitude' => my_planting.garden.longitude,
'location' => my_planting.garden.location,
'percentage-grown' => nil,
'planted-at' => '2000-01-01',
'planted-from' => my_planting.planted_from,
@@ -46,6 +50,7 @@ RSpec.describe Api::V1::PlantingsController, type: :controller do
let(:expected_attributes) do
{
'crop-name' => my_planting.crop.name,
'crop-slug' => my_planting.crop.slug,
'description' => my_planting.description,
'expected-lifespan' => nil,
'finish-predicted-at' => nil,
@@ -53,6 +58,9 @@ RSpec.describe Api::V1::PlantingsController, type: :controller do
'finished-at' => my_planting.finished_at,
'first-harvest-date' => nil,
'last-harvest-date' => nil,
'latitude' => my_planting.garden.latitude,
'longitude' => my_planting.garden.longitude,
'location' => my_planting.garden.location,
'percentage-grown' => nil,
'planted-at' => '2000-01-01',
'planted-from' => my_planting.planted_from,

View File

@@ -212,7 +212,7 @@ describe Planting do
end
it "generates a location" do
planting.location.should eq "#{garden_owner.login_name}'s #{garden.name}"
planting.location.should eq garden.location
end
it "has a slug" do

View File

@@ -4,7 +4,7 @@ RSpec.describe 'Plantings', type: :request do
subject { JSON.parse response.body }
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
let!(:planting) { FactoryBot.create :planting }
let!(:planting) { FactoryBot.create :planting }
let(:planting_encoded_as_json_api) do
{ "id" => planting.id.to_s,
"type" => "plantings",
@@ -60,6 +60,7 @@ RSpec.describe 'Plantings', type: :request do
"quantity" => 33,
"description" => planting.description,
"crop-name" => planting.crop.name,
"crop-slug" => planting.crop.slug,
"sunniness" => nil,
"planted-from" => nil,
"expected-lifespan" => nil,
@@ -67,12 +68,17 @@ RSpec.describe 'Plantings', type: :request do
"percentage-grown" => nil,
"first-harvest-date" => nil,
"last-harvest-date" => nil,
"thumbnail" => nil
"thumbnail" => nil,
"location" => planting.garden.location,
"longitude" => planting.garden.longitude,
"latitude" => planting.garden.latitude
}
end
it '#index' do
get '/api/v1/plantings', params: {}, headers: headers
expect(subject['data'][0].keys).to eq(planting_encoded_as_json_api.keys)
expect(subject['data'][0]['attributes'].keys.sort!).to eq(planting_encoded_as_json_api['attributes'].keys.sort!)
expect(subject['data']).to include(planting_encoded_as_json_api)
end