This commit is contained in:
Taras Machyshyn
2020-04-06 14:36:42 +03:00
12 changed files with 123 additions and 27 deletions
+1 -1
View File
@@ -219,7 +219,7 @@ class DataManager
$cryptKey = $config->get('cryptKey');
if (!$cryptKey) {
$cryptKey = \Espo\Core\Utils\Util::generateKey();
$cryptKey = \Espo\Core\Utils\Util::generateSecretKey();
$config->set('cryptKey', $cryptKey);
}
+1 -1
View File
@@ -97,6 +97,6 @@ class Crypt
public function generateKey()
{
return \Espo\Core\Utils\Util::generateKey();
return \Espo\Core\Utils\Util::generateSecretKey();
}
}
+16 -9
View File
@@ -556,28 +556,35 @@ class Util
return true;
}
public static function generateId()
public static function generateId() : string
{
return uniqid() . substr(md5(rand()), 0, 4);
}
public static function generateApiKey()
public static function generateMoreEntropyId() : string
{
return substr(md5(uniqid(rand(), true)), 0, 16) . substr(md5(rand()), 0, 4);
}
public static function generateCryptId() : string
{
if (!function_exists('random_bytes')) {
return self::generateId();
return self::generateMoreEntropyId();
}
return bin2hex(random_bytes(16));
}
public static function generateSecretKey()
public static function generateApiKey() : string
{
if (!function_exists('random_bytes')) {
return self::generateId();
}
return bin2hex(random_bytes(16));
return self::generateCryptId();
}
public static function generateKey()
public static function generateSecretKey() : string
{
return self::generateCryptId();
}
public static function generateKey() : string
{
return md5(uniqid(rand(), true));
}
+4 -2
View File
@@ -31,6 +31,8 @@ namespace Espo\Entities;
class UniqueId extends \Espo\Core\ORM\Entity
{
public function getIdValue() : ?string
{
return $this->get('name');
}
}
@@ -83,18 +83,17 @@ class MassEmail extends \Espo\Services\Record
{
parent::afterDeleteEntity($massEmail);
$this->cleanupQueueItems($massEmail);
$this->getEntityManager()->getMapper('RDB')->massDeleteFromDb('EmailQueueItem', [
'massEmailId' => $massEmail->id,
]);
}
protected function cleanupQueueItems(Entity $massEmail)
{
$existingQueueItemList = $this->getEntityManager()->getRepository('EmailQueueItem')->select(['id'])->where([
'status' => ['Pending', 'Failed'],
$this->getEntityManager()->getMapper('RDB')->massDeleteFromDb('EmailQueueItem', [
'massEmailId' => $massEmail->id,
])->find();
foreach ($existingQueueItemList as $existingQueueItem) {
$this->getEntityManager()->getMapper('RDB')->deleteFromDb('EmailQueueItem', $existingQueueItem->id);
}
'status' => ['Pending', 'Failed'],
]);
}
public function createQueue(Entity $massEmail, $isTest = false, $additionalTargetList = [])
+27
View File
@@ -1061,6 +1061,33 @@ abstract class Mapper implements IMapper
return false;
}
/**
* Mass delete from database by specified whereClause.
* @return Number of deleted records or null if failure.
*/
public function massDeleteFromDb(string $entityType, array $whereClause) : ?int
{
$table = $this->toDb($entityType);
$sql = "DELETE FROM `{$table}`";
$entity = $this->entityFactory->create($entityType);
if (!$entity) return null;
$wherePart = $this->query->getWhere($entity, $whereClause);
if ($wherePart) {
$sql .= ' WHERE ' . $wherePart;
}
$sth = $this->pdo->prepare($sql);
if ($sth->execute()) {
return $sth->rowCount();
}
return null;
}
public function restoreDeleted(string $entityType, $id)
{
if (empty($entityType) || empty($id)) return false;
+1 -1
View File
@@ -44,7 +44,7 @@ class UniqueId extends \Espo\Core\ORM\Repositories\RDB
public function getNew() : ?Entity
{
$entity = parent::getNew();
$entity->set('name', \Espo\Core\Utils\Util::generateId());
$entity->set('name', \Espo\Core\Utils\Util::generateMoreEntropyId());
return $entity;
}
}
+1 -1
View File
@@ -52,7 +52,7 @@ class Webhook extends \Espo\Core\ORM\Repositories\RDB
protected function fillSecretKey(Entity $entity)
{
$secretKey = \Espo\Core\Utils\Util::generateKey();
$secretKey = \Espo\Core\Utils\Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
+4 -4
View File
@@ -245,7 +245,7 @@ class User extends Record
throw new Forbidden(json_encode(['reason' => 'Already-Sent']));
}
$requestId = Util::generateId() . Util::generateKey();
$requestId = Util::generateCryptId();
$passwordChangeRequest = $this->getEntityManager()->getEntity('PasswordChangeRequest');
$passwordChangeRequest->set([
@@ -411,7 +411,7 @@ class User extends Record
$entity->set('apiKey', $apiKey);
if ($entity->get('authMethod') === 'Hmac') {
$secretKey = \Espo\Core\Utils\Util::generateKey();
$secretKey = \Espo\Core\Utils\Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
@@ -508,7 +508,7 @@ class User extends Record
$entity->set('apiKey', $apiKey);
if ($entity->get('authMethod') === 'Hmac') {
$secretKey = \Espo\Core\Utils\Util::generateKey();
$secretKey = \Espo\Core\Utils\Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
}
@@ -559,7 +559,7 @@ class User extends Record
if ($entity->isApi()) {
if ($entity->isAttributeChanged('authMethod') && $entity->get('authMethod') === 'Hmac') {
$secretKey = \Espo\Core\Utils\Util::generateKey();
$secretKey = \Espo\Core\Utils\Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
}
+1 -1
View File
@@ -104,7 +104,7 @@ table.table {
.list-kanban > div > table > thead,
.list-group-panel,
.popup-notification {
.box-shadow(2px 2px 4px rgba(0,0,0,0.13));
.box-shadow(2px 2px 4px rgba(0,0,0,0.09));
}
.stick-sub.button-container {
+33
View File
@@ -302,4 +302,37 @@ class MapperTest extends \tests\integration\Core\BaseTestCase
$isRelated = $em->getRepository('Lead')->isRelated($l1, 'createdAccount', $a1);
$this->assertFalse($isRelated);
}
public function testMassDeleteFromDb1()
{
$app = $this->createApplication();
$em = $app->getContainer()->get('entityManager');
$mapper = $em->getMapper('RDB');
$a1 = $em->createEntity('Account', [
'name' => '1',
]);
$a2 = $em->createEntity('Account', [
'name' => '2',
]);
$count = $mapper->massDeleteFromDb('Account', [
'name' => '1',
]);
$this->assertEquals(1, $count);
$a1 = $em->getEntity('Account', $a1->id);
$this->assertNull($a1);
$a2 = $em->getEntity('Account', $a2->id);
$this->assertNotNull($a2);
$count = $mapper->massDeleteFromDb('Account', [
'name' => '3',
]);
$this->assertEquals(0, $count);
}
}
+28
View File
@@ -490,4 +490,32 @@ class DBMapperTest extends \PHPUnit\Framework\TestCase
));
}
public function testMassDeleteFromDb()
{
$query = "DELETE FROM `post` WHERE post.name = 'test' AND post.deleted = '1'";
$sth = $this->getMockBuilder('\\PDOStatement')->disableOriginalConstructor()->getMock();
$this->pdo
->expects($this->once())
->method('prepare')
->with($query)
->will($this->returnValue($sth));
$sth
->expects($this->once())
->method('execute')
->will($this->returnValue(true));
$sth
->expects($this->once())
->method('rowCount')
->will($this->returnValue(1));
$this->db->massDeleteFromDb('Post', [
'name' => 'test',
'deleted' => true,
]);
}
}