function testCleanupFiles_4Files2Allowed_2Removed()
 {
     $project = self::$environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $project->write();
     $text = new TextModel($project);
     $textId = $text->write();
     $fakeId = new Id();
     $fakeTextId = $fakeId->asString();
     $folderPath = $project->getAssetsFolderPath();
     FileUtilities::createAllFolders($folderPath);
     $allowedExtensions = array(".mp2", ".mp3");
     // put a copy of the test files in the folderPath
     $fileName1 = 'TestAudio1.mp1';
     $filePath1 = SfchecksUploadCommands::mediaFilePath($folderPath, $textId, $fileName1);
     copy(TestPhpPath . 'common/TestAudio.mp3', $filePath1);
     $fileName2 = 'TestAudio2.mp2';
     $filePath2 = SfchecksUploadCommands::mediaFilePath($folderPath, $textId, $fileName2);
     copy(TestPhpPath . 'common/TestAudio.mp3', $filePath2);
     $fileName3 = 'TestAudio3.mp3';
     $filePath3 = SfchecksUploadCommands::mediaFilePath($folderPath, $textId, $fileName3);
     copy(TestPhpPath . 'common/TestAudio.mp3', $filePath3);
     $fileName4 = 'TestAudio4.mp3';
     $filePath4 = SfchecksUploadCommands::mediaFilePath($folderPath, $fakeTextId, $fileName4);
     copy(TestPhpPath . 'common/TestAudio.mp3', $filePath4);
     $this->assertTrue(file_exists($filePath1), 'File should exist before cleanup');
     $this->assertTrue(file_exists($filePath2), 'File should exist before cleanup');
     $this->assertTrue(file_exists($filePath3), 'File should exist before cleanup');
     $this->assertTrue(file_exists($filePath4), 'File should exist before cleanup');
     SfchecksUploadCommands::cleanupFiles($folderPath, $textId, $allowedExtensions);
     $this->assertTrue(file_exists($filePath1), 'File should exist after cleanup');
     $this->assertFalse(file_exists($filePath2), 'File should not exist after cleanup');
     $this->assertFalse(file_exists($filePath3), 'File should not exist after cleanup');
     $this->assertTrue(file_exists($filePath4), 'File should exist after cleanup');
     self::$environ->cleanupTestFiles($folderPath);
 }
 public function testInitializeNewProject_SendReceiveProjectAndExistingTargetFile_SourceFileMovedAndSymlinksCreated()
 {
     $project = self::$environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $project->sendReceiveProjectIdentifier = 'sr_id';
     $project->sendReceiveProject = new SendReceiveProjectModel('sr_name', '', 'manager');
     $project->write();
     $this->assertTrue($project->hasSendReceive());
     $projectWorkPath = $project->getSendReceiveWorkFolder();
     $srImagePath = $projectWorkPath . DIRECTORY_SEPARATOR . 'LinkedFiles' . DIRECTORY_SEPARATOR . 'Pictures';
     FileUtilities::createAllFolders($srImagePath);
     $srTestImageFilePath = $srImagePath . DIRECTORY_SEPARATOR . 'existingTargetImage.jpg';
     touch($srTestImageFilePath);
     $this->assertTrue(file_exists($srTestImageFilePath));
     $assetImagePath = $project->getImageFolderPath();
     $filenameToMove = 'existingSourceImage.jpg';
     $filePathToMove = $assetImagePath . DIRECTORY_SEPARATOR . $filenameToMove;
     touch($filePathToMove);
     $this->assertTrue(file_exists($filePathToMove));
     $project->initializeNewProject();
     $this->assertTrue(is_link($assetImagePath));
     $this->assertTrue(file_exists($srTestImageFilePath));
     $this->assertTrue(file_exists($filePathToMove));
     $this->assertTrue(file_exists($srImagePath . DIRECTORY_SEPARATOR . $filenameToMove));
     $assetAudioPath = $project->getAudioFolderPath();
     $this->assertTrue(is_link($assetAudioPath));
     $project->initializeNewProject();
     $this->assertTrue(is_link($assetImagePath));
     $this->assertTrue(file_exists($srTestImageFilePath));
     $this->assertTrue(file_exists($filePathToMove));
     $this->assertTrue(file_exists($srImagePath . DIRECTORY_SEPARATOR . $filenameToMove));
     $this->assertTrue(is_link($assetAudioPath));
     FileUtilities::removeFolderAndAllContents($project->getAssetsFolderPath());
     FileUtilities::removeFolderAndAllContents($projectWorkPath);
 }
 /**
  * Import a LIFT file
  *
  * @param string $projectId
  * @param string $mediaType
  * @param string $tmpFilePath
  * @throws \Exception
  * @return \Api\Model\Shared\Command\UploadResponse
  */
 public static function importLiftFile($projectId, $mediaType, $tmpFilePath)
 {
     if ($mediaType != 'import-lift') {
         throw new \Exception("Unsupported upload type.");
     }
     if (!$tmpFilePath) {
         throw new \Exception("Upload controller did not move the uploaded file.");
     }
     $file = $_FILES['file'];
     $fileName = $file['name'];
     $mergeRule = $_POST['mergeRule'];
     $skipSameModTime = $_POST['skipSameModTime'];
     $deleteMatchingEntry = $_POST['deleteMatchingEntry'];
     $finfo = finfo_open(FILEINFO_MIME_TYPE);
     $fileType = finfo_file($finfo, $tmpFilePath);
     finfo_close($finfo);
     $fileName = FileUtilities::replaceSpecialCharacters($fileName);
     $fileExt = false === ($pos = strrpos($fileName, '.')) ? '' : substr($fileName, $pos);
     $allowedTypes = array("text/xml", "application/xml");
     $response = new UploadResponse();
     if (in_array(strtolower($fileType), $allowedTypes) && in_array(strtolower($fileExt), self::$allowedLiftExtensions)) {
         // make the folders if they don't exist
         $project = new LexiconProjectModel($projectId);
         $folderPath = $project->getAssetsFolderPath();
         FileUtilities::createAllFolders($folderPath);
         $importer = LiftImport::get()->merge($tmpFilePath, $project, $mergeRule, $skipSameModTime, $deleteMatchingEntry);
         $project->write();
         $moveOk = true;
         if (!$project->liftFilePath || $mergeRule != LiftMergeRule::IMPORT_LOSES) {
             // cleanup previous files of any allowed extension
             $cleanupFiles = glob($folderPath . '/*[' . implode(', ', self::$allowedLiftExtensions) . ']');
             foreach ($cleanupFiles as $cleanupFile) {
                 @unlink($cleanupFile);
             }
             // move uploaded LIFT file from tmp location to assets
             $filePath = $folderPath . '/' . $fileName;
             $project->liftFilePath = $filePath;
             $project->write();
             $moveOk = copy($tmpFilePath, $filePath);
             @unlink($tmpFilePath);
         }
         // construct server response
         if ($moveOk && $tmpFilePath) {
             $data = new ImportResult();
             $data->path = $project->getAssetsRelativePath();
             $data->fileName = $fileName;
             $data->stats = $importer->stats;
             $data->importErrors = $importer->getReport()->toFormattedString();
             $response->result = true;
         } else {
             $data = new ErrorResult();
             $data->errorType = 'UserMessage';
             $data->errorMessage = "{$fileName} could not be saved to the right location. Contact your Site Administrator.";
             $response->result = false;
         }
     } else {
         $allowedExtensionsStr = implode(", ", self::$allowedLiftExtensions);
         $data = new ErrorResult();
         $data->errorType = 'UserMessage';
         if (count(self::$allowedLiftExtensions) < 1) {
             $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. No LIFT file formats are currently enabled, contact your Site Administrator.";
         } elseif (count(self::$allowedLiftExtensions) == 1) {
             $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. Ensure the file is a {$allowedExtensionsStr}.";
         } else {
             $data->errorMessage = "{$fileName} of type: {$fileType} is not an allowed LIFT file. Ensure the file is one of the following types: {$allowedExtensionsStr}.";
         }
         $response->result = false;
     }
     $response->data = $data;
     return $response;
 }
 /**
  * Cleanup associated project files
  */
 protected function cleanup()
 {
     parent::cleanup();
     if (!is_null($this->projectCode)) {
         $projectFilename = strtolower($this->projectCode);
         $stateFilename = strtolower($this->projectCode) . '.state';
         $lfmergePaths = SendReceiveCommands::getLFMergePaths();
         foreach ($lfmergePaths as $key => $path) {
             if (!is_null($path)) {
                 if ($key == "workPath") {
                     FileUtilities::removeFolderAndAllContents($lfmergePaths->workPath . DIRECTORY_SEPARATOR . $projectFilename);
                 }
                 if (file_exists($path . DIRECTORY_SEPARATOR . $projectFilename)) {
                     unlink($path . DIRECTORY_SEPARATOR . $projectFilename);
                 }
                 if (file_exists($path . DIRECTORY_SEPARATOR . $stateFilename)) {
                     unlink($path . DIRECTORY_SEPARATOR . $stateFilename);
                 }
             }
         }
     }
 }
 /**
  * Cleanup test files and folders
  *
  * @param string $assetsFolderPath
  */
 public function cleanupTestFiles($assetsFolderPath)
 {
     $this->cleanupTestUploadFiles();
     FileUtilities::removeFolderAndAllContents($assetsFolderPath);
 }
