Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Sun, May 18, 4:28 PM
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 137bdd4..5a70282 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -1,17 +1,30 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery.min
//= require jquery_ujs
//= require bootstrap.min
//= require typeahead.bundle.min
//= require_tree .
+
+$(function() {
+
+ // Show priority on MX record only
+ $('#record_type').change(function() {
+ if ($(this).val() == 'MX') {
+ $('#record_prio').parents('div.form-group').removeClass('hidden');
+ } else {
+ $('#record_prio').parents('div.form-group').addClass('hidden');
+ }
+ });
+
+});
diff --git a/app/controllers/records_controller.rb b/app/controllers/records_controller.rb
index 7ce17fa..0d2881e 100644
--- a/app/controllers/records_controller.rb
+++ b/app/controllers/records_controller.rb
@@ -1,56 +1,56 @@
class RecordsController < ApplicationController
before_action :set_domain
before_action :set_record, only: [:edit, :update, :destroy]
# GET /records/new
def new
@record = @domain.records.build
end
# GET /records/1/edit
def edit
end
# POST /records
def create
@record = @domain.records.new(new_record_params)
if @record.save
redirect_to @domain, notice: 'Record was successfully created.'
else
render :new
end
end
# PATCH/PUT /records/1
def update
if @record.update(edit_record_params)
redirect_to @domain, notice: 'Record was successfully updated.'
else
render :edit
end
end
# DELETE /records/1
def destroy
@record.destroy
redirect_to @domain, notice: 'Record was successfully destroyed.'
end
private
def set_record
@record = @domain.records.find(params[:id])
end
def set_domain
@domain = Domain.find(params[:domain_id])
end
def edit_record_params
- params.require(:record).permit(:name, :content)
+ params.require(:record).permit(:name, :content, :prio)
end
def new_record_params
- params.require(:record).permit(:name, :content, :type)
+ params.require(:record).permit(:name, :content, :type, :prio)
end
end
diff --git a/app/models/mx.rb b/app/models/mx.rb
new file mode 100644
index 0000000..15855a6
--- /dev/null
+++ b/app/models/mx.rb
@@ -0,0 +1,9 @@
+class MX < Record
+ validates :content, presence: true, hostname: true
+ validates :name, presence: true, hostname: true
+ validates :prio, presence: true, prio: true
+
+ def supports_prio?
+ true
+ end
+end
diff --git a/app/models/record.rb b/app/models/record.rb
index faf9fdd..46b6829 100644
--- a/app/models/record.rb
+++ b/app/models/record.rb
@@ -1,54 +1,58 @@
class Record < ActiveRecord::Base
belongs_to :domain
def self.record_types
[
'SOA', 'NS', 'CNAME',
'A', 'AAAA',
'MX',
'TXT', 'SPF', 'SRV', 'SSHFP',
'PTR',
]
end
validates :name, presence: true
validates :type, inclusion: { in: record_types }
before_validation :set_name
after_save :update_zone_serial
after_destroy :update_zone_serial
def short
return '' if name == domain.name
return '' if name.blank?
File.basename(name, ".#{domain.name}")
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
private
# Hooks
# 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 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 b1cef23..42a3499 100644
--- a/app/views/domains/show.html.erb
+++ b/app/views/domains/show.html.erb
@@ -1,23 +1,24 @@
<table class="table table-striped">
<thead>
<tr>
- <th colspan="4">Records</th>
+ <th colspan="5">Records</th>
<th colspan="2">Controls</th>
</tr>
</thead>
<tbody>
<% @domain.records.each do |record| %>
<tr>
<td><%= record.name %></td>
<td>IN</td>
<td><%= record.type %></td>
+ <td><%= record.supports_prio? ? record.prio : '' %></td>
<td><%= record.content %></td>
<td><%= link_to 'Edit', edit_domain_record_path(@domain, record) %></td>
<td><%= link_to 'Remove', [@domain, record], method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<p><%= link_to 'New Record', new_domain_record_path(@domain) %></p>
diff --git a/app/views/records/_form.html.erb b/app/views/records/_form.html.erb
index 75cf980..6388a97 100644
--- a/app/views/records/_form.html.erb
+++ b/app/views/records/_form.html.erb
@@ -1,13 +1,14 @@
<%= bootstrap_form_for([@domain, @record], layout: :horizontal, label_col: 'col-sm-2', control_col: 'col-sm-4') do |f| %>
<%= f.text_field :name, value: @record.short, label: 'Record', append: ".#{@domain.name}" %>
<% if @record.persisted? %>
<%= f.static_control :type %>
<% else %>
<%= f.select :type, Record.record_types %>
<% end %>
+ <%= f.text_field :prio, placeholder: 10, wrapper_class: 'hidden' %>
<%= f.text_field :content %>
<%= f.submit 'Save', class: 'btn btn-primary col-sm-offset-2' %>
<% end %>
diff --git a/lib/prio_validator.rb b/lib/prio_validator.rb
new file mode 100644
index 0000000..f2395b6
--- /dev/null
+++ b/lib/prio_validator.rb
@@ -0,0 +1,18 @@
+# Prio should be between [0, 65535]
+class PrioValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ # Rails autocasts integer fields to 0 if a non-numerical value is passed
+ # we override that by using th *_before_type_cast helper method
+ before_cast = :"#{attribute}_before_type_cast"
+ raw_value = record.send(before_cast) if record.respond_to?(before_cast)
+ raw_value ||= value
+
+ val = Integer(raw_value)
+ if val < 0 || val > 65_535
+ record.errors[attribute] << 'is not a valid DNS priority [0, 65535]'
+ end
+
+ rescue ArgumentError, TypeError
+ record.errors[attribute] << 'is not a valid DNS priority [0, 65535]'
+ end
+end
diff --git a/test/factories/mx.rb b/test/factories/mx.rb
new file mode 100644
index 0000000..204ac0d
--- /dev/null
+++ b/test/factories/mx.rb
@@ -0,0 +1,8 @@
+FactoryGirl.define do
+ factory :mx, class: 'MX' do
+ domain
+ name ''
+ prio 10
+ content 'ns.example.com'
+ end
+end
diff --git a/test/models/mx_test.rb b/test/models/mx_test.rb
new file mode 100644
index 0000000..68f8d6e
--- /dev/null
+++ b/test/models/mx_test.rb
@@ -0,0 +1,41 @@
+require 'test_helper'
+
+class MXTest < ActiveSupport::TestCase
+
+ test 'saves' do
+ rec = build(:mx)
+ rec.valid?
+ assert_empty rec.errors
+ assert rec.save
+ end
+
+ test 'supports prio' do
+ rec = build(:mx)
+ assert rec.supports_prio?, 'supports prio'
+ end
+
+ [
+ 0,
+ 10,
+ 65_535,
+ ].each { |prio|
+ test "valid prio #{prio}" do
+ rec = build(:mx, prio: prio)
+ rec.valid?
+ assert_empty rec.errors[:prio], "#{prio} should be valid!"
+ end
+ }
+
+ [
+ -10,
+ 65_535 + 1,
+ 'str',
+ ].each { |prio|
+ test "invalid prio #{prio}" do
+ rec = build(:mx, prio: prio)
+ rec.valid?
+ assert_not_empty rec.errors[:prio], "#{prio} should be invalid!"
+ end
+ }
+
+end

Event Timeline