diff --git a/README.md b/README.md index be805bd3..db5f8aeb 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,7 @@ -# phalcon-api -Baka API using Phalcon - -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/?branch=master) -[![Code Coverage](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/?branch=master) -[![Build Status](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/badges/build.png?b=master)](https://scrutinizer-ci.com/g/bakaphp/phalcon-api/build-status/master) - - -Implementation of an API application using the Phalcon Framework [https://phalconphp.com](https://phalconphp.com) - -### Installation -- Clone the project -- Copy `storage/ci/.env.example` and paste it in the root of the project and rename it `.env` -- On `phalcon-api/.env` in `MYSQL_ROOT_PASSWORD` and `DATA_API_MYSQL_PASS` assign the root password for MySQL. -- On `phalcon-api/.env`, update MySQL credentials (`DATA_API_MYSQL_NAME,DATA_API_MYSQL_USER,DATA_API_MYSQL_PASS`) -- On `phalcon-api/.env`, change `DATA_API_MYSQL_HOST = localhost` to `DATA_API_MYSQL_HOST = mysql` -- Download [Canvas Core](https://github.com/bakaphp/canvas-core) and copy it on the same folder where `phalcon-api` is located(Both projects must be in the same folder). -- On `phalcon-api/library/Core/autoload.php` comment `require dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . '/vendor/canvas/core/src/Core/functions.php';` and uncomment `require '/ canvas-core/src/Core/functions.php';` -- On `phalcon-api/library/Core/autoload.php` uncomment `'Canvas' => '/canvas-core/src',` -- Run Docker containers with the `docker-compose up --build` command -- After the build, access the project main container with `docker exec -it id_of_docker_container sh` -- Inside the container's console run get inside the `apps` folder, `cd app/` -- Inside the container's console run `./vendor/bin/phinx migrate -e production` to create the db , you need to have the phinx.php file , if you dont see it on your main filder you can find the copy at `storage/ci/phinx.php` -- Inside the container's console run `./vendor/bin/phinx seed:run` to create the necesary initial data -- Inside the container's console run `php cli/cli.php acl` AND `php cli/cli.php acl crm` to create the default roles of the system -- Inside the container's console run `./vendor/bin/codecept run` to run project tests. - -**NOTE** : This requires [docker](https://www.docker.com/) to be present in your system. Visit their site for installation instructions. - -**NOTE** : To ensure the project runs smoothly in a development environment you must comment or remove `canvas/core": "dev-master"` dependency from composer.json - -### CLI -- On every deploy crear the session caches `./app/php cli/cli.php clearcache` -- On every deploy update your DB `./app/vendor/bin/phinx migrate -e production` -- Queue to clear jwt sessions `./app/php cli/cli.php clearcache sessions` - -### Features -- User Managament - - Registration , Login, Multi Tenant -- ACL *working on it -- Saas Configuracion *working on it - - Company Configuration - - Payment / Free trial flow -- Rapid API CRUD Creation - -##### JWT Tokens -As part of the security of the API, [JWT](https://jwt.io) are used. JSON Web Tokens offer an easy way for a consumer of the API to send requests without the need to authenticate all the time. The expiry of each token depends on the setup of the API. An admin can easily keep the expiry very short, thus consumers will always have to log in first and then access a resource, or they can increase the "life" of each token, thus having less calls to the API. - -##### Middleware -- Lazy loading to save resources per request -- Stop execution as early as possible when an error occurs -- Execution - - NotFound - 404 when the resource requested is not found - - Authentication - After a `/login` checks the `Authentication` header - - TokenUser - When a token is supplied, check if it corresponds to a user in the database - - TokenVerification - When a token is supplied, check if it is correctly signed - - TokenValidation - When a token is supplied, check if it is valid (`issuedAt`, `notBefore`, `expires`) - -##### Baka HTTP -We use the library [Baka HTTP](https://github.com/bakaphp/http) to handle our Routing - -### Usage - -#### Requests - -**Error** - -```json -{ - "errors": { - "Description of the error no 1", - "Description of the error no 2" - }, -} -``` +# Gewaer API +Gewaer Kanvas App CRM API ### TODO -- Create docs endpoint +- Create docs endpoint** - Migrate Testing to Baka diff --git a/api/controllers/AffiliatesController.php b/api/controllers/AffiliatesController.php index 2c045fea..9a6e2fb4 100644 --- a/api/controllers/AffiliatesController.php +++ b/api/controllers/AffiliatesController.php @@ -7,7 +7,7 @@ use Gewaer\Models\Affiliates; /** - * Class CustomFieldsController + * Class CustomFieldsController. * * @package Gewaer\Api\Controllers * @@ -20,7 +20,7 @@ class AffiliatesController extends BaseController { /** - * set objects + * set objects. * * @return void */ @@ -28,5 +28,4 @@ public function onConstruct(): void { $this->model = new Affiliates(); } - -} \ No newline at end of file +} diff --git a/api/controllers/AgentsController.php b/api/controllers/AgentsController.php index 1e6d8315..1c46e8a9 100644 --- a/api/controllers/AgentsController.php +++ b/api/controllers/AgentsController.php @@ -7,7 +7,7 @@ use Gewaer\Models\Agents; /** - * Class CustomFieldsController + * Class CustomFieldsController. * * @package Gewaer\Api\Controllers * @@ -20,7 +20,7 @@ class AgentsController extends BaseController { /** - * set objects + * set objects. * * @return void */ @@ -28,5 +28,4 @@ public function onConstruct(): void { $this->model = new Agents(); } - -} \ No newline at end of file +} diff --git a/api/controllers/AuthController.php b/api/controllers/AuthController.php index d06393bc..af69583e 100644 --- a/api/controllers/AuthController.php +++ b/api/controllers/AuthController.php @@ -5,25 +5,8 @@ namespace Gewaer\Api\Controllers; use Canvas\Api\Controllers\AuthController as CanvasAuthController; -use Phalcon\Http\Response; use Gewaer\Models\Users; -use Stripe\Stripe; -use Stripe\Customer; -use function Canvas\Core\envValue; -use Canvas\Traits\AuthTrait; -use Phalcon\Security\Random; -use Throwable; -use Canvas\Models\UsersAssociatedApps; -use Phalcon\Di; -use Gewaer\Zoho; -use Gewaer\Models\Affiliates; use Canvas\Models\UserLinkedSources; -use Phalcon\Validation\Validator\Confirmation; -use Phalcon\Validation\Validator\Email as EmailValidator; -use Phalcon\Validation\Validator\PresenceOf; -use Phalcon\Validation\Validator\StringLength; -use Baka\Auth\Models\Sessions; -use Canvas\Validation as CanvasValidation; /** * Class AuthController. diff --git a/api/controllers/IndexController.php b/api/controllers/IndexController.php index 55f6a63c..f8f4749b 100644 --- a/api/controllers/IndexController.php +++ b/api/controllers/IndexController.php @@ -29,7 +29,7 @@ class IndexController extends CanvasIndexController */ public function index($id = null) : Response { - return $this->response(['Woot Canvas']); + return $this->response(['Woot Gewaer']); } /** diff --git a/api/controllers/LeadsController.php b/api/controllers/LeadsController.php index e6fe1e1f..387b4b57 100644 --- a/api/controllers/LeadsController.php +++ b/api/controllers/LeadsController.php @@ -13,13 +13,13 @@ use Gewaer\Models\LeadsLinkedSources; /** - * Base controller + * Base controller. * */ class LeadsController extends BaseController { /** - * set objects + * set objects. * * @return void */ @@ -33,17 +33,17 @@ public function onConstruct(): void } /** - * get Leads count for specific user + * get Leads count for specific user. * * @method GET * url /v1/leads * * @param int $id - * @return \Phalcon\Http\Response + * @return Response */ public function getLeadCountByUserId($id = null): Response { - $company_id = $this->request->get('company_id', 'string'); + $companyId = $this->request->get('company_id', 'string'); $leadsCount = ' SELECT count(*) as total @@ -54,7 +54,7 @@ public function getLeadCountByUserId($id = null): Response '; $result = $this->db->prepare($leadsCount); - $result->execute([$id, $company_id]); + $result->execute([$id, $companyId]); $leads = $result->fetch(); $stats = [ @@ -67,13 +67,10 @@ public function getLeadCountByUserId($id = null): Response } /** - * get item - * - * @method GET - * url /v1/leads/{id} + * get item. * * @param int $id - * @return \Phalcon\Http\Response + * @return Response */ public function getById($id): Response { @@ -104,17 +101,15 @@ public function getById($id): Response } /** - * Overwrite create funcions + * Overwrite create function. * - * @method POST - * /v1/leads * - * @return \Phalcon\Http\Response + * @return Response */ public function create(): Response { //if post is empty, then get it from raw body array style - $data = empty($this->request->getPost()) ? $this->request->getJsonRawBody(true) : $this->request->getPost(); + $data = $this->request->getPostData(); // This gonna check if the email have withe spaces if (key_exists('email', $data)) { @@ -131,7 +126,7 @@ public function create(): Response 'key' => $publicKey, ]); - //register an attemp to the leave before saving anything to have a backup of the given data + //register an attempt to the leave before saving anything to have a backup of the given data $attempt = new LeadsAttempt(); $attempt->request = json_encode($data); $attempt->ip = $this->request->getClientAddress(); @@ -192,13 +187,11 @@ public function create(): Response } /** - * Update a new Entry + * Update a new Entry. * - * @method PUT - * url /v1/leads/{id} * * @param int $id - * @return \Phalcon\Http\Response + * @return Response */ public function edit($id): Response { @@ -208,7 +201,7 @@ public function edit($id): Response ]); if ($lead) { - $data = $this->request->getPut(); + $data = $this->request->getPutData(); $publicKey = $this->request->getHeader('PUBLICKEY'); @@ -249,7 +242,7 @@ public function edit($id): Response //update $lead->updateOrFail($data, $this->updateFields); - + $attempt->processed = 1; $attempt->update(); @@ -260,7 +253,7 @@ public function edit($id): Response } /** - * This method update one or more leads by the query on url + * This method update one or more leads by the query on url. * * @return array of leads updated */ @@ -303,10 +296,8 @@ public function multipleUpdates(): Response } /** - * Return every field from leads model + * Return every field from leads model. * - * @method POST - * @url /v1/business * * @return Phalcon\Http\Response */ @@ -321,7 +312,7 @@ public function getFields() } /** - * Return every stadistic showed in the dashboard + * Return every stadistic showed in the dashboard. * * @method GET * @url /v1/leads/stats @@ -427,7 +418,7 @@ public function getStats(): Response } /** - * Filter leads by a specific custom field + * Filter leads by a specific custom field. * @param $memberId Member Id * @return Response */ @@ -438,9 +429,9 @@ public function getLeadsByCustomField($memberId): Response //lets search custom field's id $customFieldId = CustomFields::findFirst([ - 'conditions' => 'name = ?0', - 'bind' => [$searchBy] - ]); + 'conditions' => 'name = ?0', + 'bind' => [$searchBy] + ]); if (!$customFieldId) { throw new Exception('Custom field not found'); @@ -498,18 +489,18 @@ public function getLeadsByCustomField($memberId): Response $limit = (int) $this->request->getQuery('limit', 'int', 25); $newResult = [ - 'data' => $newResult, - 'limit' => $limit, - 'page' => $this->request->getQuery('page', 'int', 1), - 'total_pages' => ceil($count / $limit) - ]; + 'data' => $newResult, + 'limit' => $limit, + 'page' => $this->request->getQuery('page', 'int', 1), + 'total_pages' => ceil($count / $limit) + ]; } return $this->response($newResult); } /** - * Fetch lead's linked zoho id + * Fetch lead's linked zoho id. * @param $id * @return Response */ diff --git a/api/controllers/LeadsOwnerController.php b/api/controllers/LeadsOwnerController.php index 2d4d2a08..9b320180 100644 --- a/api/controllers/LeadsOwnerController.php +++ b/api/controllers/LeadsOwnerController.php @@ -13,7 +13,7 @@ class LeadsOwnerController extends BaseController { /** * set objects - *use Exception; + *use Exception;. * @return void */ @@ -22,14 +22,32 @@ class LeadsOwnerController extends BaseController * * @var array */ - protected $createFields = ['firstname', 'lastname', 'email', 'phone', 'address', 'created_at', 'updated_at', 'companies_id']; + protected $createFields = [ + 'firstname', + 'lastname', + 'email', + 'phone', + 'address', + 'created_at', + 'updated_at', + 'companies_id' + ]; /** - * fields we accept to update + * fields we accept to update. * * @var array */ - protected $updateFields = ['firstname', 'lastname', 'email', 'phone', 'address', 'created_at', 'updated_at', 'companies_id']; + protected $updateFields = [ + 'firstname', + 'lastname', + 'email', + 'phone', + 'address', + 'created_at', + 'updated_at', + 'companies_id' + ]; public function onConstruct(): void { @@ -37,7 +55,7 @@ public function onConstruct(): void } /** - * This function update the lead owner of a lead setting the lead owner using rotation, and change the leads status + * This function update the lead owner of a lead setting the lead owner using rotation, and change the leads status. * @return Response */ public function updateLeadOwner():Response @@ -65,7 +83,7 @@ public function updateLeadOwner():Response } /** - * Validates zoho user existence + * Validates zoho user existence. * @todo Zoho gives invalid ticket, check the cause of it * @return array */ @@ -80,4 +98,4 @@ public function leadOwnerValidation(): Response return $this->response($leadOwnerValidation); } -} \ No newline at end of file +} diff --git a/api/controllers/ReceiversController.php b/api/controllers/ReceiversController.php index 1958c396..a02b7411 100644 --- a/api/controllers/ReceiversController.php +++ b/api/controllers/ReceiversController.php @@ -9,14 +9,13 @@ use Phalcon\Http\Response; /** - * Base controller + * Base controller. * */ class ReceiversController extends BaseController { - /** - * Receiver a lead via a lead reciever + * Receiver a lead via a lead reciever. * * @method POST * /v1/reciever/{key}/lead @@ -33,7 +32,6 @@ public function createLead(string $key) if ($this->request->hasPost('json')) { $post = json_decode(preg_replace('!\s+!', ' ', $this->request->get('json'))); } - $this->log->info("RawBody $mapper->name: ", [$raw_body]); $this->log->info("Post $mapper->name: ", [$post]); @@ -67,7 +65,7 @@ public function createLead(string $key) break; default: - throw new Exception("We dont handle this type of data type "); + throw new Exception('We dont handle this type of data type '); break; } @@ -83,12 +81,12 @@ public function createLead(string $key) $this->log->error($e->getMessage()); } } else { - throw new Exception(_("Key doesnt exist")); + throw new Exception(_('Key doesnt exist')); } } /** - * Parse incoming data from Zoho Webhook + * Parse incoming data from Zoho Webhook. * * @param [string] $json_string * @return String @@ -96,19 +94,19 @@ public function createLead(string $key) public static function parseWebhookData(string $jsonString): String { $token = '<>'; - + $convertedJson = $jsonString; do { $tokenLength = strlen($token); $startPos = strpos($convertedJson, $token); - $endPos = strpos($convertedJson, $token, $startPos+1); - - $subString =addslashes(substr($convertedJson, $startPos+$tokenLength, $endPos-$startPos-$tokenLength)); - - $convertedJson = substr_replace($convertedJson, $subString, $startPos, $endPos-$startPos+$tokenLength); - } while (strpos($convertedJson, $token)!==false); - + $endPos = strpos($convertedJson, $token, $startPos + 1); + + $subString = addslashes(substr($convertedJson, $startPos + $tokenLength, $endPos - $startPos - $tokenLength)); + + $convertedJson = substr_replace($convertedJson, $subString, $startPos, $endPos - $startPos + $tokenLength); + } while (strpos($convertedJson, $token) !== false); + return $convertedJson; } } diff --git a/api/controllers/RotationUsersController.php b/api/controllers/RotationUsersController.php index 66648067..13e84711 100644 --- a/api/controllers/RotationUsersController.php +++ b/api/controllers/RotationUsersController.php @@ -8,7 +8,7 @@ use Phalcon\Http\Response; /** - * Leads Custom Fields controller + * Leads Custom Fields controller. * */ class RotationUsersController extends BaseController @@ -18,17 +18,17 @@ class RotationUsersController extends BaseController * * @var array */ - protected $createFields = ['name', 'email', 'phone','percentage', 'rotations_id', 'users_id','companies_id']; + protected $createFields = ['name', 'email', 'phone', 'percentage', 'rotations_id', 'users_id', 'companies_id']; /** - * fields we accept to update + * fields we accept to update. * * @var array */ - protected $updateFields = ['name', 'email', 'phone','percentage', 'rotations_id', 'users_id','companies_id']; + protected $updateFields = ['name', 'email', 'phone', 'percentage', 'rotations_id', 'users_id', 'companies_id']; /** - * set objects + * set objects. * * @return void */ @@ -38,7 +38,7 @@ public function onConstruct(): void } /** - * Fetches lead owner from a lead + * Fetches lead owner from a lead. * * @return void */ @@ -52,19 +52,19 @@ public function getRotationUser() } $leadOwner = $this->model->findFirst([ - "conditions" => "email = ?0 OR name = ?1", - "bind" => [$email, $name], + 'conditions' => 'email = ?0 OR name = ?1', + 'bind' => [$email, $name], ]); if (!$leadOwner) { - throw new Exception("Lead Owner not found"); + throw new Exception('Lead Owner not found'); } return $this->response($leadOwner); } /** - * Add a new item + * Add a new item. * * @method POST * @url /v1/leads-rotation @@ -72,14 +72,14 @@ public function getRotationUser() */ public function create(): Response { - $data = empty($this->request->getPost()) ? $this->request->getJsonRawBody(true) : $this->request->getPost(); + $data = $this->request->getPostData(); $data['companies_id'] = isset($data['companies_id']) ? $data['companies_id'] : (int) $this->userData->getCurrentCompany()->getId(); $data['users_id'] = isset($data['users_id']) ? $data['users_id'] : (int) $this->userData->getId(); //try to save all the fields we allow if ($this->model->save($data, $this->createFields)) { - $rotation = Rotations::findFirstOrFail([ - 'conditions'=>'id = ?0 and companies_id = ?1 and is_deleted = 0', - 'bind'=>[$data['rotations_id'],$data['companies_id']] + $rotation = Rotations::findFirstOrFail([ + 'conditions' => 'id = ?0 and companies_id = ?1 and is_deleted = 0', + 'bind' => [$data['rotations_id'], $data['companies_id']] ]); $rotationUsers = RotationUsers::findOrFail([ @@ -92,8 +92,7 @@ public function create(): Response $rotationUser->hits = 0; $rotationUser->save(); } - - + return $this->response($this->model->toArray()); } else { //if not thorw exception @@ -109,11 +108,11 @@ public function editAllPercentages(int $id): Response { if ($this->request->isPost()) { $rotationAgentData = empty($this->request->getPost()) ? $this->request->getJsonRawBody(true) : $this->request->getPost(); - + foreach ($rotationAgentData as $key => $value) { - $agent = RotationUsers::findFirst([ + $agent = RotationUsers::findFirst([ 'conditions' => 'rotations_id = ?0 AND id = ?1', - 'bind' => [$id,$key] + 'bind' => [$id, $key] ]); if (!$agent) { diff --git a/api/controllers/RotationsController.php b/api/controllers/RotationsController.php index 2347597a..85a99fac 100644 --- a/api/controllers/RotationsController.php +++ b/api/controllers/RotationsController.php @@ -8,23 +8,31 @@ class RotationsController extends BaseController { - /* * fields we accept to create * * @var array */ - protected $createFields = ['name', 'users_id', 'companies_id', 'percent']; + protected $createFields = [ + 'name', + 'users_id', + 'companies_id', + 'percent' + ]; /** - * fields we accept to update + * fields we accept to update. * * @var array */ - protected $updateFields = ['name', 'users_id', 'companies_id', 'percent']; + protected $updateFields = [ + 'name', + 'users_id', + 'companies_id', + 'percent']; /** - * set objects + * set objects. * * @return void */ diff --git a/api/routes/api.php b/api/routes/api.php index a62425c2..bc62180f 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -26,4 +26,7 @@ /** * @todo look for a better way to handle this */ -return array_merge($publicRoutesGroup->toCollections(), $privateRoutesGroup->toCollections()); +return array_merge( + $publicRoutesGroup->toCollections(), + $privateRoutesGroup->toCollections() +); diff --git a/cli/tasks/LeadsTask.php b/cli/tasks/LeadsTask.php index 467edea2..c1f8f929 100644 --- a/cli/tasks/LeadsTask.php +++ b/cli/tasks/LeadsTask.php @@ -24,7 +24,7 @@ class LeadsTask extends PhTask { /** - * [$PARAMS array of params for search on Zoho] + * [$PARAMS array of params for search on Zoho]. * @var [array] */ const PARAMS = [ @@ -42,7 +42,7 @@ public function mainAction() } /** - * Internal queue for the Service + * Internal queue for the Service. * * @return void */ @@ -66,7 +66,7 @@ public function queueAction() $lead->updateOrFail(); /** - * We need to overwrite the userData session + * We need to overwrite the userData session. */ $di->set('userData', function () use ($config, $di, $lead) { $userData = Users::findFirstOrFail($lead->users_id); @@ -104,7 +104,7 @@ public function queueAction() } /** - * Send a lead to zoho + * Send a lead to zoho. * * @param Leads $lead * @return void @@ -175,7 +175,6 @@ private function sendToZoho(Leads $lead, array $leadOptions) //Gets the desired lead to update.Gets the first element of the array $response = reset($response); if ($response) { - $this->createLeadLinkedSource($lead, $response['LEADID']); if (!$response = $zohoClient->updateRecords($response['LEADID'], $validXml, ['wfTrigger' => 'true'])) { @@ -244,7 +243,7 @@ private function sendToZoho(Leads $lead, array $leadOptions) } /** - * Set Rotation Agents on Lead + * Set Rotation Agents on Lead. * * @param array $zohoData * @return array @@ -298,9 +297,8 @@ private function setRotationsAgents(array $zohoData, Leads $lead): array return $zohoData; } - /** - * Create a new Lead Linked Source + * Create a new Lead Linked Source. * @param Leads $lead * @param array $responseLeadId * @return void diff --git a/composer.json b/composer.json index a37c0824..3793cea6 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "league/flysystem": "^1.0", "league/flysystem-aws-s3-v3": "^1.0", "league/fractal": "^0.17.0", - "mctekk/zohocrm": "dev-sdk-version-2", + "mctekk/zohocrm": "^0.1", "monolog/monolog": "^1.23", "namshi/notificator": " 1.0.*", "nesbot/carbon": "~1.18",