copy current state of medienstaatsvertrag.org, to be verified

This commit is contained in:
Milan
2017-12-18 10:58:50 +01:00
parent 8b35e7c5c2
commit 69e5d0e4c6
401 changed files with 74197 additions and 0 deletions

45
lib/calcms/UTF8DBI.pm Normal file
View File

@@ -0,0 +1,45 @@
# UTF8DBI.pm re-implementation by Pavel Kudinov http://search.cpan.org/~kudinov/
# originally from: http://dysphoria.net/code/perl-utf8/
# And patched again by Andrew Forrest, Jan 2007
use DBI 1.21;
use utf8;
use Encode;
package UTF8DBI; use base DBI;
sub _utf8_ {
if (ref $_ eq 'ARRAY') { _utf8_() foreach @$_ }
elsif (ref $_ eq 'HASH' ) { _utf8_() foreach values %$_ }
else {
Encode::_utf8_on($_);
if (Encode::is_utf8($_) && ! Encode::is_utf8($_, 1)) {
#$_ = '⁂malformed-UTF8‼' #die "Malformed utf8 string in database"
#print data_string_desc($_)."\n"
#data_string_desc(STRING);
#Encode::decode_utf8($_);
#;
#Encode::_utf8_off($_);
#Encode::decode_utf8($_);
#Encode::encode_utf8($_);
}
};
$_;
};
package UTF8DBI::db; use base DBI::db;
sub selectrow_arrayref { return UTF8DBI::_utf8_ for shift->SUPER::selectrow_arrayref(@_) };
sub selectrow_hashref { return UTF8DBI::_utf8_ for shift->SUPER::selectrow_hashref (@_) };
sub selectall_arrayref { return UTF8DBI::_utf8_ for shift->SUPER::selectall_arrayref(@_) };
sub selectall_hashref { return UTF8DBI::_utf8_ for shift->SUPER::selectall_hashref (@_) };
sub selectcol_arrayref { return UTF8DBI::_utf8_ for shift->SUPER::selectcol_arrayref(@_) };
sub selectrow_array { @{shift->selectrow_arrayref(@_)} };
package UTF8DBI::st; use base DBI::st;
sub fetch { return UTF8DBI::_utf8_ for shift->SUPER::fetch (@_) };
1;

294
lib/calcms/aggregator.pm Normal file
View File

@@ -0,0 +1,294 @@
use warnings "all";
use strict;
use events;
use comments;
use calendar;
use project;
package aggregator;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_cache configure_cache put_cache get_list check_params);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#my $cgi=undef;
sub get_list{
my $config = shift;
my $request=shift;
my $params=$request->{params}->{checked};
my $debug=$config->{system}->{debug};
#customize prefiltered request parameters
$request->{params}->{original}->{date}=$request->{params}->{checked}->{date};
if ($params->{event_id}ne''){
$request->{params}->{original}->{template}='event_details.html';
}else{
$request->{params}->{original}->{template}='event_list.html';
}
$request->{params}->{checked} = events::check_params($config, $request->{params}->{original});
log::write($config, 'params',$request->{params}->{checked}) if ($debug);
my $content='';
my $results=events::get($config, $request);
events::render($content, $config, $request, $results);
# calendar::get_cached_or_render($content,$request);
#set url to embed as last loaded url in javascript
my $date=$params->{date}||'';
$date='heute' if ($params->{date}eq'today');
$date=$results->[0]->{day} if ($params->{event_id}ne'');
my $url='';
#$config->{controllers}->{events}.'/'.$date.'/';
if ($params->{from_date}ne'' && $params->{till_date}ne''){
$url=$config->{controllers}->{events}.'/'.$params->{from_date}.'/'.$params->{till_date} ;
}else{
$url=$config->{controllers}->{events}.'/'.$params->{from_date}.'/'.$params->{till_date} ;
}
#count most projects
my $used_projects={};
for my $result (@$results){
my $project=$result->{project_title}||'';
$used_projects->{$project}++;
}
my @used_projects=reverse sort {$used_projects->{$a} <=> $used_projects->{$b}} (keys %$used_projects);
my $most_used_project=$used_projects[0];
#use Data::Dumper;print STDERR Dumper(\@used_projects);
return {
day => $results->[0]->{day},
start_datetime => $results->[0]->{start_datetime},
event_id => $results->[0]->{event_id},
program => $results->[0]->{program},
project_title => $most_used_project,
series_name => $results->[0]->{series_name},
title => $results->[0]->{title},
content => $content,
results => $results,
url => $url,
};
}
sub get_menu{
my $config = shift;
my $request=shift;
my $date=shift;
my $results=shift;
my $params=$request->{params}->{checked};
#load details only on demand
if ($params->{event_id}ne''){
$request->{params}->{original}->{template}='event_menu.html';
$request->{params}->{original}->{event_id}=undef;
$request->{params}->{original}->{date}=$date;
$request->{params}->{checked} =events::check_params($config, $request->{params}->{original});
$results=events::get($config, $request);
}else{
$request->{params}->{checked}->{template}=template::check('event_menu.html');
}
#events menu
my $output='';
events::render($output, $config, $request, $results);
return {
content => $output
};
}
sub get_calendar{
my $config = shift;
my $request=shift;
my $date=shift;
my $params=$request->{params}->{checked};
my $debug=$config->{system}->{debug};
$request->{params}->{original}->{template} = 'calendar.html';
$request->{params}->{original}->{date} = $date if (defined $date);
$request->{params}->{checked} = calendar::check_params($config, $request->{params}->{original});
$params = $request->{params}->{checked};
log::write($config, 'params',$params) if ($debug);
#set query string for caching
my $options=[];
push (@$options,'date='.$params->{date}) if ($params->{date} ne'');
push (@$options,'from_date='.$params->{from_date}) if ($params->{from_date} ne'');
push (@$options,'till_date='.$params->{till_date}) if ($params->{till_date} ne'');
$ENV{QUERY_STRING}=''.join("&",@$options);
my $content='';
calendar::get_cached_or_render($content, $config, $request);
return {
content => $content
};
}
sub get_newest_comments{
my $config = shift;
my $request=shift;
my $params={
template =>'comments_newest.html',
limit => 10,
type =>'list',
show_max => 3
};
$request={
url => $ENV{QUERY_STRING},
params => {
original => $params,
checked => comments::check_params($config, $params),
},
config => $config,
connection => $request->{connection}
};
my $content='';
comments::get_cached_or_render($content, $config, $request);
return {
content => $content
};
}
sub get_cache{
my $config = shift;
my $request = shift;
my $params =$request->{params}->{checked};
my $debug=$config->{system}->{debug};
if ($config->{cache}->{use_cache} == 1){
configure_cache($config);
log::write($config, 'cache_files',cache::get_map()) if ($debug);
my $cache=cache::load($config, $params);
log::write($config, 'cache_files',$cache->{action}) if ($debug);
return $cache;
}
return{};
}
sub configure_cache{
my $config = shift;
cache::init();
my $controllers=$config->{controllers};
my $date_pattern=$cache::date_pattern;
# cache::add_map('' ,'programm/index.html');
cache::add_map('date=today' ,'programm/'.$controllers->{events}.'/today.html');
cache::add_map('date='.$date_pattern ,'programm/'.$controllers->{events}.'/$1-$2-$3.html');
cache::add_map('from_date='.$date_pattern.'&till_date='.$date_pattern ,'programm/'.$controllers->{events}.'/$1-$2-$3_$4-$5-$6.html');
cache::add_map('event_id=(\d+)' ,'programm/'.$controllers->{event}.'/$1.html');
}
sub put_cache{
my $config = shift;
my $request = shift;
my $cache = shift;
#write to cache
if ($config->{cache}->{use_cache} == 1){
cache::save($cache);
}
}
sub check_params{
my $config = shift;
my $params = shift;
#get start and stop from projects
my $range= project::get_date_range($config);
my $start_date = $range->{start_date};
my $end_date = $range->{end_date};
# my $project_name=$config->{project}||'';
# log::error($config, 'no default project configured') if($project_name eq '');
# log::error($config, "no configuration found for project '$project_name'") unless(exists($config->{projects}->{$project_name}));
# my $project=$config->{projects}->{$project_name}||'';
# log::erorr($config, 'no configuration found for project') if($project eq'');
# if ((defined $params->{project}) && ($params->{project}=~/(\w+)/)){
# $project=$config->{projects}->{$1} if exists($config->{projects}->{$1});
# }
#filter for date
my $date=time::check_date($params->{date});
#print STDERR $date."\n";
if ($date eq ''){
$date=time::time_to_date(time()) ;
}
#
if ($date eq 'today'){
$date=time::get_event_date($config);
}
# $date =$config->{date}->{start_date} if ($date lt $config->{date}->{start_date});
# $date =$config->{date}->{end_date} if ($date gt $config->{date}->{end_date});
$date =$start_date if $date lt $start_date;
$date =$end_date if $date gt $end_date;
#filter for date
# my $date=time::check_date($params->{date});
my $time=time::check_time($params->{time});
if ((defined $params->{today}) && ($params->{today}eq'1')){
$date =time::time_to_date(time());
$params->{date}=$date;
};
my $from_date=time::check_date($params->{from_date});
my $till_date=time::check_date($params->{till_date});
my $previous_series=$params->{previous_series} || '';
if(($previous_series)&&($previous_series=~/(\d+)/)){
$params->{event_id}=events::get_previous_event_of_series(undef, $config, $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);
}
my $event_id=$params->{event_id}||'';
unless ($event_id eq''){
if ($event_id=~/(\d+)/){
$event_id=$1;
}else{
log::error($config, "invalid event_id");
}
}
my $debug=$params->{debug}||'';
if ($debug=~/([a-z\_\,]+)/){
$debug=$1;
}
#set query string for caching
if ((!exists $ENV{QUERY_STRING}) || ($ENV{QUERY_STRING}eq'')){
my $options=[];
push (@$options,'date='.$date) if $date ne'';
push (@$options,'from_date='.$from_date) if $from_date ne'';
push (@$options,'till_date='.$till_date) if $till_date ne'';
push (@$options,'event_id='.$event_id) if $event_id ne'';
$ENV{QUERY_STRING}=''.join("&",@$options);
}
return {
date => $date,
time => $time,
from_date => $from_date,
till_date => $till_date,
event_id => $event_id,
# project => $project,
debug => $debug,
};
;
}
#do not delete last line!
1;

View File

@@ -0,0 +1,180 @@
#!/bin/perl
package audio_recordings;
use warnings "all";
use strict;
use Data::Dumper;
use db;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
# columns:
# id, project_id, studio_id, event_id
# created_by, created_at
# path, md5
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_audio_recordings');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get playout entries
sub get{
my $config = shift;
my $condition = shift;
return undef unless defined $condition->{project_id};
return undef unless defined $condition->{studio_id};
my $date_range_include=0;
$date_range_include=1 if (defined $condition->{date_range_include}) && ($condition->{date_range_include}==1);
my $dbh=db::connect($config);
my $conditions=[];
my $bind_values=[];
if ((defined $condition->{id}) && ($condition->{id} ne '')){
push @$conditions, 'id=?';
push @$bind_values, $condition->{id};
}
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->{event_id}) && ($condition->{event_id} ne '')){
push @$conditions, 'event_id=?';
push @$bind_values, $condition->{event_id};
}
if ((defined $condition->{path}) && ($condition->{path} ne '')){
push @$conditions, 'path=?';
push @$bind_values, $condition->{path};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $whereClause='';
$whereClause=" where ".join(" and ",@$conditions) if (scalar @$conditions>0);
my $query=qq{
select id
,project_id
,studio_id
,event_id
,path
,md5
,size
,created_by
,created_at
from calcms_audio_recordings
$whereClause
order by created_at desc
};
print STDERR Dumper($query).Dumper($bind_values);
my $entries=db::get($dbh, $query, $bind_values);
return $entries;
}
# update playout entry if differs to old values
sub update{
my $config = shift;
my $dbh = shift;
my $entry = shift;
print STDERR "update:".Dumper($entry);
my $day_start=$config->{date}->{day_starting_hour};
my $bind_values=[
$entry->{path}, $entry->{md5}, $entry->{size}, $entry->{created_by}, $entry->{created_at},
$entry->{project_id}, $entry->{studio_id}, $entry->{event_id}
];
my $query=qq{
update calcms_audio_recordings
set path=?, md5=?, size=?, created_by=?, created_at=?
where project_id=? and studio_id=? and event_id=?
};
print STDERR Dumper($query).Dumper($bind_values);
return db::put($dbh, $query, $bind_values);
}
# insert playout entry
sub insert{
my $config = shift;
my $dbh = shift;
my $entry = shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
return undef unless defined $entry->{event_id};
return undef unless defined $entry->{path};
print STDERR "insert into audio_recordings:".Dumper($entry);
return db::insert($dbh, 'calcms_audio_recordings', {
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
event_id => $entry->{event_id},
path => $entry->{path},
size => $entry->{size},
md5 => $entry->{md5},
created_by => $entry->{created_by},
});
}
# delete playout entry
sub delete{
my $config = shift;
my $dbh = shift;
my $entry = shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
return undef unless defined $entry->{event_id};
return undef unless defined $entry->{path};
my $query=qq{
delete
from calcms_audio_recordings
where project_id=? and studio_id=? and event_id=? and path=?
};
my $bind_values = [ $entry->{project_id}, $entry->{studio_id}, $entry->{event_id}, $entry->{path} ];
return db::put($dbh, $query, $bind_values);
}
sub error{
my $msg = shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

354
lib/calcms/auth.pm Normal file
View File

@@ -0,0 +1,354 @@
#!/bin/perl
use CGI;
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use CGI::Session qw(-ip-match);
use CGI::Cookie;
#$CGI::Session::IP_MATCH=1;
package auth;
use warnings "all";
use strict;
use Data::Dumper;
use Authen::Passphrase::BlowfishCrypt;
use time;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_user login logout crypt_password);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
my $defaultExpiration=60;
my $tmp_dir='/var/tmp/';
my $debug=0;
sub debug;
sub get_user{
my $cgi=shift;
my $config=shift;
my %parms=$cgi->Vars();
my $parms=\%parms;
debug("get_user")if ($debug);
# login or logout on action
if (defined $parms->{action}){
if ($parms->{action} eq 'login'){
my $user=login($cgi, $config, $parms->{user}, $parms->{password});
$cgi->delete('user','password','uri','action');
return $user;
}elsif($parms->{action} eq 'logout'){
logout($cgi);
$cgi->delete('user','password','uri','action');
return undef;
}
}
# read session id from cookie
my $session_id=read_cookie($cgi);
# login if no cookie found
return show_login_form($parms->{user}, 'Please login') unless defined $session_id;
# read session
my $session=read_session($session_id);
# login if user not found
return show_login_form($parms->{user}, 'unknown User') unless defined $session;
$parms->{user} = $session->{user};
$parms->{expires} = $session->{expires};
debug($parms->{expires});
return $session->{user}, $session->{expires};
}
sub crypt_password{
my $password=shift;
my $ppr = Authen::Passphrase::BlowfishCrypt->new(
cost => 8,
salt_random => 1,
passphrase => $password
);
return{
salt => $ppr->salt_base64,
crypt => $ppr->as_crypt
};
}
sub login{
my $cgi=shift;
my $config=shift;
my $user=shift;
my $password=shift;
debug("login")if ($debug);
#print STDERR "login $user $password\n";
my $result = authenticate($config, $user, $password);
#print STDERR Dumper($result);
return show_login_form($user,'Could not authenticate you') unless defined $result;
return unless defined $result->{login}eq '1';
my $timeout=$result->{timeout} || $defaultExpiration;
$timeout='+'.$timeout.'m';
my $session_id=create_session($user, $password, $timeout);
return $user if(create_cookie($cgi, $session_id, $timeout));
return undef;
}
sub logout{
my $cgi=shift;
my $session_id=read_cookie($cgi);
debug("logout")if ($debug);
unless(delete_session($session_id)){
return show_login_form('Cant delete session', 'logged out');
};
unless(delete_cookie($cgi)){
return show_login_form('Cant remove cookie', 'logged out');
}
my $uri=$ENV{HTTP_REFERER}||'';
$uri=~s/action=logout//g;
print $cgi->redirect($uri);
# return show_login_form('', 'logged out');
}
#read and write data from browser, http://perldoc.perl.org/CGI/Cookie.html
sub create_cookie{
my $cgi=shift;
my $session_id=shift;
my $timeout=shift;
#debug("create_cookie")if ($debug);
my $cookie = CGI::Cookie->new(
-name => 'sessionID',
-value => $session_id,
-expires => $timeout,
# -domain => '.capricorn.com',
# -path => '/agenda/admin/',
-secure => 1
);
print "Set-Cookie: ",$cookie->as_string,"\n";
print STDERR "#Set-Cookie: ",$cookie->as_string,"\n";
# print $cgi->header( -cookie => $cookie );
return 1;
}
sub read_cookie{
my $cgi=shift;
debug("read_cookie")if ($debug);
my %cookie = CGI::Cookie->fetch;
debug("cookies: ".Dumper(\%cookie))if ($debug);
my $cookie=$cookie{'sessionID'};
debug("cookie: ".$cookie)if ($debug);
return undef unless (defined $cookie);
my $session_id= $cookie->value || undef;
debug("sid: ".$session_id)if ($debug);
return $session_id;
#return $cgi->cookie('sessionID') || undef;
};
sub delete_cookie{
my $cgi=shift;
debug("delete_cookie")if ($debug);
my $cookie = $cgi->cookie(
-name => 'sessionID',
-value => '',
-expires => '+1s'
);
print $cgi->header( -cookie => $cookie );
return 1;
}
#read and write server-side session data
sub create_session{
my $user=shift;
my $password=shift;
my $expiration=shift;
debug("create_session")if ($debug);
my $session = new CGI::Session(undef, undef, {Directory=>$tmp_dir});
$session->expire($expiration);
$session->param("user", $user);
$session->param("pid", $$);
# $session->param("password", $password);
return $session->id();
}
sub read_session{
my $session_id=shift;
debug("read_session")if $debug;
return undef unless(defined $session_id);
debug("read_session2")if $debug;
my $session = new CGI::Session(undef, $session_id, {Directory=>$tmp_dir});
return undef unless defined $session;
debug("read_session3")if $debug;
my $user = $session->param("user") || undef;
return undef unless defined $user;
my $expires = time::time_to_datetime($session->param("_SESSION_ATIME")+$session->param("_SESSION_ETIME"));
return {
user => $user,
expires => $expires
}
}
sub delete_session{
my $session_id=shift;
debug("delete_session")if ($debug);
return undef unless(defined $session_id);
my $session = new CGI::Session(undef, $session_id, {Directory=>$tmp_dir});
$session->delete();
return 1;
}
#check user authentication
sub authenticate{
my $config=shift;
my $user=shift;
my $password=shift;
$config->{access}->{write}=0;
my $dbh = db::connect($config);
my $query = qq{
select *
from calcms_users
where name=?
};
my $bind_values = [$user];
#print STDERR "query:".Dumper($query).Dumper($bind_values);
my $users = db::get($dbh,$query,$bind_values);
#print STDERR "result:".Dumper($users);
if (scalar(@$users) != 1){
print STDERR "auth: did not find user '$user'\n";
return undef;
}
#print STDERR Dumper($users);
my $salt=$users->[0]->{salt};
my $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt(
$users->[0]->{pass},
$users->[0]->{salt}
);
return undef unless $ppr->match($password);
if($users->[0]->{disabled} == 1){
print STDERR "user '$user' is disabled\n";
return undef;
}
my $timeout = $users->[0]->{session_timeout} || 120;
$timeout =10 if $timeout < 10;
$timeout =12*60 if $timeout > 12*60;
return {
timeout => $timeout,
login => 1
}
}
sub show_login_form{
my $user=shift||'';
my $uri=$ENV{HTTP_REFERER}||'';
my $message=shift||'';
debug("show_login_form")if ($debug);
print qq{Content-type:text/html
<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
html,body{
height: 100%;
font-family:helvetica,arial,sans-serif;
}
body{
display: table;
margin: 0 auto;
}
input, .row, .field{
padding:0.5em;
}
.container{
height: 100%;
display: table-cell;
vertical-align: middle;
}
#login_form{
background:#ddd;
box-shadow: 1em 1em 1em #888;
margin:1em;
padding:1em;
text-align:center;
}
#login_form .field{
width:8em;
float:left;
}
#login_form .message{
background:#ccc;
text-align:left;
font-weight:bold;
padding:1em;
margin:-1em;
margin-bottom:0;
}
</style>
</head>
<body>
<div class="container">
<div id="login_form">
<div class="message">$message</div><br/>
<form method="post">
<div class="row">
<div class="field">user</div>
<input name="user" value="$user"><br/>
</div>
<div class="row">
<div class="field">password</div>
<input type="password" name="password"><br/>
</div>
<div class="row">
<input type="submit" name="action" value="login">
<input type="submit" name="action" value="logout">
</div>
<input type="hidden" name="uri" value="$uri">
</form>
</div>
</container>
</body>
</html>
};
return undef;
}
sub debug{
my $message=shift;
print STDERR "$message\n" if $debug>0;
}
#do not delete last line!
1;

179
lib/calcms/cache.pm Normal file
View File

@@ -0,0 +1,179 @@
use warnings "all";
use strict;
#use Data::Dumper;
use config;
use time;
use log;
use markup;
package cache;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(init add_map get_map get_map_keys load save get_filename escape_regexp escape_regexp_line);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
my $cache_map ={};
my $cache_map_keys =[];
my $header_printed =0;
our $date_pattern ='(\d{4})\-(\d{2})\-(\d{2})';
our $datetime_pattern ='(\d{4})\-(\d{2})\-(\d{2})[T\+](\d{2})\:(\d{2})(\:\d{2})?';
sub init{
$cache_map ={};
$cache_map_keys =[];
$header_printed =0;
}
sub add_map{
my $key =$_[0];
my $value =$_[1];
$key='^'.$key.'$';
push @$cache_map_keys,$key;
$cache_map->{$key}=$value;
}
sub get_map{
return $cache_map;
}
sub get_map_keys{
return $cache_map_keys;
}
#get cache from params
sub load{
my $params=shift;
my $filename=get_filename($params);
my $result={
filename=>$filename
};
if (defined $filename){
my @file_info=stat($filename);
my $modified=$file_info[9]||'';
if ($modified ne ''){
#file exists
my @now =localtime(time());
my @modified =localtime($modified);
if ($now[2]==$modified[2]){
#file is elder than a hour
my $content=log::load_file($filename);
if (defined $content){
$result->{content} =$content;
$result->{action} ='read';
return $result;
}
}
}
}
$result->{action}='save';
return $result;
}
#get filename from params
sub get_filename{
my $config = shift;
my $params = shift;
# my $url=$ENV{REQUEST_URI};
my $url=$ENV{QUERY_STRING}||'';
if ($url ne''){
$url=~s/(^|\&)update\=\d//gi;
$url=~s/(^|\&)debug\=.*//gi;
$url=~s/\?\&/\?/g;
$url=~s/\&{2,99}/\&/g;
$url=~s/\&$//g;
$url=~s/^\/\//\//g;
}
foreach my $pattern (@$cache_map_keys){
my $filename=$url;
log::write($config, 'cache_trace',"look at \"$filename\" for $pattern") if ($config->{system}->{debug});
if ($filename =~/$pattern/){
my $m1=$1;
my $m2=$2;
my $m3=$3;
my $m4=$4;
my $m5=$5;
my $m6=$6;
my $m7=$7;
my $m8=$8;
# my $m9=$9;
my $result=$cache_map->{$pattern};
$filename=~s/$pattern/$result/;
$filename=~s/\$1/$m1/ if (defined $m1);
$filename=~s/\$2/$m2/ if (defined $m2);
$filename=~s/\$3/$m3/ if (defined $m3);
$filename=~s/\$4/$m4/ if (defined $m4);
$filename=~s/\$5/$m5/ if (defined $m5);
$filename=~s/\$6/$m6/ if (defined $m6);
$filename=~s/\$7/$m7/ if (defined $m7);
$filename=~s/\$8/$m8/ if (defined $m8);
# $filename=~s/\$9/$m9/ if (defined $m9);
$filename=$config->{cache}->{cache_dir}.$filename;
return $filename;
}
}
return undef;
}
#deprecated: set file from params
sub set{
my $params=shift;
my $content=shift;
my $filename=get_filename($params);
my $cache={
filename => $filename,
content => $content
};
# print $filename.":file\n";
if (defined $filename){
cache::save($cache);
}
}
sub save{
my $cache=shift;
return if ($cache->{action}ne'save');
return if ((!defined $cache->{filename}) || ($cache->{filename}eq''));
log::save_file($cache->{filename},$cache->{content});
chmod 0664, $cache->{filename};
}
sub escape_regexp{
my $reg_exp=shift;
$reg_exp=~s/([\^\$\\(\)\[\]\{\}\|\/\*\+\.\-\&\:])/\\$1/gi;
return $reg_exp;
}
sub escape_regexp_line{
my $reg_exp=shift;
$reg_exp=~s/([\^\$\\(\)\[\]\{\}\|\/\*\+\.\-\&\:])/\\$1/gi;
return '^'.$reg_exp.'$';
}
sub configure{
my $file_name=shift;
cache::init();
cache::add_map('',$file_name);
}
#do not delete last line!
1;

516
lib/calcms/calendar.pm Normal file
View File

