Added basic Registrant portal

This commit is contained in:
Priit Tark 2015-05-13 13:02:08 +03:00
parent 90633160c0
commit fdcad95683
28 changed files with 810 additions and 26 deletions

View file

@ -0,0 +1,14 @@
#= require jquery
#= require jquery_ujs
#= require jquery.validate
#= require jquery.validate.additional-methods
#= require turbolinks
#= require bootstrap-sprockets
#= require jquery.nested_attributes
#= require shared/jquery.validate.bootstrap
#= require jquery-ui/datepicker
#= require select2
#= require shared/general
#= require registrar/application

View file

@ -0,0 +1,13 @@
//= require 'shared/general-manifest'
//= require 'registrant/registrant-bootstrap'
//= require 'jquery-ui/datepicker'
//= require 'select2'
//= require 'select2-bootstrap'
@import shared/fonts
@import shared/general
@import nprogress
@import nprogress-bootstrap
@import typeaheadjs
@import selectize
@import selectize.bootstrap3
@import registrant/registrant

View file

@ -0,0 +1,19 @@
$brand-primary: #7EA82F
$navbar-default-bg: #7EA82F
$navbar-default-brand-color: #fff
$navbar-default-link-color: #fff
$border-radius-base: 2px
$body-bg: #F8F8F8
$container-large-desktop: 1040px
$font-family-sans-serif: 'EtelkaLightProRegular', Arial, Helvetica, sans-serif
$font-family-serif: 'EtelkaLightProBold', Georgia, "Times New Roman", Times, serif
$font-size-h1: 26px
$navbar-default-link-active-color: #333
@import 'bootstrap-sprockets'
@import 'bootstrap'
@import 'shared/general-bootstrap'
// Support rails error element
.field_with_errors
@extend .has-error

View file

@ -0,0 +1,34 @@
html
position: relative
min-height: 100%
body
padding-bottom: 130px
body > .container
height: 100%
background: #fff
padding: 60px 30px 30px 30px
h1, h2, h3, h4
margin-bottom: 0px !important
// Commented out, default 20px is needed on forms
// hr
// margin-top: 10px !important
// margin-bottom: 10px !important
.navbar li
font-weight: bold
.footer
position: absolute
bottom: 0
width: 100%
height: 130px
background: image_url('bg.jpg')
color: white !important
background-size: 100%
.semifooter
padding: 42px 0 80px 0

View file

@ -12,11 +12,14 @@ class ApplicationController < ActionController::Base
end
rescue_from CanCan::AccessDenied do |exception|
redirect_to admin_root_path, alert: exception.message if current_user.is_a?(AdminUser)
redirect_to registrar_root_path, alert: exception.message if current_user.is_a?(ApiUser)
redirect_to current_root_url, alert: exception.message
end
helper_method :registrant_request?, :registrar_request?, :admin_request?, :current_root_url
def registrant_request?
request.path.match(/^\/registrant/)
end
helper_method :registrar_request?, :admin_request?
def registrar_request?
request.path.match(/^\/registrar/)
end
@ -25,21 +28,28 @@ class ApplicationController < ActionController::Base
request.path.match(/^\/admin/)
end
def after_sign_in_path_for(_resource)
rt = session[:user_return_to].to_s.presence
login_paths = [admin_login_path, registrar_login_path, '/login']
return rt if rt && !login_paths.include?(rt)
def current_root_url
if registrar_request?
registrar_root_url
elsif registrant_request?
registrar_root_url
elsif admin_request?
admin_root_url
end
end
def after_sign_in_path_for(_resource)
rt = session[:user_return_to].to_s.presence
login_paths = [admin_login_path, registrar_login_path, '/login']
return rt if rt && !login_paths.include?(rt)
current_root_url
end
def after_sign_out_path_for(_resource)
if registrar_request?
registrar_login_url
elsif registrant_request?
registrant_login_url
elsif admin_request?
admin_login_url
end

View file

@ -0,0 +1,32 @@
class Registrant::DeppController < RegistrantController # EPP controller
helper_method :depp_current_user
rescue_from(Errno::ECONNRESET, Errno::ECONNREFUSED) do |_exception|
redirect_to registrant_login_url, alert: t(:no_connection_to_registry)
end
before_action :authenticate_user
def authenticate_user
redirect_to registrant_login_url and return unless depp_current_user
end
def depp_controller?
true
end
def depp_current_user
return nil unless current_user
@depp_current_user ||= Depp::User.new(
tag: current_user.username,
password: current_user.password
)
end
def response_ok?
@data.css('result').each do |x|
success_codes = %(1000, 1001, 1300, 1301)
return false unless success_codes.include?(x['code'])
end
true
end
end

