Merge pull request #4962 from christianbeeznest/ofaj-20927-2
Social: Add social post attachments - refs BT#20927pull/4965/head
commit
139acd882f
@ -0,0 +1,58 @@ |
||||
<?php |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace Chamilo\CoreBundle\Controller\Api; |
||||
|
||||
use Chamilo\CoreBundle\Entity\SocialPost; |
||||
use Chamilo\CoreBundle\Entity\SocialPostAttachment; |
||||
use Chamilo\CoreBundle\Entity\User; |
||||
use Chamilo\CoreBundle\Repository\Node\SocialPostAttachmentRepository; |
||||
use Doctrine\ORM\EntityManager; |
||||
use Exception; |
||||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
||||
use Symfony\Component\HttpFoundation\Request; |
||||
use Symfony\Component\Security\Core\Security; |
||||
|
||||
class CreateSocialPostAttachmentAction extends BaseResourceFileAction |
||||
{ |
||||
/** |
||||
* @throws Exception |
||||
*/ |
||||
public function __invoke(Request $request, SocialPostAttachmentRepository $repo, EntityManager $em, Security $security): SocialPostAttachment |
||||
{ |
||||
/** @var UploadedFile $uploadedFile */ |
||||
$uploadedFile = $request->files->get('file'); |
||||
$socialPostId = $request->request->get('messageId'); |
||||
|
||||
if (!$uploadedFile instanceof UploadedFile) { |
||||
throw new \Exception('No file uploaded'); |
||||
} |
||||
|
||||
$socialPost = $em->getRepository(SocialPost::class)->find($socialPostId); |
||||
if (!$socialPost) { |
||||
throw new \Exception('No social post found'); |
||||
} |
||||
|
||||
/** @var User $currentUser */ |
||||
$currentUser = $security->getUser(); |
||||
$attachment = new SocialPostAttachment(); |
||||
$attachment->setSocialPost($socialPost); |
||||
$attachment->setPath(uniqid('social_post', true)); |
||||
$attachment->setFilename($uploadedFile->getClientOriginalName()); |
||||
$attachment->setSize($uploadedFile->getSize()); |
||||
$attachment->setInsertUserId($currentUser->getId()); |
||||
$attachment->setInsertDateTime(new \DateTime('now', new \DateTimeZone('UTC'))); |
||||
$attachment->setParent($currentUser); |
||||
$attachment->addUserLink($currentUser); |
||||
|
||||
$em->persist($attachment); |
||||
$em->flush(); |
||||
|
||||
$repo->addFile($attachment, $uploadedFile); |
||||
|
||||
return $attachment; |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace Chamilo\CoreBundle\Controller\Api; |
||||
|
||||
use Chamilo\CoreBundle\Entity\SocialPost; |
||||
use Chamilo\CoreBundle\Entity\SocialPostAttachment; |
||||
use Chamilo\CoreBundle\Repository\Node\SocialPostAttachmentRepository; |
||||
use Doctrine\ORM\EntityManager; |
||||
use Doctrine\ORM\EntityManagerInterface; |
||||
use Symfony\Component\HttpFoundation\JsonResponse; |
||||
use Symfony\Component\Security\Core\Security; |
||||
|
||||
class SocialPostAttachmentsController extends BaseResourceFileAction |
||||
{ |
||||
|
||||
public function __invoke(SocialPost $socialPost, EntityManager $em, Security $security, SocialPostAttachmentRepository $attachmentRepo): JsonResponse |
||||
{ |
||||
$attachments = $em->getRepository(SocialPostAttachment::class)->findBy(['socialPost' => $socialPost->getId()]); |
||||
|
||||
if (!$attachments) { |
||||
return new JsonResponse(['error' => 'No attachments found for this post'], JsonResponse::HTTP_NOT_FOUND); |
||||
} |
||||
|
||||
$attachmentsInfo = []; |
||||
foreach ($attachments as $attachment) { |
||||
$attachmentsInfo[] = [ |
||||
'id' => $attachment->getId(), |
||||
'filename' => $attachment->getFilename(), |
||||
'path' => $attachmentRepo->getResourceFileUrl($attachment), |
||||
'size' => $attachment->getSize(), |
||||
]; |
||||
} |
||||
|
||||
return new JsonResponse($attachmentsInfo, JsonResponse::HTTP_OK); |
||||
} |
||||
} |
@ -0,0 +1,192 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Entity; |
||||
|
||||
use ApiPlatform\Metadata\ApiResource; |
||||
use ApiPlatform\Metadata\Get; |
||||
use ApiPlatform\Metadata\GetCollection; |
||||
use ApiPlatform\Metadata\Post; |
||||
use Chamilo\CoreBundle\Controller\Api\CreateSocialPostAttachmentAction; |
||||
use Chamilo\CoreBundle\Repository\Node\SocialPostAttachmentRepository; |
||||
use DateTime; |
||||
use Doctrine\ORM\Mapping as ORM; |
||||
use Stringable; |
||||
|
||||
#[ApiResource( |
||||
types: ['http://schema.org/MediaObject'], |
||||
operations: [ |
||||
new Get(), |
||||
new GetCollection(), |
||||
new Post( |
||||
controller: CreateSocialPostAttachmentAction::class, |
||||
openapiContext: [ |
||||
'requestBody' => [ |
||||
'content' => [ |
||||
'multipart/form-data' => [ |
||||
'schema' => [ |
||||
'type' => 'object', |
||||
'properties' => [ |
||||
'file' => [ |
||||
'type' => 'string', |
||||
'format' => 'binary', |
||||
], |
||||
'messageId' => [ |
||||
'type' => 'integer', |
||||
], |
||||
], |
||||
], |
||||
], |
||||
], |
||||
], |
||||
], |
||||
security: 'is_granted(\'ROLE_USER\')', |
||||
validationContext: [ |
||||
'groups' => [ |
||||
'Default', |
||||
'message_attachment:create', |
||||
], |
||||
], |
||||
deserialize: false |
||||
), |
||||
], |
||||
normalizationContext: [ |
||||
'groups' => ['message:read'], |
||||
], |
||||
)] |
||||
#[ORM\Table(name: 'social_post_attachments')] |
||||
#[ORM\Entity(repositoryClass: SocialPostAttachmentRepository::class)] |
||||
class SocialPostAttachment extends AbstractResource implements ResourceInterface, Stringable |
||||
{ |
||||
#[ORM\Column(name: 'id', type: 'integer')] |
||||
#[ORM\Id] |
||||
#[ORM\GeneratedValue] |
||||
protected ?int $id = null; |
||||
|
||||
#[ORM\ManyToOne(targetEntity: \Chamilo\CoreBundle\Entity\SocialPost::class)] |
||||
#[ORM\JoinColumn(name: 'social_post_id', referencedColumnName: 'id', onDelete: 'CASCADE')] |
||||
protected SocialPost $socialPost; |
||||
|
||||
#[ORM\Column(name: 'path', type: 'string', length: 255, nullable: false)] |
||||
protected string $path; |
||||
|
||||
#[ORM\Column(name: 'filename', type: 'text', nullable: false)] |
||||
protected string $filename; |
||||
|
||||
#[ORM\Column(name: 'size', type: 'integer')] |
||||
protected int $size; |
||||
|
||||
#[ORM\Column(name: 'sys_insert_user_id', type: 'integer')] |
||||
protected int $insertUserId; |
||||
|
||||
#[ORM\Column(name: 'sys_insert_datetime', type: 'datetime')] |
||||
protected DateTime $insertDateTime; |
||||
|
||||
#[ORM\Column(name: 'sys_lastedit_user_id', type: 'integer', nullable: true, unique: false)] |
||||
protected ?int $lastEditUserId = null; |
||||
|
||||
#[ORM\Column(name: 'sys_lastedit_datetime', type: 'datetime', nullable: true, unique: false)] |
||||
protected ?DateTime $lastEditDateTime = null; |
||||
|
||||
public function __toString(): string |
||||
{ |
||||
return $this->getFilename(); |
||||
} |
||||
|
||||
/** |
||||
* @return int |
||||
*/ |
||||
public function getId() |
||||
{ |
||||
return $this->id; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getPath() |
||||
{ |
||||
return $this->path; |
||||
} |
||||
|
||||
public function setPath(string $path): self |
||||
{ |
||||
$this->path = $path; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getFilename() |
||||
{ |
||||
return $this->filename; |
||||
} |
||||
|
||||
public function setFilename(string $filename): self |
||||
{ |
||||
$this->filename = $filename; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* @return int |
||||
*/ |
||||
public function getSize() |
||||
{ |
||||
return $this->size; |
||||
} |
||||
|
||||
public function setSize(int $size): self |
||||
{ |
||||
$this->size = $size; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getSocialPost(): SocialPost |
||||
{ |
||||
return $this->socialPost; |
||||
} |
||||
|
||||
public function setSocialPost(SocialPost $socialPost): self |
||||
{ |
||||
$this->socialPost = $socialPost; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function getResourceName(): string |
||||
{ |
||||
return $this->getFilename(); |
||||
} |
||||
|
||||
public function setResourceName(string $name) |
||||
{ |
||||
return $this->setFilename($name); |
||||
} |
||||
|
||||
public function getResourceIdentifier(): int |
||||
{ |
||||
return $this->getId(); |
||||
} |
||||
|
||||
public function setInsertUserId(int $insertUserId): self |
||||
{ |
||||
$this->insertUserId = $insertUserId; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function setInsertDateTime(DateTime $insertDateTime): self |
||||
{ |
||||
$this->insertDateTime = $insertDateTime; |
||||
|
||||
return $this; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Migrations\Schema\V200; |
||||
|
||||
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo; |
||||
use Doctrine\DBAL\Schema\Schema; |
||||
|
||||
class Version20231026221100 extends AbstractMigrationChamilo |
||||
{ |
||||
public function getDescription(): string |
||||
{ |
||||
return 'Add table social_post_attachments'; |
||||
} |
||||
|
||||
public function up(Schema $schema): void |
||||
{ |
||||
if (false === $schema->hasTable('social_post_attachments')) { |
||||
$this->addSql("CREATE TABLE social_post_attachments (id INT AUTO_INCREMENT NOT NULL, social_post_id BIGINT DEFAULT NULL, resource_node_id BIGINT DEFAULT NULL, path VARCHAR(255) NOT NULL, filename LONGTEXT NOT NULL, size INT NOT NULL, sys_insert_user_id INT NOT NULL, sys_insert_datetime DATETIME NOT NULL COMMENT '(DC2Type:datetime)', sys_lastedit_user_id INT DEFAULT NULL, sys_lastedit_datetime DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime)', INDEX IDX_DF2A8F34C4F2D6B1 (social_post_id), UNIQUE INDEX UNIQ_DF2A8F341BAD783F (resource_node_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB ROW_FORMAT = DYNAMIC;"); |
||||
$this->addSql("ALTER TABLE social_post_attachments ADD CONSTRAINT FK_DF2A8F34C4F2D6B1 FOREIGN KEY (social_post_id) REFERENCES social_post (id) ON DELETE CASCADE;"); |
||||
$this->addSql("ALTER TABLE social_post_attachments ADD CONSTRAINT FK_DF2A8F341BAD783F FOREIGN KEY (resource_node_id) REFERENCES resource_node (id) ON DELETE CASCADE;"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,116 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
namespace Chamilo\CoreBundle\Migrations\Schema\V200; |
||||
|
||||
use Chamilo\CoreBundle\Entity\SocialPost; |
||||
use Chamilo\CoreBundle\Entity\SocialPostAttachment; |
||||
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo; |
||||
use Chamilo\CoreBundle\Repository\Node\SocialPostAttachmentRepository; |
||||
use Chamilo\CoreBundle\Repository\Node\UserRepository; |
||||
use DirectoryIterator; |
||||
use Doctrine\DBAL\Connection; |
||||
use Doctrine\DBAL\Schema\Schema; |
||||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
||||
|
||||
final class Version20231026231100 extends AbstractMigrationChamilo |
||||
{ |
||||
public function getDescription(): string |
||||
{ |
||||
return 'Migrate message_attachments to social_post_attachments'; |
||||
} |
||||
|
||||
public function up(Schema $schema): void |
||||
{ |
||||
$container = $this->getContainer(); |
||||
$em = $this->getEntityManager(); |
||||
/** @var Connection $connection */ |
||||
$connection = $em->getConnection(); |
||||
|
||||
$kernel = $container->get('kernel'); |
||||
$rootPath = $kernel->getProjectDir(); |
||||
|
||||
$repo = $container->get(SocialPostAttachmentRepository::class); |
||||
$userRepo = $container->get(UserRepository::class); |
||||
$admin = $this->getAdmin(); |
||||
|
||||
$sub = $em->createQueryBuilder(); |
||||
$sub->select('sp.id') |
||||
->from('Chamilo\CoreBundle\Entity\SocialPost', 'sp'); |
||||
|
||||
$qb = $em->createQueryBuilder(); |
||||
$qb->select('ma') |
||||
->from('Chamilo\CoreBundle\Entity\MessageAttachment', 'ma') |
||||
->where($qb->expr()->in('ma.message', $sub->getDQL())); |
||||
|
||||
$query = $qb->getQuery(); |
||||
$messageAttachments = $query->getResult(); |
||||
|
||||
foreach ($messageAttachments as $attachment) { |
||||
$message = $attachment->getMessage(); |
||||
if ($message) { |
||||
$messageId = $message->getId(); |
||||
$filename = $attachment->getFilename(); |
||||
$rootDir = $rootPath.'/app/upload/users'; |
||||
$targetFile = $attachment->getPath(); |
||||
$foundFilePath = $this->findFileRecursively($rootDir, $targetFile); |
||||
|
||||
if ($foundFilePath) { |
||||
echo "Archivo encontrado en: " . $foundFilePath; |
||||
|
||||
$mimeType = mime_content_type($foundFilePath); |
||||
$uploadFile = new UploadedFile($foundFilePath, $filename, $mimeType, null, true); |
||||
|
||||
$socialPost = $em->getRepository(SocialPost::class)->find($messageId); |
||||
|
||||
$attachment = new SocialPostAttachment(); |
||||
$attachment->setSocialPost($socialPost); |
||||
$attachment->setPath(uniqid('social_post', true)); |
||||
$attachment->setFilename($uploadFile->getClientOriginalName()); |
||||
$attachment->setSize($uploadFile->getSize()); |
||||
$attachment->setInsertUserId($admin->getId()); |
||||
$attachment->setInsertDateTime(new \DateTime('now', new \DateTimeZone('UTC'))); |
||||
$attachment->setParent($admin); |
||||
$attachment->addUserLink($admin); |
||||
$attachment->setCreator($admin); |
||||
|
||||
$em->persist($attachment); |
||||
$em->flush(); |
||||
|
||||
$repo->addFile($attachment, $uploadFile); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private function findFileRecursively(string $directory, string $targetFile): ?string |
||||
{ |
||||
if (!is_dir($directory)) { |
||||
return null; |
||||
} |
||||
|
||||
foreach (new DirectoryIterator($directory) as $fileInfo) { |
||||
if ($fileInfo->isDot()) { |
||||
continue; |
||||
} |
||||
|
||||
$filePath = $fileInfo->getPathname(); |
||||
|
||||
if ($fileInfo->isDir()) { |
||||
$result = $this->findFileRecursively($filePath, $targetFile); |
||||
if ($result !== null) { |
||||
return $result; |
||||
} |
||||
} else { |
||||
if (str_contains($fileInfo->getFilename(), $targetFile)) { |
||||
return $filePath; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
<?php |
||||
|
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace Chamilo\CoreBundle\Repository\Node; |
||||
|
||||
use Chamilo\CoreBundle\Entity\SocialPostAttachment; |
||||
use Chamilo\CoreBundle\Repository\ResourceRepository; |
||||
use Doctrine\Persistence\ManagerRegistry; |
||||
|
||||
class SocialPostAttachmentRepository extends ResourceRepository |
||||
{ |
||||
public function __construct(ManagerRegistry $registry) |
||||
{ |
||||
parent::__construct($registry, SocialPostAttachment::class); |
||||
} |
||||
} |
Loading…
Reference in new issue