<NME> domain-soa.js
<BEF> const test = require('../testlib');

test.run(async function () {
    await test('admin', async function (assert, req) {
        //Try to set soa for non exitent domain
        var res = await req({
            url: '/domains/100/soa',
            method: 'put',
            data: {
                primary: 'ns1.example.com',
                email: 'hostmaster@example.com',
                refresh: 3600,
                retry: 900,
                expire: 604800,
                ttl: 86400
            }
        });

        assert.equal(res.status, 404, 'Updating SOA for not existing domain should fail');

        //Try to set soa for slave domain
        var res = await req({
            url: '/domains/2/soa',
            method: 'put',
            data: {
                primary: 'ns1.example.com',
                email: 'hostmaster@example.com',
                refresh: 3600,
                retry: 900,
                expire: 604800,
                ttl: 86400
            }
        });

        assert.equal(res.status, 405, 'Updating SOA for slave domain should fail');

        //Try to set soa with missing fields
        var res = await req({
            url: '/domains/2/soa',
            method: 'put',
            data: {
                primary: 'ns1.example.com',
                retry: 900,
                expire: 604800,
                ttl: 86400
            }
        });

        assert.equal(res.status, 422, 'Updating SOA with missing fields should fail.');

        //Set soa for zone without one
        var res = await req({
            url: '/domains/1/soa',
            method: 'put',
            data: {
                primary: 'ns1.example.com',
                email: 'hostmaster@example.com',
                refresh: 3600,
                retry: 900,
                expire: 604800,
                ttl: 86400
            }
        });

        assert.equal(res.status, 204, 'Updating SOA for Zone without one should succeed.');
    });
});

<MSG> Added GET /domains/{domainId}/soa

<DFF> @@ -48,20 +48,120 @@ test.run(async function () {
 
         assert.equal(res.status, 422, 'Updating SOA with missing fields should fail.');
 
+        //Getting soa data from master zone without soa should fail
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'get'
+        });
+
+        assert.equal(res.status, 404, 'Not existing soa should trigger error');
+
+        //Getting soa data from slave zone should fail
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'get'
+        });
+
+        assert.equal(res.status, 404, 'Geting soa from slave should trigger error');
+
+        //Soa data for test
+        var soaData = {
+            primary: 'ns1.example.com',
+            email: 'hostmaster@example.com',
+            refresh: 3600,
+            retry: 900,
+            expire: 604800,
+            ttl: 86400
+        };
+
         //Set soa for zone without one
         var res = await req({
             url: '/domains/1/soa',
             method: 'put',
-            data: {
-                primary: 'ns1.example.com',
-                email: 'hostmaster@example.com',
-                refresh: 3600,
-                retry: 900,
-                expire: 604800,
-                ttl: 86400
-            }
+            data: soaData
         });
 
         assert.equal(res.status, 204, 'Updating SOA for Zone without one should succeed.');
+
+        //Get the new soa
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'get'
+        });
+
+        assert.equal(res.status, 200, 'Getting soa should succeed.');
+        const firstSerial = res.data.serial;
+        delete res.data['serial'];
+        assert.equal(res.data, soaData, 'The set and get data should be equal');
+
+        //Soa data for update test
+        soaData = {
+            primary: 'ns2.example.com',
+            email: 'hostmasterFoo@example.com',
+            refresh: 3601,
+            retry: 901,
+            expire: 604801,
+            ttl: 86401
+        };
+
+        //Update soa with new values
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'put',
+            data: soaData
+        });
+
+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed.');
+
+        //Check if update suceeded
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'get'
+        });
+
+        assert.equal(res.status, 200, 'Getting updated soa should succeed.');
+        assert.true(firstSerial < res.data.serial, 'Serial value should increase with update');
+        delete res.data['serial'];
+        assert.equal(res.data, soaData, 'The set and get data should be equal after update');
+    });
+
+    await test('user', async function (assert, req) {
+        //Soa data for test
+        var soaData = {
+            primary: 'ns1.example.com',
+            email: 'hostmaster@example.com',
+            refresh: 3600,
+            retry: 900,
+            expire: 604800,
+            ttl: 86400
+        };
+
+        //Updating soa for domain with permissions should work
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'put',
+            data: soaData
+        });
+
+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed for user.');
+
+        //Get the updated soa
+        var res = await req({
+            url: '/domains/1/soa',
+            method: 'get'
+        });
+
+        assert.equal(res.status, 200, 'Getting soa should succeed for user.');
+        delete res.data['serial'];
+        assert.equal(res.data, soaData, 'The set and get data should be equal');
+
+        //Updating soa for domain with permissions should work
+        var res = await req({
+            url: '/domains/4/soa',
+            method: 'put',
+            data: soaData
+        });
+
+        assert.equal(res.status, 403, 'Updating SOA for Zone without permissions should fail.');
     });
 });
