Skip to content
Snippets Groups Projects
Commit deb002e6 authored by Sebastien's avatar Sebastien
Browse files

Fix project creation with password for edit access

parent 0f72dbaa
No related branches found
No related tags found
3 merge requests!43tuleap-83-access-my-capsules,!42Draft: access-my-capsules-conflicts-fixed,!40Draft: Tuleap 83 access my capsules
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20220114111659 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE capsule ADD password VARCHAR(50) DEFAULT \'\' NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE capsule DROP password');
}
}
......@@ -15,6 +15,7 @@ class CapsuleBuilder
private bool $hasRequiredPreviewLink = false;
private bool $hasRequiredEditionLink = false;
private bool $hasRequiredUpdateDate = false;
private bool $hasPasswordSet = false;
public function __construct()
{
......@@ -50,11 +51,21 @@ class CapsuleBuilder
return $this;
}
public function withEditionLink(string $edition_link): CapsuleBuilder
private function createEditionLink(): void
{
$this->capsule->setEditionLink($edition_link);
ContractHelper::requires(
$this->hasRequiredPreviewLink,
"The call of CapsuleBuilder::withPreviewLink should be " .
"called before CapsuleBuilder::createEditionLink"
);
ContractHelper::requires(
$this->hasPasswordSet,
"The call of CapsuleBuilder::withPassword should be " .
"called before CapsuleBuilder::createEditionLink"
);
$this->capsule->setEditionLink($this->capsule->getPreviewLink() .
"/?p=" . $this->capsule->getPassword());
$this->hasRequiredEditionLink = true;
return $this;
}
public function withUpdateAuthor(User $update_author): CapsuleBuilder
......@@ -70,8 +81,17 @@ class CapsuleBuilder
return $this;
}
public function withPassword(string $password): CapsuleBuilder
{
$this->capsule->setPassword($password);
$this->hasPasswordSet = true;
return $this;
}
public function createCapsule(): Capsule
{
$this->createEditionLink();
ContractHelper::requires(
$this->hasRequiredName,
"The call of CapsuleBuilder::withName should be called before CapsuleBuilder::create"
......@@ -96,6 +116,10 @@ class CapsuleBuilder
$this->hasRequiredUpdateDate,
"The call of CapsuleBuilder::withUpdateDate should be called before CapsuleBuilder::create"
);
ContractHelper::requires(
$this->hasPasswordSet,
"The capsule should have its password defined"
);
return $this->capsule;
}
......
......@@ -54,6 +54,10 @@ class UserBuilder
public function withPassword(string $password): UserBuilder
{
ContractHelper::requires(
$this->hasRequiredSalt,
"The call of UserBuilder::withSalt should be called before UserBuilder::withPassword"
);
$this->user->setPassword($this->password_hasher->hashPassword($this->user, $password));
$this->hasRequiredPassword = true;
return $this;
......
......@@ -3,6 +3,7 @@
namespace App\Controller;
use App\Entity\User;
use App\Helper\StringHelper;
use App\Repository\CapsuleRepository;
use App\Builder\CapsuleBuilder;
use App\Form\CreateCapsuleFormType;
......@@ -51,8 +52,8 @@ class CapsuleController extends AbstractController
$new_date_time = new \DateTime();
$capsule_name = $form->get('name')->getData();
$video_url = htmlspecialchars($form->get('video_url')->getData());
$password = StringHelper::generateRandomHashedString();
$preview_link = Uuid::v4();
$edition_link = $preview_link . '/?p=edit';
$entityManager = $this->getDoctrine()->getManager();
$capsule_builder = new CapsuleBuilder();
......@@ -61,8 +62,8 @@ class CapsuleController extends AbstractController
->withCreationAuthor($current_user)
->withCreationDate($new_date_time)
->withPreviewLink($preview_link)
->withEditionLink($edition_link)
->withUpdateDate($new_date_time)
->withPassword($password)
->createCapsule();
$entityManager->persist($capsule);
......
......@@ -7,6 +7,7 @@ use App\Exception\ZipArchiveNotOpeningException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Config\Util\Exception\XmlParsingException;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
......@@ -46,6 +47,8 @@ class ProjectController extends AbstractController
$this->addProjectVideoUrlInXMLProjectFile($capsule_directory, $video_url);
$this->createOrUpdatePasswordFile($capsule_directory, $capsule->getPassword());
$this->addFlash(
'capsule_created_success',
$translator->trans(
......@@ -92,4 +95,10 @@ class ProjectController extends AbstractController
throw new XmlParsingException('Video URL could not be written in XML project file');
}
}
private function createOrUpdatePasswordFile(string $capsule_directory, string $password): void
{
$project_password_file = $capsule_directory . "/file/projectPassword.txt";
file_put_contents($project_password_file, $password);
}
}
......@@ -38,13 +38,14 @@ class CapsuleFixtures extends Fixture implements DependentFixtureInterface
$new_date_time
) {
$uuid = Uuid::v4();
$password = sha1(random_bytes(100));
$builder
->withName("Pomme")
->withCreationAuthor($verified_user1)
->withCreationDate($new_date_time)
->withUpdateDate($new_date_time)
->withPreviewLink($uuid)
->withEditionLink($uuid . '/?p=edit');
->withPassword($password);
}
);
......@@ -54,13 +55,14 @@ class CapsuleFixtures extends Fixture implements DependentFixtureInterface
$new_date_time
) {
$uuid = Uuid::v4();
$password = sha1(random_bytes(100));
$builder
->withName("Adele")
->withCreationAuthor($verified_user2)
->withCreationDate($new_date_time)
->withUpdateDate($new_date_time)
->withPreviewLink($uuid)
->withEditionLink($uuid . '/?p=edit');
->withPassword($password);
}
);
......
......@@ -70,6 +70,13 @@ class Capsule
*/
private string $edition_link;
/**
* @var string the capsule edit password access
*
* @ORM\Column (name="password", type="string", length=50, nullable=false, options={"default":""})
*/
private string $password;
public function getId(): int
{
return $this->id;
......@@ -155,4 +162,14 @@ class Capsule
{
$this->updated_date = $update_date;
}
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): void
{
$this->password = $password;
}
}
<?php
namespace App\Helper;
class StringHelper
{
public static function generateRandomHashedString(): string
{
return strtoupper(sha1(random_bytes(100)));
}
}
......@@ -87,6 +87,11 @@ class ProjectControllerTest extends WebTestCase
return $this->getCapsuleDirPath($capsule_directory) . '/file/project.xml';
}
private function getPasswordFilePath(string $capsule_directory): string
{
return $this->getCapsuleDirPath($capsule_directory) . '/file/projectPassword.txt';
}
public function testProjectDirectoryWithCorrespondingXMLFileIsCreatedWhenCapsuleCreationIsSuccessful(): void
{
$video_url = "https://TestUrl";
......@@ -129,4 +134,45 @@ class ProjectControllerTest extends WebTestCase
$this->assertEquals($video_url, $video_url_in_xml_file);
$this->assertSame(self::CAPSULE_NAME, $capsule_name_in_db);
}
public function testProjectDirectoryWithCorrespondingPasswordFileIsCreatedWhenCapsuleCreationIsSuccessful(): void
{
$video_url = "https://TestUrl";
$this->form['create_capsule_form[name]'] = self::CAPSULE_NAME;
$this->form['create_capsule_form[video_url]'] = $video_url;
$this->client->submit($this->form);
$this->assertResponseRedirects(
'/my_capsules',
302,
'Once the capsule is created, the user should be redirected to its capsules lists'
);
$this->client->followRedirect();
$this->assertResponseIsSuccessful('/my_capsules');
$capsule_repository = $this->object_manager->getRepository(Capsule::class);
$capsule_in_db = $capsule_repository->findOneBy(['name' => self::CAPSULE_NAME]);
if (! $capsule_in_db instanceof Capsule) {
throw new \Exception("Capsule does not exist.");
}
$capsule_name_in_db = $capsule_in_db->getName();
$capsule_directory = $capsule_in_db->getPreviewLink();
$this->assertDirectoryExists($capsule_directory);
$this->assertDirectoryIsReadable($capsule_directory);
$password_file_path = $this->getPasswordFilePath($capsule_directory);
$password = file_get_contents($password_file_path, true);
$this->assertTrue(false !== $password, "The projectPassword.txt should be readable");
$this->assertSame(
$capsule_in_db->getPassword(),
$password,
"The password should be saved in projectPassword.txt file"
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment