Skip to content

Commit 05cc75c

Browse files
committed
Merge pull request #13 from codebendercc/libtest-updates
Libtest updates
2 parents b8a470b + 92fbad2 commit 05cc75c

File tree

5 files changed

+232
-24
lines changed

5 files changed

+232
-24
lines changed

Diff for: Symfony/src/Codebender/LibraryBundle/Controller/DefaultController.php

+71-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Symfony\Component\Finder\Finder;
99
use Symfony\Component\HttpFoundation\JsonResponse;
1010
use Symfony\Component\HttpFoundation\Response;
11-
use Symfony\Component\HttpFoundation\Request;
11+
use Doctrine\ORM\EntityManager;
1212

1313
class DefaultController extends Controller
1414
{
@@ -76,22 +76,25 @@ private function selectAction($content)
7676
return $handler->checkGithubUpdates();
7777
case "getKeywords":
7878
return $this->getKeywords($content["library"]);
79+
case 'deleteLibrary':
80+
return $this->deleteLibrary($content['library']);
7981
default:
8082
return ['success' => false, 'message' => 'No valid action requested'];
8183
}
8284
}
8385

8486
private function isValid($requestContent)
8587
{
86-
if (!array_key_exists("type", $requestContent)) {
88+
if (!array_key_exists('type', $requestContent)) {
8789
return false;
8890
}
8991

90-
if (in_array($requestContent["type"], array("getExampleCode", "getExamples", "fetch", "getKeywords")) && !array_key_exists("library", $requestContent)) {
92+
if (in_array($requestContent['type'], ['getExampleCode', 'getExamples', 'fetch', 'getKeywords', 'deleteLibrary'])
93+
&& !array_key_exists('library', $requestContent)) {
9194
return false;
9295
}
9396

94-
if ($requestContent["type"] == "getExampleCode" && !array_key_exists("example", $requestContent)) {
97+
if ($requestContent['type'] == 'getExampleCode' && !array_key_exists('example', $requestContent)) {
9598
return false;
9699
}
97100

@@ -217,6 +220,68 @@ public function getRepoGitTreeAndMetaAction()
217220
]);
218221
}
219222

223+
/**
224+
* Deletes a library based on the provided.
225+
*
226+
* @param string $machineName
227+
* @return array
228+
*/
229+
public function deleteLibrary($machineName)
230+
{
231+
$exists = $this->getLibraryType($machineName, true);
232+
if ($exists['success'] !== true) {
233+
return ['success' => false, 'error' => $exists['message']];
234+
}
235+
if ($exists['type'] != 'external') {
236+
return ['success' => false, 'error' => 'Library ' . $machineName . ' is not an external library.'];
237+
}
238+
$storagePath = $this->container->getParameter('external_libraries') . '/' . $machineName;
239+
if (!file_exists($storagePath)) {
240+
return ['success' => false, 'error' => 'Library ' . $machineName . ' does not exist in filesystem.'];
241+
}
242+
243+
$this->removeLibraryExamplesEntities($machineName);
244+
$this->removeLibraryEntity($machineName);
245+
246+
/* @var \Codebender\LibraryBundle\Handler\DefaultHandler $handler */
247+
$handler = $this->get('codebender_library.handler');
248+
249+
$handler->removeDirectory($storagePath);
250+
251+
return ['success' => true, 'message' => 'Library ' . $machineName . ' deleted successfully.'];
252+
}
253+
254+
private function removeLibraryEntity($machineName)
255+
{
256+
/* @var EntityManager $entityManager */
257+
$entityManager = $this->container->get('doctrine')->getManager();
258+
259+
/* @var ExternalLibrary $libraryEntity */
260+
$libraryEntity = $entityManager->getRepository('CodebenderLibraryBundle:ExternalLibrary')
261+
->findOneBy(['machineName' => $machineName]);
262+
263+
$entityManager->remove($libraryEntity);
264+
$entityManager->flush();
265+
}
266+
267+
private function removeLibraryExamplesEntities($machineName)
268+
{
269+
/* @var EntityManager $entityManager */
270+
$entityManager = $this->container->get('doctrine')->getManager();
271+
272+
/* @var ExternalLibrary $libraryEntity */
273+
$libraryEntity = $entityManager->getRepository('CodebenderLibraryBundle:ExternalLibrary')
274+
->findOneBy(['machineName' => $machineName]);
275+
276+
$libraryExamples = $entityManager->getRepository('CodebenderLibraryBundle:Example')
277+
->findBy(['library' => $libraryEntity->getId()]);
278+
foreach ($libraryExamples as $example) {
279+
/* @var Example $example */
280+
$entityManager->remove($example);
281+
}
282+
$entityManager->flush();
283+
}
284+
220285
private function getLibraryExamples($library)
221286
{
222287
$exists = $this->getLibraryType($library);
@@ -272,14 +337,14 @@ private function getLibraryExamples($library)
272337
return ['success' => true, 'examples' => $examples];
273338
}
274339

275-
private function getLibraryType($library)
340+
private function getLibraryType($library, $checkDisabledToo = false)
276341
{
277342
$handler = $this->get('codebender_library.handler');
278343

279344
/*
280345
* Each library's type can be either external () ..
281346
*/
282-
$isExternal = json_decode($handler->checkIfExternalExists($library), true);
347+
$isExternal = json_decode($handler->checkIfExternalExists($library, $checkDisabledToo), true);
283348
if ($isExternal['success']) {
284349
return ['success' => true, 'type' => 'external'];
285350
}

Diff for: Symfony/src/Codebender/LibraryBundle/Controller/ViewsController.php

+13-15
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ private function addLibrary($data)
8787
$lastCommit = $handler->getLastCommitFromGithub($data['GitOwner'], $data['GitRepo'], $data['GitBranch'], $path);
8888
break;
8989
case 'zip':
90-
$libraryStructure = json_decode($this->getLibFromZipFile($data["Zip"]), true);
90+
$libraryStructure = $this->getLibFromZipFile($data["Zip"]);
9191
break;
9292
}
9393

@@ -454,23 +454,23 @@ private function getLibFromZipFile($file)
454454
$handler = $this->get('codebender_library.handler');
455455
$zip->extractTo('/tmp/lib/');
456456
$zip->close();
457-
$dir = json_decode($this->processZipDir('/tmp/lib'), true);
457+
$dir = $this->processZipDir('/tmp/lib');
458458

459459
if (!$dir['success']) {
460460
return json_encode($dir);
461461
}
462462

463463
$dir = $dir['directory'];
464-
$baseDir = json_decode($handler->findBaseDir($dir), true);
464+
$baseDir = $handler->findBaseDir($dir);
465465
if ($baseDir['success'] !== true) {
466-
return json_encode($baseDir);
466+
return $baseDir;
467467
}
468468

469469
$baseDir = $baseDir['directory'];
470470

471-
return json_encode(['success' => true, 'library' => $baseDir]);
471+
return ['success' => true, 'library' => $baseDir];
472472
} else {
473-
return json_encode(['success' => false, 'message' => 'Could not unzip Archive. Code: ' . $opened]);
473+
return ['success' => false, 'message' => 'Could not unzip Archive. Code: ' . $opened];
474474
}
475475
}
476476

