diff --git a/app/controllers/admin/listing_categories_controller.rb b/app/controllers/admin/listing_categories_controller.rb new file mode 100644 index 000000000..33040a5f0 --- /dev/null +++ b/app/controllers/admin/listing_categories_controller.rb @@ -0,0 +1,69 @@ +module Admin + class ListingCategoriesController < Admin::ApplicationController + include ListingsToolkit + layout "admin" + + def index + @listing_categories = ListingCategory.order(id: :desc) + .page(params[:page]).per(50) + + return if params[:search].blank? + + @listing_categories = @listing_categories.where("name ILIKE :search", search: "%#{params[:search]}%") + end + + def new + @listing_category = ListingCategory.new + end + + def edit + @listing_category = ListingCategory.find(params[:id]) + end + + def create + @listing_category = ListingCategory.new(listing_category_params) + + if @listing_category.save + flash[:success] = "Listing Category has been created!" + redirect_to admin_listing_categories_path + else + flash[:danger] = @listing_category.errors_as_sentence + render new_admin_listing_category_path + end + end + + def update + @listing_category = ListingCategory.find(params[:id]) + + if @listing_category.update(listing_category_params) + flash[:success] = "Listing Category has been updated!" + redirect_to admin_listing_categories_path + else + flash[:danger] = @listing_category.errors_as_sentence + render :edit + end + end + + def destroy + @listing_category = ListingCategory.find(params[:id]) + + if @listing_category.destroy + flash[:success] = "Listing Category has been deleted!" + redirect_to admin_listing_categories_path + else + flash[:danger] = @listing_category.errors.full_messages.to_sentence + render :edit + end + end + + private + + def listing_category_params + params.permit(:name, :cost, :rules, :slug, :social_preview_color, :social_preview_description) + end + + def authorize_admin + authorize ListingCategory, :access?, policy_class: InternalPolicy + end + end +end diff --git a/app/lib/constants/role.rb b/app/lib/constants/role.rb index 07aba0d99..3a2f3dc0b 100644 --- a/app/lib/constants/role.rb +++ b/app/lib/constants/role.rb @@ -18,6 +18,7 @@ module Constants "Resource Admin: Config", "Resource Admin: Broadcast", "Resource Admin: HtmlVariant", - "Resource Admin: DisplayAd"].freeze + "Resource Admin: DisplayAd", + "Resource Admin: ListingCategory"].freeze end end diff --git a/app/models/listing_category.rb b/app/models/listing_category.rb index 14d0cfb74..0670cf909 100644 --- a/app/models/listing_category.rb +++ b/app/models/listing_category.rb @@ -1,4 +1,6 @@ class ListingCategory < ApplicationRecord + resourcify + # We used to use both "classified listing" and "listing" throughout the app. # We standardized on the latter, but keeping the table name was easier. self.table_name = "classified_listing_categories" diff --git a/app/views/admin/listing_categories/_form.html.erb b/app/views/admin/listing_categories/_form.html.erb new file mode 100644 index 000000000..5cd87aa92 --- /dev/null +++ b/app/views/admin/listing_categories/_form.html.erb @@ -0,0 +1,29 @@ +
+ <%= label_tag :name, "Name" %> + <%= text_field_tag :name, @listing_category.name, class: "form-control" %> +
+ +
+ <%= label_tag :cost, "Cost" %> + <%= number_field_tag :cost, @listing_category.cost, class: "form-control" %> +
+ +
+ <%= label_tag :rules, "Rules" %> + <%= text_field_tag :rules, @listing_category.rules, class: "form-control" %> +
+ +
+ <%= label_tag :slug, "Slug" %> + <%= text_field_tag :slug, @listing_category.slug, class: "form-control" %> +
+ +
+ <%= label_tag :social_preview_color, "Color hex" %> + <%= text_field_tag :social_preview_color, @listing_category.social_preview_color, class: "form-control" %> +
+ +
+ <%= label_tag :social_preview_description, "Description" %> + <%= text_area_tag :social_preview_description, @listing_category.social_preview_description, size: "100x10", class: "form-control" %> +
diff --git a/app/views/admin/listing_categories/edit.html.erb b/app/views/admin/listing_categories/edit.html.erb new file mode 100644 index 000000000..0c245a81c --- /dev/null +++ b/app/views/admin/listing_categories/edit.html.erb @@ -0,0 +1,7 @@ +

Edit Listing Category:

+
+ <%= form_for([:admin, @listing_category], method: :patch) do %> + <%= render "form" %> + <%= submit_tag "Update Listing Category", class: "btn btn-primary" %> + <% end %> +
diff --git a/app/views/admin/listing_categories/index.html.erb b/app/views/admin/listing_categories/index.html.erb new file mode 100644 index 000000000..834802656 --- /dev/null +++ b/app/views/admin/listing_categories/index.html.erb @@ -0,0 +1,43 @@ + + +<%= paginate @listing_categories %> + + + + + + + + + + + + + + + <% @listing_categories.each do |category| %> + + + + + + + + + + + + <% end %> + +
IDNameCostRulesSlugColorDescription
<%= link_to category.id, edit_admin_listing_category_path(category) %><%= category.name %><%= category.cost %><%= category.rules %><%= category.slug %><%= category.social_preview_color %><%= category.social_preview_description %><%= link_to "Edit", edit_admin_listing_category_path(category), class: "crayons-btn" %><%= link_to "Destroy", admin_listing_category_path(category), class: "crayons-btn crayons-btn--danger", method: :delete, data: { confirm: "Are you sure?" } %>
+ +<%= paginate @listing_categories %> diff --git a/app/views/admin/listing_categories/new.html.erb b/app/views/admin/listing_categories/new.html.erb new file mode 100644 index 000000000..4ad040cbb --- /dev/null +++ b/app/views/admin/listing_categories/new.html.erb @@ -0,0 +1,7 @@ +

