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
This commit is contained in:
Anna Buianova 2019-07-29 15:32:49 +03:00 committed by Ben Halpern
parent 9f34dcd0eb
commit 3de1bdad02
9 changed files with 258 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -27,6 +27,7 @@ class Role < ApplicationRecord
chatroom_beta_tester
comment_banned
pro
podcast_admin
]
}
scopify

View file

@ -0,0 +1,43 @@
<h1>
<%= link_to @podcast.title, "/#{@podcast.slug}" %>
</h1>
<% if @podcast.admins.any? %>
<p><strong>Admins: </strong></p>
<ul>
<% @podcast.admins.each do |admin| %>
<%= form_for @podcast, url: remove_admin_internal_podcast_path(@podcast.id), html: { method: :delete } do |f| %>
<li>
<%= link_to "@#{admin.username}", "/#{admin.username}" %>
<%= f.hidden_field :user_id, value: admin.id %>
<%= f.submit "Remove" %>
</li>
<br>
<% end %>
<% end %>
</ul>
<% else %>
<p>There are no admins for this podcast.</p>
<% end %>
<%= form_for @podcast, url: add_admin_internal_podcast_path(@podcast.id), html: { method: :post } do |f| %>
<div>
<%= f.label "Add Admin (by user_id) " %>
<%= f.text_field :user_id, value: "" %>
<%= f.submit "Add Admin" %>
</div>
<% end %>
<%= form_for [:internal, @podcast] do |f| %>
<hr>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :feed_url %>
<%= f.text_field :feed_url %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>

View file

@ -0,0 +1,42 @@
<style>
.alert {
border: 2px red solid;
}
</style>
<h1>Podcasts</h1>
<%= 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 %>
<br>
<div class="wrapper-7" style="font-weight: 600; border-bottom: 2px solid black;">
<div>ID</div>
<div>Title</div>
<div>Feed URL</div>
<div>Episodes</div>
<div>Reachable</div>
<div>Status Notice</div>
<div>Admins</div>
</div>
<% @podcasts.each do |podcast| %>
<div class="wrapper-7" style="border-bottom: 1px solid grey; padding: 10px;">
<div class="grid-item"><%= podcast.id %></div>
<div class="grid-item"><a href="<%= edit_internal_podcast_path(podcast) %>"><%= podcast.title %></a></div>
<div class="grid-item"><a href="<%= podcast.feed_url %>"><%= podcast.feed_url %></a></div>
<div class="grid-item"><%= podcast.podcast_episodes.count %></div>
<div class="grid-item"><%= podcast.reachable %></div>
<div class="grid-item"><%= podcast.status_notice %></div>
<div class="grid-item">
<% podcast.admins.pluck(:username).each do |username| %>
<%= link_to "@#{username}", "/#{username}" %>
<% end %>
</div>
</div>
<% end %>
<%= paginate @podcasts %>

View file

@ -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| %>
<li class="<%= "active" if controller_name == name %>"><a href="/internal/<%= name %>"><%= name %></a></li>
<% end %>
<li class="<%= "active" if controller_name == "podcasts" %>"><a href="/internal/podcasts">pod</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>

View file

@ -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

View file

@ -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

View file

@ -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