@@ -0,0 +1,516 @@
#use Calendar::Simple qw(date_span);
use Date::Calc;
use config;
use template;
use markup;
use cache;
use log;
use time;
use project;
use events;
package calendar;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(init get_cached_or_render get render get_calendar_weeks configure_cache);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#my $debug='';
sub init{
}
sub get_cached_or_render{
# my $output = $_[0]
my $config = $_[1];
my $request = $_[2];
my $parms =$request->{params}->{checked};
my $debug=$config->{system}->{debug};
my $cache={};
if ($config->{cache}->{use_cache} == 1){
calendar::configure_cache($config);
$cache=cache::load($config, $parms);
log::write($config, 'cache',$cache->{action}) if ($debug);
if (defined $cache->{content}){
$_[0]=$cache->{content};
return;
}
}
my $calendar=calendar::get($config, $request);
log::write($config, 'calendar',$calendar) if ($debug);
#print STDERR Dumper($calendar);
calendar::render($_[0], $config, $request, $calendar);
#write to cache
if ($config->{cache}->{use_cache} == 1){
#todo:put out reference only
$cache->{content}=$_[0];
log::write($config, 'cache_files',$cache) if ($debug);
cache::save($cache);
}
}
sub get{
my $config = shift;
my $request = shift;
my $params=$request->{params}->{checked};
my $debug=$config->{system}->{debug};
my $language = $config->{date}->{language} || 'en';
my $date = $params->{date}||'';
my $template = $params->{template}||'';
my $from_time = $params->{from_time}||'';
my $till_time = $params->{till_time}||'';
my @today=localtime(time());
my $today=sprintf('%04d-%02d-%02d', 1900+$today[5], $today[4]+1, $today[3]);
my $weekday_names = $time::names->{$language}->{weekdays};
my $weekday_short_names = $time::names->{$language}->{weekdays_abbr};
my $week_label={};
my $c=0;
for my $weekday (@$weekday_short_names){
$week_label->{$weekday}=$weekday_names->[$c]||'';
$c++;
}
$template=~s/\'//gi;
$from_time=~s/\'//gi;
$till_time=~s/\'//gi;
#put "clear all" filter into final results
my $day_result={};
my $clear_filter=$day_result;
#put "week day" filter into final results
my $days=[];
$c=0;
for my $weekday (@$weekday_short_names){
my $day_result={
label => $week_label->{$weekday},
weekday => $c+1,
weekday_parameter => 'weekday='.$c,
weekday_short_name => $weekday_short_names->[$c] ||'',
weekday_name => $weekday_names->[$c] ||'',
description => qq{alle $week_label->{$weekday}-Termine anzeigen},
};
push @$days,$day_result;
$c++;
}
#weeks and days array
my $weekAndDayResults=[];
#weekday array
my $weekdayResults=$days;
#week array
my $weekResults=[];
#info hash by timedate
my $dateInfo={};
#generate content for each day in a week in a month in a year
#get today
my $start_date='';
my $end_date='';
if ($date=~/(\d{4})\-(\d{2})/){
my $year=$1;
my $month=$2;
$start_date = "$year-$month-01";
$end_date = "$year-$month-".Date::Calc::Days_in_Month($year,$month);
}else{
$start_date = $params->{start_date};
$end_date = $params->{end_date};
}
my $previous_month=$start_date;
if ($previous_month=~/(\d{4})\-(\d{2})/){
my $year =$1;
my $month=$2-1;
$month='0'.$month if (length($month)<2);
if ($month lt '01'){
$year-=1;
$month='12';
}
$previous_month="$year-$month-01";
$previous_month=$params->{start_date} if ($previous_month lt $params->{start_date});
}
my $next_month=$end_date;
if ($next_month=~/(\d{4})\-(\d{2})/){
my $year=$1;
my $month=$2+1;
$month='0'.$month if (length($month)<2);
if ($month gt '12'){
$year+=1;
$month='01';
}
$next_month="$year-$month-01";
$next_month=$params->{end_date} if ($next_month gt $params->{end_date});
}
my $start_year=undef;
my $start_month=undef;
if ($start_date=~/(\d{4})\-(\d{2})/){
$start_year=$1;
$start_month=$2;
}
my $start_month_name=$time::names->{$language}->{months_abbr}->[$start_month-1];
if($params->{month_only}eq'1'){
return {
next_month => $next_month,
previous_month => $previous_month,
start_year => $start_year,
start_month => $start_month,
start_month_name => $start_month_name
};
}
my $years=calendar::get_calendar_weeks($config, $start_date, $end_date);
my $dbh=db::connect($config, $request);
my $used_days=events::get_by_date_range($dbh, $config, $start_date, $end_date);
my $used_day={};
for my $day(@$used_days){
$used_day->{$day->{start_date}}=1;
}
for my $year (sort {$a <=> $b} keys %$years){
my $months=$years->{$year};
for my $month (sort {$a <=> $b} keys %$months){
my $weeks=$months->{$month};
my $weekCounter=1;
for my $week (@$weeks){
my $dayResults=[];
my $week_end =undef;
my $week_start=undef;
my $week_of_year=undef;
my $woy_year = undef;
for my $date (@$week){
my ($year, $month, $day)=split(/\-/,$date);
my $weekday=0;
my $day_result=undef;
($week_of_year,$woy_year) = Date::Calc::Week_of_Year($year,$month,$day) unless defined $week_of_year;
$day_result={
date => $date,
date_parameter => 'date='.$date,
day => $day,
year => $year,
month => $month,
};
$day_result->{time} =$from_time if defined $from_time;
$day_result->{class}.= ' calcms_today' if $date eq $today;
$day_result->{class}.= ' selected' if defined $used_day->{$date};
$day_result->{class}.= " week_$weekCounter";
$day_result->{class}.= " other_month" if ($weekCounter<2) && ($day gt "15");
$day_result->{class}.= " other_month" if ($weekCounter>3) && ($day lt "15");
$day_result->{class}=~s/^\s+//g;
$week_start =$day unless defined $week_start;
$week_end =$day;
log::write($config, 'day_results',$day_result)if ($debug);
$day_result->{weekday_name}=$weekday_names->[$weekday];
$day_result->{weekday_short_name}=$weekday_short_names->[$weekday];
$day_result->{weekday}=$weekday+1;
$dateInfo->{$day_result->{date}}=$day_result->{weekday} if defined $day_result->{date};
push @$dayResults, $day_result;
$weekday++;
}#end for days
#week filter
my $start_date=$week->[0];
my $end_date =$week->[-1];
my $week_result={
from_date => $start_date,
till_date => $end_date,
week_start => $week_start,
week_end => $week_end,
week_month => sprintf("%2d",$month),
week_year => $year,
week_of_year => $week_of_year,
};
$week_result->{class}.= ' selected' if (
((defined $params->{from_date}) && ($start_date eq $params->{from_date}))
|| ((defined $params->{till_date}) && ($end_date eq $params->{till_date}))
);
$week_result->{class}.= " week_$weekCounter";
$week_result->{class}=~s/^\s+//g;
push @$weekResults, $week_result;
push @$weekAndDayResults,{
days=>$dayResults,
week=>[$week_result]
};
$weekCounter++;
}#end week
}#end month
}#end year
for my $weekday (@$weekdayResults){
$weekday->{start_date} = $start_date;
$weekday->{end_date} = $end_date;
}
return {
week_and_days => $weekAndDayResults,
weekdays => $weekdayResults,
weeks => $weekResults,
days => $dateInfo,
next_month => $next_month,
previous_month => $previous_month,
start_date => $start_date,
end_date => $end_date,
start_month_name => $start_month_name,
start_month => $start_month,
start_year => $start_year,
base_url => $config->{locations}->{base_url},
cache_base_url => $config->{cache}->{base_url},
controllers => $config->{controllers},
};
}
sub render{
# my $out = $_[0];
my $config = $_[1];
my $request = $_[2];
my $calendar = $_[3];
my $parms =$request->{params}->{checked};
my $debug=$config->{system}->{debug};
my $template_parameters=$calendar;
$template_parameters->{debug} = $config->{system}->{debug};
$template_parameters->{base_url} = $config->{locations}->{base_url};
$template_parameters->{cache_base_url} = $config->{cache}->{base_url};
$template_parameters->{server_cache} = $config->{cache}->{server_cache} if ($config->{cache}->{server_cache});
$template_parameters->{use_client_cache} = $config->{cache}->{use_client_cache} if ($config->{cache}->{use_client_cache});
template::process($_[0], $parms->{template}, $template_parameters);
}
sub get_calendar_weeks{
my $config = shift;
my $start = shift;
my $end = shift;
my $debug = $config->{system}->{debug};
$start = time::date_to_array($start);
$end = time::date_to_array($end);
my $start_year = int($start->[0]);
my $end_year = int($end->[0]);
my $start_month = int($start->[1]);
my $end_month = int($end->[1]);
my $years={};
for my $year ($start_year..$end_year){
my $months={};
for my $month ($start_month..$end_month){
#get week arrays of days of the month
my $weeks=getWeeksOfMonth($year, $month);
$months->{$month}=$weeks;
}
$years->{$year}=$months;
}
log::write($config, 'years',$years)if ($debug);
return $years;
}
sub getWeeksOfMonth{
my $thisYear = shift;
my $thisMonth = shift;
my $thisDay = 1;
# get weekday of 1st of month
my $thisMonthWeekday = Date::Calc::Day_of_Week($thisYear,$thisMonth,1);
# get next month date
my($nextYear, $nextMonth, $nextDay)=Date::Calc::Add_Delta_YM($thisYear,$thisMonth,$thisDay, 0,1);
# get weekday of 1st of next month
my $nextMonthWeekday = Date::Calc::Day_of_Week($nextYear, $nextMonth, $nextDay);
my($lastYear, $lastMonth, $lastDayOfMonth)=Date::Calc::Add_Delta_Days($nextYear,$nextMonth,$nextDay, -1);
# get date of 1st of row
my( $week,$year) = Date::Calc::Week_of_Year($thisYear,$thisMonth,$thisDay);
($year,my $month, my $day) = Date::Calc::Monday_of_Week($week,$year);
my @weeks=();
my $weekday=1;
{
# first week
my @days=();
for $weekday(0 .. $thisMonthWeekday-2){
push @days, sprintf("%04d-%02d-%02d",$year,$month,$day);
$day++;
}
# set current month
$month = $thisMonth;
$year = $thisYear;
$day = 1;
for $weekday($thisMonthWeekday..7){
push @days, sprintf("%04d-%02d-%02d",$year,$month,$day);
$day++;
}
# next week
push @weeks, \@days;
}
# weeks until end of month
while(scalar(@weeks)<6){
my @days=();
$weekday=1;
while($weekday<=7){
push @days, sprintf("%04d-%02d-%02d",$year,$month,$day);
$day++;
$weekday++;
last if $day>$lastDayOfMonth;
}
if ($day>$lastDayOfMonth){
# set next month
$month=$nextMonth;
$year=$nextYear;
$day=1;
if ($nextMonthWeekday!=1){
# finish end week
if($weekday<=7){
while( $weekday<=7){
push @days, sprintf("%04d-%02d-%02d",$year,$month,$day);
$day++;
$weekday++;
}
}
}
push @weeks, \@days;
last;
};
push @weeks, \@days if $weeks[-1]->[-1] ne $days[-1];
}
#coming weeks
while(scalar(@weeks)<6){
my @days=();
for $weekday(1..7){
push @days, sprintf("%04d-%02d-%02d",$year,$month,$day);
$day++;
}
push @weeks, \@days;
}
return \@weeks;
}
sub configure_cache{
my $config = shift;
my $debug=$config->{system}->{debug};
cache::init();
my $date_pattern = $cache::date_pattern;
my $controllers = $config->{controllers};
cache::add_map('' , $controllers->{calendar}.'/cal.html');
cache::add_map('date='.$date_pattern , $controllers->{calendar}.'/$1-$2.html');
cache::add_map('from_date='.$date_pattern.'&till_date='.$date_pattern , $controllers->{calendar}.'/$1-$2_$5-$6.html');
log::write($config, 'cache_files',cache::get_map()) if ($debug);
}
sub check_params{
my $config=shift;
my $params=shift;
#get start and stop from projects
my $range= project::get_date_range($config);
my $start_date = $range->{start_date};
my $end_date = $range->{end_date};
#switch off limiting end date by project
my $open_end=0;
if((defined $params->{'open_end'})&&($params->{'open_end'}=~/(\d+)/)){
$open_end = $1;
$end_date = time::add_days_to_datetime(time::time_to_datetime(), 365);
}
my $month_only=$params->{month_only}||'';
#filter for date
my $date=time::check_date($params->{date});
$date =$start_date if ($date lt $start_date);
$date =$end_date if ($date gt $end_date);
log::error($config, "no valid year-month format given!") if ($date eq"-1");
my $time=time::check_time($params->{time});
log::error($config, "no valid time format given!") if ($time eq"-1");
my $from_date=time::check_date($params->{from_date})||'';
log::error($config, "no valid date format given!") if (defined $from_date && $from_date eq"-1");
$from_date =$start_date if ($from_date lt $start_date);
$from_date =$end_date if ($from_date gt $end_date);
my $till_date=time::check_date($params->{till_date}||'');
log::error($config, "no valid date format given!") if (defined $till_date && $till_date eq"-1");
$till_date =$start_date if ($till_date lt $start_date);
$till_date =$end_date if ($till_date gt $end_date);
my $template=template::check($params->{template},'calendar.html');
my $debug=$params->{debug};
if ((defined $debug) && ($debug=~/([a-z\_\,]+)/)){
$debug=$1;
}
return {
template => $template,
date => $date,
from_date => $from_date,
till_date => $till_date,
debug => $debug,
month_only => $month_only,
open_end => $open_end,
start_date => $start_date,
end_date => $end_date
}
}
#do not delete last line!
1;

712
lib/calcms/comments.pm Normal file
View File

@@ -0,0 +1,712 @@
use warnings "all";
use strict;
use Data::Dumper;
use config;
use template;
use time;
package comments;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
#our @EXPORT = qw(all);
our @EXPORT_OK = qw(init get_cached_or_render get modify_results render configure_cache get_query get_by_event get_level get_events check insert set_lock_status set_news_status lock update_comment_count sort);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub init{
}
sub get_cached_or_render{
# my $response=$_[0];
my $config = $_[1];
my $request = $_[2];
my $mark_locked = $_[3];
my $params=$request->{params}->{checked};
#print STDERR Dumper($params);
$config->{app_name}=$config->{controllers}->{comments};
my $comment=$request->{params}->{checked};
my $filename='';
my $cache={};
my $results=comments::get($config, $request);
if((defined $mark_locked) && ($mark_locked eq 'mark_locked')){
for my $result(@$results){
if($result->{lock_status}ne'show'){
$result->{author}='Zensur';
$result->{content}='Dieser Eintrag wurde gel&ouml;scht.';
}
}
}elsif((defined $mark_locked) && ($mark_locked eq 'filter_locked')){
my @results2=();
for my $result(@$results){
push @results2, $result if($result->{lock_status}eq'show');
}
$results=\@results2;
}
comments::modify_results($results, $config, $request);
#print STDERR Dumper($results);
$results=comments::sort($config, $results) if ($comment->{type}eq'tree');
#print STDERR Dumper($results);
# if ($comment->{sort_order}eq'desc'){
# my @results= reverse(@$results);
# $results=\@results;
# }
if (
($params->{show_max} ne'')
&& ($params->{limit} ne'')
&& ($params->{show_max}<$params->{limit})
){
my @results2=();
my $c=0;
for my $result(@$results){
push @results2,$result;
$c++;
last if ($c>=$params->{show_max});
}
$results=\@results2;
}
comments::render($_[0], $config, $request, $results);
}
sub get{
my $config = shift;
my $request= shift;
my $params=$request->{params}->{checked};
my $dbh=db::connect($config, $request);
(my $query, my $bind_values)=comments::get_query($dbh, $config, $request);
#print STDERR Dumper($$query);
#print STDERR Dumper($bind_values);
my $results=db::get($dbh, $$query, $bind_values);
#print STDERR Dumper($results);
return $results;
}
sub get_query{
my $dbh = shift;
my $config = shift;
my $request=shift;
my $params=$request->{params}->{checked};
my $event_id = undef;
my $event_start = undef;
my $from = 'calcms_comments c';
my $where = '';
my $limit = '';
my @conditions=();
my $bind_values=[];
#exclude comments from config filter/exclude_locations
if (
(defined $config->{filter})
&& (defined $config->{filter}->{exclude_locations})
){
my @exclude_locations=split(/[,\s]+/,$config->{filter}->{exclude_locations});
my $exclude_locations=join(', ',map {'?'} @exclude_locations);
$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 @$bind_values, $location;
}
}
if (
(defined $params->{event_id} && $params->{event_id}ne'') &&
(defined $params->{event_start} && $params->{event_start}ne'')
){
#$where =qq{ and (event_id=? or event_start=?) };
push @conditions, q{ (event_id=? or event_start=?) };
push @$bind_values, $params->{event_id};
push @$bind_values, $params->{event_start};
}
my $sort_order=$params->{sort_order};
if ($params->{limit} ne''){
$limit ='limit ?';
push @$bind_values,$params->{limit};
}
if (@conditions>0){
$where= 'where '.join(' and ',@conditions);
}
my $dbcols=['id', 'event_start', 'event_id', 'content', 'ip', 'author', 'email',
'lock_status', 'created_at', 'title', 'parent_id', 'level', 'news_status', 'project'];
my $cols=join(', ',map { 'c.'.$_ } @$dbcols);
my $query=qq{
select $cols
from $from
$where
order by created_at $sort_order
$limit
};
# where lock_status='show'
# use Data::Dumper;print STDERR Dumper($query);
return (\$query, $bind_values);
}
sub modify_results{
my $results = $_[0];
my $config = $_[1];
my $request = $_[2];
my $params=$request->{params}->{checked};
my $time_diff='';
if ($params->{template}=~/\.xml/){
$time_diff=time::utc_offset($config->{date}->{time_zone});
$time_diff=~s/(\d\d)(\d\d)/$1\:$2/g;
}
my $language = $config->{date}->{language} || 'en';
for my $result (@$results){
$result->{allow}->{new_comments} = 1 if ($params->{allow}->{new_comments});
$result->{start_date_name} = time::date_format($result->{created_at}, $language);
$result->{start_time_name} = time::time_format($result->{created_at});
my $comment_limit=100;
if (length($result->{content})>$comment_limit){
$result->{short_content} = substr($result->{content},0,$comment_limit).'...' ;
}else{
$result->{short_content} = $result->{content};
}
$result->{base_url} = $config->{locations}->{base_url};
$result->{cache_base_url} = $config->{cache}->{base_url};
if($params->{template}=~/\.xml/){
# $result->{content} =~s/(\[\[.*?\]\])//gi;
# $result->{content} =markup::plain_to_xml($result->{content});
# $result->{content} =$result->{html_content};
$result->{content} = markup::html_to_plain($result->{html_content});
$result->{short_content}= markup::html_to_plain($result->{short_content});
$result->{excerpt} = "lass dich ueberraschen" if ((defined $result->{excerpt}) && ($result->{excerpt}eq''));
$result->{excerpt} = markup::html_to_plain($result->{excerpt});
$result->{title} = markup::html_to_plain($result->{title});
$result->{series_name} = markup::html_to_plain($result->{series_name});
$result->{program} = markup::html_to_plain($result->{program});
if (defined $result->{created_at}){
$result->{created_at}=~s/ /T/gi;
$result->{created_at}.=$time_diff;
}
if (defined $result->{modified_at}){
$result->{modified_at}=~s/ /T/gi;
$result->{modified_at}.=$time_diff;
}
}
}
return $results;
}
sub render{
# my $response =$_[0];
my $config = $_[1];
my $request = $_[2];
my $results = $_[3];
my $params =$request->{params}->{checked};
my %template_parameters=%$params;
my $template_parameters=\%template_parameters;
$template_parameters->{comments} = $results;
$template_parameters->{comment_count} =(@$results)+0;
$template_parameters->{one_result} =1 if($template_parameters->{comment_count}==1);
$template_parameters->{allow}->{new_comments} =1 if ($params->{allow}->{new_comments});
$template_parameters->{event_id} = $params->{event_id};
$template_parameters->{event_start} = $params->{event_start};
$template_parameters->{server_cache} = $config->{cache}->{server_cache} if ($config->{cache}->{server_cache});
$template_parameters->{use_client_cache}= $config->{cache}->{use_client_cache} if ($config->{cache}->{use_client_cache});
$template_parameters->{controllers} = $config->{controllers};
template::process($_[0],$params->{template},$template_parameters);
}
#check if comment exists already
sub check{
my $dbh = shift;
my $config = shift;
my $comment = shift;
my $query=qq{
select id
from calcms_comments
where (
event_start=?
or event_id=?
)
and parent_id=?
and author=?
and ip=?
and content=?
};
my $bind_values=[
$comment->{event_start},
$comment->{event_id},
$comment->{parent_id},
$comment->{author},
$comment->{ip},
$comment->{content}
];
my $comments=db::get($dbh,$query,$bind_values);
my @comments=@$comments;
return 0 if (@comments>0);
return 1;
}
#used for insert
sub get_level{
my $dbh = shift;
my $config = shift;
my $comment = shift;
my $parent_id=$comment->{parent_id};
return 0 unless defined $parent_id;
if($parent_id=~/(\d+)/){
$parent_id=$1;
}
return 0 unless $parent_id=~/^\d+$/;
return 0 if $parent_id==0;
#get level from parent node
my $query=qq{
select level
from calcms_comments
where (
event_start=?
or event_id=?
)
and id=?
limit 1
};
my $bind_values=[
$comment->{event_start},
$comment->{event_id},
$parent_id
];
my $comments=db::get($dbh,$query,$bind_values);
my @comments=@$comments;
if (@comments>0){
return $comments->[0]->{level}+1;
}
return 0;
}
sub get_by_event{
my $dbh = shift;
my $config = shift;
my $request =$_[0];
my $params = $request->{params}->{checked}->{comment};
my $event_id = undef;
my $search = undef;
my $where = '';
my $limit = '';
my $bind_values=[];
if ($params->{event_id}ne''){
$where =qq{ event_id=? };
$bind_values=[$params->{event_id}];
}
if ((defined $params->{search}) && ($params->{search}ne'')){
$search ='%'.$params->{search}.'%';
$where =qq{ (content like ?) or (email like ?) or (author like ?) or (ip like ?)};
$bind_values=[
$search,
$search,
$search,
$search
];
}
my $sort_order=$params->{sort_order} || 'desc';
if ((defined $params->{limit}) && ($params->{limit} ne'')){
$limit ='limit ?';
push @$bind_values,$params->{limit};
}
my $query=qq{
select *
from calcms_comments
where $where
order by created_at $sort_order
$limit
};
#print STDERR $query."\n";
my $comments=db::get($dbh, $query, $bind_values);
return $comments;
}
sub get_by_time{
my $dbh = shift;
my $config = shift;
my $comment = shift;
my $where='';
my $bind_values=[];
if ($comment->{age} ne ''){
$where=qq{
where event_id in (
select distinct event_id
from calcms_comments
where (
unix_timestamp(now()) - ? < unix_timestamp(created_at)
)
)
};
$bind_values=[
$comment->{age}*3600,
];
}elsif (($comment->{from} ne '') && ($comment->{till} ne '')){
$where=qq{
where event_id in (
select distinct event_id
from calcms_comments
where created_at >= ?
and created_at <= ?
)
};
$bind_values=[
$comment->{from},
$comment->{till}
];
}
my $query=qq{
select *
from calcms_comments
$where
order by event_id, id
};
my $comments=db::get($dbh, $query, $bind_values);
return $comments;
}
sub get_events{
my $dbh=shift;
my $config = shift;
my $request=shift;
my $comments=shift;
my $params=$request->{params}->{checked}->{comment};
#get event_ids from comments
my $event_ids={};
for my $comment (@$comments){
my $event_id=$comment->{event_id};
$event_ids->{$event_id}=1;
}
#get events from comment's event ids
return [] if ((keys %{$event_ids})==0);
#my $quoted_event_ids=join "," ,(map {$dbh->quote($_)}(keys %{$event_ids}));
my @bind_values=keys %{$event_ids};
my $event_id_values=join "," ,(map {'?'}(keys %{$event_ids}));
my $query=qq{
select id, start, program, series_name, title, excerpt
from calcms_events
where id in ($event_id_values)
};
my $events=db::get($dbh, $query, \@bind_values);
#build lookup table for events by id
my $events_by_id={};
for my $event (@$events){
$events_by_id->{$event->{id}}=$event;
$event->{max_comment_id}=0;
}
#add unassigned events
# for my $event_id (keys %{$event_ids}){
# if ($events_by_id->{$event_id}eq''){
# my $event={
# title => "not assigned",
# max_comment_id => 0
#
# };
# push @$events,$event;
# $events_by_id->{$event_id}=$event;
# }
# }
for my $comment (@$comments){
my $event_id=$comment->{event_id};
my $event=$events_by_id->{$event_id};
next unless (defined $event);
$event->{comment_count}++;
push @{$event->{comments}},$comment;# if ($params->{event_id}ne'');
$event->{max_comment_id}=$comment->{id} if ($comment->{id} > $event->{max_comment_id});
for my $name (keys %{$config->{controllers}}){
$comment->{"controller_".$name}=$config->{controllers}->{$name}||'';
# $event->{"controller_$name"}=$config->{controllers}->{$name};
}
}
my @sorted_events=reverse sort {$a->{max_comment_id} <=> $b->{max_comment_id}} @$events;
return \@sorted_events;
}
sub insert{
my $dbh = shift;
my $config = shift;
my $comment = shift;
$comment->{level}=comments::get_level($dbh, $config, $comment);
my $entry={
event_start => $comment->{event_start},
event_id => $comment->{event_id},
parent_id => $comment->{parent_id},
level => $comment->{level},
title => $comment->{title},
content => $comment->{content},
author => $comment->{author},
email => $comment->{email},
ip => $comment->{ip}
};
my $comment_id=db::insert($dbh, 'calcms_comments', $entry);
return $comment_id;
}
sub set_lock_status{
my $dbh=shift;
my $config = shift;
my $comment=shift;
my $id = $comment->{id};
my $lock_status = $comment->{set_lock_status};
my $query=qq{
update calcms_comments
set lock_status = ?
where id = ?
};
my $bind_values=[
$lock_status,
$id
];
db::put($dbh,$query,$bind_values);
$query=qq{
select event_id
from calcms_comments
where id=?
};
$bind_values=[$id];
my $comments=db::get($dbh,$query,$bind_values);
if (@$comments>0){
$comment->{event_id}=$comments->[0]->{event_id};
update_comment_count($dbh,$comment);
}
}
sub set_news_status{
my $dbh=shift;
my $config = shift;
my $comment=shift;
my $id = $comment->{id};
my $news_status = $comment->{set_news_status};
my $query=qq{
update calcms_comments
set news_status= ?
where id = ?
};
my $bind_values=[$news_status,$id];
db::put($dbh,$query,$bind_values);
}
sub update_comment_count{
my $dbh=shift;
my $config = shift;
my $comment=shift;
my $query=qq{
select count(id) count
from calcms_comments
where lock_status='show'
and event_id=?
};
my $bind_values=[$comment->{event_id}];
my $comments=db::get($dbh,$query,$bind_values);
my $count=0;
$count=$comments->[0]->{count} if (@$comments>0);
$query=qq{
update calcms_events
set comment_count=?
where id=?
};
$bind_values=[
$count,
$comment->{event_id}
];
db::put($dbh,$query,$bind_values);
}
#precondition: results are presorted by creation date (by sql)
sub sort{
my $config = shift;
my $results=shift;
#define parent nodes
my $nodes={};
for my $node (@$results){
$nodes->{$node->{id}}=$node;
}
my @root_nodes=();
for my $node (@$results){
#fill childs into parent nodes
push @{$nodes->{$node->{parent_id}}->{childs}},$node;
#define root nodes
push @root_nodes,$node if ($node->{level}==0);
}
#print STDERR Dumper(\@root_nodes);
#sort root nodes from newest to oldest
my $sorted_nodes=[];
for my $node (@root_nodes){
#for my $node (reverse @root_nodes){
sort_childs($node,$nodes,$sorted_nodes);
}
return $sorted_nodes;
}
sub sort_childs{
my $node=shift;
my $nodes=shift;
my $sorted_nodes=shift;
#push node into list of sorted nodes
push @{$sorted_nodes},$node;
#return if node is leaf
return $sorted_nodes unless (defined $node->{childs});
#process child nodes
for my $child (@{$node->{childs}}){
$sorted_nodes=sort_childs($child,$nodes,$sorted_nodes);
}
return $sorted_nodes;
}
sub configure_cache{
my $config = shift;
cache::init();
my $date_pattern = $cache::date_pattern;
my $datetime_pattern = $cache::datetime_pattern;
my $controllers = $config->{controllers};
cache::add_map('template=comments_newest&limit=3&type=list' ,$controllers->{comments}.'/neueste.html');
cache::add_map('template=comments_atom.xml&limit=20' ,$controllers->{comments}.'/feed.xml');
cache::add_map('template=comments.html&event_id=(\d+)&event_start='.$datetime_pattern ,$controllers->{comments}.'/$1_$2-$3-$4_$5-$6.html');
}
sub check_params{
my $config = shift;
my $params = shift;
my $comment={};
$comment->{event_start}='';
if ( (defined $params->{event_start}) && ($params->{event_start}=~/(\d\d\d\d\-\d\d\-\d\d[T ]\d\d\:\d\d)(\:\d\d)?/) ){
$comment->{event_start}=$1;
}
$comment->{sort_order}='desc';
$comment->{limit}='';
if ( (defined $params->{limit}) && ($params->{limit}=~/(\d+)/) ){
$comment->{limit}=$1;
}
$comment->{show_max}='';
if ( (defined $params->{show_max}) && ($params->{show_max}=~/(\d+)/) ){
$comment->{show_max}=$1;
}
if ( (defined $params->{sort_order}) && ($params->{sort_order}eq'asc') ){
$comment->{sort_order}='asc';
}
$comment->{event_id}='';
if ( (defined $params->{event_id}) && ($params->{event_id}=~/(\d+)/) ){
$comment->{event_id}=$1;
}
if ( (defined $params->{parent_id}) && ($params->{parent_id}=~/(\d+)/) ){
$comment->{parent_id}=$1;
}
if ((defined $params->{type}) && ($params->{type} eq 'list')){
$comment->{type}='list';
}else{
$comment->{type}='tree';
}
my $debug=$params->{debug}||'';
if ($debug=~/([a-z\_\,]+)/){
$comment->{debug}=$1;
}
log::error($config, 'missing parameter a') if ( (defined $params->{limit}) && ($comment->{limit} eq'') );
log::error($config, 'missing parameter b') if ( (defined $params->{event_id}) && ($comment->{event_id} eq'') );
log::error($config, 'missing parameter c') if ( (defined $params->{event_start}) && ($comment->{event_start} eq'') );
my $delta_days=1;
if ($comment->{event_start}ne''){
my $today = time::datetime_to_array(time::time_to_datetime());
my $date = time::datetime_to_array($comment->{event_start});
$delta_days = time::days_between($today,$date);
}
if(
($delta_days > $config->{permissions}->{no_new_comments_before} )
|| ($delta_days < -1*$config->{permissions}->{no_new_comments_after} )
){
$comment->{allow}->{new_comments}=0;
}else{
$comment->{allow}->{new_comments}=1;
}
$comment->{template}=template::check($params->{template},'comments.html');
return $comment;
}
#do not delete last line!
1;

33
lib/calcms/config.pm Normal file
View File

@@ -0,0 +1,33 @@
package config;
require Exporter;
my @ISA = qw(Exporter);
my @EXPORT_OK = qw(get $config);
my %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
use Config::General;
our $modified_at=-999;
our $config= undef;
sub get{
my $filename=shift;
#return config if known
#my $age=(-M $filename);
#return $config::config if ((defined $config::config) && ($age <= $config::modified_at));
#reload config if changed
my $configuration = new Config::General(
-ConfigFile=>$filename,
-UTF8=>1
);
$config::config=$configuration->{DefaultConfig}->{config};
$config::modified_at=$age;
#print STDERR "reload $filename\n";
return $config::config;
}
#do not delete last line
1;

261
lib/calcms/creole_wiki.pm Normal file
View File

