Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Mon, Nov 25, 9:13 AM
diff --git a/app/models/record.rb b/app/models/record.rb
index a02cb3b..4152064 100644
--- a/app/models/record.rb
+++ b/app/models/record.rb
@@ -1,144 +1,160 @@
require 'ipaddr'
require_dependency 'drop_privileges_validator'
class Record < ActiveRecord::Base
belongs_to :domain
# Powerdns inserts empty records on slave zones,
# we want to hide them
#
# http://mailman.powerdns.com/pipermail/pdns-users/2013-December/010389.html
default_scope { where.not(type: nil) }
def self.record_types
[
'A', 'AAAA', 'CNAME',
'MX',
'TXT', 'SPF', 'SRV', 'SSHFP',
'SOA', 'NS',
'PTR', 'NAPTR'
]
end
def self.forward_records
record_types - ['SOA', 'PTR']
end
def self.reverse_records
['PTR', 'CNAME', 'TXT', 'NS', 'NAPTR']
end
def self.allowed_record_types
record_types - WebDNS.settings[:prohibit_records_types]
end
validates :name, presence: true
validates :type, inclusion: { in: record_types }
# http://mark.lindsey.name/2009/03/never-use-dns-ttl-of-zero-0.html
validates_numericality_of :ttl,
allow_nil: true, # Default pdns TTL
only_integer: true,
greater_than: 0,
less_than_or_equal_to: 2_147_483_647
# Don't allow the following actions on drop privileges mode
validate :no_touching_for_slave_zones, if: -> { domain.slave? }
validates_drop_privileges :type,
message: 'You cannot touch that record!',
unless: -> { Record.allowed_record_types.include?(type) }
validates_drop_privileges :name,
message: 'You cannot touch top level NS records!',
if: -> { type == 'NS' && domain_record? }
before_validation :guess_reverse_name
before_validation :set_name
after_save :update_zone_serial
after_destroy :update_zone_serial
+
+ # Smart order a list of domains
+ def self.smart_order(records)
+ records.sort_by { |r|
+ [
+ r.domain_record? ? 0 : 1, # Zone records
+ r.name,
+ r.type == 'SOA' ? 0 : 1,
+ r.type == 'NS' ? 0 : 1,
+ record_types.index(r.type), # Friendly type
+ r.prio,
+ r.content
+ ]
+ }
+ end
+
def short
return '' if name == domain.name
return '' if name.blank?
File.basename(name, ".#{domain.name}")
end
def domain_record?
name.blank? || name == domain.name
end
def editable?(by = :user)
return false if domain.slave?
case by
when :user
return false unless Record.allowed_record_types.include?(type)
return false if type == 'NS' && domain_record?
end
true
end
def supports_prio?
false
end
# Create record specific urls for all record types
#
# Overrides default rails STI
def self.model_name
return super if self == Record
Record.model_name
end
def to_dns
[name, ttl, 'IN', type, supports_prio? ? prio : nil, content].compact.join(' ')
end
def to_short_dns
[name, 'IN', type].join(' ')
end
private
# Validations
def no_touching_for_slave_zones
# Allow automatic SOA creation for slave zones
# powerdns needs a valid serial to compare it with master
return if type == 'SOA' && validation_context == :create
errors.add(:type, 'This is a slave zone!')
end
# Hooks
def guess_reverse_name
return if not type == 'PTR'
return if not domain.reverse?
return if name.blank?
reverse = IPAddr.new(name).reverse
self.name = reverse if reverse.end_with?(domain.name)
rescue IPAddr::InvalidAddressError # rubycop:disable HandleExceptions
end
# Powerdns expects full domain names
def set_name
self.name = domain.name if name.blank?
self.name = "#{name}.#{domain.name}" if not name.end_with?(domain.name)
end
def remove_terminating_dot
self.content = content.gsub(/\.+\Z/, '')
end
def update_zone_serial
# SOA records handle serial themselves
return true if type == 'SOA'
domain.soa.bump_serial!
end
end
diff --git a/app/views/domains/show.html.erb b/app/views/domains/show.html.erb
index d6f46e0..38aea61 100644
--- a/app/views/domains/show.html.erb
+++ b/app/views/domains/show.html.erb
@@ -1,44 +1,44 @@
<table class="table table-striped table-hover">
<thead>
<tr>
<th colspan="6">Records</th>
<th colspan="3"><%= 'Controls' if !@domain.slave? %></th>
</tr>
</thead>
<tbody>
- <% @domain.records.each do |record| %>
+ <% Record.smart_order(@domain.records).each do |record| %>
<tr class="<%= record.disabled? ? 'warning' : '' %>">
<td><%= record.name %></td>
<td><%= record.ttl %></td>
<td>IN</td>
<td><%= record.type %></td>
<td><%= record.supports_prio? ? record.prio : '' %></td>
<td><%= record.content %></td>
<% if can_edit?(record) %>
<td>
<% if record.disabled? %>
<%= link_to_enable enable_domain_record_path(@domain, record), method: :put %>
<% else %>
<%= link_to_disable disable_domain_record_path(@domain, record), method: :put %>
<% end %>
</td>
<td><%= link_to_edit edit_domain_record_path(@domain, record) if can_edit?(record) %></td>
<td><%= link_to_destroy [@domain, record], method: :delete, data: { confirm: 'Are you sure?' } %></td>
<% else %>
<td/>
<td/>
<td/>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<p>
<%= link_to 'Add Record', '#new_record', class: 'btn btn-primary', onclick: '$("#new_record_wrapper").toggleClass("hidden");' %>
</p>
<div class="jumbotron hidden" id="new_record_wrapper">
<%= render 'records/form' %>
</div>

Event Timeline