<%= form.check_box :published, checked: @classified_listing.published? %>
@@ -28,7 +28,7 @@
<% end %>
- <%= form_for [:internal, @classified_listing] do |f| %>
+ <%= form_with model: [:internal, @classified_listing], method: :patch do |f| %>
<%= f.submit "Bump Listing ⏫", class: "btn btn-secondary" %>
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index 83a17916b..b515c2496 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -47,11 +47,12 @@ Rails.application.routes.draw do
resources :articles, only: %i[index show update]
resources :broadcasts, only: %i[index new create edit update]
resources :buffer_updates, only: %i[create update]
+ # TODO: [mkohl] Change this to a single resource definition
resources :classified_listings, only: %i[index edit update destroy]
+ resources :listings, only: %i[index edit update destroy], controller: "classified_listings"
resources :comments, only: [:index]
resources :events, only: %i[index create update]
resources :feedback_messages, only: %i[index show]
- resources :listings, only: %i[index edit update destroy], controller: "classified_listings"
resources :pages, only: %i[index new create edit update destroy]
resources :mods, only: %i[index update]
resources :moderator_actions, only: %i[index]
diff --git a/db/seeds.rb b/db/seeds.rb
index 691f95e6c..31547c213 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -418,7 +418,54 @@ end
##############################################################################
-puts <<-ASCII # rubocop:disable Rails/Output
+counter += 1
+Rails.logger.info "#{counter}. Creating Classified Listing Categories"
+
+CATEGORIES = [
+ {
+ slug: "cfp",
+ cost: 1,
+ name: "Conference CFP",
+ rules: "Currently open for proposals,with link to form."
+ },
+ {
+ slug: "education",
+ cost: 1,
+ name: "Education/Courses",
+ rules: "Educational material and/or schools/bootcamps."
+ },
+ {
+ slug: "jobs",
+ cost: 25,
+ name: "Job Listings",
+ rules: "Companies offering employment right now."
+ },
+ {
+ slug: "forsale",
+ cost: 1,
+ name: "Stuff for Sale",
+ rules: "Personally owned physical items for sale."
+ },
+ {
+ slug: "events",
+ cost: 1,
+ name: "Upcoming Events",
+ rules: "In-person or online events with date included."
+ },
+ {
+ slug: "misc",
+ cost: 1,
+ name: "Miscellaneous",
+ rules: "Must not fit in any other category."
+ }
+].freeze
+
+CATEGORIES.each { |attributes| ClassifiedListingCategory.create(attributes) }
+
+##############################################################################
+
+# rubocop:disable Rails/Output
+puts <<-ASCII
@@ -447,3 +494,4 @@ puts <<-ASCII # rubocop:disable Rails/Output
All done!
ASCII
+# rubocop:enable Rails/Output
diff --git a/spec/factories/classified_listing_categories.rb b/spec/factories/classified_listing_categories.rb
index 1b3268414..f2a087659 100644
--- a/spec/factories/classified_listing_categories.rb
+++ b/spec/factories/classified_listing_categories.rb
@@ -7,6 +7,8 @@ FactoryBot.define do
trait :cfp do
name { "Conference CFP" }
+ slug { "cfp" }
+ cost { 5 }
end
end
end
diff --git a/spec/factories/classified_listings.rb b/spec/factories/classified_listings.rb
index 0f3c1f10d..0df205968 100644
--- a/spec/factories/classified_listings.rb
+++ b/spec/factories/classified_listings.rb
@@ -3,8 +3,14 @@ FactoryBot.define do
user
title { Faker::Book.title + " #{rand(1000)}" }
body_markdown { Faker::Hipster.paragraph(sentence_count: 2) }
- category { "education" }
published { true }
bumped_at { Time.current }
+
+ after(:build) do |cl|
+ if cl.classified_listing_category_id.blank?
+ category = ClassifiedListingCategory.first || create(:classified_listing_category)
+ cl.classified_listing_category_id = category.id
+ end
+ end
end
end
diff --git a/spec/models/classified_listing_spec.rb b/spec/models/classified_listing_spec.rb
index 1e6b1be8d..74556d638 100644
--- a/spec/models/classified_listing_spec.rb
+++ b/spec/models/classified_listing_spec.rb
@@ -32,18 +32,6 @@ RSpec.describe ClassifiedListing, type: :model do
end
end
- # TODO: remove this once we are live with the new ClassifiedListingCategory model
- describe "classified listing category" do
- it "automatically assigns a category on save" do
- create(:classified_listing_category)
-
- cl = build(:classified_listing, user_id: user.id)
- cl.save
- expect(cl).to be_valid
- expect(cl.reload.classified_listing_category).to be_present
- end
- end
-
describe "body html" do
it "converts markdown to html" do
expect(classified_listing.processed_html).to include("
")
@@ -100,15 +88,5 @@ RSpec.describe ClassifiedListing, type: :model do
end
end
end
-
- describe ".cost_by_category" do
- it "returns the cost per category" do
- expected_cost = described_class::CATEGORIES_AVAILABLE.dig("cfp", "cost")
- expect(described_class.cost_by_category("cfp")).to eq(expected_cost)
- end
-
- it "returns 0 with invalid category" do
- expect(described_class.cost_by_category("invalid")).to eq(0)
- end
- end
end
+
diff --git a/spec/requests/api/v0/classified_listings_spec.rb b/spec/requests/api/v0/classified_listings_spec.rb
index 71c252d28..e03ac2ce1 100644
--- a/spec/requests/api/v0/classified_listings_spec.rb
+++ b/spec/requests/api/v0/classified_listings_spec.rb
@@ -1,6 +1,13 @@
require "rails_helper"
RSpec.describe "Api::V0::ClassifiedListings", type: :request do
+ let_it_be_readonly(:cfp_category) do
+ create(:classified_listing_category, :cfp)
+ end
+ let_it_be_readonly(:edu_category) do
+ create(:classified_listing_category)
+ end
+
shared_context "when user is authorized" do
let(:api_secret) { create(:api_secret) }
let(:user) { api_secret.user }
@@ -12,14 +19,14 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
{
title: "Title",
body_markdown: "Markdown text",
- category: "cfp"
+ classified_listing_category_id: cfp_category.id
}
end
let(:draft_params) do
{
title: "Title draft",
body_markdown: "Markdown draft text",
- category: "cfp",
+ classified_listing_category_id: cfp_category.id,
action: "draft"
}
end
@@ -36,8 +43,8 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
let(:user2) { create(:user) }
before do
- create_list(:classified_listing, 3, user: user1, category: "cfp")
- create_list(:classified_listing, 4, user: user2)
+ create_list(:classified_listing, 3, user: user1, classified_listing_category_id: cfp_category.id)
+ create_list(:classified_listing, 4, user: user2, classified_listing_category_id: edu_category.id)
end
end
@@ -239,21 +246,31 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
describe "user must have enough credit to create a classified listing" do
include_context "when user is authorized"
+ include_context "when param list is valid"
it "fails to create a classified listing if user does not have enough credit" do
- post_classified_listing(category: "cfp")
+ post_classified_listing(listing_params)
expect(response).to have_http_status(:payment_required)
end
it "fails to create a classifiedlisting if the org does not have enough credit" do
org = user_admin_organization(user)
- post_classified_listing(category: "cfp", organization_id: org.id)
+ post_classified_listing(
+ **listing_params,
+ organization_id: org.id,
+ )
expect(response).to have_http_status(:payment_required)
end
end
describe "user cannot create a classified with a request lacking mandatory parameters" do
- let(:invalid_params) { { title: "Title", category: "cfp" } }
+ let(:invalid_params) do
+ {
+ title: "Title",
+ category: "cfp",
+ classified_listing_category_id: cfp_category.id
+ }
+ end
include_context "when user is authorized"
include_context "when user has enough credit"
@@ -338,15 +355,9 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "cannot create a draft due to internal error" do
- listing = create(:classified_listing, user_id: user.id)
- allow(ClassifiedListing).to receive_messages(cost_by_category: nil, new: listing)
allow(Organization).to receive(:find_by)
- allow(listing).to receive(:save) do
- listing.errors.add(:base)
- false
- end
- post_classified_listing(draft_params)
- expect(response.parsed_body["errors"]["base"]).to eq(["is invalid"])
+ post_classified_listing(draft_params.except(:classified_listing_category_id))
+ expect(response.parsed_body["errors"]["category"]).to eq(["not a valid category"])
expect(response).to have_http_status(:unprocessable_entity)
end
@@ -384,7 +395,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
expect(listing.title).to eq(listing_params[:title])
expect(listing.body_markdown).to eq(listing_params[:body_markdown])
- expect(listing.category).to eq(listing_params[:category])
+ expect(listing.category).to eq(cfp_category.slug)
end
it "creates a classified listing with a location" do
@@ -491,7 +502,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "bumps the listing and subtract credits" do
- cost = ClassifiedListing.cost_by_category(listing.category)
+ cost = listing.cost
create_list(:credit, cost, user: user)
previous_bumped_at = listing.bumped_at
expect do
@@ -501,7 +512,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "bumps the org listing using org credits before user credits" do
- cost = ClassifiedListing.cost_by_category(org_listing.category)
+ cost = org_listing.cost
create_list(:credit, cost, organization: organization)
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
@@ -512,7 +523,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "bumps the org listing using user credits if org credits insufficient and user credits are" do
- cost = ClassifiedListing.cost_by_category(org_listing.category)
+ cost = org_listing.cost
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
expect do
@@ -526,7 +537,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
include_context "when user is authorized"
it "publishes a draft and charges user credits if first publish" do
- cost = ClassifiedListing.cost_by_category(listing_draft.category)
+ cost = listing_draft.cost
create_list(:credit, cost, user: user)
expect do
put_classified_listing(listing_draft.id, action: "publish")
@@ -534,14 +545,14 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "publishes a draft and ensures published column is true" do
- cost = ClassifiedListing.cost_by_category(listing_draft.category)
+ cost = listing_draft.cost
create_list(:credit, cost, user: user)
put_classified_listing(listing_draft.id, action: "publish")
expect(listing_draft.reload.published).to eq(true)
end
it "publishes an org draft and charges org credits if first publish" do
- cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
+ cost = org_listing_draft.cost
create_list(:credit, cost, organization: organization)
expect do
put_classified_listing(org_listing_draft.id, action: "publish")
@@ -549,7 +560,7 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "publishes an org draft and ensures published column is true" do
- cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
+ cost = org_listing_draft.cost
create_list(:credit, cost, organization: organization)
put_classified_listing(org_listing_draft.id, action: "publish")
expect(org_listing_draft.reload.published).to eq(true)
@@ -594,7 +605,8 @@ RSpec.describe "Api::V0::ClassifiedListings", type: :request do
end
it "fails if category is invalid" do
- put_classified_listing(listing.id, title: "New title", category: "unknown")
+ max_id = ClassifiedListingCategory.maximum(:id)
+ put_classified_listing(listing.id, title: "New title", classified_listing_category_id: max_id + 1)
expect(response).to have_http_status(:unprocessable_entity)
expect(response.parsed_body.dig("errors", "category").first).to match(/not a valid category/)
end
diff --git a/spec/requests/classified_listings_spec.rb b/spec/requests/classified_listings_spec.rb
index a53db700d..aa381c991 100644
--- a/spec/requests/classified_listings_spec.rb
+++ b/spec/requests/classified_listings_spec.rb
@@ -1,13 +1,16 @@
require "rails_helper"
RSpec.describe "ClassifiedListings", type: :request do
+ let_it_be_readonly(:edu_category) do
+ create(:classified_listing_category, cost: 1)
+ end
let(:user) { create(:user) }
let(:listing_params) do
{
classified_listing: {
title: "something",
body_markdown: "something else",
- category: "cfp",
+ classified_listing_category_id: edu_category.id,
tag_list: "",
contact_via_connect: true
}
@@ -18,7 +21,7 @@ RSpec.describe "ClassifiedListings", type: :request do
classified_listing: {
title: "this a draft",
body_markdown: "something draft",
- category: "cfp",
+ classified_listing_category_id: edu_category.id,
tag_list: "",
contact_via_connect: true,
action: "draft"
@@ -144,13 +147,15 @@ RSpec.describe "ClassifiedListings", type: :request do
create_list(:credit, 25, user: user)
end
+ let_it_be_readonly(:cfp_category) { create(:classified_listing_category, :cfp) }
+
context "when the listing is invalid" do
let(:invalid_params) do
{
classified_listing: {
title: "nothing",
body_markdown: "",
- category: "cfp",
+ classified_listing_category_id: cfp_category.id,
tag_list: ""
}
}
@@ -195,9 +200,9 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "properly deducts the amount of credits" do
- post "/listings", params: listing_params
- listing_cost = ClassifiedListing.categories_available[:cfp][:cost]
- expect(user.credits.spent.size).to eq(listing_cost)
+ expect do
+ post "/listings", params: listing_params
+ end.to change { user.credits.spent.size }.by(edu_category.cost)
end
it "creates a listing draft under the org" do
@@ -305,7 +310,7 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "bumps the listing and subtract credits" do
- cost = ClassifiedListing.cost_by_category(listing.category)
+ cost = listing.cost
create_list(:credit, cost, user: user)
previous_bumped_at = listing.bumped_at
expect do
@@ -315,7 +320,7 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "bumps the org listing using org credits before user credits" do
- cost = ClassifiedListing.cost_by_category(org_listing.category)
+ cost = org_listing.cost
create_list(:credit, cost, organization: organization)
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
@@ -326,7 +331,7 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "bumps the org listing using user credits if org credits insufficient and user credits are" do
- cost = ClassifiedListing.cost_by_category(org_listing.category)
+ cost = org_listing.cost
create_list(:credit, cost, user: user)
previous_bumped_at = org_listing.bumped_at
expect do
@@ -340,7 +345,7 @@ RSpec.describe "ClassifiedListings", type: :request do
let(:params) { { classified_listing: { action: "publish" } } }
it "publishes a draft and charges user credits if first publish" do
- cost = ClassifiedListing.cost_by_category(listing_draft.category)
+ cost = listing_draft.cost
create_list(:credit, cost, user: user)
expect do
put "/listings/#{listing_draft.id}", params: params
@@ -348,14 +353,14 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "publishes a draft and ensures published column is true" do
- cost = ClassifiedListing.cost_by_category(listing_draft.category)
+ cost = listing_draft.cost
create_list(:credit, cost, user: user)
put "/listings/#{listing_draft.id}", params: params
expect(listing_draft.reload.published).to eq(true)
end
it "publishes an org draft and charges org credits if first publish" do
- cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
+ cost = org_listing_draft.cost
create_list(:credit, cost, organization: organization)
expect do
put "/listings/#{org_listing_draft.id}", params: params
@@ -363,7 +368,7 @@ RSpec.describe "ClassifiedListings", type: :request do
end
it "publishes an org draft and ensures published column is true" do
- cost = ClassifiedListing.cost_by_category(org_listing_draft.category)
+ cost = org_listing_draft.cost
create_list(:credit, cost, organization: organization)
put "/listings/#{org_listing_draft.id}", params: params
expect(org_listing_draft.reload.published).to eq(true)
diff --git a/spec/requests/listings_spec.rb b/spec/requests/listings_spec.rb
index cb9502b17..4efb9beeb 100644
--- a/spec/requests/listings_spec.rb
+++ b/spec/requests/listings_spec.rb
@@ -3,8 +3,20 @@ require "rails_helper"
RSpec.describe "/listings", type: :request do
let(:user) { create(:user) }
let(:organization) { create(:organization) }
+ let(:cl_category) { create(:classified_listing_category, cost: 1) }
- describe "GETS /listings" do
+ let(:params) do
+ {
+ classified_listing: {
+ title: "Hey",
+ classified_listing_category_id: cl_category.id,
+ body_markdown: "hey hey my my",
+ tag_list: "ruby, rails, go"
+ }
+ }
+ end
+
+ describe "GET /listings" do
it "has page content" do
get "/listings"
expect(response.body).to include("classified-filters")
@@ -30,63 +42,51 @@ RSpec.describe "/listings", type: :request do
end
it "creates proper listing if credits are available" do
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my" }
- }
+ post "/listings", params: params
expect(ClassifiedListing.last.processed_html).to include("hey my")
end
it "spends credits" do
num_credits = Credit.where(spent: true).size
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my" }
- }
+ post "/listings", params: params
expect(Credit.where(spent: true).size).to be > num_credits
end
it "adds tags" do
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my", tag_list: "ruby, rails, go" }
- }
+ post "/listings", params: params
expect(ClassifiedListing.last.cached_tag_list).to include("rails")
end
it "creates the listing under the user" do
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my", tag_list: "ruby, rails, go" }
- }
+ post "/listings", params: params
expect(ClassifiedListing.last.user_id).to eq user.id
end
it "creates the listing for the user if no organization_id is selected" do
create(:organization_membership, user_id: user.id, organization_id: organization.id)
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my", tag_list: "ruby, rails, go" }
- }
+ post "/listings", params: params
expect(ClassifiedListing.last.organization_id).to eq nil
expect(ClassifiedListing.last.user_id).to eq user.id
end
it "creates the listing for the organization" do
create(:organization_membership, user_id: user.id, organization_id: organization.id)
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my", tag_list: "ruby, rails, go", organization_id: organization.id }
- }
+ params[:classified_listing][:organization_id] = organization.id
+ post "/listings", params: params
expect(ClassifiedListing.last.organization_id).to eq(organization.id)
end
it "does not create an org listing if a different org member doesn't belong to the org" do
another_org = create(:organization)
create(:organization_membership, user_id: user.id, organization_id: another_org.id)
+ params[:classified_listing][:organization_id] = organization.id
expect do
- post "/listings", params: {
- classified_listing: { title: "Hey", category: "education", body_markdown: "hey hey my my", tag_list: "ruby, rails, go", organization_id: organization.id }
- }
+ post "/listings", params: params
end.to raise_error Pundit::NotAuthorizedError
end
end
- describe "GETS /listings/edit" do
+ describe "GET /listings/edit" do
let(:classified_listing) { create(:classified_listing, user_id: user.id) }
before do
diff --git a/spec/requests/social_previews_spec.rb b/spec/requests/social_previews_spec.rb
index d0cf79226..df26b61b1 100644
--- a/spec/requests/social_previews_spec.rb
+++ b/spec/requests/social_previews_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe "SocialPreviews", type: :request do
let(:article) { create(:article, user_id: user.id, tags: tag.name) }
let(:comment) { create(:comment, user_id: user.id, commentable: article) }
let(:image_url) { "https://hcti.io/v1/image/6c52de9d-4d37-4008-80f8-67155589e1a1" }
- let(:listing) { create(:classified_listing, user_id: user.id, category: "cfp") }
before do
stub_request(:post, /hcti.io/).
@@ -136,9 +135,11 @@ RSpec.describe "SocialPreviews", type: :request do
end
describe "GET /social_previews/listing/:id" do
+ let(:listing) { create(:classified_listing, user_id: user.id) }
+
it "renders pretty category name" do
get "/social_previews/listing/#{listing.id}"
- expect(response.body).to include CGI.escapeHTML("Call For Proposal")
+ expect(response.body).to include CGI.escapeHTML("Education")
end
it "renders consistent HTML between requests" do
diff --git a/spec/services/search/classified_listing_spec.rb b/spec/services/search/classified_listing_spec.rb
index fe41c2440..50904d4b3 100644
--- a/spec/services/search/classified_listing_spec.rb
+++ b/spec/services/search/classified_listing_spec.rb
@@ -31,9 +31,10 @@ RSpec.describe Search::ClassifiedListing, type: :service, elasticsearch: true do
context "with a term filter" do
it "searches by category" do
- classified_listing.update(category: "forhire")
+ new_category = create(:classified_listing_category, :cfp)
+ classified_listing.update(classified_listing_category_id: new_category.id)
index_documents(classified_listing)
- params = { size: 5, category: "forhire" }
+ params = { size: 5, category: new_category.slug }
classified_listing_docs = described_class.search_documents(params: params)
expect(classified_listing_docs.count).to eq(1)
@@ -121,8 +122,9 @@ RSpec.describe Search::ClassifiedListing, type: :service, elasticsearch: true do
end
it "sorts documents for a given field" do
- classified_listing.update(category: "forhire")
- classified_listing2 = FactoryBot.create(:classified_listing, category: "cfp")
+ classified_listing = create(:classified_listing)
+ cfp = create(:classified_listing_category, :cfp)
+ classified_listing2 = create(:classified_listing, classified_listing_category_id: cfp.id)
index_documents([classified_listing, classified_listing2])
params = { size: 5, sort_by: "category", sort_direction: "asc" }