#! /usr/bin/perl -w use warnings "all"; use strict; use Data::Dumper; use URI::Escape; use Encode; use utf8; use params; use config; use log; use template; use calendar; use auth; use uac; use roles; use project; use studios; use events; use series; use markup; use series_dates; use studio_timeslot_dates; use work_dates; use playout; use markup; use user_settings; use localization; use DateTime; binmode STDOUT, ":utf8"; my $r = shift; ( my $cgi, my $params, my $error ) = params::get($r); my $config = config::get('../config/config.cgi'); my $debug = $config->{system}->{debug}; my ( $user, $expires ) = auth::get_user( $cgi, $config ); return if ( ( !defined $user ) || ( $user eq '' ) ); my $user_presets = uac::get_user_presets( $config, { user => $user, project_id => $params->{project_id}, studio_id => $params->{studio_id} } ); $params->{default_studio_id} = $user_presets->{studio_id}; $params->{project_id} = $user_presets->{project_id} if ( ( !( defined $params->{action} ) ) || ( $params->{action} eq '' ) || ( $params->{action} eq 'login' ) ); $params->{expires} = $expires; #print STDERR Dumper($params); my $scriptName = 'calendar.cgi'; #add "all" studio to select box unshift @{ $user_presets->{studios} }, { id => -1, name => '-all-' }; # select studios, TODO: do in JS if ( $params->{studio_id} eq '-1' ) { for my $studio ( @{ $user_presets->{studios} } ) { delete $studio->{selected}; $studio->{selected} = 1 if $params->{studio_id} eq $studio->{id}; } } my $request = { url => $ENV{QUERY_STRING} || '', params => { original => $params, checked => check_params( $params, $config ), }, }; $request = uac::prepare_request( $request, $user_presets ); log::init($request); $params = $request->{params}->{checked}; #print STDERR Dumper($request); if ( ( ( defined $params->{action} ) && ( ( $params->{action} eq 'show' ) || ( $params->{action} eq 'edit_event' ) ) ) || ( $params->{part} == 1 ) ) { print "Content-type:text/html; charset=UTF-8;\n\n"; } else { #process header my $headerParams = uac::set_template_permissions( $request->{permissions}, $params ); $headerParams->{loc} = localization::get( $config, { user => $user, file => 'menu' } ); template::process( 'print', template::check('default.html'), $headerParams ); print q{ }; if ( $params->{list} eq '1' ) { print q{ }; } } if ( defined $user_presets->{error} ) { print "

