Compare commits

..

7 Commits

Author SHA1 Message Date
Daniel O'Connor
d57ca1b4bb Merge branch 'dev' into fix-3278 2024-07-23 19:44:09 +09:30
Daniel O'Connor
dc4133abd2 Merge branch 'dev' into fix-3278 2024-07-17 20:06:48 +09:30
Daniel O'Connor
0b4bdc6946 Re-add expectation 2024-07-13 09:55:06 +00:00
Daniel O'Connor
3d308db0d9 'Only required for wrangers, and only when approving 2024-07-13 09:54:31 +00:00
Daniel O'Connor
bfa1ae3ae2 Require a name 2024-07-13 09:42:20 +00:00
Daniel O'Connor
71ef2c058b Require a URL 2024-07-13 09:41:35 +00:00
Daniel O'Connor
b42385be14 Fix #3278 by ensuring we rebuild names on error 2024-07-13 09:39:58 +00:00
21 changed files with 118 additions and 222 deletions

View File

@@ -255,10 +255,10 @@ GEM
railties (>= 5.0.0)
faker (3.4.2)
i18n (>= 1.8.11, < 2)
faraday (2.10.1)
faraday (2.10.0)
faraday-net_http (>= 2.0, < 3.2)
logger
faraday-net_http (3.1.1)
faraday-net_http (3.1.0)
net-http
ffi (1.16.3)
flickraw (0.9.10)
@@ -434,7 +434,7 @@ GEM
racc
percy-capybara (5.0.0)
capybara (>= 3)
pg (1.5.7)
pg (1.5.6)
platform-api (3.7.0)
heroics (~> 0.1.1)
moneta (~> 1.0.0)
@@ -449,7 +449,7 @@ GEM
puma (6.4.2)
nio4r (~> 2.0)
query_diet (0.7.1)
racc (1.8.1)
racc (1.8.0)
rack (2.2.9)
rack-cors (2.0.2)
rack (>= 2.0.0)
@@ -522,7 +522,7 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.3.4)
rexml (3.3.2)
strscan
rouge (4.1.2)
rspec (3.13.0)
@@ -564,7 +564,7 @@ GEM
rswag-ui (2.13.0)
actionpack (>= 3.1, < 7.2)
railties (>= 3.1, < 7.2)
rubocop (1.65.1)
rubocop (1.65.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)

View File