\ No newline at end of file

{'commit': "diff --git a/backend/src/controllers/Domains.php b/backend/src/controllers/Domains.php\nindex cacc780..47d8718 100644\n--- a/backend/src/controllers/Domains.php\n+++ b/backend/src/controllers/Domains.php\n@@ -202,4 +202,27 @@ class Domains\n             return $res->withJson(['error' => 'SOA can not be set for slave domains'], 405);\n         }\n     }\n+\n+    public function getSoa(Request $req, Response $res, array $args)\n+    {\n+        $userId = $req->getAttribute('userId');\n+        $domainId = $args['domainId'];\n+\n+        $ac = new \\Operations\\AccessControl($this->c);\n+        if (!$ac->canAccessDomain($userId, $domainId)) {\n+            $this->logger->info('Non admin user tries to get domain without permission.');\n+            return $res->withJson(['error' => 'You have no permissions for this domain.'], 403);\n+        }\n+\n+        $soa = new \\Operations\\Soa($this->c);\n+\n+        try {\n+            $soaArray = $soa->getSoa($domainId);\n+\n+            return $res->withJson($soaArray, 200);\n+        } catch (\\Exceptions\\NotFoundException $e) {\n+            $this->logger->debug('User tried to get non existing soa.', ['domainId' => $domainId]);\n+            return $res->withJson(['error' => 'This domain has no soa record.'], 404);\n+        }\n+    }\n }\ndiff --git a/backend/src/operations/Soa.php b/backend/src/operations/Soa.php\nindex 080b426..c02a470 100644\n--- a/backend/src/operations/Soa.php\n+++ b/backend/src/operations/Soa.php\n@@ -110,6 +110,38 @@ class Soa\n         $this->db->commit();\n     }\n \n+    /**\n+     * Get soa record for domain\n+     * \n+     * @param   $domainId   Domain to get soa from\n+     * \n+     * @return  array       Soa data as associative array\n+     */\n+    public function getSoa(int $domainId)\n+    {\n+        $query = $this->db->prepare('SELECT content FROM records WHERE domain_id=:domainId AND type=\\'SOA\\'');\n+        $query->bindValue(':domainId', $domainId, \\PDO::PARAM_INT);\n+        $query->execute();\n+\n+        $record = $query->fetch();\n+\n+        if ($record === false) {\n+            throw new \\Exceptions\\NotFoundException();\n+        }\n+\n+        $soaArray = explode(' ', $record['content']);\n+\n+        return [\n+            'primary' => $soaArray[0],\n+            'email' => $this->toEmail($soaArray[1]),\n+            'serial' => intval($soaArray[2]),\n+            'refresh' => intval($soaArray[3]),\n+            'retry' => intval($soaArray[4]),\n+            'expire' => intval($soaArray[5]),\n+            'ttl' => intval($soaArray[6])\n+        ];\n+    }\n+\n     /**\n      * Increases the serial number of the given domain to the next required.\n      * \ndiff --git a/backend/src/public/index.php b/backend/src/public/index.php\nindex 4b97a8c..e2132ac 100644\n--- a/backend/src/public/index.php\n+++ b/backend/src/public/index.php\n@@ -34,6 +34,7 @@ $app->group('/v1', function () {\n         $this->put('/domains/{domainId}', '\\Controllers\\Domains:put');\n \n         $this->put('/domains/{domainId}/soa', '\\Controllers\\Domains:putSoa');\n+        $this->get('/domains/{domainId}/soa', '\\Controllers\\Domains:getSoa');\n     })->add('\\Middlewares\\Authentication');\n });\n \ndiff --git a/backend/test/tests/domain-soa.js b/backend/test/tests/domain-soa.js\nindex 3f52d43..e76f7f3 100644\n--- a/backend/test/tests/domain-soa.js\n+++ b/backend/test/tests/domain-soa.js\n@@ -48,20 +48,120 @@ test.run(async function () {\n \n         assert.equal(res.status, 422, 'Updating SOA with missing fields should fail.');\n \n+        //Getting soa data from master zone without soa should fail\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 404, 'Not existing soa should trigger error');\n+\n+        //Getting soa data from slave zone should fail\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 404, 'Geting soa from slave should trigger error');\n+\n+        //Soa data for test\n+        var soaData = {\n+            primary: 'ns1.example.com',\n+            email: 'hostmaster@example.com',\n+            refresh: 3600,\n+            retry: 900,\n+            expire: 604800,\n+            ttl: 86400\n+        };\n+\n         //Set soa for zone without one\n         var res = await req({\n             url: '/domains/1/soa',\n             method: 'put',\n-            data: {\n-                primary: 'ns1.example.com',\n-                email: 'hostmaster@example.com',\n-                refresh: 3600,\n-                retry: 900,\n-                expire: 604800,\n-                ttl: 86400\n-            }\n+            data: soaData\n         });\n \n         assert.equal(res.status, 204, 'Updating SOA for Zone without one should succeed.');\n+\n+        //Get the new soa\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting soa should succeed.');\n+        const firstSerial = res.data.serial;\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal');\n+\n+        //Soa data for update test\n+        soaData = {\n+            primary: 'ns2.example.com',\n+            email: 'hostmasterFoo@example.com',\n+            refresh: 3601,\n+            retry: 901,\n+            expire: 604801,\n+            ttl: 86401\n+        };\n+\n+        //Update soa with new values\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed.');\n+\n+        //Check if update suceeded\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting updated soa should succeed.');\n+        assert.true(firstSerial < res.data.serial, 'Serial value should increase with update');\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal after update');\n+    });\n+\n+    await test('user', async function (assert, req) {\n+        //Soa data for test\n+        var soaData = {\n+            primary: 'ns1.example.com',\n+            email: 'hostmaster@example.com',\n+            refresh: 3600,\n+            retry: 900,\n+            expire: 604800,\n+            ttl: 86400\n+        };\n+\n+        //Updating soa for domain with permissions should work\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed for user.');\n+\n+        //Get the updated soa\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting soa should succeed for user.');\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal');\n+\n+        //Updating soa for domain with permissions should work\n+        var res = await req({\n+            url: '/domains/4/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 403, 'Updating SOA for Zone without permissions should fail.');\n     });\n });\n\\ No newline at end of file\n", 'commit_subject': 'Added GET /domains/{domainId}/soa', 'repo_name': 'loewexy/pdnsmanager', 'committer': {'name': 'Lukas Metzger', 'email': '3dacbce532ccd48f27fa62e993067b3c35f094f7@lukas-metzger.com', 'time_sec': '1522088085', 'tz_offset': '120', 'date': {'seconds': '1522088085'}}, 'commit_tree': '99d7a99daaa3785d76fca6def7042613867bd4ca', 'commit_message': 'Added GET /domains/{domainId}/soa\n', 'language_name': 'Shell', 'license': 'apache-2.0', 'hunks': "@@ -48,20 +48,120 @@ test.run(async function () {\n \n         assert.equal(res.status, 422, 'Updating SOA with missing fields should fail.');\n \n+        //Getting soa data from master zone without soa should fail\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 404, 'Not existing soa should trigger error');\n+\n+        //Getting soa data from slave zone should fail\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 404, 'Geting soa from slave should trigger error');\n+\n+        //Soa data for test\n+        var soaData = {\n+            primary: 'ns1.example.com',\n+            email: 'hostmaster@example.com',\n+            refresh: 3600,\n+            retry: 900,\n+            expire: 604800,\n+            ttl: 86400\n+        };\n+\n         //Set soa for zone without one\n         var res = await req({\n             url: '/domains/1/soa',\n             method: 'put',\n-            data: {\n-                primary: 'ns1.example.com',\n-                email: 'hostmaster@example.com',\n-                refresh: 3600,\n-                retry: 900,\n-                expire: 604800,\n-                ttl: 86400\n-            }\n+            data: soaData\n         });\n \n         assert.equal(res.status, 204, 'Updating SOA for Zone without one should succeed.');\n+\n+        //Get the new soa\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting soa should succeed.');\n+        const firstSerial = res.data.serial;\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal');\n+\n+        //Soa data for update test\n+        soaData = {\n+            primary: 'ns2.example.com',\n+            email: 'hostmasterFoo@example.com',\n+            refresh: 3601,\n+            retry: 901,\n+            expire: 604801,\n+            ttl: 86401\n+        };\n+\n+        //Update soa with new values\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed.');\n+\n+        //Check if update suceeded\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting updated soa should succeed.');\n+        assert.true(firstSerial < res.data.serial, 'Serial value should increase with update');\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal after update');\n+    });\n+\n+    await test('user', async function (assert, req) {\n+        //Soa data for test\n+        var soaData = {\n+            primary: 'ns1.example.com',\n+            email: 'hostmaster@example.com',\n+            refresh: 3600,\n+            retry: 900,\n+            expire: 604800,\n+            ttl: 86400\n+        };\n+\n+        //Updating soa for domain with permissions should work\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 204, 'Updating SOA for Zone should succeed for user.');\n+\n+        //Get the updated soa\n+        var res = await req({\n+            url: '/domains/1/soa',\n+            method: 'get'\n+        });\n+\n+        assert.equal(res.status, 200, 'Getting soa should succeed for user.');\n+        delete res.data['serial'];\n+        assert.equal(res.data, soaData, 'The set and get data should be equal');\n+\n+        //Updating soa for domain with permissions should work\n+        var res = await req({\n+            url: '/domains/4/soa',\n+            method: 'put',\n+            data: soaData\n+        });\n+\n+        assert.equal(res.status, 403, 'Updating SOA for Zone without permissions should fail.');\n     });\n });\n\\ No newline at end of file\n", 'addition_count': 108, 'deletion_count': 8, 'src_file': 'a/backend/test/tests/domain-soa.js', 'tgt_file': 'b/backend/test/tests/domain-soa.js', 'file_extension': '.js', 'before_file': "const test = require('../testlib');\n\ntest.run(async function () {\n    await test('admin', async function (assert, req) {\n        //Try to set soa for non exitent domain\n        var res = await req({\n            url: '/domains/100/soa',\n            method: 'put',\n            data: {\n                primary: 'ns1.example.com',\n                email: 'hostmaster@example.com',\n                refresh: 3600,\n                retry: 900,\n                expire: 604800,\n                ttl: 86400\n            }\n        });\n\n        assert.equal(res.status, 404, 'Updating SOA for not existing domain should fail');\n\n        //Try to set soa for slave domain\n        var res = await req({\n            url: '/domains/2/soa',\n            method: 'put',\n            data: {\n                primary: 'ns1.example.com',\n                email: 'hostmaster@example.com',\n                refresh: 3600,\n                retry: 900,\n                expire: 604800,\n                ttl: 86400\n            }\n        });\n\n        assert.equal(res.status, 405, 'Updating SOA for slave domain should fail');\n\n        //Try to set soa with missing fields\n        var res = await req({\n            url: '/domains/2/soa',\n            method: 'put',\n            data: {\n                primary: 'ns1.example.com',\n                retry: 900,\n                expire: 604800,\n                ttl: 86400\n            }\n        });\n\n        assert.equal(res.status, 422, 'Updating SOA with missing fields should fail.');\n\n        //Set soa for zone without one\n        var res = await req({\n            url: '/domains/1/soa',\n            method: 'put',\n            data: {\n                primary: 'ns1.example.com',\n                email: 'hostmaster@example.com',\n                refresh: 3600,\n                retry: 900,\n                expire: 604800,\n                ttl: 86400\n            }\n        });\n\n        assert.equal(res.status, 204, 'Updating SOA for Zone without one should succeed.');\n    });\n});\n", 'message': 'Added GET /domains/{domainId}/soa\n', 'author_name': 'Lukas Metzger', 'lang': 'js'}