docbrown/app/controllers/concerns/listings_toolkit.rb
Rafi d570edcf07
Showing date in listing tile (#10217)
* Showing date in listing tile

* Displaying date in listing tile

1. Sending created_at in listing search API
2. Global util functions for short and long date formatting
3. New date util functions extend timestampToLocalDateTime
4. Converting div to time tag
5. Adding title attribute for date

* originally_published_at column

* Displaying originally_published_at date

* Fixing test in modal

* Fixing all listing test

* Fixing casing of dateTime

* Adding tests for originally_published_at

* Reverting to bumped_at

* Backfilling only published listing

* Removing ReIndexListingWithOriginallyPublishedAt
2020-09-21 10:14:26 +02:00

204 lines
5.4 KiB
Ruby

module ListingsToolkit
extend ActiveSupport::Concern
MANDATORY_FIELDS_FOR_UPDATE = %i[body_markdown title tag_list].freeze
def unpublish_listing
@listing.update(published: false)
end
def publish_listing
@listing.update(published: true)
end
def update_listing_details
# [@forem/oss] Not entirely sure what the intention behind the
# original code was, but at least this is more compact.
filtered_params = listing_params.reject { |_k, v| v.nil? }
@listing.update(filtered_params)
end
def bump_listing_success
@listing.update(bumped_at: Time.current)
end
def clear_listings_cache
Listings::BustCacheWorker.perform_async(@listing.id)
end
def set_listing
@listing = Listing.find(params[:id])
end
def create
@listing = Listing.new(listing_params)
# this will 401 for now if they don't belong in the org
authorize @listing, :authorized_organization_poster? if @listing.organization_id.present?
@listing.user_id = current_user.id
org = Organization.find_by(id: @listing.organization_id)
if listing_params[:action] == "draft"
create_draft
return
end
unless @listing.valid?
@credits = current_user.credits.unspent
process_unsuccessful_creation
return
end
cost = @listing.cost
# we use the org's credits if available, otherwise we default to the user's
if org&.enough_credits?(cost)
create_listing(org, cost)
elsif current_user.enough_credits?(cost)
create_listing(current_user, cost)
else
process_no_credit_left
end
end
ALLOWED_PARAMS = %i[
title body_markdown listing_category_id tag_list
expires_at contact_via_connect location organization_id action
].freeze
# Filter for a set of known safe params
def listing_params
tags = params["listing"].delete("tags")
if tags.present?
params["listing"]["tag_list"] = tags.join(", ")
end
params.require(:listing).permit(ALLOWED_PARAMS)
end
def create_draft
@listing.published = false
if @listing.save
process_successful_draft
else
@credits = current_user.credits.unspent
@listing.cached_tag_list = listing_params[:tag_list]
@organizations = current_user.organizations
process_unsuccessful_draft
end
end
def create_listing(purchaser, cost)
successful_transaction = false
ActiveRecord::Base.transaction do
# subtract credits
Credits::Buyer.call(
purchaser: purchaser,
purchase: @listing,
cost: cost,
)
# save the listing
@listing.bumped_at = Time.current
@listing.published = true
@listing.originally_published_at = Time.current
# since we can't raise active record errors in this transaction
# due to the fact that we need to display them in the :new view,
# we manually rollback the transaction if there are validation errors
raise ActiveRecord::Rollback unless @listing.save
successful_transaction = true
end
if successful_transaction
rate_limiter.track_limit_by_action(:listing_creation)
clear_listings_cache
process_successful_creation
else
@credits = current_user.credits.unspent
@listing.cached_tag_list = listing_params[:tag_list]
@organizations = current_user.organizations
process_unsuccessful_creation
end
end
def update
authorize @listing
cost = @listing.cost
# NOTE: this should probably be split in three different actions: bump, unpublish, publish
return bump_listing(cost) if listing_params[:action] == "bump"
if listing_params[:action] == "unpublish"
unpublish_listing
process_after_unpublish
return
elsif listing_params[:action] == "publish"
unless @listing.bumped_at?
first_publish(cost)
return
end
publish_listing
elsif listing_updatable?
saved = update_listing_details
return process_unsuccessful_update unless saved
end
clear_listings_cache
process_after_update
end
def bump_listing(cost)
org = Organization.find_by(id: @listing.organization_id)
if org&.enough_credits?(cost)
charge_credits_before_bump(org, cost)
elsif current_user.enough_credits?(cost)
charge_credits_before_bump(current_user, cost)
else
process_no_credit_left && return
end
end
def charge_credits_before_bump(purchaser, cost)
ActiveRecord::Base.transaction do
Credits::Buyer.call(
purchaser: purchaser,
purchase: @listing,
cost: cost,
)
raise ActiveRecord::Rollback unless bump_listing_success
end
end
def first_publish(cost)
available_author_credits = @listing.author.credits.unspent
available_user_credits = []
if @listing.author.is_a?(Organization)
available_user_credits = current_user.credits.unspent
end
if available_author_credits.size >= cost
create_listing(@listing.author, cost)
elsif available_user_credits.size >= cost
create_listing(current_user, cost)
else
process_no_credit_left
end
end
def listing_updatable?
at_least_one_param_present? && (bumped_in_last_24_hrs? || !@listing.published)
end
def at_least_one_param_present?
MANDATORY_FIELDS_FOR_UPDATE.any? { |i| listing_params.include? i }
end
def bumped_in_last_24_hrs?
@listing.bumped_at && @listing.bumped_at > 24.hours.ago
end
end