View file

@ -0,0 +1,119 @@
class Registrant::DomainsController < Registrant::DeppController # EPP controller
before_action :init_domain, except: :new
def index
authorize! :view, Depp::Domain
limit, offset = pagination_details
res = depp_current_user.repp_request('domains', { details: true, limit: limit, offset: offset })
if res.code == '200'
@response = res.parsed_body.with_indifferent_access
@contacts = @response ? @response[:contacts] : []
@paginatable_array = Kaminari.paginate_array(
[], total_count: @response[:total_number_of_records]
).page(params[:page]).per(limit)
end
flash.now[:epp_results] = [{ 'code' => res.code, 'msg' => res.message }]
end
def info
authorize! :view, Depp::Domain
@data = @domain.info(params[:domain_name]) if params[:domain_name]
if response_ok?
render 'info'
else
flash[:alert] = t(:domain_not_found)
redirect_to registrant_domains_url and return
end
end
def check
authorize! :view, Depp::Domain
if params[:domain_name]
@data = @domain.check(params[:domain_name])
render 'check_index' and return unless response_ok?
else
render 'check_index'
end
end
def new
authorize! :create, Depp::Domain
@domain_params = Depp::Domain.default_params
end
def create
authorize! :create, Depp::Domain
@domain_params = params[:domain]
@data = @domain.create(@domain_params)
if response_ok?
redirect_to info_registrant_domains_url(domain_name: @domain_params[:name])
else
render 'new'
end
end
def edit
authorize! :update, Depp::Domain
@data = @domain.info(params[:domain_name])
@domain_params = Depp::Domain.construct_params_from_server_data(@data)
end
def update
authorize! :update, Depp::Domain
@domain_params = params[:domain]
@data = @domain.update(@domain_params)
if response_ok?
redirect_to info_registrant_domains_url(domain_name: @domain_params[:name])
else
params[:domain_name] = @domain_params[:name]
render 'new'
end
end
def delete
authorize! :delete, Depp::Domain
end
def destroy
authorize! :delete, Depp::Domain
@data = @domain.delete(params[:domain])
@results = @data.css('result')
if response_ok?
params[:domain_name] = nil
render 'info_index'
else
params[:domain_name] = params[:domain][:name]
render 'delete'
end
end
def renew
authorize! :renew, Depp::Domain
if params[:domain_name] && params[:cur_exp_date]
@data = @domain.renew(params)
render 'renew_index' and return unless response_ok?
else
render 'renew_index'
end
end
def transfer
authorize! :transfer, Depp::Domain
if params[:domain_name]
@data = @domain.transfer(params)
render 'transfer_index' and return unless response_ok?
else
render 'transfer_index'
end
end
private
def init_domain
@domain = Depp::Domain.new(current_user: depp_current_user)
end
end

View file

