public function testEncode_ProjectWithTexts_DtoReturnsTextCount2()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $userId = $e->createUser("User", "Name", "*****@*****.**");
     $user = new UserModel($userId);
     $user->role = SystemRoles::SYSTEM_ADMIN;
     $user->write();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $project->id->asString();
     $project->ownerRef->id = $userId;
     $project->write();
     $text1 = new TextModel($project);
     $text1->title = "Chapter 3";
     $text1->content = "I opened my eyes upon a strange and weird landscape. I knew that I was on Mars; …";
     $text1Id = $text1->write();
     $text2 = new TextModel($project);
     $text2->title = "Chapter 4";
     $text2->content = "We had gone perhaps ten miles when the ground began to rise very rapidly. …";
     $text2Id = $text2->write();
     $dto = ProjectListDto::encode($userId, $e->website);
     $this->assertEqual($dto['count'], 1);
     $this->assertIsA($dto['entries'], 'array');
     $this->assertEqual($dto['entries'][0]['id'], $projectId);
     $this->assertEqual($dto['entries'][0]['projectName'], SF_TESTPROJECT);
     $this->assertEqual($dto['entries'][0]['role'], ProjectRoles::NONE);
 }
 public function testUpdateThenRemove_NewProject_CreatesThenRemovesProjectDatabase()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $databaseName = $project->databaseName();
     $project->remove();
     $db = MongoStore::connect($databaseName);
     $this->assertEqual(count($db->listCollections()), 0);
     $text = new TextModel($project);
     $text->title = 'Some Title';
     $text->write();
     $this->assertTrue(MongoStore::hasDB($databaseName));
     $this->assertEqual(count($db->listCollections()), 1);
     $project->remove();
     $this->assertEqual(count($db->listCollections()), 0);
 }
 /**
  * @param string $projectId
  * @param JSON $object
  * @return ID of text updated/added
  */
 public static function updateText($projectId, $object)
 {
     $projectModel = new \Api\Model\ProjectModel($projectId);
     $textModel = new \Api\Model\TextModel($projectModel);
     $isNewText = $object['id'] == '';
     if (!$isNewText) {
         $textModel->read($object['id']);
     }
     JsonDecoder::decode($textModel, $object);
     TextCommands::makeValidRange($object);
     if (TextCommands::hasRange($object)) {
         $usxTrimHelper = new UsxTrimHelper($textModel->content, $object['startCh'] || 0, $object['startVs'] || 0, $object['endCh'] || 0, $object['endVs'] || 0);
         $textModel->content = $usxTrimHelper->trimUsx();
     }
     $textId = $textModel->write();
     if ($isNewText) {
         ActivityCommands::addText($projectModel, $textId, $textModel);
     }
     return $textId;
 }
 public function encodeIdReference($key, $model)
 {
     if ($model->asString() == '') {
         return '';
     }
     if ($key == 'userRef' || $key == 'userRef2') {
         $user = new UserModel();
         if ($user->exists($model->asString())) {
             $user->read($model->asString());
             return array('id' => $user->id->asString(), 'avatar_ref' => $user->avatar_ref, 'username' => $user->username);
         } else {
             return '';
         }
     } elseif ($key == 'projectRef') {
         $project = new ProjectModel($model->asString());
         return array('id' => $project->id->asString(), 'type' => $project->appName);
     } elseif ($key == 'textRef') {
         $text = new TextModel($this->_project);
         if ($text->exists($model->asString())) {
             return $model->asString();
         } else {
             return '';
         }
     } elseif ($key == 'questionRef') {
         $question = new QuestionModel($this->_project);
         if ($question->exists($model->asString())) {
             return $model->asString();
         } else {
             return '';
         }
     } elseif ($key == 'entryRef') {
         $entry = new LexEntryModel($this->_project);
         if ($entry->exists($model->asString())) {
             return $model->asString();
         } else {
             return '';
         }
     } else {
         return $model->asString();
     }
 }
 public function testUserEngagementReport_simpleProjectWithQuestionsAndAnswers_AsExpected()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $text = new TextModel($project);
     $text->title = "Text 1";
     $usx = MongoTestEnvironment::usxSample();
     $text->content = $usx;
     $textId = $text->write();
     $user1Id = $e->createUser("user1", "user1", "*****@*****.**");
     $user2Id = $e->createUser("user2", "user2", "*****@*****.**");
     $user3Id = $e->createUser("user3", "user3", "*****@*****.**");
     ProjectCommands::updateUserRole($project->id->asString(), $user1Id);
     ProjectCommands::updateUserRole($project->id->asString(), $user2Id);
     ProjectCommands::updateUserRole($project->id->asString(), $user3Id);
     // Workflow is first to create a question
     $question = new QuestionModel($project);
     $question->title = "the question";
     $question->description = "question description";
     $question->textRef->id = $textId;
     $questionId = $question->write();
     // Then to add an answer to a question
     $answer = new AnswerModel();
     $answer->content = "first answer";
     $answer->score = 10;
     $answer->userRef->id = $user3Id;
     $answer->textHightlight = "text highlight";
     $answerId = $question->writeAnswer($answer);
     // Followed by comments
     $comment1 = new CommentModel();
     $comment1->content = "first comment";
     $comment1->userRef->id = $user1Id;
     $comment1Id = QuestionModel::writeComment($project->databaseName(), $questionId, $answerId, $comment1);
     $comment2 = new CommentModel();
     $comment2->content = "second comment";
     $comment2->userRef->id = $user2Id;
     $comment2Id = QuestionModel::writeComment($project->databaseName(), $questionId, $answerId, $comment2);
     $data = SfchecksReports::UserEngagementReport($project->id->asString());
     $this->assertTrue($data['output']);
 }
 public function testEncode_ProjectWith2Users1Unvalidated_DtoCorrect1User()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $user1Id = $e->createUser("", "", "");
     $user1 = new UserModel($user1Id);
     $user1->role = SystemRoles::USER;
     $user2Id = $e->createUser("User", "Name", "*****@*****.**");
     $user2 = new UserModel($user2Id);
     $user2->role = SystemRoles::USER;
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $project->id->asString();
     $project->addUser($user1Id, ProjectRoles::CONTRIBUTOR);
     $user1->addProject($projectId);
     $user1->write();
     $project->addUser($user2Id, ProjectRoles::CONTRIBUTOR);
     $user2->addProject($projectId);
     $user2->write();
     $project->write();
     $text1 = new TextModel($project);
     $text1->title = "Some Title";
     $text1->write();
     $text2 = new TextModel($project);
     $text2->title = "Archived Title";
     $text2->isArchived = true;
     $text2->write();
     $dto = ProjectSettingsDto::encode($projectId, $user2Id);
     $this->assertEqual($dto['count'], 1);
     $this->assertIsA($dto['entries'], 'array');
     $this->assertEqual($dto['entries'][0]['id'], $user2Id);
     $this->assertEqual($dto['entries'][0]['name'], 'Name');
     $this->assertEqual($dto['entries'][0]['role'], ProjectRoles::CONTRIBUTOR);
     $this->assertEqual(count($dto['archivedTexts']), 1);
     $this->assertEqual($dto['archivedTexts'][0]['title'], 'Archived Title');
     $this->assertTrue(count($dto['rights']) > 0, "No rights in dto");
     $this->assertEqual($dto['bcs']['op'], 'settings');
     $this->assertEqual($dto['bcs']['project'], array('id' => $projectId, 'crumb' => SF_TESTPROJECT));
     $this->assertFalse(isset($dto['project']['users']));
     $this->assertEqual($dto['project']['id'], $projectId);
 }
 public function testPublishTexts_2ArchivedTexts_1Published()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $text1 = new TextModel($project);
     $text1->title = "Some Title";
     $text1->isArchived = true;
     $text1->write();
     $text2 = new TextModel($project);
     $text2->title = "Another Title";
     $text2->isArchived = true;
     $text2->write();
     $this->assertEqual($text1->isArchived, true);
     $this->assertEqual($text2->isArchived, true);
     $count = TextCommands::publishTexts($project->id->asString(), array($text1->id->asString()));
     $text1->read($text1->id->asString());
     $text2->read($text2->id->asString());
     $this->assertEqual($count, 1);
     $this->assertEqual($text1->isArchived, false);
     $this->assertEqual($text2->isArchived, true);
 }
 /**
  * @param string $projectId
  * @param string $userId
  * @returns array - the DTO array
  */
 public static function encode($projectId, $userId)
 {
     $userModel = new UserModel($userId);
     $projectModel = new SfchecksProjectModel($projectId);
     $textList = new TextListModel($projectModel);
     $textList->read();
     $list = $projectModel->listUsers();
     $data = array();
     $data['count'] = count($list->entries);
     $data['entries'] = array_values($list->entries);
     // re-index array
     $data['project'] = ProjectSettingsDtoEncoder::encode($projectModel);
     unset($data['project']['users']);
     $data['archivedTexts'] = array();
     foreach ($textList->entries as $entry) {
         $textModel = new TextModel($projectModel, $entry['id']);
         if ($textModel->isArchived) {
             $questionList = $textModel->listQuestionsWithAnswers();
             // Just want count of questions and responses, not whole list
             $entry['questionCount'] = $questionList->count;
             $responseCount = 0;
             // "Responses" = answers + comments
             foreach ($questionList->entries as $q) {
                 foreach ($q['answers'] as $a) {
                     $commentCount = count($a['comments']);
                     $responseCount += $commentCount + 1;
                     // +1 for this answer
                 }
             }
             $entry['responseCount'] = $responseCount;
             $entry['dateModified'] = $textModel->dateModified->format(\DateTime::RFC2822);
             $data['archivedTexts'][] = $entry;
         }
     }
     $data['rights'] = RightsHelper::encode($userModel, $projectModel);
     $data['bcs'] = BreadCrumbHelper::encode('settings', $projectModel, null, null);
     return $data;
 }
 function testCleanupFiles_4Files2Allowed_2Removed()
 {
     $environ = new MongoTestEnvironment();
     $environ->clean();
     $project = $environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $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(TestPath . 'common/TestAudio.mp3', $filePath1);
     $fileName2 = 'TestAudio2.mp2';
     $filePath2 = SfchecksUploadCommands::mediaFilePath($folderPath, $textId, $fileName2);
     copy(TestPath . 'common/TestAudio.mp3', $filePath2);
     $fileName3 = 'TestAudio3.mp3';
     $filePath3 = SfchecksUploadCommands::mediaFilePath($folderPath, $textId, $fileName3);
     copy(TestPath . 'common/TestAudio.mp3', $filePath3);
     $fileName4 = 'TestAudio4.mp3';
     $filePath4 = SfchecksUploadCommands::mediaFilePath($folderPath, $fakeTextId, $fileName4);
     copy(TestPath . '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');
     $environ->cleanupTestFiles($folderPath);
 }
 public function testEncode_2Questions1Archived_DtoCorrect1ArchivedQuestion()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $userId = $e->createUser("User", "Name", "*****@*****.**");
     $user = new UserModel($userId);
     $user->role = SystemRoles::USER;
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $project->id->asString();
     $project->addUser($userId, ProjectRoles::MANAGER);
     $user->addProject($projectId);
     $user->write();
     $project->write();
     $text = new TextModel($project);
     $text->title = "Text Title";
     $textId = $text->write();
     $question1 = new QuestionModel($project);
     $question1->title = "Some Title";
     $question1->textRef->id = $textId;
     $question1->write();
     $question2 = new QuestionModel($project);
     $question2->title = "Archived Title";
     $question2->textRef->id = $textId;
     $question2->isArchived = true;
     $question2->write();
     $dto = TextSettingsDto::encode($projectId, $textId, $userId);
     $this->assertIsA($dto['text'], 'array');
     $this->assertEqual($dto['text']['id'], $textId);
     $this->assertEqual($dto['text']['title'], 'Text Title');
     $this->assertIsA($dto['archivedQuestions'], 'array');
     $this->assertEqual(count($dto['archivedQuestions']), 1);
     $this->assertEqual($dto['archivedQuestions'][0]['title'], 'Archived Title');
     $this->assertTrue(count($dto['rights']) > 0, "No rights in dto");
     $this->assertEqual($dto['bcs']['op'], 'settings');
     $this->assertEqual($dto['bcs']['project'], array('id' => $projectId, 'crumb' => SF_TESTPROJECT));
 }
 public function testGetActivityForProject_ProjectWithTextQuestionAnswerAndComments_DtoAsExpected()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $text = new TextModel($project);
     $text->title = "Text 1";
     $text->content = "text content";
     $textId = $text->write();
     $a1 = ActivityCommands::addText($project, $textId, $text);
     $user1Id = $e->createUser("user1", "user1", "*****@*****.**");
     $user2Id = $e->createUser("user2", "user2", "*****@*****.**");
     $user3Id = $e->createUser("user3", "user3", "*****@*****.**");
     $a2 = ActivityCommands::addUserToProject($project, $user1Id);
     $a3 = ActivityCommands::addUserToProject($project, $user2Id);
     $a4 = ActivityCommands::addUserToProject($project, $user3Id);
     // Workflow is first to create a question
     $question = new QuestionModel($project);
     $question->title = "the question";
     $question->description = "question description";
     $question->textRef->id = $textId;
     $questionId = $question->write();
     $a5 = ActivityCommands::addQuestion($project, $questionId, $question);
     // Then to add an answer to a question
     $answer = new AnswerModel();
     $answer->content = "first answer";
     $answer->score = 10;
     $answer->userRef->id = $user3Id;
     $answer->textHightlight = "text highlight";
     $answerId = $question->writeAnswer($answer);
     $a6 = ActivityCommands::addAnswer($project, $questionId, $answer);
     // Followed by comments
     $comment1 = new CommentModel();
     $comment1->content = "first comment";
     $comment1->userRef->id = $user1Id;
     $comment1Id = QuestionModel::writeComment($project->databaseName(), $questionId, $answerId, $comment1);
     $a7 = ActivityCommands::addComment($project, $questionId, $answerId, $comment1);
     $comment2 = new CommentModel();
     $comment2->content = "second comment";
     $comment2->userRef->id = $user2Id;
     $comment2Id = QuestionModel::writeComment($project->databaseName(), $questionId, $answerId, $comment2);
     $a8 = ActivityCommands::addComment($project, $questionId, $answerId, $comment2);
     // updated answer
     $question->read($questionId);
     $answer_updated = $question->readAnswer($answerId);
     $answer_updated->content = "first answer revised";
     $question->writeAnswer($answer_updated);
     $a9 = ActivityCommands::updateAnswer($project, $questionId, $answer_updated);
     // updated comment1
     $question->read($questionId);
     $comment1_updated = $question->readComment($answerId, $comment1Id);
     $comment1_updated->content = "first comment revised";
     QuestionModel::writeComment($project->databaseName(), $questionId, $answerId, $comment1_updated);
     $a10 = ActivityCommands::updateComment($project, $questionId, $answerId, $comment1_updated);
     $dto = ActivityListDto::getActivityForProject($project);
     $this->assertEqual($dto[$a1]['action'], 'add_text');
     $this->assertEqual($dto[$a1]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a1]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a1]['textRef'], $textId);
     $this->assertEqual($dto[$a1]['content']['text'], $text->title);
     $this->assertEqual($dto[$a2]['action'], 'add_user_to_project');
     $this->assertEqual($dto[$a2]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a2]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a2]['userRef']['id'], $user1Id);
     $this->assertEqual($dto[$a2]['userRef']['username'], 'user1');
     $this->assertEqual($dto[$a2]['userRef']['avatar_ref'], 'user1.png');
     $this->assertEqual($dto[$a2]['content']['user'], 'user1');
     $this->assertEqual($dto[$a3]['action'], 'add_user_to_project');
     $this->assertEqual($dto[$a3]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a3]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a3]['userRef']['id'], $user2Id);
     $this->assertEqual($dto[$a3]['userRef']['username'], 'user2');
     $this->assertEqual($dto[$a3]['userRef']['avatar_ref'], 'user2.png');
     $this->assertEqual($dto[$a3]['content']['user'], 'user2');
     $this->assertEqual($dto[$a4]['action'], 'add_user_to_project');
     $this->assertEqual($dto[$a4]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a4]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a4]['userRef']['id'], $user3Id);
     $this->assertEqual($dto[$a4]['userRef']['username'], 'user3');
     $this->assertEqual($dto[$a4]['userRef']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a4]['content']['user'], 'user3');
     $this->assertEqual($dto[$a5]['action'], 'add_question');
     $this->assertEqual($dto[$a5]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a5]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a5]['textRef'], $textId);
     $this->assertEqual($dto[$a5]['content']['text'], $text->title);
     $this->assertEqual($dto[$a5]['questionRef'], $questionId);
     $this->assertEqual($dto[$a5]['content']['question'], $question->title);
     $this->assertEqual($dto[$a6]['action'], 'add_answer');
     $this->assertEqual($dto[$a6]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a6]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a6]['textRef'], $textId);
     $this->assertEqual($dto[$a6]['content']['text'], $text->title);
     $this->assertEqual($dto[$a6]['questionRef'], $questionId);
     $this->assertEqual($dto[$a6]['content']['question'], $question->title);
     $this->assertEqual($dto[$a6]['userRef']['id'], $user3Id);
     $this->assertEqual($dto[$a6]['userRef']['username'], 'user3');
     $this->assertEqual($dto[$a6]['userRef']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a6]['content']['answer'], $answer->content);
     $this->assertEqual($dto[$a6]['content']['user'], 'user3');
     $this->assertEqual($dto[$a7]['action'], 'add_comment');
     $this->assertEqual($dto[$a7]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a7]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a7]['textRef'], $textId);
     $this->assertEqual($dto[$a7]['content']['text'], $text->title);
     $this->assertEqual($dto[$a7]['questionRef'], $questionId);
     $this->assertEqual($dto[$a7]['content']['question'], $question->title);
     $this->assertEqual($dto[$a7]['userRef']['id'], $user1Id);
     $this->assertEqual($dto[$a7]['userRef']['username'], 'user1');
     $this->assertEqual($dto[$a7]['userRef']['avatar_ref'], 'user1.png');
     $this->assertEqual($dto[$a7]['content']['user'], 'user1');
     $this->assertEqual($dto[$a7]['userRef2']['id'], $user3Id);
     $this->assertEqual($dto[$a7]['userRef2']['username'], 'user3');
     $this->assertEqual($dto[$a7]['userRef2']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a7]['content']['user2'], 'user3');
     $this->assertEqual($dto[$a7]['content']['answer'], $answer->content);
     $this->assertEqual($dto[$a7]['content']['comment'], $comment1->content);
     $this->assertEqual($dto[$a8]['action'], 'add_comment');
     $this->assertEqual($dto[$a8]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a8]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a8]['textRef'], $textId);
     $this->assertEqual($dto[$a8]['content']['text'], $text->title);
     $this->assertEqual($dto[$a8]['questionRef'], $questionId);
     $this->assertEqual($dto[$a8]['content']['question'], $question->title);
     $this->assertEqual($dto[$a8]['userRef']['id'], $user2Id);
     $this->assertEqual($dto[$a8]['userRef']['username'], 'user2');
     $this->assertEqual($dto[$a8]['userRef']['avatar_ref'], 'user2.png');
     $this->assertEqual($dto[$a8]['content']['user'], 'user2');
     $this->assertEqual($dto[$a8]['userRef2']['id'], $user3Id);
     $this->assertEqual($dto[$a8]['userRef2']['username'], 'user3');
     $this->assertEqual($dto[$a8]['userRef2']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a8]['content']['user2'], 'user3');
     $this->assertEqual($dto[$a8]['content']['answer'], $answer->content);
     $this->assertEqual($dto[$a8]['content']['comment'], $comment2->content);
     $this->assertEqual($dto[$a9]['action'], 'update_answer');
     $this->assertEqual($dto[$a9]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a9]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a9]['textRef'], $textId);
     $this->assertEqual($dto[$a9]['content']['text'], $text->title);
     $this->assertEqual($dto[$a9]['questionRef'], $questionId);
     $this->assertEqual($dto[$a9]['content']['question'], $question->title);
     $this->assertEqual($dto[$a9]['userRef']['id'], $user3Id);
     $this->assertEqual($dto[$a9]['userRef']['username'], 'user3');
     $this->assertEqual($dto[$a9]['userRef']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a9]['content']['user'], 'user3');
     $this->assertEqual($dto[$a9]['content']['answer'], $answer_updated->content);
     $this->assertEqual($dto[$a10]['action'], 'update_comment');
     $this->assertEqual($dto[$a10]['projectRef'], array('id' => $project->id->asString(), 'type' => 'sfchecks'));
     $this->assertEqual($dto[$a10]['content']['project'], $project->projectName);
     $this->assertEqual($dto[$a10]['textRef'], $textId);
     $this->assertEqual($dto[$a10]['content']['text'], $text->title);
     $this->assertEqual($dto[$a10]['questionRef'], $questionId);
     $this->assertEqual($dto[$a10]['content']['question'], $question->title);
     $this->assertEqual($dto[$a10]['userRef']['id'], $user1Id);
     $this->assertEqual($dto[$a10]['userRef']['username'], 'user1');
     $this->assertEqual($dto[$a10]['userRef']['avatar_ref'], 'user1.png');
     $this->assertEqual($dto[$a10]['content']['user'], 'user1');
     $this->assertEqual($dto[$a10]['userRef2']['id'], $user3Id);
     $this->assertEqual($dto[$a10]['userRef2']['username'], 'user3');
     $this->assertEqual($dto[$a10]['userRef2']['avatar_ref'], 'user3.png');
     $this->assertEqual($dto[$a10]['content']['user2'], 'user3');
     $this->assertEqual($dto[$a10]['content']['answer'], $answer_updated->content);
     $this->assertEqual($dto[$a10]['content']['comment'], $comment1_updated->content);
 }
 public function testUpdateComment_ExistingComment_OriginalAuthorIsPreserved()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $text = new TextModel($project);
     $text->title = "Text 1";
     $usx = MongoTestEnvironment::usxSample();
     $text->content = $usx;
     $textId = $text->write();
     $question = new QuestionModel($project);
     $question->textRef->id = $textId;
     $questionId = $question->write();
     $user1Id = $e->createUser("user1", "user1", "user1");
     $user2Id = $e->createUser("user2", "user2", "user2");
     $answer = new AnswerModel();
     $answer->content = "the answer";
     $answer->userRef->id = $user2Id;
     $answerId = $question->writeAnswer($answer);
     $comment = new CommentModel();
     $comment->userRef->id = $user1Id;
     $comment->content = "the comment";
     $commentId = $question->writeComment($project->databaseName(), $questionId, $answerId, $comment);
     $commentArray = array("id" => $commentId, "content" => "updated comment");
     QuestionCommands::updateComment($project->id->asString(), $questionId, $answerId, $commentArray, $user2Id);
     $question->read($questionId);
     $newComment = $question->readComment($answerId, $commentId);
     $this->assertEqual($user1Id, $newComment->userRef->asString());
 }
 public function testEncode_ArchivedText_ManagerCanViewContributorCannot()
 {
     $project = $this->environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $project->id->asString();
     // archived Text
     $text = new TextModel($project);
     $text->title = "Chapter 3";
     $text->isArchived = true;
     $textId = $text->write();
     // Answers are tied to specific users, so let's create some sample users
     $managerId = $this->environ->createUser("jcarter", "John Carter", "*****@*****.**");
     $contributorId = $this->environ->createUser("dthoris", "Dejah Thoris", "*****@*****.**");
     $project->addUser($managerId, ProjectRoles::MANAGER);
     $project->addUser($contributorId, ProjectRoles::CONTRIBUTOR);
     $project->write();
     $dto = QuestionListDto::encode($projectId, $textId, $managerId);
     // Manager can view archived Text
     $this->assertEqual($dto['text']['title'], "Chapter 3");
     // Contributor cannot view archived Text, throw Exception
     $this->environ->inhibitErrorDisplay();
     $this->expectException();
     $dto = QuestionListDto::encode($projectId, $textId, $contributorId);
     // nothing runs in the current test function after an exception. IJH 2014-11
 }
 /**
  *
  * @param string $projectId
  * @param string $userId
  * @returns array - the DTO array
  */
 public static function encode($projectId, $userId)
 {
     $user = new UserModel($userId);
     $project = new SfchecksProjectModel($projectId);
     if ($project->isArchived && $project->users[$userId]->role != ProjectRoles::MANAGER) {
         throw new ResourceNotAvailableException("This Project is no longer available. If this is incorrect contact your project manager.");
     }
     $textList = new TextListModel($project);
     $textList->read();
     $data = array();
     $data['rights'] = RightsHelper::encode($user, $project);
     $data['project'] = array('name' => $project->projectName, 'id' => $projectId);
     $data['texts'] = array();
     foreach ($textList->entries as $entry) {
         $text = new TextModel($project, $entry['id']);
         if (!$text->isArchived) {
             $questionList = $text->listQuestionsWithAnswers();
             // Just want count of questions and responses, not whole list
             $entry['questionCount'] = 0;
             $responseCount = 0;
             // "Responses" = answers + comments
             foreach ($questionList->entries as $q) {
                 $question = new QuestionModel($project, $q['id']);
                 if (!$question->isArchived) {
                     $entry['questionCount']++;
                     foreach ($q['answers'] as $a) {
                         $commentCount = count($a['comments']);
                         $responseCount += $commentCount + 1;
                         // +1 for this answer
                     }
                 }
             }
             $entry['responseCount'] = $responseCount;
             $entry['dateCreated'] = $text->dateCreated->format(\DateTime::RFC2822);
             $data['texts'][] = $entry;
         }
     }
     // sort Texts with newest at the top
     usort($data['texts'], function ($a, $b) {
         $sortOn = 'dateCreated';
         if (array_key_exists($sortOn, $a) && array_key_exists($sortOn, $b)) {
             return strtotime($a[$sortOn]) < strtotime($b[$sortOn]) ? 1 : -1;
         } else {
             return 0;
         }
     });
     // future support for members
     $data['members'] = array();
     // unread activity count
     $unreadActivity = new UnreadActivityModel($userId, $projectId);
     $unreadItems = $unreadActivity->unreadItems();
     $data['activityUnreadCount'] = count($unreadItems);
     // unread broadcast messages
     $unreadMessages = new UnreadMessageModel($userId, $projectId);
     $messageIds = $unreadMessages->unreadItems();
     $messages = array();
     foreach ($messageIds as $messageId) {
         $message = new MessageModel($project, $messageId);
         $messages[] = array('id' => $message->id->asString(), 'subject' => $message->subject, 'content' => $message->content);
     }
     $data['broadcastMessages'] = $messages;
     return $data;
 }
 public function run($mode = 'test')
 {
     $testMode = $mode != 'run';
     $message = "";
     $projectlist = new ProjectListModel();
     $projectlist->read();
     $textsExamined = 0;
     $textsUpdated = 0;
     // foreach existing project
     foreach ($projectlist->entries as $projectParams) {
         $projectId = $projectParams['id'];
         if ($projectParams['projectName'] == 'Jamaican Psalms') {
             $project = new SfchecksProjectModel($projectId);
             $textlist = new TextListModel($project);
             $textlist->read();
             // foreach text in project
             foreach ($textlist->entries as $textParams) {
                 $textsExamined++;
                 $textId = $textParams['id'];
                 $legacyText = new TextModel_sf_v0_9_18($project, $textId);
                 $fileName = '';
                 if ($legacyText->audioUrl) {
                     $text = new TextModel($project, $textId);
                     if (!$testMode) {
                         if (!$text->audioFileName) {
                             // legacy audioUrl format "assets/<projectId>/<textId>_<fileName>"
                             $fileNamePrefix = $textId . '_';
                             $pos = strpos($legacyText->audioUrl, $fileNamePrefix);
                             $text->audioFileName = substr($legacyText->audioUrl, $pos + strlen($fileNamePrefix));
                         }
                         $text->write();
                     }
                     $message .= "Changed text: {$text->title}\n";
                     $textsUpdated++;
                 }
             }
             if (!$testMode) {
                 TextModel_sf_v0_9_18::removeAudioProperty($project->databaseName());
                 $message .= "Removed 'audioUrl' property from project: {$project->projectName}\n";
             }
         }
     }
     if ($textsUpdated > 0) {
         $message .= "\n\nChanged {$textsUpdated} legacy texts to only store audio filename\n\n";
     } else {
         $message .= "\n\nNo legacy text audio were found/changed. {$textsExamined} texts examined.\n\n";
     }
     // re-arrange assets folder
     // - remove <siteName> from path for LF
     // - add <appName> to path for SF and change <projectId> in path to <projectSlug (databaseName)>
     $message .= "\n\nRe-arrange assets folder\n~~~~~~~~~~~~~~~~~~~~~~~~\n\n";
     $project = new SfchecksProjectModel();
     $assetsFolderPath = APPPATH . "assets";
     $assetsSubfolders = glob($assetsFolderPath . '/*');
     @mkdir($assetsFolderPath . '/lexicon');
     @mkdir($assetsFolderPath . '/sfchecks');
     foreach ($assetsSubfolders as $assetsSubfolder) {
         if (file_exists($assetsSubfolder) && is_dir($assetsSubfolder)) {
             $assetsSubfolderName = basename($assetsSubfolder);
             if (strpos($assetsSubfolderName, 'languageforge') !== false) {
                 $message .= "Move into lexicon: {$assetsSubfolderName}\n";
                 $oldFolderPath = $assetsSubfolder . '/lexicon';
                 $newFolderPath = $assetsFolderPath . '/lexicon';
             } elseif ($assetsSubfolderName == 'lexicon' || $assetsSubfolderName == 'sfchecks') {
                 $message .= "No change: {$assetsSubfolderName}\n";
                 $oldFolderPath = '';
                 $newFolderPath = '';
                 $assetsSubfolder = '';
             } elseif ($project->exists($assetsSubfolderName)) {
                 $message .= "Move into sfchecks: {$assetsSubfolderName}\n";
                 $oldFolderPath = $assetsSubfolder;
                 $project->read($assetsSubfolderName);
                 $projectSlug = $project->databaseName();
                 $newFolderPath = $assetsFolderPath . "/sfchecks/{$projectSlug}";
                 if (!$testMode) {
                 }
             } else {
                 $message .= "Delete: {$assetsSubfolderName}\n";
                 $oldFolderPath = '';
                 $newFolderPath = '';
             }
             if (!$testMode) {
                 if (file_exists($oldFolderPath) && is_dir($oldFolderPath)) {
                     if (!@rename($oldFolderPath, $newFolderPath)) {
                         $oldFiles = glob($oldFolderPath . '/*');
                         foreach ($oldFiles as $oldFile) {
                             $newFile = $newFolderPath . '/' . basename($oldFile);
                             rename($oldFile, $newFile);
                         }
                     }
                 }
                 if (file_exists($assetsSubfolder) && is_dir($assetsSubfolder)) {
                     $this->recursiveRemoveFolder($assetsSubfolder);
                 }
             }
         }
     }
     return $message;
 }
 public function testMultipleUnreadModels_multipleUsers_multipleUpdates_multipleVisitsToQuestionPage_usersHaveDifferentUnreadStates()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject("unread_test", "unreadCode");
     $projectId = $project->id->asString();
     $userId1 = $e->createUser('user1', 'user1', 'user1');
     $user1 = new UserModel($userId1);
     $user1->addProject($project->id->asString());
     $user1->write();
     $userId2 = $e->createUser('user2', 'user2', 'user2');
     $user2 = new UserModel($userId2);
     $user2->addProject($project->id->asString());
     $user2->write();
     $userId3 = $e->createUser('user3', 'user3', 'user3');
     $user3 = new UserModel($userId3);
     $user3->addProject($project->id->asString());
     $user3->write();
     $answer1 = array('content' => "test answer 1", 'id' => '');
     $answer2 = array('content' => "test answer 2", 'id' => '');
     $text = new TextModel($project);
     $text->title = "Text 1";
     $usx = MongoTestEnvironment::usxSample();
     $text->content = $usx;
     $textId = $text->write();
     $question = new QuestionModel($project);
     $question->title = "test question";
     $question->textRef->id = $textId;
     $questionId = $question->write();
     $answer1Dto = QuestionCommands::updateAnswer($projectId, $questionId, $answer1, $userId1);
     $answer2Dto = QuestionCommands::updateAnswer($projectId, $questionId, $answer2, $userId2);
     $answer1 = array_pop($answer1Dto);
     $answer1Id = $answer1['id'];
     $answer2 = array_pop($answer2Dto);
     $answer2Id = $answer2['id'];
     // the answer author does NOT get their answer marked as unread
     $unreadModel = new UnreadAnswerModel($userId1, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 1);
     // the answer author does NOT get their answer marked as unread
     $unreadModel = new UnreadAnswerModel($userId2, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 1);
     $unreadModel = new UnreadAnswerModel($userId3, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 2);
     // user1 visits question page
     $pageDto = QuestionCommentDto::encode($projectId, $questionId, $userId1);
     $unreadModel = new UnreadAnswerModel($userId1, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
     $unreadModel = new UnreadAnswerModel($userId2, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 1);
     $unreadModel = new UnreadAnswerModel($userId3, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 2);
     // user2 visits question page
     $pageDto = QuestionCommentDto::encode($projectId, $questionId, $userId2);
     $unreadModel = new UnreadAnswerModel($userId1, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
     $unreadModel = new UnreadAnswerModel($userId2, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
     $unreadModel = new UnreadAnswerModel($userId3, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 2);
     // user2 visits question page
     $pageDto = QuestionCommentDto::encode($projectId, $questionId, $userId3);
     $unreadModel = new UnreadAnswerModel($userId1, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
     $unreadModel = new UnreadAnswerModel($userId2, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
     $unreadModel = new UnreadAnswerModel($userId3, $projectId, $questionId);
     $this->assertEqual(count($unreadModel->unreadItems()), 0);
 }
 public function testExportCommentsForText_QuestionArchived_NoneExported()
 {
     $e = new MongoTestEnvironment();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $text = new TextModel($project);
     $text->title = "Text 1";
     $usx = MongoTestEnvironment::usxSample();
     $text->content = $usx;
     $textId = $text->write();
     $user1Id = $e->createUser("user1", "user1", "*****@*****.**");
     $user2Id = $e->createUser("user2", "user2", "*****@*****.**");
     $user3Id = $e->createUser("user3", "user3", "*****@*****.**");
     // Workflow is first to create a question
     $question = new QuestionModel($project);
     $question->title = "the question";
     $question->description = "question description";
     $question->textRef->id = $textId;
     $question->isArchived = true;
     $questionId = $question->write();
     // Then to add an answer to a question
     $answer = new AnswerModel();
     $answer->content = "first answer";
     $answer->score = 10;
     $answer->userRef->id = $user1Id;
     $answer->tags->exchangeArray(array('export', 'to review'));
     $answer->isToBeExported = true;
     $answerId = $question->writeAnswer($answer);
     // Then to add an answer to a question
     $answer = new AnswerModel();
     $answer->content = "second answer - very long";
     $answer->score = 2;
     $answer->userRef->id = $user2Id;
     $answer->tags->exchangeArray(array('to review'));
     $answer->isToBeExported = false;
     $answerId = $question->writeAnswer($answer);
     // Then to add an answer to a question
     $answer = new AnswerModel();
     $answer->content = "third answer - very very very very long";
     $answer->userRef->id = $user3Id;
     $answer->tags->exchangeArray(array('export'));
     $answer->isToBeExported = true;
     $answerId = $question->writeAnswer($answer);
     $params = array('textId' => $textId, 'exportComments' => true, 'exportFlagged' => true, 'tags' => array());
     $download = ParatextExport::exportCommentsForText($project->id->asString(), $textId, $params);
     //echo "<pre>" . print_r($download) . "</pre>";
     $this->assertNoPattern('/<Contents>third answer - very very very very long \\(by user3/', $download['xml']);
     $this->assertNoPattern('/<Contents>second answer/', $download['xml']);
     $this->assertNoPattern('/<Contents>first answer/', $download['xml']);
 }
 public function testEncode_ArchivedText_ManagerCanViewContributorCannot()
 {
     $project = $this->environ->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $managerId = $this->environ->createUser("manager", "manager", "*****@*****.**");
     $contributorId = $this->environ->createUser("contributor1", "contributor1", "*****@*****.**");
     $project->addUser($managerId, ProjectRoles::MANAGER);
     $project->addUser($contributorId, ProjectRoles::CONTRIBUTOR);
     $project->write();
     // Question not archived but Text is archived
     $text = new TextModel($project);
     $text->title = "Text 1";
     $text->isArchived = true;
     $textId = $text->write();
     $question = new QuestionModel($project);
     $question->title = "the question";
     $question->description = "question description";
     $question->textRef->id = $textId;
     $questionId = $question->write();
     $dto = QuestionCommentDto::encode($project->id->asString(), $questionId, $managerId);
     // Manager can view Question of archived Text
     $this->assertEqual($dto['question']['title'], 'the question');
     // Contributor cannot view Question of archived Text, throw Exception
     $this->environ->inhibitErrorDisplay();
     $this->expectException();
     $dto = QuestionCommentDto::encode($project->id->asString(), $questionId, $contributorId);
     // nothing runs in the current test function after an exception. IJH 2014-11
 }
 /**
  * Upload a file
  *
  * @param string $projectId
  * @param string $mediaType
  * @param string $tmpFilePath
  * @throws \Exception
  * @return \Api\Model\Shared\Command\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);
         $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;
 }
 public function testEncode_TextWithQuestions_DtoReturnsExpectedData()
 {
     $e = new MongoTestEnvironment();
     $e->clean();
     $project = $e->createProject(SF_TESTPROJECT, SF_TESTPROJECTCODE);
     $projectId = $project->id->asString();
     // Two texts, with different numbers of questions for each text and different create dates
     $text1 = new TextModel($project);
     $text1->title = "Chapter 3";
     $text1->content = "I opened my eyes upon a strange and weird landscape. I knew that I was on Mars; …";
     $text1->write();
     $text1->dateCreated->sub(date_interval_create_from_date_string('1 day'));
     $text1Id = $text1->write();
     $text2 = new TextModel($project);
     $text2->title = "Chapter 4";
     $text2->content = "We had gone perhaps ten miles when the ground began to rise very rapidly. …";
     $text2Id = $text2->write();
     // Answers are tied to specific users, so let's create some sample users
     $user1Id = $e->createUser("jcarter", "John Carter", "*****@*****.**");
     $user2Id = $e->createUser("dthoris", "Dejah Thoris", "*****@*****.**");
     // Two questions for text 1...
     $question1 = new QuestionModel($project);
     $question1->title = "Who is speaking?";
     $question1->description = "Who is telling the story in this text?";
     $question1->textRef->id = $text1Id;
     $question1Id = $question1->write();
     $question2 = new QuestionModel($project);
     $question2->title = "Where is the storyteller?";
     $question2->description = "The person telling this story has just arrived somewhere. Where is he?";
     $question2->textRef->id = $text1Id;
     $question2Id = $question2->write();
     // ... and one question for text 2.
     $question3 = new QuestionModel($project);
     $question3->title = "How far had they travelled?";
     $question3->description = "How far had the group just travelled when this text begins?";
     $question3->textRef->id = $text2Id;
     $question3Id = $question3->write();
     // One answer for question 1...
     $answer1 = new AnswerModel();
     $answer1->content = "Me, John Carter.";
     $answer1->score = 10;
     $answer1->userRef->id = $user1Id;
     $answer1->textHightlight = "I knew that I was on Mars";
     $answer1Id = $question1->writeAnswer($answer1);
     // ... and two answers for question 2...
     $answer2 = new AnswerModel();
     $answer2->content = "On Mars.";
     $answer2->score = 1;
     $answer2->userRef->id = $user1Id;
     $answer2->textHightlight = "I knew that I was on Mars";
     $answer2Id = $question2->writeAnswer($answer2);
     $answer3 = new AnswerModel();
     $answer3->content = "On the planet we call Barsoom, which you inhabitants of Earth normally call Mars.";
     $answer3->score = 7;
     $answer3->userRef->id = $user2Id;
     $answer3->textHightlight = "I knew that I was on Mars";
     $answer3Id = $question2->writeAnswer($answer3);
     // ... and 1 comment.
     $comment1 = new CommentModel();
     $comment1->content = "By the way, our name for Earth is Jasoom.";
     $comment1->userRef->id = $user2Id;
     $comment1Id = QuestionModel::writeComment($project->databaseName(), $question2Id, $answer3Id, $comment1);
     $dto = ProjectPageDto::encode($projectId, $user1Id);
     // Now check that it all looks right
     $this->assertIsa($dto['texts'], 'array');
     $this->assertEqual($dto['texts'][0]['id'], $text2Id);
     $this->assertEqual($dto['texts'][1]['id'], $text1Id);
     $this->assertEqual($dto['texts'][0]['title'], "Chapter 4");
     $this->assertEqual($dto['texts'][1]['title'], "Chapter 3");
     $this->assertEqual($dto['texts'][0]['questionCount'], 1);
     $this->assertEqual($dto['texts'][1]['questionCount'], 2);
     $this->assertEqual($dto['texts'][0]['responseCount'], 0);
     $this->assertEqual($dto['texts'][1]['responseCount'], 4);
     // archive 1 Question
     $question2->isArchived = true;
     $question2->write();
     $dto = ProjectPageDto::encode($projectId, $user1Id);
     $this->assertEqual($dto['texts'][0]['questionCount'], 1);
     $this->assertEqual($dto['texts'][1]['questionCount'], 1);
     $this->assertEqual($dto['texts'][0]['responseCount'], 0);
     $this->assertEqual($dto['texts'][1]['responseCount'], 1);
 }
 /**
  * @param string $projectId
  * @param array $textIds
  * @return int Total number of texts removed.
  */
 public static function deleteTexts($projectId, $textIds)
 {
     $projectModel = new ProjectModel($projectId);
     $count = 0;
     foreach ($textIds as $textId) {
         TextModel::remove($projectModel->databaseName(), $textId);
         $count++;
     }
     return $count;
 }