Skip to content

Commit

Permalink
Merge pull request #714 from xibosignage/release21
Browse files Browse the repository at this point in the history
Release 2.1.2
  • Loading branch information
dasgarner authored Oct 28, 2019
2 parents 91b9e8e + 8f6ac77 commit b2cd4ae
Show file tree
Hide file tree
Showing 66 changed files with 482 additions and 163 deletions.
42 changes: 30 additions & 12 deletions lib/Controller/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,22 +124,32 @@ function displayPage()
{
// We need to provide a list of displays
$displayGroupIds = $this->session->get('displayGroupIds');
$groups = array();
$displays = array();
$displayGroups = [];

foreach ($this->displayGroupFactory->query(null, ['isDisplaySpecific' => -1]) as $display) {
/* @var \Xibo\Entity\DisplayGroup $display */
if ($display->isDisplaySpecific == 1) {
$displays[] = $display;
} else {
$groups[] = $display;
// Boolean to check if the option show all was saved in session
$displayGroupsShowAll = false;

if (count($displayGroupIds) > 0) {
foreach ($displayGroupIds as $displayGroupId) {
if ($displayGroupId == -1) {
$displayGroupsShowAll = true;
continue;
}


$displayGroup = $this->displayGroupFactory->getById($displayGroupId);

if ($this->getUser()->checkViewable($displayGroup)) {
$displayGroups[] = $displayGroup;
}
}
}

$data = [
'selectedDisplayGroupIds' => $displayGroupIds,
'groups' => $groups,
'displays' => $displays
'optionGroups' => ['Group', 'Displays'],
'displayGroupIds' => $displayGroupIds,
'displayGroups' => $displayGroups,
'displayGroupsShowAll' => $displayGroupsShowAll
];

// Render the Theme and output
Expand Down Expand Up @@ -1044,8 +1054,9 @@ public function edit($eventId)
$schedule = $this->scheduleFactory->getById($eventId);
$schedule->load();

if (!$this->isEventEditable($schedule->displayGroups))
if (!$this->isEventEditable($schedule->displayGroups)) {
throw new AccessDeniedException();
}

$schedule->eventTypeId = $this->getSanitizer()->getInt('eventTypeId');
$schedule->campaignId = $this->getSanitizer()->getInt('campaignId');
Expand All @@ -1062,6 +1073,13 @@ public function edit($eventId)
$schedule->recurrenceMonthlyRepeatsOn = $this->getSanitizer()->getInt('recurrenceMonthlyRepeatsOn');
$schedule->displayGroups = [];

// if we are editing Layout/Campaign event that was set with Always daypart and change it to Command event type
// the daypartId will remain as always, which will then cause the event to "disappear" from calendar
// https://github.com/xibosignage/xibo/issues/1982
if ($schedule->eventTypeId == \Xibo\Entity\Schedule::$COMMAND_EVENT) {
$schedule->dayPartId = $this->dayPartFactory->getCustomDayPart()->dayPartId;
}

foreach ($this->getSanitizer()->getIntArray('displayGroupIds') as $displayGroupId) {
$schedule->assignDisplayGroup($this->displayGroupFactory->getById($displayGroupId));
}
Expand Down
22 changes: 16 additions & 6 deletions lib/Entity/Layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ public function toXlf()

// Keep track of whether this layout has an empty region
$layoutHasEmptyRegion = false;
$layoutCountRegionsWithMinDuration = 0;
$layoutCountRegionsWithDuration = 0;

$document = new \DOMDocument();
$layoutNode = $document->createElement('layout');
Expand Down Expand Up @@ -1043,6 +1043,13 @@ public function toXlf()
$layoutHasEmptyRegion = true;
}

// Work out if we have any "lead regions", those are Widgets with a duration
foreach ($widgets as $widget) {
if ($widget->useDuration == 1 || $countWidgets > 1 || $regionLoop == 1 || $widget->type == 'video') {
$layoutCountRegionsWithDuration++;
}
}

foreach ($widgets as $widget) {
/* @var Widget $widget */
$module = $this->moduleFactory->createWithWidget($widget, $region);
Expand All @@ -1064,12 +1071,15 @@ public function toXlf()
// the only time we want to override this, is if we want it set to the Minimum Duration for the XLF
$widgetDuration = $widget->calculatedDuration;

if ($widget->useDuration == 0 && $countWidgets <= 1 && $regionLoop == 0 && count($this->regions) > $layoutCountRegionsWithMinDuration + 1) {
// We have a widget without a specified duration in a region on its own and the region isn't set to
// loop.
// Reset to the minimum duration
// Is this Widget one that does not have a duration of its own?
// Assuming we have at least 1 region with a set duration, then we ought to
// Reset to the minimum duration
if ($widget->useDuration == 0 && $countWidgets <= 1 && $regionLoop == 0 && $widget->type != 'video'
&& $layoutCountRegionsWithDuration >= 1
) {
// Make sure this Widget expires immediately so that the other Regions can be the leaders when
// it comes to expiring the Layout
$widgetDuration = Widget::$widgetMinDuration;
$layoutCountRegionsWithMinDuration++;
}

// Region duration
Expand Down
7 changes: 7 additions & 0 deletions lib/Entity/Playlist.php
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,7 @@ public function updateDuration()
]);

$duration = 0;
$removedWidget = false;

// What is the next time we need to update this Playlist (0 is never)
$nextUpdate = 0;
Expand All @@ -839,6 +840,8 @@ public function updateDuration()
'forceNotifyPlaylists' => false,
'notifyDisplays' => false
]);