"; uac::print_error( $user_presets->{error} ); return; } $config->{access}->{write} = 0; unless ( defined $params->{project_id} ) { uac::print_error("Please select a project"); return; } if ( $params->{project_id} ne '-1' ) { if ( project::check( $config, { project_id => $params->{project_id} } ) ne '1' ) { uac::print_error("invalid project"); return; } } unless ( defined $params->{studio_id} ) { uac::print_error("Please select a studio"); return; } if ( $params->{studio_id} ne '-1' ) { if ( studios::check( $config, { studio_id => $params->{studio_id} } ) ne '1' ) { uac::print_error("invalid studio"); return; } } my $start_of_day = $params->{day_start}; my $end_of_day = $start_of_day; $end_of_day += 24 if ( $end_of_day <= $start_of_day ); our $hour_height = 60; our $yzoom = 1.5; showCalendar( $config, $request, { hour_height => $hour_height, yzoom => $yzoom, start_of_day => $start_of_day, end_of_day => $end_of_day, } ); sub showCalendar { my $config = shift; my $request = shift; my $cal_options = shift; my $hour_height = $cal_options->{hour_height}; my $yzoom = $cal_options->{yzoom}; my $start_of_day = $cal_options->{start_of_day}; my $end_of_day = $cal_options->{end_of_day}; my $params = $request->{params}->{checked}; my $permissions = $request->{permissions}; unless ( $permissions->{read_series} == 1 ) { uac::permissions_denied('read_series'); return; } #get range from user settings my $user_settings = user_settings::get( $config, { user => $params->{presets}->{user} } ); $params->{range} = $user_settings->{range} unless defined $params->{range}; $params->{range} = 28 unless defined $params->{range}; #get colors from user settings print user_settings::getColorCss( $config, { user => $params->{presets}->{user} } ) if $params->{part} == 0; $params->{loc} = localization::get( $config, { user => $params->{presets}->{user}, file => 'all,calendar' } ); my $language = $user_settings->{language} || 'en'; $params->{language} = $language; print localization::getJavascript( $params->{loc} ) if $params->{part} == 0; my $calendar = getCalendar( $config, $params, $language ); my $options = {}; my $events = []; if ( ( $params->{part} == 1 ) || ( $params->{list} == 1 ) ) { #set date range my $from = $calendar->{from_date}; my $till = $calendar->{till_date}; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; #build event filter $options = { project_id => $project_id, template => 'no', limit => 600, get => 'no_content', from_date => $from, till_date => $till, date_range_include => 1, archive => 'all', }; # set options depending on switches if ( $params->{studio_id} ne '-1' ) { $options->{studio_id} = $studio_id; my $location = $params->{presets}->{studio}->{location}; $options->{location} = $location if $location =~ /\S/; } if ( $params->{project_id} ne '-1' ) { $options->{project_id} = $project_id; my $project = $params->{presets}->{project}->{name}; $options->{project} = $project if $project =~ /\S/; } if ( defined $params->{series_id} ) { $options->{series_id} = $params->{series_id}; delete $options->{from_date}; delete $options->{till_date}; delete $options->{date_range_include}; } if ( $params->{search} =~ /\S/ ) { $options->{search} = $params->{search}; delete $options->{from_date} if ( $params->{list} == 1 ); delete $options->{till_date} if ( $params->{list} == 1 ); delete $options->{date_range_include} if ( $params->{list} == 1 ); } $options->{draft}=0 unless $params->{list}==1; #get events sorted by date $events = getSeriesEvents( $config, $request, $options, $params ); unless ( $params->{list} == 1 ) { for my $event (@$events) { $event->{origStart} = $event->{start}; } $events = break_dates( $events, $start_of_day ); } # recalc after break (for list only?) for my $event (@$events) { #if ($event->{splitCount}>0){ delete $event->{day}; delete $event->{start_date}; delete $event->{end_date}; $event = events::calc_dates( $config, $event ); #} } my $events_by_start = {}; for my $event (@$events) { $events_by_start->{ $event->{start} } = $event; } #build series filter $options = { project_id => $project_id, studio_id => $studio_id, from => $from, till => $till, date_range_include => 1, exclude => 0 }; if ( defined $params->{series_id} ) { $options->{series_id} = $params->{series_id}; delete $options->{from}; delete $options->{till}; delete $options->{date_range_include}; } if ( $params->{search} =~ /\S/ ) { $options->{search} = $params->{search}; delete $options->{from} if ( $params->{list} == 1 ); delete $options->{till} if ( $params->{list} == 1 ); delete $options->{date_range_include} if ( $params->{list} == 1 ); } #get all series dates my $series_dates = series_dates::get_series( $config, $options ); my $id = 0; for my $date (@$series_dates) { $date->{schedule} = 1; #$date->{event_id}=-1; $date->{event_id} = $id; $date->{origStart} = $date->{start}; delete $date->{day}; delete $date->{start_date}; delete $date->{end_date}; $id++; } unless ( $params->{list} == 1 ) { $series_dates = break_dates( $series_dates, $start_of_day ); } #merge series and events for my $date (@$series_dates) { $date = events::calc_dates( $config, $date ); push @$events, $date; } #get timeslot_dates my $studio_dates = studio_timeslot_dates::get( $config, $options ); #print STDERR Dumper($options); $id = 0; for my $date (@$studio_dates) { $date->{grid} = 1; $date->{series_id} = -1; #$date->{event_id}=-1; $date->{event_id} = $id; $date->{origStart} = $date->{start}; delete $date->{day}; delete $date->{start_date}; delete $date->{end_date}; $id++; } unless ( $params->{list} == 1 ) { $studio_dates = break_dates( $studio_dates, $start_of_day ); } for my $date (@$studio_dates) { $date = events::calc_dates( $config, $date ); push @$events, $date; } #get work_dates my $work_dates = work_dates::get( $config, $options ); for my $date (@$work_dates) { $date->{work} = 1; $date->{series_id} = -1; $date->{event_id} = -1; $date->{origStart} = $date->{start}; delete $date->{day}; delete $date->{start_date}; delete $date->{end_date}; } unless ( $params->{list} == 1 ) { $work_dates = break_dates( $work_dates, $start_of_day ); } for my $date (@$work_dates) { $date = events::calc_dates( $config, $date ); push @$events, $date; } #get playout delete $options->{exclude}; my $playout_dates = playout::get( $config, $options ); $id = 0; for my $date (@$playout_dates) { my $format = undef; if ( defined $date->{'format'} ) { $format = ( $date->{'format'} || '' ) . " " . ( $date->{'format_version'} || '' ) . " " . ( $date->{'format_profile'} || '' ); $format =~ s/MPEG Audio Version 1 Layer 3/MP3/g; $format .= ' ' . ( $date->{'format_settings'} || '' ) if defined $date->{'format_settings'}; $format .= '
'; } #print STDERR Dumper($date); $date->{play} = 1; $date->{series_id} = -1; $date->{event_id} = $id; $date->{title} = ''; $date->{title} .= 'errors: ' . $date->{errors} . '
' if defined $date->{errors}; $date->{title} .= formatDuration( $date->{duration} ) . "s
" if defined $date->{duration}; $date->{title} .= formatLoudness( "L:", $date->{rms_left} ) . ' dB, ' if defined $date->{rms_left}; $date->{title} .= formatLoudness( "R:", $date->{rms_right} ) . ' dB
' if defined $date->{rms_right}; $date->{title} .= formatBitrate( $date->{bitrate} ) . ' ' . $date->{bitrate_mode} . '
' if defined $date->{bitrate}; $date->{title} .= 'replay gain ' . sprintf( "%.1f", $date->{replay_gain} ) . '
' if defined $date->{replay_gain}; $date->{title} .= ( ( $date->{sampling_rate} || '0' ) / 1000 ) . ' kHz
' if defined $date->{sampling_rate}; $date->{title} .= ( $date->{channels} || '' ) . ' channels
' if defined $date->{channels}; $date->{title} .= int( ( $date->{'stream_size'} || '0' ) / ( 1024 * 1024 ) ) . 'MB
' if defined $date->{'stream_size'}; $date->{title} .= $format if defined $format; $date->{title} .= 'library: ' . ( $date->{writing_library} || '' ) . '
' if defined $date->{'writing_library'}; $date->{title} .= 'path: ' . ( $date->{file} || '' ) . '
' if defined $date->{file}; #$date->{title}.= 'rms_image: ' .($date->{rms_image}||'').'
' if defined $date->{rms_image}; $date->{rms_image} = uri_unescape( $date->{rms_image} ) if defined $date->{rms_image}; $date->{origStart} = $date->{start}; # set end date seconds to 00 to handle error at break_dates/join_dates $date->{end} =~ s/(\d\d\:\d\d)\:\d\d/$1\:00/; delete $date->{day}; delete $date->{start_date}; delete $date->{end_date}; $id++; } unless ( $params->{list} == 1 ) { $playout_dates = break_dates( $playout_dates, $start_of_day ); } for my $date (@$playout_dates) { $date = events::calc_dates( $config, $date ); if ( defined $events_by_start->{ $date->{start} } ) { $events_by_start->{ $date->{start} }->{duration} = $date->{duration} || 0; $events_by_start->{ $date->{start} }->{rms_left} = $date->{rms_left} || 0; $events_by_start->{ $date->{start} }->{rms_right} = $date->{rms_right} || 0; } push @$events, $date; } } #output printToolbar( $config, $params, $calendar ) if $params->{part} == 0; #if($params->{part}==1){ print qq{ }; #} #filter events by time unless ( $params->{list} == 1 ) { $events = filterEvents( $events, $options, $start_of_day ); } #sort events by start @$events = sort { $a->{start} cmp $b->{start} } @$events; #for my $date(@$events){debugDate($date);} #separate by day (e.g. to 6 pm) my $events_by_day = {}; for my $event (@$events) { my $day = time::datetime_to_date( time::add_hours_to_datetime( $event->{start}, -$start_of_day ) ); push @{ $events_by_day->{$day} }, $event; } #get min and max hour from all events unless ( $params->{list} == 1 ) { my $min_hour = 48; my $max_hour = 0; for my $event (@$events) { if ( $event->{start} =~ /(\d\d)\:\d\d\:\d\d$/ ) { my $hour = $1; $hour += 24 if $hour < $start_of_day; $min_hour = $hour if ( ( $hour < $min_hour ) && ( $hour >= $start_of_day ) ); } if ( $event->{end} =~ /(\d\d)\:\d\d\:\d\d$/ ) { my $hour = $1; $hour += 24 if $hour <= $start_of_day; $max_hour = $hour if ( ( $hour > $max_hour ) && ( $hour <= $end_of_day ) ); } } $cal_options->{min_hour} = $min_hour; $cal_options->{max_hour} = $max_hour; } #print STDERR $start_of_day." ".$cal_options->{min_hour}."\n"; # calculate positions and find schedule errors (depending on position) for my $date ( sort ( keys %$events_by_day ) ) { for my $events ( $events_by_day->{$date} ) { calc_positions( $events, $cal_options ); find_errors($events); } } if ( $params->{list} == 1 ) { showEventList( $config, $permissions, $params, $events_by_day ); } else { if ( $params->{part} == 0 ) { print qq{
}; } if ( $params->{part} == 1 ) { calcCalendarTable( $config, $permissions, $params, $calendar, $events_by_day, $cal_options ); printTableHeader( $config, $permissions, $params, $cal_options ); printTableBody( $config, $permissions, $params, $cal_options ); } if ( $params->{part} == 0 ) { printSeries( $config, $permissions, $params, $cal_options ); print qq{ }; } # time has to be set when events come in printJavascript( $config, $permissions, $params, $cal_options ); if ( $params->{part} == 0 ) { print qq{ }; } if ( $params->{part} == 1 ) { } } } sub formatLoudness { my $label = shift; my $value = shift; return '' unless defined $value; return '' if $value == 0; return '' if $value eq ''; #print STDERR "'$value'\n"; $value = sprintf( "%.1f", $value ); my $class = 'ok'; $class = 'warn' if $value > -18.5; $class = 'error' if $value > -16.0; $class = 'warn' if $value < -24.0; $class = 'error' if $value < -27.0; return qq{$label} . $value . qq{}; } sub formatDuration { my $duration = shift; return '' unless defined $duration; return '' if $duration eq ''; my $result = int( ( $duration + 3600 ) * 10 + 0.5) % 600; my $class = "ok"; $class = "warn" if $result > 1; $class = "error" if $result > 10; return sprintf( qq{%.01f}, $class, $duration ); } sub formatBitrate { my $bitrate = shift; return '' if $bitrate eq ''; if ( $bitrate >= 200 ) { return qq{$bitrate}; } elsif ( $bitrate < 190 ) { return qq{$bitrate}; } else { return qq{$bitrate}; } } sub debugDate { my $date = shift; $date->{program} = '' unless defined $date->{program}; $date->{series_name} = '' unless defined $date->{series_name}; $date->{title} = '' unless defined $date->{title}; $date->{splitCount} = 0 unless defined $date->{splitCount}; my $dt = ( $date->{start} || '' ) . " " . ( $date->{end} | '' ); my $da = ( $date->{start_date} || '' ) . " " . ( $date->{end_date} || '' ); my $type = "schedule:" . ( $date->{schedule} || "" ) . " grid:" . ( $date->{grid} || "" ); #print STDERR "$dt $da count:$date->{splitCount} $type $date->{program}-$date->{series_name}-$date->{title}\n"; } # break dates at start_of_day sub break_dates { my $dates = shift; my $start_of_day = shift; #return $dates if $start_of_day eq '0'; for my $date (@$dates) { next unless defined $date; $date->{splitCount} = 0 unless defined $date->{splitCount}; #debugDate($date); next if $date->{splitCount} > 6; my $nextDayStart = breaks_day( $date->{start}, $date->{end}, $start_of_day ); next if $nextDayStart eq '0'; # add new entry my $entry = {}; for my $key ( keys %$date ) { $entry->{$key} = $date->{$key}; } $entry->{start} = $nextDayStart; $entry->{splitCount}++; push @$dates, $entry; # print STDERR "add $entry->{start} $entry->{end} count:$entry->{splitCount} $entry->{program}-$entry->{series_name}-$entry->{title}\n"; #modify existing entry my $start_date = time::datetime_to_date( $date->{start} ); $date->{end} = $nextDayStart; $date->{splitCount}++; # print STDERR "set $date->{start} $date->{end} count:$date->{splitCount} $date->{program}-$date->{series_name}-$date->{title}\n"; } return join_dates( $dates, $start_of_day ); } # check if event breaks the start of day (e.g. 06:00) sub breaks_day { my $start = shift; my $end = shift; my $start_of_day = shift; my $starts = time::datetime_to_array($start); my $startDate = time::array_to_date($starts); my $startTime = time::array_to_time($starts); $start = $startDate . ' ' . $startTime; my $ends = time::datetime_to_array($end); my $endDate = time::array_to_date($ends); my $endTime = time::array_to_time($ends); $end = $endDate . ' ' . $endTime; my $dayStartTime = time::array_to_time($start_of_day); my $dayStart = $startDate . ' ' . $dayStartTime; # start before 6:00 of same day return $dayStart if ( $start lt $dayStart ) && ( $end gt $dayStart ); # start before 6:00 of next day my $nextDayStart = time::add_days_to_datetime( $dayStart, 1 ); #$nextDayStart=~s/:00$//; return $nextDayStart if ( $start lt $nextDayStart ) && ( $end gt $nextDayStart ); return 0; } # merge events with same seriesId and eventId at 00:00 sub join_dates { my $dates = shift; my $start_of_day = shift; return $dates if $start_of_day == 0; @$dates = sort { $a->{start} cmp $b->{start} } @$dates; my $prev_date = undef; for my $date (@$dates) { next unless defined $date; unless ( defined $prev_date ) { $prev_date = $date; next; } if ( ( $date->{event_id} == $prev_date->{event_id} ) && ( $date->{series_id} == $prev_date->{series_id} ) && ( $date->{start} eq $prev_date->{end} ) && ( $date->{start} =~ /00\:00\:\d\d/ ) ) { $prev_date->{end} = $date->{end}; $date = undef; next; } $prev_date = $date; } my $results = []; for my $date (@$dates) { next unless defined $date; push @$results, $date; } return $results; } sub filterEvents { my $events = shift; my $options = shift; my $start_of_day = shift; return [] unless defined $options->{from}; return [] unless defined $options->{till}; my $dayStartTime = time::array_to_time($start_of_day); my $startDatetime = $options->{from} . ' ' . $dayStartTime; my $endDatetime = $options->{till} . ' ' . $dayStartTime; my $results = []; for my $date (@$events) { next if ( ( $date->{start} ge $endDatetime ) || ( $date->{end} le $startDatetime ) ); push @$results, $date; } return $results; } sub showEventList { my $config = shift; my $permissions = shift; my $params = shift; my $events_by_day = shift; my $language = $params->{language}; print qq{
} if $params->{part} == 0; my $i = 1; my $scheduled_events = {}; for my $date ( reverse sort ( keys %$events_by_day ) ) { for my $event ( reverse @{ $events_by_day->{$date} } ) { next unless defined $event; next if defined $event->{grid}; next if defined $event->{work}; next if defined $event->{play}; #schedules with matching date are marked to be hidden in find_errors next if defined $event->{hide}; $event->{project_id} = $params->{project_id}; $event->{studio_id} = $params->{studio_id}; $event->{series_id} = '-1' unless defined $event->{series_id}; $event->{event_id} = '-1' unless defined $event->{event_id}; my $id = 'event_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{series_id} . '_' . $event->{event_id}; my $class = 'event'; $class = $event->{class} if defined $event->{class}; $class = 'schedule' if defined $event->{schedule}; if ( $class =~ /(event|schedule)/ ) { $class .= ' scheduled' if defined $event->{scheduled}; $class .= ' error' if defined $event->{error}; $class .= ' no_series' if ( ( $class eq 'event' ) && ( $event->{series_id} eq '-1' ) ); for my $filter ( 'rerun', 'archived', 'playout', 'published', 'live', 'disable_event_sync', 'draft' ) { $class .= ' ' . $filter if ( ( defined $event->{$filter} ) && ( $event->{$filter} eq '1' ) ); } $class .= ' preproduced' unless ( ( defined $event->{'live'} ) && ( $event->{'live'} eq '1' ) ); $class .= ' no_playout' unless ( ( defined $event->{'playout'} ) && ( $event->{'playout'} eq '1' ) ); $class .= ' no_rerun' unless ( ( defined $event->{'rerun'} ) && ( $event->{'rerun'} eq '1' ) ); } $event->{start} ||= ''; $event->{weekday_short_name} ||= ''; $event->{start_date_name} ||= ''; $event->{start_time_name} ||= ''; $event->{end_time} ||= ''; $event->{series_name} ||= ''; $event->{title} ||= ''; $event->{user_title} ||= ''; $event->{episode} ||= ''; $event->{rerun} ||= ''; $event->{draft} ||= ''; $id ||= ''; $class ||= ''; my $archived = $event->{archived} || '-'; $archived = '-' if $archived eq '0'; $archived = 'x' if $archived eq '1'; my $live = $event->{live} || '-'; $live = '-' if $live eq '0'; $live = 'x' if $live eq '1'; my $rerun = $event->{rerun} || '-'; #$rerun='-' if $rerun eq '0'; #$rerun='x' if $rerun eq '1'; $rerun = " [" . markup::base26( $event->{recurrence_count} + 1 ) . "]" if ( defined $event->{recurrence_count} ) && ( $event->{recurrence_count} ne '' ) && ( $event->{recurrence_count} > 0 ); my $draft = $event->{draft} || '0'; $draft='-' if $draft eq '0'; $draft='x' if $draft eq '1'; my $title = $event->{title}; $title .= ': ' . $event->{user_title} if $event->{user_title} ne ''; print qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . qq!! . "\n"; } $i++; } print qq{
$params->{loc}->{label_day_of_year} $params->{loc}->{label_weekday} $params->{loc}->{label_start} $params->{loc}->{label_end} $params->{loc}->{label_series} $params->{loc}->{label_title} $params->{loc}->{label_episode}
! . time::dayOfYear( $event->{start} ) . q!$event->{weekday_short_name},$event->{start_date_name}$event->{start_time_name} - $event->{end_time}$event->{series_name}$title$event->{episode}$rerun$draft$live$archived
} if $params->{part} == 0; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; #add handler for events not assigned to series if ( ( $params->{studio_id} ne '' ) && ( $params->{studio_id} ne '-1' ) ) { my $series = series::get( $config, { project_id => $project_id, studio_id => $studio_id } ); print q{}; } print qq{ } if $params->{part} == 0; } sub calcCalendarTable { my $config = shift; my $permissions = shift; my $params = shift; my $calendar = shift; my $events_by_day = shift; my $cal_options = shift; my $start_of_day = $cal_options->{start_of_day}; my $end_of_day = $cal_options->{end_of_day}; my $min_hour = $cal_options->{min_hour}; my $max_hour = $cal_options->{max_hour}; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; my $language = $params->{language}; #insert time column for my $hour ( $min_hour .. $max_hour ) { push @{ $events_by_day->{0} }, { start => sprintf( '%02d:00', $hour % 24 ), start_time => sprintf( '%02d:00', $hour ), end_time => sprintf( '%02d:00', $hour + 1 ), series_id => -1, event_id => -1, project_id => $project_id, studio_id => $studio_id, class => 'time', time => sprintf( '%02d', $hour % 24 ) }; } #insert current time my $now = time::get_datetime( time::time_to_datetime(), $config->{date}->{time_zone} ); my $time = '00:00'; my $date = ''; if ( $now =~ /(\d\d\d\d\-\d\d\-\d\d)[ T](\d\d\:\d\d)/ ) { $date = $1; $time = $2; } push @{ $events_by_day->{0} }, { start => $time, start_time => $time, end_time => $time, series_id => -1, event_id => -1, project_id => -1, studio_id => -1, class => 'time now', time => $time, }; calc_positions( $events_by_day->{0}, $cal_options ); #print Dumper($events_by_day); my $yoffset = $min_hour * $hour_height; my @days = sort keys %$events_by_day; $cal_options->{days} = \@days; $cal_options->{yoffset} = $yoffset; $cal_options->{events_by_day} = $events_by_day; $cal_options->{date} = $date; } sub printTableHeader { my $config = shift; my $permissions = shift; my $params = shift; my $cal_options = shift; my $days = $cal_options->{days}; my $events_by_day = $cal_options->{events_by_day}; my $yoffset = $cal_options->{yoffset}; my $date = $cal_options->{date}; my $min_hour = $cal_options->{min_hour}; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; my $language = $params->{language}; #print row with weekday and date my $out = ''; my $numberOfDays = scalar(@$days); my $width = int( 85 / $numberOfDays ); $out .= qq! !; $out .= q{ }; print $out; } sub printTableBody { my $config = shift; my $permissions = shift; my $params = shift; my $cal_options = shift; my $days = $cal_options->{days}; my $events_by_day = $cal_options->{events_by_day}; my $yoffset = $cal_options->{yoffset}; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; if ( scalar( @{$days} ) == 0 ) { uac::print_info("no dates found at the selected time span"); } my $out = q{ }; print $out; } sub printSeries { my $config = shift; my $permissions = shift; my $params = shift; my $cal_options = shift; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; my $series = series::get( $config, { project_id => $project_id, studio_id => $studio_id } ); my $out = ''; #add schedule entry for series if ( ( defined $permissions->{update_schedule} ) && ( $permissions->{update_schedule} eq '1' ) && ( @$series > 0 ) ) { $out .= q{}; } if ( ( $params->{studio_id} ne '' ) && ( $params->{studio_id} ne '-1' ) ) { $out .= q{}; } $out .= q{ }; print $out; } sub printJavascript { my $config = shift; my $permissions = shift; my $params = shift; my $cal_options = shift; my $startOfDay = $cal_options->{min_hour} % 24; #print STDERR "js: ".$cal_options->{min_hour}." ".$startOfDay."\n"; my $out = q{ }; print $out; } #TODO: Javascript sub addCalendarButton { my $params = shift; my $calendar = shift; #add calendar button my $content = qq{
$calendar->{month} $calendar->{year}
}; return $content; } sub addSeries { my $series = shift; my $params = shift; return unless defined $series; return unless @$series > 0; my $out = ''; $out .= q{
} . $params->{loc}->{label_series} . q{
} . $params->{loc}->{label_date} . q{
} . $params->{loc}->{label_duration} . q{
}; return $out; } # create form to add events to series (that are not assigned to series, yet) sub addEventsToSeries { my $series = shift; my $params = shift; return unless defined $series; return unless @$series > 0; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; my $out = ''; $out .= qq{
} . $params->{loc}->{label_assign_event_series} . qq{
} . $params->{loc}->{label_series} . qq{
}; return $out; } # insert form to create series on not assigned events sub createSeries { my $params = shift; my $project_id = $params->{project_id}; my $studio_id = $params->{studio_id}; return qq{
} . $params->{loc}->{label_create_series} . qq{
} . $params->{loc}->{label_name} . qq{
} . $params->{loc}->{label_title} . qq{
}; } sub print_event { my $params = shift; my $event = shift; my $ypos = shift; my $yoffset = shift; my $yzoom = shift; $event->{project_id} = '-1' unless defined $event->{project_id}; $event->{studio_id} = '-1' unless defined $event->{studio_id}; $event->{series_id} = '-1' unless defined $event->{series_id}; $event->{event_id} = '-1' unless defined $event->{event_id}; my $id = 'event_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{series_id} . '_' . $event->{event_id}; $id = 'grid_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{series_id} if defined $event->{grid}; $id = 'work_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{schedule_id} if defined $event->{work}; $id = 'play_' . $event->{project_id} . '_' . $event->{studio_id} if defined $event->{play}; my $class = $event->{class} || ''; my $showIcons = 0; if ( $class =~ /(event|schedule)/ ) { $class .= ' scheduled' if defined $event->{scheduled}; $class .= ' no_series' if ( ( $class eq 'event' ) && ( $event->{series_id} eq '-1' ) ); $class .= " error x$event->{error}" if defined $event->{error}; for my $filter ( 'rerun', 'archived', 'playout', 'published', 'live', 'disable_event_sync', 'draft' ) { $class .= ' ' . $filter if ( ( defined $event->{$filter} ) && ( $event->{$filter} eq '1' ) ); } $class .= ' preproduced' unless ( ( defined $event->{'live'} ) && ( $event->{'live'} eq '1' ) ); $class .= ' no_playout' unless ( ( defined $event->{'playout'} ) && ( $event->{'playout'} eq '1' ) ); $class .= ' no_rerun' unless ( ( defined $event->{'rerun'} ) && ( $event->{'rerun'} eq '1' ) ); $showIcons = 1; } my $ystart = $event->{ystart} - $yoffset; my $yend = $event->{yend} - $yoffset - 10; $ystart = int( $ystart * $yzoom ); $yend = int( $yend * $yzoom ); my $height = $yend - $ystart + 2; if ( $ypos > 0 ) { $height = q{height:} . ($height) . 'px;'; } else { $height = ''; } my $date = $event->{origStart} || $event->{start} || ''; $date = $event->{time} if defined $event->{time}; $date = $event->{date} if defined $event->{date}; my $content = $event->{content} || ''; if ( $class =~ /schedule/ ) { my $frequency = getFrequency($event); $content .= "
($frequency)" if defined $frequency; } my $attr = ''; if ( $class =~ /play/ ) { $attr .= ' rms="' . $event->{rms_image} . '"' if defined $event->{rms_image}; $attr .= ' start="' . $event->{start} . '"' if defined $event->{start}; } if ($showIcons) { $content = '
' . $content . '
'; } return q{
$content
} . "\n"; } sub getFrequency { my $event = shift; my $period_type = $event->{period_type}; return undef unless defined $period_type; return undef if $period_type ne 'days'; my $frequency = $event->{frequency}; return undef unless defined $frequency; return undef unless $frequency > 0; if ( ( $frequency >= 7 ) && ( ( $frequency % 7 ) == 0 ) ) { $frequency /= 7; return '1 week' if $frequency == 1; return $frequency .= ' weeks'; } return '1 day' if $frequency == 1; return $frequency .= ' days'; } sub calc_positions { my $events = $_[0]; my $cal_options = $_[1]; my $start_of_day = $cal_options->{start_of_day}; for my $event (@$events) { my ( $start_hour, $start_min ) = getTime( $event->{start_time} ); my ( $end_hour, $end_min ) = getTime( $event->{end_time} ); $start_hour += 24 if $start_hour < $start_of_day; $end_hour += 24 if $end_hour <= $start_of_day; $event->{ystart} = $start_hour * 60 + $start_min; $event->{yend} = $end_hour * 60 + $end_min; } } sub find_errors { my $events = $_[0]; for my $event (@$events) { next if defined $event->{grid}; next if defined $event->{work}; next if defined $event->{play}; next if (defined $event->{draft}) && ($event->{draft} == 1); next unless defined $event->{ystart}; next unless defined $event->{yend}; $event->{check_errors} = 1; } #check next events for my $i ( 0 .. @$events - 1 ) { my $event = $events->[$i]; next unless defined $event->{check_errors}; #look for conflicts with next 5 events of day my $min_index = $i + 1; next if $min_index >= @$events; my $max_index = $i + 8; $max_index = @$events - 1 if $max_index >= @$events; for my $j ( $min_index .. $max_index ) { my $event2 = $events->[$j]; next unless defined $event2->{check_errors}; #mark events if same start,stop,series_id, one is schedule one is event if ( ( defined $event->{series_id} ) && ( defined $event2->{series_id} ) && ( $event->{series_id} == $event2->{series_id} ) ) { if ( ( $event->{ystart} eq $event2->{ystart} ) && ( $event->{yend} eq $event2->{yend} ) ) { if ( ( defined $event->{schedule} ) && ( !( defined $event2->{schedule} ) ) ) { $event->{hide} = 1; $event2->{scheduled} = 1; next; } if ( ( !( defined $event->{schedule} ) ) && ( defined $event2->{schedule} ) ) { $event->{scheduled} = 1; $event2->{hide} = 1; next; } } elsif ( ( $event->{ystart} >= $event2->{ystart} ) && ( $event->{scheduled} == 1 ) && ( $event2->{scheduled} == 1 ) ) { #subsequent schedules $event->{error}++; $event2->{error} = 1 unless defined $event2->{error}; $event2->{error}++; next; } } elsif ( $event->{ystart} >= $event2->{ystart} ) { #errors on multiple schedules or events $event->{error}++; $event2->{error} = 1 unless defined $event2->{error}; $event2->{error}++; } } } #remove error tags from correctly scheduled entries (subsequent entries with same series id) for my $event (@$events) { delete $event->{error} if ( ( defined $event->{error} ) && ( ( ( defined $event->{scheduled} ) && ( $event->{scheduled} == 1 ) ) || ( ( defined $event->{hide} ) && ( $event->{hide} == 1 ) ) ) ); } } sub printToolbar { my $config = shift; my $params = shift; my $calendar = shift; #print Dumper($params); my $today = time::time_to_date(); #setToday (TODO:javascript) my $toolbar = '
'; #$toolbar.='
'.addCalendarButton($params, $calendar).'
'; $toolbar .= addCalendarButton( $params, $calendar ); $toolbar .= qq{}; #ranges my $ranges = { $params->{loc}->{label_month} => 'month', $params->{loc}->{label_4_weeks} => '28', $params->{loc}->{label_2_weeks} => '14', $params->{loc}->{label_1_week} => '7', $params->{loc}->{label_day} => '1', }; $toolbar .= qq{ }; # start of day my $day_start = $params->{day_start} || ''; $toolbar .= qq{ }; #filter my $filter = $params->{filter} || ''; $toolbar .= qq{ }; #search $toolbar .= qq{ }; # $toolbar .= qq{ } if $params->{list} == 1; $toolbar .= qq{
}; print $toolbar; } sub getTime { my $time = shift; if ( $time =~ /^(\d\d)\:(\d\d)/ ) { return ( $1, $2 ); } return ( -1, -1 ); } sub getCalendar { my $config = shift; my $params = shift; my $language = shift; my $from_date = getFromDate( $config, $params ); my $till_date = getTillDate( $config, $params ); my $range = $params->{range}; my $previous = ''; my $next = ''; if ( $range eq 'month' ) { $previous = time::get_datetime( $from_date, $config->{date}->{time_zone} )->subtract( months => 1 )->set_day(1)->date(); $next = time::get_datetime( $from_date, $config->{date}->{time_zone} )->add( months => 1 )->set_day(1)->date(); } else { $previous = time::get_datetime( $from_date, $config->{date}->{time_zone} )->subtract( days => $range )->date(); $next = time::get_datetime( $from_date, $config->{date}->{time_zone} )->add( days => $range )->date(); } my ( $year, $month, $day ) = split( /\-/, $from_date ); $month = $time::names->{$language}->{months_abbr}->[ $month - 1 ] || ''; return { from_date => $from_date, till_date => $till_date, next_date => $next, previous_date => $previous, month => $month, year => $year }; } sub getFromDate { my $config = shift; my $params = shift; if ( $params->{from_date} ne '' ) { return $params->{from_date}; } my $date = $params->{date}; if ( $date eq '' ) { $date = DateTime->now( time_zone => $config->{date}->{time_zone} )->date(); } if ( $params->{range} eq '28' ) { #get start of 4 week period $date = time::get_datetime( $date, $config->{date}->{time_zone} )->truncate( to => 'week' )->ymd(); } if ( $params->{range} eq 'month' ) { #get first day of month return time::get_datetime( $date, $config->{date}->{time_zone} )->set_day(1)->date(); } #get date return time::get_datetime( $date, $config->{date}->{time_zone} )->date(); } sub getTillDate { my $config = shift; my $params = shift; if ( $params->{till_date} ne '' ) { return $params->{till_date}; } my $date = $params->{date} || ''; if ( $date eq '' ) { $date = DateTime->now( time_zone => $config->{date}->{time_zone} )->date(); } if ( $params->{range} eq '28' ) { $date = time::get_datetime( $date, $config->{date}->{time_zone} )->truncate( to => 'week' )->ymd(); } if ( $params->{range} eq 'month' ) { #get last day of month return time::get_datetime( $date, $config->{date}->{time_zone} )->set_day(1)->add( months => 1 )->subtract( days => 1 )->date(); } #add range to date return time::get_datetime( $date, $config->{date}->{time_zone} )->add( days => $params->{range} )->date(); } sub getSeriesEvents { my $config = shift; my $request = shift; my $options = shift; my $params = shift; #get events by series id my $series_id = $request->{params}->{checked}->{series_id}; if ( defined $series_id ) { my $events = series::get_events( $request->{config}, $options ); return $events; } #get events (directly from database to get the ones, not assigned, yet) delete $options->{studio_id}; delete $options->{project_id}; my $request2 = { params => { checked => events::check_params( $config, $options ) }, config => $request->{config}, permissions => $request->{permissions} }; $request2->{params}->{checked}->{published} = 'all'; $request2->{params}->{checked}->{draft} = '1' if $params->{list}==1; #delete $request2->{params}->{checked}->{locations_to_exclude} # if ( ( $params->{studio_id} == -1 ) && ( defined $request2->{params}->{checked}->{locations_to_exclude} ) ); my $events = events::get( $config, $request2 ); #print STDERR Dumper($request2->{params}->{checked}); #print STDERR Dumper($events); series::add_series_ids_to_events( $request->{config}, $events ); my $studios = studios::get( $request->{config}, { project_id => $options->{project_id} } ); my $studio_id_by_location = {}; for my $studio (@$studios) { $studio_id_by_location->{ $studio->{location} } = $studio->{id}; } for my $event (@$events) { $event->{project_id} = $options->{project_id} unless defined $event->{project_id}; $event->{studio_id} = $studio_id_by_location->{ $event->{location} } unless defined $event->{studio_id}; } return $events; } sub check_params { my $params = shift; my $config = shift; my $checked = {}; my $template = ''; $checked->{template} = template::check( $params->{template}, 'series' ); my $debug = $params->{debug} || ''; if ( $debug =~ /([a-z\_\,]+)/ ) { $debug = $1; } $checked->{debug} = $debug; #numeric values $checked->{part} = 0; $checked->{list} = 0; for my $param ( 'id', 'project_id', 'studio_id', 'default_studio_id', 'user_id', 'series_id', 'event_id', 'part', 'list', 'day_start' ) { if ( ( defined $params->{$param} ) && ( $params->{$param} =~ /^\d+$/ ) ) { $checked->{$param} = $params->{$param}; } } $checked->{day_start} = $config->{date}->{day_starting_hour} unless defined $checked->{day_start}; $checked->{day_start} %= 24; if ( defined $checked->{studio_id} ) { # a studio is selected, use the studio from parameter $checked->{default_studio_id} = $checked->{studio_id}; } elsif ( ( defined $params->{studio_id} ) && ( $params->{studio_id} eq '-1' ) ) { # all studios selected, use -1 $checked->{studio_id} = -1; } else { # no studio given, use default studio $checked->{studio_id} = $checked->{default_studio_id}; } $checked->{open_end} = 1; for my $param ('open_end') { if ( ( defined $params->{$param} ) && ( $params->{$param} =~ /^\d+$/ ) ) { $checked->{$param} = $params->{$param}; } } #scalars $checked->{search} = ''; $checked->{filter} = ''; #$checked->{range}='month'; for my $param ( 'search', 'filter', 'range' ) { if ( defined $params->{$param} ) { $checked->{$param} = $params->{$param}; $checked->{$param} =~ s/^\s+//g; $checked->{$param} =~ s/\s+$//g; } } for my $param ('expires') { $checked->{$param} = time::check_datetime( $params->{$param} ); } for my $param ( 'date', 'from_date', 'till_date' ) { $checked->{$param} = time::check_date( $params->{$param} ); } for my $param ( 'series_name', 'title', 'excerpt', 'content', 'program', 'category', 'image', 'user_content' ) { if ( defined $params->{$param} ) { #$checked->{$param}=uri_unescape(); $checked->{$param} = $params->{$param}; $checked->{$param} =~ s/^\s+//g; $checked->{$param} =~ s/\s+$//g; } } #actions and roles if ( defined $params->{action} ) { if ( $params->{action} =~ /^(add_user|remove_user|delete|save|details|show|edit_event|save_event)$/ ) { $checked->{action} = $params->{action}; } } return $checked; }