From 231159a6c697169bd7740a7d364cd1eb105cfbd0 Mon Sep 17 00:00:00 2001 From: "Michael Kaufmann (d00p)" Date: Tue, 6 Mar 2018 14:02:27 +0100 Subject: [PATCH] added first methods of Emails ApiCommand Signed-off-by: Michael Kaufmann (d00p) --- customer_email.php | 75 +------ lib/classes/api/commands/class.Emails.php | 230 ++++++++++++++++++++++ lib/classes/api/commands/class.Ftps.php | 6 +- phpunit.xml | 1 + tests/Emails/EmailsTest.php | 44 +++++ 5 files changed, 285 insertions(+), 71 deletions(-) create mode 100644 lib/classes/api/commands/class.Emails.php create mode 100644 tests/Emails/EmailsTest.php diff --git a/customer_email.php b/customer_email.php index 02517fc1..efed543a 100644 --- a/customer_email.php +++ b/customer_email.php @@ -205,76 +205,13 @@ if ($page == 'overview') { } elseif ($action == 'add') { if ($userinfo['emails_used'] < $userinfo['emails'] || $userinfo['emails'] == '-1') { if (isset($_POST['send']) && $_POST['send'] == 'send') { - $email_part = $_POST['email_part']; - // domain does not need idna encoding as the value of the select-box is already Punycode - $domain = validate($_POST['domain'], 'domain'); - $stmt = Database::prepare("SELECT `id`, `domain`, `customerid` FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE `domain`= :domain - AND `customerid`= :customerid - AND `isemaildomain`='1' " - ); - $domain_check = Database::pexecute_first($stmt, array("domain" => $domain, "customerid" => $userinfo['customerid'])); - - if (isset($_POST['iscatchall']) && $_POST['iscatchall'] == '1') { - $iscatchall = '1'; - $email = '@' . $domain; - } else { - $iscatchall = '0'; - $email = $email_part . '@' . $domain; - } - - $email_full = $email_part . '@' . $domain; - - if (!validateEmail($email_full)) { - standard_error('emailiswrong', $email_full); - } - - $stmt = Database::prepare("SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "` - WHERE (`email` = :email - OR `email_full` = :emailfull ) - AND `customerid`= :cid" - ); - $params = array( - "email" => $email, - "emailfull" => $email_full, - "cid" => $userinfo['customerid'] - ); - $email_check = Database::pexecute_first($stmt, $params); - - if ($email == '' || $email_full == '' || $email_part == '') { - standard_error(array('stringisempty', 'emailadd')); - } elseif ($domain == '') { - standard_error('domaincantbeempty'); - } elseif ($domain_check['domain'] != $domain) { - standard_error('maindomainnonexist', $domain); - } elseif (strtolower($email_check['email_full']) == strtolower($email_full)) { - standard_error('emailexistalready', $email_full); - } elseif ($email_check['email'] == $email) { - standard_error('youhavealreadyacatchallforthisdomain'); - } else { - $stmt = Database::prepare("INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` - (`customerid`, `email`, `email_full`, `iscatchall`, `domainid`) - VALUES (:cid, :email, :email_full, :iscatchall, :domainid)" - ); - $params = array( - "cid" => $userinfo['customerid'], - "email" => $email, - "email_full" => $email_full, - "iscatchall" => $iscatchall, - "domainid" => $domain_check['id'] - ); - Database::pexecute($stmt, $params); - - $address_id = Database::lastInsertId(); - $stmt = Database::prepare("UPDATE " . TABLE_PANEL_CUSTOMERS . " - SET `emails_used` = `emails_used` + 1 - WHERE `customerid`= :cid" - ); - Database::pexecute($stmt, array("cid" => $userinfo['customerid'])); - - $log->logAction(USR_ACTION, LOG_INFO, "added email address '" . $email_full . "'"); - redirectTo($filename, array('page' => $page, 'action' => 'edit', 'id' => $address_id, 's' => $s)); + try { + $json_result = Emails::getLocal($userinfo, $_POST)->add(); + } catch (Exception $e) { + dynamic_error($e->getMessage()); } + $result = json_decode($json_result, true)['data']; + redirectTo($filename, array('page' => $page, 'action' => 'edit', 'id' => $result['id'], 's' => $s)); } else { $result_stmt = Database::prepare("SELECT `id`, `domain`, `customerid` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid`= :cid diff --git a/lib/classes/api/commands/class.Emails.php b/lib/classes/api/commands/class.Emails.php new file mode 100644 index 00000000..ce45ab72 --- /dev/null +++ b/lib/classes/api/commands/class.Emails.php @@ -0,0 +1,230 @@ + (2010-) + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package API + * @since 0.10.0 + * + */ +class Emails extends ApiCommand implements ResourceEntity +{ + + /** + * add a new email address + * + * @access admin, customer + * @throws Exception + * @return array + */ + public function add() + { + if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) { + throw new Exception("You cannot access this resource", 405); + } + + if ($this->getUserDetail('emails_used') < $this->getUserDetail('emails') || $this->getUserDetail('emails') == '-1') { + + // required parameters + $email_part = $this->getParam('email_part'); + $domain = $this->getParam('domain'); + + // parameters + $iscatchall = $this->getParam('iscatchall', true, 0); + + // validation + if (substr($domain, 0, 4) != 'xn--') { + $idna_convert = new idna_convert_wrapper(); + $domain = $idna_convert->encode(validate($domain, 'domain', '', '', array(), true)); + } + + // check domain and whether it's an email-enabled domain + $domain_check = $this->apiCall('SubDomains.get', array( + 'domainname' => $domain + )); + if ($domain_check['isemaildomain'] == 0) { + standard_error('maindomainnonexist', $domain, true); + } + + // check for catchall-flag + if ($iscatchall) { + $iscatchall = '1'; + $email = '@' . $domain; + } else { + $iscatchall = '0'; + $email = $email_part . '@' . $domain; + } + + // full email value + $email_full = $email_part . '@' . $domain; + + // validate it + if (!validateEmail($email_full)) { + standard_error('emailiswrong', $email_full, true); + } + + // get needed customer info to reduce the email-address-counter by one + if ($this->isAdmin()) { + // get customer id + $customer_id = $this->getParam('customer_id'); + $customer = $this->apiCall('Customers.get', array( + 'id' => $customer_id + )); + // check whether the customer has enough resources to get the ftp-user added + if ($customer['emails_used'] >= $customer['emails'] && $customer['emails'] != '-1') { + throw new Exception("Customer has no more resources available", 406); + } + } else { + $customer_id = $this->getUserDetail('customerid'); + $customer = $this->getUserData(); + } + + // duplicate check + $stmt = Database::prepare(" + SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "` + WHERE (`email` = :email OR `email_full` = :emailfull ) + AND `customerid`= :cid + "); + $params = array( + "email" => $email, + "emailfull" => $email_full, + "cid" => $customer['customerid'] + ); + $email_check = Database::pexecute_first($stmt, $params, true, true); + + if (strtolower($email_check['email_full']) == strtolower($email_full)) { + standard_error('emailexistalready', $email_full, true); + } elseif ($email_check['email'] == $email) { + standard_error('youhavealreadyacatchallforthisdomain', '', true); + } + + $stmt = Database::prepare(" + INSERT INTO `" . TABLE_MAIL_VIRTUAL . "` SET + `customerid` = :cid, + `email` = :email, + `email_full` = :email_full, + `iscatchall` = :iscatchall, + `domainid` = :domainid + "); + $params = array( + "cid" => $customer['customerid'], + "email" => $email, + "email_full" => $email_full, + "iscatchall" => $iscatchall, + "domainid" => $domain_check['id'] + ); + Database::pexecute($stmt, $params, true, true); + $address_id = Database::lastInsertId(); + + // update customer usage + Customers::increaseUsage($customer_id, 'emails_used'); + + // update admin usage + Admins::increaseUsage($customer['adminid'], 'emails_used'); + + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_INFO, "[API] added email address '" . $email_full . "'"); + + $result = $this->apiCall('Emails.get', array( + 'emailaddr' => $email_full + )); + return $this->response(200, "successfull", $result); + } + throw new Exception("No more resources available", 406); + } + + /** + * return a email-address entry by either id or email-address + * + * @param int $id + * optional, the customer-id + * @param string $emailaddr + * optional, the email-address + * + * @access admin, customer + * @throws Exception + * @return array + */ + public function get() + { + $id = $this->getParam('id', true, 0); + $ea_optional = ($id <= 0 ? false : true); + $emailaddr = $this->getParam('emailaddr', $ea_optional, ''); + + $params = array(); + $customer_ids = $this->getAllowedCustomerIds('email'); + $params['customerid'] = implode(", ", $customer_ids); + $params['idea'] = ($id <= 0 ? $emailaddr : $id); + + $result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, u.`quota` + FROM `" . TABLE_MAIL_VIRTUAL . "` v + LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id` + WHERE v.`customerid` IN (:customerid) + AND (v.`id`= :idea OR (v.`email` = :idea OR v.`email_full` = :idea)) + "); + $result = Database::pexecute_first($result_stmt, $params, true, true); + if ($result) { + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_NOTICE, "[API] get email address '" . $result['email_full'] . "'"); + return $this->response(200, "successfull", $result); + } + $key = ($id > 0 ? "id #" . $id : "emailaddr '" . $emailaddr . "'"); + throw new Exception("Email address with " . $key . " could not be found", 404); + } + + public function update() + { + } + + /** + * list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to view, or specify id or loginname for one specific customer + * + * @param int $customerid + * optional, admin-only, select ftp-users of a specific customer by id + * @param string $loginname + * optional, admin-only, select ftp-users of a specific customer by loginname + * + * @access admin, customer + * @throws Exception + * @return array count|list + */ + public function listing() + { + $customer_ids = $this->getAllowedCustomerIds('email'); + $result = array(); + $params['customerid'] = implode(", ", $customer_ids); + $result_stmt = Database::prepare(" + SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, u.`quota`, m.`destination`, m.`popaccountid`, d.`domain`, u.`mboxsize` + FROM `" . TABLE_MAIL_VIRTUAL . "` m + LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`) + LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`) + WHERE m.`customerid` IN (:customerid) + "); + Database::pexecute($result_stmt, $params, true, true); + while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { + $result[] = $row; + } + $this->logger()->logAction($this->isAdmin() ? ADM_ACTION : USR_ACTION, LOG_NOTICE, "[API] list email-addresses"); + return $this->response(200, "successfull", array( + 'count' => count($result), + 'list' => $result + )); + } + + /** + * delete an email address by either id or username + * + * @access admin, customer + * @throws Exception + * @return array + */ + public function delete() + { + } +} diff --git a/lib/classes/api/commands/class.Ftps.php b/lib/classes/api/commands/class.Ftps.php index 6f3223be..56ef099b 100644 --- a/lib/classes/api/commands/class.Ftps.php +++ b/lib/classes/api/commands/class.Ftps.php @@ -75,8 +75,10 @@ class Ftps extends ApiCommand implements ResourceEntity if (Settings::Get('customer.ftpatdomain') == '1') { $ftpusername = validate(trim($ftpusername), 'username', '/^[a-zA-Z0-9][a-zA-Z0-9\-_]+\$?$/', '', array(), true); - $idna_convert = new idna_convert_wrapper(); - $ftpdomain = $idna_convert->encode(validate($ftpdomain, 'domain', '', '', array(), true)); + if (substr($ftpdomain, 0, 4) != 'xn--') { + $idna_convert = new idna_convert_wrapper(); + $ftpdomain = $idna_convert->encode(validate($ftpdomain, 'domain', '', '', array(), true)); + } } $params = array(); diff --git a/phpunit.xml b/phpunit.xml index efedaf51..f1754d3b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -16,6 +16,7 @@ tests/SubDomains tests/Certificates tests/Ftps + tests/Emails diff --git a/tests/Emails/EmailsTest.php b/tests/Emails/EmailsTest.php new file mode 100644 index 00000000..5a07bc1e --- /dev/null +++ b/tests/Emails/EmailsTest.php @@ -0,0 +1,44 @@ + 'test1' + ))->get(); + $customer_userdata = json_decode($json_result, true)['data']; + + $data = [ + 'email_part' => 'info', + 'domain' => 'test2.local' + ]; + $json_result = Emails::getLocal($customer_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertEquals("info@test2.local", $result['email_full']); + $this->assertEquals(0, $result['iscatchall']); + } + + public function testAdminEmailsAdd() + { + global $admin_userdata; + $data = [ + 'email_part' => 'catchall', + 'domain' => 'test2.local', + 'iscatchall' => 1, + 'customer_id' => 1 + ]; + $json_result = Emails::getLocal($admin_userdata, $data)->add(); + $result = json_decode($json_result, true)['data']; + $this->assertEquals("catchall@test2.local", $result['email_full']); + $this->assertEquals(1, $result['iscatchall']); + } +}