@@ -1,19 +1,11 @@
$(document).ready(function() {
$('.like-btn').show();
/**
* Handles the result of an ajax call and updates UI
*
* @param {object} data JSON data from ajax response
* @param {string} type object type (ie: post, activity, etc)
*/
var likeableSuccess = function(data, type) {
var target = '.' + type + '-' + data.id;
var objectClass = type.charAt(0).toUpperCase() + type.slice(1);
var likeButton = $(target + ' .' + type + '-like');
var likeBadge = $(target + ' .like-badge');
$('.post-like').on('ajax:success', function(event, data) {
var likeButton = $('#post-' + data.id + ' .post-like');
var likeBadge = $('#post-'+ data.id + ' .like-badge');
$(target + ' .like-count').text(data.like_count);
$('#post-' + data.id + ' .like-count').text(data.like_count);
if (data.liked_by_member) {
likeBadge.addClass('liked');
likeButton.data('method', 'delete');
@@ -22,26 +14,11 @@ $(document).ready(function() {
} else {
likeBadge.removeClass('liked');
likeButton.data('method', 'post');
likeButton.attr('href', '/likes.json?type=' + objectClass + '&id=' + data.id);
likeButton.attr('href', '/likes.json?type=Post&id=' + data.id);
likeButton.text('Like');
}
};
$('.post-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'post');
});
$('.activity-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'activity');
});
$('.planting-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'planting');
});
$('.harvest-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'harvest');
});
$('.photo-like').on('ajax:success', function(event, data) {
var likeBadge = $('#photo-'+ data.id + ' .like-badge');

View File

@@ -5,7 +5,6 @@ class Activity < ApplicationRecord
include Ownable
include Finishable
include SearchActivities
include Likeable
belongs_to :garden, optional: true
belongs_to :planting, optional: true

View File

@@ -6,7 +6,6 @@ class Harvest < ApplicationRecord
include PhotoCapable
include Ownable
include SearchHarvests
include Likeable
friendly_id :harvest_slug, use: %i(slugged finders)

View File

@@ -8,7 +8,6 @@ class Planting < ApplicationRecord
include PredictPlanting
include PredictHarvest
include SearchPlantings
include Likeable
friendly_id :planting_slug, use: %i(slugged finders)

View File

@@ -1,5 +1,5 @@
- if can?(:edit, activity)
%span.dropdown.activity-actions
.dropdown.activity-actions
%a#activity-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions
.dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "planting-actions-button"}
= activity_edit_button(activity, classes: 'dropdown-item')

View File

@@ -22,17 +22,19 @@
%small.text-muted= @activity.category
%tt
= @activity.due_date
- if @activity.description.present?
:markdown
#{strip_tags markdownify(@activity.description)}
= render 'likes/likes', object: @activity
= render 'activities/actions', activity: @activity
.col-md-4.col-xs-12
= render 'activities/owner', planting: @activity
.col-md-8.col-xs-12
- if @activity.description.present?
= cute_icon
.card
.card-header
%h2 Description
.card-body
:markdown
#{strip_tags markdownify(@activity.description)}
- if @activity.garden
%section.gardens
@@ -46,3 +48,4 @@
.col-md-4.col-xs-12
= render 'activities/actions', activity: @activity

View File

@@ -1,5 +1,5 @@
- if can?(:edit, harvest)
%span.dropdown.harvest-actions
.dropdown.harvest-actions
%a#harvest-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions
.dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "harvest-actions-button"}
= harvest_edit_button(harvest, classes: 'dropdown-item')

View File

@@ -15,26 +15,13 @@
.harvest
.row
.col-md-8.col-xs-12
.jumbotron
.d-flex.justify-content-between
%h1.display-3
= harvest_icon
%strong= @harvest.crop
%small.text-muted
harvested by
= @harvest.owner
- if @harvest.description.present?
:markdown
#{strip_tags markdownify(@harvest.description)}
= render partial: 'planting'
= render 'likes/likes', object: @harvest
= render 'harvests/actions', harvest: @harvest
%h1
= harvest_icon
#{@harvest.crop} harvested by #{@harvest.owner}
.col-md-4.col-xs-12
= render 'harvests/owner', harvest: @harvest
= render 'harvests/actions', harvest: @harvest
.col-md-8.col-xs-12
= render partial: 'planting'
.index-cards.facts
- if @harvest.plant_part
.card
@@ -66,5 +53,14 @@
Havested from
= link_to @harvest.planting, @harvest.planting
- if @harvest.description.present?
.card
.card-header
%h2 Notes
.card-body
:markdown
#{strip_tags markdownify(@harvest.description)}
.col-md-4.col-xs-12
= render 'harvests/owner', harvest: @harvest
= render @harvest.crop

View File

@@ -1,4 +1,4 @@
%span.badge.like-badge{class: liked ? 'liked' : ''}
= like_icon
&nbsp;
%span.like-count{title: t('buttons.total_likes')}= likeable.likes_count
%span.like-count= likeable.likes_count

View File

@@ -1,18 +0,0 @@
%span.likes
- if member_signed_in? && can?(:new, Like)
- if !object.liked_by?(current_member)
= link_to likes_path(type: object.class.name, id: object.id, format: :json),
title: t('buttons.like'),
method: :post,
remote: true,
class: "#{object.class.name.downcase}-#{object.id} #{object.class.name.downcase}-like like-btn btn" do
= render 'likes/count', likeable: object, liked: false
- else
= link_to likes_path(type: object.class.name, id: object.id, format: :json),
title: t('buttons.unlike'),
method: :delete,
remote: true,
class: "#{object.class.name.downcase}-#{object.id} #{object.class.name.downcase}-like like-btn btn" do
= render 'likes/count', likeable: object, liked: true
- else
= render 'likes/count', likeable: object, liked: member_signed_in? && object.liked_by?(current_member)

View File

@@ -1,7 +1,7 @@
- if can?(:edit, @photo) && can?(:destroy, @photo)
.dropdown.float-right.photo-actions
%a#photo-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions
.dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "photo-actions-button"}
%a#harvest-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions
.dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "harvest-actions-button"}
= edit_button(edit_photo_path(@photo), classes: 'dropdown-item')
.dropdown-divider
= delete_button(@photo, classes: 'dropdown-item text-danger')

View File