Exemplo n.º 6
0
 /**
  * Add node as a custom field
  *
  * @param SimpleXMLElement $sxeNode
  * @param string $nodeId
  * @param string $customFieldNamePrefix
  * @param array $customFieldSpecs
  * @param LexiconFieldListConfigObj $levelConfig
  * @param LexEntryModel|Sense|Example $item
  */
 private function addCustomField($sxeNode, $nodeId, $customFieldNamePrefix, $levelConfig, $item)
 {
     $fieldType = FileUtilities::replaceSpecialCharacters($nodeId);
     $customFieldSpecs = $this->getCustomFieldSpecs($fieldType);
     $customFieldName = $this->createCustomField($nodeId, $fieldType, $customFieldNamePrefix, $customFieldSpecs, $levelConfig);
     if ($customFieldSpecs['Type'] == 'ReferenceAtom') {
         $item->customFields[$customFieldName] = new LexiconField();
         $item->customFields[$customFieldName]->value = (string) $sxeNode['value'];
     } elseif ($customFieldSpecs['Type'] == 'ReferenceCollection') {
         if (!array_key_exists($customFieldName, $item->customFields)) {
             $item->customFields[$customFieldName] = new LexiconMultiValueField();
         }
         $item->customFields[$customFieldName]->value((string) $sxeNode['value']);
     } elseif ($customFieldSpecs['Type'] == 'OwningAtom') {
         $multiText = $this->readMultiText($sxeNode, $levelConfig->fields[$customFieldName]->inputSystems);
         $item->customFields[$customFieldName] = self::convertMultiParaMultiText($multiText);
     } else {
         $item->customFields[$customFieldName] = $this->readMultiText($sxeNode, $levelConfig->fields[$customFieldName]->inputSystems);
     }
 }
