Skip to content

Commit 4fdfcb2

Browse files
committed
Merge pull request #11 from codebendercc/libtest-updates
Payload generation option
2 parents b690e21 + 7c6368a commit 4fdfcb2

File tree

7 files changed

+203
-593
lines changed

7 files changed

+203
-593
lines changed

Symfony/app/config/config.yml

+12-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ imports:
33
- { resource: security.yml }
44

55
framework:
6-
#esi: ~
7-
#translator: { fallback: "%locale%" }
86
secret: "%secret%"
97
router:
108
resource: "%kernel.root_dir%/config/routing.yml"
@@ -14,13 +12,24 @@ framework:
1412
validation: { enable_annotations: true }
1513
templating:
1614
engines: ['twig']
17-
#assets_version: SomeVersionScheme
1815
default_locale: "%locale%"
1916
trusted_proxies: ~
2017
session: ~
2118
fragments: ~
2219
http_method_override: true
2320

21+
# Services configuration
22+
services:
23+
kernel.listener.auth_listener:
24+
class: Codebender\BuilderBundle\EventListener\AuthListener
25+
tags:
26+
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 1 }
27+
arguments: [ "%authorizationKey%", "%version%" ]
28+
kernel.listener.data_validation_listener:
29+
class: Codebender\BuilderBundle\EventListener\DataValidationListener
30+
tags:
31+
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 0 }
32+
2433
# Twig Configuration
2534
twig:
2635
debug: "%kernel.debug%"

Symfony/src/Codebender/BuilderBundle/Controller/DefaultController.php

+75-45
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
66
use Symfony\Component\HttpFoundation\JsonResponse;
7-
use Symfony\Component\HttpFoundation\Response;
87