@@ -0,0 +1,261 @@
use warnings;
use strict;
use Data::Dumper;
use markup;
package creole_wiki;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(extractEventFromWikiText removeMeta eventToWikiText extractMeta removeMeta metaToWiki);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#convert creole wiki text to event
sub extractEventFromWikiText{
my $params=shift;
my $event=shift;
$event={} unless (defined $event);
my $title =$params->{title}||'';
my $content =$params->{content}||'';
my $local_media_url =$params->{local_media_url}||'';
#split content into excerpt, content and comments
$content=~s/\s*\,\s*/, /g;
my @lines=split(/\s*\-{10,99}\s*/,$content);
my $lines=\@lines;
for my $line (@$lines){
$line=~s/^\s+|\s+$//g;
}
if (@lines==1){
$event->{content}=shift @lines;
}elsif(@lines==2){
$event->{excerpt}=shift @lines;
$event->{content}=shift @lines;
}else{
$event->{excerpt}=shift @lines;
$event->{content}=shift @lines;
$event->{comments}=join("--------------------\n",@lines);
}
if (defined $event->{excerpt}){
$event->{excerpt}=markup::html_to_plain($event->{excerpt});
}
#extract program from title
$event->{program}='';
if ($title=~/^(.*?)\:/){
my $program=$1;
unless ($program=~/\s\-\s/){
$event->{program}=$program;
$event->{program}=~s/^\s+|\s+$//g;
$event->{program}=~s/\s+/ /g;
$title=~s/^.*?\:\s+//gi;
}
}
#extract series_name from title
$event->{series_name}='';
if ($title=~/^(.*?)\s+\-\s+/){
$event->{series_name}=$1;
$event->{series_name}=~s/^\s+|\s+$//g;
$event->{series_name}=~s/\s+/ /g;
$title=~s/^(.*?)\s+\-\s+//gi;
}
#extract categories from title
my @categories=();
while ($title=~/\((.*?),(.*?)\)/){
my $category=$1;
$category =~s/\s+/ /g;
$category =~s/^\s+|\s+$//g;
$category =~s/\&/\+/g;
push @categories,$category if (defined $category && $category=~/\S/);
$category='';
$category=$2 if (defined $2);
$category =~s/\s+/ /g;
$category =~s/^\s+|\s+$//g;
$category =~s/\&/\+/g;
push @categories,$category if (defined $category && $category=~/\S/);
$title=~s/\((.*?),(.*?)\)/\($2\)/;
}
if ($title=~/\((.*?)\)/){
my $category=$1;
$category =~s/\s+/ /g;
$category =~s/^\s+|\s+$//g;
$category =~s/\&/\+/g;
# print $category."\n";
push @categories,$category if (defined $category && $category=~/\S/);
$title=~s/\((.*?)\)//;
}
$event->{categories} = \@categories if (@categories>0);
$event->{title} = $title;
$event->{title} =~s/^\s+|\s+$//g;
if (defined $event->{content}){
#extract podcast_url from content link 'podcast'
my $podcast_url='';
if ($event->{content}=~/\[\[\s*([^\|\]]+)\s*\|\s*podcast\s*\]\]/i){
$podcast_url=$1;
# $podcast_url=~s/\|.*//g;
# print "found podcast:".$podcast_url."\n";
}
$event->{podcast_url} = $podcast_url;
#extract media_url from content link 'download'
my $media_url='';
if ($event->{content}=~/\[\[\s*([^\|\]]+)\s*\|\s*(direct\s+)?download\s*\]\]/i){
$media_url=$1;
# $podcast_url=~s/\|.*//g;
# print "found media:".$media_url."\n";
}
$event->{media_url} = $media_url;
#replace "thumbs/xxx" link by link to local media URI
$event->{content}=~s/\{\{\s*thumbs\/+(.*?)\s*\|\s*(.*?)\s*\}\}/\[\[$local_media_url\/images\/$1\|\{\{$local_media_url\/thumbs\/$1\|$2\}\}\]\]/g;
#extract image from content
if ($event->{content}=~/\{\{(.*?)(\||\}\})/){
$event->{image}=$1;
}
}
#meta
if (defined $event->{comments}){
my $meta=extractMeta($event->{comments});
$event->{meta} = $meta if (@$meta>0);
}
return $event;
}
sub eventToWikiText{
my $event=shift;
my $local_media_url =$event->{local_media_url}||'';
$event->{program} =~s/^\s+|\s+$//g;
$event->{series_name} =~s/^\s+|\s+$//g;
$event->{title} =~s/^\s+|\s+$//g;
$event->{excerpt} =~s/^\s+|\s+$//g;
$event->{content} =~s/^\s+|\s+$//g;
$event->{comments} =~s/^\s+|\s+$//g;
my $title='';
if($event->{program} ne''){
$title=$event->{program};
$title.=': ' if (($event->{series_name} ne'') || ($event->{title} ne''));
}
if($event->{series_name} ne''){
$title.=$event->{series_name};
$title.=' - ' if ($event->{title} ne'');
}
$title.=$event->{title};
if ($event->{categories}){
$title.=' ('.join(",", @{$event->{categories}} ).')' if (@{$event->{categories}}>0);
}
my $meta=extractMeta($event->{comments}, $event->{meta});
#use Data::Dumper;print "extracted meta".Dumper($meta);
$event->{comments}=removeMeta($event->{comments});
$event->{wiki_comments}=$event->{comments}."\n\n".metaToWiki($meta);
#use Data::Dumper;print "event content".Dumper($event->{content});
#rich content editors:
#$event->{wiki_content}=markup::html_to_creole($event->{content});
#markup editors
$event->{wiki_content}=$event->{content};
# [[http://localhost/agenda_files/media/images/Vl8X7YmaWrmm9RMN_OMywA.jpg|{{http://localhost/agenda_files/media/thumbs/Vl8X7YmaWrmm9RMN_OMywA.jpg|}}]]
#replace "thumbs/xxx" link by link to local media URI
# while ($event->{wiki_content}=~/\[\[.*?\/+media\/+images\/+(.*?)\s*\|.*?\{\{.*?\/+media\/+thumbs\/+(.*?)\s*\|\s*(.*?)\s*\}\}\]\]/){
$event->{wiki_content}=~s/\[\[.*?\/+media\/+images\/+(.*?)\s*\|.*?\{\{.*?\/+media\/+thumbs\/+(.*?)\s*\|\s*(.*?)\s*\}\}\]\]/\{\{thumbs\/$1\|$3\}\}/g;
# }
my $wiki_content=join("\n".("-"x20)."\n",($event->{excerpt}, $event->{wiki_content}) );
$wiki_content.="\n".("-"x20)."\n".$event->{wiki_comments} if ($event->{wiki_comments}=~/\S/);
return {
title => $title,
content => $event->{content},
wiki_content => $wiki_content
};
}
#extrace meta tags from comment text
sub extractMeta{
my $comments =shift;
my $meta =shift;
$meta=[] unless (defined $meta);
#push meta tags into meta list
if (defined $comments){
#build index for meta already defined
my $meta_keys={};
for my $pair (@$meta){
$meta_keys->{$pair->{name}.'='.$pair->{value}}=1;
}
while ($comments=~/\~\~META\:(.+?)\=(.+?)\~\~/g){
my $name=$1;
my $value=$2;
#fix meta values
$name=lc($name);
$name=~s/^\s+|\s+$//g;
$value=~s/^\s+|\s+$//g;
#insert into list, if not defined yet
unless( ($name eq'') || ($value eq'') || (exists $meta_keys->{$name.'='.$value}) ){
push @$meta,{
name=>$name,
value=>$value,
};
$meta_keys->{$name.'='.$value}=1;
}
};
}
# use Data::Dumper;print Dumper($meta);
return $meta;
}
#remove meta tags from comment text
sub removeMeta{
my $comments=shift||'';
my $result='';
for my $line (split(/\n/,$comments)){
$result.=$line unless ($line=~/\~\~META\:(.+?)\=(.+?)\~\~/g);
}
#use Data::Dumper;print "removed metsas:".Dumper($result);
$result=~s/^\s+//g;
$result=~s/\s+$//g;
return $result;
}
#add meta tags to comment text
sub metaToWiki{
my $meta =shift;
my $result='';
for my $pair (@$meta){
# use Data::Dumper;print Dumper($pair);
$result.='~~META:'.$pair->{name}.'='.$pair->{value}.'~~'."\n";
}
return $result;
#use Data::Dumper;print Dumper($meta);
}
#test:
#perl -e 'use creole_wiki;$a=creole_wiki::extractEventFromWikiText("teaser\n----------------------\nbody[[asd|download]][[bsd|hallo]][[csd|podcast]]{{a|b}}[[dsd|wer]]\n----------------------\ncomments",{title=>" a : b - c ( d e - f , g h i - j, k - m - l) "});use Data::Dumper;print Dumper($a)';
#do not delete last line!
1;

278
lib/calcms/db.pm Normal file
View File

