Compare commits

..

53 Commits

Author SHA1 Message Date
Cesy
c08beb5291 Merge pull request #1495 from Growstuff/dev
Release 37
2017-12-22 09:54:32 +00:00
pozorvlak
269f3164b7 Merge pull request #1497 from Br3nda/feature/admin-nicer
Nicer admin interface
2017-12-18 11:33:02 +00:00
Shiny
9d47b2b029 Merge branch 'dev' into feature/admin-nicer 2017-12-18 15:10:36 +13:00
Daniel O'Connor
81e26aaf02 Merge pull request #1496 from Br3nda/feature/ordering
Feature/ordering
2017-12-18 09:30:51 +10:30
Shiny
d62322b498 Merge branch 'dev' into feature/admin-nicer 2017-12-18 06:59:33 +13:00
Shiny
ebb2f90294 Merge branch 'dev' into feature/ordering 2017-12-18 06:59:17 +13:00
Shiny
72922a160d Merge pull request #1498 from Growstuff/bundle-update-2017-12-18-000857
Bundle Update on 2017-12-18
2017-12-18 06:58:50 +13:00
deppbot
0699716c19 Bundle Update on 2017-12-18 2017-12-18 00:08:58 +08:00
Brenda Wallace
4c35987cb7 Ignore long method in ability.rb 2017-12-17 17:57:19 +13:00
Brenda Wallace
54e0806f38 don't check role is there's no member 2017-12-17 17:55:14 +13:00
Brenda Wallace
99828c7c01 Updated spec for new admin#index 2017-12-17 17:54:13 +13:00
Brenda Wallace
25d2773464 Use nested module/class definitions instead of compact style. 2017-12-17 17:50:30 +13:00
Brenda Wallace
233a30a045 Haml code style fix up 2017-12-17 17:49:05 +13:00
Brenda Wallace
01a7463ae8 Split up ability.rb into methods 2017-12-17 12:47:41 +13:00
Brenda Wallace
8a446ecbfc Member admin 2017-12-17 12:45:19 +13:00
Brenda Wallace
efc60e6313 Nicer layout on editing roles 2017-12-17 12:11:55 +13:00
Brenda Wallace
406b2dbf04 Make admin index a bit nicer 2017-12-17 12:06:03 +13:00
Brenda Wallace
ac056b4eb5 Merge remote-tracking branch 'upstream/dev' into dev 2017-12-17 12:05:42 +13:00
Brenda Wallace
2394f4d237 One view for showing photos on an item 2017-12-17 11:40:55 +13:00
Brenda Wallace
2a4fd57050 Merge remote-tracking branch 'upstream/dev' into feature/ordering 2017-12-17 10:18:25 +13:00
Shiny
5c885d675e Merge branch 'master' into dev 2017-12-17 10:05:25 +13:00
Shiny
0b08691160 Merge pull request #1474 from Br3nda/feature/photos-1457
Polymorphic relationship to photos
2017-12-17 10:04:30 +13:00
Brenda Wallace
b1052a2dbf Order posts by most recent 2017-12-17 10:01:51 +13:00
Brenda Wallace
95a923ff5f Order the plantings on the front page 2017-12-17 10:01:51 +13:00
deppbot
c8e34b640e Bundle Update on 2017-12-14 2017-12-17 10:01:51 +13:00
Brenda Wallace
6f2b4b13cd Only show photo pagination if there are photos 2017-12-17 09:55:52 +13:00
Brenda Wallace
970da53873 Merge remote-tracking branch 'origin/feature/photos-1457' into feature/photos-1457 2017-12-17 09:15:24 +13:00
Brenda Wallace
3aa2f0bd3b Paginate photos on seeds#show (inc feature specs) 2017-12-17 08:55:08 +13:00
Shiny
8c1514bc04 Merge branch 'dev' into feature/photos-1457 2017-12-15 17:13:12 +13:00
Daniel O'Connor
d2e39f58d5 Merge pull request #1494 from Br3nda/fix/ordering
More ordering fixes
2017-12-15 12:57:08 +10:30
Brenda Wallace
3d3a3b669e Order posts by most recent 2017-12-15 13:28:41 +13:00
Brenda Wallace
8697e56323 Order the plantings on the front page 2017-12-15 13:26:48 +13:00
Shiny
472b2eb192 Merge branch 'dev' into feature/photos-1457 2017-12-15 12:10:36 +13:00
Cesy
1698157d8d Merge pull request #1492 from Growstuff/bundle-update-2017-12-14-201051
Bundle Update on 2017-12-14
2017-12-14 12:25:49 +00:00
deppbot
ff652ae234 Bundle Update on 2017-12-14 2017-12-14 20:10:52 +08:00
Brenda Wallace
25e9ef892d Merge remote-tracking branch 'origin/feature/photos-1457' into feature/photos-1457 2017-12-14 08:45:40 +13:00
Shiny
82149d4565 Merge branch 'dev' into feature/photos-1457 2017-12-14 08:44:31 +13:00
Brenda Wallace
fcd3e36e36 Removed commented out code 2017-12-14 08:42:51 +13:00
Brenda Wallace
f8e51f4b45 Merge remote-tracking branch 'origin/feature/photos-1457' into feature/photos-1457 2017-12-13 22:35:29 +13:00
Brenda Wallace
1c8b75b7cb add and show photos for seeds
close #1457
2017-12-13 22:34:16 +13:00
Shiny
700fba58e8 Merge branch 'dev' into feature/photos-1457 2017-12-13 21:52:55 +13:00
Brenda Wallace
4f64698403 Merge remote-tracking branch 'origin/feature/photos-1457' into feature/photos-1457 2017-12-09 20:59:56 +13:00
Brenda Wallace
14551b6ec8 Merge remote-tracking branch 'upstream/dev' into feature/photos-1457
Conflicts:
	spec/models/crop_spec.rb
