diff --git a/migrations/007.php b/migrations/007.php new file mode 100644 index 0000000..6e1e476 --- /dev/null +++ b/migrations/007.php @@ -0,0 +1,9 @@ +database->exec('ALTER TABLE ONLY zone ADD catalog text;'); + +$this->database->exec("INSERT INTO replication_type VALUES (3, 'Producer', 'A producer or catalog zone is a special zone that store the current list of zones assoicated with it. It can be used by secondary servers to update the list of zones for which they are authoritative')"); + +$this->database->exec("INSERT INTO soa_template VALUES (1, 'Producer', 'invalid.', 'invalid.', 3600, 600, 2147483646, 0, 0)"); +$this->database->exec("INSERT INTO ns_template VALUES (1, 'Producer', 'invalid.')"); diff --git a/model/migrationdirectory.php b/model/migrationdirectory.php index 4d49451..83de45d 100644 --- a/model/migrationdirectory.php +++ b/model/migrationdirectory.php @@ -22,7 +22,7 @@ class MigrationDirectory extends DBDirectory { /** * Increment this constant to activate a new migration from the migrations directory */ - const LAST_MIGRATION = 6; + const LAST_MIGRATION = 7; public function __construct() { parent::__construct(); diff --git a/model/zone.php b/model/zone.php index da23521..17718b7 100644 --- a/model/zone.php +++ b/model/zone.php @@ -201,6 +201,7 @@ public function update() { global $config; $update = new StdClass; $update->kind = $this->kind; + $update->catalog = $this->catalog; $update->account = $this->account; if(isset($config['dns']['dnssec']) && $config['dns']['dnssec'] == 1) { $update->dnssec = (bool)$this->dnssec; @@ -648,6 +649,7 @@ public function restore() { $data = new StdClass; $data->name = $this->name; $data->kind = $this->kind; + $data->catalog = $this->catalog; $data->nameservers = array(); $data->rrsets = array(); foreach($rrsets as $rrset) { diff --git a/model/zonedirectory.php b/model/zonedirectory.php index b4ea1d1..68e0171 100644 --- a/model/zonedirectory.php +++ b/model/zonedirectory.php @@ -39,13 +39,14 @@ public function __construct() { * @param Zone $zone to be added */ public function add_zone(Zone $zone) { - $stmt = $this->database->prepare('INSERT INTO zone (pdns_id, name, serial, kind, account, dnssec) VALUES (?, ?, ?, ?, ?, ?)'); + $stmt = $this->database->prepare('INSERT INTO zone (pdns_id, name, serial, kind, account, dnssec, catalog) VALUES (?, ?, ?, ?, ?, ?, ?)'); $stmt->bindParam(1, $zone->pdns_id, PDO::PARAM_STR); $stmt->bindParam(2, $zone->name, PDO::PARAM_STR); $stmt->bindParam(3, $zone->serial, PDO::PARAM_INT); $stmt->bindParam(4, $zone->kind, PDO::PARAM_STR); $stmt->bindParam(5, $zone->account, PDO::PARAM_STR); $stmt->bindParam(6, $zone->dnssec, PDO::PARAM_INT); + $stmt->bindParam(7, $zone->catalog, PDO::PARAM_STR); try { $stmt->execute(); $zone->id = $this->database->lastInsertId('zone_id_seq'); @@ -73,6 +74,7 @@ public function create_zone($zone) { $data = new StdClass; $data->name = $zone->name; $data->kind = $zone->kind; + $data->catalog = $zone->catalog; $data->nameservers = $zone->nameservers; $data->rrsets = array(); foreach($zone->list_resource_record_sets() as $rrset) { @@ -111,6 +113,16 @@ public function create_zone($zone) { syslog_report(LOG_INFO, "zone={$zone->name};object=zone;action=add;status=succeeded"); } + /** + * Zone name comparison function, that will group zones by TLD, then SLD, etc. + * To be used as callback function with e.g. the "uasort" function + */ + private function compare_zones_by_name($a, $b) { + $aname = implode(',', array_reverse(explode('.', punycode_to_utf8($a->name)))); + $bname = implode(',', array_reverse(explode('.', punycode_to_utf8($b->name)))); + return strnatcasecmp($aname, $bname); + } + /** * List all zones in PowerDNS and update list in database to match. * @param array $include list of extra data to include in response @@ -149,6 +161,7 @@ public function list_zones($include = array()) { $zone->pdns_id = $pdns_zone->id; $zone->name = $pdns_zone->name; $zone->kind = $pdns_zone->kind; + $zone->catalog = $pdns_zone->catalog; $zone->serial = $pdns_zone->serial; $zone->account = $pdns_zone->account; $zone->dnssec = $pdns_zone->dnssec; @@ -156,7 +169,7 @@ public function list_zones($include = array()) { $zones_by_pdns_id[$zone->pdns_id] = $zone; $current_zones[$zone->pdns_id] = true; } else { - $fields = array('serial' => PDO::PARAM_INT, 'kind' => PDO::PARAM_STR, 'account' => PDO::PARAM_STR, 'dnssec' => PDO::PARAM_INT); + $fields = array('serial' => PDO::PARAM_INT, 'kind' => PDO::PARAM_STR, 'account' => PDO::PARAM_STR, 'dnssec' => PDO::PARAM_INT, 'catalog' => PDO::PARAM_STR); foreach($fields as $field => $type) { if($zones_by_pdns_id[$pdns_zone->id]->{$field} != $pdns_zone->{$field}) { $zones_by_pdns_id[$pdns_zone->id]->{$field} = $pdns_zone->{$field}; @@ -188,6 +201,41 @@ public function list_zones($include = array()) { } } $this->database->query('COMMIT WORK'); + uasort($zones_by_pdns_id, array($this, 'compare_zones_by_name')); + return $zones_by_pdns_id; + } + + /** + * Fetch the list of zones matching the specific type + * @param string $type of the zones to list + * @return array of Zone objects indexed by pdns_id + */ + public function list_zones_by_kind($type) { + $stmt = $this->database->prepare('SELECT * FROM zone WHERE kind = ?'); + $stmt->bindParam(1, $type, PDO::PARAM_STR); + $stmt->execute(); + $zones_by_pdns_id = array(); + while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $zones_by_pdns_id[$row['pdns_id']] = new Zone($row['id'], $row); + } + uasort($zones_by_pdns_id, array($this, 'compare_zones_by_name')); + return $zones_by_pdns_id; + } + + /** + * Fetch the list of member zones having the specified catalog zone as producer + * @param string $catalog zone to list members + * @return array of member Zone objects indexed by pdns_id + */ + public function list_zones_by_catalog($catalog) { + $stmt = $this->database->prepare('SELECT * FROM zone WHERE catalog = ?'); + $stmt->bindParam(1, $catalog, PDO::PARAM_STR); + $stmt->execute(); + $zones_by_pdns_id = array(); + while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $zones_by_pdns_id[$row['pdns_id']] = new Zone($row['id'], $row); + } + uasort($zones_by_pdns_id, array($this, 'compare_zones_by_name')); return $zones_by_pdns_id; } diff --git a/public_html/extra.js b/public_html/extra.js index 6659f6b..fc2bb5e 100644 --- a/public_html/extra.js +++ b/public_html/extra.js @@ -867,10 +867,45 @@ $(function() { }); }); + // Add template button functionality on zone add and zone soa edit form + // and handle constraints for 'Producer' zones $('form.zoneadd, form.zoneeditsoa').each(function() { + + function set_zone_settings_constraints(form) { + var zone_kind = $('select#kind', form).val() + if (zone_kind == 'Producer') { + $('button.soa-template, button.ns-template', form).each(function() { + $(this).prop('disabled', true) + }); + $('button.soa-template:contains(Producer), ' + + 'button.ns-template:contains(Producer)', form).each(function() { + $(this).prop('disabled', false).click(); + }); + $('#catalog', form).val(''); + $('#dnssec', form).prop('checked', false); + } else { + $('button.soa-template, button.ns-template', form).each(function() { + $(this).prop('disabled', false) + }); + $('button.soa-template:contains(Producer), ' + + 'button.ns-template:contains(Producer)', form).each(function() { + $.each(this.dataset, function(index, value) { $('#' + index).val('') }); + $(this).removeClass('btn-success').addClass('btn-default').prop('disabled', true); + }); + $('button.soa-template[data-default="1"], ' + + 'button.ns-template[data-default="1"]', form).each(function() { + $(this).click(); + }); + } + $('#catalog, #dnssec', form).each(function() { + $(this).prop('disabled', (zone_kind === 'Producer')) + }); + } + var form = $(this); - $('button.soa-template[data-default="1"], button.ns-template[data-default="1"]', form).each(function() { + $('button.soa-template[data-default="1"], ' + + 'button.ns-template[data-default="1"]', form).each(function() { $.each(this.dataset, function(index, value) { $('#' + index).val(value) }); $(this).removeClass('btn-default').addClass('btn-success'); }); @@ -880,6 +915,9 @@ $(function() { $(this).removeClass('btn-default').addClass('btn-success'); }); + set_zone_settings_constraints(form); + $('select#kind', form).on('change', function() { set_zone_settings_constraints(form); }); + $('input#ipv4_zone_prefix').on('keyup', function(event) { if(event.which == 13) prefill_reverse_ipv4_zone($(this)) }); $('button#ipv4_zone_create').on('click', function() { prefill_reverse_ipv4_zone($('input#ipv4_zone_prefix')) }); $('input#ipv6_zone_prefix').on('keyup', function(event) { if(event.which == 13) prefill_reverse_ipv6_zone($(this)) }); @@ -903,7 +941,7 @@ $(function() { $('a[href=#create]').tab('show'); } }); - + $('#changelog-expand-all').on('click', function() { $('table.changelog tbody tr[data-changeset]').each(function() { show_changes($(this), true); diff --git a/templates/template.php b/templates/template.php index 7823fcf..a0a4db4 100644 --- a/templates/template.php +++ b/templates/template.php @@ -23,7 +23,7 @@
Member zone | +Action | +
---|---|
name))?> | ++ | +