@@ -0,0 +1,278 @@
use warnings "all";
use strict;
#use DBI;
#use Apache::DBI;
use DBD::mysql;
package db;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
connect disconnect
get insert put
next_id get_max_id
shift_date_by_hours shift_datetime_by_minutes
get_columns get_columns_hash
$write
$read
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#debug settings
our $debug_read=0;
our $debug_write=0;
#database control
our $read=1;
our $write=1;
# connect to database
sub connect{
my $options=shift;
my $request=shift;
return $request->{connection} if ((defined $request) && (defined $request->{connection}));
my $access_options=$options->{access};
my $hostname =$access_options->{hostname};
my $port =$access_options->{port};
my $database =$access_options->{database};
my $username =$access_options->{username};
my $password =$access_options->{password};
if ((defined $access_options->{write}) && ($access_options->{write}eq'1')){
$username =$access_options->{username_write};
$password =$access_options->{password_write};
}
my $dbh=undef;
my $dsn = "DBI:mysql:database=$database;host=$hostname;port=$port";
# if ($db::utf8dbi eq '1'){
# use UTF8DBI;
# $dbh = UTF8DBI->connect( $dsn,$username,$password) || die "Database connection not made: $DBI::errstr"; # \nfor $dsn, $username
# }else{
# use DBI;
$dbh = DBI->connect( $dsn,$username,$password,{mysql_enable_utf8 => 1}) || die "could not connect to database: $DBI::errstr"; # \nfor $dsn, $username
# }
#print STDERR "db connect $username\n" if ($debug_read==1);
#print STDERR "db connect $username\n";
$dbh->{RaiseError} = 1;
$dbh->{'mysql_enable_utf8'} = 1;
put($dbh,"set character set utf8");
put($dbh,"set names utf8");
put($dbh,"set time_zone='".$options->{date}->{time_zone}."'");
$request->{connection}=$dbh;
return $dbh;
}
sub disconnect{
my $request=shift;
my $dbh=$request->{connection};
$dbh->disconnect;
delete $request->{connection};
}
# get all database entries of an sql query (as list of hashs)
sub get{
my $dbh=shift;
my $sql=shift;
my $bind_values=shift;
if ($debug_read==1){
print STDERR $sql."\n";
print STDERR Dumper($bind_values)."\n" if defined $bind_values;
}
my $sth = $dbh->prepare( $sql );
if ((defined $bind_values)&&(ref($bind_values)eq'ARRAY')){
# print STDERR Dumper($bind_values)."\n";
my $result = $sth->execute(@$bind_values);
unless ($result){
print STDERR $sql."\n";
die "db: $DBI::errstr $sql" if ($read==1);
}
}else{
$sth->execute() || die "db: $DBI::errstr $sql" if ($read==1);
}
my @results=();
while ( my $row=$sth->fetchrow_hashref){
my $result={};
foreach my $key (keys %$row){
$result->{$key}=$row->{$key};
}
push @results, $result;
}
if ($debug_read==1){
print STDERR Dumper($results[0])."\n" if (@results==1);
print STDERR @results."\n" if (@results!=1);
}
$sth->finish;
return \@results;
}
# get list of table columns
sub get_columns{
my $dbh=shift;
my $table=shift;
my $columns=db::get($dbh, 'select column_name from information_schema.columns where table_name=?',[$table]);
my @result=map {$_->{column_name}} (@$columns);
return \@result;
}
# get hash with table columns as keys
sub get_columns_hash{
my $dbh=shift;
my $table=shift;
my $columns=db::get_columns($dbh, $table);
my $result={};
for my $column (@$columns){
$result->{$column}=1;
}
return $result;
}
# insert an entry into database (select from where)
sub insert_old{
my $dbh=shift;
my $tablename=shift;
my $entry=shift;
my $do_not_quote=shift;
my $keys =join(",", map {$_} (keys %$entry));
my $values =undef;
if (defined $do_not_quote && $do_not_quote ne ''){
$values =join("\n,", map {$entry->{$_}} (keys %$entry));
}else{
$values =join("\n,", map {$dbh->quote($entry->{$_})} (keys %$entry));
}
my $sql ="insert into $tablename \n ($keys) \n values ($values);\n";
print STDERR $sql."\n" if ($debug_write==1);
put($dbh,$sql);
}
#returns last inserted id
sub insert{
my $dbh=shift;
my $tablename=shift;
my $entry=shift;
# my $do_not_quote=shift;
my $keys =join(",", map {$_} (keys %$entry));
my $values =join(",", map {'?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
my $sql ="insert into $tablename \n ($keys) \n values ($values);\n";
if ($debug_write==1){
print STDERR $sql."\n";
print STDERR Dumper(\@bind_values)."\n" if (@bind_values);
}
put($dbh, $sql, \@bind_values);
my $result=get($dbh, 'SELECT LAST_INSERT_ID() id;');
return $result->[0]->{id} if $result->[0]->{id}>0;
return undef;
}
# execute a modifying database command (update,insert,...)
sub put{
my $dbh=shift;
my $sql=shift;
my $bind_values=shift;
if ($debug_write==1){
print STDERR $sql."\n";
print STDERR Dumper($bind_values)."\n" if defined $bind_values;
}
my $sth = $dbh->prepare( $sql );
if ($write==1){
if ((defined $bind_values)&&(ref($bind_values)eq'ARRAY')){
$sth->execute(@$bind_values);
}else{
$sth->execute();
}
};
$sth->finish;
print STDERR "1\n" if ($debug_write==1);
my $result=get($dbh, 'SELECT ROW_COUNT() changes;');
return $result->[0]->{changes} if $result->[0]->{changes}>0;
return undef;
}
sub quote{
my $dbh=shift;
my $sql=shift;
$sql=~s/\_/\\\_/g;
return $dbh->quote($sql);
}
#subtract hours, deprecated(!)
sub shift_date_by_hours{
my $dbh=shift;
my $date=shift;
my $offset=shift;
my $query='select date(? - INTERVAL ? HOUR) date';
my $bind_values=[$date,$offset];
my $results=db::get($dbh, $query, $bind_values);
return $results->[0]->{date};
}
#add minutes, deprecated(!)
sub shift_datetime_by_minutes{
my $dbh=shift;
my $datetime=shift;
my $offset=shift;
my $query="select ? + INTERVAL ? MINUTE date";
my $bind_values=[$datetime,$offset];
my $results=db::get($dbh, $query, $bind_values);
return $results->[0]->{date};
}
# get next free id of a database table
sub next_id{
my $dbh=shift;
my $table=shift;
my $query=qq{
select max(id) id
from $table
where 1
};
my $results=get($dbh,$query);
return $results->[0]->{id}+1;
}
# get max id from table
sub get_max_id{
my $dbh=shift;
my $table=shift;
my $query=qq{
select max(id) id
from $table
where 1
};
my $results=get($dbh,$query);
return $results->[0]->{id};
}
#do not delete last line!
1;

134
lib/calcms/eventOps.pm Normal file
View File

@@ -0,0 +1,134 @@
package eventOps;
use warnings "all";
use strict;
use series;
use series_dates;
use time;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
setAttributesFromSeriesTemplate
setAttributesFromSchedule
setAttributesFromOtherEvent
setAttributesForCurrentTime
getRecurrenceBaseId
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
# functions: to be separated
sub setAttributesFromSeriesTemplate{
my $config=shift;
my $params=shift;
my $event=shift;
#get attributes from series
my $series=series::get(
$config,{
project_id => $params->{project_id},
studio_id => $params->{studio_id},
series_id => $params->{series_id},
}
);
if(@$series!=1){
uac::print_error("series not found");
return undef;
}
#copy fields from series template
my $serie=$series->[0];
for my $attr(
'program','series_name','title',
'excerpt', 'topic', 'content', 'html_content',
'project','category','location','image', 'live',
'archive_url', 'podcast_url'
){
$event->{$attr}=$serie->{$attr};
}
return $serie;
}
sub setAttributesFromSchedule{
my $config=shift;
my $params=shift;
my $event=shift;
#set attributes from schedule
my $schedules=series_dates::get(
$config, {
project_id => $params->{project_id},
studio_id => $params->{studio_id},
series_id => $params->{series_id},
start_at => $params->{start_date}
}
);
if(@$schedules!=1){
uac::print_error("schedule not found");
return undef;
}
my $schedule=$schedules->[0];
for my $attr(
'start','end',
'day', 'weekday',
'start_date', 'end_date'
){
$event->{$attr}=$schedule->{$attr};
}
my $timezone=$config->{date}->{time_zone};
$event->{duration} = time::get_duration($event->{start}, $event->{end}, $timezone);
return $event;
}
sub setAttributesFromOtherEvent{
my $config=shift;
my $params=shift;
my $event=shift;
my $event2=series::get_event($config, {
allow_any => 1,
#project_id => $params->{project_id},
#studio_id => $params->{studio_id},
#series_id => $params->{series_id},
event_id => $params->{source_event_id}
});
if (defined $event2){
for my $attr ('title', 'user_title', 'excerpt', 'user_excerpt', 'content', 'html_content', 'topics', 'image', 'live', 'no_event_sync', 'podcast_url', 'archive_url'){
$event->{$attr}=$event2->{$attr};
}
$event->{rerun}=1;
$event->{recurrence}=getRecurrenceBaseId($event2);
}
return $event;
}
sub setAttributesForCurrentTime{
my $serie=shift;
my $event=shift;
#on new event not from schedule use current time
if($event->{start}eq''){
$event->{start}=time::time_to_datetime();
if ($event->{start}=~/(\d\d\d\d\-\d\d\-\d\d \d\d)/){
$event->{start}=$1.':00';
}
}
$event->{duration}=$serie->{duration}||60;
$event->{end} =time::add_minutes_to_datetime($event->{start}, $event->{duration});
$event->{end}=~s/(\d\d:\d\d)\:\d\d/$1/;
return $event;
}
# get recurrence base id
sub getRecurrenceBaseId{
my $event = shift;
return $event->{recurrence} if (defined $event->{recurrence}) && ($event->{recurrence} ne '') && ($event->{recurrence} ne '0');
return $event->{event_id};
}

176
lib/calcms/event_history.pm Normal file
View File

@@ -0,0 +1,176 @@
#!/bin/perl
package event_history;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get get_by_id insert insert_by_event_id delete);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_event_history');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
sub get{
my $config=shift;
my $condition=shift;
return undef unless defined $condition->{studio_id};
my $dbh=db::connect($config);
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->{event_id}) && ($condition->{event_id} ne '')){
push @conditions, 'event_id=?';
push @bind_values, $condition->{event_id};
}
if ((defined $condition->{change_id}) && ($condition->{change_id} ne '')){
push @conditions, 'id=?';
push @bind_values, $condition->{change_id};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_event_history
$conditions
order by modified_at desc
$limit
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $changes=db::get($dbh, $query, \@bind_values);
#print STDERR Dumper($changes);
for my $change (@$changes){
$change->{change_id}=$change->{id};
delete $change->{id};
}
return $changes;
}
sub get_by_id{
my $config=shift;
my $id=shift;
my $dbh=db::connect($config);
my $query=qq{
select *
from calcms_event_history
where event_id=?
};
my $studios=db::get($dbh,$query,[$id]);
return undef if (@$studios!=1);
return $studios->[0];
}
sub insert{
my $config=shift;
my $entry=shift;
$entry->{modified_at}= time::time_to_datetime(time());
$entry->{event_id}=$entry->{id} if((defined $entry->{id})&&(!(defined $entry->{event_id})));
delete $entry->{id};
#TODO:filter for existing attributes
my $columns=get_columns($config);
my $event={};
for my $column (keys %$columns){
$event->{$column}=$entry->{$column} if defined $entry->{$column};
}
my $dbh=db::connect($config);
my $id=db::insert($dbh, 'calcms_event_history', $event);
return $id;
}
# insert event
sub insert_by_event_id{
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};
return undef unless defined $options->{event_id};
return undef unless defined $options->{user};
my $sql=q{
select * from calcms_events
where id=?
};
my $bind_values=[$options->{event_id}];
my $dbh=db::connect($config);
my $results=db::get($dbh, $sql, $bind_values);
if(@$results!=1){
print STDERR "cannot find event with event_id=$options->{event_id}";
return 0;
}
# add to history
my $event=$results->[0];
$event->{project_id} = $options->{project_id};
$event->{studio_id} = $options->{studio_id};
$event->{series_id} = $options->{series_id};
$event->{event_id} = $options->{event_id};
$event->{user} = $options->{user};
$event->{deleted} = 1;
event_history::insert($config, $event);
}
sub delete{
my $config=shift;
my $entry=shift;
my $dbh=db::connect($config);
db::put($dbh, 'delete from calcms_event_history where event_id=?', [$entry->{id}]);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

1775
lib/calcms/events.pm Normal file

File diff suppressed because it is too large Load Diff

297
lib/calcms/images.pm Normal file
View File

@@ -0,0 +1,297 @@
use warnings "all";
use strict;
use config;
use template;
package images;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
#our @EXPORT = qw(all);
our @EXPORT_OK = qw(get insert update insert_or_update delete delete_files);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#column 'created_at' will be set at insert
#column 'modified_at' will be set by default (do not update)
my $sql_columns =['filename', 'name', 'description', 'created_by', 'modified_by', 'modified_at', 'studio_id', 'project_id'];
sub get{
my $config=shift;
my $options=shift;
my @cond=();
my $bind_values=[];
if ((defined $options->{project_id}) && ($options->{project_id}ne'')){
push @cond, 'project_id = ?';
push @$bind_values, $options->{project_id};
}
if ((defined $options->{studio_id}) && ($options->{studio_id}ne'')){
push @cond, 'studio_id = ?';
push @$bind_values, $options->{studio_id};
}
if ((defined $options->{filename}) && ($options->{filename}ne'')){
push @cond, 'filename = ?';
push @$bind_values,$options->{filename};
}
if ((defined $options->{from}) && ($options->{from}ne'')){
push @cond, 'date(created_at) >= ?';
push @$bind_values,$options->{from};
}
if ((defined $options->{till}) && ($options->{till}ne'')){
push @cond, 'date(created_at) <= ?';
push @$bind_values,$options->{till};
}
if ((defined $options->{created_by}) && ($options->{created_by}ne'')){
push @cond, 'created_by = ?';
push @$bind_values,$options->{created_by};
}
if ((defined $options->{modified_by}) && ($options->{modified_by}ne'')){
push @cond, 'modified_by = ?';
push @$bind_values,$options->{modified_by};
}
if ((defined $options->{search}) && ($options->{search}ne'')){
push @cond, '(filename like ?'
.' or name like ?'
.' or description like ?'
.' or created_by like ?'
.')';
my $search='%'.$options->{search}.'%';
push @$bind_values,$search;
push @$bind_values,$search;
push @$bind_values,$search;
push @$bind_values,$search;
# push @$bind_values,$search;
}
my $where='';
if (@cond>0){
$where = 'where '.join (' and ', @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 $dbh=db::connect($config);
my $results=db::get($dbh, $query, $bind_values);
#print STDERR @$results."\n";
return $results;
}
sub insert_or_update{
my $dbh=shift;
my $image=shift;
$image->{name}='new' if ($image->{name}eq'');
my $entry=get_by_filename($dbh, $image->{filename});
if (defined $entry){
update($dbh, $image);
}else{
insert($dbh, $image);
}
}
sub insert{
my $dbh=shift;
my $image=shift;
my @sql_columns=@$sql_columns;
#set created at timestamp
push @sql_columns,'created_at';
$image->{created_at}=time::time_to_datetime();
unless (defined $image->{created_by}){
print STDERR "missing created_by at image::insert\n";
return undef;
}
unless (defined $image->{studio_id}){
print STDERR "missing studio_id at image::insert\n";
return undef;
}
unless (defined $image->{project_id}){
print STDERR "missing project_id at image::insert\n";
return undef;
}
my $query=q{
insert into calcms_images(
}.join(',',@sql_columns).qq{
)
values( }.join(', ', (map {'?'} @sql_columns)).q{ )
};
my @bind_values=map { $image->{$_} } @sql_columns;
#print STDERR Dumper($query).Dumper(\@bind_values);
return db::put($dbh, $query, \@bind_values);
}
sub update{
my $dbh=shift;
my $image=shift;
unless (defined $image->{studio_id}){
print STDERR "missing studio_id at images::update\n";
return undef;
}
unless (defined $image->{project_id}){
print STDERR "missing project_id at image::update\n";
return undef;
}
$image->{modified_at}=time::time_to_datetime();
my @set=();
my $bind_values=[];
for my $column (@$sql_columns){
if (defined $image->{$column}){
push @set, $column.' = ?';
push @$bind_values,$image->{$column};
}
}
#conditions
my $conditions=['filename=?'];
push @$bind_values,$image->{filename};
push @$conditions, 'project_id=?';
push @$bind_values, $image->{project_id}||0;
push @$conditions, 'studio_id=?';
push @$bind_values, $image->{studio_id}||0;
return if (@set==0);
my $set=join (",",@set);
$conditions=join(' and ', @$conditions);
my $query=qq{
update calcms_images
set $set
where $conditions
};
#print STDERR Dumper($query).Dumper($bind_values);
return db::put($dbh,$query,$bind_values);
}
sub delete{
my $dbh=shift;
my $image=shift;
unless (defined $image->{project_id}){
print STDERR "missing project_id at images::delete\n";
return undef;
}
unless (defined $image->{project_id}){
print STDERR "missing project_id at images::delete\n";
return undef;
}
unless (defined $image->{filename}){
print STDERR "missing filename at images::delete\n";
return undef;
}
my $project_id = $image->{project_id};
my $studio_id = $image->{studio_id};
my $filename = $image->{filename};
my $conditions = ['filename=?'];
my $bind_values = [$filename];
push @$conditions, 'project_id=?';
push @$bind_values, $studio_id;
push @$conditions, 'studio_id=?';
push @$bind_values, $project_id;
$conditions=join(' and ', @$conditions);
my $query=qq{
delete from calcms_images
where $conditions
};
#print STDERR Dumper($query).Dumper($bind_values);
return db::put($dbh, $query, $bind_values);
}
# deactivated
sub delete_files{
my $config = $_[0];
my $local_media_dir = $_[1];
my $filename = $_[2];
my $action_result = $_[3];
my $errors = $_[4];
return undef;
print log::error($config, 'missing permissions on writing into local media dir')unless(-w $local_media_dir);
if ($filename=~/[^a-zA-Z0-9\.\_\-]/){
log::error($config, "invalid filename: '$filename'");
return;
}
if ($filename=~/\.\./ || $filename=~/^\// || $filename=~/\//){
log::error($config, "invalid filename: '$filename'");
return;
}
log::error($config, 'missing permissions on writing into local_media_dir/images/')unless(-w $local_media_dir.'images/');
log::error($config, 'missing permissions on writing into local_media_dir/thumbs/')unless(-w $local_media_dir.'thumbs/');
log::error($config, 'missing permissions on writing into local_media_dir/icons/') unless(-w $local_media_dir.'icons/');
my $path=$local_media_dir.'/upload/'.$filename;
#delete_file($path,"Upload $filename",$action_result,$errors);
$path=$local_media_dir.'/images/'.$filename;
delete_file($path,"Image $filename",$action_result,$errors);
$path=$local_media_dir.'/thumbs/'.$filename;
delete_file($path,"Thumb $filename",$action_result,$errors);
$path=$local_media_dir.'/icons/'.$filename;
delete_file($path,"Icon $filename",$action_result,$errors);
}
# deactivated
sub delete_file{
my $path = $_[0];
my $type = $_[1];
my $action_result = $_[2];
my $errors = $_[3];
return undef;
unless (-e $path){
$errors.= qq{Error: File does not exist!<br>};
return;
}
unless (-w $path){
$errors.= qq{Error: Cannot write $type<br>};
return;
}
unlink($path);
if ($?==0){
$action_result.= qq{$type deleted<br>};
}else{
$errors.= qq{Error on deleting $type<br>};
}
}
#do not delete last line!
1;

110
lib/calcms/localization.pm Normal file
View File

@@ -0,0 +1,110 @@
package localization;
use warnings "all";
use strict;
use Data::Dumper;
use uac;
use user_settings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get getJavascript);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
# get localisation
# file : po file
# language : get for selected language
# user : get from user settings
# loc : add to existing localization, optional
sub get{
my $config =shift;
my $options=shift;
#print STDERR Dumper($options);
#get pot file
unless (defined $options->{file}){
print STDERR "missing po file\n";
return $options->{loc}||{};
}
my $language=undef;
#get language from options
$language=$options->{language} if (defined $options->{language});
#get language from user
if ( (!(defined $language)) && (defined $options->{user})){
my $user_settings=user_settings::get($config, {user=>$options->{user}});
$language=$user_settings->{language};
}
$language='en' unless defined $language;
$language='en' unless $language eq 'de';
my $loc={};
$loc=$options->{loc} if defined $options->{loc};
my $files=$options->{file};
$files=~s/[^a-zA-Z\,\_\-]//g;
#get all comma separated po files
for my $file (split/\,/,$files){
#read default language
#my $po_file=$config->{locations}->{admin_pot_dir}.'/en/'.$file.'.po';
#$loc=read_po_file($po_file, $loc);
#read selected language
#if($language ne 'en'){
my $po_file=$config->{locations}->{admin_pot_dir}.'/'.$language.'/'.$file.'.po';
$loc=read_po_file($po_file, $loc);
#}
}
return $loc;
}
sub read_po_file{
my $po_file=shift;
my $loc =shift;
unless (-e $po_file){
print STDERR "po file $po_file does not exist\n";
return $loc;
}
unless (-r $po_file){
print STDERR "cannot read po file $po_file\n";
return $loc;
}
my $key='';
open my $file, '<:encoding(UTF-8)', $po_file;
while (<$file>){
my $line=$_;
#print STDERR $line;
if ($line=~/^msgid\s*\"(.*)\"\s*$/){
$key=$1;
$key=~s/\'//g;
$key=~s/\"//g;
}
if ($line=~/^msgstr\s*\"(.*)\"\s*$/){
my $val=$1;
$val=~s/\'//g;
$val=~s/\"//g;
$loc->{$key}=$val;
}
}
return $loc;
}
sub getJavascript{
my $loc=shift;
my $out='<script>';
$out.="var loc={};\n";
for my $key (sort keys %$loc){
$out.=qq{loc['$key']='$loc->{$key}';}."\n";
}
$out.="</script>\n";
return $out;
}
1;

166
lib/calcms/log.pm Normal file
View File

@@ -0,0 +1,166 @@
use warnings "all";
use strict;
use template;
use config;
package log;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
#our @EXPORT = qw(all);
our @EXPORT_OK = qw(init write read error mem);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
#our $debug=0;
our $debug_params='';
our $header="Content-type:text/html\n\n";
our $gtop = undef;
our $proc = undef;
sub init{
my $request =$_[0];
$log::debug_params =$request->{params}->{checked}->{debug}||'';
$log::header =$request->{header}if (defined $request->{header});
#if ($config->{system}->{debug_memory}>0){
#use GTop();
#$log::gtop=GTop->new;
#$log::proc=$gtop->proc_mem($$);
#}
}
sub write{
my $config = shift;
my $key = shift;
my $data = shift;
my $dump = shift;
return unless(defined $config::config->{system}->{debug});
return unless(($config::config->{system}->{debug}>0) &&($log::debug_params=~/$key/));
my $line=Dumper($data);
$line=~s/^\$VAR1 = \{\n/<code>/g;
$line=~s/\};\n$/<\/code>/g;
$line=~s/\n/\\n/g;
my $msg=localtime()." [$key] ".$ENV{REQUEST_URI}."\\n".$line;
$msg.=Dumper($dump) if (defined $dump);
$msg.="\n";
log::print($config, $msg);
}
sub print{
my $config = $_[0];
my $message= $_[1];
unless (defined $config){
print STDERR "missing config at log::error\n";
return;
}
my $filename=$config->{system}->{log_debug_file}||'';
if ($filename eq ''){
print STDERR "calcms config parameter 'system/log_debug_file' not set!\n";
return;
};
open my $FILE, ">>:utf8", $filename or warn("cant write log file '$filename'");
print $FILE $message;
close $FILE;
}
sub error{
my $config = $_[0];
my $message="Error: $_[1]\n";
unless (defined $config){
print STDERR "missing config at log::error\n";
}
print STDERR $message."\n";
if($config::config->{system}->{debug}){
log::write($config, '', $message);# if ($config::config->{system}->{debug}>1);
my $out='';
#do not call template::check to avoid deep recursion!
template::process('print','templates/default.html', {
static_files_url => $config::config->{locations}->{static_files_url},
error=>$message
});
}
# TODO: remove exit
die();
#exit;
}
sub mem{
my $config = $_[0];
return unless $config::config->{system}->{debug_memory};
my $size=$log::gtop->proc_mem($$)->size();
my $format_size=$size;
$format_size=~s/(\d)(\d\d\d)$/$1\.$2/g;
$format_size=~s/(\d)(\d\d\d)(\d\d\d)$/$1\.$2\.$3/g;
my $line=localtime(time())."\t".$$."\t".$format_size."\t".$_[0];
$line.="\t\t".($size-$_[1]) if(defined $_[1]);
log::error($config, "log_memory_file is not defined!") if (!defined $config::config->{system}->{log_debug_memory_file});
log::append_file($config::config->{system}->{log_debug_memory_file} , $line);
}
sub load_file{
my $filename=$_[0];
# my $content=$_[1];
# binmode STDOUT, ":utf8";
my $content='';
if (-e $filename){
my $FILE=undef;
open $FILE, "<:utf8", $filename || warn "cant read file '$filename'";
$content=join "",(<$FILE>);
close $FILE;
return $content;
}
}
sub save_file{
my $filename=$_[0];
my $content=$_[1];
#check if directory is writeable
if ($filename=~/^(.+?)\/[^\/]+$/){
my $dir=$1;
unless (-w $dir){
print STDERR `pwd;id -a;`;
print STDERR "log::save_file : cannot write to directory ($dir)\n";
return;
}
}
open my $FILE, ">:utf8", $filename || warn("cant write file '$filename'");
if (defined $FILE){
print $FILE $content."\n";
close $FILE;
}
}
sub append_file{
my $filename =$_[0];
my $content =$_[1];
unless ( (defined $filename) && ($filename ne'') && (-e $filename) ){
print STDERR "cannot append, file '$filename' does not exist\n";
return;
}
if (defined $content){
open my $FILE, ">>:utf8", $filename or warn("cant write file '$filename'");
print $FILE $content."\n";
close $FILE;
}
}
#do not delete last line!
1;

485
lib/calcms/markup.pm Normal file
View File

@@ -0,0 +1,485 @@
use warnings "all";
use strict;
use Data::Dumper;
use Text::WikiCreole;
use HTML::Parse;
use HTML::FormatText;
use log;
package markup;
use Encode;
require Exporter;
our @ISA = qw(Exporter);
#our @EXPORT = qw(all);
our @EXPORT_OK = qw(fix_line_ends html_to_creole creole_to_html creole_to_plain plain_to_ical ical_to_plain ical_to_xml html_to_plain fix_utf8 uri_encode compress base26);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub fix_line_ends{
my $s=shift;
$s=~s/\r?\n|\r/\n/g;
return $s;
}
# convert 1..26 to a..z, 27 to aa, inspired by ConvertAA
sub base26{
my $num = shift ;
return '' if $num <= 0;
my $s = "";
while($num){
$s= chr (--$num % 26 + ord "a").$s;
$num = int $num/26;
}
return $s;
}
sub html_to_creole{
my $s=shift;
#remove elements
# $s=~s/[\r\f\n]+/\n/gi;
# $s=~s/<\/p.*?>//gi;
# $s=~s/<\/br.*?>//gi;
$s=~s/\<\!\-\-[\s\S]*?\-\-\>//gi;
$s=~s/<script.*?>.*?<\/script.*?>//gi;
# $s=~s/<\/?span.*?>//gi;
# $s=~s/<\/?font.*?>//gi;
# $s=~s/<\/?meta.*?>//gi;
# $s=~s/<\/?title.*?>//gi;
# $s=~s/<\/?style.*?>//gi;
# $s=~s/<\/?col.*?>//gi;
# $s=~s/<\/?thead.*?>//gi;
# $s=~s/<\/?tbody.*?>//gi;
$s=~s/<\/?form.*?>//gi;
$s=~s/<\/?select.*?>//gi;
$s=~s/<\/?option.*?//gi;
$s=~s/<\/?input.*?>//gi;
# $s=~s/<\/?button.*?>//gi;
# $s=~s/<\/?textarea.*?>//gi;
$s=~s/<\/?script.*?>//gi;
#table elements
# $s=~s/\s*<\/?td.*?>//gi;
# $s=~s/\s*<\/?th.*?>//gi;
#remove line breaks
$s=~s/[\r\n]+/ /gi;
#formats
$s=~s/<img.*?src="(.*?)".*?>/{{$1\|}}/gi;
$s=~s/<img.*?title="(.*?)".*?>/{{$2\|$1}}/gi;
$s=~s/<img.*?src="(.*?)"[^>]*?title="(.*?)".*?>/{{$1\|$2}}/gi;
$s=~s/<img.*?title="(.*?)"[^>]*?src="(.*?)".*?>/{{$2\|$1}}/gi;
$s=~s/<\/?img.*?>//gi;
#replace line breaks from images
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
$s=~s/<i.*?>(.*?)<\/i>/\/\/$1\/\//gi;
$s=~s/<\/?i.*?>//gi;
$s=~s/<b.*?>(.*?)<\/b>/\*\*$1\*\*/gi;
# $s=~s/<\/?b.*?>//gi;
$s=~s/<strong.*?>(.*?)<\/strong>/\*\*$1\*\*/gi;
$s=~s/<em.*?>(.*?)<\/em>/\/\/$1\/\//gi;
$s=~s/<blockquote.*?>((\W+|\w+)*?)<\/blockquote>/{{{$1}}}/gi;
# $s=~s/<a\s+.*?href="(.*?)".*?>((\W+|\w+)*?)<\/a>/\[\[$1\|$2\]\]$3/gi;
$s=~s/<a\s+.*?href="(.*?)".*?>(.*?)(\s*)<\/a>/\[\[$1\|$2\]\]$3/gi;
$s=~s/<a.*?>//gi;
#replace line breaks from links
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
# print STDERR Dumper($s) if ($s=~/</);
$s=~s/[\s]+/ /gi;
# $s=~s/\n[ \t\r\n]+\n/\n\n/gi;
# $s=~s/\n[ ]+/\n /gi;
# $s=~s/\n+/\n/gi;
# $s=~s/\n+/\\\n/gi;
#line elements, increase head line level to avoid breaking single = chars
$s=~s/\s*<h1.*?>/== /gi;
$s=~s/\s*<h2.*?>/=== /gi;
$s=~s/\s*<h3.*?>/==== /gi;
$s=~s/\s*<h\d.*?>/===== /gi;
# $s=~s/\s*<\/h\d.*?>/\n/gi;
# $s=~s/<br.*?>/\\\\<br>/gi;
# $s=~s/\s*<div.*?>//gi;
# $s=~s/\s*<\/div>/\n/gi;
# $s=~s/<table.*?>/\n/gi;
# $s=~s/<\/table>/\n/gi;
# $s=~s/\s*<tr.*?>//gi;
# $s=~s/\s*<\/tr>//gi;
# $s=~s/\s*<ol.*?>/\n/gi;
# $s=~s/\s*<\/ol>/\n/gi;
# $s=~s/\s*<ul.*?>/\n/gi;
# $s=~s/\s*<\/ul>/\n/gi;
# $s=~s/\s*<li.*?>/\n\* /gi;
# $s=~s/\s*<\/li>//gi;
# $s=~s/\s*<p.*?>\s*/\n\n/gi;
# $s=~s/\s*<br.*?>\s*/\n /gi;
my $tree=HTML::Parse::parse_html('<body>'.$s.'</body>');
my $formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 2000);
$s= $formatter->format($tree);
#use Data::Dumper; print "asd:<textarea cols=100 rows=5>".Dumper($s);print "</textarea>";
$s=~s/\</\&lt;/g;
#fix line endings
$s=~s/\n[ \t]+/\n/gi;
#$s=~s/\n[\t\r ]+\n/\n\n/g;
$s=~s/\n{3,99}/\n\n/g;
$s=~s/\n*\*[\s]+/\n\* /g;
#$s=~s/(\n\*.*?\n)([^\*])/$1\n\n$2/g;
#enter line break before headlines
$s=~s/(={2,99})/\n$1/g;
#reduce head line level
$s=~s/=(=+)/$1/g;
$s=~s/^\s+//gi;
$s=~s/\s+$//gi;
$s=~s/\n{3,99}/\n\n/g;
# $s=~s/\n\n+/ \\\\\n/g;
$s=~s/\n/\\\\\n/g;
$s=~s/\\\\\n\=/\n\=/g;
#$s=~s/\n\n/ \\\\\n/g;
# $s=~s/(\\\\\n){3,99}/\\\\\n\\\\\n/g;
#$s=~s/\\\\[ \t]+/\\\\\n/g;
# $s=~s/<\/a>//gi;
return $s;
}
sub creole_to_html{
my $s=$_[0]||'';
#$s=~s/\n\#\n/\n/g;
#fix_line_ends($s);
$s=~s/<a\s+.*?href="(.*?)".*?>(.*?)(\s*)<\/a>/\[\[$1\|$2\]\]$3/gi;
$s=~s/<a.*?>//gi;
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
$s=~s/(\[\[[^\]\n]*?)\n([^\]]*?\]\])/$1$2/g;
$s=~s/^\s+//g;
$s=~s/\s+$//g;
$s=Text::WikiCreole::creole_parse($s)||'';
# $s=~s/<p>/\n/gi;
# $s=~s/\{\{\{((\W+|\w+)+?)\}\}\}/<blockquote>$1<\/blockquote>/g;
# $s=~s/\{\{(.+?)\|(.*?)\}\}/<img src="$1" title="$2" \/>/g;
# $s=~s/\[\[(.+?)\|(.*?)\]\]/<a href="$1">$2<\/a>/g;
# $s=~s/([^\:])\/\/(.*?[^\:])\/\//$1<em>$2<\/em> /g;
# $s=~s/\n=== (.*?)\n/<h3>$1<\/h3>\n/g;
# $s=~s/\n== (.*?)\n/<h2>$1<\/h2>\n/g;
#replace line breaks from images
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
$s=~s/(\{\{[^\}\n]*?)\n([^\}\n]*?\}\})/$1$2/g;
#replace line breaks from links
# $s=~s/\n= (.*?)\n/<h1>$1<\/h1>\n/g;
# $s=~s/\*\*(.*?)\*\*/<strong>$1<\/strong> /g;
# $s=~s/^== (.*?)\n/<h2>$1<\/h2>\n/g;
# $s=~s/\n\* (.*?)([\r\n]+)/<li>$1<\/li>\n/g;
# $s=~s/\n\- (.*?)\n/<lo>$1<\/lo>\n/g;
# $s=~s/\n\n/<p>/gi;
# $s=~s/\n+/<br \/>/gi;
# $s=~s/\</\&lt;/g;
#remove whitespaces and break lines at start or end of elements
for my $elem ('p','li'){
$s=~s|<$elem>\s*<br/><br/>|<$elem>|g;
$s=~s|<br/><br/>\s*</$elem>|</$elem>|g;
}
return $s;
}
sub creole_to_plain{
my $s=shift;
$s=~s/\<p\>/\n/gi;
$s=~s/\{\{\{((\W+|\w+)+?)\}\}\}/<blockquote>$1<\/blockquote>/g;
$s=~s/\{\{(.+?)\|(.*?)\}\}//g;
$s=~s/\[\[(.+?)\|(.*?)\]\]/$2/g;
$s=~s/\/\/([^\/\/]*?)\/\//<em>$1<\/em> /g;
$s=~s/\n=== (.*?)\n/\n<h3>$1<\/h3>\n/g;
$s=~s/\n== (.*?)\n/\n<h2>$1<\/h2>\n/g;
$s=~s/\*\*(.*?)\*\*/<strong>$1<\/strong> /g;
$s=~s/^== (.*?)\n/<h2>$1<\/h2>\n/g;
$s=~s/\n\* (.*?)\n/\n<li>$1<\/li>\n/g;
$s=~s/\n\* (.*?)\n/\n<li>$1<\/li>\n/g;
$s=~s/\n\- (.*?)\n/\n<lo>$1<\/lo>\n/g;
$s=~s/\n\- (.*?)\n/\n<lo>$1<\/lo>\n/g;
$s=~s/\n\n/\n<p>/gi;
$s=~s/\n/\n<br\/>/gi;
return $s;
}
sub html_to_plain{
my $s=shift;
return '' unless (defined $s);
my $tree=HTML::Parse::parse_html('<body>'.$s.'</body>');
my $formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 2000);
$s= $formatter->format($tree);
return $s;
}
sub ical_to_plain{
return '' unless defined ($_[0]);
$_[0]=~s/\\n/\n/gi;
$_[0]=~s/ /\t/gi;
$_[0]=~s/\\\./\./gi;
$_[0]=~s/\\\,/\,/gi;
$_[0]=~s/\\\\/\\/gi;
return $_[0];
}
sub plain_to_ical{
return '' unless defined ($_[0]);
#remove images + links
$_[0]=~s/\[\[.+?\|(.+?)\]\]/$1/g;
$_[0]=~s/\{\{.+?\}\}//g;
$_[0]=~s/^\s+//g;
$_[0]=~s/\\/\\\\/gi;
$_[0]=~s/\,/\\\,/gi;
# $_[0]=~s/\./\\\./gi;
$_[0]=~s/[\r\n]/\\n/gi;
$_[0]=~s/\t/ /gi;
return $_[0];
}
sub plain_to_xml{
return '' unless defined ($_[0]);
$_[0]=~s/\n\={1,6} (.*?)\s+/\n\[\[$1\]\]\n/gi;
#remove images + links
$_[0]=~s/\[\[.+?\|(.+?)\]\]/$1/g;
$_[0]=~s/\{\{.+?\}\}//g;
return encode_xml_element($_[0]);
# $_[0]=~s/\&auml;/ä/gi;
# $_[0]=~s/\&ouml;/ö/gi;
# $_[0]=~s/\&uuml;/ü/gi;
# $_[0]=~s/\&Auml;/Ä/gi;
# $_[0]=~s/\&Ouml;/Ö/gi;
# $_[0]=~s/\&Uuml;/Ü/gi;
# $_[0]=~s/\&szlig;/ß/gi;
# $_[0]=~s/\&/\&amp;/gi;
# $_[0]=~s/\</\&lt;/gi;
# $_[0]=~s/\>/\&gt;/gi;
# $_[0]=~s/\"/\&quot;/gi;
## $_[0]=~s/\n/<br\/>/gi;
## $_[0]=~s/\&amp;amp;/\&amp;/gi;
## $_[0]=~s/\&amp;amp;/+/gi;
## $_[0]=~s/\&amp;/+/gi;
## $_[0]=~s/\&/+/gi;
# return $_[0];
}
sub fix_utf8{
$_[0] = decode( 'cp1252', $_[0] );
return $_[0];
}
sub uri_encode{
$_[0] =~s/([^a-zA-Z0-9_\.\-])/sprintf("%%%02lx",ord($1))/esg;
return $_[0];
}
sub compress{
my $header='';
if($_[0]=~/(Content\-type\:[^\n]+[\n]+)/){
$header=$1;
}else{
#return;
}
my $start=index($_[0],$header);
return if ($start<0);
my $header_length=length($header);
$header =substr($_[0],0,$start+$header_length);
# print $header."\n";
my $content=substr($_[0],$start+$header_length);
# #remove multiple line breaks
$content=~s/[\r\n]+[\s]*[\r\n]+/\n/g;
#remove leading whitespaces
$content=~s/[\r\n]+[\s]+/\n/g;
#remove tailing whitespaces
$content=~s/[\t ]*[\r\n]+/\n/g;
#remove whitespaces inside tags
$content=~s/([\n]\<[^\n]+)[\r\n]+/$1 /g;
$content=~s/\"\s+\>/\"\>/g;
#get closing tags closer
$content=~s/[\r\n]+(\<[\/\!])/$1/g;
$content=~s/(\>)[\r\n]+([^\<])/$1$2/g;
#remove leading whitespaces
#$content=~s/[\r\n]+([\d\S])/$1/g;
#remove empty lines
$content=~s/[\n\r]+/\n/g;
#remove whitespaces between tags
$content=~s/\>[\t ]+\<(^\/T)/\>\<$1/g;
#multiple whitespaces
$content=~s/[\t ]+/ /g;
#restore content-type line break
$_[0]=$header.$content;
#$_[0]=~s/HTTP_CONTENT_TYPE/\n\n/;
# return $_[0];
}
#from XML::RSS.pm
my %entity = (
nbsp => "&#160;",
iexcl => "&#161;",
cent => "&#162;",
pound => "&#163;",
curren => "&#164;",
yen => "&#165;",
brvbar => "&#166;",
sect => "&#167;",
uml => "&#168;",
copy => "&#169;",
ordf => "&#170;",
laquo => "&#171;",
not => "&#172;",
shy => "&#173;",
reg => "&#174;",
macr => "&#175;",
deg => "&#176;",
plusmn => "&#177;",
sup2 => "&#178;",
sup3 => "&#179;",
acute => "&#180;",
micro => "&#181;",
para => "&#182;",
middot => "&#183;",
cedil => "&#184;",
sup1 => "&#185;",
ordm => "&#186;",
raquo => "&#187;",
frac14 => "&#188;",
frac12 => "&#189;",
frac34 => "&#190;",
iquest => "&#191;",
Agrave => "&#192;",
Aacute => "&#193;",
Acirc => "&#194;",
Atilde => "&#195;",
Auml => "&#196;",
Aring => "&#197;",
AElig => "&#198;",
Ccedil => "&#199;",
Egrave => "&#200;",
Eacute => "&#201;",
Ecirc => "&#202;",
Euml => "&#203;",
Igrave => "&#204;",
Iacute => "&#205;",
Icirc => "&#206;",
Iuml => "&#207;",
ETH => "&#208;",
Ntilde => "&#209;",
Ograve => "&#210;",
Oacute => "&#211;",
Ocirc => "&#212;",
Otilde => "&#213;",
Ouml => "&#214;",
times => "&#215;",
Oslash => "&#216;",
Ugrave => "&#217;",
Uacute => "&#218;",
Ucirc => "&#219;",
Uuml => "&#220;",
Yacute => "&#221;",
THORN => "&#222;",
szlig => "&#223;",
agrave => "&#224;",
aacute => "&#225;",
acirc => "&#226;",
atilde => "&#227;",
auml => "&#228;",
aring => "&#229;",
aelig => "&#230;",
ccedil => "&#231;",
egrave => "&#232;",
eacute => "&#233;",
ecirc => "&#234;",
euml => "&#235;",
igrave => "&#236;",
iacute => "&#237;",
icirc => "&#238;",
iuml => "&#239;",
eth => "&#240;",
ntilde => "&#241;",
ograve => "&#242;",
oacute => "&#243;",
ocirc => "&#244;",
otilde => "&#245;",
ouml => "&#246;",
divide => "&#247;",
oslash => "&#248;",
ugrave => "&#249;",
uacute => "&#250;",
ucirc => "&#251;",
uuml => "&#252;",
yacute => "&#253;",
thorn => "&#254;",
yuml => "&#255;",
);
my $entities = join('|', keys %entity);
sub encode_xml_element {
my $text = shift;
my $encoded_text = '';
while ( $text =~ s/(.*?)(\<\!\[CDATA\[.*?\]\]\>)//s ) {
$encoded_text .= encode_xml_element_text($1) . $2;
}
$encoded_text .= encode_xml_element_text($text);
return $encoded_text;
}
sub encode_xml_element_text {
my $text = shift;
$text =~ s/&(?!(#[0-9]+|#x[0-9a-fA-F]+|\w+);)/&amp;/g;
$text =~ s/&($entities);/$entity{$1}/g;
$text =~ s/\</\&lt\;/g;
$text =~ s/\>/\&gt\;/g;
return $text;
}
#do not delete last line!
1;

83
lib/calcms/params.pm Normal file
View File

@@ -0,0 +1,83 @@
package params;
use warnings "all";
use strict;
use Data::Dumper;
use CGI;
use Apache2::Request;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get isJson);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
my $isJson=0;
sub isJson{
return $isJson;
}
sub get{
#get the Apache2::RequestRec
my $r=shift;
my $tmp_dir ='/var/tmp/';
my $upload_limit=1000*1024;
my $cgi = undef;
my $status = undef;
my $params = {};
$isJson=0;
if (defined $r){
#print STDERR "Apache2::Request\n";
#get Apache2::Request
my $req = Apache2::Request->new($r, POST_MAX => $upload_limit, TEMP_DIR => $tmp_dir);
for my $key ($req->param){
$params->{scalar($key)}=scalar($req->param($key));
}
#copy params to hash
#my $body=$req->body();
#if (defined $body){
# for my $key (keys %$body){
# $params->{scalar($key)}=scalar($req->param($key));
# }
#}
$status = $req->parse; #parse
}else{
#print STDERR "CGI\n";
$CGI::POST_MAX = $upload_limit;
$CGI::TMPDIRECTORY=$tmp_dir;
$cgi=new CGI();
$status=$cgi->cgi_error()||$status;
my %params=$cgi->Vars();
$params=\%params;
}
$cgi=new CGI() unless(defined $cgi);
$isJson=1 if (defined $params->{json}) && ($params->{json}eq'1');
if(defined $status){
$status='' if ($status eq 'Success');
$status='' if ($status eq 'Missing input data');
print $cgi->header.$status."\n" if($status ne'');
}
#print STDERR Dumper($params);
#print $cgi->header.Dumper($params).$status;
return ($cgi, $params, $status);
}
sub debug{
my $message=shift;
#print "$msg<br/>\n" if ($debug>0);
#print "$message<br>\n";
#log::print($message."\n") if ($debug);
}
#do not delete last line!
1;

367
lib/calcms/playout.pm Normal file
View File

@@ -0,0 +1,367 @@
#!/bin/perl
package playout;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use db;
use time;
use series_events;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get sync);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_playout');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get playout entries
sub get{
my $config=shift;
my $condition=shift;
return undef unless defined $condition->{studio_id};
my $date_range_include=0;
$date_range_include=1 if $condition->{date_range_include}==1;
my $dbh=db::connect($config);
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->{start_at}) && ($condition->{start_at} ne '')){
push @conditions, 'start=?';
push @bind_values, $condition->{start_at};
}
if ((defined $condition->{from}) && ($condition->{from} ne '')){
if ($date_range_include==1){
push @conditions, 'end_date>=?';
push @bind_values, $condition->{from};
}else{
push @conditions, 'start_date>=?';
push @bind_values, $condition->{from};
}
}
if ((defined $condition->{till}) && ($condition->{till} ne '')){
if ($date_range_include==1){
push @conditions, 'start_date<=?';
push @bind_values, $condition->{till};
}else{
push @conditions, 'end_date<=?';
push @bind_values, $condition->{till};
}
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select date(start) start_date
,date(end) end_date
,dayname(start) weekday
,start_date day
,start
,end
,studio_id
,project_id
,duration
,file
,errors
,channels
,format
,format_version
,format_profile
,format_settings
,stream_size
,bitrate
,bitrate_mode
,sampling_rate
,writing_library
,rms_left
,rms_right
,rms_image
from calcms_playout
$conditions
order by start
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
return $entries;
}
# update playout entries for a given date span
# insert, update and delete entries
sub sync{
my $config=shift;
my $options=shift;
#print STDERR Dumper($config);
#print STDERR Dumper($options);
return undef unless defined $options->{project_id} ;
return undef unless defined $options->{studio_id} ;
return undef unless defined $options->{from} ;
return undef unless defined $options->{till} ;
return undef unless defined $options->{events} ;
my $project_id = $options->{project_id};
my $studio_id = $options->{studio_id};
my $updates = $options->{events};
#print STDERR "sync\n";
#print STDERR Dumper($updates);
# get new entries by date
my $update_by_date={};
for my $entry (@$updates){
$update_by_date->{$entry->{start}}=$entry;
}
# get database entries
my $bind_values=[
$options->{project_id}, $options->{studio_id}, $options->{from}, $options->{till}
];
my $query=qq{
select *
from calcms_playout
where project_id=?
and studio_id=?
and start >=?
and end <= ?
order by start
};
print STDERR "from:$options->{from} till:$options->{till}\n";
my $dbh=db::connect($config);
my $entries=db::get($dbh, $query, $bind_values);
#print STDERR "entries:".Dumper($entries);
# get database entries by date
my $entries_by_date={};
for my $entry (@$entries){
# store entry by date
my $start=$entry->{start};
$entries_by_date->{$start}=$entry;
# remove outdated entries
unless (defined $update_by_date->{$start}){
print STDERR "delete:".Dumper($entry);
playout::delete($config, $dbh, $entry);
my $result=series_events::set_playout_status($config, {
project_id => $project_id,
studio_id => $studio_id,
start => $entry->{start},
playout => 0,
});
print STDERR "delete playout_status result=".$result."\n";
next;
}
# update existing entries
if (defined $update_by_date->{$start}){
next if has_changed($entry, $update_by_date->{$start})==0;
print STDERR "update:".Dumper($entry);
playout::update($config, $dbh, $entry, $update_by_date->{$start});
my $result=series_events::set_playout_status($config, {
project_id => $project_id,
studio_id => $studio_id,
start => $entry->{start},
playout => 1,
});
print STDERR "update playout_status result=".$result."\n";
next;
}
}
# insert new entries
for my $entry (@$updates){
my $start=$entry->{start};
unless (defined $entries_by_date->{$start}){
$entry->{project_id} = $project_id;
$entry->{studio_id} = $studio_id;
print STDERR "insert:".Dumper($entry);
playout::insert($config, $dbh, $entry);
my $result=series_events::set_playout_status($config, {
project_id => $project_id,
studio_id => $studio_id,
start => $entry->{start},
playout => 1,
});
print STDERR "insert playout_status result=".$result."\n";
}
}
return 1;
}
sub has_changed{
my $oldEntry=shift;
my $newEntry=shift;
my $update=0;
for my $key ('duration', 'errors', 'file', 'channels', 'format', 'format_version', 'format_profile', 'format_settings', 'stream_size', 'bitrate', 'bitrate_mode', 'sampling_rate', 'writing_library'){
return 1 if ($oldEntry->{$key}||'') ne ($newEntry->{$key}||'');
}
return 0;
}
# update playout entry if differs to old values
sub update{
my $config=shift;
my $dbh=shift;
my $oldEntry=shift;
my $newEntry=shift;
return if has_changed($oldEntry, $newEntry)==0;
for my $key ('duration', 'errors', 'file', 'channels', 'format', 'format_version', 'format_profile', 'format_settings', 'stream_size', 'bitrate', 'bitrate_mode', 'sampling_rate', 'writing_library', 'rms_left', 'rms_right', 'rms_image', 'replay_gain'){
if (($oldEntry->{$key}||'') ne ($newEntry->{$key}||'')){
$oldEntry->{$key}=$newEntry->{$key};
}
}
my $entry=$oldEntry;
print STDERR "update:".Dumper($entry);
my $day_start=$config->{date}->{day_starting_hour};
$entry->{end} = playout::getEnd($entry->{start}, $entry->{duration});
$entry->{start_date} = time::add_hours_to_datetime($entry->{start}, -$day_start);
$entry->{end_date} = time::add_hours_to_datetime($entry->{end}, -$day_start);
my $bind_values=[
$entry->{end}, $entry->{duration}, $entry->{file}, $entry->{errors},
$entry->{start_date}, $entry->{end_date},
$entry->{channels}, $entry->{'format'}, $entry->{format_version}, $entry->{format_profile}, $entry->{format_settings}, $entry->{stream_size},
$entry->{bitrate}, $entry->{bitrate_mode}, $entry->{sampling_rate}, $entry->{writing_library},
$entry->{rms_left}, $entry->{rms_right}, $entry->{rms_image},
$entry->{replay_gain},
$entry->{project_id}, $entry->{studio_id}, $entry->{start}
];
my $query=qq{
update calcms_playout
set end=?, duration=?, file=?, errors=?,
start_date=?, end_date=?,
channels=?, format=?, format_version=?, format_profile=?, format_settings=?, stream_size=?,
bitrate=?, bitrate_mode=?, sampling_rate=?, writing_library=?,
rms_left=?, rms_right=?, rms_image=?,
replay_gain=?
where project_id=? and studio_id=? and start=?
};
return db::put($dbh, $query, $bind_values);
}
# insert playout entry
sub insert{
my $config=shift;
my $dbh=shift;
my $entry=shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
return undef unless defined $entry->{start};
return undef unless defined $entry->{duration};
return undef unless defined $entry->{file};
my $day_start=$config->{date}->{day_starting_hour};
$entry->{end} = playout::getEnd($entry->{start}, $entry->{duration});
$entry->{start_date} = time::add_hours_to_datetime($entry->{start}, -$day_start);
$entry->{end_date} = time::add_hours_to_datetime($entry->{end}, -$day_start);
return db::insert($dbh, 'calcms_playout', {
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
start => $entry->{start},
end => $entry->{end},
start_date => $entry->{start_date},
end_date => $entry->{end_date},
duration => $entry->{duration},
rms_left => $entry->{rms_left},
rms_right => $entry->{rms_right},
rms_image => $entry->{rms_image},
replay_gain => $entry->{replay_gain},
file => $entry->{file},
errors => $entry->{errors},
channels => $entry->{channels},
"format" => $entry->{"format"},
format_version => $entry->{format_version},
format_profile => $entry->{format_profile},
format_settings => $entry->{format_settings},
stream_size => $entry->{stream_size},
bitrate => $entry->{bitrate},
bitrate_mode => $entry->{bitrate_mode},
sampling_rate => $entry->{sampling_rate},
writing_library => $entry->{writing_library}
});
}
# delete playout entry
sub delete{
my $config=shift;
my $dbh=shift;
my $entry=shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
return undef unless defined $entry->{start};
my $query=qq{
delete
from calcms_playout
where project_id=? and studio_id=? and start=?
};
my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{start}];
return db::put($dbh, $query, $bind_values);
}
sub getEnd{
my $start=shift;
my $duration=shift;
# calculate end from start + duration
my @start = @{time::datetime_to_array($start)};
next unless @start>=6;
#print STDERR Dumper(\@start);
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$start[0], $start[1], $start[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, 0, int($duration) # delta days, hours, minutes, seconds
);
#print STDERR Dumper(\@end_datetime);
return time::array_to_datetime(\@end_datetime);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

478
lib/calcms/project.pm Normal file
View File

@@ -0,0 +1,478 @@
#!/bin/perl
package project;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use config;
use log;
use template;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
check get_columns get insert delete get_date_range
get_studios assign_studio unassign_studio is_studio_assigned get_studio_assignments
get_series_ids assign_series unassign_series is_series_assigned get_series_assignments
get_with_dates get_sorted
);
#TODO: globally replace get_studios by get_studio_assignments
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
# get project columns
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_projects');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get projects
sub get{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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->{name}) && ($condition->{name} ne '')){
push @conditions, 'name=?';
push @bind_values, $condition->{name};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_projects
$conditions
order by start_date
$limit
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $projects=db::get($dbh, $query, \@bind_values);
return $projects;
}
sub get_date_range{
my $config=shift;
my $query=qq{
select min(start_date) start_date, max(end_date) end_date
from calcms_projects
};
my $dbh=db::connect($config);
my $projects=db::get($dbh, $query);
return $projects->[0];
}
# insert project
sub insert{
my $config=shift;
my $entry=shift;
my $columns=get_columns($config);
my $project={};
for my $column (keys %$columns){
$project->{$column}=$entry->{$column} if defined $entry->{$column};
}
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;
my $project=shift;
my $columns=project::get_columns($config);
my $entry={};
for my $column (keys %$columns){
$entry->{$column}=$project->{$column} if defined $project->{$column};
}
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{project_id};
my $query=qq{
update calcms_projects
set $values
where project_id=?
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $dbh=db::connect($config);
db::put($dbh, $query, \@bind_values);
}
# get studios of a project
sub get_studios{
my $config=shift;
my $options=shift;
return undef unless defined $options->{project_id};
my $project_id=$options->{project_id};
my $query=qq{
select *
from calcms_project_studios
where project_id=?
};
my $dbh=db::connect($config);
my $project_studios=db::get($dbh,$query,[$project_id]);
return $project_studios;
}
sub get_studio_assignments{
my $config=shift;
my $options=shift;
my @conditions=();
my @bind_values=();
if ((defined $options->{project_id}) && ($options->{project_id} ne '')){
push @conditions, 'project_id=?';
push @bind_values, $options->{project_id};
}
if ((defined $options->{studio_id}) && ($options->{studio_id} ne '')){
push @conditions, 'studio_id=?';
push @bind_values, $options->{studio_id};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_project_studios
$conditions
};
my $dbh=db::connect($config);
my $results=db::get($dbh, $query, \@bind_values);
return $results;
}
# is studio assigned to project
sub is_studio_assigned{
my $config=shift;
my $entry=shift;
return 0 unless defined $entry->{project_id};
return 0 unless defined $entry->{studio_id};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
my $query=qq{
select *
from calcms_project_studios
where project_id=? and studio_id=?
};
my $bind_values=[$project_id, $studio_id];
my $dbh=db::connect($config);
my $project_studios=db::get($dbh, $query, $bind_values);
return 1 if @$project_studios==1;
return 0;
}
# assign studio to project
sub assign_studio{
my $config=shift;
my $entry=shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
if (is_studio_assigned($entry)){
print STDERR "studio $entry->{studio_id} already assigned to project $entry->{project_id}\n";
return 1;
}
my $dbh=db::connect($config);
my $id=db::insert($dbh, 'calcms_project_studios', $entry);
return $id;
}
# unassign studio from project
sub unassign_studio{
my $config=shift;
my $entry=shift;
return undef unless defined $entry->{project_id};
return undef unless defined $entry->{studio_id};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
my $sql='delete from calcms_project_studios where project_id=? and studio_id=?';
my $bind_values=[$project_id, $studio_id];
my $dbh=db::connect($config);
return db::put($dbh, $sql, $bind_values);
}
# get series by project and studio
sub get_series{
my $config=shift;
my $options=shift;
return undef unless defined $options->{project_id};
return undef unless defined $options->{studio_id};
my $project_id=$options->{project_id};
my $studio_id= $options->{studio_id};
my $query=qq{
select *
from calcms_project_series
where project_id=? and studio_id=?
};
my $bind_values=[$project_id, $studio_id];
my $dbh=db::connect($config);
my $project_series=db::get($dbh, $query, $bind_values);
return $project_series;
}
sub get_series_assignments{
my $config=shift;
my $options=shift;
my @conditions=();
my @bind_values=();
if ((defined $options->{project_id}) && ($options->{project_id} ne '')){
push @conditions, 'project_id=?';
push @bind_values, $options->{project_id};
}
if ((defined $options->{studio_id}) && ($options->{studio_id} ne '')){
push @conditions, 'studio_id=?';
push @bind_values, $options->{studio_id};
}
if ((defined $options->{series_id}) && ($options->{series_id} ne '')){
push @conditions, 'series_id=?';
push @bind_values, $options->{series_id};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_project_series
$conditions
};
my $dbh=db::connect($config);
my $results=db::get($dbh, $query, \@bind_values);
return $results;
}
# is series assigned to project and studio
sub is_series_assigned{
my $config=shift;
my $entry=shift;
return 0 unless defined $entry->{project_id};
return 0 unless defined $entry->{studio_id};
return 0 unless defined $entry->{series_id};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
my $series_id= $entry->{series_id};
my $query=qq{
select *
from calcms_project_series
where project_id=? and studio_id=? and series_id=?
};
my $bind_values=[$project_id, $studio_id, $series_id];
my $dbh=db::connect($config);
my $project_series=db::get($dbh,$query, $bind_values);
return 1 if @$project_series==1;
return 0;
}
# assign series to project and studio
sub assign_series{
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};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
my $series_id= $entry->{series_id};
if (is_series_assigned($entry)){
print STDERR "series $series_id already assigned to project $project_id and studio $studio_id\n";
return return undef;
}
my $dbh=db::connect($config);
my $id=db::insert($dbh, 'calcms_project_series', $entry);
print STDERR "assigned series $series_id to project $project_id and studio $studio_id\n";
return $id;
}
# unassign series from project
# TODO: remove series _single_ if no event is assigned to
sub unassign_series{
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};
my $project_id=$entry->{project_id};
my $studio_id= $entry->{studio_id};
my $series_id= $entry->{series_id};
my $sql='delete from calcms_project_series where project_id=? and studio_id=? and series_id=?';
my $bind_values=[$project_id, $studio_id, $series_id];
my $dbh=db::connect($config);
return db::put($dbh, $sql, $bind_values);
}
sub get_with_dates{
my $config=shift;
my $options=shift;
my $language = $config->{date}->{language} || 'en';
my $projects=project::get($config, {});
foreach my $project (reverse sort { $a->{end_date} cmp $b->{end_date} } (@$projects) ){
$project->{months} = get_months($config, $project, $language);
$project->{user} = $ENV{REMOTE_USER};
$project->{current} = 1 if ($project->{name} eq $config::config->{project});
}
return $projects;
}
#TODO: add config
sub get_sorted{
my $config=shift;
my $projects=project::get($config, {});
my @projects=reverse sort { $a->{end_date} cmp $b->{end_date} } (@$projects);
unshift @projects,{
name => 'all',
title => 'alle',
priority => '0',
start_date => $projects[-1]->{start_date},
end_date => $projects[0]->{end_date},
};
return \@projects;
}
# internal
sub get_months{
my $config=shift;
my $project = shift;
my $language = shift || $config->{date}->{language} || 'en';
my $start = $project->{start_date};
my $end = $project->{end_date};
(my $start_year,my $start_month,my $start_day)=split(/\-/,$start);
my $last_day = Date::Calc::Days_in_Month($start_year,$start_month);
$start_day = 1 if ($start_day<1);
$start_day = $last_day if ($start_day gt $last_day);
(my $end_year,my $end_month,my $end_day)=split(/\-/,$end);
$last_day = Date::Calc::Days_in_Month($end_year,$end_month);
$end_day = 1 if ($end_day<1);
$end_day = $last_day if ($end_day gt $last_day);
my @months=();
for my $year($start_year..$end_year){
my $m1=1;
my $m2=12;
$m1=$start_month if $year eq $start_year;
$m2=$end_month if $year eq $end_year;
for my $month($m1..$m2){
my $d1=1;
my $d2=Date::Calc::Days_in_Month($year,$month);
$d1=$start_day if $month eq $start_month;
$d2=$end_day if $month eq $end_month;
push @months,{
start => time::array_to_date($year,$month,$d1),
end => time::array_to_date($year,$month,$d2),
year => $year,
month => $month,
month_name => $time::names->{$language}->{months_abbr}->[$month-1],
title => $project->{title},
user => $ENV{REMOTE_USER}
};
}
}
@months=reverse @months;
return \@months;
}
# check project_id
sub check{
my $config=shift;
my $options=shift;
return "missing project_id at checking project" unless defined $options->{project_id};
return "Please select a project" if($options->{project_id}eq'-1');
return "Please select a project" if($options->{project_id}eq'');
my $projects=project::get($config, { project_id=>$options->{project_id} } );
return "Sorry. unknown project" unless defined $projects;
return 1;
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

8
lib/calcms/projects.pm Normal file
View File

@@ -0,0 +1,8 @@
use warnings "all";
use strict;
package projects;
print STDERR "projects.pm is not used anymore!\n";
#do not delete last line!
1;

146
lib/calcms/roles.pm Normal file
View File

@@ -0,0 +1,146 @@
package roles;
use Apache2::Reload;
require Exporter;
my @ISA = qw(Exporter);
my @EXPORT_OK = qw($roles get_user get_user_permissions get_template_parameters);
my %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
our $roles={
'admin' => {
access_events => 1,
access_images => 1,
access_comments => 1,
access_sync => 1,
access_system => 1,
read_event_all => 1,
create_event => 1,
delete_event => 1,
update_comment => 1,
create_image => 1,
read_image_own => 1,
read_image_all => 1,
update_image_own => 1,
update_image_all => 1,
delete_image_own => 1,
delete_image_all => 1,
sync_own => 1,
sync_all => 1,
sync_select_range => 1,
upload_playlist => 1,
},
'dev' => {
access_events => 1,
access_images => 1,
access_comments => 1,
access_sync => 1,
access_system => 0,
read_event_all => 1,
create_event => 1,
delete_event => 1,
update_comment => 1,
create_image => 1,
read_image_own => 1,
read_image_all => 1,
update_image_own => 1,
update_image_all => 1,
delete_image_own => 1,
delete_image_all => 1,
sync_own => 0,
sync_all => 1,
sync_select_range => 1,
upload_playlist => 1,
},
'editor' => {
access_events => 1,
access_images => 1,
access_comments => 1,
access_sync => 1,
access_system => 0,
read_event_all => 0,
create_event => 1,
delete_event => 0,
update_comment => 0,
create_image => 1,
read_image_own => 1,
read_image_all => 1,
update_image_own => 1,
update_image_all => 0,
delete_image_own => 1,
delete_image_all => 0,
sync_own => 1,
sync_all => 0,
sync_select_range => 0,
upload_playlist => 1,
},
'nobody' => {
access_events => 0,
access_images => 0,
access_comments => 0,
access_sync => 0,
access_system => 0,
read_event_all => 0,
create_event => 0,
delete_event => 0,
update_comment => 0,
create_image => 0,
read_image_own => 0,
read_image_all => 0,
update_image_own => 0,
update_image_all => 0,
delete_image_own => 0,
delete_image_all => 0,
sync_own => 0,
sync_all => 0,
sync_select_range => 0,
upload_playlist => 0,
}
};
sub get_user{
my $user= $ENV{REMOTE_USER};
my $users=$config::config->{users};
return $user if (defined $users->{$user});
return 'nobody';
}
sub get_user_permissions{
my $user= $ENV{REMOTE_USER}||'';
return $roles::roles->{nobody} unless ($user=~/\S/);
my $users=$config::config->{users};
if (defined $users->{$user}){
my $role=$users->{$user};
if (defined $roles::roles->{$role}){
return $roles::roles->{$role};
}
}
return $roles::roles->{nobody};
}
sub get_user_jobs{
my $user= $ENV{REMOTE_USER}||'';
return [] unless($user =~/\S/);
my $result=[];
my $jobs=$config::config->{jobs}->{job};
for my $job (@$jobs){
for my $job_user (split /\,/,$job->{users}){
push @$result,$job if ($user eq $job_user);
}
}
return $result;
}
sub get_jobs{
return $config::config->{jobs}->{job};
}
sub get_template_parameters{
my $user_permissions=shift;
$user_permissions=roles::get_user_permissions() unless(defined $user_permissions);
my @user_permissions=();
for my $usecase (keys %$user_permissions){
push @user_permissions, $usecase if ($user_permissions->{$usecase}eq'1');
}
return \@user_permissions;
}

1208
lib/calcms/series.pm Normal file

File diff suppressed because it is too large Load Diff

555
lib/calcms/series_dates.pm Normal file
View File

@@ -0,0 +1,555 @@
package series_dates;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use time;
use db;
use log;
use studio_timeslot_dates;
use series_schedule;
# schedule dates for series_schedule
# table: calcms_series_dates
# columns: id, studio_id, series_id, start(datetime), end(datetime)
# TODO: delete column schedule_id
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete get_dates get_series);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_series_dates');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get all series_dates for studio_id and series_id within given time range
# calculate start_date, end_date, weeday, day from start and end(datetime)
sub get{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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->{start_at}) && ($condition->{start_at} ne '')){
push @conditions, 'start=?';
push @bind_values, $condition->{start_at};
}
if ((defined $condition->{from}) && ($condition->{from} ne '')){
push @conditions, 'start_date>=?';
push @bind_values, $condition->{from};
}
if ((defined $condition->{till}) && ($condition->{till} ne '')){
push @conditions, 'end_date<?';
push @bind_values, $condition->{till};
}
if ((defined $condition->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'id=?';
push @bind_values, $condition->{schedule_id};
}
if ((defined $condition->{exclude}) && ($condition->{exclude} ne '')){
push @conditions, 'exclude=?';
push @bind_values, $condition->{exclude};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select date(start) start_date
,date(end) end_date
,dayname(start) weekday
,start_date day
,start
,end
,id schedule_id
,series_id
,studio_id
,project_id
,exclude
from calcms_series_dates
$conditions
order by start
};
#print STDERR $query."\n";
#print STDERR Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{weekday}=substr($entry->{weekday},0,2);
}
return $entries;
}
#check if event is scheduled (on permission check)
sub is_event_scheduled{
my $request=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 0 unless defined $options->{start_at};
my $config = $request->{config};
my $schedules=series_dates::get(
$config, {
project_id => $options->{project_id},
studio_id => $options->{studio_id},
series_id => $options->{series_id},
start_at => $options->{start_at}
}
);
return 0 if(@$schedules!=1);
return 1;
}
#get all series for given studio_id, time range and search
sub get_series{
my $config=shift;
my $condition=shift;
my $date_range_include=0;
$date_range_include=1 if $condition->{date_range_include}==1;
my $dbh=db::connect($config);
my @conditions=();
my @bind_values=();
push @conditions, 'd.series_id=s.id';
# push @conditions, 'd.studio_id=s.studio_id';
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'd.project_id=?';
push @bind_values, $condition->{project_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'd.studio_id=?';
push @bind_values, $condition->{studio_id};
}
if ((defined $condition->{series_id}) && ($condition->{series_id} ne '')){
push @conditions, 'd.series_id=?';
push @bind_values, $condition->{series_id};
}
if ((defined $condition->{start_at}) && ($condition->{start_at} ne '')){
push @conditions, 'd.start=?';
push @bind_values, $condition->{start_at};
}
if ((defined $condition->{from}) && ($condition->{from} ne '')){
if ($date_range_include==1){
push @conditions, 'd.end_date>=?';
push @bind_values, $condition->{from};
}else{
push @conditions, 'd.start_date>=?';
push @bind_values, $condition->{from};
}
}
if ((defined $condition->{till}) && ($condition->{till} ne '')){
if ($date_range_include==1){
push @conditions, 'd.start_date<=?';
push @bind_values, $condition->{till};
}else{
push @conditions, 'd.end_date<?';
push @bind_values, $condition->{till};
}
}
if ((defined $condition->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'd.id=?';
push @bind_values, $condition->{schedule_id};
}
if ((defined $condition->{exclude}) && ($condition->{exclude} ne '')){
push @conditions, 'd.exclude=?';
push @bind_values, $condition->{exclude};
}
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=('s.title', 's.series_name', 's.excerpt', 's.category', 's.content');
push @conditions, "(".join(" or ", map {'lower('.$_.') like ?'} @attr ).")";
for my $attr (@attr){
push @bind_values,$search;
}
}
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select date(d.start) start_date
,date(d.end) end_date
,dayname(d.start) weekday
,d.start_date day
,d.start
,d.end
,d.id schedule_id
,d.series_id
,d.series_schedule_id
,d.exclude
,d.studio_id
,d.project_id
,s.series_name
,s.title
,s.has_single_events
from calcms_series_dates d, calcms_series s
$conditions
order by start
};
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{weekday} = substr($entry->{weekday},0,2);
}
# add series schedule
$entries=series_dates::addSeriesScheduleAttributes($config, $entries);
return $entries;
}
sub addSeriesScheduleAttributes{
my $config=shift;
my $entries=shift;
my $scheduleIds={};
# get series schedule ids used at entries
for my $entry (@$entries){
$scheduleIds->{$entry->{series_schedule_id}}=1;
}
my @scheduleIds=keys %$scheduleIds;
return $entries if scalar(@scheduleIds)==0;
# get schedules with schedule ids
my $schedules=series_schedule::get($config, {
schedule_ids => \@scheduleIds
});
# get schedules by id
my $scheduleById={};
for my $schedule (@$schedules){
$scheduleById->{$schedule->{schedule_id}}=$schedule;
}
for my $entry (@$entries){
$entry->{frequency} = $scheduleById->{$entry->{series_schedule_id}}->{frequency};
$entry->{period_type} = $scheduleById->{$entry->{series_schedule_id}}->{period_type};
}
return $entries;
}
#update series dates for all schedules of a series and studio_id
sub update{
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} ;
my $dbh=db::connect($config);
#delete all dates for series (by studio and series id)
series_dates::delete($config, $entry);
my $day_start=$config->{date}->{day_starting_hour};
#get all schedules for series ordered by exclude, date
my $schedules=series_schedule::get($config, {
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
series_id => $entry->{series_id},
});
#add scheduled series dates and remove exluded dates
my $series_dates={};
#TODO:set schedules exclude to 0 if not 1
#insert all normal dates (not excludes)
for my $schedule (@$schedules){
my $dates=get_schedule_dates($schedule, {exclude => 0});
for my $date (@$dates){
$date->{exclude}=0;
$series_dates->{$date->{start}}=$date;
#print STDERR Dumper($date)."\n" if ($date->{start} eq'2014-02-05 19:00:00');
}
}
#insert / overwrite all exlude dates
for my $schedule (@$schedules){
my $dates=get_schedule_dates($schedule, {exclude => 1});
for my $date (@$dates){
$date->{exclude}=1;
$series_dates->{$date->{start}}=$date;
#print STDERR Dumper($date)."\n" if ($date->{start} eq'2014-02-05 19:00:00');
}
}
#print STDERR Dumper($series_dates->{'2014-02-05 19:00:00'});
my $request={
config => $config
};
my $i=0;
my $j=0;
for my $date (keys %$series_dates){
my $series_date=$series_dates->{$date};
#insert date
my $entry={
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
series_id => $entry->{series_id},
series_schedule_id => $series_date->{series_schedule_id},
start => $series_date->{start},
end => $series_date->{end},
exclude => $series_date->{exclude},
};
if(studio_timeslot_dates::can_studio_edit_events($config, $entry)==1){ # by studio_id, start, end
$entry->{start_date}= time::add_hours_to_datetime($entry->{start}, -$day_start);
$entry->{end_date}= time::add_hours_to_datetime($entry->{end}, -$day_start);
db::insert($dbh, 'calcms_series_dates', $entry);
#print STDERR "$entry->{start_date}\n";
$i++;
}else{
$j++;
#print STDERR Dumper($entry);
}
}
#print STDERR "$i series_dates updates\n";
return $j." dates out of studio times, ".$i;
}
sub get_schedule_dates{
my $schedule=shift;
my $options=shift;
my $is_exclude=$options->{exclude}||0;
my $dates=[];
return $dates if (($is_exclude eq'1') && ($schedule->{exclude}ne'1'));
return $dates if (($is_exclude eq'0') && ($schedule->{exclude}eq'1'));
if ($schedule->{period_type}eq'single'){
$dates=get_single_date($schedule->{start}, $schedule->{duration}) ;
}elsif($schedule->{period_type}eq'days'){
$dates=get_dates($schedule->{start}, $schedule->{end}, $schedule->{duration}, $schedule->{frequency}) ;
}elsif($schedule->{period_type}eq'week_of_month'){
$dates=get_week_of_month_dates($schedule->{start}, $schedule->{end}, $schedule->{duration}, $schedule->{week_of_month}, $schedule->{weekday}, $schedule->{month}, $schedule->{nextDay});
}else{
print STDERR "unknown schedule period_type\n";
}
# set series schedule id
for my $date (@$dates){
$date->{series_schedule_id}=$schedule->{schedule_id};
}
return $dates;
}
sub get_week_of_month_dates{
my $start =shift; # datetime string
my $end =shift; # datetime string
my $duration =shift; # in minutes
my $week =shift; # every nth week of month
my $weekday =shift; # weekday [1..7]
my $frequency =shift; # every 1st,2nd,3th time
my $nextDay =shift; # add 24 hours to start, (for night hours at last weekday of month)
return undef if $start eq'';
return undef if $end eq'';
return undef if $duration eq'';
return undef if $week eq'';
return undef if $weekday eq'';
return undef if $frequency eq'';
return undef if $frequency==0;
my $start_dates=time::get_nth_weekday_in_month($start, $end, $week, $weekday-1);
if ((defined $nextDay) && ($nextDay>0)){
for (my $i=0;$i<@$start_dates;$i++){
$start_dates->[$i]=time::add_hours_to_datetime($start_dates->[$i],24);
}
}
my $results=[];
my $c=-1;
for my $start_datetime (@$start_dates){
$c++;
my @start = @{time::datetime_to_array($start_datetime)};
next unless @start>=6;
next if (($c % $frequency)!=0);
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$start[0], $start[1], $start[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
my $end_datetime=time::array_to_datetime(\@end_datetime);
push @$results, {
start => $start_datetime,
end => $end_datetime
};
}
return $results;
}
#add duration to a single date
sub get_single_date{
my $start_datetime = shift;
my $duration = shift;
my @start = @{time::datetime_to_array($start_datetime)};
return unless @start>=6;
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$start[0], $start[1], $start[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
my $date={
start => $start_datetime,
end => time::array_to_datetime(\@end_datetime)
};
return [$date];
}
#calculate all dates between start_datetime and end_date with duration(minutes) and frequency(days)
sub get_dates{
my $start_datetime = shift;
my $end_date = shift;
my $duration = shift; # in minutes
my $frequency = shift; # in days
#print "start_datetime:$start_datetime end_date:$end_date duration:$duration frequency:$frequency\n";
my @start = @{time::datetime_to_array($start_datetime)};
return unless @start>=6;
my @start_date = ($start[0], $start[1], $start[2]);
my $start_time = sprintf('%02d:%02d:%02d', $start[3], $start[4], $start[5]);
#print STDERR "$start_datetime,$end_date,$duration,$frequency\n";
#return on single date
my $date={};
$date->{start}= sprintf("%04d-%02d-%02d",@start_date).' '.$start_time;
return undef if $duration eq '';
return undef if (($frequency eq '')||($end_date eq''));
#continue on recurring date
my @end = @{time::datetime_to_array($end_date)};
return unless @end>=3;
my @end_date = ($end[0], $end[1], $end[2]);
my $today=time::time_to_date();
my ($year, $month, $day)=split(/\-/,$today);
my $dates=[];
return $dates if ($end_date lt $today);
return $dates if ($frequency<1);
my $j = Date::Calc::Delta_Days(@start_date, @end_date);
my $c=0;
for (my $i = 0; $i <= $j; $i+=$frequency ){
my @date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], $i);
my $date={};
$date->{start}=sprintf("%04d-%02d-%02d",@date).' '.$start_time;
#if($date->{start} gt $today){
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$date[0], $date[1], $date[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
$date->{end}=time::array_to_datetime(\@end_datetime);
push @$dates,$date;
#}
last if ($c>200);
$c++;
}
return $dates;
}
#remove all series_dates for studio_id and series_id
sub delete{
my $config=shift;
my $entry=shift;
return unless defined $entry->{project_id};
return unless defined $entry->{studio_id};
return unless defined $entry->{series_id};
my $dbh=db::connect($config);
my $query=qq{
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}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

467
lib/calcms/series_events.pm Normal file
View File

@@ -0,0 +1,467 @@
package series_events;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use markup;
use db;
use log;
use time;
use uac;
use events;
use series;
use series_dates;
use studios;
use studio_timeslot_dates;
use event_history;
# check permissions, insert and update events related to series
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
check_permission
save_content
save_event_time
insert_event
delete_event
set_playout_status
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
# update main fields of the event by id
# do not check for project,studio,series
# all changed columns are returned for history handling
sub save_content{
my $config=shift;
my $entry=shift;
my $dbh=db::connect($config);
return undef unless(defined $entry->{id});
for my $attr (keys %$entry){
$entry->{$attr}=~s/^\s+//g;
$entry->{$attr}=~s/\s+$//g;
}
#print STDERR Dumper(\$entry->{content});
for my $attr ('content', 'topic'){
if (defined $entry->{$attr}){
$entry->{'html_'.$attr}=markup::creole_to_html($entry->{$attr});
#$entry->{'html_'.$attr}=~s/([^\>])\n+([^\<])/$1<br\/><br\/>$2/g;
#$entry->{'html_'.$attr}=~s/^\s*(<p>)?//g;
#$entry->{'html_'.$attr}=~s/(<\/p>)?\s*$//g;
}
}
#print STDERR Dumper(\$entry->{html_content});
#print STDERR "ok2\n";
#return;
$entry->{modified_at}= time::time_to_datetime(time());
#return;
#update only existing atributes
#TODO: double check series_name (needed for reassignment but not for editing...)
my @keys=();
for my $key ('series_name', 'title', 'excerpt', 'content', 'html_content',
'user_title', 'user_excerpt', 'topic', 'html_topic',
'episode', 'image', 'podcast_url', 'archive_url',
'live', 'published', 'playout', 'archived', 'rerun', 'disable_event_sync',
'modified_by'
){
push @keys, $key if defined $entry->{$key};
}
$entry->{episode}=undef if((defined $entry->{episode}) && ($entry->{episode}eq'0'));
my $values =join(",", map {$_.'=?'} (@keys));
my @bind_values =map {$entry->{$_}} (@keys);
push @bind_values,$entry->{id};
my $query=qq{
update calcms_events
set $values
where id=?
};
#print STDERR $query.Dumper(\@bind_values);
db::put($dbh, $query, \@bind_values);
return $entry;
}
# save event time by id
# do not check project, studio, series
# for history handling all changed columns are returned
sub save_event_time{
my $config=shift;
my $entry=shift;
return undef unless(defined $entry->{id});
return undef unless(defined $entry->{duration});
return undef unless(defined $entry->{start_date});
my $dbh=db::connect($config);
my $event={
id => $entry->{id},
start => $entry->{start_date},
end => time::add_minutes_to_datetime($entry->{start_date}, $entry->{duration})
};
my $day_start=$config->{date}->{day_starting_hour};
my $event_hour=int((split(/[\-\:\sT]/,$event->{start}))[3]);
my @update_columns=();
my $bind_values=[];
push @update_columns,'start=?';
push @$bind_values,$event->{start};
push @update_columns, 'end=?';
push @$bind_values, $event->{end};
# add start date
my $start_date= time::add_hours_to_datetime($event->{start}, -$day_start);
push @update_columns, 'start_date=?';
push @$bind_values, $start_date;
$event->{start_date} =$start_date;
# add end date
my $end_date= time::add_hours_to_datetime($event->{end}, -$day_start);
push @update_columns, 'end_date=?';
push @$bind_values, $end_date;
$event->{end_date} = $end_date;
my $update_columns=join(",\n", @update_columns);
my $update_sql=qq{
update calcms_events
set $update_columns
where id=?
};
push @$bind_values, $event->{id};
#print STDERR $update_sql."\n".Dumper($bind_values)."\n";
db::put($dbh, $update_sql, $bind_values);
return $event;
}
sub set_playout_status{
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->{start};
return undef unless defined $entry->{playout};
my $dbh=db::connect($config);
# check if event is assigned to project and studio
my $sql=qq{
select se.event_id event_id
from calcms_series_events se, calcms_events e
where
se.event_id=e.id
and e.start=?
and se.project_id=?
and se.studio_id=?
};
my $bind_values=[$entry->{start}, $entry->{project_id}, $entry->{studio_id}];
#print STDERR Dumper($sql).Dumper($bind_values);
my $events=db::get($dbh, $sql, $bind_values);
#print STDERR Dumper($events);
return undef if scalar(@$events)!=1;
my $event_id=$events->[0]->{event_id};
$sql=qq{
update calcms_events
set playout=?
where id=?
and start=?
};
$bind_values=[$entry->{playout}, $event_id, $entry->{start}];
#print STDERR $sql."\n".Dumper($bind_values)."\n";
my $result=db::put($dbh, $sql, $bind_values);
return $result;
}
# is event assigned to project, studio and series?
sub is_event_assigned{
my $config=shift;
my $entry=shift;
return 0 unless defined $entry->{project_id};
return 0 unless defined $entry->{studio_id};
return 0 unless defined $entry->{series_id};
return 0 unless defined $entry->{event_id};
my $dbh=db::connect($config);
my $sql=q{
select * from calcms_series_events
where project_id=? and studio_id=? and series_id=? and event_id=?
};
my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{event_id}];
my $results=db::get($dbh, $sql, $bind_values);
return 1 if @$results>=1;
return 0;
}
sub delete_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};
return undef unless defined $entry->{user};
#is event assigned to project, studio and series?
unless(is_event_assigned($config, $entry)==1){
print STDERR "cannot delete event with project_id=$entry->{project_id}, studio_id=$entry->{studio_id}, series_id=$entry->{series_id}, event_id=$entry->{event_id}";
return 0;
}
event_history::insert_by_event_id($config, $entry);
#delete the association
series::unassign_event($config, $entry);
# delete the event
my $dbh=db::connect($config);
my $sql=q{
delete from calcms_events
where id=?
};
my $bind_values=[$entry->{event_id}];
db::put($dbh, $sql, $bind_values);
return 1;
}
#check permissions
# options: conditions (studio_id, series_id,...)
# key permission: permissions to be checked (one of)
# key check_for: user, studio, series, events, schedule
# return error text or 1 if okay
sub check_permission{
my $request=shift;
my $options=shift;
return "missing permission at check" unless defined $options->{permission};
return "missing check_for at check" unless defined $options->{check_for};
return "missing user at check" unless defined $request->{user};
return "missing project_id at check" unless defined $options->{project_id};
return "missing studio_id at check" unless defined $options->{studio_id};
return "missing series_id at check" unless defined $options->{series_id};
my $permissions = $request->{permissions};
my $config = $request->{config};
my $studio_check=studios::check($config, $options);
return $studio_check if($studio_check ne '1');
print STDERR "check studio ok\n";
my $project_check=project::check($config, $options);
return $project_check if($project_check ne '1');
print STDERR "check project ok\n";
#check if permissions are set (like create_event)
my $found=0;
for my $permission (split /\,/,$options->{permission}){
$found=1 if ((defined $permissions->{$permission})&&($permissions->{$permission})eq'1');
}
return 'missing permission to '.$options->{permission} if $found==0;
delete $options->{permission};
#convert check list to hash
my $check={};
for my $permission (@{$options->{check_for}}){
$check->{$permission}=1;
}
delete $options->{check_for};
# is project assigned to studio
return "studio is not assigned to project" unless project::is_studio_assigned($config, $options)==1;
#get studio names
my $studios=studios::get($config, {
project_id => $options->{project_id},
studio_id => $options->{studio_id}
});
return "unknown studio" unless defined $studios;
return "unknown studio" unless (@$studios==1);
my $studio=$studios->[0];
my $studio_name=$studio->{name}||'';
#get series names
my $series=series::get($config, {
project_id => $options->{project_id},
studio_id => $options->{studio_id},
series_id => $options->{series_id}
});
my $series_name=$series->[0]->{series_name}||'';
$series_name.=' - '.$series->[0]->{title} if $series->[0]->{series_name} ne '';
#check all items from checklist
if((defined $check->{user})&&(uac::is_user_assigned_to_studio($request, $options)==0)){
return "User '$request->{user}' is not assigned to studio $studio_name ($options->{studio_id})";
}
if((defined $check->{studio})&&(project::is_series_assigned($config, $options)==0)){
return "Series '$series_name' ($options->{series_id}) is not assigned to studio '$studio_name' ($options->{studio_id})";
}
# check series and can user update events
if((defined $check->{series})&&(series::can_user_update_events($request, $options)==0)){
return "unknown series" unless defined $series;
return "User $request->{user} cannot update events for series '$series_name' ($options->{series_id})";
}
# check series and can user create events
if((defined $check->{create_events})&&(series::can_user_create_events($request, $options)==0)){
return "unknown series" unless defined $series;
return "User $request->{user} cannot create events for series '$series_name' ($options->{series_id})";
}
if((defined $check->{studio_timeslots})&&(studio_timeslot_dates::can_studio_edit_events($config, $options)==0)){
return "requested time is not assigned to studio '$studio_name' ($options->{studio_id})";
}
#check if event is assigned to user,project,studio,series,location
if(defined $check->{events}){
return "missing event_id" unless defined $options->{event_id};
my $result=series::is_event_assigned_to_user($request, $options);
return $result if $result ne '1';
}
# prevent editing events that are over for more than 14 days
if(defined $check->{event_age}){
if (series::is_event_older_than_days($config, {
project_id => $options->{project_id},
studio_id => $options->{studio_id},
series_id => $options->{series_id},
event_id => $options->{event_id},
max_age => 14
})==1){
return "show is over for more than 2 weeks" unless(
(defined $permissions->{update_event_after_week})
&& ($permissions->{update_event_after_week} eq '1')
);
}
}
#check if schedule event exists for given date
if(defined $check->{schedule}){
return "unknown series" unless defined $series;
return "missing start_at at check_permission" unless defined $options->{start_date};
#TODO: check "is_event_scheduled" if start_at could be moved to start_date
$options->{start_at}=$options->{start_date};
return "No event scheduled for series '$series_name' ($options->{series_id})" if(series_dates::is_event_scheduled($request, $options)==0);
}
return '1';
}
#not handled, yet:
# responsible, status, rating, podcast_url, media_url, visible, time_of_day, recurrence, reference, created_at
# category, time_of_day,
#insert event
sub insert_event{
my $config=shift;
my $options=shift;
my $project_id = $options->{project_id};
my $studio = $options->{studio};
my $serie = $options->{serie};
my $params = $options->{event};
my $user = $options->{user};
return 0 unless defined $studio;
return 0 unless defined $serie;
return 0 unless defined $params;
return 0 unless defined $user;
return 0 unless defined $studio->{location};
my $projects=project::get($config, {project_id=>$project_id});
if(@$projects==0){
print STDERR "project not found at insert event\n";
return 0;
}
my $projectName=$projects->[0]->{name};
my $event={
project => $projectName,
location => $studio->{location}, # location from studio
};
#print '<pre>';
$event=series_events::add_event_dates($config, $event, $params);
#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};
}
#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->{'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'};
#add event status
for my $attr ('live', 'published', 'playout', 'archived', 'rerun', 'disable_event_sync'){
$event->{$attr}=$params->{$attr}||0;
}
if($serie->{has_single_events}eq'1'){
delete $event->{series_name};
delete $event->{episode};
}
$event->{modified_at} = time::time_to_datetime(time());
$event->{created_at} = time::time_to_datetime(time());
$event->{modified_by} = $user;
#print STDERR Dumper($event);
my $dbh=db::connect($config);
my $event_id= db::insert($dbh, 'calcms_events', $event);
#add to history
$event->{project_id}= $project_id;
$event->{studio_id} = $studio->{id};
$event->{series_id} = $serie->{series_id};
$event->{event_id} = $event_id;
event_history::insert($config, $event);
return $event_id;
}
#set start, end, start-date, end_date to an event
sub add_event_dates{
my $config =shift;
my $event =shift;
my $params =shift;
#start and end datetime
$event->{start} = $params->{start_date};
$event->{end} = time::add_minutes_to_datetime($params->{start_date}, $params->{duration});
#set program days
my $day_start=$config->{date}->{day_starting_hour};
$event->{start_date} = time::date_cond(time::add_hours_to_datetime($event->{start}, -$day_start));
$event->{end_date} = time::date_cond(time::add_hours_to_datetime($event->{end}, -$day_start));
return $event;
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

View File

@@ -0,0 +1,183 @@
package series_schedule;
use warnings "all";
use strict;
use Data::Dumper;
use series_dates;
# table: calcms_series_schedule
# columns: id, studio_id, series_id,
# start (datetime),
# duration (minutes),
# frequency (days),
# end (date),
# weekday (1..7)
# week_of_month (1..5)
# month
# nextDay (add 24 hours to start)
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_series_schedule');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
#map schedule id to id
sub get{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'id=?';
push @bind_values, $condition->{schedule_id};
}
if ((defined $condition->{schedule_ids}) && (ref($condition->{schedule_ids}) eq 'ARRAY')){
my @scheduleIds = @{$condition->{schedule_ids}};
push @conditions, 'id in ('.(join(',', (map {'?'} @scheduleIds) )).')';
for my $id (@scheduleIds){
push @bind_values, $id;
}
}
if ((defined $condition->{start}) && ($condition->{start} ne '')){
push @conditions, 'start=?';
push @bind_values, $condition->{start};
}
if ((defined $condition->{exclude}) && ($condition->{exclude} ne '')){
push @conditions, 'exclude=?';
push @bind_values, $condition->{exclude};
}
if ((defined $condition->{period_type}) && ($condition->{period_type} ne '')){
push @conditions, 'period_type=?';
push @bind_values, $condition->{period_type};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_series_schedule
$conditions
order by exclude, start
};
#print STDERR $query."\n".Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{schedule_id}=$entry->{id};
delete $entry->{id};
}
#print STDERR Dumper($entries);
return $entries;
}
sub insert{
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->{start};
my $dbh=db::connect($config);
return db::insert($dbh, 'calcms_series_schedule', $entry);
}
#schedule id to id
sub update{
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->{schedule_id};
return undef unless defined $entry->{start};
$entry->{nextDay}=0 unless defined $entry->{nextDay};
$entry->{id}=$entry->{schedule_id};
delete $entry->{schedule_id};
my $dbh=db::connect($config);
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{project_id};
push @bind_values,$entry->{studio_id};
push @bind_values,$entry->{id};
my $query=qq{
update calcms_series_schedule
set $values
where project_id=? and studio_id=? and id=?
};
#print STDERR Dumper($query).Dumper(\@bind_values);
db::put($dbh, $query, \@bind_values);
print "done\n";
}
#map schedule id to id
sub delete{
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->{schedule_id};
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_series_schedule
where project_id=? and studio_id=? and series_id=? and id=?
};
my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{series_id}, $entry->{schedule_id}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

