Merge branch 'master' into PHRAS-2911-gif-preview-video

This commit is contained in:
Nicolas Maillat
2020-02-18 15:55:59 +01:00
committed by GitHub
10 changed files with 197 additions and 36 deletions

View File

@@ -19,8 +19,10 @@ use Alchemy\Phrasea\Core\PhraseaEvents;
use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\Aggregate;
use Alchemy\Phrasea\Feed\Link\AggregateLinkGenerator; use Alchemy\Phrasea\Feed\Link\AggregateLinkGenerator;
use Alchemy\Phrasea\Feed\Link\FeedLinkGenerator; use Alchemy\Phrasea\Feed\Link\FeedLinkGenerator;
use Alchemy\Phrasea\Model\Entities\Feed;
use Alchemy\Phrasea\Model\Entities\FeedEntry; use Alchemy\Phrasea\Model\Entities\FeedEntry;
use Alchemy\Phrasea\Model\Entities\FeedItem; use Alchemy\Phrasea\Model\Entities\FeedItem;
use Alchemy\Phrasea\Model\Entities\FeedPublisher;
use Alchemy\Phrasea\Model\Repositories\FeedEntryRepository; use Alchemy\Phrasea\Model\Repositories\FeedEntryRepository;
use Alchemy\Phrasea\Model\Repositories\FeedItemRepository; use Alchemy\Phrasea\Model\Repositories\FeedItemRepository;
use Alchemy\Phrasea\Model\Repositories\FeedPublisherRepository; use Alchemy\Phrasea\Model\Repositories\FeedPublisherRepository;
@@ -46,6 +48,7 @@ class FeedController extends Controller
} }
public function createFeedEntryAction(Request $request) { public function createFeedEntryAction(Request $request) {
/** @var Feed $feed */
$feed = $this->getFeedRepository()->find($request->request->get('feed_id')); $feed = $this->getFeedRepository()->find($request->request->get('feed_id'));
if (null === $feed) { if (null === $feed) {
@@ -53,6 +56,8 @@ class FeedController extends Controller
} }
$user = $this->getAuthenticatedUser(); $user = $this->getAuthenticatedUser();
/** @var FeedPublisher $publisher */
$publisher = $this->getFeedPublisherRepository()->findOneBy([ $publisher = $this->getFeedPublisherRepository()->findOneBy([
'feed' => $feed, 'feed' => $feed,
'user' => $user, 'user' => $user,

View File

@@ -13,7 +13,9 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Core\Event\FeedEntryEvent; use Alchemy\Phrasea\Core\Event\FeedEntryEvent;
use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Core\PhraseaEvents;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Entities\WebhookEvent; use Alchemy\Phrasea\Model\Entities\WebhookEvent;
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
use Alchemy\Phrasea\Notification\Receiver; use Alchemy\Phrasea\Notification\Receiver;
use Alchemy\Phrasea\Notification\Mail\MailInfoNewPublication; use Alchemy\Phrasea\Notification\Mail\MailInfoNewPublication;
@@ -53,36 +55,43 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber
do { do {
$results = $Query->limit($start, $perLoop)->execute()->get_results(); $results = $Query->limit($start, $perLoop)->execute()->get_results();
foreach ($results as $user_to_notif) { $users_emailed = []; // for all users
$mailed = false; $users_to_email = []; // list only users who must be emailed (=create tokens)
if ($params['notify_email'] && $this->shouldSendNotificationFor($user_to_notif, 'eventsmanager_notify_feed')) { /** @var User $user */
$readyToSend = false; foreach ($results as $user) {
try { $users_emailed[$user->getId()] = false;
$token = $this->app['manipulator.token']->createFeedEntryToken($user_to_notif, $entry); if ($params['notify_email'] && $this->shouldSendNotificationFor($user, 'eventsmanager_notify_feed')) {
$url = $this->app->url('lightbox', ['LOG' => $token->getValue()]); $users_to_email[$user->getId()] = $user;
$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;
}
} }
$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; $start += $perLoop;
} while (count($results) > 0); }
while (count($results) > 0);
} }
public static function getSubscribedEvents() public static function getSubscribedEvents()
@@ -91,4 +100,12 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber
PhraseaEvents::FEED_ENTRY_CREATE => 'onCreate', PhraseaEvents::FEED_ENTRY_CREATE => 'onCreate',
]; ];
} }
/**
* @return TokenManipulator
*/
private function getTokenManipulator()
{
return $this->app['manipulator.token'];
}
} }

View File