@@ -484,34 +484,32 @@ private function processZipDir($path)
484484
}
485485

486486
if (is_dir($path . '/' . $file)) {
487-
$subdir = json_decode($this->processZipDir($path . '/' . $file), true);
487+
$subdir = $this->processZipDir($path . '/' . $file);
488488
if ($subdir['success'] !== true) {
489-
return json_encode($subdir);
489+
return $subdir;
490490
}
491491
array_push($files, $subdir['directory']);
492492
} else {
493-
$file = json_decode($this->processZipFile($path . '/' . $file), true);
493+
$file = $this->processZipFile($path . '/' . $file);
494494
if ($file['success'] === true) {
495495
array_push($files, $file['file']);
496496
} else if ($file['message'] != "Bad Encoding") {
497-
return json_encode($file);
497+
return $file;
498498
}
499499
}
500500
}
501-
return json_encode(
502-
['success' => true, 'directory' => ['name' => substr($path, 9), 'type' => 'dir', 'contents' => $files]]
503-
);
501+
return ['success' => true, 'directory' => ['name' => substr($path, 9), 'type' => 'dir', 'contents' => $files]];
504502
}
505503

506504
private function processZipFile($path)
507505
{
508506
$contents = file_get_contents($path);
509507

510508
if ($contents === null) {
511-
return json_encode(['success' => false, 'message' => 'Could not read file ' . basename($path)]);
509+
return ['success' => false, 'message' => 'Could not read file ' . basename($path)];
512510
}
513511

514-
return json_encode(['success' => true, 'file' => ['name' => basename($path), 'type' => 'file', 'contents' => $contents]]);
512+
return ['success' => true, 'file' => ['name' => basename($path), 'type' => 'file', 'contents' => $contents]];
515513
}
516514

517515
private function destroy_dir($dir)

Diff for: Symfony/src/Codebender/LibraryBundle/Handler/DefaultHandler.php

+35-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\ContainerInterface;
1616
use Symfony\Component\HttpFoundation\JsonResponse;
1717
use Symfony\Component\HttpFoundation\Response;
18+
use DirectoryIterator;
1819

1920
class DefaultHandler
2021
{
@@ -386,7 +387,7 @@ public function findBaseDir($dir)
386387
{
387388
foreach ($dir['contents'] as $file) {
388389
if ($file['type'] == 'file' && strpos($file['name'], ".h") !== false)
389-
return json_encode(array('success' => true, 'directory' => $dir));
390+
return ['success' => true, 'directory' => $dir];
390391

391392
}
392393

@@ -395,7 +396,7 @@ public function findBaseDir($dir)
395396
foreach ($file['contents'] as $f) {
396397
if ($f['type'] == 'file' && strpos($f['name'], ".h") !== false) {
397398
$file = $this->fixDirName($file);
398-
return json_encode(array('success' => true, 'directory' => $file));
399+
return ['success' => true, 'directory' => $file];
399400
}
400401
}
401402
}
@@ -716,4 +717,36 @@ public function getRepoDefaultDescription($owner, $repo)
716717
return $gitResponse['description'];
717718
}
718719