@ -0,0 +1,130 @@
class Registrant::SessionsController < ::SessionsController
layout 'registrant/application'
helper_method :depp_controller?
def depp_controller?
false
end
def login
@depp_user = Depp::User.new
end
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
def create
@depp_user = Depp::User.new(params[:depp_user].merge(
pki: !Rails.env.development?
)
)
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'].blank?
@depp_user.errors.add(:base, :webserver_missing_user_name_directive)
end
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'] == '(null)'
@depp_user.errors.add(:base, :webserver_user_name_directive_should_be_required)
end
if @depp_user.pki && request.env['HTTP_SSL_CLIENT_S_DN_CN'] != params[:depp_user][:tag]
@depp_user.errors.add(:base, :invalid_cert)
end
if @depp_user.errors.none? && @depp_user.valid?
@api_user = ApiUser.find_by(username: params[:depp_user][:tag])
if @api_user.active?
sign_in @api_user
redirect_to registrant_root_url
else
@depp_user.errors.add(:base, :not_active)
render 'login'
end
else
render 'login'
end
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
def login_mid
@user = User.new
end
def mid
phone = params[:user][:phone]
client = Digidoc::Client.new
if Rails.env.test? && phone == "123"
@user = ApiUser.find_by(identity_code: "14212128025")
sign_in(@user, event: :authentication)
return redirect_to registrant_root_url
end
# country_codes = {'+372' => 'EST'}
response = client.authenticate(
phone: "+372#{phone}",
message_to_display: 'Authenticating',
service_name: 'Testing'
)
if response.faultcode
render json: { message: response.detail.message }, status: :unauthorized
return
end
@user = find_user_by_idc(response.user_id_code)
if @user.persisted?
session[:user_id_code] = response.user_id_code
session[:mid_session_code] = client.session_code
render json: { message: t(:check_your_phone_for_confirmation_code) }, status: :ok
else
render json: { message: t(:no_such_user) }, status: :unauthorized
end
end
# rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/MethodLength
def mid_status
client = Digidoc::Client.new
client.session_code = session[:mid_session_code]
auth_status = client.authentication_status
case auth_status.status
when 'OUTSTANDING_TRANSACTION'
render json: { message: t(:check_your_phone_for_confirmation_code) }, status: :ok
when 'USER_AUTHENTICATED'
@user = find_user_by_idc(session[:user_id_code])
sign_in @user
flash[:notice] = t(:welcome)
flash.keep(:notice)
render js: "window.location = '#{registrant_root_path}'"
when 'NOT_VALID'
render json: { message: t(:user_signature_is_invalid) }, status: :bad_request
when 'EXPIRED_TRANSACTION'
render json: { message: t(:session_timeout) }, status: :bad_request
when 'USER_CANCEL'
render json: { message: t(:user_cancelled) }, status: :bad_request
when 'MID_NOT_READY'
render json: { message: t(:mid_not_ready) }, status: :bad_request
when 'PHONE_ABSENT'
render json: { message: t(:phone_absent) }, status: :bad_request
when 'SENDING_ERROR'
render json: { message: t(:sending_error) }, status: :bad_request
when 'SIM_ERROR'
render json: { message: t(:sim_error) }, status: :bad_request
when 'INTERNAL_ERROR'
render json: { message: t(:internal_error) }, status: :bad_request
else
render json: { message: t(:internal_error) }, status: :bad_request
end
end
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
# rubocop: enable Metrics/MethodLength
def find_user_by_idc(idc)
return User.new unless idc
ApiUser.find_by(identity_code: idc) || User.new
end
end

View file

@ -0,0 +1,16 @@
class RegistrantController < ApplicationController
before_action :authenticate_user!
layout 'registrant/application'
include Registrant::ApplicationHelper
helper_method :depp_controller?
def depp_controller?
false
end
helper_method :head_title_sufix
def head_title_sufix
t(:registrant_head_title_sufix)
end
end

View file

@ -0,0 +1,13 @@
module Registrant::ApplicationHelper
def env_style
return '' if unstable_env.nil?
"background-image: url(#{image_path("registrar/bg-#{unstable_env}.png")});"
end
def pagination_details
params[:page] ||= 1
limit = ENV['depp_records_on_page'] || 20
offset = ((params[:page].to_i - 1) * limit.to_i)
[limit, offset]
end
end

View file