Exemplo n.º 7
0
 /**
  * @param string $zipFilePath
  * @param string $destDir
  * @throws \Exception
  */
 public static function extractZip($zipFilePath, $destDir)
 {
     // Use absolute path for archive file
     $realpathResult = realpath($zipFilePath);
     if ($realpathResult) {
         $zipFilePath = $realpathResult;
     } else {
         throw new \Exception("Error receiving uploaded file");
     }
     if (!file_exists($realpathResult)) {
         throw new \Exception("Error file '{$zipFilePath}' does not exist.");
     }
     $basename = basename($zipFilePath);
     $pathinfo = pathinfo($basename);
     $extension_1 = isset($pathinfo['extension']) ? $pathinfo['extension'] : 'NOEXT';
     // Handle .tar.gz, .tar.bz2, etc. by checking if there's another extension "inside" the first one
     $basename_without_ext = $pathinfo['filename'];
     $pathinfo = pathinfo($basename_without_ext);
     $extension_2 = isset($pathinfo['extension']) ? $pathinfo['extension'] : 'NOEXT';
     // $extension_2 will be 'tar' if the file was a .tar.gz, .tar.bz2, etc.
     if ($extension_2 == "tar") {
         // We don't handle tarball formats... yet.
         throw new \Exception("Sorry, the ." . $extension_2 . "." . $extension_1 . " format isn't allowed");
     }
     switch ($extension_1) {
         case "zip":
             $cmd = 'unzip ' . escapeshellarg($zipFilePath) . " -d " . escapeshellarg($destDir);
             break;
         case "zipx":
         case "7z":
             $cmd = '7z x ' . escapeshellarg($zipFilePath) . " -o" . escapeshellarg($destDir);
             break;
         default:
             throw new \Exception("Sorry, the ." . $extension_1 . " format isn't allowed");
             break;
     }
     FileUtilities::createAllFolders($destDir);
     $destFilesBeforeUnpacking = scandir($destDir);
     // ensure non-roman filesnames are returned
     $cmd = 'LANG="en_US.UTF-8" ' . $cmd;
     $output = array();
     $retcode = 0;
     exec($cmd, $output, $retcode);
     if ($retcode) {
         if ($retcode != 1 || $retcode == 1 && strstr(end($output), 'failed setting times/attribs') == false) {
             throw new \Exception("Uncompressing archive file failed: " . print_r($output, true));
         }
     }
     // If the .zip contained just one top-level folder with all contents below that folder,
     // "promote" the contents up one level so that $destDir contains all the .zip's contents.
     $destFilesAfterUnpacking = scandir($destDir);
     if (count($destFilesAfterUnpacking) == count($destFilesBeforeUnpacking) + 1) {
         $diff = array_values(array_diff($destFilesAfterUnpacking, $destFilesBeforeUnpacking));
         $zipTopLevel = $diff[0];
         if (is_dir($destDir . "/" . $zipTopLevel)) {
             FileUtilities::promoteDirContents($destDir . "/" . $zipTopLevel);
         }
     }
 }