@@ -16,7 +16,7 @@ class Version
/** /**
* @var string * @var string
*/ */
private $number = '4.1.0-alpha.21a'; private $number = '4.1.0-alpha.22a';
/** /**
* @var string * @var string

View File

@@ -15,7 +15,14 @@ use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo; 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") * @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\TokenRepository")
*/ */
class Token class Token

View File

@@ -22,7 +22,6 @@ use RandomLib\Generator;
class TokenManipulator implements ManipulatorInterface class TokenManipulator implements ManipulatorInterface
{ {
const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const TYPE_FEED_ENTRY = 'FEED_ENTRY'; const TYPE_FEED_ENTRY = 'FEED_ENTRY';
const TYPE_PASSWORD = 'password'; const TYPE_PASSWORD = 'password';
const TYPE_ACCOUNT_UNLOCK = 'account-unlock'; const TYPE_ACCOUNT_UNLOCK = 'account-unlock';
@@ -126,6 +125,38 @@ class TokenManipulator implements ManipulatorInterface
return $this->create($user, self::TYPE_FEED_ENTRY, null, $entry->getId()); 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();
$tokens = [];
foreach ($users as $user) {
$value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS) . $user->getId();
$token = new Token();
$token->setUser($user)
->setType(self::TYPE_FEED_ENTRY)
->setValue($value)
->setExpiration(null)
->setData($entry->getId());
$tokens[] = $token;
$this->om->persist($token);
}
$this->om->flush();
$this->om->clear();
return $tokens;
}
/** /**
* @param User $user * @param User $user
* @param $data * @param $data

View File

@@ -72,4 +72,9 @@ class TokenRepository extends EntityRepository
return $query->getResult(); return $query->getResult();
} }
public function getEntityManager()
{
return parent::getEntityManager();
}
} }

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2019 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Alchemy\Phrasea\Application;
class patch_410alpha22a implements patchInterface
{
/** @var string */
private $release = '4.1.0-alpha.22a';
/** @var array */
private $concern = [base::APPLICATION_BOX];
/**
* Returns the release version.
*
* @return string
*/
public function get_release()
{
return $this->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;
}
}

View File

@@ -27,3 +27,17 @@
{# bootstrap admin field backbone application #} {# bootstrap admin field backbone application #}
<script type="text/javascript" src="{{ path('minifier', { 'f' : '/scripts/apps/admin/fields/main.js' }) }}"></script> <script type="text/javascript" src="{{ path('minifier', { 'f' : '/scripts/apps/admin/fields/main.js' }) }}"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#admin-field-app').on('change', '#tbranch', function () {
if ($(this).val() === '') {
$('#generate_cterms').prop('checked', false);
$('.generate-cterms').addClass('hidden');
} else {
$('.generate-cterms').removeClass('hidden');
}
return false;
});
});
</script>

View File

@@ -259,11 +259,14 @@
</tr> </tr>
<tr> <tr>
<td><label for="tbranch">{% trans %}Thesaurus branch{% endtrans %}</label></td> <td><label for="tbranch">{% trans %}Thesaurus branch{% endtrans %}</label></td>
<td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td> <td>
</tr> <input id="tbranch" type="text" value="<%= field.tbranch %>"/>
<tr> <div style="display: inline-block;" <%= (field.tbranch == "") ? "class='generate-cterms hidden'" : "class='generate-cterms'" %> >
<td><label for="generate_cterms" class="checkbox">{% trans %}Generate-cterms{% endtrans %}</label></td> <label for="generate_cterms" class="checkbox">
<td><input id="generate_cterms" type="checkbox" <%= field.generate_cterms ? "checked='checked'" : "" %> /></td> <input id="generate_cterms" type="checkbox" <%= field.generate_cterms ? "checked='checked'" : "" %> />
{% trans %}Generate-cterms{% endtrans %}</label>
</div>
</td>
</tr> </tr>
</table> </table>
</div> </div>

View File

@@ -30,7 +30,11 @@
<li><p>{{ 'help::help-section-bullet: search-in-a-specific-field' | trans }}</p></li> <li><p>{{ 'help::help-section-bullet: search-in-a-specific-field' | trans }}</p></li>
</ul> </ul>
</div> </div>
<p> <br>
<span class="btn btn-info btn-lg trigger-reload-search" onclick="jQuery('.reload-search').trigger('click');">{{ 'help::help-search: relaunch search without filter' | trans }}</span></p> <p class="text-center">{{ 'help::help-search: OR' | trans }}</p>
<br>
<p class="text-center">
<span class="btn btn-info btn-lg trigger-reload-search" onclick="jQuery('.reload-search').trigger('click');">{{ 'help::help-search: relaunch search without filter' | trans }}</span>
</p>
</div> </div>
{% endblock %} {% endblock %}