Add contribution actions and member deletion
This commit is contained in:
parent
57e976ef96
commit
882d0a51ed
@ -1,7 +1,25 @@
|
||||
/* Application styles */
|
||||
|
||||
table { border: 1px solid black; }
|
||||
body {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
td, th { padding: 10px; }
|
||||
table {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
width: calc(100% - 42px);
|
||||
}
|
||||
|
||||
.new_contribution_form { max-width: 600px; }
|
||||
td, th { padding: 10px; text-align: left; }
|
||||
|
||||
table.zebra tr:nth-child(2n) { background-color: #eee; }
|
||||
table.lined tr:nth-child(n + 2) td { border-top: 1px solid #eee; }
|
||||
|
||||
ul {
|
||||
padding-left: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li { padding: 5px 0px; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
class ContributionsController < ApplicationController
|
||||
before_action :set_member, only: %i[ new create ]
|
||||
before_action :set_contribution, only: %i[ edit ]
|
||||
before_action :set_contribution, only: %i[ edit update delete destroy ]
|
||||
|
||||
# GET /members/new
|
||||
def new
|
||||
@ -27,14 +27,26 @@ class ContributionsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
## PATCH/PUT /members/1
|
||||
#def update
|
||||
# if @member.update(member_params)
|
||||
# redirect_to @member, notice: "Member was successfully updated."
|
||||
# else
|
||||
# render :edit, status: :unprocessable_entity
|
||||
# end
|
||||
#end
|
||||
# PATCH/PUT /members/1
|
||||
def update
|
||||
if @contribution.update(contribution_params)
|
||||
redirect_to @contribution.member, notice: "Contribution was successfully updated."
|
||||
else
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
#
|
||||
# GET /members/1/delete
|
||||
def delete
|
||||
end
|
||||
|
||||
# DELETE /members/1
|
||||
def destroy
|
||||
@member = @contribution.member
|
||||
@contribution.destroy
|
||||
|
||||
redirect_to @member, notice: "Member personal data permanently removed."
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
|
@ -1,5 +1,5 @@
|
||||
class MembersController < ApplicationController
|
||||
before_action :set_member, only: %i[ show edit update destroy ]
|
||||
before_action :set_member, only: %i[ show edit update delete destroy ]
|
||||
helper_method :sort_params
|
||||
|
||||
# GET /members
|
||||
@ -46,6 +46,17 @@ class MembersController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
# GET /members/1/delete
|
||||
def delete
|
||||
end
|
||||
|
||||
# DELETE /members/1
|
||||
def destroy
|
||||
@member.remove_personal_information!
|
||||
|
||||
redirect_to members_path, notice: "Member personal data permanently removed."
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_member
|
||||
|
@ -2,4 +2,8 @@ module ApplicationHelper
|
||||
def member_status(status)
|
||||
t("members.status.#{status}")
|
||||
end
|
||||
|
||||
def notification_status(status)
|
||||
t("notifications.status.#{status}")
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
class Member < ApplicationRecord
|
||||
default_scope { where(excluded: false) }
|
||||
has_many :contributions
|
||||
has_many :notifications
|
||||
|
||||
@ -10,6 +11,17 @@ class Member < ApplicationRecord
|
||||
update(status: expected_status)
|
||||
end
|
||||
|
||||
def remove_personal_information!
|
||||
update(
|
||||
excluded: true,
|
||||
display_name: "",
|
||||
email: nil,
|
||||
identification_number: "",
|
||||
category: "",
|
||||
address: "",
|
||||
)
|
||||
end
|
||||
|
||||
def expected_status
|
||||
if joined_on.nil?
|
||||
:pending
|
||||
|
28
app/views/contributions/delete.html.erb
Normal file
28
app/views/contributions/delete.html.erb
Normal file
@ -0,0 +1,28 @@
|
||||
<p style="color: green"><%= notice %></p>
|
||||
|
||||
<h1><%= t('contributions.delete.title') %></h1>
|
||||
|
||||
<p><%= t('contributions.delete.confirmation_message') %></p>
|
||||
|
||||
<table>
|
||||
<tr><td><%= t('members.attributes.display_name') %></td><td><%= @contribution.member.display_name %></td></tr>
|
||||
<tr><td><%= t('members.attributes.email') %></td><td><%= @contribution.member.email %></td></tr>
|
||||
<tr><td><%= t('members.attributes.category') %></td><td><%= @contribution.member.category %></td></tr>
|
||||
<tr><td><%= t('members.attributes.identification_number') %></td><td><%= @contribution.member.identification_number %></td></tr>
|
||||
<tr><td><%= t('members.attributes.address') %></td><td><%= simple_format @contribution.member.address %></td></tr>
|
||||
<tr><td><%= t('members.attributes.joined_on') %></td><td><%= @contribution.member.joined_on %></td></tr>
|
||||
<tr><td><%= t('members.attributes.expires_on') %></td><td><%= @contribution.member.expires_on %></td></tr>
|
||||
<tr><td><%= t('members.attributes.status') %></td><td><%= @contribution.member.status %></td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<%= form_with model: @contribution, method: :delete do |form| %>
|
||||
<div>
|
||||
<%= form.submit t('contributions.delete.actions.submit') %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= link_to t('contributions.delete.actions.go_back'), members_path %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
@ -1,22 +1,36 @@
|
||||
editando contriboot
|
||||
<h1><%= t('contributions.edit.title') %></h1>
|
||||
|
||||
<%= form_with(model: @contribution) do |form| %>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Amount</td>
|
||||
<td>€<%= @contribution.eurocents %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Payment date</td>
|
||||
<td>€<%= @contribution.payment_on %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Payment method</td>
|
||||
<td><%= @contribution.payment_method %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Payment reference</td>
|
||||
<td><%= @contribution.payment_reference %></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td><%= t('contributions.edit.member') %></td>
|
||||
<td>
|
||||
<%= link_to @contribution.member do %>
|
||||
<%= @contribution.member.number %>.
|
||||
<%= @contribution.member.display_name %>
|
||||
<<%= @contribution.member.email %>>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><%= t('contributions.attributes.amount') %></label></td>
|
||||
<td><%= form.number_field :eurocents, required: true %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><%= t('contributions.attributes.payment_on') %></label></td>
|
||||
<td><%= form.date_field :payment_on %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><%= t('contributions.attributes.payment_method') %></label></td>
|
||||
<td><%= form.select :payment_method, %w[iban mbway multibanco] %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><%= t('contributions.attributes.payment_reference') %></label></td>
|
||||
<td><%= form.text_field :payment_reference %></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div>
|
||||
<%= form.submit t('contributions.edit.actions.submit') %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
@ -1,39 +1,46 @@
|
||||
<h1>Registering contribution for <%= @member.display_name %></h1>
|
||||
|
||||
<table>
|
||||
<tr><td>Member number</td><td><%= @member.number %></td></tr>
|
||||
<tr><td>Joined on</td><td><%= @member.joined_on %></td></tr>
|
||||
<tr><td>Expires on</td><td><%= @member.expires_on %></td></tr>
|
||||
</table>
|
||||
|
||||
<h1><%= t('contributions.new.title') %></h1>
|
||||
|
||||
<%= form_with(model: [@member, @contribution]) do |form| %>
|
||||
<table class="new_contribution_form">
|
||||
<tr>
|
||||
<td><label for="contribution_eurocents">Amount</label></td>
|
||||
<td><%= t('contributions.new.member') %></td>
|
||||
<td>
|
||||
<%= link_to @member do %>
|
||||
<%= @member.number %>.
|
||||
<%= @member.display_name %>
|
||||
<<%= @member.email %>>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="contribution_eurocents"><%= t('contributions.attributes.amount') %></label></td>
|
||||
<td><%= form.number_field :eurocents %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="contribution_payment_on">Payment date</label></td>
|
||||
<td><label for="contribution_payment_on"><%= t('contributions.attributes.payment_on') %></label></td>
|
||||
<td><%= form.date_field :payment_on %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="contribution_payment_method">Payment method</label></td>
|
||||
<td><label for="contribution_payment_method"><%= t('contributions.attributes.payment_method') %></label></td>
|
||||
<td><%= form.select :payment_method, %w[iban mbway multibanco] %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="contribution_payment_reference">Referência</label></td>
|
||||
<td><label for="contribution_payment_reference"><%= t('contributions.attributes.payment_reference') %></label></td>
|
||||
<td><%= form.text_field :payment_reference %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
Adding a contribution will automatically bump the membership expiration
|
||||
date by one year. If it's the first contribution for this member, the
|
||||
join date will be set to the payment date and the expiration date one
|
||||
year after that. You can override the expiration date by setting a date
|
||||
below:
|
||||
<%= t('contributions.new.expires_on_warning') %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= t('members.attributes.joined_on') %></td>
|
||||
<td><%= @member.joined_on %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><%= t('members.attributes.expires_on') %></td>
|
||||
<td><%= @member.expires_on %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="member_expires_on">Nova data de expiração</label></td>
|
||||
<td>
|
||||
|
27
app/views/members/delete.html.erb
Normal file
27
app/views/members/delete.html.erb
Normal file
@ -0,0 +1,27 @@
|
||||
<p style="color: green"><%= notice %></p>
|
||||
|
||||
<h1><%= t('members.delete.title') %></h1>
|
||||
|
||||
<p><%= t('members.delete.confirmation_message') %></p>
|
||||
|
||||
<table>
|
||||
<tr><td><%= t('members.attributes.display_name') %></td><td><%= @member.display_name %></td></tr>
|
||||
<tr><td><%= t('members.attributes.email') %></td><td><%= @member.email %></td></tr>
|
||||
<tr><td><%= t('members.attributes.category') %></td><td><%= @member.category %></td></tr>
|
||||
<tr><td><%= t('members.attributes.identification_number') %></td><td><%= @member.identification_number %></td></tr>
|
||||
<tr><td><%= t('members.attributes.address') %></td><td><%= simple_format @member.address %></td></tr>
|
||||
<tr><td><%= t('members.attributes.joined_on') %></td><td><%= @member.joined_on %></td></tr>
|
||||
<tr><td><%= t('members.attributes.expires_on') %></td><td><%= @member.expires_on %></td></tr>
|
||||
<tr><td><%= t('members.attributes.status') %></td><td><%= @member.status %></td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<%= form_with model: @member, method: :delete do |form| %>
|
||||
<div>
|
||||
<%= form.submit t('members.delete.actions.submit') %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= link_to t('members.delete.actions.go_back'), members_path %>
|
||||
</div>
|
||||
<% end %>
|
@ -14,18 +14,16 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<table id="members">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.number'), 'number.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.status'), 'status.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.email'), 'email.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.display_name'), 'display_name.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.joined_on'), 'joined_on.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.expires_on'), 'expires_on.asc' %></th>
|
||||
<th><%= t('members.index.actions.title') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<table class='zebra'>
|
||||
<tr>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.number'), 'number.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.status'), 'status.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.email'), 'email.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.display_name'), 'display_name.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.joined_on'), 'joined_on.asc' %></th>
|
||||
<th><%= link_to_current_with_sort t('members.attributes.expires_on'), 'expires_on.asc' %></th>
|
||||
<th><%= t('members.index.actions.title') %></th>
|
||||
</tr>
|
||||
<% @members.each do |member| %>
|
||||
<tr id="<%= dom_id member %>">
|
||||
<td><%= member.number %></td>
|
||||
@ -35,9 +33,12 @@
|
||||
<td><%= member.joined_on %></td>
|
||||
<td><%= member.expires_on %></td>
|
||||
<td>
|
||||
<%= link_to t('members.index.actions.show'), member %> |
|
||||
<%= link_to t('members.index.actions.edit'), edit_member_path(member) %> |
|
||||
<%= link_to t('members.index.actions.new_contribution'), new_member_contribution_path(member) %>
|
||||
<ul>
|
||||
<li><%= link_to t('members.index.actions.show'), member %></li>
|
||||
<li><%= link_to t('members.index.actions.edit'), edit_member_path(member) %></li>
|
||||
<li><%= link_to t('members.index.actions.new_contribution'), new_member_contribution_path(member) %></li>
|
||||
<li><%= link_to t('members.index.actions.delete'), delete_member_path(member) %></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<h1><%= t('members.show.title') %></h1>
|
||||
|
||||
<table>
|
||||
<table class='lined'>
|
||||
<tr><td><%= t('members.attributes.display_name') %></td><td><%= @member.display_name %></td></tr>
|
||||
<tr><td><%= t('members.attributes.email') %></td><td><%= @member.email %></td></tr>
|
||||
<tr><td><%= t('members.attributes.category') %></td><td><%= @member.category %></td></tr>
|
||||
@ -19,12 +19,12 @@
|
||||
|
||||
<h2><%= t('members.show.contribution_history') %></h2>
|
||||
|
||||
<table>
|
||||
<table class='zebra'>
|
||||
<tr>
|
||||
<th>Payment date</th>
|
||||
<th>Payment method</th>
|
||||
<th>Payment reference</th>
|
||||
<th>Amount</th>
|
||||
<th><%= t('contributions.attributes.payment_on') %></th>
|
||||
<th><%= t('contributions.attributes.payment_method') %></th>
|
||||
<th><%= t('contributions.attributes.payment_reference') %></th>
|
||||
<th><%= t('contributions.attributes.amount') %></th>
|
||||
</tr>
|
||||
<% @member.contributions.each do |contribution| %>
|
||||
<tr>
|
||||
@ -33,8 +33,31 @@
|
||||
<td><%= contribution.payment_reference %></td>
|
||||
<td>€<%= contribution.eurocents %></td>
|
||||
<td>
|
||||
<%= link_to t('members.show.actions.edit_contribution'), edit_contribution_path(contribution) %>
|
||||
<ul>
|
||||
<li><%= link_to t('members.show.actions.edit_contribution'), edit_contribution_path(contribution) %></div>
|
||||
<li><%= link_to t('members.show.actions.delete_contribution'), delete_contribution_path(contribution) %></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
<h2></h2>
|
||||
|
||||
<h2><%= t('members.show.notifications') %></h2>
|
||||
|
||||
<table class='zebra'>
|
||||
<tr>
|
||||
<th><%= t('notifications.attributes.to_be_sent_on') %></th>
|
||||
<th><%= t('notifications.attributes.template') %></th>
|
||||
<th><%= t('notifications.attributes.status') %></th>
|
||||
</tr>
|
||||
<% @member.notifications.order(to_be_sent_on: :desc).each do |notification| %>
|
||||
<tr>
|
||||
<td><%= notification.to_be_sent_on %></td>
|
||||
<td><code><%= notification.template %></code></td>
|
||||
<td><%= notification_status(notification.status) %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
|
@ -44,6 +44,14 @@ en:
|
||||
unemployed: "Unemployed"
|
||||
student: "Student"
|
||||
retired: "Retired"
|
||||
contributions:
|
||||
new:
|
||||
expires_on_warning: |
|
||||
Adding a contribution will automatically bump the membership expiration
|
||||
date by one year. If it's the first contribution for this member, the
|
||||
join date will be set to the payment date and the expiration date one
|
||||
year after that. You can override the expiration date by setting a date
|
||||
below.
|
||||
notification_mailer:
|
||||
expiration_in_60d:
|
||||
subject: "ANSOL - Pagamento anual de quotas"
|
||||
|
@ -2,6 +2,16 @@ pt:
|
||||
navigation:
|
||||
members: "Lista de membros"
|
||||
members:
|
||||
delete:
|
||||
confirmation_message: |
|
||||
Tens a certeza que queres apagar o registo deste membro
|
||||
permanentemente? Esta acção vai apagar todos os dados pessoais da
|
||||
pessoa em questão, mas não irá apagar o registo de contribuições, caso
|
||||
estas sejam necessárias por motivos legais/fiscais.
|
||||
title: "Remover membro permanentemente"
|
||||
actions:
|
||||
submit: "Confirmar remoção"
|
||||
go_back: "Cancelar"
|
||||
index:
|
||||
title: "Membros"
|
||||
actions:
|
||||
@ -16,6 +26,9 @@ pt:
|
||||
actions:
|
||||
edit: "Editar detalhes"
|
||||
edit_contribution: "Editar"
|
||||
delete_contribution: "Apagar"
|
||||
contribution_history: "Histórico de contribuições"
|
||||
notifications: "Notificações por correio electrónico"
|
||||
edit:
|
||||
title: "Editar detalhes de membro"
|
||||
actions:
|
||||
@ -46,6 +59,34 @@ pt:
|
||||
unemployed: "Desempregado"
|
||||
student: "Estudante"
|
||||
retired: "Reformado"
|
||||
notifications:
|
||||
attributes:
|
||||
to_be_sent_on: Data de envio
|
||||
template: Modelo
|
||||
status: Estado
|
||||
status:
|
||||
sent: Enviada
|
||||
scheduled: Agendada
|
||||
contributions:
|
||||
attributes:
|
||||
amount: Montante
|
||||
payment_on: Data de pagamento
|
||||
payment_method: Método de pagamento
|
||||
payment_reference: Referência
|
||||
edit:
|
||||
member: "Membro"
|
||||
title: "Editar dados de contribuição"
|
||||
actions:
|
||||
submit: "Gravar"
|
||||
new:
|
||||
member: "Membro"
|
||||
title: "Registar contribuição"
|
||||
expires_on_warning: |
|
||||
Ao registar uma contribuição, o sistema estende a data de expiração por
|
||||
um ano automaticamente. Se for a primeira contribuição deste membro, a
|
||||
data de inscrição é automaticamente definida como a data de pagamento,
|
||||
e a data de expiração passa a ser um ano após essa data. Podes definir
|
||||
uma data de expiração manualmente usando o próximo campo.
|
||||
notification_mailer:
|
||||
expiration_in_60d:
|
||||
subject: "ANSOL - Pagamento anual de quotas"
|
||||
|
@ -5,8 +5,15 @@ Rails.application.routes.draw do
|
||||
# root "articles#index"
|
||||
|
||||
resources :members do
|
||||
member do
|
||||
get :delete
|
||||
end
|
||||
resources :contributions, only: [:new, :create]
|
||||
end
|
||||
|
||||
resources :contributions, only: [:edit, :update]
|
||||
resources :contributions, only: [:edit, :update, :destroy] do
|
||||
member do
|
||||
get :delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
7
db/migrate/20220625174250_add_excluded_to_members.rb
Normal file
7
db/migrate/20220625174250_add_excluded_to_members.rb
Normal file
@ -0,0 +1,7 @@
|
||||
class AddExcludedToMembers < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
change_table :members do |t|
|
||||
t.boolean :excluded, default: false
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,6 @@
|
||||
class RemoveNullConstraintsFromMember < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
change_column_null :members, :email, true
|
||||
change_column_null :members, :display_name, true
|
||||
end
|
||||
end
|
7
db/schema.rb
generated
7
db/schema.rb
generated
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2022_06_25_181824) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
enable_extension "plpgsql"
|
||||
@ -28,8 +28,8 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do
|
||||
|
||||
create_table "members", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.serial "number", null: false
|
||||
t.string "email", null: false
|
||||
t.string "display_name", null: false
|
||||
t.string "email"
|
||||
t.string "display_name"
|
||||
t.string "identification_number"
|
||||
t.string "status"
|
||||
t.string "category"
|
||||
@ -40,6 +40,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do
|
||||
t.date "expires_on"
|
||||
t.string "regular_ifthenpay_link"
|
||||
t.string "reduced_ifthenpay_link"
|
||||
t.boolean "excluded", default: false
|
||||
t.index ["email"], name: "index_members_on_email", unique: true
|
||||
t.index ["number"], name: "index_members_on_number", unique: true
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user