$removedWidget = true;
}

// Do not assess it
Expand Down Expand Up @@ -872,6 +875,10 @@ public function updateDuration()

$this->save(['saveTags' => false, 'saveWidgets' => false]);

if ($removedWidget) {
$this->notifyLayouts();
}

if ($delta !== 0) {
// Use the closure table to update all parent playlists (including this one).
$this->getStore()->update('
Expand Down
10 changes: 6 additions & 4 deletions lib/Entity/Region.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,15 @@ public function setOptionValue($option, $value)
}

/**
* @param array $options
* @return Playlist
* @throws NotFoundException
*/
public function getPlaylist()
public function getPlaylist($options = [])
{
if ($this->regionPlaylist === null)
$this->regionPlaylist = $this->playlistFactory->getByRegionId($this->regionId)->load();
if ($this->regionPlaylist === null) {
$this->regionPlaylist = $this->playlistFactory->getByRegionId($this->regionId)->load($options);
}

return $this->regionPlaylist;
}
Expand Down Expand Up @@ -336,7 +338,7 @@ public function load($options = [])

// Load the Playlist?
if ($options['loadPlaylists']) {
$this->getPlaylist();
$this->getPlaylist($options);
}

$this->hash = $this->hash();
Expand Down
42 changes: 41 additions & 1 deletion lib/Entity/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,37 @@ public function validate()
// Check recurrenceDetail every is positive
if ($this->recurrenceType != '' && ($this->recurrenceDetail === null || $this->recurrenceDetail <= 0))
throw new InvalidArgumentException(__('Repeat every must be a positive number'), 'recurrenceDetail');

// Check and disallow Minute/Hourly repeats to be indefinite (or too long)
$twelveHoursInSeconds = 12 * 60 * 60;
$oneWeekInSeconds = 24 * 7 * 60 * 60;
if($this->recurrenceType == 'Minute') {

if (empty($this->recurrenceRange)) {
throw new InvalidArgumentException(__(' An end time is needed for an event that has its repeating interval set to Minute.'), 'recurrenceRange');
}

$distance = ($this->getDate()->parse($this->recurrenceRange, 'U')->diffInSeconds($this->getDate()->parse($this->fromDt, 'U'))) / $this->recurrenceDetail;

if ($distance > $twelveHoursInSeconds) {
// Recurrence range cannot be more than 12 hours
$exceedLimit = $this->getDate()->parse($this->fromDt, 'U')->addSeconds($twelveHoursInSeconds * $this->recurrenceDetail );
throw new InvalidArgumentException(sprintf(__('The end time for this event can only be %s in the future because of the repeating interval being Minute.', $exceedLimit->format('Y-m-d H:i:s'))), 'recurrenceRange');
}

} elseif ($this->recurrenceType == 'Hour') {

if (empty($this->recurrenceRange)) {
throw new InvalidArgumentException(__(' An end time is needed for an event that has its repeating interval set to Hour'), 'recurrenceRange');
}
$distance = ($this->getDate()->parse($this->recurrenceRange, 'U')->diffInSeconds($this->getDate()->parse($this->fromDt, 'U'))) / $this->recurrenceDetail;

if ($distance > $oneWeekInSeconds) {
// Recurrence range cannot be more than 1 week
$exceedLimit = $this->getDate()->parse($this->fromDt, 'U')->addSeconds($oneWeekInSeconds * $this->recurrenceDetail );
throw new InvalidArgumentException(sprintf(__('The end time for this event can only be %s in the future because of the repeating interval being Hour.', $exceedLimit->format('Y-m-d H:i:s'))), 'recurrenceRange');
}
}
}