Exemplo n.º 8
0
$changeDatabase = false;
// process xml into a php data structure, organized by language
$xml = simplexml_load_file($xmlFilePath);
$lang = $argv[2];
$version = $argv[3];
$projectCode = "semdom-{$lang}-{$semdomVersion}";
$projectName = "Semdom {$lang} Project";
$appName = LfProjectModel::SEMDOMTRANS_APP;
$website = new Website($domain, Website::LANGUAGEFORGE);
// if a previous project for that language and semantic domain version exists, DO NOT IMPORT
$previousProject = new SemDomTransProjectModel();
$previousProject->readByProperties(array("languageIsoCode" => $lang, "semdomVersion" => $semdomVersion));
if ($previousProject->id->asString() == "") {
    $sourceProject = new SemDomTransProjectModel();
    $sourceProject->readByCode("en");
    $projectID = ProjectCommands::createProject($projectName, $projectCode, $appName, $userId, $website);
    $projectModel = new SemDomTransProjectModel($projectID);
    $newXmlFilePath = $projectModel->getAssetsFolderPath() . '/' . basename($xmlFilePath);
    FileUtilities::createAllFolders($projectModel->getAssetsFolderPath());
    print "copying {$xmlFilePath} to  {$newXmlFilePath}\n";
    copy($xmlFilePath, $newXmlFilePath);
    $projectModel->xmlFilePath = $newXmlFilePath;
    $projectModel->languageIsoCode = $lang;
    $projectModel->semdomVersion = $semdomVersion;
    $projectModel->sourceLanguageProjectId = $sourceProject->id->asString();
    $projectModel->write();
    $importer = new SemDomXMLImporter($xmlFilePath, $projectModel, false, $isEnglish);
    $importer->run();
} else {
    echo "Project exists already" . "\n";
}
            unlink($filePath);
        }
    }
    FileUtilities::removeFolderAndAllContents($otherAssetsFolderPath);
}
// cleanup LfMerge 'syncqueue', 'webwork' and 'state' folders
if ($testProject->appName == LexProjectModel::LEXICON_APP) {
    $syncQueuePath = SendReceiveCommands::getLFMergePaths()->syncQueuePath;
    foreach (glob("{$syncQueuePath}/*") as $file) {
        if (is_file($file)) {
            unlink($file);
        }
    }
    $workPath = SendReceiveCommands::getLFMergePaths()->workPath;
    FileUtilities::removeFolderAndAllContents($workPath . DIRECTORY_SEPARATOR . $constants['srProjectCode']);
    FileUtilities::removeFolderAndAllContents($workPath . DIRECTORY_SEPARATOR . 'mock-id4');
    $stateFilePath = SendReceiveCommands::getLFMergePaths()->statePath . DIRECTORY_SEPARATOR . 'mock-id4.state';
    if (is_file($stateFilePath)) {
        unlink($stateFilePath);
    }
}
// cleanup mocked uploaded zip import (jpg file)
$tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $constants['testMockJpgImportFile']['name'];
@unlink($tmpFilePath);
// cleanup mocked uploaded zip import (zip file)
$tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $constants['testMockZipImportFile']['name'];
@unlink($tmpFilePath);
// cleanup mock uploaded audio (png file)
$tmpFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $constants['testMockPngUploadFile']['name'];
@unlink($tmpFilePath);
// cleanup mock uploaded audio (mp3 file)
 public function testCreateProject_NewSRProject_SRProjectWithLinks()
 {
     self::$environ = new LexiconMongoTestEnvironment();
     self::$environ->clean();
     $user1Id = self::$environ->createUser("user1name", "User1 Name", "*****@*****.**");
     $user1 = new UserModel($user1Id);
     $srProject = array('identifier' => 'srIdentifier', 'name' => 'srName', 'repository' => 'http://public.languagedepot.org', 'role' => 'manager');
     $projectId = ProjectCommands::createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE, LexProjectModel::LEXICON_APP, $user1->id->asString(), self::$environ->website, $srProject);
     $project = new LexProjectModel($projectId);
     $assetImagePath = $project->getImageFolderPath();
     $assetAudioPath = $project->getAudioFolderPath();
     $this->assertTrue($project->hasSendReceive());
     $this->assertTrue(is_link($assetImagePath));
     $this->assertTrue(is_link($assetAudioPath));
     $projectWorkPath = $project->getSendReceiveWorkFolder();
     FileUtilities::removeFolderAndAllContents($project->getAssetsFolderPath());
     FileUtilities::removeFolderAndAllContents($projectWorkPath);
 }
 public function testNotificationSendRequest_HasSendReceiveAndHasUncommittedEntry_Notified()
 {
     self::$environ->clean();
     $project = self::$environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $project->sendReceiveProjectIdentifier = 'sr_id';
     $project->sendReceiveProject = new SendReceiveProjectModel('sr_name', '', 'manager');
     $project->write();
     $tmpTestPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'notifiedTest';
     $lfmergePaths = SendReceiveCommands::getLFMergePaths(true, $tmpTestPath);
     $projectStatePath = $lfmergePaths->statePath . DIRECTORY_SEPARATOR . strtolower($project->projectCode) . '.state';
     FileUtilities::createAllFolders($tmpTestPath);
     FileUtilities::createAllFolders($lfmergePaths->sendQueuePath);
     FileUtilities::createAllFolders($lfmergePaths->statePath);
     file_put_contents($projectStatePath, '{"state": "SENDING", "uncommittedEditCount": 1}');
     $mockPidFilePath = sys_get_temp_dir() . '/mockLFMerge.pid';
     $mockCommand = 'php ' . __DIR__ . '/mockLFMergeExe.php';
     $isNotified = SendReceiveCommands::notificationSendRequest($project->projectCode, $lfmergePaths->statePath, $lfmergePaths->sendQueuePath, $mockPidFilePath, $mockCommand);
     $queueFileNames = scandir($lfmergePaths->sendQueuePath);
     $this->assertTrue($isNotified);
     $this->assertCount(3, $queueFileNames);
     FileUtilities::removeFolderAndAllContents($tmpTestPath);
 }