2017-12-09 20:59:20 +13:00
Shiny
0f317f624e Merge branch 'dev' into feature/photos-1457 2017-12-07 13:40:19 +13:00
Shiny
41e26a2c74 Merge branch 'dev' into feature/photos-1457 2017-12-03 21:09:04 +13:00
Brenda Wallace
c4c659f159 DRY specs, and use create_list in crops model spec 2017-11-30 13:37:47 +13:00
Brenda Wallace
14b16b0d8c Moved photo.items's item lookup to a class method 2017-11-30 11:23:34 +13:00
Brenda Wallace
697779e67c Don't add item to photo is already there 2017-11-30 10:15:05 +13:00
Brenda Wallace
35ce8b84db Adding a unique index on the items <--> photos table 2017-11-30 09:56:47 +13:00
Brenda Wallace
ccbdfe51f6 Modified a spec to avoid a chicken and an egg 2017-11-29 22:30:11 +13:00
Brenda Wallace
ff57176d60 Simplified the photos controller a bit 2017-11-29 22:13:03 +13:00
Brenda Wallace
12700d6268 Added polymorphic relationship to photos 2017-11-29 21:41:22 +13:00
Brenda Wallace
17fd6f61a5 Added polymorphic relationship to photos 2017-11-29 20:14:27 +13:00
38 changed files with 373 additions and 274 deletions

View File

