Files
racalmas/lib/calcms/series.pm
2018-01-25 20:50:44 +01:00

1219 lines
35 KiB
Perl

package series;
use warnings "all";
use strict;
use Data::Dumper;
use events;
require Exporter;
our @ISA = qw(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
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#TODO: remove studio_id
#TODO: get project_id, studio_id by join with project_series
sub debug;
# get series columns
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_series');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# 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}) && ($condition->{series_name} ne '')){
push @conditions, 'series_name=?';
push @bind_values, $condition->{series_name};
}
if ((defined $condition->{title}) && ($condition->{title} ne '')){
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', 'category', '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);
#print STDERR Dumper(time());
for my $serie (@$series){
$serie->{series_id}=$serie->{id};
delete $serie->{id};
}
#print STDERR Dumper($series);
return $series;
}
# insert series
sub insert{
my $config=shift;
my $series=shift;
#print STDERR Dumper($series);
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->{created_at} = time::time_to_datetime(time());
$entry->{modified_at}= time::time_to_datetime(time());
#print STDERR Dumper($entry);
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->{id} = $series->{series_id};
$entry->{modified_at}= time::time_to_datetime(time());
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values, $entry->{id};
my $query=qq{
update calcms_series
set $values
where id=?
};
#print STDERR Dumper($query).Dumper(\@bind_values);
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=?
};
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
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(@$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=?
};
#print STDERR $query.$query.Dumper($bind_values);
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
};
#print STDERR $query." ".Dumper(\@bind_values)."\n";
my $dbh =db::connect($config);
my $result=db::get($dbh, $query, \@bind_values);
#print STDERR $query." ".Dumper($result)."\n";
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 (@$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);
#print STDERR '<pre>'.Dumper($checked_params).'</pre>';
my $request2={
params=>{
checked=>$checked_params
},
config => $request->{config},
permissions => $request->{permissions}
};
#my $debug=1;
#print STDERR Dumper($request2->{params});
my $events=events::get($config, $request2);
#print Dumper($events);
return $events;
}
#get events (only assigned ones) by project_id,studio_id,series_id,
sub get_events{
my $config=shift;
my $options=shift;
#print STDERR Dumper($options);
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=' and '.join(' and ', @conditions);
}
my $limit='';
if( (defined $options->{limit}) && ($limit=~/(\d+)/) ){
$limit='limit '.$1;
}
my $query=qq{
select *
,date(start) start_date
,date(end) end_date
,weekday(start) weekday
,weekofyear(start) week_of_year
,dayofyear(start) day_of_year
,start_date day
,id event_id
,location location
from calcms_series_events se, calcms_events e
where se.event_id = e.id
$conditions
order by start_date desc
$limit
};
#print STDERR '<pre>'.$query.Dumper(\@bind_values).'</pre>';
my $dbh=db::connect($config);
my $results=db::get($dbh, $query, \@bind_values);
$results=events::modify_results($dbh, $config, {base_url=>'', params=>{checked=>{template=>''}}}, $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}};
}
#print STDERR Dumper($results);
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(@$events==0){
uac::print_error("event not found");
return undef;
}
if(@$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;
#print STDERR Dumper($options);
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
};
#print STDERR $query." ".Dumper(\@bind_values);
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;
#print STDERR Dumper($options);
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];
#print STDERR Dumper($event);
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');
#print STDERR Dumper($results);
#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={};
my $found=0;
for my $event (@$events){
my $image=$event->{image};
$image=~s/.*\///;
$images->{$image}=1;
$found++;
}
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
};
#print STDERR Dumper($query).Dumper($bind_values);
my $results=db::get($dbh, $query, $bind_values);
#print STDERR @$results."\n";
return $results;
}
#assign event to series
#TODO: manual assign needs to update automatic one
sub assign_event{
my $config=shift;
my $entry=shift;
#print STDERR Dumper($entry);
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(@$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(@$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}];
#print STDERR '<pre>'.$query.Dumper($bind_values).'</pre>';
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}];
#print STDERR '<pre>'.$query.Dumper($bind_values).'</pre>';
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 (@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 (@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={};
for my $event_id (@$event_ids){
$event_id_hash->{$event_id}=1;
}
#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);
my $found={};
#mark events found assigned to series
my $i=1;
for my $event (@$results){
#print "found event $i: $event->{event_id}\n";
$found->{$event->{event_id}}=1;
$i++;
}
#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 (@$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 @$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
}
);
#print STDERR Dumper(@$events);
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 @$events==0;
return 1;
}
# 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 (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;
print STDERR "remove recurrence\t'$event->{event_id}'\t'$event->{start}'\t'$event->{rerun}'\t'$event->{recurrence}'\t'$event->{key}'\n";
$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};
print STDERR "0\t'$event->{recurrence_count}'\t'$event->{event_id}'\t'$event->{start}'\t'$event->{rerun}'\t'$event->{recurrence}'\t'$event->{key}'\n";
# succeeding events are reruns
for (my $c=1; $c < scalar(@$events); $c++){
my $event=$events->[$c];
print STDERR "$c\t'$event->{recurrence_count}'\t'$event->{event_id}'\t'$event->{start}'\t'$event->{rerun}'\t'$event->{recurrence}'\t'$event->{key}'\n";
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=?
};
#print STDERR $update_sql."\n".Dumper($bind_values)."\n";
my $dbh=db::connect($config);
db::put($dbh, $update_sql, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;