<?php

require_once 'e2eTestConfig.php';
use Api\Model\Languageforge\Lexicon\LexiconProjectModel;
use Api\Model\Languageforge\Lexicon\Command\LexUploadCommands;
use Api\Model\ProjectModel;
use Palaso\Utilities\FileUtilities;
$constants = json_decode(file_get_contents(TestPath . '/testConstants.json'), true);
// cleanup test assets folder
$project = new ProjectModel();
$project->readByProperties(array('projectCode' => $constants['testProjectCode']));
$testProject = $project->getById($project->id->asString());
$assetsFolderPath = $testProject->getAssetsFolderPath();
FileUtilities::removeFolderAndAllContents($assetsFolderPath);
// cleanup mocked uploaded zip import (jpg file)
$tmpFilePath = sys_get_temp_dir() . '/' . $constants['testMockJpgImportFile']['name'];
@unlink($tmpFilePath);
// cleanup mocked uploaded zip import (zip file)
$tmpFilePath = sys_get_temp_dir() . '/' . $constants['testMockZipImportFile']['name'];
@unlink($tmpFilePath);
Exemplo n.º 13
0
 /**
  * @return string Full path of the projects assets folder
  */
 public function getAssetsFolderPath()
 {
     $folderPath = APPPATH . $this->getAssetsRelativePath();
     FileUtilities::createAllFolders($folderPath);
     return $folderPath;
 }
 /**
  * Upload a file
  *
  * @param string $projectId
  * @param string $mediaType
  * @param string $tmpFilePath
  * @throws \Exception
  * @return UploadResponse
  */
 public static function uploadFile($projectId, $mediaType, $tmpFilePath)
 {
     if ($mediaType != 'audio') {
         throw new \Exception("Unsupported upload type: {$mediaType}");
     }
     if (!$tmpFilePath) {
         throw new \Exception("Upload controller did not move the uploaded file.");
     }
     $textId = $_POST['textId'];
     $file = $_FILES['file'];
     $fileName = $file['name'];
     $finfo = finfo_open(FILEINFO_MIME_TYPE);
     $fileType = finfo_file($finfo, $tmpFilePath);
     finfo_close($finfo);
     $fileName = FileUtilities::replaceSpecialCharacters($fileName);
     $fileExt = false === ($pos = strrpos($fileName, '.')) ? '' : substr($fileName, $pos);
     // allowed types: documented, observed
     $allowedTypes = array("audio/mpeg", "audio/mp3");
     $allowedExtensions = array(".mp3");
     $response = new UploadResponse();
     if (in_array(strtolower($fileType), $allowedTypes) && in_array(strtolower($fileExt), $allowedExtensions)) {
         // make the folders if they don't exist
         $project = new SfchecksProjectModel($projectId);
         ProjectCommands::checkIfArchivedAndThrow($project);
         $folderPath = $project->getAssetsFolderPath();
         FileUtilities::createAllFolders($folderPath);
         // cleanup previous files of any allowed extension
         self::cleanupFiles($folderPath, $textId, $allowedExtensions);
         // move uploaded file from tmp location to assets
         $filePath = self::mediaFilePath($folderPath, $textId, $fileName);
         $moveOk = copy($tmpFilePath, $filePath);
         @unlink($tmpFilePath);
         // update database with file location
         $text = new TextModel($project, $textId);
         $text->audioFileName = '';
         if ($moveOk) {
             $text->audioFileName = $fileName;
         }
         $text->write();
         // construct server response
         if ($moveOk && $tmpFilePath) {
             $data = new MediaResult();
             $data->path = $project->getAssetsRelativePath();
             $data->fileName = $fileName;
             $response->result = true;
         } else {
             $data = new ErrorResult();
             $data->errorType = 'UserMessage';
             $data->errorMessage = "{$fileName} could not be saved to the right location. Contact your Site Administrator.";
             $response->result = false;
         }
     } else {
         $allowedExtensionsStr = implode(", ", $allowedExtensions);
         $data = new ErrorResult();
         $data->errorType = 'UserMessage';
         if (count($allowedExtensions) < 1) {
             $data->errorMessage = "{$fileName} is not an allowed audio file. No audio file formats are currently enabled, contact your Site Administrator.";
         } elseif (count($allowedExtensions) == 1) {
             $data->errorMessage = "{$fileName} is not an allowed audio file. Ensure the file is a {$allowedExtensionsStr}.";
         } else {
             $data->errorMessage = "{$fileName} is not an allowed audio file. Ensure the file is one of the following types: {$allowedExtensionsStr}.";
         }
         $response->result = false;
     }
     $response->data = $data;
     return $response;
 }
 /**
  * Cleanup assets folder upon project deletion
  */
 protected function cleanup()
 {
     FileUtilities::removeFolderAndAllContents($this->getAssetsFolderPath());
 }
 /**
  * @param string $projectCode
  * @param string $statePath
  * @param string $sendQueuePath
  * @param string $pidFilePath
  * @param string $command
  * @return bool true if notification file is created (or already exists) and LFMerge started, false otherwise
  * @throws \Exception
  */
 public static function notificationSendRequest($projectCode, $statePath = null, $sendQueuePath = null, $pidFilePath = null, $command = null)
 {
     $project = new LexProjectModel();
     if (!$project->readByProperty('projectCode', $projectCode)) {
         return false;
     }
     if (!$project->hasSendReceive()) {
         return false;
     }
     $status = self::getProjectStatus($project->id->asString(), $statePath);
     if (!$status || !array_key_exists('uncommittedEditCount', $status)) {
         return false;
     }
     if ($status['uncommittedEditCount'] <= 0) {
         return false;
     }
     if (is_null($sendQueuePath)) {
         $sendQueuePath = self::getLFMergePaths()->sendQueuePath;
     }
     $notificationFilePath = $sendQueuePath . '/' . $project->projectCode . '.notification';
     if (!file_exists($notificationFilePath) || !is_file($notificationFilePath)) {
         FileUtilities::createAllFolders($sendQueuePath);
         if (file_put_contents($notificationFilePath, '') === false) {
             throw new \Exception('Cannot write to Send/Receive Send Queue. Contact the website administrator.');
         }
     }
     return self::startLFMergeIfRequired($project->id->asString(), $pidFilePath, $command);
 }