diff --git a/app/controllers/admin/disputes_controller.rb b/app/controllers/admin/disputes_controller.rb
new file mode 100644
index 000000000..8061eb890
--- /dev/null
+++ b/app/controllers/admin/disputes_controller.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Admin
+ class DisputesController < BaseController
+ load_and_authorize_resource
+ before_action :set_dispute, only: %i[show edit update destroy]
+
+ # GET /admin/disputes
+ def index
+ params[:q] ||= {}
+ disputes = Dispute.all.order(:domain_name)
+ @q = disputes.search(params[:q])
+ @disputes = @q.result.page(params[:page])
+ @disputes = @disputes.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
+ end
+
+ # GET /admin/disputes/1
+ def show; end
+
+ # GET /admin/disputes/new
+ def new
+ @dispute = Dispute.new
+ end
+
+ # GET /admin/disputes/1/edit
+ def edit; end
+
+ # POST /admin/disputes
+ def create
+ @dispute = Dispute.new(dispute_params)
+
+ if @dispute.save
+ redirect_to @dispute, notice: 'Dispute was successfully created.'
+ else
+ render :new
+ end
+ end
+
+ # PATCH/PUT /admin/disputes/1
+ def update
+ if @dispute.update(dispute_params)
+ redirect_to @dispute, notice: 'Dispute was successfully updated.'
+ else
+ render :edit
+ end
+ end
+
+ # DELETE /admin/disputes/1
+ def destroy
+ @dispute.destroy
+ redirect_to disputes_url, notice: 'Dispute was successfully destroyed.'
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_dispute
+ @dispute = Dispute.find(params[:id])
+ end
+
+ # Only allow a trusted parameter "white list" through.
+ def dispute_params
+ params.require(:dispute).permit(:domain_name, :password, :expires_at, :comment, :created_at)
+ end
+ end
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index a727254ad..0e18f433a 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -100,6 +100,7 @@ class Ability
can :manage, Invoice
can :manage, WhiteIp
can :manage, AccountActivity
+ can :manage, Dispute
can :read, ApiLog::EppLog
can :read, ApiLog::ReppLog
can :update, :pending
diff --git a/app/models/dispute.rb b/app/models/dispute.rb
new file mode 100644
index 000000000..874e46b30
--- /dev/null
+++ b/app/models/dispute.rb
@@ -0,0 +1,5 @@
+class Dispute < ApplicationRecord
+ validates :domain_name, :password, :starts_at, :expires_at, :comment,
+ presence: true
+ validates_uniqueness_of :domain_name, case_sensitive: true
+end
diff --git a/app/views/admin/base/_menu.haml b/app/views/admin/base/_menu.haml
index fa1b50440..a327419fd 100644
--- a/app/views/admin/base/_menu.haml
+++ b/app/views/admin/base/_menu.haml
@@ -32,10 +32,11 @@
%li= link_to t('.zones'), admin_zones_path
%li= link_to t('.blocked_domains'), admin_blocked_domains_path
%li= link_to t('.reserved_domains'), admin_reserved_domains_path
+ %li= link_to t('.disputed_domains'), admin_disputes_path
%li= link_to t('.epp_log'), admin_epp_logs_path(created_after: 'today')
%li= link_to t('.repp_log'), admin_repp_logs_path(created_after: 'today')
%li= link_to t('.que'), '/admin/que'
%ul.nav.navbar-nav.navbar-right
%li= link_to t('.sign_out'), destroy_admin_user_session_path, method: :delete,
- class: 'navbar-link'
\ No newline at end of file
+ class: 'navbar-link'
diff --git a/app/views/admin/disputes/_form.html.erb b/app/views/admin/disputes/_form.html.erb
new file mode 100644
index 000000000..a234c17bc
--- /dev/null
+++ b/app/views/admin/disputes/_form.html.erb
@@ -0,0 +1,58 @@
+<%= form_for([:admin, @dispute], html: { class: 'form-horizontal' }) do |f| %>
+ <%= render 'shared/full_errors', object: @dispute %>
+
+
+
+
+
+
+ <%= t(:general) %>
+
+
+
+
+
+
+
+
+
+ <%= button_tag(t(:save), class: 'btn btn-primary') %>
+
+
+<% end %>
diff --git a/app/views/admin/disputes/edit.haml b/app/views/admin/disputes/edit.haml
new file mode 100644
index 000000000..51d77f0cc
--- /dev/null
+++ b/app/views/admin/disputes/edit.haml
@@ -0,0 +1,3 @@
+= render 'shared/title', name: t(:edit_pw)
+
+= render 'form'
diff --git a/app/views/admin/disputes/index.haml b/app/views/admin/disputes/index.haml
new file mode 100644
index 000000000..63438ad9e
--- /dev/null
+++ b/app/views/admin/disputes/index.haml
@@ -0,0 +1,72 @@
+- content_for :actions do
+ = link_to(t('.new_btn'), new_admin_dispute_path, class: 'btn btn-primary')
+= render 'shared/title', name: t('.title')
+
+.row
+ .col-md-12
+ = search_form_for [:admin, @q], html: { style: 'margin-bottom: 0;', class: 'js-form', autocomplete: 'off' } do |f|
+ .row
+ .col-md-3
+ .form-group
+ = f.label :name
+ = f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', placeholder: t(:name)
+ .col-md-3
+ .form-group
+ = f.label t(:created_at_from)
+ = f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control js-datepicker', placeholder: t(:created_at_from)
+ .col-md-3
+ .form-group
+ = f.label t(:created_at_until)
+ = f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control js-datepicker', placeholder: t(:created_at_until)
+ .row
+ .col-md-3
+ .form-group
+ = label_tag t(:results_per_page)
+ = text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page)
+ .col-md-3{style: 'padding-top: 25px;'}
+ %button.btn.btn-primary
+
+ %span.glyphicon.glyphicon-search
+
+ = link_to(t('.reset_btn'), admin_disputes_path, class: 'btn btn-default')
+%hr
+.row
+ .col-md-12
+ .table-responsive
+ %table.table.table-hover.table-bordered.table-condensed
+ %thead
+ %tr
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'name')
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'password')
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'expires_at')
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'comment')
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'created_at', t(:created_at))
+ %th{class: 'col-xs-2'}
+ = sort_link(@q, 'updated_at', t(:updated_at))
+ %th{class: 'col-xs-2'}
+ = t(:actions)
+ %tbody
+ - @disputes.each do |x|
+ %tr
+ %td= x.domain_name
+ %td= x.password
+ %td= x.expires_at
+ %td= x.comment
+ %td= l(x.created_at, format: :short)
+ %td= l(x.updated_at, format: :short)
+ %td
+ = link_to(t(:edit_pw), edit_admin_dispute_path(id: x.id),
+ class: 'btn btn-primary btn-xs')
+ = link_to(t(:delete), delete_admin_dispute_path(id: x.id),
+ data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger btn-xs')
+.row
+ .col-md-6
+ = paginate @disputes
+ .col-md-6.text-right
+ .pagination
+ = t(:result_count, count: @disputes.total_count)
diff --git a/app/views/admin/disputes/new.haml b/app/views/admin/disputes/new.haml
new file mode 100644
index 000000000..0a57af7be
--- /dev/null
+++ b/app/views/admin/disputes/new.haml
@@ -0,0 +1,3 @@
+= render 'shared/title', name: t(:add_disputed_domain)
+
+= render 'form'
diff --git a/config/locales/admin/disputes.en.yml b/config/locales/admin/disputes.en.yml
new file mode 100644
index 000000000..4073d6e61
--- /dev/null
+++ b/config/locales/admin/disputes.en.yml
@@ -0,0 +1,10 @@
+en:
+ admin:
+ disputes:
+ index:
+ title: Domain disputes
+ new_btn: New domain dispute
+ reset_btn: Reset
+
+ form:
+ password_hint: Generated automatically if left blank
diff --git a/config/locales/admin/menu.en.yml b/config/locales/admin/menu.en.yml
index 2c31a5193..1cb396ed6 100644
--- a/config/locales/admin/menu.en.yml
+++ b/config/locales/admin/menu.en.yml
@@ -13,6 +13,7 @@ en:
zones: Zones
blocked_domains: Blocked domains
reserved_domains: Reserved domains
+ disputed_domains: Domain disputes
epp_log: EPP log
repp_log: REPP log
que: Que
diff --git a/config/locales/en.yml b/config/locales/en.yml
index cf72b1027..f1d2ad817 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -629,6 +629,7 @@ en:
available_verification_url_not_found: 'Available verification url not found, for domain.'
add_reserved_domain: 'Add domain to reserved list'
add_blocked_domain: 'Add domain to blocked list'
+ add_disputed_domain: 'Add domain to disputed list'
edit_pw: 'Edit Pw'
optional: 'Optional'
test_registrar: "Test registrar"
diff --git a/config/routes.rb b/config/routes.rb
index 53d78dfa9..0d2093d36 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,6 +1,7 @@
require_dependency 'epp_constraint'
Rails.application.routes.draw do
+ resources :disputes
# https://github.com/internetee/epp_proxy#translation-of-epp-calls
namespace :epp do
constraints(EppConstraint.new(:session)) do
@@ -258,6 +259,7 @@ Rails.application.routes.draw do
get 'delete'
end
end
+ resources :disputes
resources :registrars do
resources :api_users, except: %i[index]
diff --git a/db/migrate/20200421093637_create_disputes.rb b/db/migrate/20200421093637_create_disputes.rb
new file mode 100644
index 000000000..48cdfae59
--- /dev/null
+++ b/db/migrate/20200421093637_create_disputes.rb
@@ -0,0 +1,14 @@
+class CreateDisputes < ActiveRecord::Migration[5.2]
+ def change
+ create_table :disputes do |t|
+ t.string :domain_name
+ t.string :password
+ t.date :expires_at
+ t.date :starts_at
+ t.text :comment
+ t.datetime :created_at
+
+ t.timestamps
+ end
+ end
+end