package series; use strict; use warnings; no warnings 'redefine'; use Data::Dumper; use events(); use images(); #use base 'Exporter'; our @EXPORT_OK = qw( get_columns get insert update delete get_users add_user remove_user get_events get_event get_next_episode search_events get_event_age is_event_older_than_days get_images assign_event unassign_event add_series_ids_to_events set_event_ids can_user_update_events can_user_create_events is_series_assigned_to_user is_event_assigned_to_user update_recurring_events update_recurring_event ); #TODO: remove studio_id #TODO: get project_id, studio_id by join with project_series # get series columns sub get_columns ($) { my $config = shift; my $dbh = db::connect($config); return db::get_columns_hash( $dbh, 'calcms_series' ); } # get series content sub get ($$) { my $config = shift; my $condition = shift; my @conditions = (); my @bind_values = (); if ( ( defined $condition->{series_id} ) && ( $condition->{series_id} ne '' ) ) { push @conditions, 'id=?'; push @bind_values, $condition->{series_id}; } if ( defined $condition->{series_name} ) { push @conditions, 'series_name=?'; push @bind_values, $condition->{series_name}; } if ( defined $condition->{title} ) { push @conditions, 'title=?'; push @bind_values, $condition->{title}; } if ( ( defined $condition->{has_single_events} ) && ( $condition->{has_single_events} ne '' ) ) { push @conditions, 'has_single_events=?'; push @bind_values, $condition->{has_single_events}; } my $search_cond = ''; if ( ( defined $condition->{search} ) && ( $condition->{search} ne '' ) ) { my $search = lc $condition->{search}; $search =~ s/[^a-z0-9\_\.\-\:\!öäüßÖÄÜ \&]/%/; $search =~ s/\%+/\%/; $search =~ s/^[\%\s]+//; $search =~ s/[\%\s]+$//; if ( $search ne '' ) { $search = '%' . $search . '%'; my @attr = ( 'title', 'series_name', 'excerpt', 'content' ); push @conditions, "(" . join( " or ", map { 'lower(' . $_ . ') like ?' } @attr ) . ")"; for my $attr (@attr) { push @bind_values, $search; } } } my $query = ''; my $conditions = ''; if ( ( defined $condition->{project_id} ) || ( defined $condition->{studio_id} ) ) { if ( ( defined $condition->{project_id} ) && ( $condition->{project_id} ne '' ) ) { push @conditions, 'ps.project_id=?'; push @bind_values, $condition->{project_id}; } if ( ( defined $condition->{studio_id} ) && ( $condition->{studio_id} ne '' ) ) { push @conditions, 'ps.studio_id=?'; push @bind_values, $condition->{studio_id}; } push @conditions, 'ps.series_id=s.id'; $conditions = " where " . join( " and ", @conditions ) if ( @conditions > 0 ); $query = qq{ select * from calcms_series s, calcms_project_series ps $conditions order by has_single_events desc, series_name, title }; } else { # simple query $conditions = " where " . join( " and ", @conditions ) if ( @conditions > 0 ); $query = qq{ select * from calcms_series $conditions order by has_single_events desc, series_name, title }; } my $dbh = db::connect($config); my $series = db::get( $dbh, $query, \@bind_values ); for my $serie (@$series) { $serie->{series_id} = $serie->{id}; delete $serie->{id}; } return $series; } # insert series sub insert ($$) { my $config = shift; my $series = shift; return undef unless defined $series->{project_id}; return undef unless defined $series->{studio_id}; my $project_id = $series->{project_id}; my $studio_id = $series->{studio_id}; my $columns = series::get_columns($config); my $entry = {}; for my $column ( keys %$columns ) { $entry->{$column} = $series->{$column} if defined $series->{$column}; } $entry->{image} = images::normalizeName( $entry->{image} ) if defined $entry->{image}; $entry->{created_at} = time::time_to_datetime( time() ); $entry->{modified_at} = time::time_to_datetime( time() ); my $dbh = db::connect($config); my $series_id = db::insert( $dbh, 'calcms_series', $entry ); return undef unless defined $series_id; my $result = project::assign_series( $config, { project_id => $project_id, studio_id => $studio_id, series_id => $series_id } ); return undef unless defined $result; return $series_id; } # update series sub update ($$) { my $config = shift; my $series = shift; return undef unless defined $series->{project_id}; return undef unless defined $series->{studio_id}; return undef unless defined $series->{series_id}; my $columns = series::get_columns($config); my $entry = {}; for my $column ( keys %$columns ) { $entry->{$column} = $series->{$column} if defined $series->{$column}; } $entry->{image} = images::normalizeName( $entry->{image} ) if defined $entry->{image}; $entry->{id} = $series->{series_id}; $entry->{modified_at} = time::time_to_datetime( time() ); my @keys = keys %$entry; my $values = join( ",", map { $_ . '=?' } @keys ); my @bind_values = map { $entry->{$_} } @keys; push @bind_values, $entry->{id}; my $query = qq{ update calcms_series set $values where id=? }; my $dbh = db::connect($config); return db::put( $dbh, $query, \@bind_values ); } # delete series, its schedules and series dates # unassign its users and events sub delete($$) { my $config = shift; my $series = shift; return undef unless defined $series->{project_id}; return undef unless defined $series->{studio_id}; return undef unless defined $series->{series_id}; my $project_id = $series->{project_id}; my $studio_id = $series->{studio_id}; my $series_id = $series->{series_id}; unless ( project::is_series_assigned( $config, $series ) == 1 ) { print STDERR "series is not assigned to project $project_id and studio $studio_id\n"; return undef; } my $query = undef; my $bind_values = undef; my $dbh = db::connect($config); $bind_values = [ $project_id, $studio_id, $series_id ]; #delete schedules $query = qq{ delete from calcms_series_schedule where project_id=? and studio_id=? and series_id=? }; db::put( $dbh, $query, $bind_values ); #delete series dates $query = qq{ delete from calcms_series_dates where project_id=? and studio_id=? and series_id=? }; db::put( $dbh, $query, $bind_values ); #unassign users series::remove_user( $config, { project_id => $project_id, studio_id => $studio_id, series_id => $series_id } ); #unassign events $bind_values = [ $project_id, $studio_id, $series_id ]; $query = qq{ delete from calcms_series_events where project_id=? and studio_id=? and series_id=? }; db::put( $dbh, $query, $bind_values ); project::unassign_series( $config, { project_id => $project_id, studio_id => $studio_id, series_id => $series_id } ); #delete series my $series_assignments = project::get_series_assignments( $config, { series_id => $series_id } ); if ( scalar @$series_assignments > 1 ) { print STDERR "do not delete series, due to assigned to other project or studio"; return; } $bind_values = [$series_id]; $query = qq{ delete from calcms_series where id=? }; db::put( $dbh, $query, $bind_values ); } # get users directly assigned to project, studio, series (editors) sub get_users ($$) { my $config = shift; my $condition = shift; my @conditions = (); my @bind_values = (); if ( ( defined $condition->{project_id} ) && ( $condition->{project_id} ne '' ) ) { push @conditions, 'us.project_id=?'; push @bind_values, $condition->{project_id}; } if ( ( defined $condition->{studio_id} ) && ( $condition->{studio_id} ne '' ) ) { push @conditions, 'us.studio_id=?'; push @bind_values, $condition->{studio_id}; } if ( ( defined $condition->{series_id} ) && ( $condition->{series_id} ne '' ) ) { push @conditions, 'us.series_id=?'; push @bind_values, $condition->{series_id}; } if ( ( defined $condition->{name} ) && ( $condition->{name} ne '' ) ) { push @conditions, 'u.name=?'; push @bind_values, $condition->{name}; } my $conditions = ''; $conditions = " and " . join( " and ", @conditions ) if ( @conditions > 0 ); my $query = qq{ select u.id, u.name, u.full_name, u.email, us.modified_by, us.modified_at from calcms_users u, calcms_user_series us where us.user_id=u.id $conditions }; my $dbh = db::connect($config); my $result = db::get( $dbh, $query, \@bind_values ); return $result; } # assign user to series sub add_user ($$) { my $config = shift; my $entry = shift; return unless defined $entry->{project_id}; return unless defined $entry->{studio_id}; return unless defined $entry->{series_id}; return unless defined $entry->{user_id}; return unless defined $entry->{user}; my $query = qq{ select id from calcms_user_series where project_id=? and studio_id=? and series_id=? and user_id=? }; my $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{user_id} ]; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, $bind_values ); return unless scalar @$results == 0; $query = qq{ insert calcms_user_series set project_id=?, studio_id=?, series_id=?, user_id=?, modified_by=?, modified_at=now() }; $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{user_id}, $entry->{user} ]; db::put( $dbh, $query, $bind_values ); } # remove user(s) from series. sub remove_user ($$) { my $config = shift; my $condition = shift; return unless defined $condition->{project_id}; return unless defined $condition->{studio_id}; return unless defined $condition->{series_id}; my @conditions = (); my @bind_values = (); if ( ( defined $condition->{project_id} ) && ( $condition->{project_id} ne '' ) ) { push @conditions, 'project_id=?'; push @bind_values, $condition->{project_id}; } if ( ( defined $condition->{studio_id} ) && ( $condition->{studio_id} ne '' ) ) { push @conditions, 'studio_id=?'; push @bind_values, $condition->{studio_id}; } if ( ( defined $condition->{series_id} ) && ( $condition->{series_id} ne '' ) ) { push @conditions, 'series_id=?'; push @bind_values, $condition->{series_id}; } if ( ( defined $condition->{user_id} ) && ( $condition->{user_id} ne '' ) ) { push @conditions, 'user_id=?'; push @bind_values, $condition->{user_id}; } my $conditions = ''; $conditions = join( " and ", @conditions ) if ( @conditions > 0 ); my $query = qq{ delete from calcms_user_series where $conditions }; my $dbh = db::connect($config); db::put( $dbh, $query, \@bind_values ); } #search events by series_name and title (for events not assigned yet) #TODO: add location sub search_events ($$$) { my $config = shift; my $request = shift; my $options = shift; my $series_name = $options->{series_name} || ''; my $title = $options->{title} || ''; return undef if ( $series_name eq '' ) && ( $title eq '' ); $series_name =~ s/[^a-zA-Z0-9 \-]+/\?/g; $title =~ s/[^a-zA-Z0-9 \-]+/\?/g; $series_name =~ s/\?+/\?/g; $title =~ s/\?+/\?/g; my $params = { series_name => $series_name, title => $title, template => 'no' }; if ( defined $options ) { $params->{from_date} = $options->{from_date} if defined $options->{from_date}; $params->{till_date} = $options->{till_date} if defined $options->{till_date}; $params->{location} = $options->{location} if defined $options->{location}; $params->{limit} = $options->{limit} if defined $options->{limit}; $params->{archive} = $options->{archive} if defined $options->{archive}; $params->{get} = $options->{get} if defined $options->{get}; } my $checked_params = events::check_params( $config, $params ); my $request2 = { params => { checked => $checked_params }, config => $request->{config}, permissions => $request->{permissions} }; my $events = events::get( $config, $request2 ); return $events; } #get events (only assigned ones) by project_id,studio_id,series_id, sub get_events ($$) { my $config = shift; my $options = shift; return [] if defined( $options->{series_id} ) && ( $options->{series_id} <= 0 ); my @conditions = (); my @bind_values = (); if ( defined $options->{project_id} ) { push @conditions, 'se.project_id = ?'; push @bind_values, $options->{project_id}; } if ( defined $options->{studio_id} ) { push @conditions, 'se.studio_id = ?'; push @bind_values, $options->{studio_id}; } if ( ( defined $options->{series_id} ) && ( $options->{series_id} =~ /(\d+)/ ) ) { push @bind_values, $1; push @conditions, 'se.series_id = ?'; } if ( defined $options->{event_id} ) { push @bind_values, $options->{event_id}; push @conditions, 'e.id = ?'; } if ( ( defined $options->{from_date} ) && ( $options->{from_date} =~ /(\d\d\d\d\-\d\d\-\d\d)/ ) ) { push @bind_values, $1; push @conditions, 'e.start_date >= ?'; } if ( ( defined $options->{till_date} ) && ( $options->{till_date} =~ /(\d\d\d\d\-\d\d\-\d\d)/ ) ) { push @bind_values, $1; push @conditions, 'e.start_date <= ?'; } if ( defined $options->{location} ) { push @conditions, 'e.location = ?'; push @bind_values, $options->{location}; } if ( defined $options->{draft} ) { push @conditions, 'e.draft = ?'; push @bind_values, $options->{draft}; } my $conditions = ''; if ( @conditions > 0 ) { $conditions = ' where ' . join( ' and ', @conditions ); } my $limit = ''; if ( ( defined $options->{limit} ) && ( $limit =~ /(\d+)/ ) ) { $limit = 'limit ' . $1; } my $query = qq{ select se.*,e.* ,date(start) start_date ,date(end) end_date ,weekday(start) weekday ,weekofyear(start) week_of_year ,dayofyear(start) day_of_year ,start_date day ,e.id event_id ,ar.path path from calcms_series_events se inner join calcms_events e on se.event_id = e.id left join calcms_audio_recordings ar on se.event_id=ar.event_id and ar.active=1 $conditions order by start_date desc $limit }; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, \@bind_values ); $results = events::modify_results( $dbh, $config, { base_url => '', params => { checked => { template => '', set_no_listen_keys => ($options->{set_no_listen_keys}//'') ? 1:0 } } }, $results ); #add studio id to events my $studios = studios::get( $config, $options ); my $studio_id_by_location = {}; for my $studio (@$studios) { $studio_id_by_location->{ $studio->{location} } = $studio->{id}; } for my $result (@$results) { $result->{studio_id} = $studio_id_by_location->{ $result->{location} }; } return $results; } # load event given by studio_id, series_id and event_id # helper for gui - errors are written to gui output # return undef on error sub get_event ($$) { my $config = shift; my $options = shift; my $project_id = $options->{project_id} || ''; my $studio_id = $options->{studio_id} || ''; my $series_id = $options->{series_id} || ''; my $event_id = $options->{event_id} || ''; my $draft = $options->{draft} || ''; unless ( defined $options->{allow_any} ) { if ( $project_id eq '' ) { uac::print_error("missing project_id"); return undef; } if ( $studio_id eq '' ) { uac::print_error("missing studio_id"); return undef; } if ( $series_id eq '' ) { uac::print_error("missing series_id"); return undef; } } if ( $event_id eq '' ) { uac::print_error("missing event_id"); return undef; } my $queryOptions = {}; $queryOptions->{project_id} = $project_id if $project_id ne ''; $queryOptions->{studio_id} = $studio_id if $studio_id ne ''; $queryOptions->{series_id} = $series_id if $series_id ne ''; $queryOptions->{event_id} = $event_id if $event_id ne ''; $queryOptions->{draft} = $draft if $draft ne ''; my $events = series::get_events( $config, $queryOptions ); unless ( defined $events ) { uac::print_error("error on loading event"); return undef; } if ( scalar(@$events) == 0 ) { uac::print_error("event not found"); return undef; } if ( scalar(@$events) > 1 ) { print STDERR q{multiple assignments found for } . q{project_id=} . $options->{project_id} . q{, studio_id=} . $options->{studio_id} . q{, series_id=} . $options->{series_id} . q{, event_id=} . $options->{event_id} . "\n"; } my $event = $events->[0]; return $event; } # get name and title of series and age in days ('days_over') sub get_event_age($$) { my $config = shift; my $options = shift; return undef unless defined $options->{project_id}; return undef unless defined $options->{studio_id}; my @conditions = (); my @bind_values = (); if ( ( defined $options->{project_id} ) && ( $options->{project_id} =~ /(\d+)/ ) ) { push @bind_values, $1; push @conditions, 'ps.project_id = ?'; } if ( ( defined $options->{studio_id} ) && ( $options->{studio_id} =~ /(\d+)/ ) ) { push @bind_values, $1; push @conditions, 'ps.studio_id = ?'; } if ( ( defined $options->{series_id} ) && ( $options->{series_id} =~ /(\d+)/ ) ) { push @bind_values, $1; push @conditions, 's.id = ?'; } if ( ( defined $options->{event_id} ) && ( $options->{event_id} =~ /(\d+)/ ) ) { push @bind_values, $1; push @conditions, 'e.id = ?'; } my $conditions = ''; if ( @conditions > 0 ) { $conditions = join( ' and ', @conditions ); } my $query = qq{ select s.id series_id, s.series_name, s.title, s.has_single_events has_single_events, (to_days(now())-to_days(max(e.start))) days_over from calcms_project_series ps left join calcms_series s on ps.series_id=s.id left join calcms_series_events se on s.id=se.series_id left join calcms_events e on e.id=se.event_id where $conditions group by s.id order by has_single_events desc, days_over }; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, \@bind_values ); for my $result (@$results) { $result->{days_over} = 0 unless defined $result->{days_over}; } return $results; } # is event older than max_age days sub is_event_older_than_days ($$) { my $config = shift; my $options = shift; return 1 unless defined $options->{project_id}; return 1 unless defined $options->{studio_id}; return 1 unless defined $options->{series_id}; return 1 unless defined $options->{event_id}; return 1 unless defined $options->{max_age}; my $events = series::get_event_age( $config, { project_id => $options->{project_id}, studio_id => $options->{studio_id}, series_id => $options->{series_id}, event_id => $options->{event_id} } ); if ( scalar(@$events) == 0 ) { print STDERR "series_events::event_over_in_days: event $options->{event_id} is not assigned to project $options->{project_id}, studio $options->{studio_id}, series $options->{series_id}\n"; return 1; } my $event = $events->[0]; return 1 if $event->{days_over} > $options->{max_age}; return 0; } sub get_next_episode($$) { my $config = shift; my $options = shift; return 0 unless defined $options->{project_id}; return 0 unless defined $options->{studio_id}; return 0 unless defined $options->{series_id}; #return if episodes should not be counted for this series my $query = q{ select count_episodes from calcms_series where id=? }; my $bind_values = [ $options->{series_id} ]; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, $bind_values ); return 0 if ( @$results != 1 ); return 0 if ( $results->[0]->{count_episodes} eq '0' ); #get all $query = q{ select title,episode from calcms_events e, calcms_series_events se where se.project_id=? and se.studio_id=? and se.series_id=? and se.event_id=e.id }; $bind_values = [ $options->{project_id}, $options->{studio_id}, $options->{series_id} ]; $results = db::get( $dbh, $query, $bind_values ); my $max = 0; for my $result (@$results) { if ( $result->{title} =~ /\#(\d+)/ ) { my $value = $1; $max = $value if $value > $max; } next unless defined $result->{episode}; $max = $result->{episode} if $result->{episode} > $max; } return $max + 1; } sub get_images ($$) { my $config = shift; my $options = shift; return undef unless defined $options->{project_id}; return undef unless defined $options->{studio_id}; return undef unless defined $options->{series_id}; #get images from all events of the series my $dbh = db::connect($config); my $events = series::get_events( $config, { project_id => $options->{project_id}, studio_id => $options->{studio_id}, series_id => $options->{series_id} } ); my $images = { map { my $image = $_->{image}; $image =~ s/.*\///; { $image => 1 }; } @$events }; my $found = scalar(keys %$images); return undef if $found == 0; # get all images from database my @cond = (); my $bind_values = []; for my $image ( keys %$images ) { push @cond, 'filename=?'; push @$bind_values, $image; } my $where = ''; if ( @cond > 0 ) { $where = 'where ' . join( ' or ', @cond ); } my $limit = ''; if ( ( defined $options->{limit} ) && ( $options->{limit} =~ /(\d+)/ ) ) { $limit = ' limit ' . $1; } my $query = qq{ select * from calcms_images $where order by created_at desc $limit }; my $results = db::get( $dbh, $query, $bind_values ); return $results; } #assign event to series #TODO: manual assign needs to update automatic one sub assign_event($$) { my $config = shift; my $entry = shift; return undef unless defined $entry->{project_id}; return undef unless defined $entry->{studio_id}; return undef unless defined $entry->{series_id}; return undef unless defined $entry->{event_id}; $entry->{manual} = 0 unless ( defined $entry->{manual} ) && ( $entry->{manual} eq '1' ); my $conditions = ''; $conditions = 'and manual=1' if $entry->{manual} eq '1'; my $query = qq{ select * from calcms_series_events where project_id=? and studio_id=? and series_id=? and event_id=? $conditions }; my $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{event_id} ]; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, $bind_values ); if ( scalar @$results > 1 ) { print STDERR "multiple assignments of project_id=$entry->{project_id}, studio_id=$entry->{studio_id}, series_id=$entry->{series_id}, event_id=$entry->{event_id}\n"; return; } if ( scalar @$results == 1 ) { print STDERR "already assigned: project_id=$entry->{project_id}, studio_id=$entry->{studio_id}, series_id=$entry->{series_id}, event_id=$entry->{event_id}\n"; return; } $query = qq{ insert into calcms_series_events (project_id, studio_id, series_id, event_id, manual) values (?,?,?,?,?) }; $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{event_id}, $entry->{manual} ]; return db::put( $dbh, $query, $bind_values ); } #unassign event from series sub unassign_event($$) { my $config = shift; my $entry = shift; return unless defined $entry->{project_id}; return unless defined $entry->{studio_id}; return unless defined $entry->{series_id}; return unless defined $entry->{event_id}; my $conditions = ''; $conditions = 'and manual=1' if ( defined $entry->{manual} ) && ( $entry->{manual} eq '1' ); my $query = qq{ delete from calcms_series_events where project_id=? and studio_id=? and series_id=? and event_id=? $conditions }; my $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{event_id} ]; my $dbh = db::connect($config); return db::put( $dbh, $query, $bind_values ); } # put series id to given events (for legacy handling) # used by calendar # TODO: optionally add project_id and studio_id to conditions sub add_series_ids_to_events ($$) { my $config = shift; my $events = shift; #get event ids from given events my @event_ids = (); for my $event (@$events) { push @event_ids, $event->{event_id}; } return if scalar @event_ids == 0; my @bind_values = @event_ids; my $event_ids = join( ',', map { '?' } @event_ids ); #query series ids my $dbh = db::connect($config); my $query = qq{ select project_id, studio_id, series_id, event_id from calcms_series_events where event_id in ($event_ids) }; my $results = db::get( $dbh, $query, \@bind_values ); my @results = @$results; return [] unless scalar @results > 0; #build hash of series ids by event ids my $assignments_by_event_id = {}; for my $entry (@$results) { my $event_id = $entry->{event_id}; $assignments_by_event_id->{$event_id} = $entry; } #fill in ids into events for my $event (@$events) { my $event_id = $event->{event_id}; my $assignment = $assignments_by_event_id->{$event_id}; if ( defined $assignment ) { $event->{project_id} = $assignment->{project_id}; $event->{studio_id} = $assignment->{studio_id}; $event->{series_id} = $assignment->{series_id}; } } } # add event_ids to series and remove all event ids from series, not given event_ids # for scan only, used at series sub set_event_ids ($$$$$) { my $config = shift; my $project_id = shift; my $studio_id = shift; my $serie = shift; my $event_ids = shift; my $serie_id = $serie->{series_id}; return unless defined $project_id; return unless defined $studio_id; return unless defined $serie_id; return unless defined $event_ids; #make lookup table from events my $event_id_hash = { map { $_ => 1 } @$event_ids }; #get series_entries from db #my $bind_names=join(',', (map { '?' } @$event_ids)); my $query = qq{ select event_id from calcms_series_events where project_id=? and studio_id=? and series_id=? }; my $bind_values = [ $project_id, $studio_id, $serie_id ]; my $dbh = db::connect($config); my $results = db::get( $dbh, $query, $bind_values ); #mark events found assigned to series my $found = { map { $_->{event_id} => 1 } @$results }; #insert events from list, not found in db for my $event_id (@$event_ids) { #print "insert event_id $event_id\n"; series::assign_event( $config, { project_id => $project_id, studio_id => $studio_id, series_id => $serie_id, event_id => $event_id } ) unless ( $found->{$event_id} ); } #delete events found in db, but not in list for my $event_id ( keys %$found ) { #print "delete event_id $event_id\n"; series::unassign_event( $config, { project_id => $project_id, studio_id => $studio_id, series_id => $serie_id, event_id => $event_id, manual => 0 } ) unless defined $event_id_hash->{$event_id}; } } # check if user allowed to update series events # evaluate permissions and consider editors directly assigned to series sub can_user_update_events ($$) { my $request = shift; my $options = shift; my $config = $request->{config}; my $permissions = $request->{permissions}; return 0 unless defined $request->{user}; return 0 unless defined $options->{project_id}; return 0 unless defined $options->{studio_id}; return 0 unless defined $options->{series_id}; return 1 if ( defined $permissions->{update_event_of_others} ) && ( $permissions->{update_event_of_others} eq '1' ); return 1 if ( defined $permissions->{is_admin} ) && ( $permissions->{is_admin} eq '1' ); return 0 if $permissions->{update_event_of_series} ne '1'; return is_series_assigned_to_user( $request, $options ); } # check if user allowed to create series events # evaluate permissions and consider editors directly assigned to series sub can_user_create_events ($$) { my $request = shift; my $options = shift; my $config = $request->{config}; my $permissions = $request->{permissions}; return 0 unless defined $request->{user}; return 0 unless defined $options->{project_id}; return 0 unless defined $options->{studio_id}; return 0 unless defined $options->{series_id}; return 1 if ( defined $permissions->{create_event} ) && ( $permissions->{create_event} eq '1' ); return 1 if ( defined $permissions->{is_admin} ) && ( $permissions->{is_admin} eq '1' ); return 0 if $permissions->{create_event_of_series} ne '1'; return is_series_assigned_to_user( $request, $options ); } sub is_series_assigned_to_user ($$) { my $request = shift; my $options = shift; my $config = $request->{config}; my $permissions = $request->{permissions}; return 0 unless defined $options->{project_id}; return 0 unless defined $options->{studio_id}; return 0 unless defined $options->{series_id}; return 0 unless defined $request->{user}; my $series_users = series::get_users( $config, { project_id => $options->{project_id}, studio_id => $options->{studio_id}, series_id => $options->{series_id}, name => $request->{user} } ); return 0 if scalar @$series_users == 0; return 1; } # check if user is assigned to studio where location matchs to event # return 1 on success or error text sub is_event_assigned_to_user ($$) { my $request = shift; my $options = shift; my $config = $request->{config}; return "missing user" unless defined $request->{user}; return "missing project_id" unless defined $options->{project_id}; return "missing studio_id" unless defined $options->{studio_id}; return "missing series_id" unless defined $options->{series_id}; return "missing event_id" unless defined $options->{event_id}; #check roles my $user_studios = uac::get_studios_by_user( $config, { project_id => $options->{project_id}, studio_id => $options->{studio_id}, user => $request->{user}, } ); return "user is not assigned to studio" if scalar @$user_studios == 0; my $studio = $user_studios->[0]; my $location = $studio->{location}; return "could not get studio location" if $location eq ''; #TODO: replace legacy support my $events = series::get_events( $config, { project_id => $options->{project_id}, studio_id => $options->{studio_id}, series_id => $options->{series_id}, event_id => $options->{event_id}, location => $location, limit => 1 } ); return "no event found for" . " project $options->{project_id}," . " studio $options->{studio_id}," . " location $location," . " series $options->{series_id}" . " and event $options->{event_id}" if scalar @$events == 0; return 1; } sub get_rebuilt_episodes ($$) { my $config = shift; my $options = shift; return "missing project_id" unless defined $options->{project_id}; return "missing studio_id" unless defined $options->{studio_id}; return "missing series_id" unless defined $options->{series_id}; # ignore project and studio as series can be used in multiple studios my $events = series::get_events( $config, { #project_id => $options->{project_id}, #studio_id => $options->{studio_id}, series_id => $options->{series_id}, draft => 0 } ); @$events = sort { $a->{start} cmp $b->{start} } @$events; my $events_by_episode = {}; for my $event (@$events) { next unless $event->{episode}; push @{ $events_by_episode->{$event->{episode}} }, $event; } my $done={}; my $episode = $events->[0]->{episode} // 0; $episode-=1; for my $i (0..$#$events){ my $event = $events->[$i]; next if $done->{$event->{id}}; $episode++; # increase episode for not set values if ( ($event->{episode}//'') eq ''){ $event->{old_episode} = $event->{episode}; $event->{episode} = $episode; next; } # set new value to all episodes with same value for my $event2 (@{$events_by_episode->{$event->{episode}}}){ $event2->{old_episode} = $event2->{episode}; $event2->{episode} = $episode; $done->{$event2->{id}}=1; }; } return $events; } # to find multiple recurrences this does not include the recurrence_count # use events::get_key to add the recurrence sub get_event_key ($) { my $event = shift; my $program = $event->{program} || ''; my $series_name = $event->{series_name} || ''; my $title = $event->{title} || ''; my $user_title = $event->{user_title} || ''; my $episode = $event->{episode} || ''; my $key = ''; $key .= $series_name if $series_name ne ''; $key .= ' - ' if ( $series_name ne '' ) && ( $title ne '' ); $key .= $title if $title ne ''; $key .= ': ' if ( $title ne '' ) && ( $user_title ne '' ); $key .= $user_title if $user_title ne ''; $key .= ' #' . $episode if $episode ne ''; return $key; } sub update_recurring_events ($$) { my $config = shift; my $options = shift; return "missing project_id" unless defined $options->{project_id}; return "missing studio_id" unless defined $options->{studio_id}; return "missing series_id" unless defined $options->{series_id}; return "missing event_id" unless defined $options->{event_id}; my $events = series::get_events( $config, { #project_id => $options->{project_id}, #studio_id => $options->{studio_id}, series_id => $options->{series_id}, draft => 0 } ); @$events = sort { $a->{start} cmp $b->{start} } @$events; # store events with recurrences by key (series_name, title, user_title, episode) my $events_by_key = {}; for my $event (@$events) { my $key = get_event_key($event); next unless $key =~ /\#\d+$/; $event->{key} = $key; push @{ $events_by_key->{$key} }, $event; } # handle all events with the same key for my $key ( sort keys %$events_by_key ) { my $events = $events_by_key->{$key}; next unless scalar @$events > 0; if ( scalar @$events == 1 ) { # one event found -> check if recurrence is to be removed my $event = $events->[0]; next if $event->{recurrence} == 0; next if $event->{recurrence_count} == 0; $event->{recurrence} = 0; $event->{recurrence_count} = 0; $event->{rerun} = 0; series::update_recurring_event( $config, $event ); } elsif ( scalar @$events > 1 ) { # multiple events found with same key # first event is the original my $event = $events->[0]; my $originalId = $event->{event_id}; # succeeding events are reruns for ( my $c = 1 ; $c < scalar(@$events) ; $c++ ) { my $event = $events->[$c]; my $update = 0; $update = 1 if $event->{recurrence} ne $originalId; $update = 1 if $event->{rerun} ne '1'; $update = 1 if $event->{recurrence_count} ne $c; next if $update == 0; $event->{recurrence} = $originalId; $event->{recurrence_count} = $c; $event->{rerun} = 1; series::update_recurring_event( $config, $event ); } } } } sub update_recurring_event($$) { my $config = shift; my $event = shift; return undef unless defined $event->{event_id}; return undef unless defined $event->{recurrence}; return undef unless defined $event->{recurrence_count}; return undef unless defined $event->{rerun}; return unless $event->{event_id} =~ /^\d+$/; return unless $event->{recurrence} =~ /^\d+$/; return unless $event->{recurrence_count} =~ /^\d+$/; return unless $event->{rerun} =~ /^\d+$/; my $bind_values = []; push @$bind_values, $event->{recurrence}; push @$bind_values, $event->{recurrence_count}; push @$bind_values, $event->{rerun}; push @$bind_values, $event->{id}; my $update_sql = qq{ update calcms_events set recurrence=?, recurrence_count=?, rerun=? where id=? }; my $dbh = db::connect($config); db::put( $dbh, $update_sql, $bind_values ); } sub error($) { my $msg = shift; print "ERROR: $msg
\n"; } #do not delete last line! 1;