Make a new Listing Category:

+
+ <%= form_for([:admin, @listing_category], method: :post) do %> + <%= render "form" %> + <%= submit_tag "Create Listing Category", class: "btn btn-primary" %> + <% end %> +
diff --git a/app/views/admin/listings/index.html.erb b/app/views/admin/listings/index.html.erb index 885e5e6b5..e9b28cc32 100644 --- a/app/views/admin/listings/index.html.erb +++ b/app/views/admin/listings/index.html.erb @@ -1,5 +1,11 @@ -
+ +

Listings

+ + Listing Categories +
<%= form_tag(admin_listings_path, method: "get", role: "search", class: "crayons-card crayons-card--secondary p-4 flex items-center") do %> diff --git a/config/routes.rb b/config/routes.rb index 7faa1310e..3254729dc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -62,6 +62,9 @@ Rails.application.routes.draw do resources :broadcasts resources :buffer_updates, only: %i[create update] resources :listings, only: %i[index edit update destroy] + resources :listing_categories, only: %i[index edit update new create + destroy], path: "listings/categories" + resources :comments, only: [:index] resources :events, only: %i[index create update] resources :feedback_messages, only: %i[index show] @@ -126,6 +129,7 @@ Rails.application.routes.draw do resource :config resources :badges, only: %i[index edit update new create] resources :display_ads, only: %i[index edit update new create destroy] + resources :html_variants, only: %i[index edit update new create show destroy] # These redirects serve as a safegaurd to prevent 404s for any Admins # who have the old badge_achievement URLs bookmarked. diff --git a/spec/requests/admin/listings_catogires_spec.rb b/spec/requests/admin/listings_catogires_spec.rb new file mode 100644 index 000000000..1f570d532 --- /dev/null +++ b/spec/requests/admin/listings_catogires_spec.rb @@ -0,0 +1,121 @@ +require "rails_helper" +require "requests/shared_examples/internal_policy_dependant_request" + +RSpec.describe "/admin/listings/categories", type: :request do + let(:get_resource) { get "/admin/listings/categories" } + let(:params) do + { name: "Computer stuff", cost: 22, rules: "Things computers do", + slug: "computer", social_preview_color: "#000", social_preview_description: "Computer things" } + end + let(:post_resource) { post "/admin/listings/categories", params: params } + + it_behaves_like "an InternalPolicy dependant request", ListingCategory do + let(:request) { get_resource } + end + + context "when the user is not an admin" do + let(:user) { create(:user) } + + before { sign_in user } + + describe "GET /admin/listings/categories" do + it "blocks the request" do + expect { get_resource }.to raise_error(Pundit::NotAuthorizedError) + end + end + + describe "POST /admin/listings/categories" do + it "blocks the request" do + expect { post_resource }.to raise_error(Pundit::NotAuthorizedError) + end + end + end + + context "when the user is a super admin" do + let(:super_admin) { create(:user, :super_admin) } + + before { sign_in super_admin } + + describe "GET /admin/listings/categories" do + it "allows the request" do + get_resource + expect(response).to have_http_status(:ok) + end + end + + describe "POST /admin/listings/categories" do + it "creates a new listing_category" do + expect do + post_resource + end.to change { ListingCategory.all.count }.by(1) + end + end + + describe "PUT /admin/listings/categories" do + let!(:listing_category) { create(:listing_category, name: "Computers") } + + it "updates Listing Category name" do + Timecop.freeze(Time.current) do + expect do + put "/admin/listings/categories/#{listing_category.id}", params: params + end.to change { listing_category.reload.name }.from("Computers").to("Computer stuff") + end + end + end + + describe "DELETE /admin/listing/categories/:id" do + let!(:listing_category) { create(:listing_category) } + + it "deletes the Listing Category" do + expect do + delete "/admin/listings/categories/#{listing_category.id}" + end.to change { ListingCategory.all.count }.by(-1) + expect(response.body).to redirect_to "/admin/listings/categories" + end + end + end + + context "when the user is a single resource admin" do + let(:single_resource_admin) { create(:user, :single_resource_admin, resource: ListingCategory) } + + before { sign_in single_resource_admin } + + describe "GET /admin/listings/categories" do + it "allows the request" do + get_resource + expect(response).to have_http_status(:ok) + end + end + + describe "POST /admin/listings/categories" do + it "creates a new listing_category" do + expect do + post_resource + end.to change { ListingCategory.all.count }.by(1) + end + end + + describe "PUT /admin/listings/categories" do + let!(:listing_category) { create(:listing_category, name: "Computers") } + + it "updates Listing Category name" do + Timecop.freeze(Time.current) do + expect do + put "/admin/listings/categories/#{listing_category.id}", params: params + end.to change { listing_category.reload.name }.from("Computers").to("Computer stuff") + end + end + end + + describe "DELETE /admin/listing/categories/:id" do + let!(:listing_category) { create(:listing_category) } + + it "deletes the Listing Category" do + expect do + delete "/admin/listings/categories/#{listing_category.id}" + end.to change { ListingCategory.all.count }.by(-1) + expect(response.body).to redirect_to "/admin/listings/categories" + end + end + end +end