720+
/**
721+
* Recursively removes a directory and its contents.
722+
*
723+
* @param string $directory
724+
* @throws \Exception
725+
*/
726+
public function removeDirectory($directory)
727+
{
728+
$directory = realpath($directory);
729+
if (!file_exists($directory)) {
730+
return;
731+
}
732+
$directoryIterator = new DirectoryIterator($directory);
733+
foreach ($directoryIterator as $directoryElement) {
734+
if ($directoryElement->isDot()) {
735+
continue;
736+
}
737+
if ($directoryElement->isDir()) {
738+
$this->removeDirectory($directoryElement->getRealPath());
739+
continue;
740+
}
741+
if (unlink($directoryElement->getRealPath()) !== true) {
742+
throw new \Exception(
743+
'Cannot delete file: ' . $directoryElement->getRealPath()
744+
);
745+
}
746+
}
747+
if (rmdir($directory) !== true) {
748+
throw new \Exception('Cannot delete directory: ' . $directory);
749+
}
750+
}
751+
719752
}

Diff for: Symfony/src/Codebender/LibraryBundle/Resources/views/Default/libraryView.html.twig

+67-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@
7676
<br/><br/>
7777
<span>This is a <strong>builtin</strong> library</span>
7878
{% endif %}
79+
<br/>
80+
<button class="btn btn-danger" id="delete-library-button" href=""> Delete library </button>
81+
<span id="delete-library-output"></span>
7982
</div>
8083
{% if meta %}
8184
{% if meta.description %}
@@ -138,6 +141,40 @@
138141
</div>
139142
</div>
140143
<div class="span1"></div>
144+
<!-- Library Deletion Modal -->
145+
<div id="deletionModal" class="modal fade" role="dialog">
146+
<div class="modal-dialog">
147+
<!-- Modal content-->
148+
<div class="modal-content">
149+
<div class="modal-header">
150+
<h4 class="modal-title">Delete {{ library }} library</h4>
151+
</div>
152+
<div class="modal-body">
153+
<p>You are about to permanently delete {{ library }} library. Are you sure?</p>
154+
<button id="yes-button" class="btn btn-default">Do it!</button>
155+
<button id="no-button" class="btn btn-default" data-dismiss="modal">God no..</button>
156+
</div>
157+
</div>
158+
159+
</div>
160+
</div>
161+
<!-- Library Deleted Modal -->
162+
<div id="deletedModal" class="modal fade" role="dialog">
163+
<div class="modal-dialog">
164+
<!-- Modal content-->
165+
<div class="modal-content">
166+
<div class="modal-header">
167+
<h4 class="modal-title">Library {{ library }} deleted!</h4>
168+
</div>
169+
<div class="modal-body">
170+
<p>Click on the button below to get redirected to the library addition page.</p>
171+
<button id="redirect-button" class="btn btn-default">Take me there</button>
172+
<p><strong>Don't forget to delete the cached library object files from the compiler!</strong></p>
173+
</div>
174+
</div>
175+
176+
</div>
177+
</div>
141178
</div>
142179

143180
<script type="text/javascript">
@@ -147,7 +184,7 @@
147184
var route = "{{ path('codebender_library_status_change', {'authorizationKey': authorizationKey, 'library': "LIBRARYNAME"}) }}";
148185
$.post( route.replace("LIBRARYNAME", library) )
149186
.done(function( data ) {
150-
var response = jQuery.parseJSON(data);
187+
var response = data;
151188
if(response.success)
152189
{
153190
$("#statusbutton").toggleClass("btn-success");
@@ -166,6 +203,35 @@
166203
});
167204
}
168205
206+
$(document).ready(function() {
207+
208+
$('#delete-library-button').click(function() {
209+
$('#deletionModal').modal('show');
210+
});
211+
$("#yes-button").click(function () {
212+
$('#deletionModal').modal('hide');
213+
$.ajax({
214+
type: "POST",
215+
url: "{{ path('codebender_api_handler', {'authorizationKey' : authorizationKey, 'version' : 'v1'}) }}",
216+
data: '{"type":"deleteLibrary","library":"{{ library }}"}',
217+
dataType: 'json'
218+
}).done(function( data ) {
219+
if(!data.success) {
220+
$("#delete-library-output").html(data.error);
221+
}
222+
if(data.success) {
223+
$('.btn').attr('disabled', 'disabled'); //disable all buttons to avoid performing operations on a deleted library
224+
$('#redirect-button').removeAttr('disabled');
225+
$('#deletedModal').modal('show');
226+
}
227+
});
228+
});
229+
230+
$('#redirect-button').click(function(){
231+
window.location.replace("{{ path('codebender_library_new_external', {'authorizationKey': authorizationKey}) }}");
232+
});
233+
});
234+
169235
</script>
170236

171237
</body>

0 commit comments

Comments
 (0)