mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-03-29 12:12:57 -04:00
2
.github/workflows/ci-features-admin.yml
vendored
2
.github/workflows/ci-features-admin.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-comments.yml
vendored
2
.github/workflows/ci-features-comments.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-crops.yml
vendored
2
.github/workflows/ci-features-crops.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-gardens.yml
vendored
2
.github/workflows/ci-features-gardens.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-harvests.yml
vendored
2
.github/workflows/ci-features-harvests.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-home.yml
vendored
2
.github/workflows/ci-features-home.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-members.yml
vendored
2
.github/workflows/ci-features-members.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-places.yml
vendored
2
.github/workflows/ci-features-places.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-plantings.yml
vendored
2
.github/workflows/ci-features-plantings.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-posts.yml
vendored
2
.github/workflows/ci-features-posts.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-seeds.yml
vendored
2
.github/workflows/ci-features-seeds.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features-timeline.yml
vendored
2
.github/workflows/ci-features-timeline.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci-features.yml
vendored
2
.github/workflows/ci-features.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
||||
sudo apt-get -y install libpq-dev google-chrome-stable
|
||||
|
||||
- name: Install NodeJS
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '12'
|
||||
|
||||
|
||||
10
Gemfile.lock
10
Gemfile.lock
@@ -142,7 +142,7 @@ GEM
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
rouge (>= 1.0.0)
|
||||
bigdecimal (3.2.2)
|
||||
bigdecimal (3.2.3)
|
||||
bluecloth (2.2.0)
|
||||
bonsai-elasticsearch-rails (7.0.1)
|
||||
elasticsearch-model (< 8)
|
||||
@@ -198,7 +198,7 @@ GEM
|
||||
comfy_bootstrap_form (4.0.9)
|
||||
rails (>= 5.0.0)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.3)
|
||||
connection_pool (2.5.4)
|
||||
crass (1.0.6)
|
||||
crowdin-api (1.12.0)
|
||||
open-uri (>= 0.1.0, < 0.2.0)
|
||||
@@ -257,9 +257,9 @@ GEM
|
||||
excon (1.2.5)
|
||||
logger
|
||||
execjs (2.10.0)
|
||||
factory_bot (6.5.4)
|
||||
factory_bot (6.5.5)
|
||||
activesupport (>= 6.1.0)
|
||||
factory_bot_rails (6.5.0)
|
||||
factory_bot_rails (6.5.1)
|
||||
factory_bot (~> 6.5)
|
||||
railties (>= 6.1.0)
|
||||
faker (3.5.2)
|
||||
@@ -475,7 +475,7 @@ GEM
|
||||
date
|
||||
stringio
|
||||
public_suffix (6.0.1)
|
||||
puma (7.0.0)
|
||||
puma (7.0.2)
|
||||
nio4r (~> 2.0)
|
||||
query_diet (0.7.2)
|
||||
racc (1.8.1)
|
||||
|
||||
10
app/controllers/api/v1/activities_controller.rb
Normal file
10
app/controllers/api/v1/activities_controller.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
# This controller is intentionally empty.
|
||||
# The `jsonapi-resources` gem provides the necessary actions.
|
||||
class ActivitiesController < BaseController
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -192,6 +192,8 @@ class CropsController < ApplicationController
|
||||
:parent_id, :perennial,
|
||||
:request_notes, :reason_for_rejection,
|
||||
:rejection_notes,
|
||||
:row_spacing, :spread, :height,
|
||||
:sowing_method, :sun_requirements, :growing_degree_days,
|
||||
scientific_names_attributes: %i(scientific_name _destroy id)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -20,6 +20,7 @@ class GardensController < DataController
|
||||
def show
|
||||
@current_plantings = @garden.plantings.current.where.not(failed: true).includes(:crop, :owner).order(planted_at: :desc)
|
||||
@current_activities = @garden.activities.current.includes(:owner).order(created_at: :desc)
|
||||
@finished_activities = @garden.activities.finished.includes(:owner).order(created_at: :desc)
|
||||
@finished_plantings = @garden.plantings.finished.includes(:crop)
|
||||
@suggested_companions = Crop.approved.where(
|
||||
id: CropCompanion.where(crop_a_id: @current_plantings.select(:crop_id)).select(:crop_b_id)
|
||||
|
||||
@@ -37,6 +37,7 @@ class PlantingsController < DataController
|
||||
@photos = @planting.photos.includes(:owner).order(date_taken: :desc)
|
||||
@harvests = Harvest.search(where: { planting_id: @planting.id })
|
||||
@current_activities = @planting.activities.current.includes(:owner).order(created_at: :desc)
|
||||
@finished_activities = @planting.activities.finished.includes(:owner).order(created_at: :desc)
|
||||
@matching_seeds = matching_seeds
|
||||
@crop = @planting.crop
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ module ApplicationHelper
|
||||
return 'today' if from_time.is_a?(Date) && (from_time == to_time)
|
||||
|
||||
return 'now' if from_time == to_time
|
||||
return distance_of_time_in_words(from_time, to_time, include_seconds:) + ' ago' if from_time > to_time
|
||||
return "#{distance_of_time_in_words(from_time, to_time, include_seconds:)} ago" if from_time < to_time
|
||||
|
||||
'in ' + distance_of_time_in_words(from_time, to_time, include_seconds:)
|
||||
"in #{distance_of_time_in_words(from_time, to_time, include_seconds:)}"
|
||||
end
|
||||
|
||||
def count_github_contibutors
|
||||
|
||||
@@ -30,4 +30,20 @@ class Activity < ApplicationRecord
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
|
||||
def garden_name
|
||||
garden&.name
|
||||
end
|
||||
|
||||
def garden_slug
|
||||
garden&.slug
|
||||
end
|
||||
|
||||
def planting_name
|
||||
planting&.crop&.name
|
||||
end
|
||||
|
||||
def planting_slug
|
||||
planting&.crop&.slug
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,14 +8,6 @@ module OpenFarmData
|
||||
fetch_attr('main_image_path')
|
||||
end
|
||||
|
||||
def height
|
||||
fetch_attr('height')
|
||||
end
|
||||
|
||||
def spread
|
||||
fetch_attr('spread')
|
||||
end
|
||||
|
||||
def svg_icon
|
||||
icon = fetch_attr('svg_icon')
|
||||
return icon if icon.present?
|
||||
@@ -31,10 +23,6 @@ module OpenFarmData
|
||||
fetch_attr('description')
|
||||
end
|
||||
|
||||
def row_spacing
|
||||
fetch_attr('row_spacing')
|
||||
end
|
||||
|
||||
def common_names
|
||||
fetch_attr('common_names')
|
||||
end
|
||||
@@ -43,22 +31,10 @@ module OpenFarmData
|
||||
fetch_attr('binomial_name')
|
||||
end
|
||||
|
||||
def sowing_method
|
||||
fetch_attr('sowing_method')
|
||||
end
|
||||
|
||||
def main_image_path
|
||||
fetch_attr('main_image_path')
|
||||
end
|
||||
|
||||
def sun_requirements
|
||||
fetch_attr('sun_requirements')
|
||||
end
|
||||
|
||||
def growing_degree_days
|
||||
fetch_attr('growing_degree_days')
|
||||
end
|
||||
|
||||
def processing_pictures
|
||||
fetch_attr('processing_pictures')
|
||||
end
|
||||
|
||||
27
app/resources/api/v1/activity_resource.rb
Normal file
27
app/resources/api/v1/activity_resource.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
class ActivityResource < BaseResource
|
||||
immutable
|
||||
|
||||
has_one :owner, class_name: 'Member'
|
||||
has_one :garden
|
||||
has_one :planting
|
||||
|
||||
attribute :name
|
||||
attribute :description
|
||||
attribute :category
|
||||
attribute :finished
|
||||
attribute :due_date
|
||||
|
||||
filter :owner
|
||||
filter :owner_id
|
||||
filter :garden
|
||||
filter :garden_id
|
||||
filter :planting
|
||||
filter :planting_id
|
||||
filter :category
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,13 @@ module Api
|
||||
has_many :photos
|
||||
|
||||
attribute :name
|
||||
|
||||
filter :owner
|
||||
filter :owner_id
|
||||
filter :active
|
||||
filter :garden_type
|
||||
filter :location
|
||||
filter :slug
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,6 +16,15 @@ module Api
|
||||
attribute :weight_quantity
|
||||
attribute :weight_unit
|
||||
attribute :si_weight
|
||||
|
||||
filter :owner
|
||||
filter :owner_id
|
||||
filter :crop
|
||||
filter :crop_id
|
||||
filter :planting
|
||||
filter :planting_id
|
||||
filter :plant_part
|
||||
filter :harvested_at
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,10 @@ module Api
|
||||
filter :owner
|
||||
filter :owner_id
|
||||
filter :finished
|
||||
filter :active, apply: ->(records, _value, _options) { records.active }
|
||||
filter :failed, apply: ->(records, _value, _options) { records.failed }
|
||||
filter :sunniness
|
||||
filter :perennial, apply: ->(records, _value, _options) { records.perennial }
|
||||
|
||||
attribute :percentage_grown
|
||||
delegate :percentage_grown, to: :@model
|
||||
|
||||
@@ -17,6 +17,15 @@ module Api
|
||||
attribute :organic
|
||||
attribute :gmo
|
||||
attribute :heirloom
|
||||
|
||||
filter :owner
|
||||
filter :owner_id
|
||||
filter :crop
|
||||
filter :crop_id
|
||||
filter :tradable_to
|
||||
filter :organic
|
||||
filter :gmo
|
||||
filter :heirloom
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
= f.radio_button(:perennial, true, label: "Perennial")
|
||||
%span.help-block Living more than two years
|
||||
|
||||
%h2 OpenFarm Data
|
||||
= f.number_field :row_spacing, label: 'Row Spacing (cm)', min: 0
|
||||
= f.number_field :spread, label: 'Spread (cm)', min: 0
|
||||
= f.number_field :height, label: 'Height (cm)', min: 0
|
||||
= f.text_field :sowing_method
|
||||
= f.text_field :sun_requirements
|
||||
= f.number_field :growing_degree_days, min: 0
|
||||
|
||||
- unless @crop.approved?
|
||||
= link_to 'Search wikipedia', "https://en.wikipedia.org/w/index.php?search=#{@crop.name}", target: '_blank'
|
||||
= f.url_field :en_wikipedia_url, id: "en_wikipedia_url", label: 'Wikipedia URL'
|
||||
|
||||
33
app/views/crops/_openfarm_data.html.haml
Normal file
33
app/views/crops/_openfarm_data.html.haml
Normal file
@@ -0,0 +1,33 @@
|
||||
- if crop.row_spacing || crop.spread || crop.height || crop.sowing_method || crop.sun_requirements || crop.growing_degree_days
|
||||
= cute_icon
|
||||
.card
|
||||
.card-body
|
||||
%h4 OpenFarm Data
|
||||
%ul.list-group.list-group-flush
|
||||
- if crop.row_spacing
|
||||
%li.list-group-item
|
||||
%strong Row Spacing:
|
||||
= crop.row_spacing
|
||||
cm
|
||||
- if crop.spread
|
||||
%li.list-group-item
|
||||
%strong Spread:
|
||||
= crop.spread
|
||||
cm
|
||||
- if crop.height
|
||||
%li.list-group-item
|
||||
%strong Height:
|
||||
= crop.height
|
||||
cm
|
||||
- if crop.sowing_method
|
||||
%li.list-group-item
|
||||
%strong Sowing Method:
|
||||
= crop.sowing_method
|
||||
- if crop.sun_requirements
|
||||
%li.list-group-item
|
||||
%strong Sun Requirements:
|
||||
= crop.sun_requirements
|
||||
- if crop.growing_degree_days
|
||||
%li.list-group-item
|
||||
%strong Growing Degree Days:
|
||||
= crop.growing_degree_days
|
||||
@@ -111,6 +111,8 @@
|
||||
= render 'harvests', crop: @crop
|
||||
= render 'find_seeds', crop: @crop
|
||||
|
||||
= render 'openfarm_data', crop: @crop
|
||||
|
||||
= cute_icon
|
||||
.card
|
||||
.card-body
|
||||
|
||||
@@ -16,3 +16,8 @@
|
||||
.col-md-12
|
||||
%p Nothing has been planted here.
|
||||
|
||||
- if @finished_activities&.size&.positive?
|
||||
%h2 Finished activities in garden
|
||||
.index-cards
|
||||
- @finished_activities.each do |activity|
|
||||
= render "activities/card", activity: activity
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
%small
|
||||
%a{href: "#content"}
|
||||
Skip to main content
|
||||
= render 'layouts/nav', model: Garden
|
||||
%label
|
||||
= link_to show_inactive_tickbox_path('gardens', owner: @owner, show_all: @show_all) do
|
||||
@@ -20,7 +23,7 @@
|
||||
%hr/
|
||||
= render @owner
|
||||
|
||||
.col-md-10
|
||||
.col-md-10#content
|
||||
- if @gardens.empty?
|
||||
%p There are no gardens to display.
|
||||
- if can?(:create, Garden) && @owner == current_member
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
- if @harvest.planting.present? && @harvest.planting.overall_rating.blank?
|
||||
.alert.alert-info{role: "alert"}
|
||||
This harvest is from a planting that hasn't been rated yet.
|
||||
= link_to "Rate this planting", edit_planting_path(@harvest.planting), class: 'alert-link'
|
||||
= link_to "Rate this planting", edit_planting_path(@harvest.planting, anchor: "planting_overall_rating"), class: 'alert-link'
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
%br
|
||||
%p
|
||||
- if current_member.plantings.active.any?
|
||||
= link_to member_path(current_member, anchor: "#content"), class: 'btn btn-dark' do
|
||||
= link_to member_path(current_member, anchor: "content"), class: 'btn btn-dark' do
|
||||
= planting_icon
|
||||
Track my plantings
|
||||
%p
|
||||
= link_to member_gardens_path(current_member), class: 'btn btn-dark' do
|
||||
= link_to member_gardens_path(current_member, anchor: "content"), class: 'btn btn-dark' do
|
||||
= garden_icon
|
||||
Show me my garden
|
||||
- else
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
%ul.navbar-nav.mr-auto.bg-dark
|
||||
- if signed_in?
|
||||
%li.nav-item
|
||||
= link_to timeline_index_path, method: :get, class: 'nav-link text-white' do
|
||||
= link_to timeline_index_path, method: :get, class: 'nav-link text-white', title: "Timeline" do
|
||||
= image_tag 'icons/notification.svg', class: 'img img-icon', alt: "Notifications"
|
||||
%li.nav-item
|
||||
= link_to member_gardens_path(current_member), class: 'nav-link text-white', title: "My gardens" do
|
||||
= link_to member_gardens_path(current_member, anchor: "content"), class: 'nav-link text-white', title: "My gardens" do
|
||||
= image_icon 'gardens'
|
||||
%li.nav-item.dropdown
|
||||
%a.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", href: "#", role: "button"}
|
||||
|
||||
@@ -83,14 +83,14 @@
|
||||
.row
|
||||
%section.order-3.order-md-1.col-12= render "map", member: @member
|
||||
- if @harvesting.size.positive?
|
||||
%section.harvests.order-2.order-md-1.col-12
|
||||
%section.harvests.order-2.order-md-1.col-12#harvests
|
||||
%h2 Ready to harvest
|
||||
.index-cards
|
||||
- @harvesting.each do |planting|
|
||||
= render 'plantings/thumbnail', planting: planting
|
||||
|
||||
- if @others.size.positive?
|
||||
%section.planting-progress.order-2.order-md-1.col-12
|
||||
%section.planting-progress.order-2.order-md-1.col-12#planting-progress
|
||||
%h2 Progress report
|
||||
%p Still growing and not ready for harvesting.
|
||||
.list-group
|
||||
@@ -99,7 +99,7 @@
|
||||
%span= render 'plantings/tiny', planting: planting
|
||||
%span= render 'plantings/progress', planting: planting
|
||||
- if @late.size.positive?
|
||||
%section.late.order-2.order-md-1.col-12
|
||||
%section.late.order-2.order-md-1.col-12#late
|
||||
%h2 Late
|
||||
%p
|
||||
These plantings are at the end of their lifecycle.
|
||||
@@ -109,7 +109,7 @@
|
||||
- @late.each do |planting|
|
||||
= render 'plantings/thumbnail', planting: planting
|
||||
- if @super_late.any?
|
||||
%section.superlate.order-2.order-md-1.col-12
|
||||
%section.superlate.order-2.order-md-1.col-12#superlate
|
||||
%h2 Super late
|
||||
%p
|
||||
We suspect the following plantings finished long ago and no longer need tracking.
|
||||
@@ -122,14 +122,14 @@
|
||||
planted on #{planting.planted_at.to_date}
|
||||
|
||||
- if @harvests.any?
|
||||
%section.havests.order-2.order-md-1.col-12
|
||||
%section.havests.order-2.order-md-1.col-12#recent-harvests
|
||||
%h2 Recent Harvests
|
||||
.index-cards
|
||||
- @harvests.each do |harvest|
|
||||
= render 'harvests/thumbnail', harvest: harvest
|
||||
|
||||
- if @activity.any?
|
||||
%section.activity.order-2.order-md-1.col-12
|
||||
%section.activity.order-2.order-md-1.col-12#activity
|
||||
%h2 Activity
|
||||
.list-group
|
||||
- @activity.each do |event|
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
.row
|
||||
.col-md-8
|
||||
= f.collection_radio_buttons(:garden_id, @planting.owner.gardens.active,
|
||||
= f.collection_radio_buttons(:garden_id, @planting.owner.gardens.active.order_by_name,
|
||||
:id, :name, required: true,
|
||||
label: 'Where did you plant it?')
|
||||
= link_to "Add a garden.", new_garden_path
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%p Which garden is the planting in?
|
||||
|
||||
%ul.list-group
|
||||
- planting.owner.gardens.active.order(:name).each do |garden|
|
||||
- planting.owner.gardens.active.order_by_name.each do |garden|
|
||||
%li.list-group-item
|
||||
= link_to plantings_path(planting: {crop_id: planting.crop_id, garden_id: garden.id}), method: :post do
|
||||
.md-v-line
|
||||
|
||||
@@ -89,7 +89,11 @@
|
||||
- else
|
||||
.col-md-12
|
||||
%p Nothing is currently planned here.
|
||||
|
||||
- if @finished_activities&.size&.positive?
|
||||
%h2 Finished activities for planting
|
||||
.index-cards
|
||||
- @finished_activities.each do |activity|
|
||||
= render "activities/card", activity: activity
|
||||
|
||||
.col-md-4.col-xs-12
|
||||
= render @planting.crop
|
||||
|
||||
@@ -141,6 +141,7 @@ Rails.application.routes.draw do
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
jsonapi_resources :activities
|
||||
jsonapi_resources :crops
|
||||
jsonapi_resources :gardens
|
||||
jsonapi_resources :harvests
|
||||
|
||||
10
db/migrate/20240101010101_add_fields_to_crops.rb
Normal file
10
db/migrate/20240101010101_add_fields_to_crops.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class AddFieldsToCrops < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :crops, :row_spacing, :integer
|
||||
add_column :crops, :spread, :integer
|
||||
add_column :crops, :height, :integer
|
||||
add_column :crops, :sowing_method, :string
|
||||
add_column :crops, :sun_requirements, :string
|
||||
add_column :crops, :growing_degree_days, :integer
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
class PopulateCropFieldsFromOpenfarmData < ActiveRecord::Migration[5.2]
|
||||
def up
|
||||
Crop.find_each do |crop|
|
||||
if crop.openfarm_data.present?
|
||||
attributes = crop.openfarm_data.fetch('attributes', {})
|
||||
crop.update_columns(
|
||||
row_spacing: attributes['row_spacing'],
|
||||
spread: attributes['spread'],
|
||||
height: attributes['height'],
|
||||
sowing_method: attributes['sowing_method'],
|
||||
sun_requirements: attributes['sun_requirements'],
|
||||
growing_degree_days: attributes['growing_degree_days']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# This migration is not reversible.
|
||||
end
|
||||
end
|
||||
@@ -252,6 +252,12 @@ ActiveRecord::Schema[7.2].define(version: 2025_09_01_130830) do
|
||||
t.jsonb "openfarm_data"
|
||||
t.integer "harvests_count", default: 0
|
||||
t.integer "photo_associations_count", default: 0
|
||||
t.integer "row_spacing"
|
||||
t.integer "spread"
|
||||
t.integer "height"
|
||||
t.string "sowing_method"
|
||||
t.string "sun_requirements"
|
||||
t.integer "growing_degree_days"
|
||||
t.index ["creator_id"], name: "index_crops_on_creator_id"
|
||||
t.index ["name"], name: "index_crops_on_name"
|
||||
t.index ["parent_id"], name: "index_crops_on_parent_id"
|
||||
|
||||
@@ -100,6 +100,36 @@ describe CropsController do
|
||||
it { expect { subject }.to change(Crop, :count).by(1) }
|
||||
it { expect { subject }.to change(AlternateName, :count).by(2) }
|
||||
it { expect { subject }.to change(ScientificName, :count).by(1) }
|
||||
|
||||
context 'with openfarm data' do
|
||||
let(:crop_params) do
|
||||
{
|
||||
crop: {
|
||||
name: 'aubergine',
|
||||
en_wikipedia_url: "https://en.wikipedia.org/wiki/Eggplant",
|
||||
row_spacing: 10,
|
||||
spread: 20,
|
||||
height: 30,
|
||||
sowing_method: 'direct',
|
||||
sun_requirements: 'full sun',
|
||||
growing_degree_days: 100
|
||||
},
|
||||
alt_name: { '1': "egg plant", '2': "purple apple" },
|
||||
sci_name: { '1': "fancy sci name", '2': "" }
|
||||
}
|
||||
end
|
||||
|
||||
it 'saves openfarm data' do
|
||||
subject
|
||||
crop = Crop.last
|
||||
expect(crop.row_spacing).to eq(10)
|
||||
expect(crop.spread).to eq(20)
|
||||
expect(crop.height).to eq(30)
|
||||
expect(crop.sowing_method).to eq('direct')
|
||||
expect(crop.sun_requirements).to eq('full sun')
|
||||
expect(crop.growing_degree_days).to eq(100)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -19,6 +19,14 @@ describe "Crop", :js do
|
||||
click_button class: "add-altname-row"
|
||||
fill_in "alt_name[3]", with: "Jazmin"
|
||||
fill_in "alt_name[4]", with: "Matsurika"
|
||||
|
||||
fill_in "crop_row_spacing", with: "12"
|
||||
fill_in "crop_spread", with: "30"
|
||||
fill_in "crop_height", with: "10"
|
||||
fill_in "crop_sowing_method", with: "directly into final position"
|
||||
|
||||
fill_in "crop_sun_requirements", with: "full sun"
|
||||
fill_in "crop_growing_degree_days", with: 100
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
56
spec/requests/api/v1/activities_request_spec.rb
Normal file
56
spec/requests/api/v1/activities_request_spec.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Activities', type: :request do
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:activity) { FactoryBot.create(:activity, garden: create(:garden), planting: create(:planting)) }
|
||||
let!(:activity2) { FactoryBot.create(:activity) }
|
||||
|
||||
it '#index' do
|
||||
get('/api/v1/activities', params: {}, headers:)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
end
|
||||
|
||||
it '#show' do
|
||||
get("/api/v1/activities/#{activity.id}", params: {}, headers:)
|
||||
expect(subject['data']['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/activities?filter[owner-id]=#{activity.owner.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by garden' do
|
||||
get("/api/v1/activities?filter[garden-id]=#{activity.garden.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by planting' do
|
||||
get("/api/v1/activities?filter[planting-id]=#{activity.planting.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by category' do
|
||||
get("/api/v1/activities?filter[category]=#{activity.category}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
expect(subject['data'][1]['id']).to eq(activity2.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -50,6 +50,33 @@ RSpec.describe 'Gardens', type: :request do
|
||||
expect(subject['data']).to include(garden_encoded_as_json_api)
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:garden2) { FactoryBot.create(:garden, active: false, garden_type: FactoryBot.create(:garden_type)) }
|
||||
pending 'filters by active' do
|
||||
get('/api/v1/gardens?filter[active]=true', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(garden.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by garden_type' do
|
||||
get("/api/v1/gardens?filter[garden_type]=#{garden2.garden_type.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(garden2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/gardens?filter[owner_id]=#{garden2.owner.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'][1]['id']).to eq(garden2.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it '#create' do
|
||||
expect do
|
||||
post '/api/v1/gardens', params: { 'garden' => { 'name' => 'can i make this' } }, headers:
|
||||
|
||||
@@ -76,6 +76,39 @@ RSpec.describe 'Harvests', type: :request do
|
||||
it { expect(subject['data']).to eq(harvest_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:harvest2) { FactoryBot.create(:harvest, planting: create(:planting)) }
|
||||
it 'filters by crop' do
|
||||
get("/api/v1/harvests?filter[crop_id]=#{harvest2.crop.id}", params: {}, headers:)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by planting' do
|
||||
get("/api/v1/harvests?filter[planting_id]=#{harvest2.planting.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by plant_part' do
|
||||
get("/api/v1/harvests?filter[plant_part]=#{harvest2.plant_part.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/harvests?filter[owner_id]=#{harvest2.owner.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it '#create' do
|
||||
expect do
|
||||
put '/api/v1/harvests', headers:, params: {
|
||||
|
||||
@@ -140,4 +140,36 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:planting2) { FactoryBot.create(:planting, failed: true, sunniness: 'shade') }
|
||||
let!(:perennial_planting) { FactoryBot.create(:planting, crop: FactoryBot.create(:crop, perennial: true)) }
|
||||
it 'filters by failed' do
|
||||
get('/api/v1/plantings?filter[failed]=true', params: {}, headers:)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by sunniness' do
|
||||
get('/api/v1/plantings?filter[sunniness]=shade', params: {}, headers:)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by perennial' do
|
||||
get('/api/v1/plantings?filter[perennial]=true', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(perennial_planting.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by active' do
|
||||
get('/api/v1/plantings?filter[active]=true', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'][0]['id']).to eq(planting.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -78,4 +78,56 @@ RSpec.describe 'Seeds', type: :request do
|
||||
delete "/api/v1/seeds/#{seed.id}", params: {}, headers:
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:seed2) { FactoryBot.create(:seed, tradable_to: 'nationally', organic: 'certified organic', gmo: 'certified GMO-free', heirloom: 'heirloom') }
|
||||
it 'filters by crop' do
|
||||
get("/api/v1/seeds?filter[crop]=#{seed2.crop.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
|
||||
|
||||
it 'filters by tradable_to' do
|
||||
get('/api/v1/seeds?filter[tradable_to]=nationally', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by organic' do
|
||||
get('/api/v1/seeds?filter[organic]=certified organic', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by gmo' do
|
||||
get('/api/v1/seeds?filter[gmo]=certified GMO-free', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by heirloom' do
|
||||
get('/api/v1/seeds?filter[heirloom]=heirloom', params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/seeds?filter[owner_id]=#{seed2.owner.id}", params: {}, headers:)
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user