merges with master
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
//= require suggest
|
||||
//= require forms
|
||||
//= require valuation_spending_proposal_form
|
||||
//= require embed_video
|
||||
|
||||
var initialize_modules = function() {
|
||||
App.Comments.initialize();
|
||||
@@ -59,6 +60,7 @@ var initialize_modules = function() {
|
||||
App.Suggest.initialize();
|
||||
App.Forms.initialize();
|
||||
App.ValuationSpendingProposalForm.initialize();
|
||||
App.EmbedVideo.initialize();
|
||||
};
|
||||
|
||||
$(function(){
|
||||
|
||||
7
app/assets/javascripts/embed_video.js.coffee
Normal file
7
app/assets/javascripts/embed_video.js.coffee
Normal file
@@ -0,0 +1,7 @@
|
||||
App.EmbedVideo =
|
||||
|
||||
initialize: ->
|
||||
$('#js-embedded-video').each ->
|
||||
code = $(this).data("video-code")
|
||||
$('#js-embedded-video').html(code)
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
|
||||
.debate-new, .debate-edit,
|
||||
.proposal-new, .proposal-edit,
|
||||
.spending-proposal-new, .spending-proposal-edit {
|
||||
.spending-proposal-new, .spending-proposal-edit {
|
||||
|
||||
.back {
|
||||
@include back;
|
||||
@@ -546,7 +546,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.debate, .proposal {
|
||||
.debate, .proposal, .investment-project {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
|
||||
@@ -565,7 +565,7 @@
|
||||
padding-bottom: rem-calc(12);
|
||||
}
|
||||
|
||||
.label-debate, .label-proposal {
|
||||
.label-debate, .label-proposal, .label-investment-project {
|
||||
background: none;
|
||||
clear: both;
|
||||
display: block;
|
||||
@@ -587,6 +587,10 @@
|
||||
color: $proposals;
|
||||
}
|
||||
|
||||
.label-investment-project {
|
||||
color: $budget;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
@@ -596,7 +600,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.debate-content, .proposal-content {
|
||||
.debate-content, .proposal-content, .investment-project-content {
|
||||
margin: 0;
|
||||
min-height: rem-calc(180);
|
||||
position: relative;
|
||||
@@ -606,7 +610,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.icon-debates, .icon-proposals {
|
||||
.icon-debates, .icon-proposals, .icon-budget {
|
||||
font-size: rem-calc(18);
|
||||
line-height: $line-height;
|
||||
position: absolute;
|
||||
@@ -623,7 +627,13 @@
|
||||
left: rem-calc(72);
|
||||
}
|
||||
|
||||
.debate-info, .proposal-info {
|
||||
.icon-budget {
|
||||
color: $budget;
|
||||
font-size: $small-font-size;
|
||||
left: rem-calc(122);
|
||||
}
|
||||
|
||||
.debate-info, .proposal-info, .investment-project-info {
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
margin: rem-calc(6) 0 0;
|
||||
@@ -638,7 +648,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.debate-description, .proposal-description {
|
||||
.debate-description, .proposal-description, .investment-project-description {
|
||||
color: $text;
|
||||
font-size: rem-calc(13);
|
||||
height: rem-calc(72);
|
||||
@@ -799,6 +809,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
.investment-project {
|
||||
|
||||
.supports {
|
||||
@include supports;
|
||||
background: none;
|
||||
border: 0;
|
||||
border-left: 1px solid $border;
|
||||
margin: 0 rem-calc(-12);
|
||||
min-height: rem-calc(180);
|
||||
padding-top: $line-height*2;
|
||||
|
||||
&:after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.button-support {
|
||||
background: $budget;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: $proposals-border;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: .75;
|
||||
}
|
||||
}
|
||||
|
||||
.total-supports {
|
||||
color: $budget;
|
||||
font-size: $base-font-size;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.not-logged,
|
||||
.organizations-votes,
|
||||
.anonymous-votes {
|
||||
background: rgba(69,67,114,.96);
|
||||
color: white;
|
||||
padding: rem-calc(12);
|
||||
}
|
||||
|
||||
.anonymous-votes p, .anonymous-votes a,
|
||||
.organizations-votes p {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.proposals-summary {
|
||||
|
||||
.panel {
|
||||
|
||||
@@ -7,7 +7,7 @@ class Admin::SpendingProposalsController < Admin::BaseController
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@spending_proposals = SpendingProposal.search(params, @current_filter).order(created_at: :desc).page(params[:page])
|
||||
@spending_proposals = SpendingProposal.scoped_filter(params, @current_filter).order(created_at: :desc).page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
|
||||
@@ -65,8 +65,7 @@ module CommentableActions
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def map
|
||||
def map
|
||||
@resource = resource_model.new
|
||||
@tag_cloud = tag_cloud
|
||||
end
|
||||
|
||||
@@ -12,6 +12,8 @@ class SpendingProposalsController < ApplicationController
|
||||
respond_to :html, :js
|
||||
|
||||
def index
|
||||
@spending_proposals = @search_terms.present? ? SpendingProposal.search(@search_terms) : SpendingProposal.all
|
||||
@spending_proposals = @spending_proposals.page(params[:page]).for_render
|
||||
end
|
||||
|
||||
def new
|
||||
|
||||
@@ -10,7 +10,7 @@ class Valuation::SpendingProposalsController < Valuation::BaseController
|
||||
|
||||
def index
|
||||
if current_user.valuator?
|
||||
@spending_proposals = SpendingProposal.search(params_for_current_valuator, @current_filter).order(created_at: :desc).page(params[:page])
|
||||
@spending_proposals = SpendingProposal.scoped_filter(params_for_current_valuator, @current_filter).order(created_at: :desc).page(params[:page])
|
||||
else
|
||||
@spending_proposals = SpendingProposal.none.page(params[:page])
|
||||
end
|
||||
|
||||
30
app/helpers/embed_videos_helper.rb
Normal file
30
app/helpers/embed_videos_helper.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module EmbedVideosHelper
|
||||
|
||||
def embedded_video_code
|
||||
link = @proposal.video_url
|
||||
if link.match(/vimeo.*/)
|
||||
server = "Vimeo"
|
||||
elsif link.match(/youtu*.*/)
|
||||
server = "YouTube"
|
||||
end
|
||||
|
||||
if server == "Vimeo"
|
||||
regExp = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/
|
||||
src = "https://player.vimeo.com/video/"
|
||||
elsif server == "YouTube"
|
||||
regExp = /youtu.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
|
||||
src = "https://www.youtube.com/embed/"
|
||||
end
|
||||
|
||||
if regExp
|
||||
match = link.match(regExp)
|
||||
end
|
||||
|
||||
if match and match[2]
|
||||
'<iframe src="' + src + match[2] + '" frameborder="0" allowfullscreen></iframe>'
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -25,12 +25,15 @@ class SpendingProposal < ActiveRecord::Base
|
||||
scope :managed, -> { valuation_open.where(valuation_assignments_count: 0).where("administrator_id IS NOT ?", nil) }
|
||||
scope :valuating, -> { valuation_open.where("valuation_assignments_count > 0 AND valuation_finished = ?", false) }
|
||||
scope :valuation_finished, -> { where(valuation_finished: true) }
|
||||
scope :feasible, -> { where(feasible: true) }
|
||||
scope :unfeasible, -> { where(feasible: false) }
|
||||
scope :not_unfeasible, -> { where("feasible IS ? OR feasible = ?", nil, true) }
|
||||
|
||||
scope :by_admin, -> (admin) { where(administrator_id: admin.presence) }
|
||||
scope :by_tag, -> (tag_name) { tagged_with(tag_name) }
|
||||
scope :by_valuator, -> (valuator) { where("valuation_assignments.valuator_id = ?", valuator.presence).joins(:valuation_assignments) }
|
||||
|
||||
scope :for_render, -> { includes(:geozone, administrator: :user, valuators: :user) }
|
||||
scope :for_render, -> { includes(:geozone) }
|
||||
|
||||
def description
|
||||
super.try :html_safe
|
||||
@@ -40,14 +43,14 @@ class SpendingProposal < ActiveRecord::Base
|
||||
params.select{|x,_| %w{geozone_id administrator_id tag_name valuator_id}.include? x.to_s }
|
||||
end
|
||||
|
||||
def self.search(params, current_filter)
|
||||
def self.scoped_filter(params, current_filter)
|
||||
results = self
|
||||
results = results.by_geozone(params[:geozone_id]) if params[:geozone_id].present?
|
||||
results = results.by_admin(params[:administrator_id]) if params[:administrator_id].present?
|
||||
results = results.by_tag(params[:tag_name]) if params[:tag_name].present?
|
||||
results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present?
|
||||
results = results.send(current_filter) if current_filter.present?
|
||||
results.for_render
|
||||
results.includes(:geozone, administrator: :user, valuators: :user)
|
||||
end
|
||||
|
||||
def self.by_geozone(geozone)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<section class="row-full comments">
|
||||
<div class="row">
|
||||
<div id="comments" class="small-12 column">
|
||||
|
||||
<h2>
|
||||
<%= t("proposals.show.comments_title") %>
|
||||
<span class="js-comments-count">(<%= @proposal.comments_count %>)</span>
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
<div class="video-link">
|
||||
<%= text_with_links @proposal.video_url %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div id="js-embedded-video" data-video-code="<%= embedded_video_code %>"></div>
|
||||
<% end %>
|
||||
|
||||
<h4><%= @proposal.question %></h4>
|
||||
|
||||
|
||||
11
app/views/spending_proposals/_sidebar.html.erb
Normal file
11
app/views/spending_proposals/_sidebar.html.erb
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="sidebar-divider"></div>
|
||||
<h3 class="sidebar-title"><%= t("spending_proposals.index.sidebar.geozones") %></h3>
|
||||
<br>
|
||||
<div class="geozone">
|
||||
<% Geozone.names.each do |geozone| %>
|
||||
<%= link_to geozone, spending_proposals_path(search: geozone) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="sidebar-divider"></div>
|
||||
<h3 class="sidebar-title"><%= t("spending_proposals.index.sidebar.feasibility") %></h3>
|
||||
<br>
|
||||
53
app/views/spending_proposals/_spending_proposal.html.erb
Normal file
53
app/views/spending_proposals/_spending_proposal.html.erb
Normal file
@@ -0,0 +1,53 @@
|
||||
<div id="<%= dom_id(spending_proposal) %>" class="investment-project clear">
|
||||
<div class="panel">
|
||||
<div class="row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<div class="investment-project-content">
|
||||
|
||||
<% cache [locale_and_user_status(spending_proposal), 'index', spending_proposal, spending_proposal.author] do %>
|
||||
<span class="label-investment-project float-left"><%= t("spending_proposals.spending_proposal.spending_proposal") %></span>
|
||||
<span class="icon-budget"></span>
|
||||
<h3><%= link_to spending_proposal.title, spending_proposal_path(spending_proposal) %></h3>
|
||||
<p class="investment-project-info">
|
||||
|
||||
<%= l spending_proposal.created_at.to_date %>
|
||||
|
||||
<% if spending_proposal.author.hidden? || spending_proposal.author.erased? %>
|
||||
<span class="bullet"> • </span>
|
||||
<span class="author">
|
||||
<%= t("spending_proposals.show.author_deleted") %>
|
||||
</span>
|
||||
<% else %>
|
||||
<span class="bullet"> • </span>
|
||||
<span class="author">
|
||||
<%= spending_proposal.author.name %>
|
||||
</span>
|
||||
<% if spending_proposal.author.official? %>
|
||||
<span class="bullet"> • </span>
|
||||
<span class="label round level-<%= spending_proposal.author.official_level %>">
|
||||
<%= spending_proposal.author.official_position %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if spending_proposal.author.verified_organization? %>
|
||||
<span class="bullet"> • </span>
|
||||
<span class="label round is-association">
|
||||
<%= t("shared.collective") %>
|
||||
</span>
|
||||
<% end %>
|
||||
</p>
|
||||
<div class="investment-project-description">
|
||||
<p><%= link_to spending_proposal.description, spending_proposal_path(spending_proposal) %></p>
|
||||
<div class="truncate"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +1,35 @@
|
||||
<% provide :title do %><%= t('spending_proposals.index.title') %><% end %>
|
||||
<div class="page row-full">
|
||||
<div class="row">
|
||||
<div class="more-information text small-12 medium-8 column">
|
||||
<h1><%= t('spending_proposals.index.title') %></h1>
|
||||
<% content_for :header_addon do %>
|
||||
<%= render "shared/search_form",
|
||||
search_path: spending_proposals_path(page: 1),
|
||||
i18n_namespace: "spending_proposals.index.search_form" %>
|
||||
<% end %>
|
||||
|
||||
<p><%= t('spending_proposals.index.text_html') %></p>
|
||||
<main>
|
||||
<div class="wrap row">
|
||||
<div id="investment-projects" class="investment-projects-list small-12 medium-9 column">
|
||||
|
||||
<% if can? :create, SpendingProposal %>
|
||||
<%= link_to t('spending_proposals.index.create_link'), new_spending_proposal_path, class: 'button' %>
|
||||
<% else %>
|
||||
<p><%= t('spending_proposals.index.verified_only', verify_account: link_to(t('spending_proposals.index.verify_account'), verification_path)).html_safe %></p>
|
||||
<% end %>
|
||||
<div class="small-12 search-results">
|
||||
<% if @search_terms %>
|
||||
<h2>
|
||||
<%= page_entries_info @spending_proposals %>
|
||||
<%= t("spending_proposals.index.search_results", count: @spending_proposals.size, search_term: @search_terms) %>
|
||||
</h2>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="show-for-small-only">
|
||||
<%= link_to t("spending_proposals.index.start_spending_proposal"), new_spending_proposal_path, class: 'button expanded' %>
|
||||
</div>
|
||||
<%= render partial: 'spending_proposals/spending_proposal', collection: @spending_proposals %>
|
||||
<%= paginate @spending_proposals %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
<aside class="margin-bottom">
|
||||
<%= render 'sidebar' %>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -131,6 +131,7 @@ ignore_unused:
|
||||
- 'proposals.index.select_order'
|
||||
- 'proposals.index.orders.*'
|
||||
- 'proposals.index.search_form.*'
|
||||
- 'spending_proposals.index.search_form.*'
|
||||
- 'notifications.index.comments_on*'
|
||||
- 'notifications.index.replies_to*'
|
||||
- 'helpers.page_entries_info.*' # kaminari
|
||||
|
||||
@@ -412,11 +412,18 @@ en:
|
||||
new: Create
|
||||
title: Spending proposal title
|
||||
index:
|
||||
create_link: Create spending proposal
|
||||
text_html: Here you can send spending proposals to be considered in the frame of the annual participatory budgeting.
|
||||
title: Participatory budgeting
|
||||
verified_only: Only verified users can create spending proposals, %{verify_account}.
|
||||
verify_account: verify your account
|
||||
search_form:
|
||||
button: Search
|
||||
placeholder: Investment projects...
|
||||
title: Search
|
||||
search_results:
|
||||
one: " containing the term '%{search_term}'"
|
||||
other: " containing the term '%{search_term}'"
|
||||
sidebar:
|
||||
geozones: Scope of operation
|
||||
feasibility: Feasibility
|
||||
start_spending_proposal: Create an investment project
|
||||
new:
|
||||
more_info: How do participatory budgeting works?
|
||||
recommendation_one: It's mandatory that the proposal makes reference to a budgetable action.
|
||||
@@ -425,6 +432,10 @@ en:
|
||||
recommendations_title: How to create a spending proposal
|
||||
start_new: Create spending proposal
|
||||
back_link: Back
|
||||
show:
|
||||
author_deleted: User deleted
|
||||
spending_proposal:
|
||||
spending_proposal: Investment project
|
||||
wrong_price_format: Only integer numbers
|
||||
spending_proposal:
|
||||
already_supported: You have already supported this. Share it!
|
||||
|
||||
@@ -412,11 +412,18 @@ es:
|
||||
new: Crear
|
||||
title: Título de la propuesta de gasto
|
||||
index:
|
||||
create_link: Enviar propuesta de gasto
|
||||
text_html: Desde esta sección podrás sugerir propuestas de gasto que irán asociadas a las partidas de presupuestos ciudadanos.<br>El requisito principal es que sean propuestas presupuestables.
|
||||
title: Presupuestos participativos
|
||||
verified_only: Sólo los usuarios verificados pueden crear propuestas de gasto, %{verify_account}.
|
||||
verify_account: verifica tu cuenta
|
||||
search_form:
|
||||
button: Buscar
|
||||
placeholder: Propuestas de inversión...
|
||||
title: Buscar
|
||||
search_results:
|
||||
one: " que contiene '%{search_term}'"
|
||||
other: " que contienen '%{search_term}'"
|
||||
sidebar:
|
||||
geozones: Ámbitos de actuación
|
||||
feasibility: Viabilidad
|
||||
start_spending_proposal: Crea una propuesta de inversión
|
||||
new:
|
||||
more_info: "¿Cómo funcionan los presupuestos participativos?"
|
||||
recommendation_one: Es fundamental que haga referencia a una actuación presupuestable.
|
||||
@@ -425,6 +432,10 @@ es:
|
||||
recommendations_title: Cómo crear una propuesta de gasto
|
||||
start_new: Crear una propuesta de gasto
|
||||
back_link: Volver
|
||||
show:
|
||||
author_deleted: Usuario eliminado
|
||||
spending_proposal:
|
||||
spending_proposal: Propuesta de inversión
|
||||
wrong_price_format: Solo puede incluir caracteres numéricos
|
||||
spending_proposal:
|
||||
already_supported: Ya has apoyado este proyecto. Compartelo!
|
||||
|
||||
@@ -87,6 +87,29 @@ feature 'Proposals' do
|
||||
end
|
||||
end
|
||||
|
||||
context "Embedded video" do
|
||||
scenario "Show YouTube video" do
|
||||
proposal = create(:proposal, video_url: "http://www.youtube.com/watch?v=a7UFm6ErMPU")
|
||||
visit proposal_path(proposal)
|
||||
expect(page).to have_selector("div[id='js-embedded-video']")
|
||||
expect(page.html).to include 'https://www.youtube.com/embed/a7UFm6ErMPU'
|
||||
end
|
||||
|
||||
scenario "Show Vimeo video" do
|
||||
proposal = create(:proposal, video_url: "https://vimeo.com/7232823" )
|
||||
visit proposal_path(proposal)
|
||||
expect(page).to have_selector("div[id='js-embedded-video']")
|
||||
expect(page.html).to include 'https://player.vimeo.com/video/7232823'
|
||||
end
|
||||
|
||||
scenario "Dont show video" do
|
||||
proposal = create(:proposal, video_url: nil)
|
||||
|
||||
visit proposal_path(proposal)
|
||||
expect(page).to_not have_selector("div[id='js-embedded-video']")
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Social Media Cards' do
|
||||
proposal = create(:proposal)
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ feature 'Spending proposals' do
|
||||
let(:author) { create(:user, :level_two, username: 'Isabel') }
|
||||
|
||||
scenario 'Index' do
|
||||
visit spending_proposals_path
|
||||
|
||||
expect(page).to_not have_link('Create spending proposal', href: new_spending_proposal_path)
|
||||
expect(page).to have_link('verify your account')
|
||||
|
||||
login_as(author)
|
||||
spending_proposals = [create(:spending_proposal), create(:spending_proposal), create(:spending_proposal)]
|
||||
|
||||
visit spending_proposals_path
|
||||
|
||||
expect(page).to have_link('Create spending proposal', href: new_spending_proposal_path)
|
||||
expect(page).to_not have_link('verify your account')
|
||||
expect(page).to have_selector('#investment-projects .investment-project', count: 3)
|
||||
spending_proposals.each do |spending_proposal|
|
||||
within('#investment-projects') do
|
||||
expect(page).to have_content spending_proposal.title
|
||||
expect(page).to have_css("a[href='#{spending_proposal_path(spending_proposal)}']", text: spending_proposal.title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Create' do
|
||||
|
||||
@@ -227,6 +227,38 @@ describe SpendingProposal do
|
||||
expect(valuation_finished.first).to eq(spending_proposal3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "feasible" do
|
||||
it "should return all feasible spending proposals" do
|
||||
feasible_spending_proposal = create(:spending_proposal, feasible: true)
|
||||
create(:spending_proposal)
|
||||
|
||||
expect(SpendingProposal.feasible).to eq [feasible_spending_proposal]
|
||||
end
|
||||
end
|
||||
|
||||
describe "unfeasible" do
|
||||
it "should return all unfeasible spending proposals" do
|
||||
unfeasible_spending_proposal = create(:spending_proposal, feasible: false)
|
||||
create(:spending_proposal, feasible: true)
|
||||
|
||||
expect(SpendingProposal.unfeasible).to eq [unfeasible_spending_proposal]
|
||||
end
|
||||
end
|
||||
|
||||
describe "not_unfeasible" do
|
||||
it "should return all not unfeasible spending proposals" do
|
||||
not_unfeasible_spending_proposal_1 = create(:spending_proposal, feasible: true)
|
||||
not_unfeasible_spending_proposal_2 = create(:spending_proposal)
|
||||
create(:spending_proposal, feasible: false)
|
||||
|
||||
not_unfeasibles = SpendingProposal.not_unfeasible
|
||||
|
||||
expect(not_unfeasibles.size).to eq(2)
|
||||
expect(not_unfeasibles.include?(not_unfeasible_spending_proposal_1)).to eq(true)
|
||||
expect(not_unfeasibles.include?(not_unfeasible_spending_proposal_2)).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user