32
lib/calcms/startup.pl Normal file
View File

@@ -0,0 +1,32 @@
use lib qw(/home/calcms/lib/calcms/);
return 1;
#use B::TerseSize
#load mod_perl modules
#use Apache2;
#use ModPerl::RegistryPrefork;
#use Apache::compat;
#on upload CGI open of tmpfile: Permission denied
#use CGI;
#load common used modules
#use Data::Dumper;
#use DBI;
use Apache::DBI;
#$Apache::DBI::DEBUG = 2;
use Time::Local;
use Date::Calc;
use Calendar::Simple qw(date_span);
use config;
use log;
use time;
use db;
use cache;
use template;
#do not delete last line!
1;

View File

@@ -0,0 +1,434 @@
package studio_timeslot_dates;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use time;
# schedule dates for calcms_studio_schedule
# table: calcms_studio_timeslot_dates
# columns: id, studio_id, start(datetime), end(datetime)
# TODO: delete column schedule_id
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete get_dates);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_studio_timeslot_dates');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get all studio_timeslot_dates for studio_id within given time range
# calculate start_date, end_date, weeday, day from start and end(datetime)
sub get{
my $config=shift;
my $condition=shift;
my $date_range_include=0;
$date_range_include=1 if $condition->{date_range_include}==1;
my $dbh=db::connect($config);
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->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'schedule_id=?';
push @bind_values, $condition->{schedule_id};
}
# from and till range from an event should beween start and end of the studio's permission
if ((defined $condition->{start}) && ($condition->{start} ne '')){
push @conditions, 'start<=?';
push @bind_values, $condition->{start};
}
if ((defined $condition->{end}) && ($condition->{end} ne '')){
push @conditions, 'end>=?';
push @bind_values, $condition->{end};
}
# check only a given date date range (without time)
if ((defined $condition->{from}) && ($condition->{from} ne '')){
if ($date_range_include==1){
push @conditions, 'end_date>=?';
push @bind_values, $condition->{from};
}else{
push @conditions, 'start_date>=?';
push @bind_values, $condition->{from};
}
}
if ((defined $condition->{till}) && ($condition->{till} ne '')){
if ($date_range_include==1){
push @conditions, 'start_date<=?';
push @bind_values, $condition->{till};
}else{
push @conditions, 'end_date<=?';
push @bind_values, $condition->{till};
}
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select date(start) start_date
,date(end) end_date
,dayname(start) start_weekday
,dayname(end) end_weekday
,start_date day
,start
,end
,schedule_id
,studio_id
from calcms_studio_timeslot_dates
$conditions
order by start
};
#print STDERR $query."\n";
#print STDERR Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{start_weekday}=substr($entry->{start_weekday},0,2);
$entry->{end_weekday}=substr($entry->{end_weekday},0,2);
}
#print STDERR Dumper($entries);
return $entries;
}
#get all studio_timeslot_schedules for studio_id and update studio_timeslot_dates
sub update{
my $config=shift;
my $entry=shift;
return undef unless(defined $entry->{schedule_id});
my $dbh=db::connect($config);
#delete all dates for schedule id
studio_timeslot_dates::delete($config, $entry);
my $day_start=$config->{date}->{day_starting_hour};
#get the schedule with schedule id ordered by date
my $schedules=studio_timeslot_schedule::get($config, {
schedule_id => $entry->{schedule_id}
});
#add scheduled dates
my $i=0;
my $dates={};
for my $schedule (@$schedules){
#calculate dates from start to end_date
my $dateList=get_dates($schedule->{start}, $schedule->{end}, $schedule->{end_date}, $schedule->{frequency});
#print STDERR Dumper($dateList);
for my $date (@$dateList){
#set studio i from
$date->{project_id} = $schedule->{project_id};
$date->{studio_id} = $schedule->{studio_id};
$date->{schedule_id} = $schedule->{schedule_id};
$dates->{$date->{start}.$date->{studio_id}}=$date;
}
}
for my $date (keys %$dates){
my $timeslot_date=$dates->{$date};
#insert date
my $entry={
project_id => $timeslot_date->{project_id},
studio_id => $timeslot_date->{studio_id},
schedule_id => $timeslot_date->{schedule_id},
start => $timeslot_date->{start},
end => $timeslot_date->{end},
};
$entry->{start_date}= time::add_hours_to_datetime($entry->{start}, -$day_start);
$entry->{end_date}= time::add_hours_to_datetime($entry->{end}, -$day_start);
db::insert($dbh, 'calcms_studio_timeslot_dates', $entry);
#print STDERR "$entry->{start_date}\n";
$i++;
}
#print STDERR "$i studio_timeslot_dates updates\n";
return $i;
}
# calculate all start/end datetimes between start_date and stop_date with a frequency(days)
# returns list of hashs with start and end
sub get_dates{
my $start_datetime = shift; # start
my $end_datetime = shift; # start
my $stop_date = shift; # limit recurring events
my $frequency = shift; # in days
my @start = @{time::datetime_to_array($start_datetime)};
return unless @start>=6;
my @start_date = ($start[0], $start[1], $start[2]);
my $start_date = sprintf("%04d-%02d-%02d",@start_date);
my $start_time = sprintf('%02d:%02d:%02d', $start[3], $start[4], $start[5]);
my @end = @{time::datetime_to_array($end_datetime)};
return unless @end>=6;
my @end_date = ($end[0], $end[1], $end[2]);
my $end_date = sprintf("%04d-%02d-%02d",@end_date);
my $end_time = sprintf('%02d:%02d:%02d', $end[3], $end[4], $end[5]);
my @stop = @{time::date_to_array($stop_date)};
return unless @end>=3;
my @stop_date = ($stop[0], $stop[1], $stop[2]);
$stop_date = sprintf("%04d-%02d-%02d",@stop_date);
my $date={};
$date->{start}= $start_date.' '.$start_time;
$date->{end} = $end_date.' '.$end_time;
my $dates=[];
return $dates if ($date->{end} le $date->{start});
return $dates if ($stop_date lt $end_date);
my $j = Date::Calc::Delta_Days(@start_date, @stop_date);
return $dates if $j<0;
# split full time events into single days
if($frequency<1){
#start day
my @next_date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], 1);
my $next_date = sprintf("%04d-%02d-%02d",@next_date);
push @$dates,{
start => $start_date.' '.$start_time,
end => $next_date .' 00:00:00',
};
my $c=0;
for (my $i = 1; $i < $j; $i++){
my @start_date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], $i);
my $start_date = sprintf("%04d-%02d-%02d",@start_date);
my @next_date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], $i+1);
my $next_date = sprintf("%04d-%02d-%02d",@next_date);
push @$dates,{
start => $start_date.' 00:00:00',
end => $next_date.' 00:00:00',
};
last if ($c>1000);
$c++;
}
#end day
push @$dates,{
start => $end_date.' 00:00:00',
end => $end_date.' '.$end_time,
} if($end_time ne '00:00:00');
return $dates;
}
# multiple time events
my $c=0;
for (my $i = 0; $i <= $j; $i+=$frequency ){
#add frequency to start and end date
my @start_date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], $i);
my @end_date = Date::Calc::Add_Delta_Days($end[0], $end[1], $end[2], $i);
#print STDERR Dumper(\@start_date);
#print STDERR Dumper(\@end_date);
my $start_date=sprintf("%04d-%02d-%02d",@start_date);
my $end_date =sprintf("%04d-%02d-%02d",@end_date);
push @$dates,{
start => $start_date.' '.$start_time,
end => $end_date.' '.$end_time,
};
last if ($c>1000);
$c++;
}
return $dates;
}
#remove all studio_timeslot_dates for studio_id and schedule_id
sub delete{
my $config=shift;
my $entry=shift;
#print STDERR "delete:".Dumper($entry);
return unless(defined $entry->{project_id});
return unless(defined $entry->{studio_id});
return unless(defined $entry->{schedule_id});
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_studio_timeslot_dates
where schedule_id=?
};
my $bind_values=[$entry->{schedule_id}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
db::put($dbh, $query, $bind_values);
}
# time based filter to check if studio is assigned to an studio at a given time range
# return 1 if there is a schedule date starting before start and ending after end
sub can_studio_edit_events{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
#print Dumper($condition);
#return 0 unless defined $condition->{project_id};
return 0 unless defined $condition->{studio_id};
return 0 unless defined $condition->{start};
return 0 unless defined $condition->{end};
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->{start}) && ($condition->{start} ne '')){
push @conditions, 'start<=?';
push @bind_values, $condition->{start};
}
if ((defined $condition->{end}) && ($condition->{end} ne '')){
push @conditions, 'end>=?';
push @bind_values, $condition->{end};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $dbh=db::connect($config);
my $query=qq{
select count(*) permission
from calcms_studio_timeslot_dates
$conditions
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
#print STDERR Dumper($entries);
return 0 if scalar(@$entries) == 0;
return 1 if $entries->[0]->{permission}>0;
if ($entries->[0]->{permission}==0){
my $timeslot=getMergedDays($config, $condition);
return 0 unless defined $timeslot;
if (
($condition->{start} ge $timeslot->{start})
&& ($condition->{end} le $timeslot->{end})
){
#print STDERR "($condition->{start} ge $timeslot->{start}) ".($condition->{start} ge $timeslot->{start});
#print STDERR "($condition->{end} le $timeslot->{end}) ".($condition->{end} le $timeslot->{end});
return 1;
}
}
return 0;
}
# merge two subsequent days if first day ends at same time as next day starts
# returns hashref with start and end of merged slot
# returns undef if not slot could be found
sub getMergedDays{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
#print Dumper($condition);
#return 0 unless defined $condition->{project_id};
return 0 unless defined $condition->{studio_id};
return 0 unless defined $condition->{start};
return 0 unless defined $condition->{end};
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};
}
# set start to next day at 00:00
my $start=undef;
if ($condition->{start}=~/(\d\d\d\d\-\d\d\-\d\d)/){
$start=$1.' 00:00';
$start=time::add_days_to_datetime($start, 1);
push @bind_values, $start;
}
# set end to end days at 00:00
my $end=undef;
if ($condition->{end}=~/(\d\d\d\d\-\d\d\-\d\d)/){
$end=$1.' 00:00';
push @bind_values, $end;
}
return undef unless defined $start;
return undef unless defined $end;
push @conditions, '(start=? or end=?)';
my $conditions='';
$conditions='where '.join(" and ",@conditions) if (@conditions>0);
# get all days starting on first day or ending at next day
my $dbh=db::connect($config);
my $query=qq{
select start, end
from calcms_studio_timeslot_dates
$conditions
order by start
};
# print STDERR Dumper($query).Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
# print STDERR Dumper($entries);
if (scalar(@$entries)==2){
if ($entries->[0]->{end} eq $entries->[1]->{start}){
$entries={
start => $entries->[0]->{start},
end => $entries->[1]->{end}
};
# print STDERR "found".Dumper($entries)."\n";
return $entries;
}
}
return undef;
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

