Rubocop: fix additional violations in todo file (#9218)

This commit is contained in:
rhymes 2020-07-09 16:25:44 +02:00 committed by GitHub
parent f37ffc0be9
commit ffc96db209
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1585 additions and 1526 deletions

View file

@ -319,6 +319,12 @@ Style/IfUnlessModifier:
# StyleGuide: '#single-line-blocks'
# Enabled: false
Style/ClassAndModuleChildren:
Description: 'Checks style of children classes and modules.'
StyleGuide: '#namespace-definition'
Enabled: true
SafeAutoCorrect: true
# Style/OptionHash:
# Description: "Don't use option hashes when you can use keyword arguments."
# Enabled: false

View file

@ -37,38 +37,10 @@ Performance/OpenStruct:
- 'spec/models/github_repo_spec.rb'
- 'spec/requests/github_repos_spec.rb'
# Offense count: 4
# Configuration parameters: Max.
RSpec/ExampleLength:
Exclude:
- 'spec/initializers/rack/attack_spec.rb'
- 'spec/liquid_tags/user_subscription_tag_spec.rb'
- 'spec/models/comment_spec.rb'
- 'spec/requests/display_ad_events_spec.rb'
# Offense count: 930
RSpec/MultipleExpectations:
Max: 12
# Offense count: 1
RSpec/SubjectStub:
Exclude:
- 'spec/models/article_spec.rb'
# Offense count: 1
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
Exclude:
- 'app/models/role.rb'
# Offense count: 3
# Configuration parameters: Include.
# Include: app/helpers/**/*.rb
Rails/HelperInstanceVariable:
Exclude:
- 'app/helpers/application_helper.rb'
# Offense count: 16
Rails/OutputSafety:
Exclude:
@ -87,13 +59,6 @@ Rails/UniqueValidationWithoutIndex:
Exclude:
- 'app/models/article.rb'
# Offense count: 38
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Enabled: false
# Offense count: 3
# Configuration parameters: Methods.
# Methods: {"reduce"=>["acc", "elem"]}, {"inject"=>["acc", "elem"]}

View file

@ -1,74 +1,78 @@
class Api::V0::ApiController < ApplicationController
protect_from_forgery with: :exception, prepend: true
module Api
module V0
class ApiController < ApplicationController
protect_from_forgery with: :exception, prepend: true
include ValidRequest
include ValidRequest
respond_to :json
respond_to :json
rescue_from ActionController::ParameterMissing do |exc|
error_unprocessable_entity(exc.message)
end
rescue_from ActionController::ParameterMissing do |exc|
error_unprocessable_entity(exc.message)
end
rescue_from ActiveRecord::RecordInvalid do |exc|
error_unprocessable_entity(exc.message)
end
rescue_from ActiveRecord::RecordInvalid do |exc|
error_unprocessable_entity(exc.message)
end
rescue_from ActiveRecord::RecordNotFound, with: :error_not_found
rescue_from ActiveRecord::RecordNotFound, with: :error_not_found
rescue_from Pundit::NotAuthorizedError, with: :error_unauthorized
rescue_from Pundit::NotAuthorizedError, with: :error_unauthorized
protected
protected
def error_unprocessable_entity(message)
render json: { error: message, status: 422 }, status: :unprocessable_entity
end
def error_unprocessable_entity(message)
render json: { error: message, status: 422 }, status: :unprocessable_entity
end
def error_unauthorized
render json: { error: "unauthorized", status: 401 }, status: :unauthorized
end
def error_unauthorized
render json: { error: "unauthorized", status: 401 }, status: :unauthorized
end
def error_not_found
render json: { error: "not found", status: 404 }, status: :not_found
end
def error_not_found
render json: { error: "not found", status: 404 }, status: :not_found
end
def authenticate!
if doorkeeper_token
@user = User.find(doorkeeper_token.resource_owner_id)
return error_unauthorized unless @user
elsif request.headers["api-key"]
@user = authenticate_with_api_key
return error_unauthorized unless @user
elsif current_user
@user = current_user
else
error_unauthorized
def authenticate!
if doorkeeper_token
@user = User.find(doorkeeper_token.resource_owner_id)
return error_unauthorized unless @user
elsif request.headers["api-key"]
@user = authenticate_with_api_key
return error_unauthorized unless @user
elsif current_user
@user = current_user
else
error_unauthorized
end
end
# Checks if the user is authenticated, sets @user to nil otherwise
def authenticate_with_api_key_or_current_user
@user = authenticate_with_api_key || current_user
end
# Checks if the user is authenticated, if so sets the variable @user
# Returns HTTP 401 Unauthorized otherwise
def authenticate_with_api_key_or_current_user!
@user = authenticate_with_api_key || current_user
error_unauthorized unless @user
end
private
def authenticate_with_api_key
api_key = request.headers["api-key"]
return unless api_key
api_secret = ApiSecret.includes(:user).find_by(secret: api_key)
return unless api_secret
# guard against timing attacks
# see <https://www.slideshare.net/NickMalcolm/timing-attacks-and-ruby-on-rails>
secure_secret = ActiveSupport::SecurityUtils.secure_compare(api_secret.secret, api_key)
return api_secret.user if secure_secret
end
end
end
# Checks if the user is authenticated, sets @user to nil otherwise
def authenticate_with_api_key_or_current_user
@user = authenticate_with_api_key || current_user
end
# Checks if the user is authenticated, if so sets the variable @user
# Returns HTTP 401 Unauthorized otherwise
def authenticate_with_api_key_or_current_user!
@user = authenticate_with_api_key || current_user
error_unauthorized unless @user
end
private
def authenticate_with_api_key
api_key = request.headers["api-key"]
return unless api_key
api_secret = ApiSecret.includes(:user).find_by(secret: api_key)
return unless api_secret
# guard against timing attacks
# see <https://www.slideshare.net/NickMalcolm/timing-attacks-and-ruby-on-rails>
secure_secret = ActiveSupport::SecurityUtils.secure_compare(api_secret.secret, api_key)
return api_secret.user if secure_secret
end
end

View file

@ -1,36 +1,38 @@
class IncomingWebhooks::MailchimpUnsubscribesController < ApplicationController
skip_before_action :verify_authenticity_token
module IncomingWebhooks
class MailchimpUnsubscribesController < ApplicationController
skip_before_action :verify_authenticity_token
class InvalidListID < StandardError; end
class InvalidListID < StandardError; end
LIST_MAPPINGS = {
mailchimp_newsletter_id: :email_newsletter,
mailchimp_sustaining_members_id: :email_membership_newsletter,
mailchimp_tag_moderators_id: :email_tag_mod_newsletter,
mailchimp_community_moderators_id: :email_community_mod_newsletter
}.freeze
LIST_MAPPINGS = {
mailchimp_newsletter_id: :email_newsletter,
mailchimp_sustaining_members_id: :email_membership_newsletter,
mailchimp_tag_moderators_id: :email_tag_mod_newsletter,
mailchimp_community_moderators_id: :email_community_mod_newsletter
}.freeze
def index
head :ok
end
def index
head :ok
end
def create
not_authorized unless valid_secret?
user = User.find_by!(email: params.dig(:data, :email))
user.update(email_type => false)
end
def create
not_authorized unless valid_secret?
user = User.find_by!(email: params.dig(:data, :email))
user.update(email_type => false)
end
private
private
def valid_secret?
params[:secret] == SiteConfig.mailchimp_incoming_webhook_secret
end
def valid_secret?
params[:secret] == SiteConfig.mailchimp_incoming_webhook_secret
end
def email_type
list_id = params.dig(:data, :list_id)
key = LIST_MAPPINGS.keys.detect { |k| SiteConfig.public_send(k) == list_id }
raise InvalidListID unless key
def email_type
list_id = params.dig(:data, :list_id)
key = LIST_MAPPINGS.keys.detect { |k| SiteConfig.public_send(k) == list_id }
raise InvalidListID unless key
LIST_MAPPINGS[key]
LIST_MAPPINGS[key]
end
end
end

View file

@ -1,45 +1,47 @@
class Internal::ApplicationController < ApplicationController
before_action :authorize_admin
after_action :verify_authorized
module Internal
class ApplicationController < ApplicationController
before_action :authorize_admin
after_action :verify_authorized
# This is used in app/views/internal/shared/_navbar.html.erb to build the
# side navbar in alphabetical order.
MENU_ITEMS = [
{ name: "articles", controller: "articles" },
{ name: "broadcasts", controller: "broadcasts" },
{ name: "badges", controller: "badges" },
{ name: "chat_channels", controller: "chat_channels" },
{ name: "comments", controller: "comments" },
{ name: "config", controller: "config" },
{ name: "events", controller: "events" },
{ name: "growth", controller: "growth" },
{ name: "listings", controller: "listings" },
{ name: "moderator_actions", controller: "moderator_actions" },
{ name: "mods", controller: "mods" },
{ name: "privileged_reactions", controller: "privileged_reactions" },
{ name: "organizations", controller: "organizations" },
{ name: "path_redirects", controller: "path_redirects" },
{ name: "pages", controller: "pages" },
{ name: "permissions", controller: "permissions" },
{ name: "podcasts", controller: "podcasts" },
{ name: "reports", controller: "reports" },
{ name: "response_templates", controller: "response_templates" },
{ name: "sponsorships", controller: "sponsorships" },
{ name: "tags", controller: "tags" },
{ name: "tools", controller: "tools" },
{ name: "users", controller: "users" },
{ name: "vault secrets", controller: "secrets" },
{ name: "webhooks", controller: "webhook_endpoints" },
{ name: "welcome", controller: "welcome" },
].sort_by { |menu_item| menu_item[:name] }.freeze
# This is used in app/views/internal/shared/_navbar.html.erb to build the
# side navbar in alphabetical order.
MENU_ITEMS = [
{ name: "articles", controller: "articles" },
{ name: "broadcasts", controller: "broadcasts" },
{ name: "badges", controller: "badges" },
{ name: "chat_channels", controller: "chat_channels" },
{ name: "comments", controller: "comments" },
{ name: "config", controller: "config" },
{ name: "events", controller: "events" },
{ name: "growth", controller: "growth" },
{ name: "listings", controller: "listings" },
{ name: "moderator_actions", controller: "moderator_actions" },
{ name: "mods", controller: "mods" },
{ name: "privileged_reactions", controller: "privileged_reactions" },
{ name: "organizations", controller: "organizations" },
{ name: "path_redirects", controller: "path_redirects" },
{ name: "pages", controller: "pages" },
{ name: "permissions", controller: "permissions" },
{ name: "podcasts", controller: "podcasts" },
{ name: "reports", controller: "reports" },
{ name: "response_templates", controller: "response_templates" },
{ name: "sponsorships", controller: "sponsorships" },
{ name: "tags", controller: "tags" },
{ name: "tools", controller: "tools" },
{ name: "users", controller: "users" },
{ name: "vault secrets", controller: "secrets" },
{ name: "webhooks", controller: "webhook_endpoints" },
{ name: "welcome", controller: "welcome" },
].sort_by { |menu_item| menu_item[:name] }.freeze
private
private
def authorization_resource
self.class.name.demodulize.sub("Controller", "").singularize.constantize
end
def authorization_resource
self.class.name.demodulize.sub("Controller", "").singularize.constantize
end
def authorize_admin
authorize(authorization_resource, :access?, policy_class: InternalPolicy)
def authorize_admin
authorize(authorization_resource, :access?, policy_class: InternalPolicy)
end
end
end

View file

@ -1,138 +1,140 @@
class Internal::ArticlesController < Internal::ApplicationController
layout "internal"
module Internal
class ArticlesController < Internal::ApplicationController
layout "internal"
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
def index
@pending_buffer_updates = BufferUpdate.where(status: "pending").includes(:article)
@user_buffer_updates = BufferUpdate.where(status: "sent_direct", approver_user_id: current_user.id).where(
"created_at > ?", 24.hours.ago
)
def index
@pending_buffer_updates = BufferUpdate.where(status: "pending").includes(:article)
@user_buffer_updates = BufferUpdate.where(status: "sent_direct", approver_user_id: current_user.id).where(
"created_at > ?", 24.hours.ago
)
case params[:state]
when /not-buffered/
days_ago = params[:state].split("-")[2].to_f
@articles = articles_not_buffered(days_ago)
when /top-/
months_ago = params[:state].split("-")[1].to_i.months.ago
@articles = articles_top(months_ago)
when "satellite"
@articles = articles_satellite
when "satellite-not-bufffered"
@articles = articles_satellite.where(last_buffered: nil)
when "boosted-additional-articles"
@articles = articles_boosted_additional
when "chronological"
@articles = articles_chronological
else
@articles = articles_mixed
@featured_articles = articles_featured
case params[:state]
when /not-buffered/
days_ago = params[:state].split("-")[2].to_f
@articles = articles_not_buffered(days_ago)
when /top-/
months_ago = params[:state].split("-")[1].to_i.months.ago
@articles = articles_top(months_ago)
when "satellite"
@articles = articles_satellite
when "satellite-not-bufffered"
@articles = articles_satellite.where(last_buffered: nil)
when "boosted-additional-articles"
@articles = articles_boosted_additional
when "chronological"
@articles = articles_chronological
else
@articles = articles_mixed
@featured_articles = articles_featured
end
end
def show
@article = Article.find(params[:id])
end
def update
article = Article.find(params[:id])
article.featured = article_params[:featured].to_s == "true"
article.approved = article_params[:approved].to_s == "true"
article.email_digest_eligible = article_params[:email_digest_eligible].to_s == "true"
article.boosted_additional_articles = article_params[:boosted_additional_articles].to_s == "true"
article.boosted_dev_digest_email = article_params[:boosted_dev_digest_email].to_s == "true"
article.user_id = article_params[:user_id].to_i
article.update!(article_params)
render body: nil
end
private
def articles_not_buffered(days_ago)
Article.published.
where(last_buffered: nil).
where("published_at > ? OR crossposted_at > ?", days_ago.days.ago, days_ago.days.ago).
includes(:user).
limited_columns_internal_select.
order("public_reactions_count DESC").
page(params[:page]).
per(50)
end
def articles_top(months_ago)
Article.published.
where("published_at > ?", months_ago).
includes(user: [:notes]).
limited_columns_internal_select.
order("public_reactions_count DESC").
page(params[:page]).
per(50)
end
def articles_satellite
Article.published.where(last_buffered: nil).
includes(:user, :buffer_updates).
tagged_with(Tag.bufferized_tags, any: true).
limited_columns_internal_select.
order("hotness_score DESC").
page(params[:page]).
per(60)
end
def articles_boosted_additional
Article.boosted_via_additional_articles.
includes(:user, :buffer_updates).
limited_columns_internal_select.
order("published_at DESC").
page(params[:page]).
per(100)
end
def articles_chronological
Article.published.
includes(user: [:notes]).
limited_columns_internal_select.
order("published_at DESC").
page(params[:page]).
per(50)
end
def articles_mixed
Article.published.
includes(user: [:notes]).
limited_columns_internal_select.
order("hotness_score DESC").
page(params[:page]).
per(30)
end
def articles_featured
Article.published.or(Article.where(published_from_feed: true)).
where(featured: true).
where("featured_number > ?", Time.current.to_i).
includes(:user, :buffer_updates).
limited_columns_internal_select.
order("featured_number DESC")
end
def article_params
allowed_params = %i[featured
social_image
body_markdown
approved
email_digest_eligible
boosted_additional_articles
boosted_dev_digest_email
main_image_background_hex_color
featured_number
user_id
last_buffered]
params.require(:article).permit(allowed_params)
end
def authorize_admin
authorize Article, :access?, policy_class: InternalPolicy
end
end
def show
@article = Article.find(params[:id])
end
def update
article = Article.find(params[:id])
article.featured = article_params[:featured].to_s == "true"
article.approved = article_params[:approved].to_s == "true"
article.email_digest_eligible = article_params[:email_digest_eligible].to_s == "true"
article.boosted_additional_articles = article_params[:boosted_additional_articles].to_s == "true"
article.boosted_dev_digest_email = article_params[:boosted_dev_digest_email].to_s == "true"
article.user_id = article_params[:user_id].to_i
article.update!(article_params)
render body: nil
end
private
def articles_not_buffered(days_ago)
Article.published.
where(last_buffered: nil).
where("published_at > ? OR crossposted_at > ?", days_ago.days.ago, days_ago.days.ago).
includes(:user).
limited_columns_internal_select.
order("public_reactions_count DESC").
page(params[:page]).
per(50)
end
def articles_top(months_ago)
Article.published.
where("published_at > ?", months_ago).
includes(user: [:notes]).
limited_columns_internal_select.
order("public_reactions_count DESC").
page(params[:page]).
per(50)
end
def articles_satellite
Article.published.where(last_buffered: nil).
includes(:user, :buffer_updates).
tagged_with(Tag.bufferized_tags, any: true).
limited_columns_internal_select.
order("hotness_score DESC").
page(params[:page]).
per(60)
end
def articles_boosted_additional
Article.boosted_via_additional_articles.
includes(:user, :buffer_updates).
limited_columns_internal_select.
order("published_at DESC").
page(params[:page]).
per(100)
end
def articles_chronological
Article.published.
includes(user: [:notes]).
limited_columns_internal_select.
order("published_at DESC").
page(params[:page]).
per(50)
end
def articles_mixed
Article.published.
includes(user: [:notes]).
limited_columns_internal_select.
order("hotness_score DESC").
page(params[:page]).
per(30)
end
def articles_featured
Article.published.or(Article.where(published_from_feed: true)).
where(featured: true).
where("featured_number > ?", Time.current.to_i).
includes(:user, :buffer_updates).
limited_columns_internal_select.
order("featured_number DESC")
end
def article_params
allowed_params = %i[featured
social_image
body_markdown
approved
email_digest_eligible
boosted_additional_articles
boosted_dev_digest_email
main_image_background_hex_color
featured_number
user_id
last_buffered]
params.require(:article).permit(allowed_params)
end
def authorize_admin
authorize Article, :access?, policy_class: InternalPolicy
end
end

View file

@ -1,26 +1,28 @@
class Internal::BadgesController < Internal::ApplicationController
layout "internal"
module Internal
class BadgesController < Internal::ApplicationController
layout "internal"
def index
@badges = Badge.all
end
def index
@badges = Badge.all
end
def award_badges
raise ArgumentError, "Please choose a badge to award" if permitted_params[:badge].blank?
def award_badges
raise ArgumentError, "Please choose a badge to award" if permitted_params[:badge].blank?
usernames = permitted_params[:usernames].split(/\s*,\s*/)
message = permitted_params[:message_markdown].presence || "Congrats!"
BadgeRewarder.award_badges(usernames, permitted_params[:badge], message)
flash[:success] = "BadgeRewarder task ran!"
redirect_to internal_badges_url
rescue ArgumentError => e
flash[:danger] = e.message
redirect_to "/internal/badges"
end
usernames = permitted_params[:usernames].split(/\s*,\s*/)
message = permitted_params[:message_markdown].presence || "Congrats!"
BadgeRewarder.award_badges(usernames, permitted_params[:badge], message)
flash[:success] = "BadgeRewarder task ran!"
redirect_to internal_badges_url
rescue ArgumentError => e
flash[:danger] = e.message
redirect_to "/internal/badges"
end
private
private
def permitted_params
params.permit(:usernames, :badge, :message_markdown)
def permitted_params
params.permit(:usernames, :badge, :message_markdown)
end
end
end

View file

@ -1,69 +1,71 @@
class Internal::BroadcastsController < Internal::ApplicationController
layout "internal"
module Internal
class BroadcastsController < Internal::ApplicationController
layout "internal"
def index
@broadcasts = if params[:type_of]
Broadcast.where(type_of: params[:type_of].capitalize)
else
Broadcast.all
end.order(title: :asc)
end
def show
@broadcast = Broadcast.find(params[:id])
end
def new
@broadcast = Broadcast.new
end
def edit
@broadcast = Broadcast.find(params[:id])
end
def create
@broadcast = Broadcast.new(broadcast_params)
if @broadcast.save
flash[:success] = "Broadcast has been created!"
redirect_to internal_broadcast_path(@broadcast)
else
flash[:danger] = @broadcast.errors.full_messages.to_sentence
render new_internal_broadcast_path
def index
@broadcasts = if params[:type_of]
Broadcast.where(type_of: params[:type_of].capitalize)
else
Broadcast.all
end.order(title: :asc)
end
end
def update
@broadcast = Broadcast.find(params[:id])
if @broadcast.update(broadcast_params)
flash[:success] = "Broadcast has been updated!"
redirect_to internal_broadcast_path(@broadcast)
else
flash[:danger] = @broadcast.errors.full_messages.to_sentence
render :edit
def show
@broadcast = Broadcast.find(params[:id])
end
end
def destroy
@broadcast = Broadcast.find(params[:id])
if @broadcast.destroy
flash[:success] = "Broadcast has been deleted!"
redirect_to internal_broadcasts_path
else
flash[:danger] = "Something went wrong with deleting the broadcast."
render :edit
def new
@broadcast = Broadcast.new
end
end
private
def edit
@broadcast = Broadcast.find(params[:id])
end
def broadcast_params
params.permit(:title, :processed_html, :type_of, :banner_style, :active)
end
def create
@broadcast = Broadcast.new(broadcast_params)
def authorize_admin
authorize Broadcast, :access?, policy_class: InternalPolicy
if @broadcast.save
flash[:success] = "Broadcast has been created!"
redirect_to internal_broadcast_path(@broadcast)
else
flash[:danger] = @broadcast.errors.full_messages.to_sentence
render new_internal_broadcast_path
end
end
def update
@broadcast = Broadcast.find(params[:id])
if @broadcast.update(broadcast_params)
flash[:success] = "Broadcast has been updated!"
redirect_to internal_broadcast_path(@broadcast)
else
flash[:danger] = @broadcast.errors.full_messages.to_sentence
render :edit
end
end
def destroy
@broadcast = Broadcast.find(params[:id])
if @broadcast.destroy
flash[:success] = "Broadcast has been deleted!"
redirect_to internal_broadcasts_path
else
flash[:danger] = "Something went wrong with deleting the broadcast."
render :edit
end
end
private
def broadcast_params
params.permit(:title, :processed_html, :type_of, :banner_style, :active)
end
def authorize_admin
authorize Broadcast, :access?, policy_class: InternalPolicy
end
end
end

View file

@ -1,36 +1,38 @@
class Internal::BufferUpdatesController < Internal::ApplicationController
def create
article_id = params[:article_id]
article = Article.find(article_id) if article_id.present?
fb_post = params[:fb_post]
tweet = params[:tweet]
listing_id = params[:listing_id]
listing = Listing.find(params[:listing_id]) if listing_id.present?
article&.update(featured: true)
case params[:social_channel]
when "main_twitter"
Bufferizer.new("article", article, tweet, current_user.id).main_tweet!
render body: nil
when "satellite_twitter"
Bufferizer.new("article", article, tweet, current_user.id).satellite_tweet!
render body: nil
when "facebook"
Bufferizer.new("article", article, fb_post, current_user.id).facebook_post!
render body: nil
when "listings_twitter"
Bufferizer.new("listing", listing, tweet, current_user.id).listings_tweet!
module Internal
class BufferUpdatesController < Internal::ApplicationController
def create
article_id = params[:article_id]
article = Article.find(article_id) if article_id.present?
fb_post = params[:fb_post]
tweet = params[:tweet]
listing_id = params[:listing_id]
listing = Listing.find(params[:listing_id]) if listing_id.present?
article&.update(featured: true)
case params[:social_channel]
when "main_twitter"
Bufferizer.new("article", article, tweet, current_user.id).main_tweet!
render body: nil
when "satellite_twitter"
Bufferizer.new("article", article, tweet, current_user.id).satellite_tweet!
render body: nil
when "facebook"
Bufferizer.new("article", article, fb_post, current_user.id).facebook_post!
render body: nil
when "listings_twitter"
Bufferizer.new("listing", listing, tweet, current_user.id).listings_tweet!
render body: nil
end
end
def update
BufferUpdate.upbuff!(params[:id], current_user.id, params[:body_text], params[:status])
render body: nil
end
end
def update
BufferUpdate.upbuff!(params[:id], current_user.id, params[:body_text], params[:status])
render body: nil
end
private
private
def authorize_admin
authorize BufferUpdate, :access?, policy_class: InternalPolicy
def authorize_admin
authorize BufferUpdate, :access?, policy_class: InternalPolicy
end
end
end

View file

@ -1,35 +1,37 @@
class Internal::ChatChannelsController < Internal::ApplicationController
layout "internal"
module Internal
class ChatChannelsController < Internal::ApplicationController
layout "internal"
def index
@q = ChatChannel.where(channel_type: "invite_only").includes(:users).ransack(params[:q])
@group_chat_channels = @q.result.page(params[:page]).per(50)
end
def index
@q = ChatChannel.where(channel_type: "invite_only").includes(:users).ransack(params[:q])
@group_chat_channels = @q.result.page(params[:page]).per(50)
end
def create
ChatChannel.create_with_users(
users: users_by_param,
channel_type: "invite_only",
contrived_name: chat_channel_params[:channel_name],
membership_role: "mod",
)
redirect_back(fallback_location: "/internal/chat_channels")
end
def create
ChatChannel.create_with_users(
users: users_by_param,
channel_type: "invite_only",
contrived_name: chat_channel_params[:channel_name],
membership_role: "mod",
)
redirect_back(fallback_location: "/internal/chat_channels")
end
def update
@chat_channel = ChatChannel.find(params[:id])
@chat_channel.invite_users(users: users_by_param, membership_role: "mod")
redirect_back(fallback_location: "/internal/chat_channels")
end
def update
@chat_channel = ChatChannel.find(params[:id])
@chat_channel.invite_users(users: users_by_param, membership_role: "mod")
redirect_back(fallback_location: "/internal/chat_channels")
end
private
private
def users_by_param
User.where(username: chat_channel_params[:usernames_string].downcase.delete(" ").split(","))
end
def users_by_param
User.where(username: chat_channel_params[:usernames_string].downcase.delete(" ").split(","))
end
def chat_channel_params
allowed_params = %i[usernames_string channel_name]
params.require(:chat_channel).permit(allowed_params)
def chat_channel_params
allowed_params = %i[usernames_string channel_name]
params.require(:chat_channel).permit(allowed_params)
end
end
end

View file

@ -1,26 +1,28 @@
class Internal::CommentsController < Internal::ApplicationController
layout "internal"
module Internal
class CommentsController < Internal::ApplicationController
layout "internal"
def index
@comments = if params[:state]&.start_with?("toplast-")
Comment.
includes(:user).
includes(:commentable).
order("public_reactions_count DESC").
where("created_at > ?", params[:state].split("-").last.to_i.days.ago).
page(params[:page] || 1).per(50)
else
Comment.
includes(:user).
includes(:commentable).
order("created_at DESC").
page(params[:page] || 1).per(50)
end
end
def index
@comments = if params[:state]&.start_with?("toplast-")
Comment.
includes(:user).
includes(:commentable).
order("public_reactions_count DESC").
where("created_at > ?", params[:state].split("-").last.to_i.days.ago).
page(params[:page] || 1).per(50)
else
Comment.
includes(:user).
includes(:commentable).
order("created_at DESC").
page(params[:page] || 1).per(50)
end
end
private
private
def authorize_admin
authorize Comment, :access?, policy_class: InternalPolicy
def authorize_admin
authorize Comment, :access?, policy_class: InternalPolicy
end
end
end

View file

@ -1,155 +1,157 @@
class Internal::ConfigsController < Internal::ApplicationController
layout "internal"
module Internal
class ConfigsController < Internal::ApplicationController
layout "internal"
before_action :extra_authorization_and_confirmation, only: [:create]
before_action :extra_authorization_and_confirmation, only: [:create]
def create
clean_up_params
def create
clean_up_params
config_params.each do |key, value|
if value.is_a?(Array)
SiteConfig.public_send("#{key}=", value.reject(&:blank?)) unless value.empty?
elsif value.respond_to?(:to_h)
SiteConfig.public_send("#{key}=", value.to_h) unless value.empty?
else
SiteConfig.public_send("#{key}=", value.strip) unless value.nil?
config_params.each do |key, value|
if value.is_a?(Array)
SiteConfig.public_send("#{key}=", value.reject(&:blank?)) unless value.empty?
elsif value.respond_to?(:to_h)
SiteConfig.public_send("#{key}=", value.to_h) unless value.empty?
else
SiteConfig.public_send("#{key}=", value.strip) unless value.nil?
end
end
bust_relevant_caches
redirect_to internal_config_path, notice: "Site configuration was successfully updated."
end
private
def config_params
allowed_params = %i[
ga_view_id ga_fetch_rate
periodic_email_digest_max
periodic_email_digest_min
sidebar_tags
twitter_hashtag
shop_url
payment_pointer
health_check_token
feed_style
]
allowed_params = allowed_params |
campaign_params |
community_params |
newsletter_params |
rate_limit_params |
mascot_params |
image_params |
onboarding_params |
job_params
has_emails = params[:site_config][:email_addresses].present?
params[:site_config][:email_addresses][:default] = ApplicationConfig["DEFAULT_EMAIL"] if has_emails
params.require(:site_config).permit(
allowed_params,
authentication_providers: [],
social_media_handles: SiteConfig.social_media_handles.keys,
email_addresses: SiteConfig.email_addresses.keys,
meta_keywords: SiteConfig.meta_keywords.keys,
)
end
def extra_authorization_and_confirmation
not_authorized unless current_user.has_role?(:single_resource_admin, Config) # Special additional permission
confirmation_message = "My username is @#{current_user.username} and this action is 100% safe and appropriate."
not_authorized if params[:confirmation] != confirmation_message
end
def clean_up_params
config = params[:site_config]
%i[sidebar_tags suggested_tags suggested_users].each do |param|
config[param] = config[param].downcase.delete(" ") if config[param]
end
end
bust_relevant_caches
redirect_to internal_config_path, notice: "Site configuration was successfully updated."
end
def bust_relevant_caches
# Needs to change when suggested_tags is edited.
CacheBuster.bust("/tags/onboarding")
end
private
def campaign_params
%i[
campaign_featured_tags
campaign_hero_html_variant_name
campaign_sidebar_enabled
campaign_sidebar_image
campaign_url
campaign_articles_require_approval
]
end
def config_params
allowed_params = %i[
ga_view_id ga_fetch_rate
periodic_email_digest_max
periodic_email_digest_min
sidebar_tags
twitter_hashtag
shop_url
payment_pointer
health_check_token
feed_style
]
def community_params
%i[
community_description
community_member_label
community_action
tagline
]
end
allowed_params = allowed_params |
campaign_params |
community_params |
newsletter_params |
rate_limit_params |
mascot_params |
image_params |
onboarding_params |
job_params
def newsletter_params
%i[
mailchimp_community_moderators_id
mailchimp_newsletter_id
mailchimp_sustaining_members_id
mailchimp_tag_moderators_id
]
end
has_emails = params[:site_config][:email_addresses].present?
params[:site_config][:email_addresses][:default] = ApplicationConfig["DEFAULT_EMAIL"] if has_emails
params.require(:site_config).permit(
allowed_params,
authentication_providers: [],
social_media_handles: SiteConfig.social_media_handles.keys,
email_addresses: SiteConfig.email_addresses.keys,
meta_keywords: SiteConfig.meta_keywords.keys,
)
end
def rate_limit_params
%i[
rate_limit_comment_creation
rate_limit_email_recipient
rate_limit_follow_count_daily
rate_limit_image_upload
rate_limit_published_article_creation
rate_limit_organization_creation
rate_limit_user_subscription_creation
]
end
def extra_authorization_and_confirmation
not_authorized unless current_user.has_role?(:single_resource_admin, Config) # Special additional permission
confirmation_message = "My username is @#{current_user.username} and this action is 100% safe and appropriate."
not_authorized if params[:confirmation] != confirmation_message
end
def mascot_params
%i[
mascot_image_description
mascot_image_url
mascot_footer_image_url
mascot_user_id
]
end
def clean_up_params
config = params[:site_config]
%i[sidebar_tags suggested_tags suggested_users].each do |param|
config[param] = config[param].downcase.delete(" ") if config[param]
def image_params
%i[
favicon_url
logo_png
logo_svg
main_social_image
secondary_logo_url
left_navbar_svg_icon
right_navbar_svg_icon
]
end
def onboarding_params
%i[
onboarding_logo_image
onboarding_background_image
onboarding_taskcard_image
suggested_tags
suggested_users
]
end
def job_params
%i[
jobs_url
display_jobs_banner
]
end
end
def bust_relevant_caches
# Needs to change when suggested_tags is edited.
CacheBuster.bust("/tags/onboarding")
end
def campaign_params
%i[
campaign_featured_tags
campaign_hero_html_variant_name
campaign_sidebar_enabled
campaign_sidebar_image
campaign_url
campaign_articles_require_approval
]
end
def community_params
%i[
community_description
community_member_label
community_action
tagline
]
end
def newsletter_params
%i[
mailchimp_community_moderators_id
mailchimp_newsletter_id
mailchimp_sustaining_members_id
mailchimp_tag_moderators_id
]
end
def rate_limit_params
%i[
rate_limit_comment_creation
rate_limit_email_recipient
rate_limit_follow_count_daily
rate_limit_image_upload
rate_limit_published_article_creation
rate_limit_organization_creation
rate_limit_user_subscription_creation
]
end
def mascot_params
%i[
mascot_image_description
mascot_image_url
mascot_footer_image_url
mascot_user_id
]
end
def image_params
%i[
favicon_url
logo_png
logo_svg
main_social_image
secondary_logo_url
left_navbar_svg_icon
right_navbar_svg_icon
]
end
def onboarding_params
%i[
onboarding_logo_image
onboarding_background_image
onboarding_taskcard_image
suggested_tags
suggested_users
]
end
def job_params
%i[
jobs_url
display_jobs_banner
]
end
end

View file

@ -1,121 +1,123 @@
class Internal::FeedbackMessagesController < Internal::ApplicationController
layout "internal"
module Internal
class FeedbackMessagesController < Internal::ApplicationController
layout "internal"
def index
@q = FeedbackMessage.includes(:reporter, :offender, :affected).
order(created_at: :desc).
ransack(params[:q])
@feedback_messages = @q.result.page(params[:page] || 1).per(5)
def index
@q = FeedbackMessage.includes(:reporter, :offender, :affected).
order(created_at: :desc).
ransack(params[:q])
@feedback_messages = @q.result.page(params[:page] || 1).per(5)
@feedback_type = params[:state] || "abuse-reports"
@status = params[:status] || "Open"
@feedback_type = params[:state] || "abuse-reports"
@status = params[:status] || "Open"
@email_messages = EmailMessage.find_for_reports(@feedback_messages)
@new_articles = Article.published.select(:title, :user_id, :path).includes(:user).
order(created_at: :desc).
where("score > ? AND score < ?", -10, 8).
limit(120)
@email_messages = EmailMessage.find_for_reports(@feedback_messages)
@new_articles = Article.published.select(:title, :user_id, :path).includes(:user).
order(created_at: :desc).
where("score > ? AND score < ?", -10, 8).
limit(120)
@possible_spam_users = User.where(
"github_created_at > ? OR twitter_created_at > ? OR length(name) > ?",
50.hours.ago, 50.hours.ago, 30
).
where("created_at > ?", 48.hours.ago).
order(created_at: :desc).
select(:username, :name, :id).
where.not("username LIKE ?", "%spam_%").
limit(150)
@possible_spam_users = User.where(
"github_created_at > ? OR twitter_created_at > ? OR length(name) > ?",
50.hours.ago, 50.hours.ago, 30
).
where("created_at > ?", 48.hours.ago).
order(created_at: :desc).
select(:username, :name, :id).
where.not("username LIKE ?", "%spam_%").
limit(150)
@vomits = get_vomits
end
def save_status
feedback_message = FeedbackMessage.find(params[:id])
if feedback_message.update(status: params[:status])
render json: { outcome: "Success" }
else
render json: { outcome: feedback_message.errors.full_messages }
@vomits = get_vomits
end
end
def show
@feedback_message = FeedbackMessage.find_by(id: params[:id])
@email_messages = EmailMessage.find_for_reports(@feedback_message.id)
end
def send_email
if NotifyMailer.with(params).feedback_message_resolution_email.deliver_now
render json: { outcome: "Success" }
else
render json: { outcome: "Failure" }
def save_status
feedback_message = FeedbackMessage.find(params[:id])
if feedback_message.update(status: params[:status])
render json: { outcome: "Success" }
else
render json: { outcome: feedback_message.errors.full_messages }
end
end
end
def create_note
note = Note.new(
noteable_id: params["noteable_id"],
noteable_type: params["noteable_type"],
author_id: params["author_id"],
content: params["content"],
reason: params["reason"],
)
def show
@feedback_message = FeedbackMessage.find_by(id: params[:id])
@email_messages = EmailMessage.find_for_reports(@feedback_message.id)
end
if note.save
params["author_name"] = note.author.name
params["feedback_message_status"] = note.noteable.status
params["feedback_type"] = note.noteable.feedback_type
def send_email
if NotifyMailer.with(params).feedback_message_resolution_email.deliver_now
render json: { outcome: "Success" }
else
render json: { outcome: "Failure" }
end
end
send_slack_message(params)
render json: {
outcome: "Success",
def create_note
note = Note.new(
noteable_id: params["noteable_id"],
noteable_type: params["noteable_type"],
author_id: params["author_id"],
content: params["content"],
author_name: note.author.name
}
else
render json: { outcome: note.errors.full_messages }
reason: params["reason"],
)
if note.save
params["author_name"] = note.author.name
params["feedback_message_status"] = note.noteable.status
params["feedback_type"] = note.noteable.feedback_type
send_slack_message(params)
render json: {
outcome: "Success",
content: params["content"],
author_name: note.author.name
}
else
render json: { outcome: note.errors.full_messages }
end
end
end
private
private
def get_vomits
q = Reaction.includes(:user, :reactable).
select(:id, :user_id, :reactable_type, :reactable_id).
order(updated_at: :desc)
if params[:status] == "Open" || params[:status].blank?
q.where(category: "vomit", status: "valid")
elsif params[:status] == "Resolved"
q.where(category: "vomit", status: "confirmed").limit(10)
else
q.where(category: "vomit", status: "invalid").limit(10)
def get_vomits
q = Reaction.includes(:user, :reactable).
select(:id, :user_id, :reactable_type, :reactable_id).
order(updated_at: :desc)
if params[:status] == "Open" || params[:status].blank?
q.where(category: "vomit", status: "valid")
elsif params[:status] == "Resolved"
q.where(category: "vomit", status: "confirmed").limit(10)
else
q.where(category: "vomit", status: "invalid").limit(10)
end
end
end
def send_slack_message(params)
Slack::Messengers::Note.call(
author_name: params[:author_name],
status: params[:feedback_message_status],
type: params[:feedback_type],
report_id: params[:noteable_id],
message: params[:content],
)
end
def send_slack_message(params)
Slack::Messengers::Note.call(
author_name: params[:author_name],
status: params[:feedback_message_status],
type: params[:feedback_type],
report_id: params[:noteable_id],
message: params[:content],
)
end
def generate_message(params)
<<~HEREDOC
*New note from #{params['author_name']}:*
*Report status: #{params['feedback_message_status']}*
Report page: https://#{ApplicationConfig['APP_DOMAIN']}/internal/reports/#{params['noteable_id']}
--------
Message: #{params['content']}
HEREDOC
end
def generate_message(params)
<<~HEREDOC
*New note from #{params['author_name']}:*
*Report status: #{params['feedback_message_status']}*
Report page: https://#{ApplicationConfig['APP_DOMAIN']}/internal/reports/#{params['noteable_id']}
--------
Message: #{params['content']}
HEREDOC
end
def feedback_message_params
params[:feedback_message].permit(
:id, :status, :reviewer_id,
note: %i[content reason noteable_id noteable_type author_id]
)
def feedback_message_params
params[:feedback_message].permit(
:id, :status, :reviewer_id,
note: %i[content reason noteable_id noteable_type author_id]
)
end
end
end

View file

@ -1,3 +1,5 @@
class Internal::GrowthController < Internal::ApplicationController
layout "internal"
module Internal
class GrowthController < Internal::ApplicationController
layout "internal"
end
end

View file

@ -1,54 +1,56 @@
class Internal::ListingsController < Internal::ApplicationController
include ListingsToolkit
layout "internal"
module Internal
class ListingsController < Internal::ApplicationController
include ListingsToolkit
layout "internal"
def index
@listings =
Listing.includes(%i[user listing_category]).
page(params[:page]).order("bumped_at DESC").per(50)
def index
@listings =
Listing.includes(%i[user listing_category]).
page(params[:page]).order("bumped_at DESC").per(50)
@listings = @listings.published unless include_unpublished?
@listings = @listings.in_category(params[:filter]) if params[:filter].present?
end
@listings = @listings.published unless include_unpublished?
@listings = @listings.in_category(params[:filter]) if params[:filter].present?
end
def edit
@listing = Listing.find(params[:id])
end
def edit
@listing = Listing.find(params[:id])
end
def update
@listing = Listing.find(params[:id])
handle_publish_status if listing_params[:published]
bump_listing(@listing.cost) if listing_params[:action] == "bump"
update_listing_details
clear_listings_cache
flash[:success] = "Listing updated successfully"
redirect_to edit_internal_listing_path(@listing)
end
def update
@listing = Listing.find(params[:id])
handle_publish_status if listing_params[:published]
bump_listing(@listing.cost) if listing_params[:action] == "bump"
update_listing_details
clear_listings_cache
flash[:success] = "Listing updated successfully"
redirect_to edit_internal_listing_path(@listing)
end
def destroy
@listing = Listing.find(params[:id])
@listing.destroy
flash[:warning] = "'#{@listing.title}' was destroyed successfully"
redirect_to internal_listings_path
end
def destroy
@listing = Listing.find(params[:id])
@listing.destroy
flash[:warning] = "'#{@listing.title}' was destroyed successfully"
redirect_to internal_listings_path
end
private
private
ALLOWED_PARAMS = %i[
published body_markdown title category listing_category_id tag_list action
].freeze
private_constant :ALLOWED_PARAMS
ALLOWED_PARAMS = %i[
published body_markdown title category listing_category_id tag_list action
].freeze
private_constant :ALLOWED_PARAMS
def listing_params
params.require(:listing).permit(ALLOWED_PARAMS)
end
def listing_params
params.require(:listing).permit(ALLOWED_PARAMS)
end
def handle_publish_status
unpublish_listing if listing_params[:published] == "0"
publish_listing if listing_params[:published] == "1"
end
def handle_publish_status
unpublish_listing if listing_params[:published] == "0"
publish_listing if listing_params[:published] == "1"
end
def include_unpublished?
params[:include_unpublished] == "1"
def include_unpublished?
params[:include_unpublished] == "1"
end
end
end

View file

@ -1,12 +1,14 @@
class Internal::ModeratorActionsController < Internal::ApplicationController
layout "internal"
module Internal
class ModeratorActionsController < Internal::ApplicationController
layout "internal"
def index
@q = AuditLog.
includes(:user).
where(category: "moderator.audit.log").
order(created_at: :desc).
ransack(params[:q])
@moderator_actions = @q.result.page(params[:page] || 1).per(25)
def index
@q = AuditLog.
includes(:user).
where(category: "moderator.audit.log").
order(created_at: :desc).
ransack(params[:q])
@moderator_actions = @q.result.page(params[:page] || 1).per(25)
end
end
end

View file

@ -1,33 +1,35 @@
class Internal::ModsController < Internal::ApplicationController
layout "internal"
module Internal
class ModsController < Internal::ApplicationController
layout "internal"
INDEX_ATTRIBUTES = %i[
id
username
comments_count
badge_achievements_count
last_comment_at
].freeze
INDEX_ATTRIBUTES = %i[
id
username
comments_count
badge_achievements_count
last_comment_at
].freeze
def index
@mods = Internal::ModeratorsQuery.call(
relation: User.select(INDEX_ATTRIBUTES),
options: permitted_params,
).page(params[:page]).per(50)
end
def index
@mods = Internal::ModeratorsQuery.call(
relation: User.select(INDEX_ATTRIBUTES),
options: permitted_params,
).page(params[:page]).per(50)
end
def update
@user = User.find(params[:id])
def update
@user = User.find(params[:id])
AssignTagModerator.add_trusted_role(@user)
AssignTagModerator.add_trusted_role(@user)
redirect_to internal_mods_path(state: :potential),
flash: { success: "#{@user.username} now has Trusted role!" }
end
redirect_to internal_mods_path(state: :potential),
flash: { success: "#{@user.username} now has Trusted role!" }
end
private
private
def permitted_params
params.permit(:state, :search, :page)
def permitted_params
params.permit(:state, :search, :page)
end
end
end

View file

@ -1,45 +1,47 @@
class Internal::OrganizationMembershipsController < Internal::ApplicationController
layout "internal"
module Internal
class OrganizationMembershipsController < Internal::ApplicationController
layout "internal"
def update
organization_membership = OrganizationMembership.find_by(id: params[:id])
if organization_membership.update(organization_membership_params)
flash[:success] = "User was successfully updated to #{organization_membership.type_of_user}"
else
flash[:danger] = organization_membership.errors.full_messages
def update
organization_membership = OrganizationMembership.find_by(id: params[:id])
if organization_membership.update(organization_membership_params)
flash[:success] = "User was successfully updated to #{organization_membership.type_of_user}"
else
flash[:danger] = organization_membership.errors.full_messages
end
redirect_to internal_user_path(organization_membership.user_id)
end
redirect_to internal_user_path(organization_membership.user_id)
end
def create
organization_membership = OrganizationMembership.new(organization_membership_params)
organization = Organization.find_by(id: organization_membership_params[:organization_id])
if organization && organization_membership.save
flash[:success] = "User was successfully added to #{organization.name}"
elsif organization.blank?
message = "Organization ##{organization_membership_params[:organization_id]} does not exist. Perhaps a typo?"
flash[:danger] = message
else
flash[:danger] = organization_membership.errors.full_messages
def create
organization_membership = OrganizationMembership.new(organization_membership_params)
organization = Organization.find_by(id: organization_membership_params[:organization_id])
if organization && organization_membership.save
flash[:success] = "User was successfully added to #{organization.name}"
elsif organization.blank?
message = "Organization ##{organization_membership_params[:organization_id]} does not exist. Perhaps a typo?"
flash[:danger] = message
else
flash[:danger] = organization_membership.errors.full_messages
end
redirect_to internal_user_path(organization_membership.user_id)
end
redirect_to internal_user_path(organization_membership.user_id)
end
def destroy
organization_membership = OrganizationMembership.find_by(id: params[:id])
if organization_membership.destroy
flash[:success] = "User was successfully removed from org ##{organization_membership.organization_id}"
else
message = "Something went wrong with removing the user from org ##{organization_membership.organization_id}"
flash[:danger] = message
def destroy
organization_membership = OrganizationMembership.find_by(id: params[:id])
if organization_membership.destroy
flash[:success] = "User was successfully removed from org ##{organization_membership.organization_id}"
else
message = "Something went wrong with removing the user from org ##{organization_membership.organization_id}"
flash[:danger] = message
end
redirect_to internal_user_path(organization_membership.user_id)
end
redirect_to internal_user_path(organization_membership.user_id)
end
private
private
def organization_membership_params
allowed_params = %i[type_of_user user_title organization_id user_id]
params.require(:organization_membership).permit(allowed_params)
def organization_membership_params
allowed_params = %i[type_of_user user_title organization_id user_id]
params.require(:organization_membership).permit(allowed_params)
end
end
end

View file

@ -1,47 +1,49 @@
class Internal::OrganizationsController < Internal::ApplicationController
layout "internal"
module Internal
class OrganizationsController < Internal::ApplicationController
layout "internal"
CREDIT_ACTIONS = {
add: :add_to,
remove: :remove_from
}.with_indifferent_access.freeze
CREDIT_ACTIONS = {
add: :add_to,
remove: :remove_from
}.with_indifferent_access.freeze
def index
@organizations = Organization.order(name: :desc).page(params[:page]).per(50)
def index
@organizations = Organization.order(name: :desc).page(params[:page]).per(50)
return if params[:search].blank?
return if params[:search].blank?
@organizations = @organizations.where(
"name ILIKE ?",
"%#{params[:search].strip}%",
)
end
@organizations = @organizations.where(
"name ILIKE ?",
"%#{params[:search].strip}%",
)
end
def show
@organization = Organization.find(params[:id])
end
def show
@organization = Organization.find(params[:id])
end
def update_org_credits
org = Organization.find(params[:id])
amount = params[:credits].to_i
update_action = CREDIT_ACTIONS.fetch(params[:credit_action])
def update_org_credits
org = Organization.find(params[:id])
amount = params[:credits].to_i
update_action = CREDIT_ACTIONS.fetch(params[:credit_action])
Credit.public_send(update_action, org, amount)
add_note(org)
Credit.public_send(update_action, org, amount)
add_note(org)
flash[:notice] = "Sucessfully updated credits"
redirect_to internal_organization_path(org)
end
flash[:notice] = "Sucessfully updated credits"
redirect_to internal_organization_path(org)
end
private
private
def add_note(org)
Note.create(
author_id: current_user.id,
noteable_id: org.id,
noteable_type: "Organization",
reason: "misc_note",
content: params[:note],
)
def add_note(org)
Note.create(
author_id: current_user.id,
noteable_id: org.id,
noteable_type: "Organization",
reason: "misc_note",
content: params[:note],
)
end
end
end

View file

@ -1,41 +1,43 @@
class Internal::PagesController < Internal::ApplicationController
layout "internal"
module Internal
class PagesController < Internal::ApplicationController
layout "internal"
def index
@pages = Page.all
end
def index
@pages = Page.all
end
def new
@page = Page.new
end
def new
@page = Page.new
end
def edit
@page = Page.find(params[:id])
end
def edit
@page = Page.find(params[:id])
end
def update
@page = Page.find(params[:id])
@page.update!(page_params)
redirect_to "/internal/pages"
end
def update
@page = Page.find(params[:id])
@page.update!(page_params)
redirect_to "/internal/pages"
end
def create
@page = Page.new(page_params)
@page.save!
redirect_to "/internal/pages"
end
def create
@page = Page.new(page_params)
@page.save!
redirect_to "/internal/pages"
end
def destroy
@page = Page.find(params[:id])
@page.destroy
redirect_to "/internal/pages"
end
def destroy
@page = Page.find(params[:id])
@page.destroy
redirect_to "/internal/pages"
end
private
private
def page_params
allowed_params = %i[title slug body_markdown body_html body_json description template is_top_level_path
social_image]
params.require(:page).permit(allowed_params)
def page_params
allowed_params = %i[title slug body_markdown body_html body_json description template is_top_level_path
social_image]
params.require(:page).permit(allowed_params)
end
end
end

View file

@ -1,66 +1,68 @@
class Internal::PathRedirectsController < Internal::ApplicationController
layout "internal"
module Internal
class PathRedirectsController < Internal::ApplicationController
layout "internal"
before_action :set_path_redirect, only: %i[edit update destroy]
before_action :set_path_redirect, only: %i[edit update destroy]
after_action only: %i[update destroy create] do
Audit::Logger.log(:internal, current_user, params.dup)
end
def new
@path_redirect = PathRedirect.new
end
def create
@path_redirect = PathRedirect.new(new_path_redirect_params)
if @path_redirect.save
flash[:success] = "Path Redirect created successfully!"
redirect_to internal_path_redirects_path
else
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render new_internal_path_redirect_path
after_action only: %i[update destroy create] do
Audit::Logger.log(:internal, current_user, params.dup)
end
end
def index
@q = PathRedirect.order(created_at: :desc).ransack(params[:q])
@path_redirects = @q.result.page(params[:page] || 1).per(25)
end
def edit; end
def update
if @path_redirect.update(edit_path_redirect_params)
flash[:success] = "Path Redirect updated successfully!"
redirect_to edit_internal_path_redirect_path(@path_redirect)
else
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render :edit
def new
@path_redirect = PathRedirect.new
end
end
def destroy
if @path_redirect.destroy
flash[:success] = "Path Redirect destroyed successfully!"
redirect_to internal_path_redirects_path
else # This should never be the case
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render :edit
def create
@path_redirect = PathRedirect.new(new_path_redirect_params)
if @path_redirect.save
flash[:success] = "Path Redirect created successfully!"
redirect_to internal_path_redirects_path
else
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render new_internal_path_redirect_path
end
end
end
private
def index
@q = PathRedirect.order(created_at: :desc).ransack(params[:q])
@path_redirects = @q.result.page(params[:page] || 1).per(25)
end
def set_path_redirect
@path_redirect = PathRedirect.find(params[:id])
end
def edit; end
def new_path_redirect_params
params.require(:path_redirect).permit(:old_path, :new_path).merge(source: "admin")
end
def update
if @path_redirect.update(edit_path_redirect_params)
flash[:success] = "Path Redirect updated successfully!"
redirect_to edit_internal_path_redirect_path(@path_redirect)
else
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render :edit
end
end
def edit_path_redirect_params
params.require(:path_redirect).permit(:new_path).merge(source: "admin")
def destroy
if @path_redirect.destroy
flash[:success] = "Path Redirect destroyed successfully!"
redirect_to internal_path_redirects_path
else # This should never be the case
flash[:danger] = @path_redirect.errors.full_messages.to_sentence
render :edit
end
end
private
def set_path_redirect
@path_redirect = PathRedirect.find(params[:id])
end
def new_path_redirect_params
params.require(:path_redirect).permit(:old_path, :new_path).merge(source: "admin")
end
def edit_path_redirect_params
params.require(:path_redirect).permit(:new_path).merge(source: "admin")
end
end
end

View file

@ -1,11 +1,13 @@
class Internal::PermissionsController < Internal::ApplicationController
layout "internal"
module Internal
class PermissionsController < Internal::ApplicationController
layout "internal"
def index
@users = User.with_role(:admin).
union(User.with_role(:super_admin)).
union(User.with_role(:single_resource_admin, :any)).
page(params[:page]).
per(50)
def index
@users = User.with_role(:admin).
union(User.with_role(:super_admin)).
union(User.with_role(:single_resource_admin, :any)).
page(params[:page]).
per(50)
end
end
end

View file

@ -1,71 +1,73 @@
class Internal::PodcastsController < Internal::ApplicationController
layout "internal"
module Internal
class PodcastsController < Internal::ApplicationController
layout "internal"
before_action :find_podcast, only: %i[edit update fetch remove_admin add_admin]
before_action :find_user, only: %i[remove_admin add_admin]
before_action :find_podcast, only: %i[edit update fetch remove_admin add_admin]
before_action :find_user, only: %i[remove_admin add_admin]
def index
@podcasts = Podcast.left_outer_joins(:podcast_episodes).
select("podcasts.*, count(podcast_episodes) as episodes_count").
group("podcasts.id").order("podcasts.created_at DESC").
page(params[:page]).per(50)
def index
@podcasts = Podcast.left_outer_joins(:podcast_episodes).
select("podcasts.*, count(podcast_episodes) as episodes_count").
group("podcasts.id").order("podcasts.created_at DESC").
page(params[:page]).per(50)
return if params[:search].blank?
return if params[:search].blank?
@podcasts = @podcasts.where("podcasts.title ILIKE :search", search: "%#{params[:search]}%")
end
def edit; end
def update
if @podcast.update(podcast_params)
redirect_to internal_podcasts_path, notice: "Podcast updated"
else
render :edit
@podcasts = @podcasts.where("podcasts.title ILIKE :search", search: "%#{params[:search]}%")
end
end
def fetch
limit = params[:limit].to_i.zero? ? nil : params[:limit].to_i
force = params[:force].to_i == 1
Podcasts::GetEpisodesWorker.perform_async(podcast_id: @podcast.id, limit: limit, force: force)
flash[:notice] = "Podcast's episodes fetching was scheduled (#{@podcast.title}, ##{@podcast.id})"
redirect_to internal_podcasts_path
end
def edit; end
def remove_admin
removed_roles = @user.remove_role(:podcast_admin, @podcast)
if removed_roles.empty?
redirect_to edit_internal_podcast_path(@podcast), notice: "Error"
else
redirect_to internal_podcasts_path, notice: "Removed admin"
def update
if @podcast.update(podcast_params)
redirect_to internal_podcasts_path, notice: "Podcast updated"
else
render :edit
end
end
end
def add_admin
role = @user.add_role(:podcast_admin, @podcast)
if role.persisted?
redirect_to internal_podcasts_path, notice: "Added admin"
else
redirect_to edit_internal_podcast_path(@podcast), notice: "Error"
def fetch
limit = params[:limit].to_i.zero? ? nil : params[:limit].to_i
force = params[:force].to_i == 1
Podcasts::GetEpisodesWorker.perform_async(podcast_id: @podcast.id, limit: limit, force: force)
flash[:notice] = "Podcast's episodes fetching was scheduled (#{@podcast.title}, ##{@podcast.id})"
redirect_to internal_podcasts_path
end
end
private
def remove_admin
removed_roles = @user.remove_role(:podcast_admin, @podcast)
if removed_roles.empty?
redirect_to edit_internal_podcast_path(@podcast), notice: "Error"
else
redirect_to internal_podcasts_path, notice: "Removed admin"
end
end
def find_podcast
@podcast = Podcast.find(params[:id])
end
def add_admin
role = @user.add_role(:podcast_admin, @podcast)
if role.persisted?
redirect_to internal_podcasts_path, notice: "Added admin"
else
redirect_to edit_internal_podcast_path(@podcast), notice: "Error"
end
end
def find_user
@user = User.find_by(id: params[:podcast][:user_id])
redirect_to edit_internal_podcast_path(@podcast), notice: "No such user" unless @user
end
private
def podcast_params
allowed_params = %i[
title feed_url
]
params.require(:podcast).permit(allowed_params)
def find_podcast
@podcast = Podcast.find(params[:id])
end
def find_user
@user = User.find_by(id: params[:podcast][:user_id])
redirect_to edit_internal_podcast_path(@podcast), notice: "No such user" unless @user
end
def podcast_params
allowed_params = %i[
title feed_url
]
params.require(:podcast).permit(allowed_params)
end
end
end

View file

@ -1,15 +1,17 @@
class Internal::PrivilegedReactionsController < Internal::ApplicationController
layout "internal"
module Internal
class PrivilegedReactionsController < Internal::ApplicationController
layout "internal"
PRIVILEGED_REACTION_CATEGORIES = %i[thumbsup thumbsdown vomit].freeze
PRIVILEGED_REACTION_CATEGORIES = %i[thumbsup thumbsdown vomit].freeze
def index
@q = Reaction.
includes(:user,
:reactable).
where("category IN (?)", PRIVILEGED_REACTION_CATEGORIES).
order("reactions.created_at DESC").
ransack(params[:q])
@privileged_reactions = @q.result.page(params[:page] || 1).per(25)
def index
@q = Reaction.
includes(:user,
:reactable).
where("category IN (?)", PRIVILEGED_REACTION_CATEGORIES).
order("reactions.created_at DESC").
ransack(params[:q])
@privileged_reactions = @q.result.page(params[:page] || 1).per(25)
end
end
end

View file

@ -1,21 +1,23 @@
class Internal::ReactionsController < Internal::ApplicationController
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
module Internal
class ReactionsController < Internal::ApplicationController
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
def update
@reaction = Reaction.find(params[:id])
if @reaction.update(status: params[:status])
Moderator::SinkArticles.call(@reaction.reactable_id) if confirmed_vomit_reaction?
render json: { outcome: "Success" }
else
render json: { error: @reaction.errors_as_sentence }, status: :unprocessable_entity
def update
@reaction = Reaction.find(params[:id])
if @reaction.update(status: params[:status])
Moderator::SinkArticles.call(@reaction.reactable_id) if confirmed_vomit_reaction?
render json: { outcome: "Success" }
else
render json: { error: @reaction.errors_as_sentence }, status: :unprocessable_entity
end
end
private
def confirmed_vomit_reaction?
@reaction.reactable_type == "User" && @reaction.status == "confirmed" && @reaction.category == "vomit"
end
end
private
def confirmed_vomit_reaction?
@reaction.reactable_type == "User" && @reaction.status == "confirmed" && @reaction.category == "vomit"
end
end

View file

@ -1,65 +1,67 @@
class Internal::ResponseTemplatesController < Internal::ApplicationController
layout "internal"
after_action only: %i[create update destroy] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
def index
@response_templates = if params[:filter]
ResponseTemplate.where(type_of: params[:filter])
else
ResponseTemplate.all
end
@response_templates = @response_templates.page(params[:page]).per(50)
end
def new
@response_template = ResponseTemplate.new
end
def create
@response_template = ResponseTemplate.new(permitted_params)
if @response_template.save
flash[:success] = "Response Template: \"#{@response_template.title}\" saved successfully."
redirect_to internal_response_templates_path
else
flash[:danger] = @response_template.errors_as_sentence
@response_templates = ResponseTemplate.page(params[:page]).per(50)
render new_internal_response_template_path
end
end
def edit
@response_template = ResponseTemplate.find(params[:id])
end
def update
@response_template = ResponseTemplate.find(params[:id])
if @response_template.update(permitted_attributes(ResponseTemplate))
flash[:success] = "The response template \"#{@response_template.title}\" was updated."
redirect_to edit_internal_response_template_path(@response_template)
else
flash[:danger] = @response_template.errors_as_sentence
render :edit
end
end
def destroy
@response_template = ResponseTemplate.find(params[:id])
if @response_template.destroy
flash[:success] = "The response template \"#{@response_template.title}\" was deleted."
else
flash[:danger] = @response_template.errors_as_sentence # this will probably never fail
module Internal
class ResponseTemplatesController < Internal::ApplicationController
layout "internal"
after_action only: %i[create update destroy] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
redirect_back(fallback_location: internal_response_templates_path)
end
def index
@response_templates = if params[:filter]
ResponseTemplate.where(type_of: params[:filter])
else
ResponseTemplate.all
end
@response_templates = @response_templates.page(params[:page]).per(50)
end
private
def new
@response_template = ResponseTemplate.new
end
def permitted_params
params.require(:response_template).permit(:body_markdown, :user_id, :content, :title, :type_of, :content_type)
def create
@response_template = ResponseTemplate.new(permitted_params)
if @response_template.save
flash[:success] = "Response Template: \"#{@response_template.title}\" saved successfully."
redirect_to internal_response_templates_path
else
flash[:danger] = @response_template.errors_as_sentence
@response_templates = ResponseTemplate.page(params[:page]).per(50)
render new_internal_response_template_path
end
end
def edit
@response_template = ResponseTemplate.find(params[:id])
end
def update
@response_template = ResponseTemplate.find(params[:id])
if @response_template.update(permitted_attributes(ResponseTemplate))
flash[:success] = "The response template \"#{@response_template.title}\" was updated."
redirect_to edit_internal_response_template_path(@response_template)
else
flash[:danger] = @response_template.errors_as_sentence
render :edit
end
end
def destroy
@response_template = ResponseTemplate.find(params[:id])
if @response_template.destroy
flash[:success] = "The response template \"#{@response_template.title}\" was deleted."
else
flash[:danger] = @response_template.errors_as_sentence # this will probably never fail
end
redirect_back(fallback_location: internal_response_templates_path)
end
private
def permitted_params
params.require(:response_template).permit(:body_markdown, :user_id, :content, :title, :type_of, :content_type)
end
end
end

View file

@ -1,33 +1,35 @@
class Internal::SecretsController < Internal::ApplicationController
layout "internal"
module Internal
class SecretsController < Internal::ApplicationController
layout "internal"
before_action :validate_settable_secret, only: [:update]
after_action only: [:update] do
Audit::Logger.log(:internal, current_user, params.dup)
end
before_action :validate_settable_secret, only: [:update]
after_action only: [:update] do
Audit::Logger.log(:internal, current_user, params.dup)
end
def index
@vault_enabled = AppSecrets.vault_enabled?
@secrets = AppSecrets::SETTABLE_SECRETS.map do |key|
secret_value = AppSecrets[key]
secret_value = secret_value.present? ? "#{secret_value.first(8)}******" : "Not In Vault"
[key, secret_value]
def index
@vault_enabled = AppSecrets.vault_enabled?
@secrets = AppSecrets::SETTABLE_SECRETS.map do |key|
secret_value = AppSecrets[key]
secret_value = secret_value.present? ? "#{secret_value.first(8)}******" : "Not In Vault"
[key, secret_value]
end
end
def update
AppSecrets[params[:key_name]] = params[:key_value]
flash[:success] = "Secret #{params[:key_name]} was successfully updated in Vault."
redirect_to internal_secrets_path
end
private
def validate_settable_secret
update_param = params.permit(*AppSecrets::SETTABLE_SECRETS)
params[:key_name], params[:key_value] = update_param.to_h.to_a.first
bad_request unless update_param.present? && params[:key_name].is_a?(String) && params[:key_value].is_a?(String)
end
end
def update
AppSecrets[params[:key_name]] = params[:key_value]
flash[:success] = "Secret #{params[:key_name]} was successfully updated in Vault."
redirect_to internal_secrets_path
end
private
def validate_settable_secret
update_param = params.permit(*AppSecrets::SETTABLE_SECRETS)
params[:key_name], params[:key_value] = update_param.to_h.to_a.first
bad_request unless update_param.present? && params[:key_name].is_a?(String) && params[:key_value].is_a?(String)
end
end

View file

@ -1,39 +1,41 @@
class Internal::SponsorshipsController < Internal::ApplicationController
layout "internal"
module Internal
class SponsorshipsController < Internal::ApplicationController
layout "internal"
def index
@sponsorships = Sponsorship.includes(:organization, :user).order("created_at desc").page(params[:page]).per(50)
end
def index
@sponsorships = Sponsorship.includes(:organization, :user).order("created_at desc").page(params[:page]).per(50)
end
def edit
@sponsorship = Sponsorship.find(params[:id])
end
def edit
@sponsorship = Sponsorship.find(params[:id])
end
def update
@sponsorship = Sponsorship.find(params[:id])
if @sponsorship.update(sponsorship_params)
flash[:notice] = "Sponsorship was successfully updated"
def update
@sponsorship = Sponsorship.find(params[:id])
if @sponsorship.update(sponsorship_params)
flash[:notice] = "Sponsorship was successfully updated"
redirect_to internal_sponsorships_path
else
flash[:danger] = @sponsorship.errors_as_sentence
render action: :edit
end
end
def destroy
@sponsorship = Sponsorship.find(params[:id])
if @sponsorship.destroy
flash[:notice] = "Sponsorship was successfully destroyed"
else
flash[:danger] = "Sponsorship was not destroyed"
end
redirect_to internal_sponsorships_path
else
flash[:danger] = @sponsorship.errors_as_sentence
render action: :edit
end
end
def destroy
@sponsorship = Sponsorship.find(params[:id])
if @sponsorship.destroy
flash[:notice] = "Sponsorship was successfully destroyed"
else
flash[:danger] = "Sponsorship was not destroyed"
private
def sponsorship_params
params.require(:sponsorship).permit(%i[status expires_at tagline url blurb_html featured_number instructions
instructions_updated_at])
end
redirect_to internal_sponsorships_path
end
private
def sponsorship_params
params.require(:sponsorship).permit(%i[status expires_at tagline url blurb_html featured_number instructions
instructions_updated_at])
end
end

View file

@ -1,55 +1,57 @@
class Internal::TagsController < Internal::ApplicationController
layout "internal"
module Internal
class TagsController < Internal::ApplicationController
layout "internal"
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
after_action only: [:update] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
def index
@tags = if params[:state] == "supported"
Tag.where(supported: true).order("taggings_count DESC").page(params[:page]).per(50)
elsif params[:state] == "unsupported"
Tag.where(supported: false).order("taggings_count DESC").page(params[:page]).per(50)
else
Tag.order("taggings_count DESC").page(params[:page]).per(50)
end
@tags = @tags.where("tags.name ILIKE :search", search: "%#{params[:search]}%") if params[:search].present?
end
def index
@tags = if params[:state] == "supported"
Tag.where(supported: true).order("taggings_count DESC").page(params[:page]).per(50)
elsif params[:state] == "unsupported"
Tag.where(supported: false).order("taggings_count DESC").page(params[:page]).per(50)
else
Tag.order("taggings_count DESC").page(params[:page]).per(50)
end
@tags = @tags.where("tags.name ILIKE :search", search: "%#{params[:search]}%") if params[:search].present?
end
def show
@tag = Tag.find(params[:id])
end
def show
@tag = Tag.find(params[:id])
end
def update
@tag = Tag.find(params[:id])
@add_user_id = params[:tag][:tag_moderator_id]
@remove_user_id = params[:tag][:remove_moderator_id]
add_moderator if @add_user_id
remove_moderator if @remove_user_id
@tag.update!(tag_params)
def update
@tag = Tag.find(params[:id])
@add_user_id = params[:tag][:tag_moderator_id]
@remove_user_id = params[:tag][:remove_moderator_id]
add_moderator if @add_user_id
remove_moderator if @remove_user_id
@tag.update!(tag_params)
redirect_to "/internal/tags/#{params[:id]}"
end
redirect_to "/internal/tags/#{params[:id]}"
end
private
private
def remove_moderator
user = User.find(@remove_user_id)
user.update(email_tag_mod_newsletter: false)
AssignTagModerator.remove_tag_moderator(user, @tag)
end
def remove_moderator
user = User.find(@remove_user_id)
user.update(email_tag_mod_newsletter: false)
AssignTagModerator.remove_tag_moderator(user, @tag)
end
def add_moderator
User.find(@add_user_id).update(email_tag_mod_newsletter: true)
AssignTagModerator.add_tag_moderators([@add_user_id], [@tag.id])
end
def add_moderator
User.find(@add_user_id).update(email_tag_mod_newsletter: true)
AssignTagModerator.add_tag_moderators([@add_user_id], [@tag.id])
end
def tag_params
allowed_params = %i[
supported rules_markdown short_summary pretty_name bg_color_hex
text_color_hex tag_moderator_id remove_moderator_id alias_for badge_id
category social_preview_template
]
params.require(:tag).permit(allowed_params)
def tag_params
allowed_params = %i[
supported rules_markdown short_summary pretty_name bg_color_hex
text_color_hex tag_moderator_id remove_moderator_id alias_for badge_id
category social_preview_template
]
params.require(:tag).permit(allowed_params)
end
end
end

View file

@ -1,51 +1,53 @@
class Internal::ToolsController < Internal::ApplicationController
layout "internal"
module Internal
class ToolsController < Internal::ApplicationController
layout "internal"
def index; end
def index; end
def bust_cache
flash[:success] = if params[:dead_link]
handle_dead_path
"#{params[:dead_link]} was successfully busted"
elsif params[:bust_user]
handle_user_cache
"User ##{params[:bust_user]} was successfully busted"
elsif params[:bust_article]
handle_article_cache
"Article ##{params[:bust_article]} was successfully busted"
end
redirect_to "/internal/tools"
rescue StandardError => e
flash[:danger] = e.message
redirect_to "/internal/tools"
end
private
def handle_dead_path
bust_link(params[:dead_link])
end
def handle_user_cache
user = User.find(params[:bust_user].to_i)
user.touch(:profile_updated_at, :last_followed_at, :last_comment_at)
bust_link(user.path)
end
def handle_article_cache
article = Article.find(params[:bust_article].to_i)
article.touch(:last_commented_at)
CacheBuster.bust_article(article)
end
def bust_link(link)
if link.starts_with?("https://#{ApplicationConfig['APP_DOMAIN']}")
link.sub!("https://#{ApplicationConfig['APP_DOMAIN']}",
"")
def bust_cache
flash[:success] = if params[:dead_link]
handle_dead_path
"#{params[:dead_link]} was successfully busted"
elsif params[:bust_user]
handle_user_cache
"User ##{params[:bust_user]} was successfully busted"
elsif params[:bust_article]
handle_article_cache
"Article ##{params[:bust_article]} was successfully busted"
end
redirect_to "/internal/tools"
rescue StandardError => e
flash[:danger] = e.message
redirect_to "/internal/tools"
end
private
def handle_dead_path
bust_link(params[:dead_link])
end
def handle_user_cache
user = User.find(params[:bust_user].to_i)
user.touch(:profile_updated_at, :last_followed_at, :last_comment_at)
bust_link(user.path)
end
def handle_article_cache
article = Article.find(params[:bust_article].to_i)
article.touch(:last_commented_at)
CacheBuster.bust_article(article)
end
def bust_link(link)
if link.starts_with?("https://#{ApplicationConfig['APP_DOMAIN']}")
link.sub!("https://#{ApplicationConfig['APP_DOMAIN']}",
"")
end
CacheBuster.bust(link)
CacheBuster.bust("#{link}/")
CacheBuster.bust("#{link}?i=i")
CacheBuster.bust("#{link}/?i=i")
end
CacheBuster.bust(link)
CacheBuster.bust("#{link}/")
CacheBuster.bust("#{link}?i=i")
CacheBuster.bust("#{link}/?i=i")
end
end

View file

@ -1,174 +1,176 @@
class Internal::UsersController < Internal::ApplicationController
layout "internal"
module Internal
class UsersController < Internal::ApplicationController
layout "internal"
after_action only: %i[update user_status banish full_delete merge] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
def index
@users = Internal::UsersQuery.call(
options: params.permit(:role, :search),
).page(params[:page]).per(50)
end
def edit
@user = User.find(params[:id])
@notes = @user.notes.order(created_at: :desc).limit(10).load
end
def show
@user = User.find(params[:id])
@organizations = @user.organizations.order(:name)
@notes = @user.notes.order(created_at: :desc).limit(10)
@organization_memberships = @user.organization_memberships.
joins(:organization).
order("organizations.name ASC").
includes(:organization)
@last_email_verification_date = @user.email_authorizations.
where.not(verified_at: nil).
order("created_at DESC").first&.verified_at || "Never"
end
def update
@user = User.find(params[:id])
manage_credits
add_note if user_params[:new_note]
redirect_to "/internal/users/#{params[:id]}"
end
def user_status
@user = User.find(params[:id])
begin
Moderator::ManageActivityAndRoles.handle_user_roles(admin: current_user, user: @user, user_params: user_params)
flash[:success] = "User has been updated"
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def banish
Moderator::BanishUserWorker.perform_async(current_user.id, params[:id].to_i)
flash[:success] = "This user is being banished in the background. The job will complete soon."
redirect_to "/internal/users/#{params[:id]}/edit"
end
def full_delete
@user = User.find(params[:id])
begin
Moderator::DeleteUser.call(admin: current_user, user: @user, user_params: user_params)
message = "@#{@user.username} (email: #{@user.email.presence || 'no email'}, user_id: #{@user.id}) " \
"has been fully deleted. If requested, old content may have been ghostified. " \
"If this is a GDPR delete, delete them from Mailchimp & Google Analytics."
flash[:success] = message
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users"
end
def merge
@user = User.find(params[:id])
begin
Moderator::MergeUser.call(admin: current_user, keep_user: @user, delete_user_id: user_params["merge_user_id"])
rescue StandardError => e
flash[:danger] = e.message
after_action only: %i[update user_status banish full_delete merge] do
Audit::Logger.log(:moderator, current_user, params.dup)
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def remove_identity
identity = Identity.find(user_params[:identity_id])
@user = identity.user
begin
BackupData.backup!(identity)
identity.delete
@user.update("#{identity.provider}_username" => nil)
flash[:success] = "The #{identity.provider.capitalize} identity was successfully deleted and backed up."
rescue StandardError => e
flash[:danger] = e.message
def index
@users = Internal::UsersQuery.call(
options: params.permit(:role, :search),
).page(params[:page]).per(50)
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def recover_identity
backup = BackupData.find(user_params[:backup_data_id])
@user = backup.instance_user
begin
identity = backup.recover!
flash[:success] = "The #{identity.provider} identity was successfully recovered, and the backup was removed."
rescue StandardError => e
flash[:danger] = e.message
def edit
@user = User.find(params[:id])
@notes = @user.notes.order(created_at: :desc).limit(10).load
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def send_email
if NotifyMailer.with(params).user_contact_email.deliver_now
redirect_back(fallback_location: users_path)
else
flash[:danger] = "Email failed to send!"
def show
@user = User.find(params[:id])
@organizations = @user.organizations.order(:name)
@notes = @user.notes.order(created_at: :desc).limit(10)
@organization_memberships = @user.organization_memberships.
joins(:organization).
order("organizations.name ASC").
includes(:organization)
@last_email_verification_date = @user.email_authorizations.
where.not(verified_at: nil).
order("created_at DESC").first&.verified_at || "Never"
end
end
def verify_email_ownership
if VerificationMailer.with(user_id: params[:user_id]).account_ownership_verification_email.deliver_now
flash[:success] = "Email Verification Mailer sent!"
redirect_back(fallback_location: internal_users_path)
else
flash[:danger] = "Email failed to send!"
def update
@user = User.find(params[:id])
manage_credits
add_note if user_params[:new_note]
redirect_to "/internal/users/#{params[:id]}"
end
end
private
def user_status
@user = User.find(params[:id])
begin
Moderator::ManageActivityAndRoles.handle_user_roles(admin: current_user, user: @user, user_params: user_params)
flash[:success] = "User has been updated"
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def manage_credits
add_credits if user_params[:add_credits]
add_org_credits if user_params[:add_org_credits]
remove_org_credits if user_params[:remove_org_credits]
remove_credits if user_params[:remove_credits]
end
def banish
Moderator::BanishUserWorker.perform_async(current_user.id, params[:id].to_i)
flash[:success] = "This user is being banished in the background. The job will complete soon."
redirect_to "/internal/users/#{params[:id]}/edit"
end
def add_note
Note.create(
author_id: current_user.id,
noteable_id: @user.id,
noteable_type: "User",
reason: "misc_note",
content: user_params[:new_note],
)
end
def full_delete
@user = User.find(params[:id])
begin
Moderator::DeleteUser.call(admin: current_user, user: @user, user_params: user_params)
message = "@#{@user.username} (email: #{@user.email.presence || 'no email'}, user_id: #{@user.id}) " \
"has been fully deleted. If requested, old content may have been ghostified. " \
"If this is a GDPR delete, delete them from Mailchimp & Google Analytics."
flash[:success] = message
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users"
end
def add_credits
amount = user_params[:add_credits].to_i
Credit.add_to(@user, amount)
end
def merge
@user = User.find(params[:id])
begin
Moderator::MergeUser.call(admin: current_user, keep_user: @user, delete_user_id: user_params["merge_user_id"])
rescue StandardError => e
flash[:danger] = e.message
end
def remove_credits
amount = user_params[:remove_credits].to_i
Credit.remove_from(@user, amount)
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def add_org_credits
org = Organization.find(user_params[:organization_id])
amount = user_params[:add_org_credits].to_i
Credit.add_to(org, amount)
end
def remove_identity
identity = Identity.find(user_params[:identity_id])
@user = identity.user
begin
BackupData.backup!(identity)
identity.delete
@user.update("#{identity.provider}_username" => nil)
flash[:success] = "The #{identity.provider.capitalize} identity was successfully deleted and backed up."
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def remove_org_credits
org = Organization.find(user_params[:organization_id])
amount = user_params[:remove_org_credits].to_i
Credit.remove_from(org, amount)
end
def recover_identity
backup = BackupData.find(user_params[:backup_data_id])
@user = backup.instance_user
begin
identity = backup.recover!
flash[:success] = "The #{identity.provider} identity was successfully recovered, and the backup was removed."
rescue StandardError => e
flash[:danger] = e.message
end
redirect_to "/internal/users/#{@user.id}/edit"
end
def user_params
allowed_params = %i[
new_note note_for_current_role user_status
pro merge_user_id add_credits remove_credits
add_org_credits remove_org_credits ghostify
organization_id identity_id backup_data_id
]
params.require(:user).permit(allowed_params)
def send_email
if NotifyMailer.with(params).user_contact_email.deliver_now
redirect_back(fallback_location: users_path)
else
flash[:danger] = "Email failed to send!"
end
end
def verify_email_ownership
if VerificationMailer.with(user_id: params[:user_id]).account_ownership_verification_email.deliver_now
flash[:success] = "Email Verification Mailer sent!"
redirect_back(fallback_location: internal_users_path)
else
flash[:danger] = "Email failed to send!"
end
end
private
def manage_credits
add_credits if user_params[:add_credits]
add_org_credits if user_params[:add_org_credits]
remove_org_credits if user_params[:remove_org_credits]
remove_credits if user_params[:remove_credits]
end
def add_note
Note.create(
author_id: current_user.id,
noteable_id: @user.id,
noteable_type: "User",
reason: "misc_note",
content: user_params[:new_note],
)
end
def add_credits
amount = user_params[:add_credits].to_i
Credit.add_to(@user, amount)
end
def remove_credits
amount = user_params[:remove_credits].to_i
Credit.remove_from(@user, amount)
end
def add_org_credits
org = Organization.find(user_params[:organization_id])
amount = user_params[:add_org_credits].to_i
Credit.add_to(org, amount)
end
def remove_org_credits
org = Organization.find(user_params[:organization_id])
amount = user_params[:remove_org_credits].to_i
Credit.remove_from(org, amount)
end
def user_params
allowed_params = %i[
new_note note_for_current_role user_status
pro merge_user_id add_credits remove_credits
add_org_credits remove_org_credits ghostify
organization_id identity_id backup_data_id
]
params.require(:user).permit(allowed_params)
end
end
end

View file

@ -1,9 +1,11 @@
class Internal::WebhookEndpointsController < Internal::ApplicationController
layout "internal"
module Internal
class WebhookEndpointsController < Internal::ApplicationController
layout "internal"
def index
@endpoints = Webhook::Endpoint.includes(:user).
page(params[:page]).per(50).
order("created_at desc")
def index
@endpoints = Webhook::Endpoint.includes(:user).
page(params[:page]).per(50).
order("created_at desc")
end
end
end

View file

@ -1,34 +1,36 @@
class Internal::WelcomeController < Internal::ApplicationController
layout "internal"
module Internal
class WelcomeController < Internal::ApplicationController
layout "internal"
def index
@daily_threads = Article.where("title LIKE 'Welcome Thread - %'")
end
def index
@daily_threads = Article.where("title LIKE 'Welcome Thread - %'")
end
def create
welcome_thread = Article.create(
body_markdown: welcome_thread_content,
user: User.dev_account,
)
redirect_to URI.parse(welcome_thread.path).path + "/edit"
end
def create
welcome_thread = Article.create(
body_markdown: welcome_thread_content,
user: User.dev_account,
)
redirect_to URI.parse(welcome_thread.path).path + "/edit"
end
private
private
def welcome_thread_content
<<~HEREDOC
---
title: Welcome Thread - v0
published: false
description: Introduce yourself to the community!
tags: welcome
---
def welcome_thread_content
<<~HEREDOC
---
title: Welcome Thread - v0
published: false
description: Introduce yourself to the community!
tags: welcome
---
Hey there! Welcome to #{ApplicationConfig['COMMUNITY_NAME']}!
Hey there! Welcome to #{ApplicationConfig['COMMUNITY_NAME']}!
![WELCOME TO THE INTERNET](https://slack-imgs.com/?c=1&url=http%3A%2F%2Fmedia0.giphy.com%2Fmedia%2FzhbrTTpmSCYog%2Fgiphy-downsized.gif)
![WELCOME TO THE INTERNET](https://slack-imgs.com/?c=1&url=http%3A%2F%2Fmedia0.giphy.com%2Fmedia%2FzhbrTTpmSCYog%2Fgiphy-downsized.gif)
Leave a comment below to introduce yourself to the community!
HEREDOC
Leave a comment below to introduce yourself to the community!
HEREDOC
end
end
end

View file

@ -1,6 +1,8 @@
class Notifications::CountsController < ApplicationController
def index
count = current_user ? current_user.notifications.unread.count : 0
render plain: count.to_s
module Notifications
class CountsController < ApplicationController
def index
count = current_user ? current_user.notifications.unread.count : 0
render plain: count.to_s
end
end
end

View file

@ -1,15 +1,17 @@
class Notifications::ReadsController < ApplicationController
def create
render plain: "" && return unless current_user
module Notifications
class ReadsController < ApplicationController
def create
render plain: "" && return unless current_user
current_user.notifications.unread.update_all(read: true)
current_user.touch(:last_notification_activity)
current_user.notifications.unread.update_all(read: true)
current_user.touch(:last_notification_activity)
if params[:org_id] && current_user.org_member?(params[:org_id])
org = Organization.find_by(id: params[:org_id])
org.notifications.unread.update_all(read: true)
if params[:org_id] && current_user.org_member?(params[:org_id])
org = Organization.find_by(id: params[:org_id])
org.notifications.unread.update_all(read: true)
end
render plain: "read"
end
render plain: "read"
end
end

View file

@ -1,52 +1,54 @@
class Stories::FeedsController < ApplicationController
respond_to :json
module Stories
class FeedsController < ApplicationController
respond_to :json
VARIANTS = {
"more_random_experiment" => :default_home_feed_with_more_randomness_experiment,
"mix_base_more_random_experiment" => :mix_default_and_more_random_experiment,
"more_tag_weight_experiment" => :more_tag_weight_experiment,
"more_tag_weight_more_random_experiment" => :more_tag_weight_more_random_experiment,
"more_comments_experiment" => :more_comments_experiment,
"more_experience_level_weight_experiment" => :more_experience_level_weight_experiment,
"more_tag_weight_randomized_at_end_experiment" => :more_tag_weight_randomized_at_end_experiment,
"more_experience_level_weight_randomized_at_end_experiment" =>
:more_experience_level_weight_randomized_at_end_experiment,
"more_comments_randomized_at_end_experiment" => :more_comments_randomized_at_end_experiment,
"more_comments_medium_weight_randomized_at_end_experiment" =>
:more_comments_medium_weight_randomized_at_end_experiment,
"more_comments_minimal_weight_randomized_at_end_experiment" =>
:more_comments_minimal_weight_randomized_at_end_experiment,
"mix_of_everything_experiment" => :mix_of_everything_experiment
}.freeze
VARIANTS = {
"more_random_experiment" => :default_home_feed_with_more_randomness_experiment,
"mix_base_more_random_experiment" => :mix_default_and_more_random_experiment,
"more_tag_weight_experiment" => :more_tag_weight_experiment,
"more_tag_weight_more_random_experiment" => :more_tag_weight_more_random_experiment,
"more_comments_experiment" => :more_comments_experiment,
"more_experience_level_weight_experiment" => :more_experience_level_weight_experiment,
"more_tag_weight_randomized_at_end_experiment" => :more_tag_weight_randomized_at_end_experiment,
"more_experience_level_weight_randomized_at_end_experiment" =>
:more_experience_level_weight_randomized_at_end_experiment,
"more_comments_randomized_at_end_experiment" => :more_comments_randomized_at_end_experiment,
"more_comments_medium_weight_randomized_at_end_experiment" =>
:more_comments_medium_weight_randomized_at_end_experiment,
"more_comments_minimal_weight_randomized_at_end_experiment" =>
:more_comments_minimal_weight_randomized_at_end_experiment,
"mix_of_everything_experiment" => :mix_of_everything_experiment
}.freeze
def show
@stories = assign_feed_stories
end
def show
@stories = assign_feed_stories
end
private
private
def assign_feed_stories
feed = Articles::Feed.new(user: current_user, page: @page, tag: params[:tag])
stories = if params[:timeframe].in?(Timeframer::FILTER_TIMEFRAMES)
feed.top_articles_by_timeframe(timeframe: params[:timeframe])
elsif params[:timeframe] == Timeframer::LATEST_TIMEFRAME
feed.latest_feed
elsif user_signed_in?
ab_test_user_signed_in_feed(feed)
else
feed.default_home_feed(user_signed_in: user_signed_in?)
end
ArticleDecorator.decorate_collection(stories)
end
def assign_feed_stories
feed = Articles::Feed.new(user: current_user, page: @page, tag: params[:tag])
stories = if params[:timeframe].in?(Timeframer::FILTER_TIMEFRAMES)
feed.top_articles_by_timeframe(timeframe: params[:timeframe])
elsif params[:timeframe] == Timeframer::LATEST_TIMEFRAME
feed.latest_feed
elsif user_signed_in?
ab_test_user_signed_in_feed(feed)
else
feed.default_home_feed(user_signed_in: user_signed_in?)
end
ArticleDecorator.decorate_collection(stories)
end
def ab_test_user_signed_in_feed(feed)
test_variant = field_test(:user_home_feed, participant: current_user)
Honeycomb.add_field("field_test_user_home_feed", test_variant) # Monitoring different variants
def ab_test_user_signed_in_feed(feed)
test_variant = field_test(:user_home_feed, participant: current_user)
Honeycomb.add_field("field_test_user_home_feed", test_variant) # Monitoring different variants
if VARIANTS[test_variant].nil? || test_variant == "base"
feed.default_home_feed(user_signed_in: true)
else
feed.public_send(VARIANTS[test_variant])
if VARIANTS[test_variant].nil? || test_variant == "base"
feed.default_home_feed(user_signed_in: true)
else
feed.public_send(VARIANTS[test_variant])
end
end
end
end

View file

@ -19,6 +19,7 @@ module ApplicationHelper
"#{controller_name}-#{controller.action_name}"
end
# rubocop:disable Rails/HelperInstanceVariable
def view_class
if @podcast_episode_show # custom due to edge cases
"stories stories-show podcast_episodes-show"
@ -28,6 +29,7 @@ module ApplicationHelper
"#{controller_name} #{controller_name}-#{controller.action_name}"
end
end
# rubocop:enable Rails/HelperInstanceVariable
def title(page_title)
derived_title = if page_title.include?(community_name)
@ -164,7 +166,7 @@ module ApplicationHelper
end
def community_name
@community_name ||= ApplicationConfig["COMMUNITY_NAME"]
@community_name ||= ApplicationConfig["COMMUNITY_NAME"] # rubocop:disable Rails/HelperInstanceVariable
end
def community_qualified_name

View file

@ -1,8 +1,10 @@
class Ahoy::Event < ApplicationRecord
include Ahoy::QueryMethods
module Ahoy
class Event < ApplicationRecord
include Ahoy::QueryMethods
self.table_name = "ahoy_events"
self.table_name = "ahoy_events"
belongs_to :visit
belongs_to :user, optional: true
belongs_to :visit
belongs_to :user, optional: true
end
end

View file

@ -1,6 +1,8 @@
class Ahoy::Visit < ApplicationRecord
self.table_name = "ahoy_visits"
module Ahoy
class Visit < ApplicationRecord
self.table_name = "ahoy_visits"
has_many :events, class_name: "Ahoy::Event"
belongs_to :user, optional: true
has_many :events, class_name: "Ahoy::Event"
belongs_to :user, optional: true
end
end

View file

@ -17,7 +17,7 @@ class Role < ApplicationRecord
workshop_pass
].freeze
has_and_belongs_to_many :users, join_table: :users_roles
has_and_belongs_to_many :users, join_table: :users_roles # rubocop:disable Rails/HasAndBelongsToMany
belongs_to :resource,
polymorphic: true, optional: true

View file

@ -1,4 +1,6 @@
class Ahoy::Store < Ahoy::DatabaseStore
module Ahoy
class Store < Ahoy::DatabaseStore
end
end
# set to true to mask ip addresses

View file

@ -1,44 +1,46 @@
Rack::Attack.throttled_response_retry_after_header = true
class Rack::Attack
throttle("search_throttle", limit: 5, period: 1) do |request|
if request.path.starts_with?("/search/")
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
throttle("api_throttle", limit: 3, period: 1) do |request|
if request.path.starts_with?("/api/") && request.get?
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
throttle("api_write_throttle", limit: 1, period: 1) do |request|
if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?)
Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"])
ip_address = track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
if request.env["HTTP_API_KEY"].present?
"#{ip_address}-#{request.env['HTTP_API_KEY']}"
elsif ip_address.present?
ip_address
module Rack
class Attack
throttle("search_throttle", limit: 5, period: 1) do |request|
if request.path.starts_with?("/search/")
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
end
throttle("site_hits", limit: 40, period: 2) do |request|
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
throttle("api_throttle", limit: 3, period: 1) do |request|
if request.path.starts_with?("/api/") && request.get?
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
throttle("message_throttle", limit: 2, period: 1) do |request|
if request.path.starts_with?("/messages") && request.post?
throttle("api_write_throttle", limit: 1, period: 1) do |request|
if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?)
Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"])
ip_address = track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
if request.env["HTTP_API_KEY"].present?
"#{ip_address}-#{request.env['HTTP_API_KEY']}"
elsif ip_address.present?
ip_address
end
end
end
throttle("site_hits", limit: 40, period: 2) do |request|
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
def self.track_and_return_ip(ip_address)
return if ip_address.blank?
throttle("message_throttle", limit: 2, period: 1) do |request|
if request.path.starts_with?("/messages") && request.post?
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
end
end
Honeycomb.add_field("fastly_client_ip", ip_address)
ip_address.to_s
def self.track_and_return_ip(ip_address)
return if ip_address.blank?
Honeycomb.add_field("fastly_client_ip", ip_address)
ip_address.to_s
end
end
end