@@ -58,7 +58,7 @@ GEM
public_suffix (>= 2.0.2, < 4.0)
arel (6.0.4)
ast (2.3.0)
autoprefixer-rails (7.2.2)
autoprefixer-rails (7.2.3)
execjs
bcrypt (3.1.11)
better_errors (2.2.0)
@@ -174,7 +174,7 @@ GEM
faraday
multi_json
erubis (2.7.0)
excon (0.59.0)
excon (0.60.0)
execjs (2.7.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
@@ -297,7 +297,7 @@ GEM
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
kgio (2.11.0)
kgio (2.11.1)
kramdown (1.16.2)
launchy (2.4.3)
addressable (~> 2.3)
@@ -353,8 +353,8 @@ GEM
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0)
omniauth-oauth2 (1.5.0)
oauth2 (~> 1.1)
omniauth (~> 1.2)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
@@ -366,7 +366,7 @@ GEM
cocaine (~> 0.5.5)
mime-types
mimemagic (~> 0.3.0)
parallel (1.12.0)
parallel (1.12.1)
parser (2.4.0.2)
ast (~> 2.3)
pg (0.21.0)
@@ -376,7 +376,7 @@ GEM
moneta (~> 0.8.1)
plupload-rails (1.2.1)
rails (>= 3.1)
poltergeist (1.16.0)
poltergeist (1.17.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
@@ -475,7 +475,7 @@ GEM
ruby_parser (3.10.1)
sexp_processor (~> 4.9)
rubyzip (1.2.1)
sass (3.5.3)
sass (3.5.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)

View File

@@ -1,38 +0,0 @@
module Growstuff
module Constants
class PhotoModels
PLANTING = { type: 'planting', class: 'Planting', relation: 'plantings' }.freeze
HARVEST = { type: 'harvest', class: 'Harvest', relation: 'harvests' }.freeze
GARDEN = { type: 'garden', class: 'Garden', relation: 'gardens' }.freeze
SEED = { type: 'seed', class: 'Seed', relation: 'seeds' }.freeze
ALL = [PLANTING, HARVEST, GARDEN, SEED].freeze
def self.types
ALL.map do |model|
model[:type]
end
end
def self.relations
ALL.map do |model|
model[:relation]
end
end
def self.get_relation(object, type)
relation = ALL.select do |model|
model[:type] == type
end[0][:relation]
object.send(relation)
end
def self.get_item(type)
class_name = ALL.select do |model|
model[:type] == type
end[0][:class]
class_name.constantize
end
end
end
end

View File

@@ -0,0 +1,14 @@
module Admin
class MembersController < ApplicationController
before_action :auth!
def index
@members = Member.order(:login_name).paginate(page: params[:page])
end
private
def auth!
authorize! :manage, :all
end
end
end

View File

@@ -1,21 +1,23 @@
class Admin::OrdersController < ApplicationController
def index
authorize! :manage, :all
respond_to do |format|
format.html # index.html.haml
end
end
def search
authorize! :manage, :all
@orders = Order.search(by: params[:search_by], for: params[:search_text])
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
module Admin
class OrdersController < ApplicationController
def index
authorize! :manage, :all
respond_to do |format|
format.html # index.html.haml
end
end
respond_to do |format|
format.html # index.html.haml
def search
authorize! :manage, :all
@orders = Order.search(by: params[:search_by], for: params[:search_text])
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
respond_to do |format|
format.html # index.html.haml
end
end
end
end

View File

@@ -18,6 +18,7 @@ class HarvestsController < ApplicationController
def show
@matching_plantings = matching_plantings if @harvest.owner == current_member
@photos = @harvest.photos.order(created_at: :desc).paginate(page: params[:page])
respond_with(@harvest)
end

View File

@@ -3,11 +3,19 @@ class PhotoAssociationsController < ApplicationController
respond_to :json, :html
def destroy
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
@photo = Photo.find_by!(id: params[:photo_id], owner: current_member)
collection = Growstuff::Constants::PhotoModels.get_relation(@photo, params[:type])
item_class = Growstuff::Constants::PhotoModels.get_item(params[:type])
@item = item_class.find_by!(id: params[:id], owner_id: current_member.id)
collection.delete(@item)
@item = Photographing.item(item_id, item_class)
@item.photos.delete(@photo)
# @photo.destroy_if_unused
respond_with(@photo)
end
def item_class
params[:type].capitalize
end
def item_id
params[:id]
end
end

View File

@@ -36,7 +36,7 @@ class PhotosController < ApplicationController
@photo = find_or_create_photo_from_flickr_photo
@item = item_to_link_to
raise "Could not find this #{type} owned by you" unless @item
collection << @item unless collection.include?(@item)
@item.photos << @photo unless @item.photos.include? @photo
@photo.save! if @photo.present?
end
respond_with @photo
@@ -74,21 +74,12 @@ class PhotosController < ApplicationController
end
# Item with photos attached
#
def item_to_link_to
raise "No item id provided" if item_id.nil?
raise "No item type provided" if item_type.nil?
raise "Missing or invalid type provided" unless photos_supported_on_type?(item_type)
item_class = Growstuff::Constants::PhotoModels.get_item(item_type)
item_class.find_by!(id: params[:id], owner_id: current_member.id)
end
def collection
Growstuff::Constants::PhotoModels.get_relation(@photo, item_type)
end
def photos_supported_on_type?(_type)
Growstuff::Constants::PhotoModels.types.include?(item_type)
item_class = item_type.capitalize
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
item_class.constantize.find_by!(id: params[:id], owner_id: current_member.id)
end
#

View File

@@ -31,6 +31,7 @@ class PlantingsController < ApplicationController
@planting = Planting.includes(:owner, :crop, :garden, :photos)
.friendly
.find(params[:id])
@photos = @planting.photos.order(created_at: :desc).includes(:owner).paginate(page: params[:page])
respond_with @planting
end

View File

@@ -19,6 +19,7 @@ class SeedsController < ApplicationController
# GET /seeds/1
# GET /seeds/1.json
def show
@photos = @seed.photos.includes(:owner).order(created_at: :desc).paginate(page: params[:page])
respond_with(@seed)
end

View File

@@ -1,7 +1,13 @@
class Ability
include CanCan::Ability
def initialize(member) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def initialize(member)
anon_abilities(member)
member_abilities(member) if member.present?
admin_abilities(member) if member.present? && member.role?(:admin)
end
def anon_abilities(_member)
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
# everyone can do these things, even non-logged in
@@ -35,7 +41,9 @@ class Ability
can :read, AlternateName do |an|
an.crop.approved?
end
end
def member_abilities(member) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
return unless member
# members can see even rejected or pending crops if they requested it
@@ -126,7 +134,9 @@ class Ability
can :destroy, Follow
cannot :destroy, Follow, followed_id: member.id # can't unfollow yourself
end
def admin_abilities(member)
return unless member.role? :admin
can :read, :all

View File

@@ -1,18 +1,10 @@
require_relative '../../constants/photo_models.rb'
module PhotoCapable
extend ActiveSupport::Concern
included do
has_and_belongs_to_many :photos # rubocop:disable Rails/HasAndBelongsToMany
has_many :photos, through: :photographings, as: :photographable
has_many :photographings, as: :photographable, dependent: :destroy
before_destroy :remove_from_list
scope :has_photos, -> { includes(:photos).where.not(photos: { id: nil }) }
end
def remove_from_list
photolist = photos.to_a # save a temp copy of the photo list
photos.clear # clear relationship b/w object and photo
photolist.each(&:destroy_if_unused)
end
end

View File

@@ -1,31 +1,19 @@
require_relative '../constants/photo_models.rb'
class Photo < ActiveRecord::Base
belongs_to :owner, class_name: 'Member'
Growstuff::Constants::PhotoModels.relations.each do |relation|
has_and_belongs_to_many relation.to_sym # rubocop:disable Rails/HasAndBelongsToMany
end
PHOTO_CAPABLE = %w(Garden Planting Harvest Seed).freeze
before_destroy { all_associations.clear }
has_many :photographings, foreign_key: :photo_id, dependent: :destroy
# creates a relationship for each assignee type
PHOTO_CAPABLE.each do |type|
has_many type.downcase.pluralize.to_s.to_sym,
through: :photographings,
source: :photographable,
source_type: type
end
default_scope { joins(:owner) } # Ensures the owner still exists
def associations?
plantings.any? || harvests.any? || gardens.any? || seeds.any?
end
def all_associations
associations = []
Growstuff::Constants::PhotoModels.relations.each do |association_name|
associations << send(association_name.to_s).to_a
end
associations.flatten!
end
def destroy_if_unused
destroy if all_associations.empty?
end
# This is split into a side-effect free method and a side-effecting method
# for easier stubbing and testing.
def flickr_metadata
@@ -43,6 +31,14 @@ class Photo < ActiveRecord::Base
}
end
def associations?
photographings.size.positive?
end
def destroy_if_unused
destroy unless associations?
end
def calculate_title(info)
if id && title # already has a title saved
title