View File

@@ -0,0 +1,144 @@
package studio_timeslot_schedule;
use warnings "all";
use strict;
use Data::Dumper;
use studio_timeslot_dates;
# table: calcms_studio_timeslot_schedule
# columns: id, project_id, studio_id, start(datetime), end(datetime), end_date(date),
# frequency(days), duration(minutes), create_events(days), publish_events(days)
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_studio_timeslot_schedule');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
#map schedule id to id
sub get{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'id=?';
push @bind_values, $condition->{schedule_id};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_studio_timeslot_schedule
$conditions
order by start
};
#print $query."\n";
#print Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{schedule_id}=$entry->{id};
delete $entry->{id};
}
return $entries;
}
sub insert{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{project_id});
return unless(defined $entry->{studio_id});
return unless(defined $entry->{start});
return unless(defined $entry->{end});
return unless(defined $entry->{frequency});
my $dbh=db::connect($config);
return db::insert($dbh, 'calcms_studio_timeslot_schedule', $entry);
}
#schedule id to id
sub update{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{project_id});
return unless(defined $entry->{studio_id});
return unless(defined $entry->{schedule_id});
return unless(defined $entry->{start});
return unless(defined $entry->{end});
return unless(defined $entry->{frequency});
$entry->{id}=$entry->{schedule_id};
delete $entry->{schedule_id};
my $dbh=db::connect($config);
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{id};
my $query=qq{
update calcms_studio_timeslot_schedule
set $values
where id=?
};
db::put($dbh, $query, \@bind_values);
#print "done\n";
$entry->{schedule_id}=$entry->{id};
delete $entry->{id};
}
#map schedule id to id
sub delete{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{schedule_id});
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_studio_timeslot_schedule
where id=?
};
my $bind_values=[$entry->{schedule_id}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

158
lib/calcms/studios.pm Normal file
View File

@@ -0,0 +1,158 @@
#!/bin/perl
use CGI;
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use CGI::Session qw(-ip-match);
use CGI::Cookie;
#$CGI::Session::IP_MATCH=1;
package studios;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get get_by_id insert update delete check check_studio);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_studios');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
sub get{
my $config=shift;
my $condition=shift||{};
my @conditions=();
my @bind_values=();
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 's.id=?';
push @bind_values, $condition->{studio_id};
}
if ((defined $condition->{name}) && ($condition->{name} ne '')){
push @conditions, 's.name=?';
push @bind_values, $condition->{name};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $query='';
unless ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
$query=qq{
select *
from calcms_studios s
$conditions
$limit
};
}else{
push @conditions, 's.id=ps.studio_id';
push @conditions, 'ps.project_id=?';
push @bind_values, $condition->{project_id};
my $conditions=" where ".join(" and ",@conditions) if (@conditions>0);
$query=qq{
select *
from calcms_studios s, calcms_project_studios ps
$conditions
$limit
};
}
my $dbh=db::connect($config);
#print STDERR Dumper($query).Dumper(\@bind_values);
my $studios=db::get($dbh, $query,\@bind_values);
return $studios;
}
sub insert{
my $config=shift;
my $entry=shift;
$entry->{created_at} = time::time_to_datetime(time());
$entry->{modified_at}= time::time_to_datetime(time());
my $dbh=db::connect($config);
my $id=db::insert($dbh, 'calcms_studios', $entry);
return $id;
}
sub update{
my $config=shift;
my $studio=shift;
$studio->{modified_at}= time::time_to_datetime(time());
my $columns=get_columns($config);
my $entry={};
for my $column (keys %$columns){
$entry->{$column}=$studio->{$column} if defined $studio->{$column};
}
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{id};
my $query=qq{
update calcms_studios
set $values
where id=?
};
my $dbh=db::connect($config);
db::put($dbh, $query, \@bind_values);
}
sub delete{
my $config=shift;
my $studio=shift;
my $dbh=db::connect($config);
db::put($dbh, 'delete from calcms_studios where id=?', [$studio->{id}]);
}
#TODO rename to check
sub check_studio{
my $config=shift;
my $options=shift;
return check($config, $options);
}
sub check{
my $config=shift;
my $options=shift;
return "missing studio_id" unless defined $options->{studio_id};
return "Please select a studio" if($options->{studio_id}eq'-1');
return "Please select a studio" if($options->{studio_id}eq'');
my $studios=studios::get($config, {studio_id => $options->{studio_id}});
return "Sorry. unknown studio" unless defined $studios;
return "Sorry. unknown studio" unless @$studios==1;
return 1;
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

24
lib/calcms/tags.pm Normal file
View File

@@ -0,0 +1,24 @@
use warnings "all";
use strict;
use Data::Dumper;
package tags;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_tags);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub get_tags{
my $dbh=shift;
my $query=qq{
select name, count(name) sum from calcms_tags
group by name
order by sum desc
};
my $tags=db::get($dbh,$query);
return $tags;
}
#do not delete last line!
1;