View file

@ -48,12 +48,18 @@ describe Rack::Attack, type: :request, throttle: true do
describe "api_write_throttle" do
let(:api_secret) { create(:api_secret) }
let(:another_api_secret) { create(:api_secret) }
let(:headers) do
{ "api-key" => api_secret.secret, "content-type" => "application/json", "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
end
let(:dif_headers) do
{
"api-key" => another_api_secret.secret,
"content-type" => "application/json",
"HTTP_FASTLY_CLIENT_IP" => "5.6.7.8"
}
end
it "throttles api write endpoints based on IP and API key" do
headers = { "api-key" => api_secret.secret, "content-type" => "application/json",
"HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
dif_headers = { "api-key" => another_api_secret.secret, "content-type" => "application/json",
"HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
params = { article: { body_markdown: "", title: Faker::Book.title } }.to_json
Timecop.freeze do

View file

@ -5,7 +5,9 @@ RSpec.describe UserSubscriptionTag, type: :liquid_tag do
let(:subscriber) { create(:user) }
let(:author) { create(:user) }
let(:article_with_user_subscription_tag) { create(:article, :with_user_subscription_tag_role_user, with_user_subscription_tag: true) }
let(:article_with_user_subscription_tag) do
create(:article, :with_user_subscription_tag_role_user, with_user_subscription_tag: true)
end
# Stub roles because adding them normally can cause flaky specs
before do
@ -76,6 +78,7 @@ RSpec.describe UserSubscriptionTag, type: :liquid_tag do
end
end
# rubocop:disable RSpec/ExampleLength
it "displays errors when there's an error creating a subscription" do
# Create a subscription so it causes an error by already being subscribed
create(
@ -98,6 +101,7 @@ RSpec.describe UserSubscriptionTag, type: :liquid_tag do
expect(page).to have_text("Subscriber has already been taken")
end
end
# rubocop:enable RSpec/ExampleLength
it "tells the user they're already subscribed by default if they're already subscribed" do
create(

View file

@ -94,7 +94,7 @@ RSpec.describe Article, type: :model do
context "when published" do
before do
# rubocop:disable RSpec/NamedSubject
allow(subject).to receive(:published?).and_return(true)
allow(subject).to receive(:published?).and_return(true) # rubocop:disable RSpec/SubjectStub
# rubocop:enable RSpec/NamedSubject
end

View file

@ -122,6 +122,7 @@ RSpec.describe Comment, type: :model do
expect(comment.processed_html.size < 450).to be(true)
end
# rubocop:disable RSpec/ExampleLength
it "adds timestamp url if commentable has video and timestamp", :aggregate_failures do
article.video = "https://example.com"
@ -146,6 +147,7 @@ RSpec.describe Comment, type: :model do
expect(comment.processed_html.include?(">1:52:30</a>")).to eq(true)
expect(comment.processed_html.include?(">1:20</a>")).to eq(true)
end
# rubocop:enable RSpec/ExampleLength
it "does not add timestamp if commentable does not have video" do
article.video = nil

View file

@ -34,22 +34,14 @@ RSpec.describe "DisplayAdEvents", type: :request do
end
it "creates a display ad success rate" do
ad_event_params = { display_ad_id: display_ad.id, context_type: "home" }
4.times do
post "/display_ad_events", params: {
display_ad_event: {
display_ad_id: display_ad.id,
context_type: "home",
category: "impression"
}
}
post "/display_ad_events", params: { display_ad_event: ad_event_params.merge(category: "impression") }
end
post "/display_ad_events", params: {
display_ad_event: {
display_ad_id: display_ad.id,
context_type: "home",
category: "click"
}
}
post "/display_ad_events", params: { display_ad_event: ad_event_params.merge(category: "click") }
expect(display_ad.reload.success_rate).to eq(0.25)
end

View file

@ -204,14 +204,18 @@ RSpec.describe "/internal/config", type: :request do
end
it "updates left_navbar_svg_icon" do
expected_svg = "<svg height='100' width='100'><circle cx='50' cy='50' r='40' stroke='black' stroke-width='3'/></svg>"
post "/internal/config", params: { site_config: { left_navbar_svg_icon: expected_svg }, confirmation: confirmation_message }
expected_svg = "<svg height='100' width='100'><circle cx='50' cy='50' r='40' " \
"stroke='black' stroke-width='3'/></svg>"
post "/internal/config", params: { site_config: { left_navbar_svg_icon: expected_svg },
confirmation: confirmation_message }
expect(SiteConfig.left_navbar_svg_icon).to eq(expected_svg)
end
it "updates right_navbar_svg_icon" do
expected_svg = "<svg height='100' width='100'><circle cx='50' cy='50' r='40' stroke='black' stroke-width='1'/></svg>"
post "/internal/config", params: { site_config: { right_navbar_svg_icon: expected_svg }, confirmation: confirmation_message }
expected_svg = "<svg height='100' width='100'><circle cx='50' cy='50' r='40' " \
"stroke='black' stroke-width='1'/></svg>"
post "/internal/config", params: { site_config: { right_navbar_svg_icon: expected_svg },
confirmation: confirmation_message }
expect(SiteConfig.right_navbar_svg_icon).to eq(expected_svg)
end