@@ -28,12 +28,12 @@
= render 'crops/thumbnail', crop: crop
.col-md-3
%p
%span.btn= render 'photos/likes', photo: @photo
= render 'photos/actions', photo: @photo
= link_to @photo.link_url, class: 'btn btn-info' do
- if @photo.source == 'flickr'
= icon 'fab', 'flickr'
View on #{@photo.source.titleize}
%span.btn= render 'photos/likes', photo: @photo
- if @photo.date_taken.present?
%h3 Taken on #{I18n.l @photo.date_taken.to_date}

View File

@@ -1,5 +1,5 @@
- if can?(:edit, planting)
%span.dropdown.planting-actions
.dropdown.planting-actions
%a#planting-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions
.dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "planting-actions-button"}
= planting_edit_button(planting, classes: 'dropdown-item')

View File

@@ -43,8 +43,6 @@
%strong #{@planting.age_in_days}/#{@planting.expected_lifespan} days
= render 'timeline', planting: @planting
= render 'likes/likes', object: @planting
= render 'plantings/actions', planting: @planting
.col-md-4.col-xs-12
= render 'plantings/owner', planting: @planting
@@ -81,6 +79,8 @@
.col-md-4.col-xs-12
= render 'plantings/actions', planting: @planting
%hr/
= render @planting.crop
- if @planting.location

View File

@@ -0,0 +1,10 @@
- if member_signed_in? && can?(:new, Like)
- if !post.liked_by?(current_member)
= link_to 'Like', likes_path(type: 'Post', id: post.id, format: :json),
method: :post, remote: true, class: 'post-like btn like-btn'
- else
= link_to 'Unlike', likes_path(type: 'Post', id: post.id, format: :json),
method: :delete, remote: true, class: 'post-like btn like-btn'
= render 'likes/count', likeable: post, liked: member_signed_in? && post.liked_by?(current_member)

View File

@@ -45,7 +45,7 @@
= render 'photos/thumbnail', photo: photo
.card-footer
= render 'likes/likes', object: @post
= render 'posts/likes', post: @post
.float-right
- if can? :create, Comment
= link_to new_comment_path(post_id: @post.id), class: 'btn' do

View File

@@ -92,9 +92,6 @@ en:
save_seeds: Save seeds
timeline: Timeline
write_blog_post: Write blog post
like: Like
unlike: Remove like
total_likes: Total likes
crops:
search: Search crops
index:

View File

@@ -1,17 +0,0 @@
# frozen_string_literal: true
class LikeEverything < ActiveRecord::Migration[7.1]
def change
change_table :activities do |t|
t.integer :likes_count, default: 0
end
change_table :plantings do |t|
t.integer :likes_count, default: 0
end
change_table :harvests do |t|
t.integer :likes_count, default: 0
end
end
end

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
ActiveRecord::Schema[7.1].define(version: 2024_02_18_053122) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -54,14 +54,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
t.integer "likes_count", default: 0
t.index ["garden_id"], name: "index_activities_on_garden_id"
t.index ["owner_id"], name: "index_activities_on_owner_id"
t.index ["planting_id"], name: "index_activities_on_planting_id"
@@ -214,13 +206,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.text "body", null: false
t.datetime "created_at", precision: nil
t.datetime "updated_at", precision: nil
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
end
create_table "crop_companions", force: :cascade do |t|
@@ -329,7 +314,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.integer "plant_part_id"
t.float "si_weight"
t.integer "planting_id"
t.integer "likes_count", default: 0
t.index ["planting_id"], name: "index_harvests_on_planting_id"
end
@@ -504,13 +488,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.datetime "date_taken", precision: nil
t.integer "likes_count", default: 0
t.string "source"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
t.index ["fullsize_url"], name: "index_photos_on_fullsize_url", unique: true
t.index ["thumbnail_url"], name: "index_photos_on_thumbnail_url", unique: true
end
@@ -553,14 +530,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.integer "days_to_last_harvest"
t.integer "parent_seed_id"
t.integer "harvests_count", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
t.integer "likes_count", default: 0
t.index ["slug"], name: "index_plantings_on_slug", unique: true
end
@@ -574,13 +543,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.integer "forum_id"
t.integer "likes_count", default: 0
t.integer "comments_count", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
t.index ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id"
t.index ["slug"], name: "index_posts_on_slug", unique: true
end
@@ -628,22 +590,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
t.index ["slug"], name: "index_seeds_on_slug", unique: true
end
create_table "votes", force: :cascade do |t|
t.string "votable_type"
t.bigint "votable_id"
t.string "voter_type"
t.bigint "voter_id"
t.boolean "vote_flag"
t.string "vote_scope"
t.integer "vote_weight"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
t.index ["votable_type", "votable_id"], name: "index_votes_on_votable"
t.index ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"
t.index ["voter_type", "voter_id"], name: "index_votes_on_voter"
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "harvests", "plantings"

