Rubocop: fix additional violations in todo file (#9218)
This commit is contained in:
parent
f37ffc0be9
commit
ffc96db209
48 changed files with 1585 additions and 1526 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
class Internal::GrowthController < Internal::ApplicationController
|
||||
layout "internal"
|
||||
module Internal
|
||||
class GrowthController < Internal::ApplicationController
|
||||
layout "internal"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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']}!
|
||||
|
||||

|
||||

|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
class Ahoy::Store < Ahoy::DatabaseStore
|
||||
module Ahoy
|
||||
class Store < Ahoy::DatabaseStore
|
||||
end
|
||||
end
|
||||
|
||||
# set to true to mask ip addresses
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue