* * This source file is subject to the GPL-3.0 license that is bundled * with this source code in the file LICENSE. */ namespace controllers\publics; /** * Api to interact with raspisms. */ class Api extends \descartes\ApiController { const DEFAULT_RETURN = [ 'error' => 0, //Error code 'message' => null, //Any message to describe a potential error 'response' => null, //The content of the response 'next' => null, //Link to the next results 'prev' => null, //Link to the previous results ]; const ERROR_CODES = [ 'NONE' => 0, 'INVALID_CREDENTIALS' => 1, 'INVALID_PARAMETER' => 2, 'MISSING_PARAMETER' => 4, 'CANNOT_CREATE' => 8, 'SUSPENDED_USER' => 16, ]; const ERROR_MESSAGES = [ 'INVALID_CREDENTIALS' => 'Invalid API Key. Please provide a valid API as GET parameter "api_key".', 'INVALID_PARAMETER' => 'You have specified an invalid parameter : ', 'MISSING_PARAMETER' => 'One require parameter is missing : ', 'CANNOT_CREATE' => 'Cannot create a new entry.', 'SUSPENDED_USER' => 'This user account is currently suspended.', ]; private $internal_user; private $internal_phone; private $internal_received; private $internal_sended; private $internal_scheduled; private $internal_contact; private $internal_group; private $internal_conditional_group; private $user; /** * Construct the object and quit if failed authentication. * * @return void; */ public function __construct() { parent::__construct(); $bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD); $this->internal_user = new \controllers\internals\User($bdd); $this->internal_phone = new \controllers\internals\Phone($bdd); $this->internal_received = new \controllers\internals\Received($bdd); $this->internal_sended = new \controllers\internals\Sended($bdd); $this->internal_scheduled = new \controllers\internals\Scheduled($bdd); $this->internal_contact = new \controllers\internals\Contact($bdd); $this->internal_group = new \controllers\internals\Group($bdd); $this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd); //If no user, quit with error $this->user = false; $api_key = $_GET['api_key'] ?? $_POST['api_key'] ?? false; if ($api_key) { $this->user = $this->internal_user->get_by_api_key($api_key); } if (!$this->user) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['INVALID_CREDENTIALS']; $return['message'] = self::ERROR_MESSAGES['INVALID_CREDENTIALS']; $this->auto_http_code(false); $this->json($return); exit(self::ERROR_CODES['INVALID_CREDENTIALS']); } if ($this->user['status'] !== \models\User::STATUS_ACTIVE) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['SUSPENDED_USER']; $return['message'] = self::ERROR_MESSAGES['SUSPENDED_USER']; $this->auto_http_code(false); $this->json($return); exit(self::ERROR_CODES['SUSPENDED_USER']); } } /** * List all entries of a certain type for the current user, sorted by id. * * @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone'] * @param int $page : Pagination number, Default = 0. Group of 25 results. * * @return : List of entries */ public function get_entries(string $entry_type, int $page = 0) { $entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone']; if (!\in_array($entry_type, $entry_types, true)) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'entry_type must be one of : ' . implode(', ', $entry_types) . '.'; $this->auto_http_code(false); $this->json($return); return false; } $controller_str = 'internal_' . $entry_type; $controller = $this->{$controller_str}; $page = (int) $page; $limit = 25; $entries = $controller->list_for_user($this->user['id'], $limit, $page); //Special case for scheduled, we must add numbers because its a join if ('scheduled' === $entry_type) { foreach ($entries as $key => $entry) { $entries[$key]['numbers'] = $this->internal_scheduled->get_numbers($entry['id']); $entries[$key]['contacts'] = $this->internal_scheduled->get_contacts($entry['id']); $entries[$key]['groups'] = $this->internal_scheduled->get_groups($entry['id']); $entries[$key]['conditional_groups'] = $this->internal_scheduled->get_conditional_groups($entry['id']); } } //Special case for group we must add contact because its a join elseif ('group' === $entry_type) { foreach ($entries as $key => $entry) { $entries[$key]['contacts'] = $this->internal_group->get_contacts($entry['id']); } } $return = self::DEFAULT_RETURN; $return['response'] = $entries; if (\count($entries) === $limit) { $return['next'] = \descartes\Router::url('Api', __FUNCTION__, ['entry_type' => $entry_type, 'page' => $page + 1], ['api_key' => $this->user['api_key']]); } if ($page > 0) { $return['prev'] = \descartes\Router::url('Api', __FUNCTION__, ['entry_type' => $entry_type, 'page' => $page - 1], ['api_key' => $this->user['api_key']]); } $this->auto_http_code(true); $this->json($return); } /** * Schedule a message to be send. * * @param string $_POST['at'] : Date to send message at format Y-m-d H:i:s * @param string $_POST['text'] : Text of the message to send * @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null use a random phone * @param string $_POST['flash'] : Default false. Is the sms a flash sms. * @param string $_POST['numbers'] : Array of numbers to send message to * @param string $_POST['contacts'] : Array of ids of contacts to send message to * @param string $_POST['groups'] : Array of ids of groups to send message to * @param string $_POST['conditional_groups'] : Array of ids of conditional groups to send message to * * @return : Id of scheduled created */ public function post_scheduled () { $at = $_POST['at'] ?? false; $text = $_POST['text'] ?? false; $id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone']; $flash = (bool) ($_POST['flash'] ?? false); $numbers = $_POST['numbers'] ?? []; $contacts = $_POST['contacts'] ?? []; $groups = $_POST['groups'] ?? []; $conditional_groups = $_POST['conditional_groups'] ?? []; $numbers = is_array($numbers) ? $numbers : [$numbers]; $contacts = is_array($contacts) ? $contacts : [$contacts]; $groups = is_array($groups) ? $groups : [$groups]; $conditional_groups = is_array($conditional_groups) ? $conditional_groups : [$conditional_groups]; if (!$at) { $at = (new \DateTime())->format('Y-m-d H:i:s'); } if (!$at || !$text) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['MISSING_PARAMETER']; $return['message'] = self::ERROR_MESSAGES['MISSING_PARAMETER'] . ($at ? '' : 'at ') . ($text ? '' : 'text'); $this->auto_http_code(false); $this->json($return); return false; } if (!\controllers\internals\Tool::validate_date($at, 'Y-m-d H:i:s')) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'at must be a date of format "Y-m-d H:i:s".'; $this->auto_http_code(false); $this->json($return); return false; } foreach ($numbers as $key => $number) { $number = \controllers\internals\Tool::parse_phone($number); if (!$number) { unset($numbers[$key]); continue; } $numbers[$key] = $number; } if (!$numbers && !$contacts && !$groups && !$conditional_groups) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['MISSING_PARAMETER']; $return['message'] = self::ERROR_MESSAGES['MISSING_PARAMETER'] . 'You must specify at least one valid number, contact, group or conditional_group.'; $this->auto_http_code(false); $this->json($return); return false; } if ($id_phone && !$this->internal_phone->get_for_user($this->user['id'], $id_phone)) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone : You must specify an id_phone number among thoses of user phones.'; $this->auto_http_code(false); $this->json($return); return false; } $scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $flash, $numbers, $contacts, $groups, $conditional_groups); if (!$scheduled_id) { $return = self::DEFAULT_RETURN; $return['error'] = self::ERROR_CODES['CANNOT_CREATE']; $return['message'] = self::ERROR_MESSAGES['CANNOT_CREATE']; $this->auto_http_code(false); $this->json($return); return false; } $return = self::DEFAULT_RETURN; $return['response'] = $scheduled_id; $this->auto_http_code(true); $this->json($return); } /** * Delete a scheduled message. * * @param int $id : Id of scheduled message to delete * * @return bool : void */ public function delete_scheduled(int $id) { $success = $this->internal_scheduled->delete_for_user($this->user['id'], $id); if (!$success) { $this->auto_http_code(false); return false; } $this->auto_http_code(true); return true; } }