View File

@@ -5,10 +5,7 @@ require 'rails_helper'
describe 'Likeable', :js, :search do
let(:another_member) { FactoryBot.create(:london_member) }
let!(:post) { FactoryBot.create(:post, :reindex, author: member) }
let!(:activity) { FactoryBot.create(:activity, :reindex, owner: member) }
let!(:photo) { FactoryBot.create(:photo, :reindex, owner: member) }
let!(:harvest) { FactoryBot.create(:harvest, :reindex, owner: member) }
let!(:planting) { FactoryBot.create(:planting, :reindex, owner: member) }
before do
Photo.reindex
@@ -16,55 +13,55 @@ describe 'Likeable', :js, :search do
include_context 'signed in member'
shared_examples 'object can be liked' do
it 'can be liked' do
visit path
expect(page).to have_css(like_count_class, text: "0")
click_link '0', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
# Reload page
visit path
expect(page).to have_css(like_count_class, text: "1")
expect(page).to have_link '1'
click_link '1', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "0")
end
it 'displays correct number of likes' do
visit path
expect(page).to have_css(like_count_class, text: "0")
expect(page).to have_link '0'
click_link '0', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
logout(member)
login_as(another_member)
visit path
expect(page).to have_css(like_count_class, text: "1")
click_link '1', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "2")
logout(another_member)
end
end
describe 'photos' do
def like_count_class
"#photo-#{photo.id} .like-count"
end
shared_examples 'photo can be liked' do
it 'can be liked' do
visit path
expect(page).to have_css(like_count_class, text: "0")
click_link '0', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
# Reload page
visit path
expect(page).to have_css(like_count_class, text: "1")
expect(page).to have_link '1'
click_link '1', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "0")
end
it 'displays correct number of likes' do
visit path
expect(page).to have_css(like_count_class, text: "0")
expect(page).to have_link '0'
click_link '0', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
logout(member)
login_as(another_member)
visit path
expect(page).to have_css(like_count_class, text: "1")
click_link '1', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "2")
logout(another_member)
end
end
describe 'photos#index' do
let(:path) { photos_path }
include_examples 'object can be liked'
include_examples 'photo can be liked'
end
describe 'photos#show' do
let(:path) { photo_path(photo) }
include_examples 'object can be liked'
include_examples 'photo can be liked'
end
describe 'crops#show' do
@@ -74,35 +71,43 @@ describe 'Likeable', :js, :search do
before { planting.photos << photo }
include_examples 'object can be liked'
include_examples 'photo can be liked'
end
end
describe 'posts' do
let(:like_count_class) { ".post-#{post.id} .like-count" }
let(:path) { post_path(post) }
let(:like_count_class) { "#post-#{post.id} .like-count" }
include_examples 'object can be liked'
end
before { visit post_path(post) }
describe 'activities' do
let(:like_count_class) { ".activity-#{activity.id} .like-count" }
let(:path) { activity_path(activity) }
it 'can be liked' do
expect(page).to have_css(like_count_class, text: "0")
expect(page).to have_link 'Like'
click_link 'Like', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
include_examples 'object can be liked'
end
# Reload page
visit post_path(post)
expect(page).to have_css(like_count_class, text: "1")
expect(page).to have_link 'Unlike'
describe 'plantings' do
let(:like_count_class) { ".planting-#{planting.id} .like-count" }
let(:path) { planting_path(planting) }
click_link 'Unlike', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "0")
end
include_examples 'object can be liked'
end
it 'displays correct number of likes' do
expect(page).to have_link 'Like'
click_link 'Like', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "1")
describe 'harvests' do
let(:like_count_class) { ".harvest-#{harvest.id} .like-count" }
let(:path) { harvest_path(harvest) }
logout(member)
login_as(another_member)
visit post_path(post)
include_examples 'object can be liked'
expect(page).to have_link 'Like'
click_link 'Like', class: 'like-btn'
expect(page).to have_css(like_count_class, text: "2")
logout(another_member)
end
end
end