View File

@@ -0,0 +1,12 @@
class Photographing < ActiveRecord::Base
belongs_to :photo
belongs_to :photographable, polymorphic: true
def self.item(item_id, item_type)
find_by!(photographable_id: item_id, photographable_type: item_type).photographable
end
def item
find_by!(photographable_id: photographable_id, photographable_type: photographable_type).photographable
end
end

View File

@@ -26,6 +26,7 @@ class Planting < ActiveRecord::Base
scope :finished, -> { where(finished: true) }
scope :current, -> { where(finished: false) }
scope :interesting, -> { has_photos.one_per_owner }
scope :recent, -> { order(created_at: :desc) }
scope :one_per_owner, lambda {
joins("JOIN members m ON (m.id=plantings.owner_id)
LEFT OUTER JOIN plantings p2

View File

@@ -43,7 +43,7 @@ class Post < ActiveRecord::Base
# return posts sorted by recent activity
def self.recently_active
Post.all.sort do |a, b|
Post.order(created_at: :desc).sort do |a, b|
b.recent_activity <=> a.recent_activity
end
end

View File

@@ -2,16 +2,28 @@
%h2 Manage
%ul#admin_links
%li= link_to "Account types", account_types_path
%li= link_to "Alternate names", alternate_names_path
%li= link_to "Scientific names", scientific_names_path
%li= link_to "Products", products_path
%li= link_to "Roles", roles_path
%li= link_to "Forums", forums_path
%li= link_to "Newsletter subscribers", admin_newsletter_path
%li= link_to "CMS", comfy_admin_cms_path
.row
.col-md-4
%h2 Site admin
%ul#site_admin
%li= link_to "Account types", account_types_path
%li= link_to "Products", products_path
%li= link_to "Roles", roles_path
%li= link_to "Forums", forums_path
%li= link_to "CMS", comfy_admin_cms_path
%h2 Orders
.col-md-4
%h2 Crop data admin
%ul
%li= link_to "Alternate names", alternate_names_path
%li= link_to "Scientific names", scientific_names_path
.col-md-4
%h2 Member admin
%ul
%li= link_to "Newsletter subscribers", admin_newsletter_path
%li= link_to "Members", admin_members_path
= render "admin/orders/searchform"
.row
.col-md-12
%h2 Orders
= render "admin/orders/searchform"

View File

@@ -0,0 +1,15 @@
.pagination
= page_entries_info @members
= will_paginate @members
%table.table.table-striped
%tr
%th Name
%th Email
%th
%th
- @members.each do |member|
%tr
%td= ember.login_name
%td= member.email

View File

@@ -48,15 +48,4 @@
:growstuff_markdown
#{ @harvest.description != "" ? strip_tags(@harvest.description) : "No description given." }
- if !@harvest.photos.empty? || (can?(:edit, @harvest) && can?(:create, Photo))
%h2 Pictures
%ul.thumbnails
- @harvest.photos.each do |p|
.col-md-2.six-across
= render partial: 'photos/thumbnail', locals: { photo: p }
- if can?(:create, Photo) && can?(:edit, @harvest)
.col-md-2
.thumbnail{ style: 'height: 220px' }
%p{ style: 'text-align: center; padding-top: 50px' }
= link_to "Add photo", new_photo_path(type: "harvest", id: @harvest.id), class: 'btn btn-primary'
= render 'photos/item_photos', item: @harvest, type: 'harvest', photos: @photos

View File

@@ -14,7 +14,7 @@
.col-md-4.hidden-xs
- cache cache_key_for(Planting) do
%h2= t('.recently_planted')
= render partial: 'plantings/list', locals: { plantings: Planting.includes(:owner, :photos).interesting.first(6) }
= render 'plantings/list', plantings: Planting.includes(:owner, :photos).interesting.recent.first(6)
.row
.col-md-12

View File

@@ -2,7 +2,7 @@
- posts = Post.limit(6)
- if posts
= render partial: "posts/summary", locals: { posts: posts, howmany: 6 }
= render "posts/summary", posts: posts, howmany: 6
- cache cache_key_for(Forum) do
- forums = Forum.all.order(:name)

View File

@@ -0,0 +1,16 @@
- if photos.size.positive? || (can?(:edit, item) && can?(:create, Photo))
%h2 Photos
- if photos.size.positive?
.row
.pagination
= page_entries_info photos
= will_paginate photos
.row
- photos.each do |photo|
.col-md-2.six-across= render 'photos/thumbnail', photo: photo
- if can?(:create, Photo) && can?(:edit, item)
.col-md-2
.thumbnail
= link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo

View File

@@ -83,15 +83,4 @@
:growstuff_markdown
#{ @planting.description != "" ? strip_tags(@planting.description) : "No description given." }
- if !@planting.photos.empty? || (can?(:edit, @planting) && can?(:create, Photo))
%h2 Photos
.row
- @planting.photos.includes(:owner).each do |p|
.col-md-2.six-across
= render partial: 'photos/thumbnail', locals: { photo: p }
- if can?(:create, Photo) && can?(:edit, @planting)
.col-md-2
.thumbnail{ style: 'height: 220px' }
%p{ style: 'text-align: center; padding-top: 50px' }
= link_to "Add photo", new_photo_path(type: "planting", id: @planting.id), class: 'btn btn-primary'
= render 'photos/item_photos', item: @planting, type: 'planting', photos: @photos

View File

@@ -1,18 +1,19 @@
= form_for @role do |f|
- if @role.errors.any?
#error_explanation
%h2
= pluralize(@role.errors.size, "error")
prohibited this role from being saved:
%ul
- @role.errors.full_messages.each do |msg|
%li= msg
.row
- if @role.errors.any?
#error_explanation
%h2
= pluralize(@role.errors.size, "error")
prohibited this role from being saved:
%ul
- @role.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name
.col-md2= f.label :name
.col-md10= f.text_field :name
.field
= f.label :description
= f.text_area :description
.col-md2= f.label :description
.col-md10= f.text_area :description
.actions
= f.submit 'Save'
= f.submit 'Save', class: 'btn btn-default'

View File

@@ -2,6 +2,4 @@
= render 'form'
= link_to 'Show', @role
\|
= link_to 'Back', roles_path

View File

@@ -3,17 +3,16 @@
- if can? :create, Role
%p= link_to 'New Role', new_role_path, class: 'btn btn-primary'
%table
%table.table.table-striped
%tr
%th Name
%th Description
%th
%th
%th
- @roles.each do |role|
%tr
%td= link_to role.name, role
%td= role.name
%td= role.description
- if can? :edit, role
%td= link_to 'Edit', edit_role_path(role), class: 'btn btn-default btn-xs'

View File

@@ -0,0 +1,11 @@
- if can? :edit, @seed
= link_to edit_seed_path(@seed), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-pencil{ title: "Edit" }
Edit
= link_to new_photo_path(id: seed.id, type: 'seed'), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo
- if can? :destroy, @seed
= link_to @seed, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
Delete

View File

@@ -58,15 +58,11 @@
subject: "Interested in your #{@seed.crop} seeds"),
class: 'btn btn-primary'
- else
= render partial: 'shared/signin_signup', locals: { to: 'request seeds' }
= render 'shared/signin_signup', to: 'request seeds'
- if can?(:edit, @seed) || can?(:destroy, @seed)
%p
- if can? :edit, @seed
= link_to 'Edit', edit_seed_path(@seed), class: 'btn btn-default btn-xs'
- if can? :destroy, @seed
= link_to 'Delete', @seed, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs'
= render 'actions', seed: @seed
.col-md-6
= render partial: "crops/index_card", locals: { crop: @seed.crop }
- if @seed.owner.location
@@ -79,3 +75,5 @@
Or
= link_to "purchase seeds via Ebay",
crop_ebay_seeds_url(@seed.crop), target: "_blank", rel: "noopener noreferrer"
= render 'photos/item_photos', item: @seed, type: 'seed', photos: @photos

View File

@@ -90,6 +90,9 @@ Growstuff::Application.routes.draw do
get '/shop/:action' => 'shop#:action'
comfy_route :cms_admin, path: '/admin/cms'
namespace :admin do
resources :members
end
get '/admin/orders' => 'admin/orders#index'
get '/admin/orders/:action' => 'admin/orders#:action'
get '/admin' => 'admin#index'

View File

@@ -0,0 +1,54 @@
class CreatePhotographings < ActiveRecord::Migration
def change
create_table :photographings do |t|
t.integer :photo_id, null: false
t.integer :photographable_id, null: false
t.string :photographable_type, null: false
t.timestamps null: false
end
add_foreign_key :photographings, :photos
add_index :photographings, %i(photographable_id photographable_type photo_id),
unique: true, name: 'items_to_photos_idx'
add_index :photographings, %i(photographable_id photographable_type),
name: 'photographable_idx'
migrate_data
end
def migrate_data
say "migrating garden photos"
GardensPhoto.all.each do |g|
Photographing.create! photo_id: g.photo_id, photographable_id: g.garden_id, photographable_type: 'Garden'
end
say "migrating planting photos"
PhotosPlanting.all.each do |p|
Photographing.create! photo_id: p.photo_id, photographable_id: p.planting_id, photographable_type: 'Planting'
end
say "migrating harvest photos"
HarvestsPhoto.all.each do |h|
Photographing.create! photo_id: h.photo_id, photographable_id: h.harvest_id, photographable_type: 'Harvest'
end
say "migrating seed photos"
PhotosSeed.all.each do |s|
Photographing.create! photo_id: s.photo_id, photographable_id: s.seed_id, photographable_type: 'Seed'
end
end
class GardensPhoto < ActiveRecord::Base
belongs_to :photo
belongs_to :garden
end
class PhotosPlanting < ActiveRecord::Base
belongs_to :photo
belongs_to :planting
end
class HarvestsPhoto < ActiveRecord::Base
belongs_to :photo
belongs_to :harvest
end
class PhotosSeed < ActiveRecord::Base
belongs_to :photo
belongs_to :seed
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20171105011017) do
ActiveRecord::Schema.define(version: 20171129041341) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -383,6 +383,17 @@ ActiveRecord::Schema.define(version: 20171105011017) do
t.integer "product_id"
end
create_table "photographings", force: :cascade do |t|
t.integer "photo_id", null: false
t.integer "photographable_id", null: false
t.string "photographable_type", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "photographings", ["photographable_id", "photographable_type", "photo_id"], name: "items_to_photos_idx", unique: true, using: :btree
add_index "photographings", ["photographable_id", "photographable_type"], name: "photographable_idx", using: :btree
create_table "photos", force: :cascade do |t|
t.integer "owner_id", null: false
t.string "thumbnail_url", null: false
@@ -498,4 +509,5 @@ ActiveRecord::Schema.define(version: 20171105011017) do
add_index "seeds", ["slug"], name: "index_seeds_on_slug", unique: true, using: :btree
add_foreign_key "harvests", "plantings"
add_foreign_key "photographings", "photos"
end

