*/
Router::defaultRouteClass('DashedRoute');
-//Router::prefix('api/v1', function (RouteBuilder $routes) {
-// $routes->extensions(['json', 'xml']);
-// $routes->resources('Users');
-// $routes->fallbacks('DashedRoute');
-//});
-
Router::prefix('api/v1', function (RouteBuilder $routes) {
$routes->extensions(['json', 'xml']);
$routes->resources('Users');
- $routes->resources('Connectors');
+ $routes->resources('Connectors', function(RouteBuilder $routes) {
+ $routes->resources('Services');
+ });
});
Router::scope('/', function (RouteBuilder $routes) {
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function view($id) {
+ $this->request->allowMethod('get');
try {
$connector = $this->Connectors->get($id);
}
catch (\Exception $ex) {
throw new ConnectorNotFoundException("The connector with the id $id does not exist");
- }
+ }
$this->Connectors->delete($connector);
$this->response->statusCode(204);
-
}
}
--- /dev/null
+<?php
+
+namespace App\Controller\Api\V1;
+
+use App\Controller\AppController;
+use App\Network\Exception\ServiceNotFoundException;
+use App\Network\Exception\ValidationException;
+
+/**
+ * Services Controller
+ *
+ * @property \App\Model\Table\ServicesTable $Services
+ */
+class ServicesController extends AppController {
+
+ /**
+ * Index method
+ *
+ * @return \Cake\Network\Response|null
+ */
+ public function index() {
+
+ $connector = $this->Services->getConnector($this->request->params['connector_id']);
+
+ $this->paginate = [
+// 'contain' => ['Connectors'],
+ 'conditions' => ['Services.connector_id' => $connector->id]
+ ];
+ $services = $this->paginate($this->Services);
+
+ $pagination = $this->request->params['paging']['Services'];
+
+ $paginationResponse = [
+ 'page_count' => $pagination['pageCount'],
+ 'current_page' => $pagination['page'],
+ 'has_next_page' => $pagination['nextPage'],
+ 'has_prev_page' => $pagination['prevPage'],
+ 'count' => $pagination['count'],
+ 'limit' => $pagination['limit']
+ ];
+
+ $this->set('pagination', $paginationResponse);
+ $this->set('services', $services);
+ }
+
+ /**
+ * View method
+ *
+ * @param string $id Service id.
+ * @return \Cake\Network\Response|null
+ * @throws \App\Network\Exception\ServiceNotFoundException When service not found.
+ */
+ public function view($id) {
+
+ $connector = $this->Services->getConnector($this->request->params['connector_id']);
+ try {
+ $service = $this->Services->get($id, [
+ 'conditions' => ['Services.connector_id' => $connector->id]
+ ]);
+ }
+ catch (\Exception $e) {
+ throw new ServiceNotFoundException("The service with the id $id does not exist");
+ }
+ $this->set('service', $service);
+ $this->set('_serialize', 'service');
+ }
+
+ /**
+ * Add method
+ *
+ * @return \Cake\Network\Response|void Redirects on successful add, renders view otherwise.
+ */
+ public function add() {
+ $this->request->allowMethod('post');
+
+ $connector = $this->Services->getConnector($this->request->params['connector_id']);
+ $this->request->data['connector_id'] = $connector->id;
+ $service = $this->Services->newEntity($this->request->data);
+ if ($this->Services->save($service)) {
+ $this->response->statusCode(201);
+ $this->set('service', $service);
+ $this->set('_serialize', 'service');
+ }
+ else {
+ $this->response->statusCode(400);
+ throw new ValidationException($service);
+ }
+ }
+
+ /**
+ * Edit method
+ *
+ * @param string $id Service id.
+ * @return \Cake\Network\Response|void Redirects on successful edit, renders view otherwise.
+ * @throws \App\Network\Exception\ServiceNotFoundException When service not found.
+ */
+ public function edit($id) {
+ $this->request->allowMethod('put');
+
+ $connector = $this->Services->getConnector($this->request->params['connector_id']);
+ try {
+ $service = $this->Services->get($id, [
+ 'conditions' => ['Services.connector_id' => $connector->id]
+ ]);
+ }
+ catch (\Exception $e) {
+ throw new ServiceNotFoundException("The service with the id $id does not exist");
+ }
+
+ $service = $this->Services->patchEntity($service, $this->request->data);
+
+ if ($this->Services->save($service)) {
+ $this->set('service', $service);
+ $this->set('_serialize', 'service');
+ }
+ else {
+ throw new ValidationException($service);
+ }
+ }
+
+ /**
+ * Delete method
+ *
+ * @param string $id Service id.
+ * @return \Cake\Network\Response|null Redirects to index.
+ * @throws \App\Network\Exception\ServiceNotFoundException When service not found.
+ */
+ public function delete($id) {
+ $this->request->allowMethod('delete');
+
+ $connector = $this->Services->getConnector($this->request->params['connector_id']);
+ try {
+ $service = $this->Services->get($id, [
+ 'conditions' => ['Services.connector_id' => $connector->id]
+ ]);
+ }
+ catch (\Exception $e) {
+ throw new ServiceNotFoundException("The service with the id $id does not exist");
+ }
+
+ $this->Services->delete($service);
+ $this->response->statusCode(204);
+ }
+
+}
--- /dev/null
+<?php
+
+namespace App\Model\Entity;
+
+use Cake\ORM\Entity;
+
+/**
+ * Service Entity.
+ *
+ * @property int $id
+ * @property string $name
+ * @property int $connector_id
+ * @property \App\Model\Entity\Connector $connector
+ * @property \App\Model\Entity\Subscription[] $subscriptions
+ * @property \App\Model\Entity\UsersMembership[] $users_memberships
+ */
+class Service extends Entity {
+
+ /**
+ * Fields that can be mass assigned using newEntity() or patchEntity().
+ *
+ * Note that when '*' is set to true, this allows all unspecified fields to
+ * be mass assigned. For security purposes, it is advised to set '*' to false
+ * (or remove it), and explicitly make individual fields accessible as needed.
+ *
+ * @var array
+ */
+ protected $_accessible = [
+ '*' => true,
+ 'id' => false,
+ ];
+
+}
--- /dev/null
+<?php
+
+namespace App\Model\Table;
+
+use App\Model\Entity\Service;
+use Cake\ORM\Query;
+use Cake\ORM\RulesChecker;
+use Cake\ORM\Table;
+use Cake\Validation\Validator;
+
+/**
+ * Services Model
+ *
+ * @property \Cake\ORM\Association\BelongsTo $Connectors
+ * @property \Cake\ORM\Association\BelongsToMany $Subscriptions
+ * @property \Cake\ORM\Association\BelongsToMany $UsersMemberships
+ */
+class ServicesTable extends Table {
+
+ /**
+ * Initialize method
+ *
+ * @param array $config The configuration for the Table.
+ * @return void
+ */
+ public function initialize(array $config) {
+ parent::initialize($config);
+
+ $this->table('services');
+ $this->displayField('name');
+ $this->primaryKey('id');
+
+ $this->belongsTo('Connectors', [
+ 'foreignKey' => 'connector_id',
+ 'joinType' => 'INNER'
+ ]);
+ $this->belongsToMany('Subscriptions', [
+ 'foreignKey' => 'service_id',
+ 'targetForeignKey' => 'subscription_id',
+ 'joinTable' => 'subscriptions_services'
+ ]);
+ $this->belongsToMany('UsersMemberships', [
+ 'foreignKey' => 'service_id',
+ 'targetForeignKey' => 'users_membership_id',
+ 'joinTable' => 'users_memberships_services'
+ ]);
+ }
+
+ /**
+ * Default validation rules.
+ *
+ * @param \Cake\Validation\Validator $validator Validator instance.
+ * @return \Cake\Validation\Validator
+ */
+ public function validationDefault(Validator $validator) {
+ $validator
+ ->integer('id')
+ ->allowEmpty('id', 'create');
+
+ $validator
+ ->requirePresence('name', 'create')
+ ->notEmpty('name')
+ ->add('name', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
+
+ return $validator;
+ }
+
+ /**
+ * Returns a rules checker object that will be used for validating
+ * application integrity.
+ *
+ * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
+ * @return \Cake\ORM\RulesChecker
+ */
+ public function buildRules(RulesChecker $rules) {
+ $rules->add($rules->isUnique(['name']));
+ $rules->add($rules->existsIn(['connector_id'], 'Connectors'));
+ return $rules;
+ }
+
+ /**
+ * Returns a single connector after finding it by its id. The connector MUST
+ * be parent to the current service.
+ *
+ * @param $connector_id The id of the connector to find
+ * @return \Cake\Datasource\EntityInterface
+ * @throws \App\Network\Exception\ConnectorNotFoundException if the
+ * connector with such id could not be found
+ */
+ public function getConnector($connector_id) {
+ try {
+ $connector = $this->Connectors->get($connector_id);
+ }
+ catch (\Exception $e) {
+ throw new \App\Network\Exception\ConnectorNotFoundException("The connector with the id $connector_id does not exist");
+ }
+ return $connector;
+ }
+
+}
--- /dev/null
+<?php
+
+namespace App\Network\Exception;
+
+use Cake\Network\Exception\NotFoundException;
+
+class ServiceNotFoundException extends NotFoundException {
+
+}
--- /dev/null
+<?php
+
+namespace App\Test\Fixture;
+
+use Cake\TestSuite\Fixture\TestFixture;
+
+/**
+ * ServicesFixture
+ *
+ */
+class ServicesFixture extends TestFixture {
+
+ /**
+ * Fields
+ *
+ * @var array
+ */
+ // @codingStandardsIgnoreStart
+ public $fields = [
+ 'id' => ['type' => 'integer', 'length' => 10, 'autoIncrement' => true, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'unsigned' => null],
+ 'name' => ['type' => 'string', 'length' => 255, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'fixed' => null],
+ 'connector_id' => ['type' => 'integer', 'length' => 10, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'unsigned' => null, 'autoIncrement' => null],
+ '_indexes' => [
+ 'services_fk_services_applications1_idx' => ['type' => 'index', 'columns' => ['connector_id'], 'length' => []],
+ ],
+ '_constraints' => [
+ 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
+ 'services_name_UNIQUE' => ['type' => 'unique', 'columns' => ['name'], 'length' => []],
+ ],
+ ];
+ // @codingStandardsIgnoreEnd
+
+ /**
+ * Records
+ *
+ * @var array
+ */
+ public $records = [
+ [
+ 'id' => 1,
+ 'name' => 'actes',
+ 'connector_id' => 1
+ ],
+ [
+ 'id' => 2,
+ 'name' => 'helios',
+ 'connector_id' => 1
+ ],
+ [
+ 'id' => 3,
+ 'name' => 'mailsec',
+ 'connector_id' => 1
+ ],
+ [
+ 'id' => 4,
+ 'name' => 'signature',
+ 'connector_id' => 2
+ ],
+ ];
+
+}
--- /dev/null
+<?php
+
+namespace App\Test\TestCase\Controller\Api\V1;
+
+/**
+ * App\Controller\Api\V1\ServicesController Test Case
+ */
+class ServicesControllerTest extends ApiIntegrationTestCase {
+
+ /**
+ * Fixtures
+ *
+ * @var array
+ */
+ public $fixtures = [
+ 'app.connectors',
+ 'app.services',
+ ];
+ public $autoFixtures = false;
+
+ public function testWhenGettingAllTheServicesOfAnExistingConnector() {
+ $this->loadFixtures('Connectors', 'Services');
+ $this->iSendAGetRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'services' => [
+ [
+ 'id' => 3, 'name' => 'mailsec', 'connector_id' => 1
+ ],
+ [
+ 'id' => 2, 'name' => 'helios', 'connector_id' => 1
+ ],
+ [
+ 'id' => 1, 'name' => 'actes', 'connector_id' => 1
+ ]
+ ],
+ 'pagination' => [
+ 'page_count' => 1,
+ 'current_page' => 1,
+ 'has_next_page' => FALSE,
+ 'has_prev_page' => FALSE,
+ 'count' => 3,
+ 'limit' => null
+ ]
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAllTheServicesOfAConnectorThatDoesNotExist() {
+ $this->loadFixtures('Services');
+ $this->iSendAGetRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The connector with the id 1 does not exist',
+ 'url' => '/api/v1/connectors/1/services.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingNoServicesFromAConnectorThatExists() {
+ $this->loadFixtures('Connectors');
+
+ $this->iSendAGetRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'services' => [],
+ 'pagination' => [
+ 'page_count' => 0,
+ 'current_page' => 1,
+ 'has_next_page' => FALSE,
+ 'has_prev_page' => FALSE,
+ 'count' => 0,
+ 'limit' => null
+ ]
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAServiceThatExistsFromItsConnectorParent() {
+ $this->loadFixtures('Connectors', 'Services');
+ $this->iSendAGetRequestTo('/connectors/1/services/1.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'id' => 1,
+ 'name' => 'actes',
+ 'connector_id' => 1
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAServiceThatExistsFromAConnectorThatDoesNotExist() {
+ $this->loadFixtures('Connectors', 'Services');
+ $this->iSendAGetRequestTo('/connectors/100/services/1.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The connector with the id 100 does not exist',
+ 'url' => '/api/v1/connectors/100/services/1.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAServiceThatExistsFromAConnectorThatIsNotItsParent() {
+ $this->loadFixtures('Connectors', 'Services');
+ $this->iSendAGetRequestTo('/connectors/2/services/1.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The service with the id 1 does not exist',
+ 'url' => '/api/v1/connectors/2/services/1.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAServiceThatDoesNotExistFromAConnectorThatExists() {
+ $this->loadFixtures('Connectors');
+ $this->iSendAGetRequestTo('/connectors/2/services/1.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The service with the id 1 does not exist',
+ 'url' => '/api/v1/connectors/2/services/1.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAServiceThatDoesNotExistFromAConnectorThatDoesNotExist() {
+ $this->iSendAGetRequestTo('/connectors/1/services/1.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The connector with the id 1 does not exist',
+ 'url' => '/api/v1/connectors/1/services/1.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingANewServiceToAConnectorThatExists() {
+ $this->loadFixtures('Connectors');
+
+ $data = [
+ 'name' => 'Test service'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+
+ $this->iSendAPostRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(201);
+ $expected = [
+ 'name' => 'Test service',
+ 'connector_id' => 1,
+ 'id' => 1
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingANewServiceToAConnectorThatDoesNotExist() {
+ $data = [
+ 'name' => 'Test service'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPostRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(404);
+ $expected = [
+ 'message' => 'The connector with the id 1 does not exist',
+ 'url' => '/api/v1/connectors/1/services.json',
+ 'code' => 404
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingAServiceThatExistsToAnotherConnector() {
+ $this->loadFixtures('Connectors', 'Services');
+
+ $data = [
+ 'name' => 'actes'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPostRequestTo('/connectors/2/services.json');
+ $this->theResponseCodeShouldBe(400);
+ $expected = [
+ 'code' => 400,
+ 'url' => '/api/v1/connectors/2/services.json',
+ 'message' => 'A validation error occurred',
+ 'errorCount' => 1,
+ 'errors' => [
+ 'name' => [
+ 'unique' => 'The provided value is invalid'
+ ]
+ ]
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingAServiceThatExistsToTheSameConnector() {
+ $this->loadFixtures('Connectors', 'Services');
+
+ $data = [
+ 'name' => 'actes'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPostRequestTo('/connectors/1/services.json');
+ $this->theResponseCodeShouldBe(400);
+ $expected = [
+ 'code' => 400,
+ 'url' => '/api/v1/connectors/1/services.json',
+ 'message' => 'A validation error occurred',
+ 'errorCount' => 1,
+ 'errors' => [
+ 'name' => [
+ 'unique' => 'The provided value is invalid'
+ ]
+ ]
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ //TODO: We need other related tables to manage deletion
+// public function testWhenDeletingAServiceThatExistsFromItsConnector() {
+// $this->loadFixtures('Connectors', 'Services');
+// $this->iSendADeleteRequestTo('/connectors/1/services/2.json');
+// $this->theResponseCodeShouldBe(204);
+// }
+
+}
--- /dev/null
+<?php
+
+namespace App\Test\TestCase\Model\Table;
+
+use App\Model\Table\ServicesTable;
+use Cake\ORM\TableRegistry;
+use Cake\TestSuite\TestCase;
+
+/**
+ * App\Model\Table\ServicesTable Test Case
+ */
+class ServicesTableTest extends TestCase {
+
+ /**
+ * Test subject
+ *
+ * @var \App\Model\Table\ServicesTable
+ */
+ public $Services;
+
+ /**
+ * Fixtures
+ *
+ * @var array
+ */
+ public $fixtures = [
+ 'app.services',
+ 'app.connectors',
+// 'app.subscriptions',
+// 'app.subscriptions_services',
+// 'app.users_memberships',
+// 'app.users_memberships_services'
+ ];
+
+ /**
+ * setUp method
+ *
+ * @return void
+ */
+ public function setUp() {
+ parent::setUp();
+ $config = TableRegistry::exists('Services') ? [] : ['className' => 'App\Model\Table\ServicesTable'];
+ $this->Services = TableRegistry::get('Services', $config);
+ }
+
+ /**
+ * tearDown method
+ *
+ * @return void
+ */
+ public function tearDown() {
+ unset($this->Services);
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test initialize method
+ *
+ * @return void
+ */
+ public function testInitialize() {
+ $this->markTestIncomplete('Not implemented yet.');
+ }
+
+ /**
+ * Test validationDefault method
+ *
+ * @return void
+ */
+// public function testValidationDefault() {
+// $this->markTestIncomplete('Not implemented yet.');
+// }
+
+ /**
+ * Test buildRules method
+ *
+ * @return void
+ */
+// public function testBuildRules() {
+// $this->markTestIncomplete('Not implemented yet.');
+// }
+
+}