From 050dfda77e2acf91dcd6cd0e125582379aade738 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sun, 7 Jul 2019 22:03:15 +1200 Subject: [PATCH] Timeline --- app/controllers/members_controller.rb | 78 +------------------ app/controllers/timeline_controller.rb | 11 +++ app/services/timeline_service.rb | 104 +++++++++++++++++++++++++ app/views/members/show.html.haml | 2 +- app/views/timeline/index.html.haml | 55 +++++++++++++ config/routes.rb | 1 + spec/services/timeline_service_spec.rb | 16 ++++ 7 files changed, 189 insertions(+), 78 deletions(-) create mode 100644 app/controllers/timeline_controller.rb create mode 100644 app/services/timeline_service.rb create mode 100644 app/views/timeline/index.html.haml create mode 100644 spec/services/timeline_service_spec.rb diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 4c8414894..76411b0ec 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -19,16 +19,7 @@ class MembersController < ApplicationController @facebook_auth = @member.auth('facebook') @posts = @member.posts - # TODO: Consider shifting all of these onto a member activity model? - @activity = plantings_for_show - .union_all(harvests_for_show) - .union_all(posts_for_show) - .union_all(comments_for_show) - .union_all(photos_for_show) - .union_all(seeds_for_show) - .where(owner_id: @member.id) - .order(event_at: :desc) - .limit(30) + @activity = TimelineService.member_query(@member).limit(30) # The garden form partial is called from the "New Garden" tab; # it requires a garden to be passed in @garden. @@ -100,71 +91,4 @@ class MembersController < ApplicationController Member.order(:login_name) end.confirmed.paginate(page: params[:page]) end - - # Queries for the show view/action - def plantings_for_show - Planting.select( - :id, - "'planting' as event_type", - 'planted_at as event_at', - :owner_id, - :crop_id, - :slug - ) - end - - def harvests_for_show - Harvest.select( - :id, - "'harvest' as event_type", - 'harvested_at as event_at', - :owner_id, - :crop_id, - :slug - ) - end - - def posts_for_show - Post.select( - :id, - "'post' as event_type", - 'posts.created_at as event_at', - 'author_id as owner_id', - 'null as crop_id', - :slug - ) - end - - def comments_for_show - Comment.select( - :id, - "'comment' as event_type", - 'comments.created_at as event_at', - 'author_id as owner_id', - 'null as crop_id', - 'null as slug' - ) - end - - def photos_for_show - Photo.select( - :id, - "'photo' as event_type", - "photos.created_at as event_at", - 'photos.owner_id', - 'null as crop_id', - 'null as slug' - ) - end - - def seeds_for_show - Seed.select( - :id, - "'seed' as event_type", - "seeds.created_at as event_at", - 'seeds.owner_id', - 'crop_id', - 'slug' - ) - end end diff --git a/app/controllers/timeline_controller.rb b/app/controllers/timeline_controller.rb new file mode 100644 index 000000000..da912e69a --- /dev/null +++ b/app/controllers/timeline_controller.rb @@ -0,0 +1,11 @@ +class TimelineController < ApplicationController + def index + if current_member + @timeline = TimelineService.followed_query(current_member).paginate(page: params[:page]) + @members = current_member.followed + else + @timeline = TimelineService.query.paginate(page: params[:page]) + @members = Member.interesting.limit 10 + end + end +end diff --git a/app/services/timeline_service.rb b/app/services/timeline_service.rb new file mode 100644 index 000000000..23074732b --- /dev/null +++ b/app/services/timeline_service.rb @@ -0,0 +1,104 @@ +class TimelineService + def self.member_query(member) + self.query.where(owner_id: member.id) + end + + # A timeline of events by people the member follows + def self.followed_query(member) + self.query.where(owner_id: [member.followed.pluck(:id)]) + end + + def self.query + plantings_query + .union_all(harvests_query) + .union_all(posts_query) + .union_all(comments_query) + .union_all(photos_query) + .union_all(seeds_query) + .where.not(event_at: nil) + .order(event_at: :desc) + end + + def self.resolve_model(event) + if event.event_type == 'planting' + Planting.find(event.id) + elsif event.event_type == 'seed' + Seed.find(event.id) + elsif event.event_type == 'harvest' + Harvest.find(event.id) + elsif event.event_type == 'comment' + Comment.find(event.id) + elsif event.event_type == 'post' + Post.find(event.id) + elsif event.event_type == 'photo' + Photo.find(event.id) + end + end + + def self.plantings_query + Planting.select( + :id, + "'planting' as event_type", + 'planted_at as event_at', + :owner_id, + :crop_id, + :slug + ) + end + + def self.harvests_query + Harvest.select( + :id, + "'harvest' as event_type", + 'harvested_at as event_at', + :owner_id, + :crop_id, + :slug + ) + end + + def self.posts_query + Post.select( + :id, + "'post' as event_type", + 'posts.created_at as event_at', + 'author_id as owner_id', + 'null as crop_id', + :slug + ) + end + + def self.comments_query + Comment.select( + :id, + "'comment' as event_type", + 'comments.created_at as event_at', + 'author_id as owner_id', + 'null as crop_id', + 'null as slug' + ) + end + + def self.photos_query + Photo.select( + :id, + "'photo' as event_type", + "photos.created_at as event_at", + 'photos.owner_id', + 'null as crop_id', + 'null as slug' + ) + end + + def self.seeds_query + Seed.select( + :id, + "'seed' as event_type", + "seeds.created_at as event_at", + 'seeds.owner_id', + 'crop_id', + 'slug' + ) + end + +end diff --git a/app/views/members/show.html.haml b/app/views/members/show.html.haml index eb6867759..8bce5be3a 100644 --- a/app/views/members/show.html.haml +++ b/app/views/members/show.html.haml @@ -94,7 +94,7 @@ - photo = Photo.find(event.id) = photo_icon took a photo - = link_to photo, photo.title + = link_to photo.title, photo .media = link_to(image_tag(photo.fullsize_url, width: 150, class: 'rounded'), photo) .media-body diff --git a/app/views/timeline/index.html.haml b/app/views/timeline/index.html.haml new file mode 100644 index 000000000..9a05976ba --- /dev/null +++ b/app/views/timeline/index.html.haml @@ -0,0 +1,55 @@ +%h1 Timeline + +.row + .col-md-9 + + .pagination + = page_entries_info @seeds + = will_paginate @seeds + + .list-group-item.list-group-item-action.flex-column.align-items-start.active{:href => "#!"} + - @timeline.each do |event| + - event_model = TimelineService.resolve_model(event) + - owner = Member.find(event.owner_id) + .d-flex.justify-content-between + %h5 + = render 'members/tiny', member: owner + - if event.event_type == 'planting' + = planting_icon + = link_to owner, owner + planted #{link_to event_model.crop, event_model} + - elsif event.event_type == 'seed' + = seed_icon + = link_to owner, owner + saved #{link_to event_model.crop, event_model} seeds + - elsif event.event_type == 'harvest' + = harvest_icon + = link_to owner, owner + harvested #{link_to event_model, event_model} + - elsif event.event_type == 'comment' + = comment_icon + = link_to owner, owner + #{link_to 'commented', event_model} on #{link_to event_model.post, event_model.post} + - elsif event.event_type == 'post' + = blog_icon + = link_to owner, owner + wrote a post about #{link_to event_model, event_model} + - elsif event.event_type == 'photo' + = photo_icon + = link_to owner, owner + took a photo #{link_to event_model.title, event_model} + %small= time_ago_in_words event.event_at + - if event.crop_id.present? + = render 'crops/thumbnail', crop: event_model.crop + .pagination + = page_entries_info @seeds + = will_paginate @seeds + .col-md-3 + .card + .card-header + %h3 Following + - @members.each do |member| + = link_to member do + %p + = render 'members/tiny', member: member + = member diff --git a/config/routes.rb b/config/routes.rb index ff1687d52..aa93d3c5d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -84,6 +84,7 @@ Rails.application.routes.draw do resources :follows, only: %i(create destroy) resources :likes, only: %i(create destroy) + resources :timeline resources :members, param: :slug do resources :gardens diff --git a/spec/services/timeline_service_spec.rb b/spec/services/timeline_service_spec.rb new file mode 100644 index 000000000..e023da518 --- /dev/null +++ b/spec/services/timeline_service_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe 'timeline' do + let(:member) { FactoryBot.create :member } + let(:friend) { FactoryBot.create :member } + describe 'followed_by(member)' do + let!(:planting) { FactoryBot.create :planting, owner: friend, planted_at: 1.day.ago } + let!(:harvest) { FactoryBot.create :harvest, owner: friend, harvested_at: 2.days.ago } + before {friend.followers << member } + subject { TimelineService.followed_query(member) } + it { expect(subject.first).to eq planting } + it { expect(TimelineService.resolve_model(subject.second)).to eq harvest } + end + + describe +end