View File

@@ -4,12 +4,12 @@ FactoryBot.define do
factory :photo do
owner
flickr_photo_id 1
title "Still life with chillies"
title { Faker::HarryPotter.quote }
license_name "CC-BY"
license_url "http://example.com/license.html"
thumbnail_url "http://example.com/thumb.jpg"
fullsize_url "http://example.com/full.jpg"
link_url "http://example.com/"
thumbnail_url { "http://example.com/#{Faker::File.file_name}.jpg" }
fullsize_url { "http://example.com/#{Faker::File.file_name}.jpg" }
link_url { Faker::Internet.url }
factory :unlicensed_photo do
license_name "All rights reserved"

View File

@@ -13,7 +13,7 @@ feature "forums", js: true do
visit root_path
click_link "Admin"
expect(current_path).to eq admin_path
within 'ul#admin_links' do
within 'ul#site_admin' do
click_link "Forums"
end
expect(current_path).to eq forums_path
@@ -25,7 +25,7 @@ feature "forums", js: true do
click_link member.login_name
click_link "Admin"
expect(current_path).to eq admin_path
within 'ul#admin_links' do
within 'ul#site_admin' do
click_link "Forums"
end
expect(current_path).to eq forums_path

View File

@@ -2,27 +2,31 @@ require 'rails_helper'
feature "crop detail page", js: true do
let(:member) { create :member }
let(:crop) { create :crop, plantings: [planting], harvests: [harvest] }
let(:planting) { create :planting, owner: member, photos: [photo1, photo2] }
let(:harvest) { create :harvest, owner: member, photos: [photo3, photo4] }
let(:planting) { create :planting, owner: member }
let(:harvest) { create :harvest, owner: member }
let(:photo1) do
create(:photo, owner: member, title: 'photo 1',
fullsize_url: 'photo1.jpg', thumbnail_url: 'thumb1.jpg')
create(:photo, owner: member, title: 'photo 1', fullsize_url: 'photo1.jpg', thumbnail_url: 'thumb1.jpg')
end
let(:photo2) do
create(:photo, owner: member, title: 'photo 2',
fullsize_url: 'photo2.jpg', thumbnail_url: 'thumb2.jpg')
create(:photo, owner: member, title: 'photo 2', fullsize_url: 'photo2.jpg', thumbnail_url: 'thumb2.jpg')
end
let(:photo3) do
create(:photo, owner: member, title: 'photo 3',
fullsize_url: 'photo3.jpg', thumbnail_url: 'thumb3.jpg')
create(:photo, owner: member, title: 'photo 3', fullsize_url: 'photo3.jpg', thumbnail_url: 'thumb3.jpg')
end
let(:photo4) do
create(:photo, owner: member, title: 'photo 4',
fullsize_url: 'photo4.jpg', thumbnail_url: 'thumb4.jpg')
create(:photo, owner: member, title: 'photo 4', fullsize_url: 'photo4.jpg', thumbnail_url: 'thumb4.jpg')
end
before { visit crop_path(crop) }
before do
planting.photos << photo1
planting.photos << photo2
harvest.photos << photo3
harvest.photos << photo4
visit crop_path(crop)
end
subject { page }
shared_examples "shows photos" do