227
lib/calcms/template.pm Normal file
View File

@@ -0,0 +1,227 @@
use warnings "all";
use strict;
package template;
use Data::Dumper;
use HTML::Template::Compiled;
use HTML::Template::Compiled::Plugin::XMLEscape;
use JSON;
use Cwd;
use config;
use params;
use project;
use log;
use roles;
require Exporter;
our @ISA = qw(Exporter);
#our @EXPORT = qw(all);
our @EXPORT_OK = qw(check process exit_on_missing_permission clear_cache);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub process{
# my $output=$_[0];
my $filename=$_[1];
my $params=$_[2];
my $config=$config::config;
for my $key (keys %{$config::config->{locations}}){
$params->{$key} =$config::config->{locations}->{$key} if ($key=~/\_url$/);
}
# add current project
unless (defined $params->{project_title}){
my $projects = project::get_with_dates($config, { name => $config->{project} });
if (@$projects==1){
my $project= $projects->[0];
foreach my $key (keys %$project){
$params->{'project_'.$key}=$project->{$key};
}
}
}
$params->{user}=$ENV{REMOTE_USER} unless defined $params->{user};
my $user_permissions=roles::get_user_permissions();
for my $permission (keys %$user_permissions){
$params->{$permission}=$user_permissions->{$permission} if ($user_permissions->{$permission} eq '1');
}
$params->{jobs}=roles::get_user_jobs();
log::write($config, 'template',$params) if ($config::config->{system}->{debug}>0);
# my $html_template = HTML::Template->new(
# filename => $filename,
# die_on_bad_params =>0,
## cache =>1,
## cache_debug => 1
# );
if (($filename =~/json\-p/) || (params::isJson)){
my $header="Content-type:application/json; charset=utf-8\n\n";
my $json=to_json($params, {pretty => 1});
# $json=$header.$params->{json_callback}.'['.$json.']';
$json=$header.$params->{json_callback}.$json;
if((defined $_[0]) && ($_[0]eq'print')){
print $json."\n";
}else{
$_[0]= $json."\n";
}
return;
}
#print STDERR $filename."\n";
log::error($config, "cannot find template $filename ") unless -e $filename;
log::error($config, "cannot read template $filename ") unless -r $filename;
my $default_escape='0';
$default_escape='JS' if ($filename=~/\.js$/);
$default_escape='JS' if ($filename=~/\.json$/);
$default_escape='HTML_ALL' if ($filename=~/\.html$/);
my $html_template=undef;
unless ($filename=~/\.xml$/){
$html_template = HTML::Template::Compiled->new(
filename => $filename,
die_on_bad_params => 0,
case_sensitive => 0,
loop_context_vars => 0,
global_vars => 0,
tagstyle => '-asp -comment',
default_escape => $default_escape,
cache => 0,
utf8 => 1,
);
}else{
$html_template = HTML::Template::Compiled->new(
filename => $filename,
die_on_bad_params => 0,
case_sensitive => 1,
loop_context_vars => 0,
global_vars => 0,
tagstyle => '-asp -comment',
default_escape => 'XML',
plugin => [qw(HTML::Template::Compiled::Plugin::XMLEscape)],
utf8 => 1
);
}
#$params=
setRelativeUrls($params,0) unless (defined $params->{extern}) && ($params->{extern} eq '1');
# HTML::Template::Compiled->preload($cache_dir);
$html_template->param($params);
if((defined $_[0]) && ($_[0]eq'print')){
print $html_template->output;
}else{
$_[0]=$html_template->output;
}
}
# set relative urls in nested params structure
sub setRelativeUrls{
my $params=shift;
my $depth=shift || 0;
#print STDERR "setRelativeUrls depth:$depth ".ref($params)."\n";
return unless defined $params;
if ($depth>10){
print STDERR "prevent deep recursion in template::setRelativeUrls()\n";
return ;
}
# set recursive for hash
if (ref($params) eq 'HASH'){
for my $key (keys %$params){
#next unless ($key eq 'icon') || ($key eq 'thumb');
my $val=$params->{$key};
next unless defined $val;
if (ref($val) eq ''){
# make link relative
$params->{$key} =~s/^https?\:(\/\/[^\/]+)/$1/;
}elsif ( (ref($val) eq 'HASH') || (ref($val) eq 'ARRAY') ){
setRelativeUrls($params->{$key}, $depth+1);
}
}
return $params;
}
# set recursive for arrays
if (ref($params) eq 'ARRAY'){
for my $i (0..@$params){
my $val=$params->[$i];
next unless defined $val;
if ( (ref($val) eq 'HASH') || (ref($val) eq 'ARRAY') ){
setRelativeUrls($params->[$i], $depth+1);
}
}
return $params;
}
return $params;
}
#requires read config
sub check{
my $template=shift||'';
my $default=shift;
if($template =~/json\-p/){
$template=~s/[^a-zA-Z0-9\-\_\.]//g;
$template=~s/\.{2,99}/\./g;
return $template;
}
my $config=$config::config;
if ($template eq''){
$template=$default;
}else{
$template=~s/^\.\///gi;
#template does use ';' in filename
log::error($config, 'invalid template!') if ($template=~/;/);
#template does use '..' in filename
log::error($config, 'invalid template!') if ($template=~/\.\./);
}
#print STDERR $config::config->{cache}->{compress}."<.compres default:$template\n";
$template=(split(/\//,$template))[-1];
my $cwd=getcwd();
$template.='.html' unless ($template=~/\./);
if (($config::config->{cache}->{compress}eq'1') && (-e $cwd.'/templates/compressed/'.$template)){
$template=$cwd.'/templates/compressed/'.$template;
}elsif (-e $cwd.'/templates/'.$template){
$template=$cwd.'/templates/'.$template;
}else{
log::error($config, "template not found: '$cwd/$template'");
}
log::error($config, "missing permission to read template '$template'") unless (-r $template);
return $template;
}
#deprecated (for old admin only)
sub exit_on_missing_permission{
my $permission=shift;
my $user_permissions=roles::get_user_permissions();
if ($user_permissions->{$permission} ne '1'){
print STDERR "missing permission to $permission\n";
template::process('print', template::check('default.html'), {error => 'sorry, missing permission!'});
die();
#exit;
}
}
sub clear_cache{
HTML::Template::Compiled->clear_cache();
# return;
# my $html_template = HTML::Template::Compiled->new();
# $html_template->clear_cache();
}
#do not delete last line!
1;

586
lib/calcms/time.pm Normal file
View File

@@ -0,0 +1,586 @@
use warnings "all";
use strict;
use Time::Local;
use DateTime;
use Date::Calc;
use Date::Manip;
use POSIX qw(strftime);
use config;
package time;
use Data::Dumper;
use utf8;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
format_datetime format_time
date_format time_format
datetime_to_time time_to_datetime time_to_date
datetime_to_date
add_days_to_datetime add_hours_to_datetime add_minutes_to_datetime
add_days_to_date
datetime_to_array date_to_array array_to_date array_to_datetime array_to_time array_to_time_hm
date_cond time_cond check_date check_time check_datetime check_year_month
datetime_to_rfc822 get_datetime datetime_to_utc datetime_to_utc_datetime
get_duration get_duration_seconds
get_durations get_names get_all_names get_weekdays weekday_index
$names
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
our $names={
'de' =>{
months =>['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
months_abbr =>['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
weekdays =>['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag'],
weekdays_abbr =>['Mo','Di','Mi','Do','Fr','Sa','So'],
},
'en' =>{
months =>['January','February','March','April','May','June','Jule','August','September','October','November','December'],
months_abbr =>['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
weekdays =>['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
weekdays_abbr =>['Mo','Tu','We','Th','Fr','Sa','Su'],
},
};
our $durations=[
0, 5,10,15,20,30,40,45,50,60,70,75,80,90,100,105,110,115,120,135,150,165,180,195,210,225,240,300,360,420,480,540,600,660,720,1440
];
sub get_names{
my $language=shift||'en';
return $time::names->{$language};
}
sub get_all_names{
return $time::names;
}
sub get_durations{
return $time::durations;
}
#TODO: build from datenames
our $weekday_index={
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'Mo'=> 0,
'Tu'=> 1,
'Di'=> 1,
'We'=> 2,
'Mi'=> 2,
'Th'=> 3,
'Do'=> 3,
'Fr'=> 4,
'Sa'=> 5,
'Su'=> 6,
'So'=> 6
};
sub get_weekdays{
return{
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
'Mo'=>0,
'Tu'=>1,
'Di'=>1,
'We'=>2,
'Mi'=>2,
'Th'=>3,
'Do'=>3,
'Fr'=>4,
'Sa'=>5,
'Su'=>6,
'So'=>6
};
}
#deprecated, for wordpress sync
sub format_datetime{
my $datetime=shift;
return $datetime if ($datetime eq '');
return add_hours_to_datetime($datetime,0);
};
#deprecated
sub format_time{
my $t=$_[0];
my $year =$t->[5]+1900;
my $month =$t->[4]+1;
$month ='0'.$month if(length($month)==1);
my $day =$t->[3];
$day ='0'.$day if(length($day)==1);
my $hour =$t->[2];
$hour ='0'.$hour if(length($hour)==1);
my $minute =$t->[1];
$minute ='0'.$minute if(length($minute)==1);
return [$day,$month,$year,$hour,$minute];
};
# convert datetime to unix time
sub datetime_to_time{
my $datetime=$_[0];
# print $datetime."\n";
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)[T\s](\d+)\:(\d+)(\:(\d+))?/){
my $year=$1;
my $month=$2-1;
my $day=$3;
my $hour=$4;
my $minute=$5;
my $second=$8||0;
return Time::Local::timelocal($second,$minute,$hour,$day,$month,$year);
}else{
print STDERR "datetime_to_time: no valid date time found! ($datetime )\n";
return -1;
}
};
#get rfc822 datetime string from datetime string
sub datetime_to_rfc822{
my $datetime=$_[0];
my $time=datetime_to_time($datetime);
return POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
}
#get seconds from epoch
sub datetime_to_utc{
my $datetime=shift;
my $time_zone=shift;
$datetime=get_datetime($datetime, $time_zone);
return $datetime->epoch();
}
# get full utc datetime including timezone offset
sub datetime_to_utc_datetime{
my $datetime=shift;
my $time_zone=shift;
$datetime=get_datetime($datetime, $time_zone);
return $datetime->format_cldr("yyyy-MM-ddTHH:mm:ssZZZZZ");
}
#add hours to datetime string
sub add_hours_to_datetime{
my $datetime=shift;
my $hours=shift;
return time_to_datetime(datetime_to_time($datetime)+(3600*$hours));
};
#add minutes to datetime string
sub add_minutes_to_datetime{
my $datetime=shift;
my $minutes=shift;
return time_to_datetime(datetime_to_time($datetime)+(60*$minutes));
};
#add days to datetime string
sub add_days_to_datetime{
my $datetime=shift;
my $days=shift;
my $time=datetime_to_array($datetime);
#print STDERR Dumper($time);
($time->[0], $time->[1], $time->[2]) =Date::Calc::Add_Delta_Days($time->[0]+0, $time->[1]+0, $time->[2]+0, $days);
return array_to_datetime($time);
}
sub add_days_to_date{
my $datetime=shift;
my $days=shift;
my $date=date_to_array($datetime);
($date->[0], $date->[1], $date->[2]) =Date::Calc::Add_Delta_Days($date->[0]+0, $date->[1]+0, $date->[2]+0, $days);
return array_to_date($date);
}
# convert unix time to datetime format
sub time_to_datetime{
my $time=shift;
$time=time() unless((defined $time) && ($time ne''));
my @t=localtime($time);
return sprintf('%04d-%02d-%02d %02d:%02d:%02d', $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
};
# convert unix time to date format
sub time_to_date{
my $time=shift;
$time=time() unless((defined $time) && ($time ne''));
my @t=localtime($time);
return sprintf('%04d-%02d-%02d', $t[5]+1900, $t[4]+1, $t[3]);
};
# convert datetime to a array of date/time values
sub datetime_to_array{
my $datetime=$_[0]||'';
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)([T\s]+(\d+)\:(\d+)(\:(\d+))?)?/){
my $year=$1;
my $month=$2;
my $day=$3;
my $hour=$5||'00';
my $minute=$6||'00';
my $second=$8||'00';
return [$year,$month,$day,$hour,$minute,$second];
}
return undef;
};
# convert datetime to date
sub datetime_to_date{
my $datetime=$_[0]||'';
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year=$1;
my $month=$2;
my $day=$3;
return sprintf("%04d-%02d-%02d",$year,$month,$day);
}
return undef;
};
#convert datetime array or single value to datetime string
sub array_to_datetime{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $date->[0], $date->[1], $date->[2], $date->[3], $date->[4], $date->[5]);
}
my $month =shift;
my $day =shift;
my $hour =shift||'0';
my $minute =shift||'0';
my $second =shift||'0';
return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $date, $month, $day, $hour, $minute, $second);
}
#convert date array or single values to date string
sub array_to_date{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%04d-%02d-%02d", $date->[0], $date->[1], $date->[2]);
}
my $month=shift;
my $day =shift;
return sprintf("%04d-%02d-%02d", $date, $month, $day);
}
sub array_to_time{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%02d:%02d:%02d", $date->[3], $date->[4], $date->[5]);
}
my $minute = shift||0;
my $second = shift||0;
return sprintf("%02d:%02d:%02d", $date, $minute, $second);
}
sub array_to_time_hm{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%02d:%02d", $date->[3], $date->[4]);
}
my $minute = shift||0;
return sprintf("%02d:%02d", $date, $minute);
}
# get number of days between two days
sub days_between{
my $today=$_[0];
my $date=$_[1];
my $delta_days=eval{Date::Calc::Delta_Days(
$today->[0],$today->[1],$today->[2],
$date->[0], $date->[1], $date->[2]
)};
return $delta_days;
}
sub dayOfYear{
my $datetime=$_[0];
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year = $1;
my $month = $2;
my $day = $3;
return Date::Calc::Day_of_Year($year,$month,$day);
}
return undef;
}
# get duration in minutes
sub get_duration{
my $start = shift;
my $end = shift;
my $timezone= shift;
$start=time::get_datetime($start, $timezone);
$end =time::get_datetime($end, $timezone);
my $duration=$end->epoch()-$start->epoch();
return $duration/60;
}
# get duration in seconds
sub get_duration_seconds{
my $start = shift;
my $end = shift;
my $timezone= shift||'UTC';
$start=time::get_datetime($start, $timezone);
$end =time::get_datetime($end, $timezone);
my $duration=$end->epoch()-$start->epoch();
return $duration;
}
# convert date string to a array of date values
sub date_to_array{
my $datetime=$_[0];
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year = $1;
my $month = $2;
my $day = $3;
return [$year,$month,$day];
}
return undef;
};
# parse date string and return date string
# pass 'today', return '' on parse error
sub date_cond{
my $date=shift;
return '' if ($date eq'');
if ($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
my $year = $1;
my $month = $2;
my $day = $3;
return sprintf("%04d-%02d-%02d", $year, $month, $day);
}
return 'today' if ($date eq 'today');
return '';
};
#parse time and return time string hh:mm:ss
#return hh:00 if time is 'now'
sub time_cond{
my $time = shift;
return '' if ($time eq'');
if ($time=~/(\d\d?)\:(\d\d?)(\:(\d\d))?/){
my $hour=$1;
my $minute=$2;
my $second=$4||'00';
return sprintf("%02d:%02d:%02d", $hour, $minute, $second);
}
if ($time eq 'now'){
my $date=datetime_to_array(time_to_datetime(time()));
my $hour=$date->[3]-2;
$hour=0 if ($hour<0);
$time=sprintf("%02d:00",$hour);
return $time;
}
return '';
};
#parse date and time string and return yyyy-mm-ddThh:mm:ss
sub datetime_cond{
my $datetime = shift;
return '' if ($datetime eq'');
(my $date,my $time)=split /[ T]/,$datetime;
$date=time::date_cond($date);
return '' if ($date eq'');
$time=time::time_cond($time);
return '' if ($time eq'');
return $date.'T'.$time;
}
sub check_date{
my $date=shift;
return "" if((!defined $date) || ($date eq ''));
if($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
return $1.'-'.$2.'-'.$3;
}elsif($date=~/(\d\d?)\.(\d\d?)\.(\d\d\d\d)/){
return $3.'-'.$2.'-'.$1;
}
return $date if ($date eq'today' || $date eq'tomorrow' || $date eq'yesterday');
return -1;
#error("no valid date format given!");
};
sub check_time{
my $time=shift;
return "" if((!defined $time) || ($time eq ''));
return $time if(($time eq 'now') || ($time eq 'future'));
if($time=~/(\d\d?)\:(\d\d?)/){
return $1.':'.$2
}
return -1;
};
sub check_datetime{
my $date=shift;
return "" if((!defined $date) || ($date eq ''));
if($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)[T ](\d\d?)\:(\d\d?)/){
return sprintf("%04d-%02d-%02dT%02d:%02d",$1,$2,$3,$4,$5);
}
return -1;
};
sub check_year_month{
my $date=shift;
return -1 unless(defined $date);
return $date if($date eq '');
if($date=~/(\d\d\d\d)\-(\d\d?)/){
return $1.'-'.$2.'-'.$3;
}
return -1;
};
#TODO: remove config dependency
sub date_time_format{
my $datetime=shift;
my $language=shift || $config::config->{date}->{language} || 'en';
if (defined $datetime && $datetime=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)[\sT](\d\d?\:\d\d?)/){
my $time=$4;
my $day=$3;
my $month=$2;
my $year=$1;
$month=$time::names->{$language}->{months_abbr}->[$month-1]||'';
return "$day. $month $year $time";
}
return $datetime;
}
#format datetime to date string
#TODO: remove config dependency
sub date_format{
my $datetime=shift;
my $language=shift || $config::config->{date}->{language} || 'en';
if (defined $datetime && $datetime=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
my $day=$3;
my $month=$2;
my $year=$1;
$month=$time::names->{$language}->{months_abbr}->[$month-1]||'';
return "$day. $month $year";
}
return $datetime;
};
#format datetime to time string
sub time_format{
my $datetime=shift;
if (defined $datetime && $datetime=~/(\d\d?\:\d\d?)/){
return $1;
}
return $datetime;
};
#get offset from given time_zone
sub utc_offset{
my $time_zone=shift;
$a=DateTime->now();
$a->set_time_zone($time_zone);
return $a->strftime("%z");
}
#get weekday from (yyyy,mm,dd)
sub weekday{
my ($year,$month,$day)=@_;
my $time = Time::Local::timelocal(0,0,0,$day,$month-1,$year);
return (localtime($time))[6];
}
#get current date, related to starting day_starting_hour
#TODO: remove config dependency
sub get_event_date{
my $config=shift;
$config=$config::config unless defined $config;
my $datetime=time::time_to_datetime(time());
my $hour=(time::datetime_to_array($datetime))->[3];
#today: between 0:00 and starting_hour show last day
if ($hour < $config->{date}->{day_starting_hour}){
my $date=time::datetime_to_array(time::add_hours_to_datetime($datetime,-24));
return $date->[0].'-'.$date->[1].'-'.$date->[2];
}else{
#today: between starting_hour and end of day show current day
my $date=time::datetime_to_array(time::time_to_datetime(time()));
return $date->[0]."-".$date->[1]."-".$date->[2];
}
}
#get datetime object from datetime string
sub get_datetime{
my $datetime=shift;
my $timezone=shift;
return unless defined $datetime;
return if $datetime eq '';
my @l = @{time::datetime_to_array($datetime)};
return undef if scalar(@l)==0;
# catch invalid datees
$datetime=undef;
eval{
$datetime=DateTime->new(
year =>$l[0],
month =>$l[1],
day =>$l[2],
hour =>$l[3],
minute =>$l[4],
second =>$l[5],
time_zone=> $timezone
);
};
return undef unless defined $datetime;
$datetime->set_locale('de_DE');
return $datetime;
}
#get list of nth weekday in month from start to end
sub get_nth_weekday_in_month{
my $start=shift; # datetime string
my $end=shift; # datetime string
my $nth=shift; # every nth week of month
my $weekday=shift; # weekday [0..6,'Mo'-'Su','Mo'-'Fr']
my $weekdays=time::get_weekdays();
$weekday=$weekdays->{$weekday+1};
my $dates=[];
if ($start=~/(\d\d\d\d)-(\d\d)-(\d\d)[ T](\d\d)\:(\d\d)/){
my $hour=int($4);
my $min=int($5);
my $sec=0;
my @date = Date::Manip::ParseRecur("0:1*$nth:$weekday:$hour:$min:$sec", "", $start, $end);
for my $date (@date){
if ($date=~/(\d\d\d\d)(\d\d)(\d\d)(\d\d)\:(\d\d)\:(\d\d)/){
push @$dates,"$1-$2-$3 $4:$5:$6";
}
}
}
return $dates;
}
#do not delete last line!
1;

818
lib/calcms/uac.pm Normal file
View File

