Add point weights for tag follows (#1229)
* Add point weights for tag follows * Adjust num articles to initially show up on home page * Fix schema.rb * Adjust follow policy spec * Adjust dashboard styling for follow points form
This commit is contained in:
parent
b51042f035
commit
651ab3ce35
16 changed files with 191 additions and 15 deletions
|
|
@ -31,7 +31,14 @@ function insertNewArticles(user){
|
|||
var articlePoints = 0
|
||||
var containsUserID = findOne([article.user_id], user.followed_user_ids || [])
|
||||
var containsOrganizationID = findOne([article.organization_id], user.followed_organization_ids || [])
|
||||
articlePoints = articlePoints + (intersect_arrays(user.followed_tag_names, article.cached_tag_list_array).length*2) + article.positive_reactions_count
|
||||
var intersectedTags = intersect_arrays(user.followed_tag_names, article.cached_tag_list_array)
|
||||
var followedPoints = 1
|
||||
JSON.parse(user.followed_tags).map(function(tag) {
|
||||
if (intersectedTags.includes(tag.name)) {
|
||||
followedPoints = followedPoints + tag.points
|
||||
}
|
||||
})
|
||||
articlePoints = articlePoints + (followedPoints*2) + article.positive_reactions_count
|
||||
if (containsUserID || article.user_id === user.id) {
|
||||
articlePoints = articlePoints + 16
|
||||
}
|
||||
|
|
@ -61,7 +68,14 @@ function insertTopArticles(user){
|
|||
var articlePoints = 0
|
||||
var containsUserID = findOne([article.user_id], user.followed_user_ids || [])
|
||||
var containsOrganizationID = findOne([article.organization_id], user.followed_organization_ids || [])
|
||||
articlePoints = articlePoints + intersect_arrays(user.followed_tag_names, article.cached_tag_list_array).length
|
||||
var intersectedTags = intersect_arrays(user.followed_tag_names, article.cached_tag_list_array)
|
||||
var followedPoints = 1
|
||||
JSON.parse(user.followed_tags).map(function(tag) {
|
||||
if (intersectedTags.includes(tag.name)) {
|
||||
followedPoints = followedPoints + tag.points
|
||||
}
|
||||
})
|
||||
articlePoints = articlePoints + followedPoints
|
||||
if (containsUserID) {
|
||||
articlePoints = articlePoints + 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@
|
|||
}
|
||||
h2{
|
||||
font-weight:500;
|
||||
margin-bottom:5px;
|
||||
margin-bottom:10px;
|
||||
margin-top:8px;
|
||||
font-size:22px;
|
||||
@media screen and ( min-width: 800px ) {
|
||||
|
|
@ -182,6 +182,30 @@
|
|||
font-size: 0.6em;
|
||||
vertical-align:0.16em;
|
||||
}
|
||||
form {
|
||||
background: $light-gray;
|
||||
padding: 8px 15px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
@media screen and ( min-width: 750px ) {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
}
|
||||
input {
|
||||
font-size: 16px;
|
||||
border-radius: 3px;
|
||||
padding: 3px 8px;
|
||||
width: 50px;
|
||||
border: 1px solid $black;
|
||||
font-weight: bold;
|
||||
&[type="submit"] {
|
||||
width: auto;
|
||||
background: $green;
|
||||
font-family: $helvetica-condensed;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h4{
|
||||
margin-top:0px;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class AsyncInfoController < ApplicationController
|
|||
username: @user.username,
|
||||
profile_image_90: ProfileImage.new(@user).get(90),
|
||||
followed_tag_names: @user.cached_followed_tag_names,
|
||||
followed_tags: @user.cached_followed_tags.to_json(only: %i[id name bg_color_hex text_color_hex]),
|
||||
followed_tags: @user.cached_followed_tags.to_json(only: %i[id name bg_color_hex text_color_hex], methods: [:points]),
|
||||
followed_user_ids: @user.cached_following_users_ids,
|
||||
followed_organization_ids: @user.cached_following_organizations_ids,
|
||||
reading_list_ids: ReadingList.new(@user).cached_ids_of_articles,
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ class DashboardsController < ApplicationController
|
|||
current_user
|
||||
end
|
||||
authorize (@user || User), :dashboard_show?
|
||||
if params[:which] == "following_users"
|
||||
if params[:which] == "following" || params[:which] == "following_users"
|
||||
@follows = @user.follows_by_type("User").
|
||||
order("created_at DESC").includes(:followable).limit(80)
|
||||
@followed_tags = @user.follows_by_type("ActsAsTaggableOn::Tag").
|
||||
order("points DESC").includes(:followable).limit(80)
|
||||
elsif params[:which] == "user_followers"
|
||||
@follows = Follow.where(followable_id: @user.id, followable_type: "User").
|
||||
includes(:follower).order("created_at DESC").limit(80)
|
||||
|
|
|
|||
|
|
@ -37,4 +37,18 @@ class FollowsController < ApplicationController
|
|||
current_user.touch
|
||||
render json: { outcome: @result }
|
||||
end
|
||||
|
||||
def update
|
||||
@follow = Follow.find(params[:id])
|
||||
authorize @follow
|
||||
if @follow.update(follow_params)
|
||||
redirect_to "/dashboard/following"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def follow_params
|
||||
params.require(:follow).permit(policy(Follow).permitted_attributes)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class StoriesController < ApplicationController
|
|||
def handle_base_index
|
||||
@home_page = true
|
||||
@page = (params[:page] || 1).to_i
|
||||
num_articles = 15
|
||||
num_articles = 25
|
||||
@stories = article_finder(num_articles)
|
||||
add_param_context(:page, :timeframe)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@ class UserDecorator < ApplicationDecorator
|
|||
delegate_all
|
||||
|
||||
def cached_followed_tags
|
||||
Rails.cache.fetch("user-#{id}-#{updated_at}/followed_tags", expires_in: 20.hours) do
|
||||
Tag.where(id: Follow.where(follower_id: id, followable_type: "ActsAsTaggableOn::Tag").pluck(:followable_id)).order("hotness_score DESC")
|
||||
Rails.cache.fetch("user-#{id}-#{updated_at}/followed_tags_11-30", expires_in: 20.hours) do
|
||||
follows_query = Follow.where(follower_id: id, followable_type: "ActsAsTaggableOn::Tag").pluck(:followable_id, :points)
|
||||
tags = Tag.where(id: follows_query.map { |f| f[0] }).order("hotness_score DESC")
|
||||
tags.each do |t|
|
||||
follow_query_item = follows_query.detect{|f| f[0] == t.id}
|
||||
t.points = follow_query_item[1]
|
||||
end
|
||||
tags
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
class Tag < ActsAsTaggableOn::Tag
|
||||
|
||||
attr_accessor :points
|
||||
|
||||
include AlgoliaSearch
|
||||
acts_as_followable
|
||||
resourcify
|
||||
|
|
|
|||
|
|
@ -2,4 +2,18 @@ class FollowPolicy < ApplicationPolicy
|
|||
def create?
|
||||
!user_is_banned?
|
||||
end
|
||||
|
||||
def update?
|
||||
user_is_follower?
|
||||
end
|
||||
|
||||
def permitted_attributes
|
||||
%i[points]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_is_follower?
|
||||
record.follower_id == user.id && record.follower_type == "User"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
<span>FOLLOWERS</span>
|
||||
<span>(<%= @user.followers_count %>)</span>
|
||||
</a>
|
||||
<a class="action <%= 'active' if params[:which] == "following_users" %>" href="/dashboard/following_users">
|
||||
<a class="action <%= 'active' if params[:which].to_s.include?("following") %>" href="/dashboard/following">
|
||||
<span>FOLLOWING</span>
|
||||
<span>(<%= @user.following_users_count %>)</span>
|
||||
<span>(<%= @user.following_users_count + @user.following_tags_count %>)</span>
|
||||
</a>
|
||||
</div>
|
||||
<% if @user.org_admin && @user.organization && (params[:which].blank? || params[:which] == "organization") %>
|
||||
|
|
@ -32,7 +32,31 @@
|
|||
<%= render "dashboard_article", article: article, org_admin: true %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% elsif params[:which] == "user_followers" || params[:which] == "following_users" || params[:which] == "organization_user_followers" %>
|
||||
<% elsif params[:which] == "user_followers" || params[:which] == "following_users" || params[:which] == "following" || params[:which] == "organization_user_followers" %>
|
||||
<% if @followed_tags %>
|
||||
<h2>Followed tags (<%= @user.following_tags_count %>)</h2>
|
||||
<p><em>Adjust <strong>Follow Weight</strong> to make a tag show up less or more in your feed (default 1.0)</em></p>
|
||||
<% @followed_tags.each do |follow| %>
|
||||
<% tag = follow.followable %>
|
||||
<% if tag %>
|
||||
<% color = HexComparer.new([tag.bg_color_hex || "#0000000",tag.text_color_hex || "#ffffff"]).brightness(0.8) %>
|
||||
<div class="single-article" style="border-color:<%= color %>;box-shadow: 3px 3px 0px <%= color %>">
|
||||
<h2>
|
||||
<a href="/t/<%= tag.name %>">
|
||||
<%= tag.name %>
|
||||
</a>
|
||||
<%= form_for(follow) do |f| %>
|
||||
<%= f.label(:points, "Follow Weight:") %>
|
||||
<%= f.text_field(:points) %>
|
||||
<%= f.submit "Submit" %>
|
||||
<% end %>
|
||||
</h2>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<h2>Followed users (<%= @user.following_users_count %>)</h2>
|
||||
<% end %>
|
||||
<% @follows.each do |follow| %>
|
||||
<% user = params[:which].include?("followers") ? follow.follower : follow.followable %>
|
||||
<% if user %>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Rails.application.routes.draw do
|
|||
get "/reports/:slug", to: "feedback_messages#show"
|
||||
resources :organizations, only: %i[update create]
|
||||
resources :followed_articles, only: [:index]
|
||||
resources :follows, only: %i[show create]
|
||||
resources :follows, only: %i[show create update]
|
||||
resources :giveaways, only: %i[create update]
|
||||
resources :image_uploads, only: [:create]
|
||||
resources :blocks
|
||||
|
|
@ -238,7 +238,7 @@ Rails.application.routes.draw do
|
|||
get "/dashboard" => "dashboards#show"
|
||||
get "/dashboard/:which" => "dashboards#show",
|
||||
constraints: {
|
||||
which: /organization|organization_user_followers|user_followers|following_users|reading/
|
||||
which: /organization|organization_user_followers|user_followers|following_users|following|reading/
|
||||
}
|
||||
get "/dashboard/:username" => "dashboards#show"
|
||||
|
||||
|
|
|
|||
5
db/migrate/20181129222416_add_points_to_follows.rb
Normal file
5
db/migrate/20181129222416_add_points_to_follows.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class AddPointsToFollows < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :follows, :points, :float, default: 1.0
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20181127173004) do
|
||||
ActiveRecord::Schema.define(version: 20181129222416) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
|
|
@ -323,6 +323,7 @@ ActiveRecord::Schema.define(version: 20181127173004) do
|
|||
t.string "followable_type", null: false
|
||||
t.integer "follower_id", null: false
|
||||
t.string "follower_type", null: false
|
||||
t.float "points", default: 1.0
|
||||
t.datetime "updated_at"
|
||||
t.index ["followable_id", "followable_type"], name: "fk_followables"
|
||||
t.index ["follower_id", "follower_type"], name: "fk_follows"
|
||||
|
|
@ -440,7 +441,7 @@ ActiveRecord::Schema.define(version: 20181127173004) do
|
|||
t.index ["chat_channel_id"], name: "index_messages_on_chat_channel_id"
|
||||
t.index ["user_id"], name: "index_messages_on_user_id"
|
||||
end
|
||||
|
||||
|
||||
create_table "notes", id: :serial, force: :cascade do |t|
|
||||
t.integer "author_id"
|
||||
t.text "content"
|
||||
|
|
|
|||
|
|
@ -351,6 +351,39 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#cached_followed_tags" do
|
||||
let(:tag1) { create(:tag) }
|
||||
let(:tag2) { create(:tag) }
|
||||
let(:tag3) { create(:tag) }
|
||||
let(:tag4) { create(:tag) }
|
||||
it "returns empty if no tags followed" do
|
||||
expect(user.decorate.cached_followed_tags.size).to eq(0)
|
||||
end
|
||||
|
||||
it "returns array of tags if user follows them" do
|
||||
user.follow(tag1)
|
||||
user.follow(tag2)
|
||||
user.follow(tag3)
|
||||
expect(user.decorate.cached_followed_tags.size).to eq(3)
|
||||
end
|
||||
|
||||
it "returns tag object with name" do
|
||||
user.follow(tag1)
|
||||
expect(user.decorate.cached_followed_tags.first.name).to eq(tag1.name)
|
||||
end
|
||||
|
||||
it "returns follow points for tag" do
|
||||
user.follow(tag1)
|
||||
expect(user.decorate.cached_followed_tags.first.points).to eq(1.0)
|
||||
end
|
||||
|
||||
it "returns adjusted points for tag" do
|
||||
user.follow(tag1)
|
||||
Follow.last.update(points: 0.1)
|
||||
expect(user.decorate.cached_followed_tags.first.points).to eq(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
it "inserts into mailchimp" do
|
||||
expect(user.subscribe_to_mailchimp_newsletter_without_delay).to eq true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -70,6 +70,14 @@ RSpec.describe "Dashboards", type: :request do
|
|||
get "/dashboard/following_users"
|
||||
expect(response.body).to include CGI.escapeHTML(second_user.name)
|
||||
end
|
||||
it "renders the current user's tag followings" do
|
||||
user.follow second_user
|
||||
tag = create(:tag)
|
||||
user.follow tag
|
||||
login_as user
|
||||
get "/dashboard/following"
|
||||
expect(response.body).to include CGI.escapeHTML(tag.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
28
spec/requests/follows_update_spec.rb
Normal file
28
spec/requests/follows_update_spec.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Following/Unfollowing", type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:user_2) { create(:user) }
|
||||
let(:tag) { create(:tag) }
|
||||
|
||||
before do
|
||||
login_as user
|
||||
end
|
||||
|
||||
describe "PUT follows/:id" do
|
||||
it "updates user to offer mentorship" do
|
||||
user.follow(tag)
|
||||
put "/follows/#{Follow.last.id}",
|
||||
params: { follow: { points: 3.0 } }
|
||||
expect(Follow.last.points).to eq(3.0)
|
||||
end
|
||||
|
||||
it "does not update if follow does not belong to user" do
|
||||
user_2.follow(tag)
|
||||
expect do
|
||||
put "/follows/#{Follow.last.id}",
|
||||
params: { follow: { points: 3.0 } }
|
||||
end.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue