Remove pro role + expose analytics to all users via dashboard (#13156)
* Remove pro role on user, expose pro dashboard to all users as analytics * Remove pro from Elasticsearch mappings * Update user role docs to use :trusted over :pro * Remove pro from Role model spec * Remove more references to pro, as noted by @rhymes
This commit is contained in:
parent
2534a8aa5f
commit
95055b2a89
35 changed files with 83 additions and 211 deletions
|
|
@ -21,11 +21,9 @@ function addRelevantButtonsToArticle(user) {
|
|||
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/manage" rel="nofollow">Manage</a>`,
|
||||
);
|
||||
}
|
||||
if (user.pro) {
|
||||
actions.push(
|
||||
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/stats" rel="nofollow">Stats</a>`,
|
||||
);
|
||||
}
|
||||
actions.push(
|
||||
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/stats" rel="nofollow">Stats</a>`,
|
||||
);
|
||||
document.getElementById('action-space').innerHTML = actions.join('');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.pro-container {
|
||||
.analytics-container {
|
||||
width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,13 +74,6 @@
|
|||
width: 1.5em;
|
||||
vertical-align: -0.22em;
|
||||
margin-right: 0.15em;
|
||||
|
||||
&.pro-checkmark {
|
||||
height: 0.5em;
|
||||
width: 0.5em;
|
||||
vertical-align: 0.08em;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
a {
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ module Admin
|
|||
def user_params
|
||||
allowed_params = %i[
|
||||
new_note note_for_current_role user_status
|
||||
pro merge_user_id add_credits remove_credits
|
||||
merge_user_id add_credits remove_credits
|
||||
add_org_credits remove_org_credits
|
||||
organization_id identity_id
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ module Api
|
|||
rescue_from UnauthorizedError, with: :error_unauthorized
|
||||
|
||||
before_action :authenticate_with_api_key_or_current_user!
|
||||
before_action :authorize_pro_user
|
||||
before_action :authorize_user_organization
|
||||
before_action :load_owner
|
||||
before_action :validate_date_params, only: [:historical]
|
||||
|
|
@ -46,10 +45,6 @@ module Api
|
|||
|
||||
private
|
||||
|
||||
def authorize_pro_user
|
||||
raise UnauthorizedError unless @user&.pro?
|
||||
end
|
||||
|
||||
def authorize_user_organization
|
||||
return unless analytics_params[:organization_id]
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ class ArticlesController < ApplicationController
|
|||
end
|
||||
|
||||
def stats
|
||||
authorize current_user, :pro_user?
|
||||
authorize @article
|
||||
@organization_id = @article.organization_id
|
||||
end
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ class AsyncInfoController < ApplicationController
|
|||
trusted: @user.trusted,
|
||||
moderator_for_tags: @user.moderator_for_tags,
|
||||
config_body_class: @user.config_body_class,
|
||||
pro: @user.pro?,
|
||||
feed_style: feed_style_preference,
|
||||
created_at: @user.created_at,
|
||||
admin: @user.any_admin?
|
||||
|
|
@ -83,7 +82,6 @@ class AsyncInfoController < ApplicationController
|
|||
#{current_user&.updated_at}__
|
||||
#{current_user&.reactions_count}__
|
||||
#{current_user&.articles_count}__
|
||||
#{current_user&.pro?}__
|
||||
#{current_user&.blocking_others_count}__"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
class DashboardsController < ApplicationController
|
||||
before_action :set_no_cache_header
|
||||
before_action :authenticate_user!
|
||||
before_action :fetch_and_authorize_user, except: :pro
|
||||
before_action :fetch_and_authorize_user, except: :analytics
|
||||
before_action :set_source, only: %i[subscriptions]
|
||||
before_action -> { limit_per_page(default: 80, max: 1000) }, except: %i[show pro]
|
||||
after_action :verify_authorized
|
||||
before_action -> { limit_per_page(default: 80, max: 1000) }, except: %i[show analytics]
|
||||
|
||||
def show
|
||||
@current_user_pro = current_user.pro?
|
||||
|
||||
target = @user
|
||||
not_authorized if params[:org_id] && !@user.org_admin?(params[:org_id] || @user.any_admin?)
|
||||
|
||||
|
|
@ -55,13 +52,10 @@ class DashboardsController < ApplicationController
|
|||
.includes(:follower).order(created_at: :desc).limit(@follows_limit)
|
||||
end
|
||||
|
||||
def pro
|
||||
def analytics
|
||||
@user_or_org = if params[:org_id]
|
||||
org = Organization.find_by(id: params[:org_id])
|
||||
authorize org, :pro_org_user?
|
||||
org
|
||||
Organization.find_by(id: params[:org_id])
|
||||
else
|
||||
authorize current_user, :pro_user?
|
||||
current_user
|
||||
end
|
||||
@organizations = current_user.member_organizations
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ describe('<ReadingList />', () => {
|
|||
user: {
|
||||
id: 318840,
|
||||
name: 'Bobby Tables',
|
||||
pro: null,
|
||||
profile_image_90: 'https://picsum.photos/90/90',
|
||||
username: 'bobbytables',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ module Constants
|
|||
"Suspend",
|
||||
"Regular Member",
|
||||
"Trusted",
|
||||
"Pro",
|
||||
].freeze
|
||||
|
||||
SPECIAL_ROLES = [
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ class Role < ApplicationRecord
|
|||
codeland_admin
|
||||
comment_banned
|
||||
podcast_admin
|
||||
pro
|
||||
restricted_liquid_tag
|
||||
single_resource_admin
|
||||
super_admin
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class User < ApplicationRecord
|
|||
\z
|
||||
}x.freeze
|
||||
|
||||
attr_accessor :scholar_email, :new_note, :note_for_current_role, :user_status, :pro, :merge_user_id,
|
||||
attr_accessor :scholar_email, :new_note, :note_for_current_role, :user_status, :merge_user_id,
|
||||
:add_credits, :remove_credits, :add_org_credits, :remove_org_credits, :ip_address,
|
||||
:current_password
|
||||
|
||||
|
|
@ -387,12 +387,6 @@ class User < ApplicationRecord
|
|||
has_role?(:tech_admin) || has_role?(:super_admin)
|
||||
end
|
||||
|
||||
def pro?
|
||||
Rails.cache.fetch("user-#{id}/has_pro_role", expires_in: 200.hours) do
|
||||
has_role?(:pro)
|
||||
end
|
||||
end
|
||||
|
||||
def vomitted_on?
|
||||
Reaction.exists?(reactable_id: id, reactable_type: "User", category: "vomit", status: "confirmed")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,8 +30,4 @@ class OrganizationPolicy < ApplicationPolicy
|
|||
def generate_new_secret?
|
||||
update?
|
||||
end
|
||||
|
||||
def pro_org_user?
|
||||
user.pro? && OrganizationMembership.exists?(user_id: user.id, organization_id: record.id)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -108,10 +108,6 @@ class UserPolicy < ApplicationPolicy
|
|||
current_user? || user_admin? || minimal_admin?
|
||||
end
|
||||
|
||||
def pro_user?
|
||||
current_user? && user.pro?
|
||||
end
|
||||
|
||||
def moderation_routes?
|
||||
(user.has_role?(:trusted) || minimal_admin?) && !user.banned
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
module Search
|
||||
class NestedUserSerializer < ApplicationSerializer
|
||||
attributes :id, :name, :pro, :profile_image_90, :username
|
||||
attributes :id, :name, :profile_image_90, :username
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ module DataSync
|
|||
SHARED_FIELDS = %i[
|
||||
username
|
||||
name
|
||||
pro
|
||||
profile_image_url
|
||||
].freeze
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ module Moderator
|
|||
|
||||
def remove_privileges
|
||||
@user.remove_role(:workshop_pass)
|
||||
@user.remove_role(:pro)
|
||||
remove_mod_roles
|
||||
remove_tag_moderator_role
|
||||
end
|
||||
|
|
@ -68,7 +67,6 @@ module Moderator
|
|||
regular_member
|
||||
when "Trusted"
|
||||
remove_negative_roles
|
||||
user.remove_role(:pro)
|
||||
TagModerators::AddTrustedRole.call(user)
|
||||
when "Admin"
|
||||
check_super_admin
|
||||
|
|
@ -90,10 +88,6 @@ module Moderator
|
|||
check_super_admin
|
||||
remove_negative_roles
|
||||
user.add_role(:single_resource_admin, role.split("Resource Admin: ").last.safe_constantize)
|
||||
when "Pro"
|
||||
remove_negative_roles
|
||||
TagModerators::AddTrustedRole.call(user)
|
||||
user.add_role(:pro)
|
||||
end
|
||||
create_note(role, note)
|
||||
end
|
||||
|
|
@ -110,7 +104,6 @@ module Moderator
|
|||
|
||||
def regular_member
|
||||
remove_negative_roles
|
||||
user.remove_role(:pro)
|
||||
remove_mod_roles
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<% title "Stats for Your Article" %>
|
||||
|
||||
<div class="dashboard-container pro-container" id="user-dashboard">
|
||||
<div class="dashboard-container analytics-container" id="user-dashboard">
|
||||
<a
|
||||
href="<%= @article.current_state_path %>"
|
||||
class="rounded-btn rounded-btn--transparent"
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
</a>
|
||||
|
||||
<section class="header-card card">
|
||||
<h1 class="pro-header">Stats for "<%= @article.title %>"</h1>
|
||||
<h1 class="analytics-header">Stats for "<%= @article.title %>"</h1>
|
||||
</section>
|
||||
|
||||
<%= render "shared/stats" %>
|
||||
|
|
|
|||
|
|
@ -39,15 +39,13 @@
|
|||
<%= inline_svg_tag("external-link.svg", aria: true, class: "crayons-icon", title: "Moderation") %>
|
||||
</a>
|
||||
|
||||
<% if @current_user_pro %>
|
||||
<a class="crayons-link crayons-link--block" href="<%= dashboard_pro_path %>">
|
||||
Pro Analytics
|
||||
</a>
|
||||
<a class="crayons-link crayons-link--block" href="<%= dashboard_analytics_path %>">
|
||||
Analytics
|
||||
</a>
|
||||
|
||||
<% if @organizations && (params[:which].blank? || params[:which] == "organization") %>
|
||||
<% @organizations.each do |org| %>
|
||||
<a class="crayons-link crayons-link--block" href="<%= dashboard_pro_org_path(org.id) %>">Pro Analytics for <%= org.name %></a>
|
||||
<% end %>
|
||||
<% if @organizations && (params[:which].blank? || params[:which] == "organization") %>
|
||||
<% @organizations.each do |org| %>
|
||||
<a class="crayons-link crayons-link--block" href="<%= dashboard_analytics_org_path(org.id) %>">Analytics for <%= org.name %></a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,13 +9,11 @@
|
|||
|
||||
<option value="/listings/dashboard">Listings</option>
|
||||
|
||||
<% if @current_user_pro %>
|
||||
<option value="<%= dashboard_pro_path %>">Pro Analytics</option>
|
||||
<option value="<%= dashboard_analytics_path %>">Analytics</option>
|
||||
|
||||
<% if @organizations && (params[:which].blank? || params[:which] == "organization") %>
|
||||
<% @organizations.each do |org| %>
|
||||
<option value="<%= dashboard_pro_org_path(org.id) %>">Pro Analytics for <%= org.name %></option>
|
||||
<% end %>
|
||||
<% if @organizations && (params[:which].blank? || params[:which] == "organization") %>
|
||||
<% @organizations.each do |org| %>
|
||||
<option value="<%= dashboard_analytics_org_path(org.id) %>">Analytics for <%= org.name %></option>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
|
|
|||
|
|
@ -64,9 +64,8 @@
|
|||
<% elsif @user == article.user %>
|
||||
<a href="<%= article.path %>/delete_confirm" data-no-instant class="crayons-btn crayons-btn--danger">Delete</a>
|
||||
<% end %>
|
||||
<% if @current_user_pro %>
|
||||
<a href="<%= article.path %>/stats" data-no-instant class="crayons-btn">Stats</a>
|
||||
<% end %>
|
||||
|
||||
<a href="<%= article.path %>/stats" data-no-instant class="crayons-btn">Stats</a>
|
||||
|
||||
<% if article.published %>
|
||||
<span id="pageviews-<%= article.id %>" class="crayons-btn dashboard-pageviews-indicator" data-analytics-pageviews data-article-id="<%= article.id %>">
|
||||
|
|
|
|||
|
|
@ -100,9 +100,7 @@
|
|||
<% if article.user_subscriptions_count > 0 %>
|
||||
<a href="<%= dashboard_subscriptions_path(source_type: "Article", source_id: article.id) %>" class="crayons-link crayons-link--block w-100"><%= "Subscriptions (#{article.user_subscriptions_count})" %></a>
|
||||
<% end %>
|
||||
<% if @current_user_pro %>
|
||||
<a href="<%= article.path %>/stats" class="crayons-link crayons-link--block w-100">Stats</a>
|
||||
<% end %>
|
||||
<a href="<%= article.path %>/stats" class="crayons-link crayons-link--block w-100">Stats</a>
|
||||
<%= form_for(article, method: :patch, remote: true, authenticity_token: true, html: { "data-type": "json", class: "js-archive-toggle" }) do |f| %>
|
||||
<%= f.hidden_field :archived, value: !article.archived, id: "article_archived_#{article.id}" %>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,25 @@
|
|||
<% title "Pro Analytics" %>
|
||||
<% title "Analytics" %>
|
||||
|
||||
<div class="dashboard-container pro-container crayons-layout" id="user-dashboard">
|
||||
<div class="dashboard-container analytics-container crayons-layout" id="user-dashboard">
|
||||
<a href="/dashboard" class="rounded-btn rounded-btn--transparent">👈 Back to Main Dashboard</a>
|
||||
|
||||
<a class="rounded-btn <%= "active" unless params[:org_id] %>" href="/dashboard/pro">
|
||||
Your Pro Dashboard
|
||||
<a class="rounded-btn <%= "active" unless params[:org_id] %>" href="<%= dashboard_analytics_path %>">
|
||||
Your Dashboard
|
||||
</a>
|
||||
|
||||
<% @organizations.each do |org| %>
|
||||
<a
|
||||
class="rounded-btn organization <%= "active" if params[:org_id].to_i == org.id %>"
|
||||
href="/dashboard/pro/org/<%= org.id %>"
|
||||
href="<%= dashboard_analytics_org_path(org.id) %>"
|
||||
href="<%= dashboard_analytics_path %>"
|
||||
data-organization-id="<%= org.id %>">
|
||||
<%= org.name %> Pro Dashboard
|
||||
<%= org.name %> Analytics Dashboard
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<section class="header-card card">
|
||||
<h1 class="pro-header">Pro Dashboard for <%= @user_or_org.name %></h1>
|
||||
<p>Welcome to the Pro Dashboard, the home of in-depth user metrics so that authors can make data-driven decisions about the <%= SiteConfig.community_member_label %> ecosystem.</p>
|
||||
<h1 class="analytics-header">Analytics Dashboard for <%= @user_or_org.name %></h1>
|
||||
<p>Welcome to the Analytics Dashboard, the home of in-depth user metrics so that authors can make data-driven decisions about the <%= SiteConfig.community_member_label %> ecosystem.</p>
|
||||
<p>This dashboard highlights deep insights especially relevant to <%= SiteConfig.community_member_label %> relations, authors, and serious bloggers.</p>
|
||||
</section>
|
||||
|
||||
|
|
@ -170,9 +170,6 @@
|
|||
},
|
||||
"profile_image_90": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"pro": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -78,9 +78,6 @@
|
|||
},
|
||||
"profile_image_90": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"pro": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,8 +557,8 @@ Rails.application.routes.draw do
|
|||
get "/settings/:tab/:id", to: "users#edit", constraints: { tab: /response-templates/ }
|
||||
get "/signout_confirm", to: "users#signout_confirm"
|
||||
get "/dashboard", to: "dashboards#show"
|
||||
get "/dashboard/pro", to: "dashboards#pro"
|
||||
get "dashboard/pro/org/:org_id", to: "dashboards#pro", as: :dashboard_pro_org
|
||||
get "/dashboard/analytics", to: "dashboards#analytics"
|
||||
get "dashboard/analytics/org/:org_id", to: "dashboards#analytics", as: :dashboard_analytics_org
|
||||
get "dashboard/following", to: "dashboards#following_tags"
|
||||
get "dashboard/following_tags", to: "dashboards#following_tags"
|
||||
get "dashboard/following_users", to: "dashboards#following_users"
|
||||
|
|
|
|||
|
|
@ -33,21 +33,21 @@ at the console.
|
|||
rails console
|
||||
```
|
||||
|
||||
- after verifying the user `test_user_name` is missing the `pro` role we proceed
|
||||
to add it and then verify the role has been added:
|
||||
- after verifying the user `test_user_name` is missing the `trusted` role we
|
||||
proceed to add it and then verify the role has been added:
|
||||
|
||||
```ruby
|
||||
> user = User.find_by(username: "test_user_name")
|
||||
> user.has_role? :pro
|
||||
> user.has_role? :trusted
|
||||
=> false
|
||||
|
||||
> user.add_role(:pro)
|
||||
> user.add_role(:trusted)
|
||||
=> #<Role:
|
||||
...
|
||||
name: "pro"
|
||||
name: "trusted"
|
||||
.. >
|
||||
|
||||
> user.has_role? :pro
|
||||
> user.has_role? :trusted
|
||||
=> true
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -99,10 +99,6 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :pro do
|
||||
after(:build) { |user| user.add_role(:pro) }
|
||||
end
|
||||
|
||||
trait :org_member do
|
||||
after(:create) do |user|
|
||||
org = create(:organization)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ RSpec.describe Role, type: :model do
|
|||
describe "::ROLES" do
|
||||
it "contains the correct values" do
|
||||
expected_roles = %w[
|
||||
admin banned chatroom_beta_tester codeland_admin comment_banned podcast_admin pro restricted_liquid_tag
|
||||
admin banned chatroom_beta_tester codeland_admin comment_banned podcast_admin restricted_liquid_tag
|
||||
single_resource_admin super_admin tag_moderator mod_relations_admin support_admin tech_admin trusted
|
||||
warned workshop_pass
|
||||
]
|
||||
|
|
|
|||
|
|
@ -759,17 +759,6 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#pro?" do
|
||||
it "returns false if the user is not a pro" do
|
||||
expect(user.pro?).to be(false)
|
||||
end
|
||||
|
||||
it "returns true if the user has the pro role" do
|
||||
user.add_role(:pro)
|
||||
expect(user.pro?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#enough_credits?" do
|
||||
it "returns false if the user has less unspent credits than neeed" do
|
||||
expect(user.enough_credits?(1)).to be(false)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.describe "Api::V0::Analytics", type: :request do
|
|||
include_examples "GET /api/analytics/:endpoint authorization examples", "historical", "&start=2019-03-29"
|
||||
|
||||
context "when the start parameter is not included" do
|
||||
before { get "/api/analytics/historical", headers: { "api-key" => pro_api_token.secret } }
|
||||
before { get "/api/analytics/historical", headers: { "api-key" => api_token.secret } }
|
||||
|
||||
it "fails with an unprocessable entity HTTP error" do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
|
|
@ -22,7 +22,7 @@ RSpec.describe "Api::V0::Analytics", type: :request do
|
|||
end
|
||||
|
||||
context "when the start parameter has the incorrect format" do
|
||||
before { get "/api/analytics/historical?start=2019/2/2", headers: { "api-key" => pro_api_token.secret } }
|
||||
before { get "/api/analytics/historical?start=2019/2/2", headers: { "api-key" => api_token.secret } }
|
||||
|
||||
it "fails with an unprocessable entity HTTP error" do
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
|
|
|
|||
|
|
@ -301,13 +301,7 @@ RSpec.describe "Articles", type: :request do
|
|||
expect { get "#{article.path}/stats" }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
it "returns unauthorized if the user is not pro" do
|
||||
article = create(:article, user: user)
|
||||
expect { get "#{article.path}/stats" }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
|
||||
it "works successfully" do
|
||||
user.add_role(:pro)
|
||||
article = create(:article, user: user)
|
||||
get "#{article.path}/stats"
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ RSpec.describe "Dashboards", type: :request do
|
|||
let(:user) { create(:user) }
|
||||
let(:second_user) { create(:user) }
|
||||
let(:super_admin) { create(:user, :super_admin) }
|
||||
let(:pro_user) { create(:user, :pro) }
|
||||
let(:article) { create(:article, user: user) }
|
||||
let(:unpublished_article) { create(:article, user: user, published: false) }
|
||||
let(:organization) { create(:organization) }
|
||||
|
|
@ -28,9 +27,12 @@ RSpec.describe "Dashboards", type: :request do
|
|||
expect(response.body).to include(CGI.escapeHTML(article.title))
|
||||
end
|
||||
|
||||
it 'does not show "STATS" for articles' do
|
||||
it 'shows "STATS" for articles' do
|
||||
article = create(:article, user: user)
|
||||
|
||||
get "/dashboard"
|
||||
expect(response.body).not_to include("Stats")
|
||||
expect(response.body).to include("Stats")
|
||||
expect(response.body).to include("#{article.path}/stats")
|
||||
end
|
||||
|
||||
it "renders the delete button for drafts" do
|
||||
|
|
@ -66,18 +68,18 @@ RSpec.describe "Dashboards", type: :request do
|
|||
expect(response.body).not_to include "pagination"
|
||||
end
|
||||
|
||||
it "does not render a link to pro analytics" do
|
||||
it "renders a link to analytics dashboard" do
|
||||
get dashboard_path
|
||||
|
||||
expect(response.body).not_to include("Pro Analytics")
|
||||
expect(response.body).to include("Analytics")
|
||||
end
|
||||
|
||||
it "does not render a link to pro analytics for the org" do
|
||||
it "renders a link to analytics for the org" do
|
||||
create(:organization_membership, type_of_user: :admin, organization: organization, user: user)
|
||||
|
||||
get dashboard_path
|
||||
|
||||
expect(response.body).not_to include("Pro Analytics for #{organization.name}")
|
||||
expect(response.body).to include("Analytics for #{organization.name}")
|
||||
end
|
||||
|
||||
it "does not render a link to upload a video when enable_video_upload is false" do
|
||||
|
|
@ -105,32 +107,6 @@ RSpec.describe "Dashboards", type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context "when logged in as a pro user" do
|
||||
it 'shows "STATS" for articles' do
|
||||
article = create(:article, user: pro_user)
|
||||
sign_in pro_user
|
||||
get "/dashboard"
|
||||
expect(response.body).to include("Stats")
|
||||
expect(response.body).to include("#{article.path}/stats")
|
||||
end
|
||||
|
||||
it "renders a link to pro analytics" do
|
||||
sign_in pro_user
|
||||
get dashboard_path
|
||||
|
||||
expect(response.body).to include("Pro Analytics")
|
||||
end
|
||||
|
||||
it "renders a link to pro analytics for the org" do
|
||||
create(:organization_membership, type_of_user: :admin, organization: organization, user: pro_user)
|
||||
|
||||
sign_in pro_user
|
||||
get dashboard_path
|
||||
|
||||
expect(response.body).to include("Pro Analytics for #{CGI.escapeHTML(organization.name)}")
|
||||
end
|
||||
end
|
||||
|
||||
context "when logged in as a non recent user with enable_video_upload set to true on the Forem" do
|
||||
it "renders a link to upload a video" do
|
||||
Timecop.freeze(Time.current) do
|
||||
|
|
@ -278,49 +254,41 @@ RSpec.describe "Dashboards", type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
describe "GET /dashboard/pro" do
|
||||
describe "GET /dashboard/analytics" do
|
||||
context "when not logged in" do
|
||||
it "raises unauthorized" do
|
||||
get "/dashboard/pro"
|
||||
get "/dashboard/analytics"
|
||||
expect(response).to redirect_to("/enter")
|
||||
end
|
||||
end
|
||||
|
||||
context "when user does not have permission" do
|
||||
it "raises unauthorized" do
|
||||
sign_in user
|
||||
expect { get "/dashboard/pro" }.to raise_error(Pundit::NotAuthorizedError)
|
||||
end
|
||||
end
|
||||
|
||||
context "when user has pro permission" do
|
||||
context "when user is signed in" do
|
||||
it "shows page properly" do
|
||||
user.add_role(:pro)
|
||||
sign_in user
|
||||
get "/dashboard/pro"
|
||||
expect(response.body).to include("pro")
|
||||
get "/dashboard/analytics"
|
||||
expect(response.body).to include("Analytics")
|
||||
end
|
||||
end
|
||||
|
||||
context "when user has pro permission and is an org admin" do
|
||||
context "when user is an org admin" do
|
||||
it "shows page properly" do
|
||||
org = create :organization
|
||||
create(:organization_membership, user: user, organization: org, type_of_user: "admin")
|
||||
user.add_role(:pro)
|
||||
|
||||
sign_in user
|
||||
get "/dashboard/pro/org/#{org.id}"
|
||||
expect(response.body).to include("pro")
|
||||
get "/dashboard/analytics/org/#{org.id}"
|
||||
expect(response.body).to include("Analytics")
|
||||
end
|
||||
end
|
||||
|
||||
context "when user has pro permission and is an org member" do
|
||||
context "when user has is an org member" do
|
||||
it "shows page properly" do
|
||||
org = create :organization
|
||||
create(:organization_membership, user: user, organization: org)
|
||||
user.add_role(:pro)
|
||||
|
||||
sign_in user
|
||||
get "/dashboard/pro/org/#{org.id}"
|
||||
expect(response.body).to include("pro")
|
||||
get "/dashboard/analytics/org/#{org.id}"
|
||||
expect(response.body).to include("Analytics")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |endpoint, params|
|
||||
let(:user) { create(:user) }
|
||||
let(:api_token) { create(:api_secret, user: user) }
|
||||
let(:pro_user) { create(:user, :pro) }
|
||||
let(:pro_api_token) { create(:api_secret, user: pro_user) }
|
||||
let(:pro_org_member) { create(:user, :pro, :org_member) }
|
||||
let(:org_member_token) { create(:api_secret, user: pro_org_member) }
|
||||
let(:org) { pro_org_member.organizations.first }
|
||||
let(:org_member) { create(:user, :org_member) }
|
||||
let(:org_member_token) { create(:api_secret, user: org_member) }
|
||||
let(:org) { org_member.organizations.first }
|
||||
let(:article) { create(:article, user: user) }
|
||||
let(:pro_user_article) { create(:article, user: pro_user) }
|
||||
let(:pro_org_article) { create(:article, user: pro_user, organization: org) }
|
||||
let(:user_article) { create(:article, user: user) }
|
||||
let(:org_article) { create(:article, user: user, organization: org) }
|
||||
|
||||
context "when an invalid token is given" do
|
||||
before { get "/api/analytics/#{endpoint}?#{params}", headers: { "api-key" => "abadskajdlsak" } }
|
||||
|
|
@ -22,21 +20,9 @@ RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |
|
|||
end
|
||||
end
|
||||
|
||||
context "when a valid token is given but the user is not a pro" do
|
||||
context "when a valid token is given" do
|
||||
before { get "/api/analytics/#{endpoint}?#{params}", headers: { "api-key" => api_token.secret } }
|
||||
|
||||
it "renders an error message: 'unauthorized' in JSON" do
|
||||
expect(response.parsed_body).to include("error" => "unauthorized")
|
||||
end
|
||||
|
||||
it "has a status 401" do
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context "when a valid token is given and the user is a pro" do
|
||||
before { get "/api/analytics/#{endpoint}?#{params}", headers: { "api-key" => pro_api_token.secret } }
|
||||
|
||||
it "renders JSON as the content type" do
|
||||
expect(response.media_type).to eq "application/json"
|
||||
end
|
||||
|
|
@ -44,7 +30,7 @@ RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |
|
|||
|
||||
context "when attempting to view organization analytics without belonging to the organization" do
|
||||
before do
|
||||
headers = { "api-key" => pro_api_token.secret }
|
||||
headers = { "api-key" => api_token.secret }
|
||||
get "/api/analytics/#{endpoint}?organization_id=#{org.id}#{params}", headers: headers
|
||||
end
|
||||
|
||||
|
|
@ -59,7 +45,7 @@ RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |
|
|||
|
||||
context "when attempting to view organization analytics and being a member of the organization" do
|
||||
before do
|
||||
path = "/api/analytics/#{endpoint}?organization_id=#{pro_org_member.organization_ids.first}#{params}"
|
||||
path = "/api/analytics/#{endpoint}?organization_id=#{org_member.organization_ids.first}#{params}"
|
||||
get path, headers: { "api-key" => org_member_token.secret }
|
||||
end
|
||||
|
||||
|
|
@ -86,7 +72,7 @@ RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |
|
|||
|
||||
context "when viewing as current user" do
|
||||
it "responds with status 200 OK" do
|
||||
sign_in pro_user
|
||||
sign_in user
|
||||
get "/api/analytics/#{endpoint}?#{params}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
|
|
@ -94,18 +80,18 @@ RSpec.shared_examples "GET /api/analytics/:endpoint authorization examples" do |
|
|||
|
||||
context "when viewing your own single article's analytics" do
|
||||
it "responds with status 200 OK" do
|
||||
sign_in pro_user
|
||||
get "/api/analytics/#{endpoint}?article_id=#{pro_user_article.id}#{params}"
|
||||
sign_in user
|
||||
get "/api/analytics/#{endpoint}?article_id=#{user_article.id}#{params}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
end
|
||||
|
||||
context "when viewing your own organizaiton's single article's analytics" do
|
||||
it "responds with status 200 OK" do
|
||||
org_param = "&organization_id=#{pro_org_article.organization.id}"
|
||||
org_param = "&organization_id=#{org_article.organization.id}"
|
||||
|
||||
sign_in pro_org_member
|
||||
get "/api/analytics/#{endpoint}?article_id=#{pro_org_article.id}#{params}#{org_param}"
|
||||
sign_in org_member
|
||||
get "/api/analytics/#{endpoint}?article_id=#{org_article.id}#{params}#{org_param}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ RSpec.describe "Viewing an article stats", type: :system, js: true do
|
|||
let(:user) { create(:user) }
|
||||
let(:article) { create(:article, user: user) }
|
||||
|
||||
it "shows stats for pro users by clicking on the stats button" do
|
||||
it "shows stats for a user by clicking on the stats button" do
|
||||
path = "/#{user.username}/#{article.slug}/stats"
|
||||
allow(user).to receive(:pro?).and_return(true)
|
||||
sign_in user
|
||||
visit path
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue