From 3de1bdad02743bad70d28f237c53508e6435164a Mon Sep 17 00:00:00 2001 From: Anna Buianova Date: Mon, 29 Jul 2019 15:32:49 +0300 Subject: [PATCH] Podcast ownership (#3546) * Podcast#admins * Start with /internal/podcasts * Adding and removing podcast admin roles * Improve podcasts internal section * Fix podcast updating * More internal podcasts specs * Podcasts internal link --- .../internal/podcasts_controller.rb | 60 +++++++++++++++++ app/models/podcast.rb | 6 ++ app/models/role.rb | 1 + app/views/internal/podcasts/edit.html.erb | 43 ++++++++++++ app/views/internal/podcasts/index.html.erb | 42 ++++++++++++ app/views/layouts/internal.html.erb | 7 ++ config/routes.rb | 6 ++ spec/models/podcast_spec.rb | 26 +++++++ spec/requests/internal/podcasts_spec.rb | 67 +++++++++++++++++++ 9 files changed, 258 insertions(+) create mode 100644 app/controllers/internal/podcasts_controller.rb create mode 100644 app/views/internal/podcasts/edit.html.erb create mode 100644 app/views/internal/podcasts/index.html.erb create mode 100644 spec/requests/internal/podcasts_spec.rb diff --git a/app/controllers/internal/podcasts_controller.rb b/app/controllers/internal/podcasts_controller.rb new file mode 100644 index 000000000..38c67f262 --- /dev/null +++ b/app/controllers/internal/podcasts_controller.rb @@ -0,0 +1,60 @@ +class Internal::PodcastsController < Internal::ApplicationController + layout "internal" + + before_action :find_podcast, only: %i[edit update remove_admin add_admin] + before_action :find_user, only: %i[remove_admin add_admin] + + def index + @podcasts = Podcast.joins(:podcast_episodes). + select("podcasts.*, count(podcast_episodes) as count"). + group("podcasts.id").order("podcasts.created_at DESC"). + page(params[:page]).per(50) + @podcasts = @podcasts.where("podcasts.title ILIKE :search", search: "%#{params[:search]}%") if params[:search].present? + end + + def edit; end + + def update + if @podcast.update(podcast_params) + redirect_to internal_podcasts_path, notice: "Podcast updated" + else + render :edit + end + 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" + 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" + end + end + + private + + 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 diff --git a/app/models/podcast.rb b/app/models/podcast.rb index ecfe3ecf1..b040d9149 100644 --- a/app/models/podcast.rb +++ b/app/models/podcast.rb @@ -1,4 +1,6 @@ class Podcast < ApplicationRecord + resourcify + has_many :podcast_episodes mount_uploader :image, ProfileImageUploader @@ -29,6 +31,10 @@ class Podcast < ApplicationRecord episode.to_a.first end + def admins + User.with_role(:podcast_admin, self) + end + private def unique_slug_including_users_and_orgs diff --git a/app/models/role.rb b/app/models/role.rb index 07f3dcc57..afe67755b 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -27,6 +27,7 @@ class Role < ApplicationRecord chatroom_beta_tester comment_banned pro + podcast_admin ] } scopify diff --git a/app/views/internal/podcasts/edit.html.erb b/app/views/internal/podcasts/edit.html.erb new file mode 100644 index 000000000..a7afda641 --- /dev/null +++ b/app/views/internal/podcasts/edit.html.erb @@ -0,0 +1,43 @@ +

+ <%= link_to @podcast.title, "/#{@podcast.slug}" %> +

+<% if @podcast.admins.any? %> +

Admins:

+ +<% else %> +

There are no admins for this podcast.

+<% end %> + +<%= form_for @podcast, url: add_admin_internal_podcast_path(@podcast.id), html: { method: :post } do |f| %> +
+ <%= f.label "Add Admin (by user_id) " %> + <%= f.text_field :user_id, value: "" %> + <%= f.submit "Add Admin" %> +
+<% end %> + +<%= form_for [:internal, @podcast] do |f| %> +
+
+ <%= f.label :title %> + <%= f.text_field :title %> +
+
+ <%= f.label :feed_url %> + <%= f.text_field :feed_url %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/internal/podcasts/index.html.erb b/app/views/internal/podcasts/index.html.erb new file mode 100644 index 000000000..336e894ea --- /dev/null +++ b/app/views/internal/podcasts/index.html.erb @@ -0,0 +1,42 @@ + + +

Podcasts

+ +<%= form_tag("/internal/podcasts", method: "get") do %> + <%= label_tag(:search, "Find by title:") %> + <%= text_field_tag(:search, params[:search]) %> + <%= submit_tag("Search") %> +<% end %> + +<%= paginate @podcasts %> +
+
+
ID
+
Title
+
Feed URL
+
Episodes
+
Reachable
+
Status Notice
+
Admins
+
+ +<% @podcasts.each do |podcast| %> +
+
<%= podcast.id %>
+ + +
<%= podcast.podcast_episodes.count %>
+
<%= podcast.reachable %>
+
<%= podcast.status_notice %>
+
+ <% podcast.admins.pluck(:username).each do |username| %> + <%= link_to "@#{username}", "/#{username}" %> + <% end %> +
+
+<% end %> +<%= paginate @podcasts %> diff --git a/app/views/layouts/internal.html.erb b/app/views/layouts/internal.html.erb index 7f19f5bd5..3c196e8d7 100644 --- a/app/views/layouts/internal.html.erb +++ b/app/views/layouts/internal.html.erb @@ -42,6 +42,12 @@ padding: 2px; } + .wrapper-7 { + display: grid; + grid-template-columns: 5% 15% 25% 10% 10% 20% 15%; + padding: 2px; + } + .wrapper-3 { display: grid; grid-template-columns: 25% 40% 25%%; @@ -137,6 +143,7 @@ <% controller_names.each do |name| %>
  • "><%= name %>
  • <% end %> +
  • ">pod
  • diff --git a/config/routes.rb b/config/routes.rb index 05362cbd2..710b13962 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -36,6 +36,12 @@ Rails.application.routes.draw do 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 :podcasts, only: %i[index edit update destroy] do + member do + post :add_admin + delete :remove_admin + end + end resources :reactions, only: [:update] resources :chat_channels, only: %i[index create update] resources :reports, only: %i[index show], controller: "feedback_messages" do diff --git a/spec/models/podcast_spec.rb b/spec/models/podcast_spec.rb index 63052090e..8e2125f8d 100644 --- a/spec/models/podcast_spec.rb +++ b/spec/models/podcast_spec.rb @@ -128,4 +128,30 @@ RSpec.describe Podcast, type: :model do expect(podcast.existing_episode(item)).to eq(nil) end end + + describe "#admins" do + let(:podcast) { create(:podcast) } + let(:podcast2) { create(:podcast) } + let(:podcast3) { create(:podcast) } + let(:user) { create(:user) } + let(:user2) { create(:user) } + let(:user3) { create(:user) } + + before do + user.add_role(:podcast_admin, podcast) + user2.add_role(:podcast_admin, podcast) + user.add_role(:podcast_admin, podcast3) + user3.add_role(:podcast_admin, podcast2) + user3.add_role(:podcast_admin, podcast2) + [user, user2, user3].each(&:save) + end + + it "returns proper admins" do + expect(podcast.admins.sort).to eq([user, user2].sort) + end + + it "returns proper admins for podcast3" do + expect(podcast3.admins).to eq([user]) + end + end end diff --git a/spec/requests/internal/podcasts_spec.rb b/spec/requests/internal/podcasts_spec.rb new file mode 100644 index 000000000..dcfbe6e6c --- /dev/null +++ b/spec/requests/internal/podcasts_spec.rb @@ -0,0 +1,67 @@ +require "rails_helper" + +RSpec.describe "/internal/podcasts", type: :request do + let(:admin) { create(:user, :super_admin) } + let(:podcast) { create(:podcast) } + let(:user) { create(:user) } + + before do + sign_in admin + end + + describe "GET /internal/podcasts" do + before do + create_list(:podcast, 3) + user.add_role(:podcast_admin, Podcast.order("random()").first) + end + + it "renders success" do + get internal_podcasts_path + expect(response).to be_success + end + end + + describe "Adding admin" do + it "adds an admin" do + expect do + post add_admin_internal_podcast_path(podcast.id), params: { podcast: { user_id: user.id } } + end.to change(Role, :count).by(1) + user.reload + expect(user.has_role?(:podcast_admin, podcast)).to be true + end + + it "does nothing when adding an admin for non-existent user" do + post add_admin_internal_podcast_path(podcast.id), params: { podcast: { user_id: user.id + 1 } } + expect(response).to redirect_to(edit_internal_podcast_path(podcast)) + end + end + + describe "Removing admin" do + it "removes an admin" do + user.add_role(:podcast_admin, podcast) + expect do + delete remove_admin_internal_podcast_path(podcast.id), params: { podcast: { user_id: user.id } } + end.to change(Role, :count).by(-1) + expect(user.has_role?(:podcast_admin, podcast)).to be false + end + + it "does nothing when removing an admin for non-existent user" do + delete remove_admin_internal_podcast_path(podcast.id), params: { podcast: { user_id: user.id + 1 } } + expect(response).to redirect_to(edit_internal_podcast_path(podcast)) + end + end + + describe "Updating" do + it "updates" do + put internal_podcast_path(podcast), params: { podcast: { title: "hello", feed_url: "https://pod.example.com/rss.rss" } } + podcast.reload + expect(podcast.title).to eq("hello") + expect(podcast.feed_url).to eq("https://pod.example.com/rss.rss") + end + + it "redirects after update" do + put internal_podcast_path(podcast), params: { podcast: { title: "hello", feed_url: "https://pod.example.com/rss.rss" } } + expect(response).to redirect_to(internal_podcasts_path) + end + end +end