View File

@@ -0,0 +1,41 @@
require 'rails_helper'
require 'custom_matchers'
feature "Seeds", :js do
let(:member) { FactoryBot.create :member }
let!(:seed) { FactoryBot.create :seed, owner: member }
subject do
login_as member
visit seed_path(seed)
page
end
it { is_expected.to have_content 'Add photo' }
# context 'no photos' do
# it { is_expected.to have_content 'no photos' }
# end
context 'has one photo' do
before { seed.photos = [photo] }
let!(:photo) { FactoryBot.create :photo, title: 'hello photo' }
it { is_expected.to have_xpath("//img[contains(@src,'#{photo.thumbnail_url}')]") }
it { is_expected.to have_xpath("//a[contains(@href,'#{photo_path(photo)}')]") }
end
context 'has 50 photos' do
before { seed.photos = photos }
let!(:photos) { FactoryBot.create_list :photo, 50 }
it "shows newest photo" do
is_expected.to have_xpath("//img[contains(@src,'#{photos.last.thumbnail_url}')]")
end
it "links to newest photo" do
is_expected.to have_xpath("//a[contains(@href,'#{photo_path(photos.last)}')]")
end
it "does not show oldest photo" do
is_expected.not_to have_xpath("//img[contains(@src,'#{photos.first.thumbnail_url}')]")
end
it "does not link to oldest photo" do
is_expected.not_to have_xpath("//a[contains(@href,'#{photo_path(photos.first)}')]")
end
end
end