@ -3,8 +3,13 @@ class DomainMailer < ApplicationMailer
return if Rails.env.production? ? false : !TEST_EMAILS.include?(domain.registrant_email)
# turn on delivery on specific request only, thus rake tasks does not deliver anything
return if domain.deliver_emails != true
if domain.registrant_verification_token.blank?
logger.warn "EMAIL DID NOT DELIVERED: registrant_verification_token is missing for #{@domain.name}"
return
end
@old_registrant = Registrant.find(domain.registrant_id_was)
@verification_url = "#{ENV['registrant_url']}/etc/"
@domain = domain
mail(to: @old_registrant.email,

View file

@ -97,6 +97,7 @@ class Epp::Domain < Domain
at[:registrant_id] = regt.id
delivery_date = frame.css('registrant').attr('verified').to_s.downcase == 'yes' ? nil : Time.zone.now
at[:registrant_verification_asked_at] = delivery_date
at[:registrant_verification_token] = SecureRandom.hex(42)
else
add_epp_error('2303', 'registrant', code, [:registrant, :not_found])
end

View file

@ -0,0 +1,46 @@
require 'open3'
# rubocop: disable Metrics/ClassLength
class ApiUser < User
include EppErrors
def epp_code_map # rubocop:disable Metrics/MethodLength
{
'2306' => [ # Parameter policy error
[:password, :blank]
]
}
end
# TODO: should have max request limit per day
belongs_to :registrar
has_many :certificates
validates :username, :password, :registrar, presence: true
validates :username, uniqueness: true
attr_accessor :registrar_typeahead
def ability
@ability ||= Ability.new(self)
end
delegate :can?, :cannot?, to: :ability
after_initialize :set_defaults
def set_defaults
return unless new_record?
self.active = true unless active_changed?
end
def registrar_typeahead
@registrar_typeahead || registrar || nil
end
def to_s
username
end
def queued_messages
registrar.messages.queued
end
end
# rubocop: enable Metrics/ClassLength

View file

@ -16,7 +16,7 @@ Linn: <%= @domain.registrant_city %><br>
Riik: <%= @domain.registrant_country %>
<br><br>
Muudatuse kinnitamiseks külastage palun allolevat võrgulehekülge, kontrollige uuesti üle muudatuse andmed ning vajutage nuppu kinnitan:<br>
https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg
<%= @verification_url %>
<br><br>
Lugupidamisega<br>
Eesti Interneti SA
@ -41,7 +41,7 @@ City: <%= @domain.registrant_city %><br>
Country: <%= @domain.registrant_country %>
<br><br>
To confirm the update please visit this website, once again review the data and press approve:<br>
https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg
<%= @verification_url %>
<br><br>
Best Regards,<br>
Estonian Internet Foundation

View file

@ -16,7 +16,7 @@ Linn: <%= @domain.registrant_city %>
Riik: <%= @domain.registrant_country %>
Muudatuse kinnitamiseks külastage palun allolevat võrgulehekülge, kontrollige uuesti üle muudatuse andmed ning vajutage nuppu kinnitan:
https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg
<%= @verification_url %>
Lugupidamisega
Eesti Interneti SA
@ -41,7 +41,7 @@ City: <%= @domain.registrant_city %>
Country: <%= @domain.registrant_country %>
To confirm the update please visit this website, once again review the data and press approve:
https://testrar.internet.ee/app/owpieruaofaksj298317498324rquhetoiqhepoijfqperyfq9384yuqpohewg
<%= @verification_url %>
Best Regards,
Estonian Internet Foundation

View file

@ -0,0 +1,56 @@
!!! 5
%html{lang: I18n.locale.to_s}
%head
%meta{charset: "utf-8"}/
%meta{content: "IE=edge", "http-equiv" => "X-UA-Compatible"}/
%meta{content: "width=device-width, initial-scale=1", name: "viewport"}/
%meta{content: "Full stack top-level domain (TLD) management.", name: "description"}/
%meta{content: "Gitlab LTD", name: "author"}/
- if content_for? :head_title
= yield :head_title
- else
%title= t(:registrant_head_title)
= csrf_meta_tags
= stylesheet_link_tag 'registrant-manifest', media: 'all', 'data-turbolinks-track' => true
= javascript_include_tag 'registrant-manifest', 'data-turbolinks-track' => true
= favicon_link_tag 'favicon.ico'
%body
/ Fixed navbar
%nav.navbar.navbar-default.navbar-fixed-top
.container
.navbar-header
%button.navbar-toggle.collapsed{"aria-controls" => "navbar", "aria-expanded" => "false", "data-target" => "#navbar", "data-toggle" => "collapse", :type => "button"}
%span.sr-only Toggle navigation
%span.icon-bar
%span.icon-bar
%span.icon-bar
= link_to registrant_root_path, class: 'navbar-brand' do
= t(:registrant_head_title)
- if unstable_env.present?
.text-center
%small{style: 'color: #0074B3;'}= unstable_env
- if current_user
.navbar-collapse.collapse
%ul.nav.navbar-nav.public-nav
- if can? :view, Depp::Domain
- active_class = %w(registrant/domains registrant/check registrant/renew registrant/tranfer registrant/keyrelays).include?(params[:controller]) ? 'active' :nil
%li{class: active_class}= link_to t(:domains), registrant_domains_path
%ul.nav.navbar-nav.navbar-right
- if user_signed_in?
%li= link_to t(:log_out, user: current_user), '/registrant/logout'
.container
= render 'shared/flash'
- if depp_controller?
= render 'registrar/shared/epp_results'
= yield
%footer.footer
.container
%row
.col-md-6
= image_tag 'eis-logo-et.png'
.col-md-6.text-right
Version
= CURRENT_COMMIT_HASH

View file

@ -0,0 +1,46 @@
- content_for :actions do
-# = link_to(t(:new), new_registrant_domain_path, class: 'btn btn-primary')
= render 'shared/title', name: t(:domains)
.row
.col-md-12{style: 'margin-bottom: -15px;'}
= form_tag info_registrant_domains_path, class: 'form-horizontal', method: :get do
.col-md-11
.form-group
= text_field_tag :domain_name, params[:domain_name], class: 'form-control', placeholder: t(:domain_name), autocomplete: 'off', autofocus: true
.col-md-1.text-right.text-center-xs
.form-group
%button.btn.btn-default
&nbsp;
%span.glyphicon.glyphicon-search
&nbsp;
%hr
- if @response
.table-responsive
%table.table.table-hover.table-condensed
%thead
%tr
%th{class: 'col-xs-3'}= t(:name)
%th{class: 'col-xs-6'}= t(:valid)
%th{class: 'col-xs-3'}= t(:actions)
%tbody
- @response['domains'].each do |x|
%tr
%td= link_to(x['name'], info_registrant_domains_path(domain_name: x['name']))
%td
= Time.zone.parse(x['valid_from']).try(:to_date)
\-
= Time.zone.parse(x['valid_to']).try(:to_date)
%td
= link_to(t(:view), info_registrant_domains_path(domain_name: x['name']),
class: 'btn btn-primary btn-xs')
-# = link_to(t(:edit), edit_registrant_domains_path(domain_name: x['name']),
-# class: 'btn btn-primary btn-xs')
-# = link_to(t(:renew), renew_registrant_domains_path(domain_name: x['name']),
-# class: 'btn btn-default btn-xs')
-# = link_to(t(:delete), delete_registrant_domains_path(domain_name: x['name']),
-# class: 'btn btn-default btn-xs')
= paginate @paginatable_array

View file

@ -0,0 +1,26 @@
- content_for :actions do
-# = link_to(t(:edit), edit_registrar_domains_path(domain_name: params[:domain_name]),
-# class: 'btn btn-default')
-# = link_to(t(:renew), renew_registrar_domains_path(domain_name: params[:domain_name]),
-# class: 'btn btn-default')
-# = link_to(t(:delete), delete_registrar_domains_path(domain_name: params[:domain_name]),
-# class: 'btn btn-default')
= render 'shared/title', name: truncate(@data.css('name').text)
.row
.col-sm-12
- if @data.css('result').first['code'] == '1000'
.row
.col-md-12= render 'registrar/domains/partials/general'
.row
.col-md-12= render 'registrar/domains/partials/contacts'
.row
.col-md-12= render 'registrar/domains/partials/statuses'
.row
.col-md-12= render 'registrar/domains/partials/nameservers'
.row
.col-md-12= render 'registrar/domains/partials/dnskeys'
- else
.row
.col-sm-6
%h1= t(:not_found)

View file

@ -0,0 +1,21 @@
.row
.form-signin.col-md-6.center-block.text-center
%h2.form-signin-heading.text-center= t(:log_in)
%hr
= form_for @depp_user, url: registrant_sessions_path, html: {class: 'form-signin'} do |f|
= render 'registrar/shared/errors', object: f.object
- error_class = f.object.errors.any? ? 'has-error' : ''
%div{class: error_class}
= f.text_field :tag, class: 'form-control', placeholder: t(:username), required: true
= f.password_field :password, class: 'form-control', placeholder: t(:password), required: true
%button.btn.btn-lg.btn-primary.btn-block{:type => 'submit'}= t(:log_in)
%hr
= link_to '/regisrant/login/mid' do
= image_tag 'mid.gif'
-# = link_to '/registrant/login/id' do
-# = image_tag 'id_card.gif'

View file

@ -0,0 +1,40 @@
.row
.form-signin.col-md-4.center-block.text-center
%h2.form-signin-heading.text-center= t(:log_in_with_mid)
%hr
= form_for @user, url: registrant_mid_path, auto_html5_validation: false,
html: {class: 'form-signin'} do |f|
= f.text_field :phone, class: 'form-control',
placeholder: t(:phone_no), autocomplete: 'off', required: true
%button.btn.btn-lg.btn-primary.btn-block.js-login{:type => 'submit'}= t(:log_in)
- if ['development', 'alpha'].include?(Rails.env)
%div.text-center
00007, 60000007, 00000766
:coffee
$('.js-login').attr('disabled', false)
status_interval = null
mid_status = () ->
status_interval = setInterval((->
$.post('/registrant/login/mid_status').fail((data) ->
clearInterval(status_interval)
flash_alert(data.responseJSON.message)
$('.js-login').attr('disabled', false)
)
), 1000)
$('.js-login').on 'click', (e) ->
e.preventDefault();
$(this).attr('disabled', true)
$.post($('form').attr('action'), $('form').serialize()).done((data) ->
if data.message
flash_notice(data.message)
mid_status()
).fail((data) ->
flash_alert(data.responseJSON.message)
$('.js-login').attr('disabled', false)
)