98
/**
109
* default controller of api bundle
1110
*/
1211
class DefaultController extends Controller
1312
{
13+
/* @var array $additionalCode */
14+
protected $additionalCode = [];
15+
1416
/**
1517
* status action
1618
*
@@ -26,36 +28,15 @@ public function statusAction()
2628
* Gets a request for compilation or library fetching (depends on the 'type' field of the request)
2729
* and passes the request to either the compiler or the library manager.
2830
*
29-
* Includes several checks in order to ensure the validity of the data provided as well
30-
* as authentication.
31-
*
32-
* @param $authKey
33-
* @param $version
3431
* @return JsonResponse
3532
*/
36-
public function handleRequestAction($authKey, $version)
33+
public function handleRequestAction()
3734
{
38-
if ($authKey !== $this->container->getParameter('authorizationKey')) {
39-
return new JsonResponse(['success' => false, 'message' => 'Invalid authorization key.']);
40-
}
35+
$contents = json_decode($this->getRequest()->getContent(), true);
4136

42-
if ($version !== $this->container->getParameter('version')) {
43-
return new JsonResponse(['success' => false, 'message' => 'Invalid api version.']);
44-
}
45-
46-
$request = $this->getRequest()->getContent();
47-
if (empty($request)) {
48-
return new JsonResponse(['success' => false, 'message' => 'Invalid input.']);
49-
}
50-
51-
$contents = json_decode($request, true);
52-
53-
if (json_last_error() !== JSON_ERROR_NONE) {
54-
return new JsonResponse(['success' => false, 'message' => 'Wrong data.']);
55-
}
56-
57-
if (!array_key_exists('data', $contents)) {
58-
return new JsonResponse(['success' => false, 'message' => 'Insufficient data provided.']);
37+
$isContentValid = $this->isContentValid($contents);
38+
if ($isContentValid['success'] !== true) {
39+
return new JsonResponse(['success' => false, 'message' => $isContentValid['error']]);
5940
}
6041

6142
if ($contents['type'] == 'compiler') {
@@ -72,6 +53,15 @@ public function handleRequestAction($authKey, $version)
7253
]);
7354
}
7455

56+
protected function isContentValid($requestContent)
57+
{
58+
if (!array_key_exists('data', $requestContent)) {
59+
return ['success' => false, 'error' => 'Insufficient data provided.'];
60+
}
61+
62+
return ['success' => true];
63+
}
64+
7565
/**
7666
* Gets the data from the handleRequestAction and proceeds with the compilation
7767
*
@@ -84,23 +74,11 @@ protected function compile($contents)
8474
{
8575
$apiHandler = $this->get('codebender_builder.handler');
8676

87-
$contents = $this->addUserIdProjectIdIfNotInRequest($contents);
88-
89-
$files = $contents['files'];
90-
91-
$userLibraries = [];
92-
93-
if (array_key_exists('libraries', $contents)) {
94-
$userLibraries = $contents['libraries'];
95-
}
96-
97-
$userAndLibmanLibraries = $this->returnProvidedAndFetchedLibraries($files, $userLibraries);
98-
99-
$contents['libraries'] = $userAndLibmanLibraries['libraries'];
77+
$contents = $this->generateCompilerPayload($contents);
10078

10179
$compilerRequestContent = json_encode($contents);
10280

103-
// perform the actual post to the compiler
81+
// perform the actual request to the compiler
10482
$data = $apiHandler->postRawData($this->container->getParameter('compiler'), $compilerRequestContent);
10583

10684
$decodedResponse = json_decode($data, true);
@@ -112,8 +90,8 @@ protected function compile($contents)
11290
$decodedResponse['step'] = 'unknown';
11391
}
11492

115-
unset($userAndLibmanLibraries['libraries']);
116-
$decodedResponse['additionalCode'] = $userAndLibmanLibraries;
93+
$decodedResponse['additionalCode'] = $this->additionalCode;
94+
$this->additionalCode = [];
11795

11896
return $decodedResponse;
11997
}
@@ -195,14 +173,66 @@ protected function returnProvidedAndFetchedLibraries($projectFiles, $userLibrari
195173
$libraries[$header] = $filesToBeAdded;
196174
}
197175

198-
return [
199-
'libraries' => $libraries,
176+
// store info about libraries and headers in the `additionalCode` class property;
177+
$this->additionalCode = [
200178
'providedLibraries' => $providedLibraries,
201179
'fetchedLibraries' => $librariesFromLibman,
202180
'detectedHeaders'=> $detectedHeaders,
203181
'foundHeaders' => $foundHeaders,
204182
'notFoundHeaders' => $notFoundHeaders
205183
];
184+
185+
return $libraries;
186+
}
187+
188+
/**
189+
* Returns the payload used for compilation. Parses projects files and libraries
190+
* already existing in request and fetches any necessary libraries from eratosthenes.
191+
*
192+
* @return JsonResponse
193+
*/
194+
public function generatePayloadAction()
195+
{
196+
$providedPayload = json_decode($this->getRequest()->getContent(), true);
197+
198+
$payload = $this->generateCompilerPayload($providedPayload);
199+
if (empty($payload)) {
200+
return new JsonResponse(['success' => false, 'message' => 'Invalid compilation payload provided.']);
201+
}
202+
203+
$payload['success'] = true;
204+
$payload['additionalCode'] = $this->additionalCode;
205+
$this->additionalCode = [];
206+
207+
return new JsonResponse($payload);
208+
}
209+
210+
/**
211+
* Returns the payload of a compilation request. Sketch files and board-related
212+
* data (build, core, variant) must be provided in the initial payload.
213+
*
214+
* @param array $providedData
215+
* @return array
216+
*/
217+
protected function generateCompilerPayload(array $providedData)
218+
{
219+
$payload = $this->addUserIdProjectIdIfNotInRequest($providedData);
220+
221+
if (!array_key_exists('files', $payload)) {
222+
return [];
223+
}
224+
225+
$files = $payload['files'];
226+
227+
$userLibraries = [];
228+
229+
if (array_key_exists('libraries', $payload)) {
230+
$userLibraries = $payload['libraries'];
231+
}
232+
233+
$payload['libraries'] = $this->returnProvidedAndFetchedLibraries($files, $userLibraries);
234+
235+
return $payload;
206236
}
207237

208238
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Codebender\BuilderBundle\EventListener;
4+
5+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
6+
use Symfony\Component\HttpFoundation\JsonResponse;
7+
8+
class AuthListener
9+
{
10+
protected $authorizationKey;
11+
12+
protected $apiVersion;
13+
14+
public function __construct($authorizationKey, $apiVersion)
15+
{
16+
$this->authorizationKey = $authorizationKey;
17+
$this->apiVersion = $apiVersion;
18+
}
19+
20+
public function onKernelRequest(GetResponseEvent $event)
21+
{
22+
$request = $event->getRequest();
23+
// don't execute on status action
24+
if ($request->get('_route') == 'CodebenderBuilderBundle_status_check') {
25+
return;
26+
}
27+
$providedAuthKey = $request->attributes->get('authKey');
28+
$providedApiVersion = $request->attributes->get('version');
29+
30+
if ($providedAuthKey !== $this->authorizationKey) {
31+
$event->setResponse(new JsonResponse(['success' => false, 'message' => 'Invalid authorization key.']));
32+
return;
33+
}
34+
35+
if ($providedApiVersion !== $this->apiVersion) {
36+
$event->setResponse(new JsonResponse(['success' => false, 'message' => 'Invalid api version.']));
37+
return;
38+
}
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Codebender\BuilderBundle\EventListener;
4+
5+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
6+
use Symfony\Component\HttpFoundation\JsonResponse;
7+
8+
class DataValidationListener
9+
{
10+
public function onKernelRequest(GetResponseEvent $event)
11+
{
12+
$request = $event->getRequest();
13+
// don't execute on status action
14+
if ($request->get('_route') == 'CodebenderBuilderBundle_status_check') {
15+
return;
16+
}
17+
$requestContent = json_decode($request->getContent(), true);
18+
if ($requestContent === null || json_last_error() != JSON_ERROR_NONE) {
19+
$event->setResponse(new JsonResponse(['success' => false, 'message' => 'Invalid input.']));
20+
}
21+
}
22+
}

Symfony/src/Codebender/BuilderBundle/Resources/config/routing.yml

+6
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ CodebenderBuilderBundle_handle_request:
77
defaults: { _controller: CodebenderBuilderBundle:Default:handleRequest }
88
requirements:
99
_method: POST
10+
11+
CodebenderBuilderBundle_ganerate_compiler_payload:
12+
pattern: /{authKey}/{version}/payload
13+
defaults: { _controller: CodebenderBuilderBundle:Default:generatePayload }
14+
requirements:
15+
_method: POST

Symfony/src/Codebender/BuilderBundle/Tests/Controller/DefaultControllerFunctionalTest.php

+48-1
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,27 @@ public function testStatusAction() {
2121
$this->assertEquals($client->getResponse()->getContent(), '{"success":true,"status":"OK"}');
2222
}
2323

24-
public function testHandleRequestGet() {
24+
public function testHandleRequestErrors() {
2525
$client = static::createClient();
2626

2727
$authorizationKey = $client->getContainer()->getParameter('authorizationKey');
2828
$apiVersion = $client->getContainer()->getParameter('version');
2929
$client->request('GET', "/{$authorizationKey}/{$apiVersion}/");
3030

3131
$this->assertEquals($client->getResponse()->getStatusCode(), 405);
32+
33+
// insufficient data
34+
$content = json_encode(['type' => 'compiler']);
35+
$response = $this->performPostRequest($content);
36+
$this->assertFalse($response['success']);
37+
$this->assertEquals('Insufficient data provided.', $response['message']);
38+
39+
// invalid action requested
40+
$content = json_encode(['type' => 'helloooo', 'data' => []]);
41+
$response = $this->performPostRequest($content);
42+
$this->assertFalse($response['success']);
43+
$this->assertEquals('Invalid request type (can handle only \'compiler\' or \'library\' requests)',
44+
$response['message']);
3245
}
3346

3447
public function testHandleRequestCompile() {
@@ -96,4 +109,38 @@ public function testHandleRequestLibraryKeywords() {
96109
$this->assertArrayHasKey('keywords', $response);
97110
$this->assertTrue(is_array($response['keywords']));
98111
}
112+
113+
public function testGeneratePayloadAction()
114+
{
115+
$providedContent = '{"files":[{"filename":"project.ino","content":"void setup(){\n\n}\nvoid loop(){\n\n}\n"}],"format":"binary","version":"105","build":{"mcu":"atmega328p","f_cpu":"16000000L","core":"arduino","variant":"standard"}}';
116+
$response = $this->performPostRequest($providedContent, 'payload');
117+
$this->assertEquals(
118+
['userId', 'projectId', 'files', 'format', 'version', 'build', 'libraries', 'success', 'additionalCode'],
119+
array_keys($response)
120+
);
121+
}
122+
123+
/**
124+
* Performs a POST
125+
* @param string $requestContent JSON-encoded POST request content
126+
* @param string $uri
127+
* @return array
128+
*/
129+
protected function performPostRequest($requestContent, $uri = '')
130+
{
131+
$client = static::createClient();
132+
$authorizationKey = $client->getContainer()->getParameter('authorizationKey');
133+
$apiVersion = $client->getContainer()->getParameter('version');
134+
$client
135+
->request(
136+
'POST',
137+
"/{$authorizationKey}/{$apiVersion}/" . $uri,
138+
$parameters = [],
139+
$files = [],
140+
$server = [],
141+
$content = $requestContent,
142+
$changeHistory = true);
143+
144+
return json_decode($client->getResponse()->getContent(), true);
145+
}
99146
}

0 commit comments

Comments
 (0)