/**
Expand Down Expand Up @@ -713,6 +744,10 @@ public function getEvents($fromDt, $toDt)
// Request month cache
while ($fromDt < $toDt) {

// Empty scheduleEvents as we are looping thorugh each month
// we dont want to save previous month events
$this->scheduleEvents = [];

// Events for the month.
$this->generateMonth($fromDt, $eventStart, $eventEnd);

Expand Down Expand Up @@ -810,6 +845,11 @@ private function generateMonth($generateFromDt, $start, $end)
/** @var Date $start */
$start = $lastWatermark->copy();
$end = $start->copy()->addSeconds($eventDuration);

if ($start <= $generateToDt && $end >= $generateFromDt) {
$this->addDetail($start->format('U'), $end->format('U'));
$this->getLog()->debug('The event start/end is inside the month' );
}
}

// range should be the smallest of the recurrence range and the generate window todt
Expand Down Expand Up @@ -967,7 +1007,7 @@ private function generateMonth($generateFromDt, $start, $end)
if ($this->recurrenceType == 'Week' && !empty($this->recurrenceRepeatsOn))
continue;

if ($start >= $generateFromDt) {
if ($start <= $generateToDt && $end >= $generateFromDt) {
if ($this->eventTypeId == self::$COMMAND_EVENT)
$this->addDetail($start->format('U'), null);
else {
Expand Down
18 changes: 14 additions & 4 deletions lib/Factory/BandwidthFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ public function createAndSave($type, $displayId, $size)
* Is the bandwidth limit exceeded
* @param string $limit the bandwidth limit to check against
* @param int $usage
* @param null $displayId
* @return bool
*/
public function isBandwidthExceeded($limit, &$usage = 0)
public function isBandwidthExceeded($limit, &$usage = 0, $displayId = null)
{
if ($limit <= 0) {
return false;
Expand All @@ -74,10 +75,19 @@ public function isBandwidthExceeded($limit, &$usage = 0)
$dbh = $this->getStore()->getConnection();

// Test bandwidth for the current month
$sth = $dbh->prepare('SELECT IFNULL(SUM(Size), 0) AS BandwidthUsage FROM `bandwidth` WHERE `Month` = :month');
$sth->execute(array(
$sql = 'SELECT IFNULL(SUM(Size), 0) AS BandwidthUsage FROM `bandwidth` WHERE `Month` = :month';
$params = [
'month' => strtotime(date('m') . '/02/' . date('Y') . ' 00:00:00')
));
];

// if we are testing the bandwidth usage for specific display, add the information to the query
if ($displayId != null) {
$sql .= ' AND `displayId` = :displayId';
$params['displayId'] = $displayId;
}

$sth = $dbh->prepare($sql);
$sth->execute($params);

$usage = $sth->fetchColumn(0);

Expand Down
27 changes: 23 additions & 4 deletions lib/Factory/LayoutFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -1344,18 +1344,37 @@ public function query($sortOrder = null, $filterBy = [])
}

// Show All, Used or UnUsed
// Used - In active schedule, scheduled in the future, directly assigned to displayGroup, default Layout.
// Unused - Every layout NOT matching the Used ie not in active schedule, not scheduled in the future, not directly assigned to any displayGroup, not default layout.
if ($this->getSanitizer()->getInt('filterLayoutStatusId', 1, $filterBy) != 1) {
if ($this->getSanitizer()->getInt('filterLayoutStatusId', $filterBy) == 2) {

// Only show used layouts
$now = $this->getDate()->parse()->format('U');
$sql = 'SELECT DISTINCT schedule.CampaignID FROM schedule WHERE ( ( schedule.fromDt < '. $now . ' OR schedule.fromDt = 0 ) ' . ' AND schedule.toDt > ' . $now . ') OR schedule.fromDt > ' . $now;
$campaignIds = [];
foreach ($this->getStore()->select($sql, []) as $row) {
$campaignIds[] = $row['CampaignID'];
}
$body .= ' AND ('
. ' campaign.CampaignID IN (SELECT DISTINCT schedule.CampaignID FROM schedule) '
. ' OR layout.layoutID IN (SELECT DISTINCT defaultlayoutid FROM display) '
. ' campaign.CampaignID IN ( ' . implode(',', array_filter($campaignIds)) . ' )
OR layout.layoutID IN (SELECT DISTINCT defaultlayoutid FROM display)
OR layout.layoutID IN (SELECT DISTINCT layoutId FROM lklayoutdisplaygroup)'
. ' ) ';
}
else {
// Only show unused layouts
$body .= ' AND campaign.CampaignID NOT IN (SELECT DISTINCT schedule.CampaignID FROM schedule) '
. ' AND layout.layoutID NOT IN (SELECT DISTINCT defaultlayoutid FROM display) ';
$now = $this->getDate()->parse()->format('U');
$sql = 'SELECT DISTINCT schedule.CampaignID FROM schedule WHERE ( ( schedule.fromDt < '. $now . ' OR schedule.fromDt = 0 ) ' . ' AND schedule.toDt > ' . $now . ') OR schedule.fromDt > ' . $now;
$campaignIds = [];
foreach ($this->getStore()->select($sql, []) as $row) {
$campaignIds[] = $row['CampaignID'];
}

$body .= ' AND campaign.CampaignID NOT IN ( ' . implode(',', array_filter($campaignIds)) . ' )
AND layout.layoutID NOT IN (SELECT DISTINCT defaultlayoutid FROM display)
AND layout.layoutID NOT IN (SELECT DISTINCT layoutId FROM lklayoutdisplaygroup)
';
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Factory/PlaylistFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function getById($playlistId)
*/
public function getByOwnerId($ownerId)
{
return $this->query(null, array('userId' => $ownerId));
return $this->query(null, ['userId' => $ownerId, 'regionSpecific' => 0]);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/Helper/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
class Environment
{
public static $WEBSITE_VERSION_NAME = '2.1.1';
public static $WEBSITE_VERSION_NAME = '2.1.2';
public static $XMDS_VERSION = '5';
public static $XLF_VERSION = '2';
public static $VERSION_REQUIRED = '5.5';
Expand Down
8 changes: 6 additions & 2 deletions lib/Helper/XiboUploadHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ protected function handle_form_data($file, $index)
$widget->unassignMedia($oldMedia->mediaId);
$widget->assignMedia($media->mediaId);

// calculate duration
$module->setWidget($widget);
$widget->calculateDuration($module);

// Raise an event for this media item
$controller->getDispatcher()->dispatch(LibraryReplaceWidgetEvent::$NAME, new LibraryReplaceWidgetEvent($module, $widget, $media, $oldMedia));

Expand Down Expand Up @@ -335,10 +339,10 @@ protected function handle_form_data($file, $index)

// Set default options (this sets options on the widget)
$module->setDefaultWidgetOptions();
// Calculate the widget duration for new uploaded media widgets
$widget->calculateDuration($module);
// Assign media
$widget->assignMedia($media->mediaId);
// Calculate the widget duration for new uploaded media widgets
$widget->calculateDuration($module);

// Assign the new widget to the playlist
$playlist->assignWidget($widget);
Expand Down
4 changes: 2 additions & 2 deletions lib/Report/ProofOfPlay.php
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ private function getProofOfPlayReportMySql($fromDt, $toDt, $displayIds, $layoutI
{

$fromDt = $fromDt->format('U');
$toDt = $toDt->startOfDay()->addDay()->format('U'); // added a day
$toDt = $toDt->format('U');

// Media on Layouts Ran
$select = '
Expand Down Expand Up @@ -851,7 +851,7 @@ private function getProofOfPlayReportMongoDb($fromDt, $toDt, $displayIds, $layou
{

$fromDt = new UTCDateTime($fromDt->format('U')*1000);
$toDt = new UTCDateTime($toDt->addDay()->format('U')*1000);
$toDt = new UTCDateTime($toDt->format('U')*1000);

// Filters the documents to pass only the documents that
// match the specified condition(s) to the next pipeline stage.
Expand Down
Loading

0 comments on commit b2cd4ae

Please sign in to comment.