@@ -0,0 +1,818 @@
#!/bin/perl
use CGI;
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use CGI::Session qw(-ip-match);
use CGI::Cookie;
#$CGI::Session::IP_MATCH=1;
package uac;
use warnings "all";
use strict;
use Data::Dumper;
use auth;
use db;
use template;
use project;
use studios;
#use series;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
get_user get_users update_user insert_user delete_user
get_roles insert_role update_role get_role_columns
get_studios_by_user get_users_by_studio
get_projects_by_user
get_user_role get_studio_roles
assign_user_role remove_user_role
get_user_permissions get_user_presets
prepare_request set_template_permissions
permission_denied
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
# get user by name
sub get_user{
my $config=shift;
my $user=shift;
my $query=qq{
select id, name, full_name, email, disabled, modified_at, created_at
from calcms_users
where name=?
};
my $bind_values=[$user];
my $dbh=db::connect($config);
my $users=db::get($dbh, $query,$bind_values);
if (@$users!=1){
print STDERR "cannot find user '$user'\n";
return undef;
}
return $users->[0];
}
# get all users
sub get_users{
my $config=shift;
my $query=qq{
select id, name, full_name, email, disabled, modified_at, created_at
from calcms_users
};
my $dbh=db::connect($config);
my $users=db::get($dbh, $query);
return $users;
}
#TODO: get_users_by_project
# get all users of a given studio id
# used at series (previously named get_studio_users)
sub get_users_by_studio{
my $config=shift;
my $condition=shift;
return unless (defined $condition->{studio_id});
my @conditions=();
my @bind_values=();
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
my $conditions='';
$conditions=" and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select distinct(u.id), u.name, u.full_name
from calcms_user_roles ur, calcms_users u
where ur.user_id=u.id
$conditions
};
my $dbh=db::connect($config);
my $users=db::get($dbh, $query, \@bind_values);
return $users;
}
# get projects a user is assigned by name
sub get_projects_by_user{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
if ((defined $condition->{user}) && ($condition->{user} ne '')){
push @conditions, 'u.name=?';
push @bind_values, $condition->{user};
}
my $conditions='';
$conditions=" and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select distinct p.*, ur.project_id project_id
from calcms_user_roles ur, calcms_users u, calcms_projects p
where ur.user_id=u.id and p.project_id=ur.project_id
$conditions
};
my $dbh=db::connect($config);
my $users=db::get($dbh, $query, \@bind_values);
return $users;
}
# get all studios a user is assigned to by role
# used at series (previously named get_user_studios)
sub get_studios_by_user{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
if ((defined $condition->{user}) && ($condition->{user} ne '')){
push @conditions, 'u.name=?';
push @bind_values, $condition->{user};
}
my $conditions='';
$conditions=" and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select distinct s.*, ur.project_id project_id
from calcms_user_roles ur, calcms_users u, calcms_studios s
where ur.user_id=u.id and s.id=ur.studio_id
$conditions
};
my $dbh=db::connect($config);
my $users=db::get($dbh, $query, \@bind_values);
return $users;
}
sub insert_user{
my $config=shift;
my $entry=shift;
$entry->{created_at} = time::time_to_datetime(time());
$entry->{modified_at}= time::time_to_datetime(time());
my $dbh=db::connect($config);
db::insert($dbh, 'calcms_users', $entry);
}
sub update_user{
my $config=shift;
my $entry=shift;
$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_users
set $values
where id=?
};
my $dbh =db::connect($config);
db::put($dbh, $query, \@bind_values);
}
sub delete_user{
my $config=shift;
my $id=shift;
return unless (defined $id && ($id=~/^\d+$/));
my $query=qq{
delete from calcms_users
where id=?
};
my $dbh =db::connect($config);
db::put($dbh, $query, [$id]);
}
# get all roles used by all users of a studio
# available conditions: project_id, studio_id
sub get_studio_roles{
my $config=shift;
my $condition=shift;
return [] if ($condition->{studio_id} eq '');
my @conditions=();
my @bind_values=();
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
my $conditions='';
$conditions=" and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select r.*, ur.studio_id, ur.project_id
from calcms_roles r, calcms_user_roles ur
where r.id=ur.role_id
$conditions
};
my $dbh=db::connect($config);
my $roles=db::get($dbh, $query, \@bind_values);
return $roles;
}
# get role columns (for external use only)
sub get_role_columns{
my $config=shift;
my $dbh=db::connect($config);
my $columns=db::get_columns_hash($dbh, 'calcms_roles');
return $columns
}
# get roles
# filter: studio_id project_id
sub get_roles{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
my $dbh=db::connect($config);
my $columns=db::get_columns_hash($dbh, 'calcms_roles');
for my $column (keys %$columns){
if (defined $condition->{$column}){
push @conditions, $column.'=?';
push @bind_values, $condition->{$column};
}
}
my $conditions='';
$conditions=' where '.join(' and ',@conditions) if(@conditions>0);
my $query=qq{
select r.*
from calcms_roles r
$conditions
};
my $roles=db::get($dbh, $query, \@bind_values);
return $roles;
}
#insert role to database, set created_at and modified_at
sub insert_role{
my $config=shift;
my $entry=shift;
$entry->{created_at} = time::time_to_datetime(time());
$entry->{modified_at}= time::time_to_datetime(time());
my $dbh=db::connect($config);
my $columns=db::get_columns_hash($dbh, 'calcms_roles');
;
my $role={};
for my $column (keys %$columns){
$role->{$column}=$entry->{$column} if defined $entry->{$column};
}
db::insert($dbh, 'calcms_roles', $role);
}
#update role, set modified_at
sub update_role{
my $config=shift;
my $entry=shift;
$entry->{modified_at}= time::time_to_datetime(time());
my $dbh =db::connect($config);
my $columns=db::get_columns_hash($dbh, 'calcms_roles');
my $values =join(",", map {$_.'=?'} (keys %$columns));
my @bind_values =map {$entry->{$_}} (keys %$columns);
push @bind_values,$entry->{id};
my $query=qq{
update calcms_roles
set $values
where id=?
};
# print $query."<br>\n".Dumper(\@bind_values)."<br>\ņ";
db::put($dbh, $query, \@bind_values);
}
# delete role from database
sub delete_role{
my $config=shift;
my $id=shift;
return unless (defined $id && ($id=~/^\d+$/));
my $query=qq{
delete from calcms_roles
where id=?
};
my $dbh =db::connect($config);
db::put($dbh, $query, [$id]);
}
# get all roles for given conditions: project_id, studio_id, user_id, name
# includes global admin user role
sub get_user_roles{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
if (defined $condition->{user}){
push @conditions, 'u.name=?';
push @bind_values, $condition->{user};
}
if (defined $condition->{user_id}){
push @conditions, 'ur.user_id=?';
push @bind_values, $condition->{user_id};
}
if (defined $condition->{studio_id}){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
if (defined $condition->{project_id}){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
my $conditions='';
$conditions= " and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select distinct r.*
from calcms_users u, calcms_user_roles ur, calcms_roles r
where ur.user_id=u.id and ur.role_id=r.id
$conditions
};
my $dbh=db::connect($config);
my $user_roles=db::get($dbh, $query, \@bind_values);
#return roles, if the contain an admin role
for my $role(@$user_roles){
return $user_roles if $role->{role}eq'Admin';
}
#get all admin roles
delete $condition->{studio_id} if defined $condition->{studio_id};
delete $condition->{project_id} if defined $condition->{project_id};
my $admin_roles=get_admin_user_roles($config, $condition);
#add admin roles to user roles
my @user_roles=(@$admin_roles, @$user_roles);
$user_roles=\@user_roles;
return $user_roles;
}
#return admin user roles for given conditions: project_id, studio_id, user, user_id
sub get_admin_user_roles{
my $config=shift;
my $condition=shift;
my @conditions=();
my @bind_values=();
if ((defined $condition->{user}) && ($condition->{user} ne '')){
push @conditions, 'u.name=?';
push @bind_values, $condition->{user};
}
if ((defined $condition->{user_id}) && ($condition->{user_id} ne '')){
push @conditions, 'ur.user_id=?';
push @bind_values, $condition->{user_id};
}
if ((defined $condition->{studio_id}) && ($condition->{studio_id} ne '')){
push @conditions, 'ur.studio_id=?';
push @bind_values, $condition->{studio_id};
}
if ((defined $condition->{project_id}) && ($condition->{project_id} ne '')){
push @conditions, 'ur.project_id=?';
push @bind_values, $condition->{project_id};
}
my $conditions='';
$conditions=" and ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select distinct r.*, ur.studio_id, ur.project_id
from calcms_users u, calcms_user_roles ur, calcms_roles r
where ur.user_id=u.id and ur.role_id=r.id and r.role='Admin'
$conditions
limit 1
};
my $dbh=db::connect($config);
my $user_roles=db::get($dbh, $query, \@bind_values);
return $user_roles;
}
# read permissions for given conditions and add to user_permissions
# return user_permissions
# studio_id, user_id, name
sub get_user_permissions{
my $config=shift;
my $conditions=shift;
my $user_permissions=shift;
my $user_roles = get_user_roles($config, $conditions);
my $admin_roles = get_admin_user_roles($config, $conditions);
my @user_roles=(@$admin_roles,@$user_roles);
#set default permissions
$user_permissions={} unless(defined $user_permissions);
$user_permissions->{is_admin}=1 if(scalar @$admin_roles>0);
my $max_level=0;
# aggregate max permissions
# should be limited by project and studio
for my $user_role (@user_roles){
if ($user_role->{level}>$max_level){
$user_permissions->{level} = $user_role->{level};
$user_permissions->{id} = $user_role->{id};
$user_permissions->{role} = $user_role->{role};
$user_permissions->{studio_id} = $user_role->{studio_id};
$user_permissions->{project_id}= $user_role->{project_id};
$max_level = $user_role->{level};
}
for my $permission (keys %$user_role){
if (($permission ne 'level') && ($permission ne 'id') && ($permission ne 'role') && ($permission ne 'studio_id') && ($permission ne 'project_id')){
$user_permissions->{$permission}=1 if ((defined $user_role->{$permission}) && ($user_role->{$permission} ne '0'));
}
}
}
return $user_permissions;
}
#get user id by user name
sub get_user_id{
my $config=shift;
my $user=shift;
return undef unless (defined $user);
my $query=qq{
select id
from calcms_users
where binary name=?
};
my $dbh=db::connect($config);
my $users=db::get($dbh, $query, [$user]);
return undef if (@$users==0);
return $users->[0]->{id};
}
#get role id by role name
sub get_role_id{
my $config=shift;
my $role=shift;
return undef unless (defined $role);
my $query=qq{
select id
from calcms_roles
where role=?
};
my $dbh=db::connect($config);
my $roles=db::get($dbh, $query, [$role]);
return undef if (@$roles==0);
return $roles->[0]->{id};
}
# assign a role to an user (for a studio)
sub assign_user_role{
my $config=shift;
my $options=shift;
#print STDERR Dumper($options);
return undef unless defined $options->{project_id};
return undef unless defined $options->{studio_id};
return undef unless defined $options->{user_id};
return undef unless defined $options->{role_id};
#return if already exists
my $query=qq{
select *
from calcms_user_roles
where project_id=? and studio_id=? and user_id=? and role_id=?
};
my $dbh=db::connect($config);
my $user_roles=db::get($dbh, $query, [$options->{project_id}, $options->{studio_id}, $options->{user_id}, $options->{role_id}]);
return undef if (@$user_roles>0);
#insert entry
my $entry={
project_id => $options->{project_id},
studio_id => $options->{studio_id},
user_id => $options->{user_id},
role_id => $options->{role_id},
created_at => time::time_to_datetime(time())
};
return db::insert($dbh, 'calcms_user_roles', $entry);
}
# unassign a user from a role of (for a studio)
sub remove_user_role{
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->{user_id};
return undef unless defined $options->{role_id};
my $query=qq{
delete
from calcms_user_roles
where project_id=? and studio_id=? and user_id=? and role_id=?
};
my $bind_values=[ $options->{project_id}, $options->{studio_id}, $options->{user_id}, $options->{role_id} ];
#print STDERR Dumper($query).Dumper($bind_values);
my $dbh=db::connect($config);
my $result=db::put($dbh, $query, $bind_values);
# successfully return even if no entry exists
return 1;
}
#checks
sub is_user_assigned_to_studio{
my $request=shift;
my $options=shift;
my $config = $request->{config};
return 0 unless defined $request->{user};
return 0 unless defined $options->{studio_id};
return 0 unless defined $options->{project_id};
my $options2={
user => $request->{user},
studio_id => $options->{studio_id},
project_id => $options->{project_id}
};
my $user_studios=uac::get_studios_by_user($config, $options2);
return 1 if(@$user_studios==1);
return 0;
}
# print errors at get_user_presets and check for project id and studio id
# call after header is printed
sub check{
my $config=shift;
my $params=shift;
my $user_presets=shift;
if (defined $user_presets->{error}){
uac::print_error($user_presets->{error});
return undef;
}
my $project_check=project::check($config, { project_id => $params->{project_id} } );
if($project_check ne '1'){
uac::print_error($project_check);
return undef;
}
my $studio_check=studios::check($config, { studio_id => $params->{studio_id} } );
if($studio_check ne '1'){
uac::print_error($studio_check);
return undef;
}
return 1;
}
# get user, projects and studios user is assigned to for selected values from params
# set permissions for selected project and studio
# return request
sub get_user_presets{
my $config = shift;
my $options = shift;
my $user = $options->{user}||'';
my $error = undef;
return {error=>"no user selected"} if ($user eq'');
my $project_id = $options->{project_id}||'';
my $studio_id = $options->{studio_id}||'';
$config->{access}->{write}=0;
#get
my $admin_roles = get_admin_user_roles($config, {user=>$user});
#get all projects by user
my $projects = uac::get_projects_by_user($config, {user=>$user});
return {error=>"no project is assigned to user"} if(@$projects==0);
$projects=project::get($config) if(@$admin_roles>0);
my @projects=reverse sort {$a->{end_date} cmp $b->{end_date}} (@$projects);
$projects=\@projects;
if ($project_id ne'' && $project_id ne'-1'){
my $projectFound=0;
for my $project(@$projects){
if ($project->{project_id} eq $project_id){
$projectFound=1;
last;
};
}
return {error=>"project is not assigned to user"} if($projectFound==0);
}else{
$project_id=$projects->[0]->{project_id};
}
#print STDERR "project:$project_id\n";
#check if studios are assigned to project
my $studios = project::get_studios($config, {project_id => $project_id});
$error="no studio is assigned to project" if (@$studios==0);
if(@$admin_roles==0){
#get all studios by user
$studios=uac::get_studios_by_user($config, {user=>$user, project_id=>$project_id});
$error="no studio is assigned to user" if (@$studios==0);
if (($studio_id ne '')&&($studio_id ne '-1')){
my $studioFound=0;
for my $studio(@$studios){
if ($studio->{id} eq $studio_id){
$studioFound=1;
last;
};
}
$error="studio is not assigned to user" if($studioFound==0);
}else{
$studio_id =$studios->[0]->{id};
}
}else{
#for admin get studios by project
$studios = studios::get($config, {project_id => $project_id});
if (($studio_id ne '')&&($studio_id ne '-1')){
my $studioFound=0;
for my $studio(@$studios){
if ($studio->{id} eq $studio_id){
$studioFound=1;
last;
};
}
$error="studio is not assigned to project" if($studioFound==0);
}else{
$studio_id =$studios->[0]->{id};
}
}
my $permissions=uac::get_user_permissions($config, {user=>$user, project_id=>$project_id, studio_id=>$studio_id});
#only admin is allowed to select all projects
# if($permissions->{is_admin}==1){
# $projects=project::get($config);
# }
#set studios and projects as selected, TODO:do in JS
my $selectedProject={};
for my $project(@$projects){
if ($project_id eq $project->{project_id}){
$project->{selected}='selected="selected"';
$selectedProject=$project;
last;
};
}
my $selectedStudio={};
for my $studio(@$studios){
if ($studio_id eq $studio->{id}){
$studio->{selected}='selected="selected"';
$selectedStudio=$studio;
last;
};
}
my $logout_url=(split(/\//, $0))[-1];
#print STDERR "ok\n";
my $result={
user => $user,
logout_url => $logout_url,
project_id => $project_id, # from parameter or default
projects => $projects,
project => $selectedProject,
studio_id => $studio_id, # from parameter or default
studios => $studios,
studio => $selectedStudio,
permissions => $permissions, # from parameter or default
config => $config
};
$result->{error}=$error if defined $error;
return $result;
}
#set user preset properties to request
sub prepare_request{
my $request=shift;
my $user_presets=shift;
for my $key (keys %$user_presets){
$request->{$key}=$user_presets->{$key};
}
#enrich menu parameters
for my $key ('studio_id', 'project_id', 'studio', 'project', 'studios', 'projects', 'user', 'logout_url'){
$request->{params}->{checked}->{presets}->{$key}=$user_presets->{$key};
}
return $request;
}
#TODO: shift to permissions sub entry
sub set_template_permissions{
my $permissions = shift;
my $params = shift;
for my $usecase (keys %$permissions){
$params->{'allow'}->{$usecase}=1 if ($permissions->{$usecase}eq'1');
}
return $params;
}
#print error message
sub permissions_denied{
my $message=shift;
$message=~s/_/ /g;
print '<div class="error">Sorry! Missing permissions to '.$message.'</div>'."\n";
print STDERR 'Sorry! Missing permissions to '.$message."\n";
}
sub print_info{
print '<div class="ok head">'
.'<span class="ui-icon ui-icon-check" style="float:left"></span>&nbsp;'
.$_[0]
.'</div>'."\n";
}
sub print_warn{
print '<div class="warn head">'
.'<span class="ui-icon ui-icon-info" style="float:left"></span>&nbsp;'
.$_[0]
.'</div>'."\n";
}
sub print_error{
print '<div class="error" head>'
.'<span class="ui-icon ui-icon-alert" style="float:left"></span>&nbsp;'
.$_[0].
'</div>'."\n";
}
#do not delete last line!
1;

214
lib/calcms/user_settings.pm Normal file
View File

@@ -0,0 +1,214 @@
package user_settings;
use warnings "all";
use strict;
use Data::Dumper;
use series_dates;
# table: calcms_user_settings
# columns: user, colors
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(getColors getColorCss get insert update delete get_columns defaultColors);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
our $defaultColors=[
{
name => 'color_event',
css => '#content .event',
color => '#c5e1a5'
},{
name => 'color_schedule',
css => '#content .schedule',
color => '#dde4e6',
},{
name => 'color_published',
css => '#content .event.published',
color => '#a5d6a7',
},{
name => 'color_no_series',
css => '#content .event.no_series',
color => '#fff59d',
},{
name => 'color_marked',
css => '#content .event.marked',
color => '#81d4fa',
},{
name => 'color_event_error',
css => '#content.conflicts .event.error',
color => '#ffab91',
},{
name => 'color_schedule_error',
css => '#content.conflicts .schedule.error',
color => '#ffcc80'
},{
name => 'color_work',
css => '#content .work',
color => '#b39ddb'
},{
name => 'color_playout',
css => '#content .play',
color => '#90caf9'
}
];
sub getColors{
my $config=shift;
my $conditions=shift;
return unless defined $conditions->{user};
my $user=$conditions->{user};
#get defaultColors
my $colors=[];
my $colorMap={};
for my $defaultColor (@$defaultColors){
my $color= {
name => $defaultColor->{name},
css => $defaultColor->{css},
color => $defaultColor->{color},
};
push @$colors,$color;
$colorMap->{$color->{css}}=$color;
}
my $settings = user_settings::get($config, {user => $user });
$settings->{colors} |='';
#overwrite colors from user settings
for my $line (split(/\n+/, $settings->{colors})){
my ($key,$value)=split(/\=/,$line);
$key=~s/^\s+//;
$key=~s/\s+$//;
$value=~s/^\s+//;
$value=~s/\s+$//;
$colorMap->{$key}->{color}=$value if (($key ne '')&&($value ne '')&&(defined $colorMap->{$key}));
}
return $colors;
}
sub getColorCss{
my $config=shift;
my $conditions=shift;
return unless defined $conditions->{user};
my $shift=20;
my $limit=220;
my $colors=getColors($config, $conditions);
my $style="<style>\n";
for my $color (@$colors){
$style.= $color->{css}."{\n\tbackground-color:".$color->{color}.";\n}\n";
my $c=$color->{color};
if ($c=~/#([a-fA-F0-9][a-fA-F0-9])([a-fA-F0-9][a-fA-F0-9])([a-fA-F0-9][a-fA-F0-9])/){
my $r=hex($1);
my $g=hex($2);
my $b=hex($3);
if ($r>$limit){$r-=$shift;}else{$r+=$shift;}
if ($g>$limit){$g-=$shift;}else{$g+=$shift;}
if ($b>$limit){$b-=$shift;}else{$b+=$shift;}
$c=sprintf("#%x%x%x",$r,$g,$b);
$style.= $color->{css}.":hover{\n\tbackground-color:".$c.";\n}\n";
}
}
$style.="</style>\n";
return $style;
}
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_user_settings');
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}) && ($condition->{user} ne '')){
push @conditions, 'user=?';
push @bind_values, $condition->{user};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_user_settings
$conditions
};
#print $query."\n";
#print Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
return $entries->[0]||undef;
}
sub insert{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{user});
return unless(defined $entry->{colors});
my $dbh=db::connect($config);
return db::insert($dbh, 'calcms_user_settings', $entry);
}
sub update{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{user});
return unless(defined $entry->{colors});
my $dbh=db::connect($config);
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{user};
my $query=qq{
update calcms_user_settings
set $values
where user=?
};
db::put($dbh, $query, \@bind_values);
print "done\n";
}
sub delete{
my $config=shift;
my $entry=shift;
return unless(defined $entry->{user});
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_user_settings
where user=?
};
my $bind_values=[$entry->{user}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

247
lib/calcms/user_stats.pm Normal file
View File

@@ -0,0 +1,247 @@
#!/bin/perl
package user_stats;
use warnings "all";
use strict;
use Data::Dumper;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get update insert get_stats increase);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_user_stats');
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->{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}) && ($condition->{user} ne '')){
push @conditions, 'user=?';
push @bind_values, $condition->{user};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_user_stats
$conditions
order by modified_at desc
$limit
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $results=db::get($dbh, $query, \@bind_values);
return $results;
}
sub get_stats{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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}) && ($condition->{user} ne '')){
push @conditions, 'user=?';
push @bind_values, $condition->{user};
}
my $limit='';
if ((defined $condition->{limit}) && ($condition->{limit} ne '')){
$limit= 'limit '.$condition->{limit};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select user, project_id, studio_id,
max(modified_at) modified_at,
sum(create_events) create_events,
sum(update_events) update_events,
sum(delete_events) delete_events,
sum(create_series) create_series,
sum(update_series) update_series,
sum(delete_series) delete_series
from calcms_user_stats
$conditions
group by user, project_id, studio_id
$limit
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $results=db::get($dbh, $query, \@bind_values);
for my $result (@$results){
$result->{score}=0;
for my $column ('create_events','update_events','delete_events','create_series','update_series','delete_series'){
$result->{score}+=$result->{$column};
}
}
my @results=reverse sort {$a->{score} <=> $b->{score}} @$results;
return \@results;
}
sub insert{
my $config=shift;
my $stats=shift;
return undef unless defined $stats->{project_id};
return undef unless defined $stats->{studio_id};
return undef unless defined $stats->{series_id};
return undef unless defined $stats->{user};
#TODO:filter for existing attributes
my $columns=get_columns($config);
my $entry={};
for my $column (keys %$columns){
$entry->{$column}=$stats->{$column} if defined $stats->{$column};
}
$entry->{modified_at}= time::time_to_datetime(time());
my $dbh=db::connect($config);
my $id=db::insert($dbh, 'calcms_user_stats', $entry);
return $id;
}
# update project
sub update{
my $config=shift;
my $stats=shift;
return undef unless defined $stats->{project_id};
return undef unless defined $stats->{studio_id};
return undef unless defined $stats->{series_id};
return undef unless defined $stats->{user};
my $columns=get_columns($config);
my $entry={};
for my $column (keys %$columns){
$entry->{$column}=$stats->{$column} if defined $stats->{$column};
}
$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->{user};
push @bind_values, $entry->{project_id};
push @bind_values, $entry->{studio_id};
push @bind_values, $entry->{series_id};
my $query=qq{
update calcms_user_stats
set $values
where user=? and project_id=? and studio_id=? and series_id=?
};
#print STDERR Dumper($query).Dumper(\@bind_values);
my $dbh=db::connect($config);
return db::put($dbh, $query, \@bind_values);
}
sub increase{
my $config=shift;
my $usecase=shift;
my $options=shift;
#print STDERR Dumper($usecase)." ".Dumper($options);
return undef unless defined $usecase;
return undef unless defined $options->{project_id};
return undef unless defined $options->{studio_id};
return undef unless defined $options->{series_id};
return undef unless defined $options->{user};
#print STDERR "ok\n";
my $columns=get_columns($config);
#print STDERR "columns:".Dumper($columns);
return undef unless defined $columns->{$usecase};
my $entries= get($config,$options);
#print STDERR "exist:".Dumper($columns);
if (@$entries==0){
my $entry={
project_id => $options->{project_id},
studio_id => $options->{studio_id},
series_id => $options->{series_id},
user => $options->{user},
$usecase => 1,
};
#print STDERR "user_stats::insert\n";
return insert($config, $entry);
}elsif (@$entries==1){
my $entry=$entries->[0];
$entry->{$usecase}++ if defined
#print STDERR "user_stats::update\n";
return update($config, $entry);
}else{
print STDERR "user_stats: to few options given: $usecase,".Dumper($options)."\n";
}
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

385
lib/calcms/work_dates.pm Normal file
View File

@@ -0,0 +1,385 @@
package work_dates;
use warnings "all";
use strict;
use Data::Dumper;
use Date::Calc;
use time;
use db;
use log;
use studio_timeslot_dates;
use work_schedule;
# schedule dates for work_schedule
# table: calcms_work_dates
# columns: id, studio_id, schedule_id, start(datetime), end(datetime)
# TODO: delete column schedule_id
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete get_dates);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_work_dates');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
# get all work_dates for studio_id and schedule_id within given time range
# calculate start_date, end_date, weeday, day from start and end(datetime)
sub get{
my $config=shift;
my $condition=shift;
my $date_range_include=0;
$date_range_include=1 if $condition->{date_range_include}==1;
my $dbh=db::connect($config);
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->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'schedule_id=?';
push @bind_values, $condition->{schedule_id};
}
if ((defined $condition->{start_at}) && ($condition->{start_at} ne '')){
push @conditions, 'start=?';
push @bind_values, $condition->{start_at};
}
if ((defined $condition->{from}) && ($condition->{from} ne '')){
if ($date_range_include==1){
push @conditions, 'end_date>=?';
push @bind_values, $condition->{from};
}else{
push @conditions, 'start_date>=?';
push @bind_values, $condition->{from};
}
}
if ((defined $condition->{till}) && ($condition->{till} ne '')){
if ($date_range_include==1){
push @conditions, 'start_date<=?';
push @bind_values, $condition->{till};
}else{
push @conditions, 'end_date<=?';
push @bind_values, $condition->{till};
}
}
if ((defined $condition->{exclude}) && ($condition->{exclude} ne '')){
push @conditions, 'exclude=?';
push @bind_values, $condition->{exclude};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select date(start) start_date
,date(end) end_date
,dayname(start) weekday
,start_date day
,start
,end
,schedule_id
,studio_id
,project_id
,exclude
,type
,title
from calcms_work_dates
$conditions
order by start
};
#print STDERR $query."\n";
#print STDERR Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
for my $entry (@$entries){
$entry->{weekday}=substr($entry->{weekday},0,2);
}
return $entries;
}
#update work dates for all schedules of a work and studio_id
sub update{
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->{schedule_id} ;
my $dbh=db::connect($config);
#delete all existing work dates (by project, studio and schedule id)
work_dates::delete($config, $entry);
my $day_start=$config->{date}->{day_starting_hour};
#get all schedules for schedule id ordered by exclude, date
my $schedules=work_schedule::get($config, {
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
schedule_id => $entry->{schedule_id},
});
#add scheduled work dates and remove exluded dates
my $work_dates={};
#TODO:set schedules exclude to 0 if not 1
#insert all normal dates (not excludes)
for my $schedule (@$schedules){
my $dates=get_schedule_dates($schedule, {exclude => 0});
for my $date (@$dates){
$date->{exclude}=0;
$work_dates->{$date->{start}}=$date;
#print STDERR Dumper($date)."\n" if ($date->{start} eq'2014-02-05 19:00:00');
}
}
#insert / overwrite all exlude dates
for my $schedule (@$schedules){
my $dates=get_schedule_dates($schedule, {exclude => 1});
for my $date (@$dates){
$date->{exclude}=1;
$work_dates->{$date->{start}}=$date;
#print STDERR Dumper($date)."\n" if ($date->{start} eq'2014-02-05 19:00:00');
}
}
#print STDERR Dumper($work_dates->{'2014-02-05 19:00:00'});
my $request={
config => $config
};
my $i=0;
my $j=0;
for my $date (keys %$work_dates){
my $work_date=$work_dates->{$date};
#insert date
my $entry={
project_id => $entry->{project_id},
studio_id => $entry->{studio_id},
schedule_id => $entry->{schedule_id},
title => $entry->{title},
type => $entry->{type},
schedule_id => $entry->{schedule_id},
start => $work_date->{start},
end => $work_date->{end},
exclude => $work_date->{exclude}
};
if(studio_timeslot_dates::can_studio_edit_events($config, $entry)==1){ # by studio_id, start, end
$entry->{start_date}= time::add_hours_to_datetime($entry->{start}, -$day_start);
$entry->{end_date}= time::add_hours_to_datetime($entry->{end}, -$day_start);
db::insert($dbh, 'calcms_work_dates', $entry);
#print STDERR "$entry->{start_date}\n";
$i++;
}else{
$j++;
#print STDERR Dumper($entry);
}
}
#print STDERR "$i work_dates updates\n";
return $j." dates out of studio times, ".$i;
}
sub get_schedule_dates{
my $schedule=shift;
my $options=shift;
my $is_exclude=$options->{exclude}||0;
my $dates=[];
return $dates if (($is_exclude eq'1') && ($schedule->{exclude}ne'1'));
return $dates if (($is_exclude eq'0') && ($schedule->{exclude}eq'1'));
if ($schedule->{period_type}eq'single'){
$dates=get_single_date($schedule->{start}, $schedule->{duration}) ;
}elsif($schedule->{period_type}eq'days'){
$dates=get_dates($schedule->{start}, $schedule->{end}, $schedule->{duration}, $schedule->{frequency}) ;
}elsif($schedule->{period_type}eq'week_of_month'){
$dates=get_week_of_month_dates($schedule->{start}, $schedule->{end}, $schedule->{duration}, $schedule->{week_of_month}, $schedule->{weekday}, $schedule->{month});
}else{
print STDERR "unknown schedule period_type\n";
}
return $dates;
}
sub get_week_of_month_dates{
my $start =shift; # datetime string
my $end =shift; # datetime string
my $duration =shift; # in minutes
my $week =shift; # every nth week of month
my $weekday =shift; # weekday [1..7]
my $frequency =shift; # every 1st,2nd,3th time
return undef if $start eq'';
return undef if $end eq'';
return undef if $duration eq'';
return undef if $week eq'';
return undef if $weekday eq'';
return undef if $frequency eq'';
return undef if $frequency==0;
my $start_dates=time::get_nth_weekday_in_month($start, $end, $week, $weekday-1);
my $results=[];
my $c=-1;
for my $start_datetime (@$start_dates){
$c++;
my @start = @{time::datetime_to_array($start_datetime)};
next unless @start>=6;
next if (($c % $frequency)!=0);
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$start[0], $start[1], $start[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
my $end_datetime=time::array_to_datetime(\@end_datetime);
push @$results, {
start => $start_datetime,
end => $end_datetime
};
}
return $results;
}
#add duration to a single date
sub get_single_date{
my $start_datetime = shift;
my $duration = shift;
my @start = @{time::datetime_to_array($start_datetime)};
return unless @start>=6;
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$start[0], $start[1], $start[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
my $date={
start => $start_datetime,
end => time::array_to_datetime(\@end_datetime)
};
return [$date];
}
#calculate all dates between start_datetime and end_date with duration(minutes) and frequency(days)
sub get_dates{
my $start_datetime = shift;
my $end_date = shift;
my $duration = shift; # in minutes
my $frequency = shift; # in days
#print "start_datetime:$start_datetime end_date:$end_date duration:$duration frequency:$frequency\n";
my @start = @{time::datetime_to_array($start_datetime)};
return unless @start>=6;
my @start_date = ($start[0], $start[1], $start[2]);
my $start_time = sprintf('%02d:%02d:%02d', $start[3], $start[4], $start[5]);
#print STDERR "$start_datetime,$end_date,$duration,$frequency\n";
#return on single date
my $date={};
$date->{start}= sprintf("%04d-%02d-%02d",@start_date).' '.$start_time;
return undef if $duration eq '';
return undef if (($frequency eq '')||($end_date eq''));
#continue on recurring date
my @end = @{time::datetime_to_array($end_date)};
return unless @end>=3;
my @end_date = ($end[0], $end[1], $end[2]);
my $today=time::time_to_date();
my ($year, $month, $day)=split(/\-/,$today);
#do not show dates one month back
my $not_before= sprintf("%04d-%02d-%02d", Date::Calc::Add_Delta_Days($year, $month, $day, -30));
my $dates=[];
return $dates if ($end_date lt $today);
return $dates if ($frequency<1);
my $j = Date::Calc::Delta_Days(@start_date, @end_date);
my $c=0;
for (my $i = 0; $i <= $j; $i+=$frequency ){
my @date = Date::Calc::Add_Delta_Days($start[0], $start[1], $start[2], $i);
my $date={};
$date->{start}=sprintf("%04d-%02d-%02d",@date).' '.$start_time;
my @end_datetime = Date::Calc::Add_Delta_DHMS(
$date[0], $date[1], $date[2], # start date
$start[3], $start[4], $start[5], # start time
0, 0, $duration, 0 # delta days, hours, minutes, seconds
);
$date->{end}=time::array_to_datetime(\@end_datetime);
last if ($c>200);
$c++;
next if $date->{end} lt $not_before;
push @$dates,$date;
}
return $dates;
}
#remove all work_dates for studio_id and schedule_id
sub delete{
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->{schedule_id};
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_work_dates
where project_id=? and studio_id=? and schedule_id=?
};
my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{schedule_id}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
return db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;

156
lib/calcms/work_schedule.pm Normal file
View File

@@ -0,0 +1,156 @@
package work_schedule;
use warnings "all";
use strict;
use Data::Dumper;
use series_dates;
# table: calcms_work_schedule
# columns: id, studio_id, series_id,
# start (datetime),
# duration (minutes),
# frequency (days),
# end (date),
# weekday (1..7)
# week_of_month (1..5)
# month
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(get_columns get insert update delete);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
sub debug;
sub get_columns{
my $config=shift;
my $dbh=db::connect($config);
my $cols=db::get_columns($dbh, 'calcms_work_schedule');
my $columns={};
for my $col (@$cols){
$columns->{$col}=1;
}
return $columns;
}
#map schedule id to id
sub get{
my $config=shift;
my $condition=shift;
my $dbh=db::connect($config);
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->{schedule_id}) && ($condition->{schedule_id} ne '')){
push @conditions, 'schedule_id=?';
push @bind_values, $condition->{schedule_id};
}
if ((defined $condition->{start}) && ($condition->{start} ne '')){
push @conditions, 'start=?';
push @bind_values, $condition->{start};
}
if ((defined $condition->{exclude}) && ($condition->{exclude} ne '')){
push @conditions, 'exclude=?';
push @bind_values, $condition->{exclude};
}
if ((defined $condition->{period_type}) && ($condition->{period_type} ne '')){
push @conditions, 'period_type=?';
push @bind_values, $condition->{period_type};
}
my $conditions='';
$conditions=" where ".join(" and ",@conditions) if (@conditions>0);
my $query=qq{
select *
from calcms_work_schedule
$conditions
order by exclude, start
};
#print STDERR $query."\n".Dumper(\@bind_values);
my $entries=db::get($dbh, $query, \@bind_values);
return $entries;
}
sub insert{
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->{start};
my $dbh=db::connect($config);
return db::insert($dbh, 'calcms_work_schedule', $entry);
}
#schedule id to id
sub update{
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->{schedule_id};
return undef unless defined $entry->{start};
my $dbh=db::connect($config);
my $values =join(",", map {$_.'=?'} (keys %$entry));
my @bind_values =map {$entry->{$_}} (keys %$entry);
push @bind_values,$entry->{project_id};
push @bind_values,$entry->{studio_id};
push @bind_values,$entry->{schedule_id};
my $query=qq{
update calcms_work_schedule
set $values
where project_id=? and studio_id=? and schedule_id=?
};
return db::put($dbh, $query, \@bind_values);
print "done\n";
}
#map schedule id to id
sub delete{
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->{schedule_id};
my $dbh=db::connect($config);
my $query=qq{
delete
from calcms_work_schedule
where project_id=? and studio_id=? and schedule_id=?
};
my $bind_values=[$entry->{project_id}, $entry->{studio_id}, $entry->{schedule_id}];
#print '<pre>$query'.$query.Dumper($bind_values).'</pre>';
return db::put($dbh, $query, $bind_values);
}
sub error{
my $msg=shift;
print "ERROR: $msg<br/>\n";
}
#do not delete last line!
1;