Skip to content

Commit

Permalink
Bugfix/3.3.2 : Various bug fixes (#1533)
Browse files Browse the repository at this point in the history
* DataSets data : Fix sorting issues
fixes xibosignage/xibo#2961

* Campaign : copy issues
fixes xibosignage/xibo#2963

* Layout grid : Fix Layout thumbnail for Layout with only subplaylist Widget
fixes xibosignage/xibo#2964

* Layout : Add permissions check on getLayoutCodes
fixes xibosignage/xibo#2968

* Notifications : fix email logic
fixes xibosignage/xibo#2973

* Layout import : Fix importing Layouts with subplaylist Widget from older CMS versions
fixes xibosignage/xibo#2972

* Ad Campaign builder form : Fix back button css
fixes xibosignage/xibo#2979
  • Loading branch information
PeterMis committed Jan 5, 2023
1 parent 29bd582 commit 0bcf081
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 40 deletions.
8 changes: 7 additions & 1 deletion lib/Controller/Campaign.php
Expand Up @@ -1313,7 +1313,7 @@ public function copy(Request $request, Response $response, $id)
$newCampaign->campaign = $sanitizedParams->getString('name');

// assign the same layouts to the new Campaign
foreach ($campaign->layouts as $layout) {
foreach ($campaign->loadLayouts() as $layout) {
$newCampaign->assignLayout(
$layout->layoutId,
$layout->displayOrder,
Expand All @@ -1323,6 +1323,12 @@ public function copy(Request $request, Response $response, $id)
);
}

// is the original campaign an ad campaign?
if ($campaign->type === 'ad') {
// assign the same displays to the new Campaign
$newCampaign->replaceDisplayGroupIds($campaign->loadDisplayGroupIds());
}

$newCampaign->save();

// Return
Expand Down
11 changes: 11 additions & 0 deletions lib/Controller/DataSetColumn.php
Expand Up @@ -369,6 +369,11 @@ public function add(Request $request, Response $response, $id)
// Assign the column to set the column order if necessary
$dataSet->assignColumn($column);

// client side formula disable sort
if (substr($column->formula, 0, 1) === '$') {
$column->showSort = 0;
}

// Save the column
$column->save();

Expand Down Expand Up @@ -569,6 +574,12 @@ public function edit(Request $request, Response $response, $id, $colId)
$column->tooltip = $sanitizedParams->getString('tooltip');
$column->isRequired = $sanitizedParams->getCheckbox('isRequired');
$column->dateFormat = $sanitizedParams->getString('dateFormat', ['default' => null]);

// client side formula disable sort
if (substr($column->formula, 0, 1) === '$') {
$column->showSort = 0;
}

$column->save();

if ($column->dataSetColumnTypeId == 3 && $column->hasPropertyChanged('remoteField')) {
Expand Down
3 changes: 2 additions & 1 deletion lib/Controller/Layout.php
Expand Up @@ -3013,7 +3013,8 @@ public function addThumbnail(Request $request, Response $response, $id): Respons
foreach ($layout->regions as $region) {
try {
// Get widgets in this region
$widgets = $region->regionPlaylist->expandWidgets();
$playlist = $region->getPlaylist()->setModuleFactory($this->moduleFactory);
$widgets = $playlist->expandWidgets();

if (count($widgets) <= 0) {
// Render the region (draw a grey box)
Expand Down
47 changes: 31 additions & 16 deletions lib/Entity/DataSet.php
Expand Up @@ -513,14 +513,12 @@ public function getData($filterBy = [], $options = [])
// Select (columns)
foreach ($this->getColumn() as $column) {
/* @var DataSetColumn $column */
$allowedOrderCols[] = $column->heading;

if ($column->dataSetColumnTypeId == 2 && !$options['includeFormulaColumns'])
if ($column->dataSetColumnTypeId == 2 && !$options['includeFormulaColumns']) {
continue;
}

// Formula column?
if ($column->dataSetColumnTypeId == 2) {

// Is this a client side column?
if (substr($column->formula, 0, 1) === '$') {
$clientSideFormula[] = $column;
Expand All @@ -531,11 +529,12 @@ public function getData($filterBy = [], $options = [])
$formula = str_replace('[DisplayId]', $displayId, $formula);

$heading = str_replace('[DisplayGeoLocation]', $displayGeoLocation, $formula) . ' AS `' . $column->heading . '`';
}
else {
} else {
$heading = '`' . $column->heading . '`';
}

$allowedOrderCols[] = $column->heading;

$body .= ', ' . $heading;
}

Expand All @@ -551,8 +550,7 @@ public function getData($filterBy = [], $options = [])
}

// Filter by ID
if (
$sanitizer->getInt('id') !== null) {
if ($sanitizer->getInt('id') !== null) {
$body .= ' AND id = :id ';
$params['id'] = $sanitizer->getInt('id');
}
Expand All @@ -570,25 +568,42 @@ public function getData($filterBy = [], $options = [])

// Check allowable
if (!in_array($sanitized, $allowedOrderCols)) {
$this->getLog()->info('Disallowed column: ' . $sanitized);
continue;
$found = false;
$this->getLog()->info('Potentially disallowed column: ' . $sanitized);
// the gridRenderSort will strip spaces on column names go through allowed order columns
// and see if we can find a match by stripping spaces from the heading
foreach ($allowedOrderCols as $allowedOrderCol) {
$this->getLog()->info('Checking spaces in original name : ' . $sanitized);
if (str_replace(' ', '', $allowedOrderCol) === $sanitized) {
$found = true;
// put the column heading with the space as sanitized to make sql happy.
$sanitized = $allowedOrderCol;
}
}

// we tried, but it was not found, omit this pair
if (!$found) {
continue;
}
}

// Substitute
if (strripos($orderPair, ' DESC')) {
$order .= sprintf(' `%s` DESC,', $sanitized);
}
else if (strripos($orderPair, ' ASC')) {
} else if (strripos($orderPair, ' ASC')) {
$order .= sprintf(' `%s` ASC,', $sanitized);
}
else {
} else {
$order .= sprintf(' `%s`,', $sanitized);
}
}

$order = trim($order, ',');
}
else {

// if after all that we still do not have any column name to order by, default to order by id
if (trim($order) === 'ORDER BY') {
$order = ' ORDER BY id ';
}
} else {
$order = ' ORDER BY id ';
}

Expand Down
63 changes: 60 additions & 3 deletions lib/Factory/LayoutFactory.php
@@ -1,6 +1,6 @@
<?php
/*
* Copyright (c) 2022 Xibo Signage Ltd
* Copyright (C) 2023 Xibo Signage Ltd
*
* Xibo - Digital Signage - http://www.xibo.org.uk
*
Expand Down Expand Up @@ -922,6 +922,19 @@ public function loadByJson($layoutJson, $playlistJson, $nestedPlaylistJson, Fold
//
$subPlaylistsOption = [];
foreach ($mediaNode['widgetOptions'] as $optionsNode) {
// subPlaylistOptions and subPlaylistIds are no longer in use from 2.3
// we need to capture these options to support Layout with sub-playlist import from older CMS
// we use continue for those 2 options, as we do not need to create widgetOption for them
if ($optionsNode['option'] == 'subPlaylistOptions') {
$oldSubPlaylistOptions = json_decode($optionsNode['value'], true);
continue;
}

if ($optionsNode['option'] == 'subPlaylistIds') {
$oldSubPlaylistIds = json_decode($optionsNode['value'], true);
continue;
}

if ($optionsNode['option'] == 'subPlaylists') {
$subPlaylistsOption = json_decode($optionsNode['value'], true);
}
Expand All @@ -939,6 +952,11 @@ public function loadByJson($layoutJson, $playlistJson, $nestedPlaylistJson, Fold
}
}

// convert old sub-playlist Widget options to the new way we handle them
if (isset($oldSubPlaylistIds) && isset($oldSubPlaylistOptions)) {
$subPlaylistsOption = $this->convertOldPlaylistOptions($oldSubPlaylistIds, $oldSubPlaylistOptions);
}

//
// Get the MediaId associated with this widget
//
Expand Down Expand Up @@ -1685,6 +1703,19 @@ public function createNestedPlaylistWidgets($widgets, $combined, &$playlists)

foreach ($widgetsDetail['widgetOptions'] as $widgetOptionE) {
if ($playlistWidget->type == 'subplaylist') {
// subPlaylistOptions and subPlaylistIds are no longer in use from 2.3
// we need to capture these options to support Layout with sub-playlist import from older CMS
// we use continue for those 2 options, as we do not need to create widgetOption for them
if ($widgetOptionE['option'] == 'subPlaylistOptions') {
$oldNestedSubPlaylistOptions = json_decode($widgetOptionE['value'], true);
continue;
}

if ($widgetOptionE['option'] == 'subPlaylistIds') {
$oldNestedSubPlaylistIds = json_decode($widgetOptionE['value'], true);
continue;
}

if ($widgetOptionE['option'] == 'subPlaylists') {
$nestedSubPlaylists = json_decode($widgetOptionE['value'], true);
}
Expand All @@ -1698,6 +1729,11 @@ public function createNestedPlaylistWidgets($widgets, $combined, &$playlists)
$playlistWidget->widgetOptions[] = $widgetOption;
}

// convert old sub-playlist Widget options to the new way we handle them
if (isset($oldNestedSubPlaylistIds) && isset($oldNestedSubPlaylistOptions)) {
$nestedSubPlaylists = $this->convertOldPlaylistOptions($oldNestedSubPlaylistIds, $oldNestedSubPlaylistOptions);
}

$module = $modules[$playlistWidget->type];

if ($playlistWidget->type == 'subplaylist') {
Expand Down Expand Up @@ -1751,15 +1787,18 @@ public function getLayoutCodes($filterBy = []): array
{
$parsedFilter = $this->getSanitizer($filterBy);
$params = [];
$select = 'SELECT DISTINCT code ';
$body = ' FROM layout WHERE code IS NOT NULL ';
$select = 'SELECT DISTINCT code, `campaign`.CampaignID, `campaign`.permissionsFolderId ';
$body = ' FROM layout INNER JOIN `lkcampaignlayout` ON lkcampaignlayout.LayoutID = layout.LayoutID INNER JOIN `campaign` ON lkcampaignlayout.CampaignID = campaign.CampaignID AND campaign.IsLayoutSpecific = 1 WHERE code IS NOT NULL';

// get by Code
if ($parsedFilter->getString('code') != '') {
$body.= ' AND layout.code LIKE :code ';
$params['code'] = '%' . $parsedFilter->getString('code') . '%';
}

// Logged in user view permissions
$this->viewPermissionSql('Xibo\Entity\Campaign', $body, $params, 'campaign.campaignId', 'layout.userId', $filterBy, 'campaign.permissionsFolderId');

$order = ' ORDER BY code';

// Paging
Expand Down Expand Up @@ -2623,5 +2662,23 @@ public function concurrentRequestRelease(Layout $layout, bool $force = false)
$this->getPool()->save($lock);
}

public function convertOldPlaylistOptions($playlistIds, $playlistOptions)
{
$convertedPlaylistOption = [];
$i = 0;
foreach ($playlistIds as $playlistId) {
$i++;
$convertedPlaylistOption[] = [
'rowNo' => $i,
'playlistId' => $playlistId,
'spotFill' => $playlistOptions[$playlistId]['subPlaylistIdSpotFill'] ?? null,
'spotLength' => $playlistOptions[$playlistId]['subPlaylistIdSpotLength'] ?? null,
'spots' => $playlistOptions[$playlistId]['subPlaylistIdSpots'] ?? null,
];
}

return $convertedPlaylistOption;
}

// </editor-fold>
}
33 changes: 18 additions & 15 deletions lib/XTR/EmailNotificationsTask.php
@@ -1,6 +1,6 @@
<?php
/*
* Copyright (C) 2022 Xibo Signage Ltd
* Copyright (C) 2023 Xibo Signage Ltd
*
* Xibo - Digital Signage - http://www.xibo.org.uk
*
Expand All @@ -20,10 +20,8 @@
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/


namespace Xibo\XTR;


use Carbon\Carbon;
use Slim\Views\Twig;
use Xibo\Factory\UserNotificationFactory;
Expand Down Expand Up @@ -68,6 +66,7 @@ private function processQueue()

$msgFrom = $this->config->getSetting('mail_from');
$msgFromName = $this->config->getSetting('mail_from_name');
$processedNotifications = [];

$this->log->debug('Notification Queue sending from ' . $msgFrom);

Expand All @@ -77,32 +76,35 @@ private function processQueue()
if (!empty($notification->email) || $notification->isSystem == 1) {
$mail = new \PHPMailer\PHPMailer\PHPMailer();

// System notifications, override the email address
$this->log->debug('Sending Notification email to ' . $notification->email);
$mail->addAddress($notification->email);

// System notifications, add mail_to to addresses if set.
if ($notification->isSystem == 1) {
// We should send the system notification to:
// - the system user
// - the mail_to (if different)
// - all assigned users
// - the mail_to (if set)
$mailTo = $this->config->getSetting('mail_to');

// We add this below.
$notification->email = $this->user->email ?? $mailTo;

// Make sure we've been able to resolve an address.
if (empty($notification->email)) {
if (empty($notification->email) && empty($mailTo)) {
$this->log->error('Discarding NotificationId ' . $notification->notificationId
. ' as no email address could be resolved.');
continue;
}

// Also add the mail_to
if ($mailTo !== $notification->email && !empty($mailTo)) {
// if mail_to is set and is different from user email, and we did not
// process this notification yet (the same notificationId will be returned for each assigned user)
// add it to addresses
if ($mailTo !== $notification->email
&& !empty($mailTo)
&& !in_array($notification->notificationId, $processedNotifications)
) {
$this->log->debug('Sending Notification email to mailTo ' . $mailTo);
$mail->addAddress($mailTo);
}
}

$this->log->debug('Sending Notification email to ' . $notification->email);
$mail->addAddress($notification->email);

// Email them
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
Expand Down Expand Up @@ -146,6 +148,7 @@ private function processQueue()
. ' as no email address could be resolved.');
}

$processedNotifications[] = $notification->notificationId;
// Mark as sent
$notification->setEmailed(Carbon::now()->format('U'));
$notification->save();
Expand Down
12 changes: 8 additions & 4 deletions ui/src/style/campaign-builder.scss
@@ -1,5 +1,5 @@
/*!
* Copyright (C) 2022 Xibo Signage Ltd
* Copyright (C) 2023 Xibo Signage Ltd
*
* Xibo - Digital Signage - http://www.xibo.org.uk
*
Expand All @@ -23,12 +23,16 @@
@import "mixins";
@import "header-center-logo";

#campaign-builder {
margin-top: -30px;
}

#campaign-builder {
// Put the back button at the top left.
.back-button {
position: fixed;
left: 16px;
top: 8px;
position: relative;
top: -12px;
left: 0;

span {
margin-left: 6px;
Expand Down

0 comments on commit 0bcf081

Please sign in to comment.