From e20bb42f9850163b3129ed5c53308933e3b34245 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 5 Feb 2020 11:21:45 +0300 Subject: [PATCH 01/13] hide cterms ckbox if not relevant --- templates/web/admin/fields/index.html.twig | 14 ++++++++++++++ templates/web/admin/fields/templates.html.twig | 14 ++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/templates/web/admin/fields/index.html.twig b/templates/web/admin/fields/index.html.twig index e8198a324f..531ef168eb 100644 --- a/templates/web/admin/fields/index.html.twig +++ b/templates/web/admin/fields/index.html.twig @@ -27,3 +27,17 @@ {# bootstrap admin field backbone application #} + + diff --git a/templates/web/admin/fields/templates.html.twig b/templates/web/admin/fields/templates.html.twig index 0dc661fc5c..a021a296c2 100644 --- a/templates/web/admin/fields/templates.html.twig +++ b/templates/web/admin/fields/templates.html.twig @@ -261,12 +261,14 @@ - - - - - /> - + + +
> + +
+ From fc53e158da3cd06b3d12bca0e2cd9ad059a24935 Mon Sep 17 00:00:00 2001 From: aynsix Date: Wed, 5 Feb 2020 18:06:04 +0300 Subject: [PATCH 02/13] fix visible ckbox in the right side --- templates/web/admin/fields/index.html.twig | 14 -------------- templates/web/admin/fields/templates.html.twig | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/templates/web/admin/fields/index.html.twig b/templates/web/admin/fields/index.html.twig index 531ef168eb..e8198a324f 100644 --- a/templates/web/admin/fields/index.html.twig +++ b/templates/web/admin/fields/index.html.twig @@ -27,17 +27,3 @@ {# bootstrap admin field backbone application #} - - diff --git a/templates/web/admin/fields/templates.html.twig b/templates/web/admin/fields/templates.html.twig index a021a296c2..c8802adc9a 100644 --- a/templates/web/admin/fields/templates.html.twig +++ b/templates/web/admin/fields/templates.html.twig @@ -263,7 +263,7 @@ -
> +
From a20962e9bac2c852e7de316f1222d2834f04b5f9 Mon Sep 17 00:00:00 2001 From: aynsix Date: Fri, 7 Feb 2020 12:35:57 +0300 Subject: [PATCH 03/13] hide chkbox --- templates/web/admin/fields/index.html.twig | 14 ++++++++++++++ templates/web/admin/fields/templates.html.twig | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/templates/web/admin/fields/index.html.twig b/templates/web/admin/fields/index.html.twig index e8198a324f..531ef168eb 100644 --- a/templates/web/admin/fields/index.html.twig +++ b/templates/web/admin/fields/index.html.twig @@ -27,3 +27,17 @@ {# bootstrap admin field backbone application #} + + diff --git a/templates/web/admin/fields/templates.html.twig b/templates/web/admin/fields/templates.html.twig index c8802adc9a..63117d56af 100644 --- a/templates/web/admin/fields/templates.html.twig +++ b/templates/web/admin/fields/templates.html.twig @@ -263,12 +263,13 @@ -
+
>
+
From e75a483cd5ba72938b9ce06ad9161c946be8e5bd Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Thu, 6 Feb 2020 19:40:59 +0100 Subject: [PATCH 04/13] PHRAS-2913_create-tokens-faster_4.1 - create token by sql - create feedentry tokens in bulk-sql --- .../Controller/Prod/FeedController.php | 5 + .../Event/Subscriber/FeedEntrySubscriber.php | 69 ++++++----- .../Model/Manipulator/TokenManipulator.php | 107 ++++++++++++++---- .../Model/Repositories/TokenRepository.php | 5 + 4 files changed, 140 insertions(+), 46 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php b/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php index 2bc333f45c..39a0a8f48d 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php @@ -19,8 +19,10 @@ use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\Link\AggregateLinkGenerator; use Alchemy\Phrasea\Feed\Link\FeedLinkGenerator; +use Alchemy\Phrasea\Model\Entities\Feed; use Alchemy\Phrasea\Model\Entities\FeedEntry; use Alchemy\Phrasea\Model\Entities\FeedItem; +use Alchemy\Phrasea\Model\Entities\FeedPublisher; use Alchemy\Phrasea\Model\Repositories\FeedEntryRepository; use Alchemy\Phrasea\Model\Repositories\FeedItemRepository; use Alchemy\Phrasea\Model\Repositories\FeedPublisherRepository; @@ -46,6 +48,7 @@ class FeedController extends Controller } public function createFeedEntryAction(Request $request) { + /** @var Feed $feed */ $feed = $this->getFeedRepository()->find($request->request->get('feed_id')); if (null === $feed) { @@ -53,6 +56,8 @@ class FeedController extends Controller } $user = $this->getAuthenticatedUser(); + + /** @var FeedPublisher $publisher */ $publisher = $this->getFeedPublisherRepository()->findOneBy([ 'feed' => $feed, 'user' => $user, diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php index 03a72a95b4..8bc7cb2b52 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FeedEntrySubscriber.php @@ -13,7 +13,9 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Core\Event\FeedEntryEvent; use Alchemy\Phrasea\Core\PhraseaEvents; +use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\WebhookEvent; +use Alchemy\Phrasea\Model\Manipulator\TokenManipulator; use Alchemy\Phrasea\Notification\Receiver; use Alchemy\Phrasea\Notification\Mail\MailInfoNewPublication; @@ -53,36 +55,43 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber do { $results = $Query->limit($start, $perLoop)->execute()->get_results(); - foreach ($results as $user_to_notif) { - $mailed = false; + $users_emailed = []; // for all users + $users_to_email = []; // list only users who must be emailed (=create tokens) - if ($params['notify_email'] && $this->shouldSendNotificationFor($user_to_notif, 'eventsmanager_notify_feed')) { - $readyToSend = false; - try { - $token = $this->app['manipulator.token']->createFeedEntryToken($user_to_notif, $entry); - $url = $this->app->url('lightbox', ['LOG' => $token->getValue()]); - - $receiver = Receiver::fromUser($user_to_notif); - $readyToSend = true; - } catch (\Exception $e) { - - } - - if ($readyToSend) { - $mail = MailInfoNewPublication::create($this->app, $receiver); - $mail->setButtonUrl($url); - $mail->setAuthor($entry->getAuthorName()); - $mail->setTitle($entry->getTitle()); - - $this->deliver($mail); - $mailed = true; - } + /** @var User $user */ + foreach ($results as $user) { + $users_emailed[$user->getId()] = false; + if ($params['notify_email'] && $this->shouldSendNotificationFor($user, 'eventsmanager_notify_feed')) { + $users_to_email[$user->getId()] = $user; } - - $this->app['events-manager']->notify($user_to_notif->getId(), 'eventsmanager_notify_feed', $datas, $mailed); } + + // get many tokens in one shot + $tokens = $this->getTokenManipulator()->createFeedEntryTokens($users_to_email, $entry); + foreach($tokens as $token) { + try { + $url = $this->app->url('lightbox', ['LOG' => $token->getValue()]); + $receiver = Receiver::fromUser($token->getUser()); + + $mail = MailInfoNewPublication::create($this->app, $receiver); + $mail->setButtonUrl($url); + $mail->setAuthor($entry->getAuthorName()); + $mail->setTitle($entry->getTitle()); + + $this->deliver($mail); + $users_emailed[$token->getUser()->getId()] = true; + } + catch (\Exception $e) { + // no-op + } + } + foreach($users_emailed as $id => $emailed) { + $this->app['events-manager']->notify($id, 'eventsmanager_notify_feed', $datas, $emailed); + } + $start += $perLoop; - } while (count($results) > 0); + } + while (count($results) > 0); } public static function getSubscribedEvents() @@ -91,4 +100,12 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber PhraseaEvents::FEED_ENTRY_CREATE => 'onCreate', ]; } + + /** + * @return TokenManipulator + */ + private function getTokenManipulator() + { + return $this->app['manipulator.token']; + } } diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index 2a43363693..c2e6786fe4 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -62,29 +62,45 @@ class TokenManipulator implements ManipulatorInterface * * @return Token */ - public function create(User $user = null, $type, \DateTime $expiration = null, $data = null) + public function create(User $user, $type, \DateTime $expiration = null, $data = null) { - $this->removeExpiredTokens(); + static $stmt = null; - $n = 0; - do { - if ($n++ > 1024) { - throw new \RuntimeException('Unable to create a token.'); + // $this->removeExpiredTokens(); + + if($stmt === null) { + $conn = $this->repository->getEntityManager()->getConnection(); + $sql = "INSERT INTO Tokens (value, user_id, type, data, created, updated, expiration)\n" + . " VALUES(:value, :user_id, :type, :data, :created, :updated, :expiration)"; + $stmt = $conn->prepare($sql); + } + + $token = null; + $now = (new \DateTime())->format('Y-m-d H:i:s'); + $stmtParms = [ + ':value' => null, + ':user_id' => $user->getId(), + ':type' => $type, + ':data' => $data, + ':created' => $now, + ':updated' => $now, + ':expiration' => $expiration + ]; + for($try=0; $try<1024; $try++) { + $stmtParms['value'] = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); + if($stmt->execute($stmtParms) === true) { + $token = new Token(); + $token->setUser($user) + ->setType($type) + ->setValue($stmtParms['value']) + ->setExpiration($expiration) + ->setData($data); + break; } - $value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); - $found = null !== $this->om->getRepository('Phraseanet:Token')->find($value); - } while ($found); - - $token = new Token(); - - $token->setUser($user) - ->setType($type) - ->setValue($value) - ->setExpiration($expiration) - ->setData($data); - - $this->om->persist($token); - $this->om->flush(); + } + if ($token === null) { + throw new \RuntimeException('Unable to create a token.'); + } return $token; } @@ -126,6 +142,57 @@ class TokenManipulator implements ManipulatorInterface return $this->create($user, self::TYPE_FEED_ENTRY, null, $entry->getId()); } + /** + * Create feedEntryTokens for many users in one shot + * + * @param User[] $users + * @param FeedEntry $entry + * @return Token[] + * @throws \Doctrine\DBAL\DBALException + */ + public function createFeedEntryTokens($users, FeedEntry $entry) + { + // $this->removeExpiredTokens(); + + $conn = $this->repository->getEntityManager()->getConnection(); + + // use an optimized tmp table we can fill fast (only 2 values changes by row, others are default) + $now = $conn->quote((new \DateTime())->format('Y-m-d H:i:s')); + $conn->executeQuery("CREATE TEMPORARY TABLE `tmpTokens` (\n" + . " `value` char(128),\n" + . " `user_id` int(11),\n" + . " `type` char(32) DEFAULT " . $conn->quote(self::TYPE_FEED_ENTRY) . ",\n" + . " `data` int(11) DEFAULT " . $conn->quote($entry->getId()) . ",\n" + . " `created` datetime DEFAULT " . $now . ",\n" + . " `updated` datetime DEFAULT " . $now . ",\n" + . " `expiration` datetime DEFAULT NULL\n" + . ") ENGINE=MEMORY;" + ); + + $tokens = []; + $sql = ""; + foreach ($users as $user) { + $value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS) . $user->getId(); + // todo: don't build a too long sql, we should flush/run into temp table if l>limit. + // But for now we trust that 100 (see FeedEntrySsuscriber) tokens is ok + $sql .= ($sql?',':'') . ('(' . $conn->quote($value) . ',' . $conn->quote($user->getId()) . ')'); + + $token = new Token(); + $token->setUser($user) + ->setType(self::TYPE_FEED_ENTRY) + ->setValue($value) + ->setExpiration(null) + ->setData($entry->getId()); + $tokens[] = $token; + } + + $conn->executeQuery("INSERT INTO tmpTokens (`value`, `user_id`) VALUES " . $sql); + $conn->executeQuery("INSERT INTO Tokens SELECT * FROM tmpTokens"); + $conn->executeQuery("DROP TABLE tmpTokens"); + + return $tokens; + } + /** * @param User $user * @param $data diff --git a/lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php index ad45425f7c..8e40f9ebd8 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php @@ -72,4 +72,9 @@ class TokenRepository extends EntityRepository return $query->getResult(); } + + public function getEntityManager() + { + return parent::getEntityManager(); + } } From 746c9076d4e4d9d57ba9ec0a63e5576b09e1ad10 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Fri, 7 Feb 2020 19:34:30 +0100 Subject: [PATCH 05/13] fix malformed sql --- lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index c2e6786fe4..e727f8dada 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -84,7 +84,7 @@ class TokenManipulator implements ManipulatorInterface ':data' => $data, ':created' => $now, ':updated' => $now, - ':expiration' => $expiration + ':expiration' => ($expiration === null ? null : $expiration->format('Y-m-d H:i:s')) ]; for($try=0; $try<1024; $try++) { $stmtParms['value'] = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); From 18993043f24d331ae20858b12c2492f42fc64d88 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Fri, 7 Feb 2020 22:14:16 +0100 Subject: [PATCH 06/13] fake change to re-run tests --- lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index e727f8dada..b3cec7dfc9 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -22,7 +22,6 @@ use RandomLib\Generator; class TokenManipulator implements ManipulatorInterface { const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const TYPE_FEED_ENTRY = 'FEED_ENTRY'; const TYPE_PASSWORD = 'password'; const TYPE_ACCOUNT_UNLOCK = 'account-unlock'; From 419440f5c2e4d8a4a0ae64184ff602fbe99e8528 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Fri, 7 Feb 2020 22:33:18 +0100 Subject: [PATCH 07/13] fix for failing test --- lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index b3cec7dfc9..9e1475cd4c 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -61,7 +61,7 @@ class TokenManipulator implements ManipulatorInterface * * @return Token */ - public function create(User $user, $type, \DateTime $expiration = null, $data = null) + public function create($user, $type, \DateTime $expiration = null, $data = null) { static $stmt = null; From 83484e3bd06ca3df59c6b5e59020ee4ed8eb6c98 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Sat, 8 Feb 2020 09:58:57 +0100 Subject: [PATCH 08/13] fix for unit-testing on null user (to dig : why ?...) --- lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index 9e1475cd4c..6314e9e614 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -78,12 +78,12 @@ class TokenManipulator implements ManipulatorInterface $now = (new \DateTime())->format('Y-m-d H:i:s'); $stmtParms = [ ':value' => null, - ':user_id' => $user->getId(), + ':user_id' => $user ? $user->getId() : null, ':type' => $type, ':data' => $data, ':created' => $now, ':updated' => $now, - ':expiration' => ($expiration === null ? null : $expiration->format('Y-m-d H:i:s')) + ':expiration' => $expiration ? $expiration->format('Y-m-d H:i:s') : null ]; for($try=0; $try<1024; $try++) { $stmtParms['value'] = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); From e4d3da93365ff452799fbffb9a03969392161486 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Sat, 8 Feb 2020 22:29:52 +0100 Subject: [PATCH 09/13] rollback : can't create token in sql since the om will cry during update. Can't mix om and sql. --- .../Model/Manipulator/TokenManipulator.php | 56 +++++++------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index 6314e9e614..607cbc6cc6 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -61,45 +61,29 @@ class TokenManipulator implements ManipulatorInterface * * @return Token */ - public function create($user, $type, \DateTime $expiration = null, $data = null) + public function create(User $user = null, $type, \DateTime $expiration = null, $data = null) { - static $stmt = null; + $this->removeExpiredTokens(); - // $this->removeExpiredTokens(); - - if($stmt === null) { - $conn = $this->repository->getEntityManager()->getConnection(); - $sql = "INSERT INTO Tokens (value, user_id, type, data, created, updated, expiration)\n" - . " VALUES(:value, :user_id, :type, :data, :created, :updated, :expiration)"; - $stmt = $conn->prepare($sql); - } - - $token = null; - $now = (new \DateTime())->format('Y-m-d H:i:s'); - $stmtParms = [ - ':value' => null, - ':user_id' => $user ? $user->getId() : null, - ':type' => $type, - ':data' => $data, - ':created' => $now, - ':updated' => $now, - ':expiration' => $expiration ? $expiration->format('Y-m-d H:i:s') : null - ]; - for($try=0; $try<1024; $try++) { - $stmtParms['value'] = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); - if($stmt->execute($stmtParms) === true) { - $token = new Token(); - $token->setUser($user) - ->setType($type) - ->setValue($stmtParms['value']) - ->setExpiration($expiration) - ->setData($data); - break; + $n = 0; + do { + if ($n++ > 1024) { + throw new \RuntimeException('Unable to create a token.'); } - } - if ($token === null) { - throw new \RuntimeException('Unable to create a token.'); - } + $value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS); + $found = null !== $this->om->getRepository('Phraseanet:Token')->find($value); + } while ($found); + + $token = new Token(); + + $token->setUser($user) + ->setType($type) + ->setValue($value) + ->setExpiration($expiration) + ->setData($data); + + $this->om->persist($token); + $this->om->flush(); return $token; } From 5f7ca7c9a6c7914586b621b0e42f5aa3a5887256 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Mon, 10 Feb 2020 11:16:41 +0100 Subject: [PATCH 10/13] add indexes to table "Tokens" --- lib/Alchemy/Phrasea/Core/Version.php | 2 +- lib/Alchemy/Phrasea/Model/Entities/Token.php | 9 ++- lib/classes/patch/410alpha21a.php | 75 ++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 lib/classes/patch/410alpha21a.php diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index 5f488cdd5a..3a3ff63afc 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -16,7 +16,7 @@ class Version /** * @var string */ - private $number = '4.1.0-alpha.20a'; + private $number = '4.1.0-alpha.21a'; /** * @var string diff --git a/lib/Alchemy/Phrasea/Model/Entities/Token.php b/lib/Alchemy/Phrasea/Model/Entities/Token.php index 576cf05d36..81c632f97d 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/Token.php +++ b/lib/Alchemy/Phrasea/Model/Entities/Token.php @@ -15,7 +15,14 @@ use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; /** - * @ORM\Table(name="Tokens") + * @ORM\Table(name="Tokens", + * indexes={ + * @ORM\index(name="type", columns={"type"}), + * @ORM\index(name="created", columns={"created"}), + * @ORM\index(name="updated", columns={"updated"}), + * @ORM\index(name="expiration", columns={"expiration"}) + * } + * ) * @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\TokenRepository") */ class Token diff --git a/lib/classes/patch/410alpha21a.php b/lib/classes/patch/410alpha21a.php new file mode 100644 index 0000000000..f691520b1a --- /dev/null +++ b/lib/classes/patch/410alpha21a.php @@ -0,0 +1,75 @@ +release; + } + + /** + * {@inheritdoc} + */ + public function concern() + { + return $this->concern; + } + + /** + * {@inheritdoc} + */ + public function require_all_upgrades() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function getDoctrineMigrations() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply(base $appbox, Application $app) + { + foreach(['type', 'created', 'updated', 'expiration'] as $t) { + $sql = "ALTER TABLE `Tokens` ADD INDEX `".$t."` (`".$t."`);"; + try { + $stmt = $appbox->get_connection()->prepare($sql); + $stmt->execute(); + $stmt->closeCursor(); + } + catch (\Exception $e) { + // the inex already exists ? + } + } + + return true; + } +} From 211ba02f595f0ab52ad6d9861aa63db008766c53 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Mon, 10 Feb 2020 11:39:42 +0100 Subject: [PATCH 11/13] bump patch to 22a --- lib/Alchemy/Phrasea/Core/Version.php | 2 +- lib/classes/patch/{410alpha21a.php => 410alpha22a.php} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename lib/classes/patch/{410alpha21a.php => 410alpha22a.php} (93%) diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index 3a3ff63afc..d17062de4c 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -16,7 +16,7 @@ class Version /** * @var string */ - private $number = '4.1.0-alpha.21a'; + private $number = '4.1.0-alpha.22a'; /** * @var string diff --git a/lib/classes/patch/410alpha21a.php b/lib/classes/patch/410alpha22a.php similarity index 93% rename from lib/classes/patch/410alpha21a.php rename to lib/classes/patch/410alpha22a.php index f691520b1a..6a80bd058e 100644 --- a/lib/classes/patch/410alpha21a.php +++ b/lib/classes/patch/410alpha22a.php @@ -11,10 +11,10 @@ use Alchemy\Phrasea\Application; -class patch_410alpha21a implements patchInterface +class patch_410alpha22a implements patchInterface { /** @var string */ - private $release = '4.1.0-alpha.21a'; + private $release = '4.1.0-alpha.22a'; /** @var array */ private $concern = [base::APPLICATION_BOX]; From 5a794c493a61b9434acfee62a3942afb909603f4 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Tue, 11 Feb 2020 15:17:13 +0100 Subject: [PATCH 12/13] create feedEntriesTokens in bulk / doctrine. No more sql --- .../Model/Manipulator/TokenManipulator.php | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php index 607cbc6cc6..56c4e9fc36 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php @@ -137,28 +137,9 @@ class TokenManipulator implements ManipulatorInterface { // $this->removeExpiredTokens(); - $conn = $this->repository->getEntityManager()->getConnection(); - - // use an optimized tmp table we can fill fast (only 2 values changes by row, others are default) - $now = $conn->quote((new \DateTime())->format('Y-m-d H:i:s')); - $conn->executeQuery("CREATE TEMPORARY TABLE `tmpTokens` (\n" - . " `value` char(128),\n" - . " `user_id` int(11),\n" - . " `type` char(32) DEFAULT " . $conn->quote(self::TYPE_FEED_ENTRY) . ",\n" - . " `data` int(11) DEFAULT " . $conn->quote($entry->getId()) . ",\n" - . " `created` datetime DEFAULT " . $now . ",\n" - . " `updated` datetime DEFAULT " . $now . ",\n" - . " `expiration` datetime DEFAULT NULL\n" - . ") ENGINE=MEMORY;" - ); - $tokens = []; - $sql = ""; foreach ($users as $user) { $value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS) . $user->getId(); - // todo: don't build a too long sql, we should flush/run into temp table if l>limit. - // But for now we trust that 100 (see FeedEntrySsuscriber) tokens is ok - $sql .= ($sql?',':'') . ('(' . $conn->quote($value) . ',' . $conn->quote($user->getId()) . ')'); $token = new Token(); $token->setUser($user) @@ -167,11 +148,11 @@ class TokenManipulator implements ManipulatorInterface ->setExpiration(null) ->setData($entry->getId()); $tokens[] = $token; - } - $conn->executeQuery("INSERT INTO tmpTokens (`value`, `user_id`) VALUES " . $sql); - $conn->executeQuery("INSERT INTO Tokens SELECT * FROM tmpTokens"); - $conn->executeQuery("DROP TABLE tmpTokens"); + $this->om->persist($token); + } + $this->om->flush(); + $this->om->clear(); return $tokens; } From f2b2092a12a401e54c75b39ea3dbd4fd9ca61d9b Mon Sep 17 00:00:00 2001 From: Harrys Ravalomanana Date: Tue, 18 Feb 2020 11:59:31 +0400 Subject: [PATCH 13/13] PHRAS-2825 center the reset button --- templates/web/prod/results/help.html.twig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/web/prod/results/help.html.twig b/templates/web/prod/results/help.html.twig index 633ebeac40..bc6406cb5b 100644 --- a/templates/web/prod/results/help.html.twig +++ b/templates/web/prod/results/help.html.twig @@ -30,7 +30,11 @@
  • {{ 'help::help-section-bullet: search-in-a-specific-field' | trans }}

  • -

    - {{ 'help::help-search: relaunch search without filter' | trans }}

    +
    +

    {{ 'help::help-search: OR' | trans }}

    +
    +

    + {{ 'help::help-search: relaunch search without filter' | trans }} +

    {% endblock %}