View File

@@ -269,78 +269,55 @@ describe Crop do
end
context 'interesting' do
it 'lists interesting crops' do
# first, a couple of candidate crops
@crop1 = FactoryBot.create(:crop)
@crop2 = FactoryBot.create(:crop)
let(:photo) { FactoryBot.create :photo }
# first, a couple of candidate crops
let(:crop1) { FactoryBot.create(:crop) }
let(:crop2) { FactoryBot.create(:crop) }
# they need 3+ plantings each to be interesting
3.times do
FactoryBot.create(:planting, crop: @crop1)
end
3.times do
FactoryBot.create(:planting, crop: @crop2)
let(:crop1_planting) { crop1.plantings.first }
let(:crop2_planting) { crop2.plantings.first }
subject { Crop.interesting }
describe 'lists interesting crops' do
before do
# they need 3+ plantings each to be interesting
FactoryBot.create_list(:planting, 3, crop: crop1)
FactoryBot.create_list(:planting, 3, crop: crop2)
# crops need 3+ photos to be interesting
crop1_planting.photos = FactoryBot.create_list :photo, 3
crop2_planting.photos = FactoryBot.create_list :photo, 3
end
# crops need 3+ photos to be interesting
@photo = FactoryBot.create(:photo)
[@crop1, @crop2].each do |c|
3.times do
c.plantings.first.photos << @photo
c.plantings.first.save
end
end
Crop.interesting.should include @crop1
Crop.interesting.should include @crop2
Crop.interesting.size.should == 2
it { is_expected.to include crop1 }
it { is_expected.to include crop2 }
it { expect(subject.size).to eq 2 }
end
it 'ignores crops without plantings' do
# first, a couple of candidate crops
@crop1 = FactoryBot.create(:crop)
@crop2 = FactoryBot.create(:crop)
# only crop1 has plantings
3.times do
FactoryBot.create(:planting, crop: @crop1)
describe 'crops without plantings are not interesting' do
before do
# only crop1 has plantings
FactoryBot.create_list(:planting, 3, crop: crop1)
# ... and photos
crop1_planting.photos = FactoryBot.create_list(:photo, 3)
end
# ... and photos
@photo = FactoryBot.create(:photo)
3.times do
@crop1.plantings.first.photos << @photo
@crop1.plantings.first.save
end
Crop.interesting.should include @crop1
Crop.interesting.should_not include @crop2
Crop.interesting.size.should == 1
it { is_expected.to include crop1 }
it { is_expected.not_to include crop2 }
it { expect(subject.size).to eq 1 }
end
it 'ignores crops without photos' do
# first, a couple of candidate crops
@crop1 = FactoryBot.create(:crop)
@crop2 = FactoryBot.create(:crop)
describe 'crops without photos are not interesting' do
before do
# both crops have plantings
FactoryBot.create_list(:planting, 3, crop: crop1)
FactoryBot.create_list(:planting, 3, crop: crop2)
# both crops have plantings
3.times do
FactoryBot.create(:planting, crop: @crop1)
# but only crop1 has photos
crop1_planting.photos = FactoryBot.create_list(:photo, 3)
end
3.times do
FactoryBot.create(:planting, crop: @crop2)
end
# but only crop1 has photos
@photo = FactoryBot.create(:photo)
3.times do
@crop1.plantings.first.photos << @photo
@crop1.plantings.first.save
end
Crop.interesting.should include @crop1
Crop.interesting.should_not include @crop2
Crop.interesting.size.should == 1
it { is_expected.to include crop1 }
it { is_expected.not_to include crop2 }
it { expect(subject.size).to eq 1 }
end
end
@@ -349,34 +326,20 @@ describe Crop do
let(:pp2) { FactoryBot.create(:plant_part) }
context "harvests" do
let(:h1) do
FactoryBot.create(:harvest,
crop: maize,
plant_part: pp1)
end
let(:h2) do
FactoryBot.create(:harvest,
crop: maize,
plant_part: pp2)
end
let(:h1) { FactoryBot.create(:harvest, crop: maize, plant_part: pp1) }
let(:h2) { FactoryBot.create(:harvest, crop: maize, plant_part: pp2) }
let!(:crop) { FactoryBot.create(:crop) }
let!(:harvest) { FactoryBot.create(:harvest, crop: crop) }
it "has harvests" do
crop = FactoryBot.create(:crop)
harvest = FactoryBot.create(:harvest, crop: crop)
crop.harvests.should eq [harvest]
expect(crop.harvests).to eq [harvest]
end
end
it "doesn't duplicate plant_parts" do
@maize = FactoryBot.create(:maize)
@pp1 = FactoryBot.create(:plant_part)
@h1 = FactoryBot.create(:harvest,
crop: @maize,
plant_part: @pp1)
@h2 = FactoryBot.create(:harvest,
crop: @maize,
plant_part: @pp1)
@h1 = FactoryBot.create(:harvest, crop: @maize, plant_part: @pp1)
@h2 = FactoryBot.create(:harvest, crop: @maize, plant_part: @pp1)
@maize.plant_parts.should eq [@pp1]
end

View File

@@ -6,6 +6,7 @@ describe "harvests/show" do
before do
controller.stub(:current_user) { nil }
assign(:harvest, harvest)
assign(:photos, harvest.photos.paginate(page: 1))
render
end

View File

@@ -12,6 +12,7 @@ describe "plantings/show" do
before(:each) do
assign(:planting, planting)
assign(:photos, planting.photos.paginate(page: 1))
controller.stub(:current_user) { member }
end

View File

@@ -5,6 +5,7 @@ describe "seeds/show" do
controller.stub(:current_user) { nil }
@seed = FactoryBot.create(:seed)
assign(:seed, @seed)
assign(:photos, @seed.photos.paginate(page: 1))
end
it "renders attributes in <p>" do