From 077d9c5a5362d540d7b66a84e5532f5f9b2bebc9 Mon Sep 17 00:00:00 2001 From: Milan Date: Sat, 17 Mar 2018 13:38:36 +0100 Subject: [PATCH] add event creation batch, lib changes for past changes --- lib/calcms/aggregator.pm | 12 +- lib/calcms/auth.pm | 15 +- lib/calcms/calendar.pm | 5 +- lib/calcms/comments.pm | 12 +- lib/calcms/eventOps.pm | 198 +++++++++++++++- lib/calcms/events.pm | 174 ++++++++------ lib/calcms/images.pm | 7 + lib/calcms/mail.pm | 26 +++ lib/calcms/password_requests.pm | 253 +++++++++++++++++++++ lib/calcms/project.pm | 27 ++- lib/calcms/series.pm | 32 ++- lib/calcms/series_dates.pm | 32 ++- lib/calcms/series_events.pm | 26 ++- lib/calcms/studios.pm | 15 +- website/agenda/planung/requestPassword.cgi | 165 ++++++++++++++ 15 files changed, 885 insertions(+), 114 deletions(-) create mode 100644 lib/calcms/mail.pm create mode 100644 lib/calcms/password_requests.pm create mode 100644 website/agenda/planung/requestPassword.cgi diff --git a/lib/calcms/aggregator.pm b/lib/calcms/aggregator.pm index ec21f82..634a4b5 100644 --- a/lib/calcms/aggregator.pm +++ b/lib/calcms/aggregator.pm @@ -246,12 +246,20 @@ sub check_params{ my $previous_series=$params->{previous_series} || ''; if(($previous_series)&&($previous_series=~/(\d+)/)){ - $params->{event_id}=events::get_previous_event_of_series(undef, $config, $1); + $params->{event_id}=events::get_previous_event_of_series(undef, $config, { + event_id => $1, + exclude_projects => 1, + exclude_locations => 1, + }); } my $next_series=$params->{next_series} || ''; if(($next_series)&&($next_series=~/(\d+)/)){ - $params->{event_id}=events::get_next_event_of_series(undef, $config, $1); + $params->{event_id}=events::get_next_event_of_series(undef, $config, { + event_id => $1, + exclude_projects => 1, + exclude_locations => 1, + }); } my $event_id=$params->{event_id}||''; diff --git a/lib/calcms/auth.pm b/lib/calcms/auth.pm index 5eabc11..97bccf6 100644 --- a/lib/calcms/auth.pm +++ b/lib/calcms/auth.pm @@ -262,9 +262,17 @@ sub authenticate{ } sub show_login_form{ - my $user=shift||''; - my $uri=$ENV{HTTP_REFERER}||''; - my $message=shift||''; + my $user= shift || ''; + my $uri = $ENV{HTTP_REFERER} || ''; + my $message = shift || ''; + my $requestReset = ''; + + if (($user ne '') && ($message ne '')){ + $requestReset = qq{ + forgotten + }; + } + debug("show_login_form")if ($debug); print qq{Content-type:text/html @@ -337,6 +345,7 @@ sub show_login_form{ + $requestReset diff --git a/lib/calcms/calendar.pm b/lib/calcms/calendar.pm index 7038713..3a3a60f 100644 --- a/lib/calcms/calendar.pm +++ b/lib/calcms/calendar.pm @@ -184,7 +184,10 @@ sub get{ my $dbh=db::connect($config, $request); - my $used_days=events::get_by_date_range($dbh, $config, $start_date, $end_date); + my $used_days=events::get_by_date_range($dbh, $config, $start_date, $end_date,{ + exclude_projects => 1, + exclude_locations => 1, + }); my $used_day={}; for my $day(@$used_days){ $used_day->{$day->{start_date}}=1; diff --git a/lib/calcms/comments.pm b/lib/calcms/comments.pm index d1078e1..2f3927c 100644 --- a/lib/calcms/comments.pm +++ b/lib/calcms/comments.pm @@ -112,18 +112,18 @@ sub get_query{ my @conditions=(); my $bind_values=[]; - #exclude comments from config filter/exclude_locations + #exclude comments from config filter/locations_to_exclude if ( (defined $config->{filter}) - && (defined $config->{filter}->{exclude_locations}) + && (defined $config->{filter}->{locations_to_exclude}) ){ - my @exclude_locations=split(/[,\s]+/,$config->{filter}->{exclude_locations}); - my $exclude_locations=join(', ',map {'?'} @exclude_locations); + my @locations_to_exclude=split(/[,\s]+/,$config->{filter}->{locations_to_exclude}); + my $locations_to_exclude=join(', ',map {'?'} @locations_to_exclude); $from.=',calcms_events e'; push @conditions,'e.id=c.event_id'; - push @conditions,'e.location not in ('.$exclude_locations.')'; - for my $location (@exclude_locations){ + push @conditions,'e.location not in ('.$locations_to_exclude.')'; + for my $location (@locations_to_exclude){ push @$bind_values, $location; } } diff --git a/lib/calcms/eventOps.pm b/lib/calcms/eventOps.pm index 2039d6d..12ae8dc 100644 --- a/lib/calcms/eventOps.pm +++ b/lib/calcms/eventOps.pm @@ -2,9 +2,14 @@ package eventOps; use warnings "all"; use strict; +use uac; +use events; use series; use series_dates; use time; +use studios; +use series_events; +use user_stats; require Exporter; our @ISA = qw(Exporter); @@ -52,10 +57,11 @@ sub setAttributesFromSeriesTemplate{ } sub setAttributesFromSchedule{ - my $config=shift; - my $params=shift; - my $event=shift; + my $config = shift; + my $params = shift; + my $event = shift; + #print 'setAttributesFromSchedule:'.Dumper($params); #set attributes from schedule my $schedules=series_dates::get( $config, { @@ -134,3 +140,189 @@ sub getRecurrenceBaseId{ return $event->{event_id}; } +# get a new event for given series +sub getNewEvent{ + my $config = shift; + my $params = shift; + my $action = shift; + + + # check for missing parameters + my $required_fields = [ 'project_id', 'studio_id', 'series_id' ]; + push @$required_fields, 'start_date' if ( $action eq 'show_new_event_from_schedule' ); + + my $event = {}; + for my $attr (@$required_fields) { + unless ( defined $params->{$attr} ) { + uac::print_error( "missing " . $attr ); + return undef; + } + $event->{$attr} = $params->{$attr}; + } + + my $serie = eventOps::setAttributesFromSeriesTemplate( $config, $params, $event ); + + #print Dumper($params); + if ( $action eq 'show_new_event_from_schedule' ) { + eventOps::setAttributesFromSchedule( $config, $params, $event ); + } else { + eventOps::setAttributesForCurrentTime( $serie, $event ); + } + + if ( defined $params->{source_event_id} ) { + + #overwrite by existing event (rerun) + eventOps::setAttributesFromOtherEvent( $config, $params, $event ); + } + + $event = events::calc_dates( $config, $event ); + + if ( $serie->{has_single_events} eq '1' ) { + $event->{has_single_events} = 1; + $event->{series_name} = undef; + $event->{episode} = undef; + } + + #get next episode + $event->{episode} = series::get_next_episode( + $config, + { + project_id => $params->{project_id}, + studio_id => $params->{studio_id}, + series_id => $params->{series_id}, + } + ); + delete $event->{episode} if $event->{episode} == 0; + + $event->{disable_event_sync} = 1; + $event->{published} = 1; + $event->{new_event} = 1; + + return $event; +} + +# add user, action +sub createEvent{ + my $request = shift; + my $event = shift; + my $action = shift; + + my $config = $request->{config}; + my $permissions = $request->{permissions}; + my $user = $request->{user}; + + my $checklist = [ 'studio', 'user', 'create_events', 'studio_timeslots' ]; + if ( $action eq 'create_event_from_schedule' ) { + push @$checklist, 'schedule' if $action eq 'create_event_from_schedule'; + } + #use Data::Dumper; + #print Dumper($checklist); + #print Dumper($request); + #print Dumper($event); + + my $start = $event->{start_date}, + my $end = time::add_minutes_to_datetime( $event->{start_date}, $event->{duration} ); + #print Dumper($start); + #print Dumper($end); + + my $result = series_events::check_permission( + $request, + { + permission => 'create_event,create_event_of_series', + check_for => $checklist, + project_id => $event->{project_id}, + studio_id => $event->{studio_id}, + series_id => $event->{series_id}, + start_date => $event->{start_date}, + draft => $event->{draft}, + start => $start, + end => $end, + } + ); + + #print Dumper(" start_date => $event->{start_date}"); + unless ( $result eq '1' ) { + uac::print_error($result); + return undef; + } + + #get series name from series + my $series = series::get( + $config, + { + project_id => $event->{project_id}, + studio_id => $event->{studio_id}, + series_id => $event->{series_id}, + } + ); + if ( @$series != 1 ) { + uac::print_error("series not found"); + return undef; + } + my $serie = $series->[0]; + + #get studio location from studios + my $studios = studios::get( + $config, + { + project_id => $event->{project_id}, + studio_id => $event->{studio_id} + } + ); + unless ( defined $studios ) { + uac::print_error("studio not found"); + return undef; + } + unless ( @$studios == 1 ) { + uac::print_error("studio not found"); + return undef; + } + my $studio = $studios->[0]; + + $config->{access}->{write} = 1; + + #insert event content and save history + my $event_id = series_events::insert_event( + $config, + { + project_id => $event->{project_id}, + studio => $studio, + serie => $serie, + event => $event, + user => $user + } + ); + uac::print_error("could not insert event") if $event_id <= 0; + + #assign event to series + $result = series::assign_event( + $config, + { + project_id => $event->{project_id}, + studio_id => $event->{studio_id}, + series_id => $event->{series_id}, + event_id => $event_id + } + ); + uac::print_error("could not assign event") unless defined $result; + + #update recurrences + $event->{event_id} = $event_id; + series::update_recurring_events( $config, $event ); + + # update user stats + user_stats::increase( + $config, + 'create_events', + { + project_id => $event->{project_id}, + studio_id => $event->{studio_id}, + series_id => $event->{series_id}, + user => $user + } + ); + + return $event_id; +} + +return 1; diff --git a/lib/calcms/events.pm b/lib/calcms/events.pm index 9ebb864..2dc14e7 100644 --- a/lib/calcms/events.pm +++ b/lib/calcms/events.pm @@ -232,7 +232,7 @@ sub modify_results { $result->{rds_title} =~ s/\_{2,99}/\_/gi; $result->{rds_title} = substr( $result->{rds_title}, 0, 63 ); - # $result->{event_id}=$result->{id}; + #$result->{event_id}=$result->{id}; $result->{base_url} = $request->{base_url}; $result->{base_domain} = $config->{locations}->{base_domain}; @@ -246,20 +246,28 @@ sub modify_results { $result->{no_comment} = 1 if ( $result->{comment_count} == 0 ); #fix image url - - if ((defined $config->{permissions}->{hide_event_images}) && ($config->{permissions}->{hide_event_images} eq '1')){ - $result->{image} = $result->{series_image}; - $result->{image_label} = $result->{series_image_label}; + #$params->{exclude_event_images}=0 unless defined $params->{exclude_event_images}; + #if ($params->{exclude_event_images}==1){ + # if ( (defined $config->{permissions}->{hide_event_images}) && ($config->{permissions}->{hide_event_images} eq '1') ){ + # $result->{image} = $result->{series_image}; + # $result->{image_label} = $result->{series_image_label}; + # } + #} + + if ( defined $result->{image} ) { + my $url = $config->{locations}->{local_media_url}||''; + my $image = $result->{image}; + $result->{thumb_url} = $url.'/thumbs/'.$image; + $result->{icon_url} = $url.'/icons/'.$image; + $result->{image_url} = $url.'/images/'.$image; } - if ( defined $result->{image} ) { - my $url=$config->{locations}->{local_media_url}||''; - if (defined $result->{image}){ - my $image=$result->{image}; - $result->{thumb} = $url.'/thumbs/'.$image; - $result->{icon} = $url.'/icons/'.$image; - $result->{image} = $url.'/images/'.$image; - } + if ( defined $result->{series_image} ) { + my $url = $config->{locations}->{local_media_url}||''; + my $image = $result->{series_image}; + $result->{series_thumb_url} = $url.'/thumbs/'.$image; + $result->{series_icon_url} = $url.'/icons/'.$image; + $result->{series_image_url} = $url.'/images/'.$image; } $result->{location_css} = $result->{location} || ''; @@ -811,11 +819,11 @@ sub get_query { # exclude location my $exclude_location_cond = ''; - if ( $params->{no_exclude} ne '1' ) { - if ( $params->{exclude_locations} ne '' ) { - my @exclude_locations = split( /,/, $params->{exclude_locations} ); - $exclude_location_cond = 'location not in (' . join( ",", map { '?' } @exclude_locations ) . ')'; - for my $location (@exclude_locations) { + if ( $params->{exclude_locations} eq '1' ) { + if ( $params->{locations_to_exclude} ne '' ) { + my @locations_to_exclude = split( /,/, $params->{locations_to_exclude} ); + $exclude_location_cond = 'location not in (' . join( ",", map { '?' } @locations_to_exclude ) . ')'; + for my $location (@locations_to_exclude) { $location =~ s/^\s+//g; $location =~ s/\s+$//g; push @$bind_values, $location; @@ -825,11 +833,11 @@ sub get_query { # exclude project my $exclude_project_cond = ''; - if ( $params->{no_exclude} ne '1' ) { - if ( $params->{exclude_projects} ne '' ) { - my @exclude_projects = split( /,/, $params->{exclude_projects} ); - $exclude_project_cond = 'project not in (' . join( ",", map { '?' } @exclude_projects ) . ')'; - for my $project (@exclude_projects) { + if ( $params->{exclude_projects} eq '1' ) { + if ( $params->{projects_to_exclude} ne '' ) { + my @projects_to_exclude = split( /,/, $params->{projects_to_exclude} ); + $exclude_project_cond = 'project not in (' . join( ",", map { '?' } @projects_to_exclude ) . ')'; + for my $project (@projects_to_exclude) { $project =~ s/^\s+//g; $project =~ s/\s+$//g; push @$bind_values, $project; @@ -1202,10 +1210,11 @@ sub render { $template_parameters->{ 'project_' . $project->{name} } = 1 if ( $project->{name} ne '' ); - $template_parameters->{controllers} = $config->{controllers}, + $template_parameters->{controllers} = $config->{controllers}; + $template_parameters->{hide_event_images}=1 if $config->{permissions}->{hide_event_images} == 1; # use Data::Dumper;print STDERR Dumper($template_parameters)."\n"; - template::process( $_[0], $params->{template}, $template_parameters ); + template::process( $_[0], $params->{template}, $template_parameters ); return $_[0]; } @@ -1241,37 +1250,47 @@ sub setDefaultEventConditions { my $config = shift; my $conditions = $_[0]; my $bind_values = $_[1]; + my $options = $_[2]; + $options={} unless defined $options; # exclude projects - if ( ( defined $config->{filter} ) - && ( defined $config->{filter}->{exclude_projects} ) ) + if ( + ( defined $options->{exclude_projects} ) + && ( $options->{exclude_projects} == 1 ) + && ( defined $config->{filter} ) + && ( defined $config->{filter}->{projects_to_exclude} ) ) { - my @exclude_projects = - split( /,/, $config->{filter}->{exclude_projects} ); - push @$conditions, 'project not in (' . join( ",", map { '?' } @exclude_projects ) . ')'; - for my $project (@exclude_projects) { + my @projects_to_exclude = + split( /,/, $config->{filter}->{projects_to_exclude} ); + push @$conditions, 'project not in (' . join( ",", map { '?' } @projects_to_exclude ) . ')'; + for my $project (@projects_to_exclude) { push @$bind_values, $project; } } # exclude locations - if ( ( defined $config->{filter} ) - && ( defined $config->{filter}->{exclude_locations} ) ) + if ( + ( defined $options->{exclude_locations} ) + && ( $options->{exclude_locations} == 1 ) + && ( defined $config->{filter} ) + && ( defined $config->{filter}->{locations_to_exclude} ) ) { - my @exclude_locations = - split( /,/, $config->{filter}->{exclude_locations} ); - push @$conditions, 'location not in (' . join( ",", map { '?' } @exclude_locations ) . ')'; - for my $location (@exclude_locations) { + my @locations_to_exclude = + split( /,/, $config->{filter}->{locations_to_exclude} ); + push @$conditions, 'location not in (' . join( ",", map { '?' } @locations_to_exclude ) . ')'; + for my $location (@locations_to_exclude) { push @$bind_values, $location; } } } +# for local use only or add support for exclude_projects and exclude_locations sub getEventById { my $dbh = shift; my $config = shift; my $event_id = shift; + my $options = shift; $dbh = db::connect($config) unless defined $dbh; @@ -1281,7 +1300,7 @@ sub getEventById { push @$conditions, "id=?"; push @$bind_values, $event_id; - setDefaultEventConditions( $config, $conditions, $bind_values ); + setDefaultEventConditions( $config, $conditions, $bind_values, $options ); $conditions = join( ' and ', @$conditions ); my $query = qq{ @@ -1297,12 +1316,15 @@ sub getEventById { sub get_next_event_of_series { my $dbh = shift; my $config = shift; - my $event_id = shift; + my $options = shift; + + my $eventId = $options->{event_id}; + return undef unless defined $eventId; $dbh = db::connect($config) unless defined $dbh; - my $events = getEventById( $dbh, $config, $event_id ); - return undef unless @$events == 1; + my $events = getEventById( $dbh, $config, $eventId, $options ); + return undef unless scalar(@$events) == 1; my $event = $events->[0]; my $conditions = []; @@ -1314,7 +1336,7 @@ sub get_next_event_of_series { push @$conditions, "series_name=?"; push @$bind_values, $event->{series_name}; - setDefaultEventConditions( $config, $conditions, $bind_values ); + setDefaultEventConditions( $config, $conditions, $bind_values, $options ); $conditions = join( ' and ', @$conditions ); my $query = qq{ @@ -1334,12 +1356,14 @@ sub get_next_event_of_series { sub get_previous_event_of_series { my $dbh = shift; my $config = shift; - my $event_id = shift; + my $options = shift; + + my $eventId = $options->{event_id}; + return undef unless defined $eventId; $dbh = db::connect($config) unless defined $dbh; - - my $events = getEventById( $dbh, $config, $event_id ); - return undef unless @$events == 1; + my $events = getEventById( $dbh, $config, $eventId, $options ); + return undef unless scalar(@$events) == 1; my $event = $events->[0]; my $conditions = []; @@ -1351,7 +1375,7 @@ sub get_previous_event_of_series { push @$conditions, "series_name=?"; push @$bind_values, $event->{series_name}; - setDefaultEventConditions( $config, $conditions, $bind_values ); + setDefaultEventConditions( $config, $conditions, $bind_values, $options ); $conditions = join( ' and ', @$conditions ); my $query = qq{ @@ -1362,7 +1386,7 @@ sub get_previous_event_of_series { }; $events = db::get( $dbh, $query, $bind_values ); - return undef unless @$events == 1; + return undef unless scalar(@$events) == 1; return $events->[0]->{id}; } @@ -1371,12 +1395,13 @@ sub get_by_date_range { my $config = shift; my $start_date = shift; my $end_date = shift; + my $options = shift; my $conditions = []; push @$conditions, 'start_date between ? and ?'; my $bind_values = [ $start_date, $end_date ]; - setDefaultEventConditions( $config, $conditions, $bind_values ); + setDefaultEventConditions( $config, $conditions, $bind_values, $options ); $conditions = join( ' and ', @$conditions ); @@ -1605,28 +1630,33 @@ sub check_params { } #if no location is set, use exclude location filter from default config - my $exclude_locations = ''; + my $locations_to_exclude = ''; if ( ( $location eq '' ) && ( defined $config->{filter} ) - && ( defined $config->{filter}->{exclude_locations} ) ) + && ( defined $config->{filter}->{locations_to_exclude} ) ) { - $exclude_locations = $config->{filter}->{exclude_locations} || ''; - $exclude_locations =~ s/\s+/ /g; + $locations_to_exclude = $config->{filter}->{locations_to_exclude} || ''; + $locations_to_exclude =~ s/\s+/ /g; } - my $exclude_projects = ''; + my $projects_to_exclude = ''; if ( ( defined $config->{filter} ) - && ( defined $config->{filter}->{exclude_projects} ) ) + && ( defined $config->{filter}->{projects_to_exclude} ) ) { - $exclude_projects = $config->{filter}->{exclude_projects} || ''; - $exclude_projects =~ s/\s+/ /g; + $projects_to_exclude = $config->{filter}->{projects_to_exclude} || ''; + $projects_to_exclude =~ s/\s+/ /g; } - #disable exclude filter by 'no_exlude=1' - my $no_exclude = ''; - $no_exclude = '1' - if ( ( defined $params->{no_exclude} ) - && ( $params->{no_exclude} eq '1' ) ); + + #enable exclude locations filter + my $exclude_locations = 0; + $exclude_locations = 1 if ( defined $params->{exclude_locations} ) && ( $params->{exclude_locations} eq '1' ) ; + + my $exclude_projects = 0; + $exclude_projects = 1 if ( defined $params->{exclude_projects} ) && ( $params->{exclude_projects} eq '1' ) ; + + my $exclude_event_images = 0; + $exclude_event_images = 1 if ( defined $params->{exclude_event_images} ) && ( $params->{exclude_event_images} eq '1' ) ; #show future events by default my $archive = 'future'; @@ -1670,7 +1700,7 @@ sub check_params { #print STDERR $params->{template}."\n"; my $template = '.html'; - if ( $params->{template} eq 'no' ) { + if ( ( defined $params->{template} ) && ($params->{template} eq 'no') ) { $template = 'no'; } else { $template = template::check( $params->{template}, 'event_list.html' ); @@ -1690,7 +1720,7 @@ sub check_params { my $default_project = undef; my $projects = project::get( $config, { name => $project_name } ); log::error( $config, "no configuration found for project '$project_name'" ) - unless ( @$projects == 1 ); + unless ( scalar(@$projects) == 1 ); $default_project = $projects->[0]; # get project from parameter (by name) @@ -1702,7 +1732,7 @@ sub check_params { my $project_name = $params->{project}; my $projects = project::get( $config, { name => $project_name } ); log::error( $config, 'invalid project ' . $project_name ) - unless @$projects == 1; + unless scalar(@$projects) == 1; $project = $projects->[0]; } @@ -1759,12 +1789,14 @@ sub check_params { studio_id => $studio_id, json_callback => $json_callback, get => $get, - exclude_locations => $exclude_locations, - exclude_projects => $exclude_projects, - no_exclude => $no_exclude, - disable_event_sync => $disable_event_sync, - extern => $extern, - recordings => $recordings, + locations_to_exclude => $locations_to_exclude, + projects_to_exclude => $projects_to_exclude, + exclude_locations => $exclude_locations, + exclude_projects => $exclude_projects, + exclude_event_images => $exclude_event_images, + disable_event_sync => $disable_event_sync, + extern => $extern, + recordings => $recordings, }; #print STDERR Dumper($checked); diff --git a/lib/calcms/images.pm b/lib/calcms/images.pm index 8fb0c88..5d81a33 100644 --- a/lib/calcms/images.pm +++ b/lib/calcms/images.pm @@ -364,6 +364,13 @@ sub getInternalPath{ return $path; } +sub normalizeName{ + my $name = shift; + return undef unless defined $name; + $name =~s/.*\///g; + return $name; +} + sub readFile{ my $path=shift; my $content=''; diff --git a/lib/calcms/mail.pm b/lib/calcms/mail.pm new file mode 100644 index 0000000..fe44a04 --- /dev/null +++ b/lib/calcms/mail.pm @@ -0,0 +1,26 @@ +package mail; + +use MIME::Lite; + +sub send { + my $mail = shift; + + my $msg = MIME::Lite->new( + 'From' => $mail->{'From'}, + 'To' => $mail->{'To'}, + 'Cc' => $mail->{'Cc'}, + 'Reply-To' => $mail->{'Reply-To'}, + 'Subject' => $mail->{'Subject'}, + 'Data' => $mail->{'Data'}, + ); + + #print '
';
+    $msg->print( \*STDERR );
+    #print '
'; + + $msg->send; +} + + +# do not delete next line +return 1; diff --git a/lib/calcms/password_requests.pm b/lib/calcms/password_requests.pm new file mode 100644 index 0000000..7640287 --- /dev/null +++ b/lib/calcms/password_requests.pm @@ -0,0 +1,253 @@ +package password_requests; + +use warnings "all"; +use strict; + +use Data::Dumper; +use Session::Token; + +# table: calcms_password_requests +require Exporter; +our @ISA = qw(Exporter); +our @EXPORT_OK = qw(get insert delete get_columns); +our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] ); + +use mail; +use uac; +use db; +use auth; + +sub debug; + +sub get_columns{ + my $config=shift; + + my $dbh=db::connect($config); + my $cols=db::get_columns($dbh, 'calcms_password_requests'); + my $columns={}; + for my $col (@$cols){ + $columns->{$col}=1; + } + return $columns; +} + +sub get{ + my $config=shift; + my $condition=shift; + + my $dbh=db::connect($config); + + my @conditions=(); + my @bind_values=(); + + if (defined $condition->{user}){ + push @conditions, 'user=?'; + push @bind_values, $condition->{user}; + } + + if (defined $condition->{token}){ + push @conditions, 'token=?'; + push @bind_values, $condition->{token}; + } + + return undef if (scalar @conditions) == 0; + + my $conditions=" where ".join(" and ",@conditions); + my $query=qq{ + select * + from calcms_password_requests + $conditions + }; + #print $query."\n".Dumper(\@bind_values); + + my $entries=db::get($dbh, $query, \@bind_values); + return $entries->[0] || undef; +} + +sub update{ + my $config=shift; + my $entry=shift; + + return unless defined $entry->{user}; + + my $dbh=db::connect($config); + my $values = join(",", map {$_.'=?'} (keys %$entry)); + my @bind_values = map {$entry->{$_}} (keys %$entry); + push @bind_values, $entry->{token}; + + my $query=qq{ + update calcms_password_requests + set $values + where token=? + }; + print STDERR $query . Dumper(\@bind_values); + db::put($dbh, $query, \@bind_values); +} + + +sub insert{ + my $config=shift; + my $entry=shift; + + return undef unless defined $entry->{user}; + + my $dbh=db::connect($config); + print STDERR 'insert ' . Dumper($entry); + return db::insert($dbh, 'calcms_password_requests', $entry); +} + +sub delete{ + my $config=shift; + my $condition=shift; + + my @conditions=(); + my @bind_values=(); + + if ((defined $condition->{user}) && ($condition->{user} ne '')){ + push @conditions, 'user=?'; + push @bind_values, $condition->{user}; + } + + if ((defined $condition->{token}) && ($condition->{token} ne '')){ + push @conditions, 'token=?'; + push @bind_values, $condition->{token}; + } + + return if (scalar @conditions)==0; + my $conditions=" where ".join(" and ", @conditions); + + my $dbh=db::connect($config); + + my $query=qq{ + delete + from calcms_password_requests + $conditions + }; + + print STDERR "$query " . Dumper(\@bind_values); + db::put($dbh, $query, \@bind_values); +} + +sub sendToken{ + my $config=shift; + my $entry=shift; + + return undef unless defined $entry->{user}; + + my $user = uac::get_user($config, $entry->{user}); + return undef unless defined $user; + + # check age of existing entry + my $oldEntry = password_requests::get($config, { user => $entry->{user} } ); + if (defined $oldEntry){ + my $createdAt = $oldEntry->{created_at}; + print STDERR Dumper($oldEntry); + print STDERR "createdAt=$createdAt\n"; + my $age = time() - time::datetime_to_time($createdAt); + if ($age < 60) { + print STDERR "too many requests"; + return undef; + } + print STDERR "age=$age\n"; + } + password_requests::delete($config, $entry); + + $entry->{max_attempts} = 0; + $entry->{token} = Session::Token->new->get; + + my $baseUrl = $config->{locations}->{source_base_url} . $config->{locations}->{editor_base_url}; + my $url = $baseUrl."/requestPassword.cgi?token=" . $entry->{token}; + my $content = "Hi,$user->{full_name}\n\n"; + $content .= "Someone just tried to reset your password for $baseUrl.\n\n"; + $content .= "If you like to set a new password, please follow the link below\n"; + $content .= $url."\n\n"; + $content .= "If you do not like to set a new password, please ignore this mail.\n"; + + mail::send({ + "To" => $user->{email}, + "Subject" => "request to change password for $baseUrl", + "Data" => $content + }); + + password_requests::insert($config, $entry); +} + +sub changePassword { + my $config = shift; + my $request = shift; + my $userName = shift; + + my $params = $request->{params}->{checked}; + my $permissions = $request->{permissions}; + + unless ( ( defined $userName ) || ( $userName eq '' ) ) { + return { error => 'user not found' }; + } + + my $user = uac::get_user( $config, $userName ); + + unless ( ( defined $user ) && ( defined $user->{id} ) && ( $user->{id} ne '' ) ) { + return { error => 'user id not found' }; + } + + unless ( password_requests::checkPassword( $params->{user_password} ) ) { + return { error => 'password does not meet requirements' }; + } + + if ( $params->{user_password} ne $params->{user_password2} ) { + return { error => 'entered passwords do not match'}; + } + + #print STDERR "error at changing password:" . Dumper($errors); + + my $crypt = auth::crypt_password( $params->{user_password} ); + $user = { id => $user->{id} }; + $user->{salt} = $crypt->{salt}; + $user->{pass} = $crypt->{crypt}; + + #print '
'.Dumper($user).'
'; + $config->{access}->{write} = 1; + print STDERR "update user".Dumper($user); + my $result = uac::update_user( $config, $user ); + print STDERR "result:".Dumper($result); + $config->{access}->{write} = 0; + return { success => "password changed for $userName" }; +} + +sub checkPassword { + my $password = shift; + unless ( defined $password || $password eq '' ) { + error("password is empty"); + return; + } + if ( length($password) < 8 ) { + error("password to short"); + return 0; + } + unless ( $password =~ /[a-z]/ ) { + error("password should contains at least one small character"); + return 0; + } + unless ( $password =~ /[A-Z]/ ) { + error("password should contains at least one big character"); + return 0; + } + unless ( $password =~ /[0-9]/ ) { + error("password should contains at least one number"); + return 0; + } + unless ( $password =~ /[^a-zA-Z0-9]/ ) { + error("password should contains at least one special character"); + return 0; + } + return 1; +} + + +sub error{ + my $msg=shift; + print "ERROR: $msg
\n"; +} + +#do not delete last line! +1; diff --git a/lib/calcms/project.pm b/lib/calcms/project.pm index a6fb181..777eb06 100644 --- a/lib/calcms/project.pm +++ b/lib/calcms/project.pm @@ -1,14 +1,17 @@ #!/bin/perl package project; + use warnings "all"; use strict; use Data::Dumper; use Date::Calc; + use config; use log; use template; +use images; require Exporter; our @ISA = qw(Exporter); @@ -109,23 +112,16 @@ sub insert{ my $columns=get_columns($config); my $project={}; for my $column (keys %$columns){ - $project->{$column}=$entry->{$column} if defined $entry->{$column}; + $project->{$column} = $entry->{$column} if defined $entry->{$column}; } + $project->{image} = images::normalizeName( $project->{image} ) if defined $project->{image}; + my $dbh=db::connect($config); my $id=db::insert($dbh, 'calcms_projects', $project); return $id; } -# delete project -sub delete{ - my $config=shift; - my $entry=shift; - - my $dbh=db::connect($config); - db::put($dbh, 'delete from calcms_projects where project_id=?', [$entry->{project_id}]); -} - # update project sub update{ my $config=shift; @@ -137,6 +133,8 @@ sub update{ $entry->{$column}=$project->{$column} if defined $project->{$column}; } + $entry->{image} = images::normalizeName( $entry->{image} ) if defined $entry->{image}; + my $values =join(",", map {$_.'=?'} (keys %$entry)); my @bind_values =map {$entry->{$_}} (keys %$entry); push @bind_values,$entry->{project_id}; @@ -151,6 +149,15 @@ sub update{ db::put($dbh, $query, \@bind_values); } +# delete project +sub delete{ + my $config=shift; + my $entry=shift; + + my $dbh=db::connect($config); + db::put($dbh, 'delete from calcms_projects where project_id=?', [$entry->{project_id}]); +} + # get studios of a project sub get_studios{ diff --git a/lib/calcms/series.pm b/lib/calcms/series.pm index 97275c4..38eea9c 100644 --- a/lib/calcms/series.pm +++ b/lib/calcms/series.pm @@ -2,8 +2,12 @@ package series; use warnings "all"; use strict; + use Data::Dumper; + use events; +use images; + require Exporter; our @ISA = qw(Exporter); @@ -136,15 +140,16 @@ sub insert{ 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 $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->{$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()); @@ -179,6 +184,7 @@ sub update{ 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()); @@ -522,7 +528,18 @@ sub get_events{ 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); + #print STDERR Dumper($results); + + $results=events::modify_results( + $dbh, $config, { + base_url => '', + params => { + checked => { + template => '' + } + } + } , $results + ); #add studio id to events my $studios=studios::get($config, $options); @@ -552,7 +569,7 @@ sub get_event{ my $event_id = $options->{event_id} ||''; my $draft = $options->{draft} ||''; - unless(defined($options->{allow_any})){ + unless(defined $options->{allow_any} ){ if ($project_id eq''){ uac::print_error("missing project_id"); return undef; @@ -580,18 +597,19 @@ sub get_event{ $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){ + if(scalar(@$events)==0){ uac::print_error("event not found"); return undef; } - if(@$events>1){ + if(scalar(@$events)>1){ print STDERR q{multiple assignments found for } .q{project_id=}.$options->{project_id} .q{, studio_id=}.$options->{studio_id} diff --git a/lib/calcms/series_dates.pm b/lib/calcms/series_dates.pm index e6f5353..3df09a9 100644 --- a/lib/calcms/series_dates.pm +++ b/lib/calcms/series_dates.pm @@ -540,11 +540,41 @@ sub delete{ from calcms_series_dates where project_id=? and studio_id=? and series_id=? }; - my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{series_id}]; + my $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{series_id} ]; #print '
$query'.$query.Dumper($bind_values).'
'; db::put($dbh, $query, $bind_values); } +# get all series dates where no event has been created for +sub getDatesWithoutEvent{ + my $config = shift; + my $options = shift; + + return unless defined $options->{project_id}; + return unless defined $options->{studio_id}; + return unless defined $options->{from}; + return unless defined $options->{till}; + + my $dbh=db::connect($config); + + my $query=q{ + SELECT sd.* + FROM calcms_series_dates sd LEFT JOIN calcms_events e + on (sd.start = e.start) + where e.start is null + and sd.exclude != 1 + and sd.project_id = ? + and sd.studio_id = ? + and sd.start > ? + and sd.end < ? + order by sd.start + }; + + my $bind_values = [ $options->{project_id}, $options->{studio_id}, $options->{from}, $options->{till} ]; + my $entries = db::get($dbh, $query, $bind_values); + return $entries; + +} sub error{ my $msg=shift; diff --git a/lib/calcms/series_events.pm b/lib/calcms/series_events.pm index 7e9d9d2..328bf08 100644 --- a/lib/calcms/series_events.pm +++ b/lib/calcms/series_events.pm @@ -17,6 +17,8 @@ use series_dates; use studios; use studio_timeslot_dates; use event_history; +use images; + # check permissions, insert and update events related to series @@ -46,10 +48,15 @@ sub save_content{ return undef unless(defined $entry->{id}); for my $attr (keys %$entry){ + next unless defined $entry->{$attr}; $entry->{$attr}=~s/^\s+//g; $entry->{$attr}=~s/\s+$//g; } + for my $attr ('image', 'series_image'){ + $entry->{$attr} = images::normalizeName($entry->{$attr}) if defined $entry->{$attr}; + } + #print STDERR Dumper(\$entry->{content}); for my $attr ('content', 'topic'){ if (defined $entry->{$attr}){ @@ -60,7 +67,7 @@ sub save_content{ } } - #print STDERR Dumper(\$entry->{html_content}); + #print STDERR Dumper(\$entry->{series_image}); #print STDERR "ok2\n"; #return; $entry->{modified_at}= time::time_to_datetime(time()); @@ -93,8 +100,15 @@ sub save_content{ where id=? }; - #print STDERR $query.Dumper(\@bind_values); - db::put($dbh, $query, \@bind_values); + #print STDERR "update:".$query.Dumper(\@bind_values); + my $result=db::put($dbh, $query, \@bind_values); + unless (defined $result){ + print STDERR "error on updating event\n" ; + return undef; + } + + #print STDERR "result=$result\n"; + #print STDERR "entr after update".Dumper($entry); return $entry; } @@ -410,14 +424,14 @@ sub insert_event{ #get event content from series for my $attr ('program', 'series_name', 'title', 'excerpt', 'content', 'topic', 'image', 'episode', 'podcast_url', 'archive_url'){ - $event->{$attr}=$serie->{$attr} if defined $serie->{$attr}; + $event->{$attr} = $serie->{$attr} if defined $serie->{$attr}; } $event->{series_image} = $serie->{image} if defined $serie->{image}; $event->{series_image_label} = $serie->{licence} if defined $serie->{licence}; #overwrite series values from parameters for my $attr ('program', 'series_name', 'title', 'user_title', 'excerpt', 'user_except', 'content', 'topic', 'image', 'episode', 'podcast_url', 'archive_url'){ - $event->{$attr}=$params->{$attr} if defined $params->{$attr}; + $event->{$attr} = $params->{$attr} if defined $params->{$attr}; } $event->{'html_content'} = markup::creole_to_html($event->{'content'}) if defined $event->{'content'}; $event->{'html_topic'} = markup::creole_to_html($event->{'topic'}) if defined $event->{'topic'}; @@ -475,6 +489,8 @@ sub update_series_images{ return "missing studio_id" unless defined $options->{studio_id}; return "missing series_id" unless defined $options->{series_id}; return "missing series_image" unless defined $options->{series_image}; + + #print "save $options->{series_image}\n"; my $events=series::get_events( $config, { diff --git a/lib/calcms/studios.pm b/lib/calcms/studios.pm index 8b7edfa..99fa98e 100644 --- a/lib/calcms/studios.pm +++ b/lib/calcms/studios.pm @@ -1,16 +1,19 @@ #!/bin/perl -use CGI; +#use CGI; #use CGI::Carp qw(warningsToBrowser fatalsToBrowser); -use CGI::Session qw(-ip-match); -use CGI::Cookie; +#use CGI::Session qw(-ip-match); +#use CGI::Cookie; #$CGI::Session::IP_MATCH=1; package studios; use warnings "all"; use strict; + use Data::Dumper; +use images; + require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(get_columns get get_by_id insert update delete check check_studio); @@ -96,8 +99,9 @@ sub insert{ my $config=shift; my $entry=shift; - $entry->{created_at} = time::time_to_datetime(time()); - $entry->{modified_at}= time::time_to_datetime(time()); + $entry->{created_at} = time::time_to_datetime(time()); + $entry->{modified_at} = time::time_to_datetime(time()); + $entry->{image} = images::normalizeName( $entry->{image} ) if defined $entry->{image}; my $dbh=db::connect($config); my $id=db::insert($dbh, 'calcms_studios', $entry); @@ -116,6 +120,7 @@ sub update{ for my $column (keys %$columns){ $entry->{$column}=$studio->{$column} if defined $studio->{$column}; } + $entry->{image} = images::normalizeName( $entry->{image} ) if defined $entry->{image}; my $values =join(",", map {$_.'=?'} (keys %$entry)); my @bind_values =map {$entry->{$_}} (keys %$entry); diff --git a/website/agenda/planung/requestPassword.cgi b/website/agenda/planung/requestPassword.cgi new file mode 100644 index 0000000..3b99163 --- /dev/null +++ b/website/agenda/planung/requestPassword.cgi @@ -0,0 +1,165 @@ +#! /usr/bin/perl -w + +use warnings "all"; +use strict; + +use Data::Dumper; + +use params; +use config; +use db; +use auth; +use password_requests; + +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}; + +$params = check_params($params); + +print "Content-type:text/html\n\n"; +print qq{ + + + + + +}; + +if ( defined $params->{user}){ + sendToken($config, $params); + return; +}else{ + my $result=checkToken($config, $params); + return; +} + +sub sendToken{ + my $config=shift; + my $params=shift; + my $entry = password_requests::sendToken($config, { user => $params->{user} }); + if (defined $entry){ + print "Please check you mails\n" + }else{ + print "Sorry\n"; + } +} + +sub checkToken{ + my $config=shift; + my $params=shift; + + my $token = $params->{token}; + + my $entry = password_requests::get($config, { token => $token }); + unless (defined $entry){ + print "invalid token\n"; + return undef; + } + + print STDERR Dumper($entry); + my $created_at = $entry->{created_at}; + unless (defined $created_at){ + print "invalid token age\n"; + return undef; + } + + my $age = time() - time::datetime_to_time($created_at); + if ($age > 600) { + print "token is too old\n"; + password_requests::delete($config, { token => $token }); + return undef; + } + + $config->{access}->{write} = 1; + $entry->{max_attempts}++; + password_requests::update($config, $entry); + $config->{access}->{write} = 0; + + if ($entry->{max_attempts}>10){ + print "too many failed attempts, please request a new token by mail\n"; + password_requests::delete($config, { token => $token }); + return undef; + } + + unless ((defined $params->{user_password}) && (defined $params->{user_password2})){ + printForm($token); + return undef; + } + + if ($params->{action} eq 'change'){ + my $user = $entry->{user}; + my $request = { + config => $config, + params => { checked => $params } + }; + my $result = password_requests::changePassword($config, $request, $user); + + if (defined $result->{error}){ + #print "sorry\n"; + print $result->{error}."\n"; + printForm($token); + } + + if (defined $result->{success}){ + #print "success\n"; + print $result->{success}."\n"; + password_requests::delete($config, { user => $user }); + my $url=$config->{locations}->{editor_base_url}; + print qq{ + + }; + } + } + +} + +sub printForm{ + my $token=shift; + print qq{ +
+ + + + +
+ }; + +} + +sub check_params { + my $params = shift; + + my $checked = {}; + + #my $template = ''; + #$checked->{template} = template::check( $params->{template}, 'requestPassword' ); + + my $debug = $params->{debug} || ''; + if ( $debug =~ /([a-z\_\,]+)/ ) { + $debug = $1; + } + $checked->{debug} = $debug; + + for my $param ( 'user','token', 'user_password', 'user_password2' ) { + if ( ( defined $params->{$param} ) && ( $params->{$param} =~ /\S/ ) ) { + $checked->{$param} = $params->{$param}; + } + } + + $checked->{action} = ''; + if ( defined $params->{action} ) { + if ( $params->{action} =~ /^(change)$/ ) { + $checked->{action} = $params->{action}; + } + } + + return $checked; +} +