Router::prefix('api/v1', function (RouteBuilder $routes) {
$routes->extensions(['json', 'xml']);
- $routes->resources('Users');
-
- $routes->resources('Connectors', ['id' => '[0-9A-Za-z-_ ]+'], function(RouteBuilder $routes) {
- $routes->resources('Services', ['id' => '[0-9A-Za-z-_ ]+']);
- });
+ $routes->resources('Users');
+ $routes->resources('Connectors');
});
Router::scope('/', function (RouteBuilder $routes) {
--- /dev/null
+<?php
+
+namespace App\Controller\Api\V1;
+
+use App\Controller\AppController;
+use App\Network\Exception\ValidationException;
+use App\Network\Exception\ConnectorNotFoundException;
+
+/**
+ * Connectors Controller
+ *
+ * @property \App\Model\Table\ConnectorsTable $Connectors
+ */
+class ConnectorsController extends AppController {
+
+ public $paginate = [
+ 'page' => 1,
+ 'limit' => 20,
+ 'maxLimit' => 100,
+ 'fields' => [
+ 'id', 'name', 'url'
+ ],
+ 'sortWhitelist' => [
+ 'id', 'name', 'url'
+ ]
+ ];
+
+ /**
+ * Index method
+ *
+ * @return \Cake\Network\Response|null
+ */
+ public function index() {
+ $this->request->allowMethod('get');
+
+ $connectors = $this->paginate($this->Connectors);
+
+ $pagination = $this->request->params['paging']['Connectors'];
+
+ $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('connectors', $connectors);
+ }
+
+ /**
+ * View method
+ *
+ * @param string $id Connector name.
+ * @return \Cake\Network\Response|null
+ * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
+ */
+ public function view($id) {
+
+ try {
+ $connector = $this->Connectors->get($id);
+ }
+ catch (\Exception $ex) {
+ throw new ConnectorNotFoundException("The connector with the id $id does not exist");
+ }
+
+ $this->set('connector', $connector);
+ $this->set('_serialize', 'connector');
+ }
+
+ /**
+ * Add method
+ *
+ * @return \Cake\Network\Response|void Redirects on successful add, renders view otherwise.
+ */
+ public function add() {
+ $this->request->allowMethod('post');
+
+ $connector = $this->Connectors->newEntity($this->request->data);
+ if ($this->Connectors->save($connector)) {
+ $this->response->statusCode(201);
+ $this->set('connector', $connector);
+ $this->set('_serialize', 'connector');
+ }
+ else {
+ $this->response->statusCode(400);
+ throw new ValidationException($connector);
+ }
+ }
+
+ /**
+ * Edit method
+ *
+ * @param string|null $id Connector id.
+ * @return \Cake\Network\Response|void Redirects on successful edit, renders view otherwise.
+ * @throws \Cake\Network\Exception\NotFoundException When record not found.
+ */
+ public function edit($id) {
+ $this->request->allowMethod('put');
+
+ try {
+ $connector = $this->Connectors->get($id);
+ }
+ catch (\Exception $ex) {
+ throw new ConnectorNotFoundException("The connector with the id $id does not exist");
+ }
+
+ if (isset($this->request->data['name'])) {
+ unset($this->request->data['name']);
+ }
+
+ $connector = $this->Connectors->patchEntity($connector, $this->request->data);
+
+ if ($this->Connectors->save($connector)) {
+ $this->response->statusCode(200);
+ $this->set('connector', $connector);
+ $this->set('_serialize', 'connector');
+ }
+ else {
+ $this->response->statusCode(400);
+ throw new ValidationException($connector);
+ }
+ }
+
+ /**
+ * Delete method
+ *
+ * @param string $id Connector id.
+ * @return \Cake\Network\Response|null Redirects to index.
+ * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
+ */
+ public function delete($id) {
+ $this->request->allowMethod('delete');
+ 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\Model\Entity;
+
+use Cake\ORM\Entity;
+
+/**
+ * Connector Entity.
+ *
+ * @property int $id
+ * @property string $name
+ * @property string $url
+ * @property \App\Model\Entity\Service[] $services
+ */
+class Connector 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\Connector;
+use Cake\ORM\Query;
+use Cake\ORM\RulesChecker;
+use Cake\ORM\Table;
+use Cake\Validation\Validator;
+
+/**
+ * Connectors Model
+ *
+ * @property \Cake\ORM\Association\HasMany $Services
+ */
+class ConnectorsTable extends Table {
+
+ /**
+ * Initialize method
+ *
+ * @param array $config The configuration for the Table.
+ * @return void
+ */
+ public function initialize(array $config) {
+ parent::initialize($config);
+
+ $this->table('connectors');
+ $this->displayField('name');
+ $this->primaryKey('id');
+
+ $this->hasMany('Services', [
+ 'foreignKey' => 'connector_id'
+ ]);
+ }
+
+ /**
+ * 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', 'message' => __('The provided connector already exists')]);
+
+ $validator
+ ->requirePresence('url', 'create')
+ ->notEmpty('url')
+ ->add('url', 'validFormat', ['rule' => ['url', true], 'message' => __('URL must be valid')]);
+ ;
+
+ 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']));
+ return $rules;
+ }
+
+}
--- /dev/null
+<?php
+
+namespace App\Network\Exception;
+
+use Cake\Network\Exception\NotFoundException;
+
+class ConnectorNotFoundException extends NotFoundException {
+
+}
--- /dev/null
+<?php
+
+namespace App\Test\Fixture;
+
+use Cake\TestSuite\Fixture\TestFixture;
+
+/**
+ * ConnectorsFixture
+ *
+ */
+class ConnectorsFixture 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],
+ 'url' => ['type' => 'string', 'length' => 425, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'fixed' => null],
+ '_constraints' => [
+ 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
+ 'connectors_name_UNIQUE' => ['type' => 'unique', 'columns' => ['name'], 'length' => []],
+ ],
+ ];
+ // @codingStandardsIgnoreEnd
+
+ /**
+ * Records
+ *
+ * @var array
+ */
+ public $records = [
+ [
+ 'id' => 1,
+ 'name' => 'pastell',
+ 'url' => 'https://pastell.example.org'
+ ],
+ [
+ 'id' => 2,
+ 'name' => 'parapheur',
+ 'url' => 'https://parapheur.example.org'
+ ],
+ ];
+
+}
}
return json_encode($data);
}
+
+ public function getApiPath() {
+ return $this->api_path;
+ }
}
--- /dev/null
+<?php
+
+namespace App\Test\TestCase\Controller\Api\V1;
+
+use App\Test\TestCase\Controller\Api\V1\ApiIntegrationTestCase;
+
+/**
+ * App\Controller\ConnectorsController Test Case
+ */
+class ConnectorsControllerTest extends ApiIntegrationTestCase {
+
+ /**
+ * Fixtures
+ *
+ * @var array
+ */
+ public $fixtures = [
+ 'app.connectors',
+ 'app.services',
+// 'app.subscriptions',
+// 'app.subscriptions_services',
+// 'app.users_memberships',
+// 'app.users_memberships_services'
+ ];
+ public $autoFixtures = false;
+
+ public function testWhenGettingAllTheConnectors() {
+ $this->loadFixtures('Connectors');
+ $this->iSendAGetRequestTo('/connectors.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'connectors' => [
+ [
+ 'id' => 1, 'name' => 'pastell', 'url' => 'https://pastell.example.org'
+ ],
+ [
+ 'id' => 2, 'name' => 'parapheur', 'url' => 'https://parapheur.example.org'
+ ]
+ ],
+ 'pagination' => [
+ 'page_count' => 1,
+ 'current_page' => 1,
+ 'has_next_page' => FALSE,
+ 'has_prev_page' => FALSE,
+ 'count' => 2,
+ 'limit' => null
+ ]
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingNoConnectors() {
+ $this->iSendAGetRequestTo('/connectors.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'connectors' => [],
+ '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 testWhenGettingAConnector() {
+ $this->loadFixtures('Connectors');
+ $this->iSendAGetRequestTo('/connectors/1.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'id' => 1,
+ 'name' => 'pastell',
+ 'url' => 'https://pastell.example.org'
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenGettingAConnectorThatDoesNotExists() {
+ $this->loadFixtures('Connectors');
+ $this->iSendAGetRequestTo('/connectors/4.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The connector with the id 4 does not exist',
+ 'url' => '/api/v1/connectors/4.json',
+ 'code' => 404
+ ];
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingANewConnector() {
+
+ $data = [
+ 'name' => 'idelibre',
+ 'url' => 'https://idelibre.example.org',
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPostRequestTo('/connectors.json');
+ $this->theResponseCodeShouldBe(201);
+
+ $expected = [
+ 'name' => 'idelibre',
+ 'url' => 'https://idelibre.example.org',
+ 'id' => 1
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenAddingAnExistingConnector() {
+ $this->loadFixtures('Connectors');
+ $uri = '/connectors.json';
+
+ $data = [
+ 'name' => 'pastell',
+ 'url' => 'https://random.example.org'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPostRequestTo($uri);
+ $this->theResponseCodeShouldBe(400);
+
+ $expected = [
+ 'code' => 400,
+ 'url' => $this->getApiPath() . $uri,
+ 'message' => 'A validation error occurred',
+ 'errorCount' => 1,
+ 'errors' => [
+ 'name' => [
+ 'unique' => 'The provided connector already exists'
+ ]
+ ]
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenUpdatingAnExistingConnector() {
+ $this->loadFixtures('Connectors');
+
+ $data = [
+ 'url' => 'https://random.example.org'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPutRequestTo('/connectors/1.json');
+ $this->theResponseCodeShouldBe(200);
+
+ $expected = [
+ 'id' => 1,
+ 'name' => 'pastell',
+ 'url' => 'https://random.example.org'
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenUpdatingANotExistingUser() {
+ $this->loadFixtures('Connectors');
+
+ $data = [
+ 'url' => 'https://random.example.org'
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPutRequestTo('/connectors/4.json');
+ $this->theResponseCodeShouldBe(404);
+
+
+ $expected = [
+ 'message' => 'The connector with the id 4 does not exist',
+ 'url' => '/api/v1/connectors/4.json',
+ 'code' => 404
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenUpdatingAConnectorWithInvalidUrl() {
+ $this->loadFixtures('Connectors');
+ $uri = '/connectors/2.json';
+ $data = [
+ 'url' => 'pastell.example.org',
+ ];
+
+ $this->givenIHaveSomeDataToSend($data);
+ $this->iSendAPutRequestTo($uri);
+ $this->theResponseCodeShouldBe(400);
+
+ $expected = [
+ 'code' => 400,
+ 'url' => $this->getApiPath() . $uri,
+ 'message' => 'A validation error occurred',
+ 'errorCount' => 1,
+ 'errors' => [
+ 'url' => [
+ 'validFormat' => 'URL must be valid'
+ ]
+ ]
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+ public function testWhenDeletingAConnectorThatExists() {
+ $this->loadFixtures('Connectors');
+
+ $this->iSendADeleteRequestTo('/connectors/2.json');
+ $this->theResponseCodeShouldBe(204);
+ }
+
+ public function testWhenDeletingAConnectorThatDoesNotExist() {
+ $this->loadFixtures('Connectors');
+
+ $this->iSendADeleteRequestTo('/connectors/4.json');
+ $this->theResponseCodeShouldBe(404);
+
+ $expected = [
+ 'message' => 'The connector with the id 4 does not exist',
+ 'url' => '/api/v1/connectors/4.json',
+ 'code' => 404
+ ];
+
+ $expectedBody = $this->getExpectedValue($expected);
+
+ $this->theResponseBodyShouldBe($expectedBody);
+ }
+
+}
--- /dev/null
+<?php
+
+namespace App\Test\TestCase\Model\Table;
+
+use App\Model\Table\ConnectorsTable;
+use Cake\ORM\TableRegistry;
+use Cake\TestSuite\TestCase;
+
+/**
+ * App\Model\Table\ConnectorsTable Test Case
+ */
+class ConnectorsTableTest extends TestCase {
+
+ /**
+ * Test subject
+ *
+ * @var \App\Model\Table\ConnectorsTable
+ */
+ public $Connectors;
+
+ /**
+ * Fixtures
+ *
+ * @var array
+ */
+ public $fixtures = [
+ 'app.connectors',
+ 'app.services'
+ ];
+
+ /**
+ * setUp method
+ *
+ * @return void
+ */
+ public function setUp() {
+ parent::setUp();
+ $config = TableRegistry::exists('Connectors') ? [] : ['className' => 'App\Model\Table\ConnectorsTable'];
+ $this->Connectors = TableRegistry::get('Connectors', $config);
+ }
+
+ /**
+ * tearDown method
+ *
+ * @return void
+ */
+ public function tearDown() {
+ unset($this->Connectors);
+
+ 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.');
+// }
+
+}