// This is a caudium module (c) Bill Welliver 2002-2004 // The calendar module. // parses the container, and creates a calendar with events // // This is based on inspiration from calendar.pike by Martin Baehr. // // Contact information: Bill Welliver // // This code is (c) 2002-2004 Bill Welliver, and can be used, modified and // redistributed freely under the terms of the GNU General Public License, // version 2. // This code comes on a AS-IS basis, with NO WARRANTY OF ANY KIND, either // implicit or explicit. Use at your own risk. /* TODO: - verify that a user may view an event/view before displaying it. currently we just filter out views from the pick a view boxes. - verify functionality with databases other than mysql. - add repeating appointments - add ability to create / update calendars and perms (administrator) */ /* database schema follows # MySQL dump 8.16 # # Host: localhost Database: event #-------------------------------------------------------- # Server version 3.23.45 # # Table structure for table 'acl' # CREATE TABLE acl ( aclid int(11) NOT NULL default '0', name char(80) NOT NULL default '', PRIMARY KEY (aclid) ) TYPE=MyISAM; # # Table structure for table 'acl_data' # # valid values for entity: public, user, owner, [userid] # valid values for permit: r=read, w=write CREATE TABLE acl_data ( aclid int(11) NOT NULL default '0', acldataid int(11) NOT NULL default '0', entity char(16) NOT NULL default '', permit char(2) NOT NULL default '', PRIMARY KEY (acldataid) ) TYPE=MyISAM; # # Table structure for table 'event_occurrences' # CREATE TABLE event_occurrences ( eventid int(11) NOT NULL default '0', occurrenceid int(11) NOT NULL default '0', startdate date NOT NULL default '0000-00-00', enddate date NOT NULL default '0000-00-00', starttime time default NULL, endtime time default NULL, PRIMARY KEY (occurrenceid) ) TYPE=MyISAM; # # Table structure for table 'events' # CREATE TABLE events ( eventid int(11) NOT NULL default '0', owner varchar(16) NOT NULL default '', acl varchar(16) NOT NULL default 'public', view varchar(16) NOT NULL default '', subject varchar(128) default NULL, description text, data text, create_stamp datetime default NULL, modify_stamp datetime default NULL, PRIMARY KEY (eventid) ) TYPE=MyISAM; # # Table structure for table 'views' # CREATE TABLE views ( viewid int(11) NOT NULL default '0', name char(80) NOT NULL default '', acl int(11) NOT NULL default '0', event_acl int(11) NOT NULL default '0', PRIMARY KEY (viewid) ) TYPE=MyISAM; */ constant cvs_version="$Id: calendar.pike,v hww3 Exp $"; constant thread_safe=0; #define SESSION id->misc->session_variables #define VARIABLES id->variables #define CAL id->misc->calendar->cal #define TODAY id->misc->calendar->today #include inherit "caudiumlib"; inherit "module"; object events, dbconn; mapping daystoevents=([]); string showdocs() { return "The displayed month can be changed with the attributes:\n" "
\n" "
type=string (optional)\n" "
this will select a different subclass from pikes Calendar\n" "class for the calendar. Thanks to the great Calendar class\n" "no changes needed to be made to support different, even way\n" "nonstandard calendars (as long as the concepts Day, Week, Month\n" "and Year are present). The default for this can be changed\n" "in the admin interface.
\n" "please note that, even if you use a different calendar type,\n" "the events still need to be entered using the gregorian calendar.\n" "the event-datess are stored with a unique number, identical" "across all calendars, so that any event can be displayed with any\n" "calendar type.\n" "

\n" "The contents of the container are first RXML parsed, to\n" "allow you to provide your own methods to get events\n" "(ie: using <insert>)

\n" "The <calendar></calendar> container\n" "understands the <event></event> container\n" "which can be used to display an event description at the given\n" "date.\n" "

\n" "
day=number (mandatory)\n" "
if missing the current day will be used which is probably " "not what you want.\n" "
month=number (optional)\n" "
if missing the current month will be used.\n" "
year=number (optional)\n" "
if missing the current year will be used.\n" "
\n" "The <event></event> container may contain\n" "anything that you may put into the <td></td> " "container.\n"; } void stop() { if(objectp(dbconn) && dbconn) destruct(dbconn); return; } void start(int cnt, object conf) { /* We need gsession */ module_dependencies(conf, ({ "gsession" })); if(query("country")) events=Calendar.Events.country(query("country")); // this is an ugly way to set up a connection. if(query("dbserver")!="") startdb(); } void startdb() { dbconn=Sql.Sql(query("dbserver")); } array register_module() { return ({ MODULE_PARSER, "Calendar", "Defines the <calendar></calendar> " "container, which produces a calendarpage of the current " "month.
\nHelp can be displayed with " "<calendar help></calendar>

\n\n"+showdocs() ,0,1 }); } void create() { defvar("type", "ISO", "Type of Calendar to use as default", TYPE_STRING_LIST, "Select, which subclass from the calendar class you want to " "use. Currently available are Austrian, Julian, Swedish, Gregorian, " "Orthodox and ISO. Select other if you provide your own class", ({ "Austrian", "Julian", "Swedish", "Gregorian", "Orthodox", "ISO", "other" })); defvar("country", "us", "Country", TYPE_STRING, "Enter the country in which this calendar should operate. " "This setting determines the holidays that are loaded." ); defvar("dbserver", "", "Event Database", TYPE_STRING, "This is the SQL URL of the database used to store user events." ); defvar("dayhilighting", 0, "Use Day Hilighting?", TYPE_FLAG, "Should days be highlighted according to a formula?" ); } string itag_calendararea(string tag_name, mapping arguments, object id, mapping defines) { string out=""; if(VARIABLES->delete_event) { out+=display_delete_event(CAL, TODAY, id); } else if(VARIABLES->view_props) { out+=display_event_properties(CAL, TODAY, id); } else if(SESSION->mode=="login") { if(!is_user(id)) return "not_query + "&login=1\">"; else return "not_query + "?mode=browse\">"; } else if(SESSION->mode=="browse") { out+=call_function(this_object()["display_" + SESSION->view_as], CAL, TODAY, id); } else if(SESSION->mode=="add_event") { out+=display_add_event(CAL, TODAY, id); } else if(SESSION->mode=="add_appointment") { out+=display_add_appointment(CAL, TODAY, id); } else if(is_user(id) && SESSION->mode=="preferences") { out+="Preferences"; } else if(is_admin_user(id) && SESSION->mode=="admin") { out+=display_admin(CAL, TODAY, id); } return out; } string itag_calendarnavigation(string tag_name, mapping arguments, object id, mapping defines) { string out=""; if(VARIABLES->delete_event) { out+=display_mode_options(id); } else if(VARIABLES->view_props) { out+=display_mode_options(id); } else if(SESSION->mode=="browse") { out+=display_mode_options(id); out+=display_navigation_options((arguments->type||"text"), id); } else if(SESSION->mode=="add_event") { out+=display_mode_options(id); } else if(SESSION->mode=="add_appointment") { out+=display_mode_options(id); } else if(is_user(id) && SESSION->mode=="preferences") { out+=display_mode_options(id); } else if(is_admin_user(id) && SESSION->mode=="admin") { out+=display_mode_options(id); } return out; } string container_events(string tag_name, mapping arguments, string contents, object id, mapping defines) { if(! arguments->view || arguments->view=="") return "error: no view specified."; array r=dbconn->query("select * from views where name=%s", arguments->view); if(sizeof(r)!=1) return "error: non-existent view " + arguments->view + "\n"; int view=r[0]->viewid; array m = get_readable_views(id); int readable=0; foreach(m, array v) if(v[0]==view) readable=1; if(!readable) return "error: read permission denied on view.\n"; string retval=""; object unit; int count; string unit_name; if(arguments->months) { unit=Calendar.Month(); count=(int)(arguments->months); unit_name = "month"; } else if(arguments->weeks) { unit=Calendar.Week(); count=(int)(arguments->weeks); unit_name = "week"; } else if(arguments->days) { unit=Calendar.Day(); count=(int)(arguments->day); unit_name = "day"; } for(int i=0; imonths) { retval+="

" + unit->month_name() + " " + unit->year_name() + "

\n"; start = unit->days()[0]->format_ymd(); end = unit->days()[-1]->format_ymd(); } else if(arguments->weeks) { retval+="

" + print_date(unit->days()[0]) + " - " + print_date(unit->days()[-1]) + "

\n"; start = unit->days()[0]->format_ymd(); end = unit->days()[-1]->format_ymd(); } else if(arguments->days) { retval+="

" + print_date(unit) + "

\n"; start = unit->days()[0]->format_ymd(); end = unit->days()[-1]->format_ymd(); } r = dbconn->query("select * from event_occurrences, events where " "events.view=" + view + " AND startdate>= '" + start + "' AND enddate <= '" + end + "' AND events.eventid = " + "event_occurrences.eventid order by event_occurrences.startdate, event_occurrences.enddate"); unit++; if(!sizeof(r)) { retval+="No events this " + unit_name + ".

"; continue; } foreach(r, mapping ev) { retval+=parse_date(ev->startdate, id) + " " + (ev->starttime!=0?(parse_time(ev->starttime, id) + (ev->endtime!=0?(" to " + parse_time(ev->endtime, id)):"")):"") + " " + ev->subject + "
\n"; retval+="" + ev->description + "

\n"; } } return retval; } string container_calendar(string tag_name, mapping arguments, string contents, object id, mapping defines) { id->misc->calendar=([]); id->misc->calendar->caltype = query("type"); if(arguments->type) id->misc->calendar->caltype=arguments->type; id->variables->caltype=id->misc->calendar->caltype; // load any session variables set_vars(id); set_prefs(id); // today is our reference. id->misc->calendar->today=Calendar[SESSION->caltype]["Hour"](); // load our current viewpoint id->misc->calendar->cal=Calendar[SESSION->caltype]["Day"](SESSION->current_point); mapping tags=([ "calendar_navigation": itag_calendarnavigation, "calendar_area": itag_calendararea ]); mapping containers=([]); contents=Caudium.parse_html(contents, tags, containers, id); return contents; } int is_user(object id) { if(id->auth && id->auth[0]==1) return 1; else return 0; } int is_admin_user(object id) { return 0; return 1; } void set_prefs(object id) { if(!SESSION->calprefs) SESSION->calprefs=([]); SESSION->calprefs->format_time="12h"; } void set_vars(object id) { if(VARIABLES->view_as) SESSION->view_as=VARIABLES->view_as; if(!SESSION->mode) SESSION->mode="browse"; if(!SESSION->event_view) SESSION->event_view="0"; if(VARIABLES->event_view) SESSION->event_view=VARIABLES->event_view; if(VARIABLES->mode) SESSION->mode=VARIABLES->mode; // the default calendar type is defined in the config interface. if(!SESSION->caltype) SESSION->caltype=id->variables->caltype; // the default view is "day". if(!SESSION->view_as) SESSION->view_as="day"; // if we don't already have a view point, we set it to today. if(!SESSION->current_point) SESSION->current_point=Calendar.ISO.Day()->jd; // do we need to move the current view point? if(VARIABLES->move_to) alter_current_point(id); return; } void alter_current_point(object id) { // we need to move the current view point. object vp; if(VARIABLES->move_to==".") // move to today vp=Calendar[SESSION->caltype]->Day(); else if(VARIABLES->move_to[0..0]=="J") // move to specific day vp=Calendar[SESSION->caltype]->Day((int)(VARIABLES->move_to[2..])); else { vp=Calendar[SESSION->caltype]->Day(SESSION->current_point); if(VARIABLES->move_to==">") vp=vp[SESSION->view_as]()->next(); // move to next whatever else if(VARIABLES->move_to=="<") vp=vp[SESSION->view_as]()->prev(); // move to last to whatever } SESSION->current_point=vp->jd; } string display_navigation_options(string type, object id) { string out="

not_query + "\">"; if(type=="text") { out+="move to: "; out+="not_query + "?move_to=<\">previous "; out+="not_query + "?move_to=.\">today "; out+="not_query + "?move_to=>\">next"; out+="   \n"; out+="calendar: "; out+="\n"; out+="
"; out+="view as: "; foreach(({"year", "month", "week", "day"}), string view) if(SESSION->view_as && SESSION->view_as==view) out+=" " + view + " "; else out+=" not_query + "?view_as=" + view + "\">" + view + ""; } else if(type=="graphics") { out+="move to: "; out+="not_query + "?move_to=<\">previous "; out+="not_query + "?move_to=.\">today "; out+="not_query + "?move_to=>\">next"; out+="   \n"; out+="view as: "; foreach(({"year", "month", "week", "day"}), string view) if(SESSION->view_as && SESSION->view_as==view) out+=" " + view + " "; else out+=" not_query + "?view_as=" + view + "\">" + view + " "; out+="   calendar: "; out+="\n"; } out+="
\n"; return out; } string display_mode_options(object id) { string out=""; out+="choose a mode: "; array o=({"browse", "add event", "add appointment"}); if(is_user(id)) o+=({"preferences"}); else o+=({"login"}); if(is_admin_user(id)) o+=({"admin"}); foreach(o, string mode) { if(replace(mode, " ", "_")==SESSION->mode) out+=" " + mode + " "; else out+= " not_query + "?mode=" + replace(mode, " ", "_") + "\">" + mode + ""; } out+="
\n"; return out; } int|string get_userid(object id) { if(id->auth && sizeof(id->auth)>1 && id->auth[0]==1) return id->auth[1]; else return 0; } array get_writeable_views(object id) { array retval=({}); string|int auth= get_userid(id); array r=dbconn->query("SELECT views.viewid, views.name FROM " "views,acl_data WHERE permit='w' AND " "entity in(" + (stringp(auth)?"'"+auth+"','user',":"") +"'public') AND " " views.acl=acl_data.aclid"); foreach(r, mapping row) retval+=({({row->viewid, row->name})}); return retval; } int get_event_acl(int view, object id) { array r=dbconn->query("SELECT * FROM " "views WHERE viewid=" + view); if(sizeof(r)>0) return (int)(r[0]->event_acl); return 0; } int is_acl_writeable(int acl, string owner, object id) { string|int auth= get_userid(id); array rules=({"'public'"}); if(stringp(auth)) { rules+=({"'"+ auth +"'", "'user'"}); if(auth==owner) rules+=({"'owner'"}); } array r=dbconn->query("SELECT acl_data.* FROM " "acl_data WHERE permit='w' AND " "entity in(" + (rules*", ") +" ) AND " " acl_data.aclid=" + acl); if(sizeof(r)>0) return 1; return 0; } array get_readable_views(object id) { array retval=({}); string|int auth= get_userid(id); array r=dbconn->query("SELECT views.viewid, views.name FROM " "views,acl_data WHERE permit='r' AND " "entity in(" + (stringp(auth)?"'"+auth+"','user',":"") +"'public') AND " " views.acl=acl_data.aclid"); foreach(r, mapping row) retval+=({({row->viewid, row->name})}); return retval; } int get_writeable(string view, object id) { string|int auth= get_userid(id); array r=dbconn->query("SELECT views.viewid, views.name FROM " "views,acl_data WHERE permit='w' AND " "entity in(" + (stringp(auth)?"'"+auth+"','user',":"") +"'public') AND " " views.acl=acl_data.aclid and views.viewid=" + view); if(sizeof(r)==0) return 0; else return 1; } string js_calendar(object cal, string name, object id) { object month; if(VARIABLES->jd) month=Calendar[SESSION->caltype]["Day"]((int)(VARIABLES->jd))->month(); else month=cal->month(); string out=""; out+="\n"; out+=""; out+="\n"; foreach(month->weeks()[0]->days(), object day) out+="\n"; out+="\n"; foreach(month->weeks(), object week){ out+=""; foreach(week->days(), object day) { if(day->month_name() != month->month_name()) // is the day in this month? out+="\n"; else // is the day any ordinary day in our month? out+="\n"; } out+="\n"; } out+=""; out+="
"; out+="not_query + "?showcal=" + name + "&jd=" + month->prev()->jd + "\"><< " + month->month_name() + " " + month->year_name() + " not_query + "?showcal=" + name + "&jd=" + month->next()->jd + "\">>>
\n"; out+="
" + day->week_day_shortname() + "
" + day->month_day_name() + "" + day->month_day_name() + "
\n"; return out; } string print_date(object x) { return x->week_day_shortname() + " " + x->month_name() + " " + x->month_day_name() + ", " + x->year_name(); } int|string parse_date(string date, object id) { if(catch(object x=Calendar.dwim_day(date))) return 0; else return x->week_day_shortname() + " " + x->month_name() + " " + x->month_day_name() + ", " + x->year_name(); } int|string parse_time(string time, object id) { if(catch(object x=Calendar.dwim_time(time))) return 0; else return format_time(x, id); } string get_date(string name, object cal, object id) { mixed x; if(VARIABLES[name] && VARIABLES[name]!="") { x=parse_date(VARIABLES[name], id); if(stringp(x) && !VARIABLES->clear_values) SESSION->event_data[name]=x; } else if(!SESSION->event_data[name] && (!VARIABLES[name] || VARIABLES[name]=="")) { x=parse_date("today", id); if(stringp(x) && !VARIABLES->clear_values) SESSION->event_data[name]=x; } string retval=""; retval+="
event_data[name]||"") + "\" size=20>"; if(VARIABLES->showcal && VARIABLES->showcal==name) retval+=js_calendar(cal, name, id); else retval+="not_query + "?showcal=" + name + "\">calendar"; retval+="
\n"; return retval; } string get_time(string name, object cal, object id) { mixed x; if(VARIABLES[name] && VARIABLES[name]!="") { x=parse_time(VARIABLES[name], id); if(stringp(x) && !VARIABLES->clear_values) SESSION->event_data[name]=x; } else if(!SESSION->event_data[name] && (!VARIABLES[name] || VARIABLES[name]=="")) { object c=Calendar[SESSION->caltype]->Hour()->next(); x=format_time(c, id); if(stringp(x) && !VARIABLES->clear_values) SESSION->event_data[name]=x; } string retval=""; retval+="
event_data[name]||"") + "\" size=10>"; retval+="
\n"; return retval; } array get_event(int eventid, object today, object id) { array retval=({}); array r=({}); r=dbconn->query("SELECT " "events.*, event_occurrences.*, views.name as view_name " "FROM events,event_occurrences,views WHERE " "events.eventid=" + eventid + " AND " "event_occurrences.eventid=events.eventid AND views.viewid=events.view"); if(sizeof(r)==1) return r; } array get_all_events(object today, object id) { array retval=({}); array r=({}); r=dbconn->query("SELECT events.subject, events.owner, events.description, " "events.acl, events.eventid " "FROM events,event_occurrences WHERE startdate<='" + today->format_ymd() + "' AND (events.view=" + SESSION->event_view + ") AND enddate >='" + today->format_ymd() + "' AND event_occurrences.eventid=events.eventid ORDER BY STARTTIME, SUBJECT ASC"); if(sizeof(r)>0) return r; } array get_all_day_events(object today, object id) { array retval=({}); array r=({}); r=dbconn->query("SELECT events.subject, events.owner, events.description, " "events.acl, events.eventid " "FROM events,event_occurrences WHERE startdate<='" + today->format_ymd() + "' AND (events.view=" + SESSION->event_view + ") AND enddate >='" + today->format_ymd() + "' AND event_occurrences.eventid=events.eventid AND starttime is NULL" " ORDER BY events.subject ASC"); if(sizeof(r)>0) return r; } array get_part_day_events(object today, object id) { array retval=({}); array r=({}); string query="SELECT events.subject, events.owner, events.description, " "event_occurrences.starttime, event_occurrences.endtime, " "events.acl, events.eventid FROM events,event_occurrences WHERE startdate<='" + today->format_ymd() + "' AND (events.view=" + SESSION->event_view + ") AND enddate >='" + today->format_ymd() + "' AND event_occurrences.eventid=events.eventid AND starttime is NOT NULL ORDER BY starttime, endtime, subject ASC"; r=dbconn->query(query); if(sizeof(r)>0) return r; } array is_today_an_event(object today, object id) { array retval=({}); if(!daystoevents[today->year_no()]) // we need to load the events. load_event_cache(today); if(daystoevents[today->year_no()][today]) // we have at least one event. foreach(daystoevents[today->year_no()][today], object event) retval+=({ event->name }); return retval; } void load_event_cache(object today) { if(!daystoevents[today->year_no()]) daystoevents[today->year_no()]=([]); foreach(indices(events), string ename) { // does this event happen this year? foreach(events[ename]->scan(today->year()), object day) if(daystoevents[today->year_no()][day]) daystoevents[today->year_no()][day] +=({events[ename]}); else daystoevents[today->year_no()][day]=({events[ename]}); } } string get_date_from_jd(int jd) { return Calendar.Day(jd)->format_ymd(); } int get_jd(string date) { return Calendar.dwim_day(date)->jd; } int get_unixtime(string time) { return Calendar.dwim_time(time)->unix_time(); } string get_todtime(string time) { return Calendar.dwim_time(time)->format_tod(); } int get_tod(string date) { return Calendar.dwim_day(date)->jd; } int do_delete_event(int eventid, object id) { if(!eventid) return 0; if(catch(dbconn->query("DELETE FROM events WHERE eventid=" + eventid))) return 0; if(catch(dbconn->query("DELETE FROM event_occurrences WHERE eventid=" + eventid))) return 0; return 1; } int do_add_event(object id) { // verify the dates are valid if(!(parse_date(SESSION->event_data->startdate, id) && parse_date(SESSION->event_data->enddate, id))) { id->misc->add_event_error="You must provide valid start and end dates for the event."; return 0; } // are the dates in the correct order? else if((get_jd(SESSION->event_data->enddate) - get_jd(SESSION->event_data->startdate))<0) { id->misc->add_event_error="Your start date must be before the end date."; return 0; } // do we have an event subject? else if(SESSION->event_data->subject=="") { id->misc->add_event_error="You must provide an event subject."; return 0; } // do we have permission to write? else if(!get_writeable(SESSION->event_data->view, id)) { id->misc->add_event_error="You do not have permission to add this event to your chosen " "calendar view."; return 0; } else // we have satisified all of the requirements! { mapping event=([]); event->owner=get_userid(id); event->acl=get_event_acl(SESSION->event_data->view, id); event->view=SESSION->event_data->view; event->subject=SESSION->event_data->subject; event->description=SESSION->event_data->description; event->occurrences=({}); event->occurrences+=({ (["startdate": get_jd(SESSION->event_data->startdate), "enddate": get_jd(SESSION->event_data->enddate) ]) }); if(add_event_to_calendar(event, id)) return 1; else { return 0; } } } int do_add_appointment(object id) { // verify the dates are valid if(!parse_date(SESSION->event_data->startdate, id)) { id->misc->add_event_error="You must provide a valid date for the event."; return 0; } // are the times in the correct order? else if((get_unixtime(SESSION->event_data->endtime) - get_unixtime(SESSION->event_data->starttime))<1) { id->misc->add_event_error="Your start time must be before the end time."; return 0; } // do we have an event subject? else if(SESSION->event_data->subject=="") { id->misc->add_event_error="You must provide an appointment subject."; return 0; } // do we have permission to write? else if(!get_writeable(SESSION->event_data->view, id)) { id->misc->add_event_error="You do not have permission to add this appointment to your chosen " "calendar view."; return 0; } else // we have satisified all of the requirements! { mapping event=([]); event->owner=get_userid(id); event->acl=get_event_acl(SESSION->event_data->view, id); event->view=SESSION->event_data->view; event->subject=SESSION->event_data->subject; event->description=SESSION->event_data->description; event->occurrences=({}); event->occurrences+=({ (["startdate": get_jd(SESSION->event_data->startdate), "enddate": get_jd(SESSION->event_data->startdate) , "starttime": get_todtime(SESSION->event_data->starttime), "endtime": get_todtime(SESSION->event_data->endtime) ]) }); if(add_event_to_calendar(event, id)) return 1; else { return 0; } } } string display_admin(object cal, object today, object id) { string out=""; out+="Administration
\n"; out+="

\n"; return out; } string display_delete_event(object cal, object today, object id) { string out=""; out+="Delete Event

\n"; array event=get_event(VARIABLES->delete_event, today, id); if(!event || sizeof(event)==0) { out+="

Unable to find the requested event.

"; out+="not_query + "\">Close and return"; return out; } out+="Event ID: " + VARIABLES->delete_event + "
\n"; out+="Subject: " + event[0]->subject + "
\n"; if(is_acl_writeable(event[0]->acl, event[0]->owner, id)) { if(VARIABLES->really) { if(do_delete_event(VARIABLES->delete_event, id)) { out+="

Event deleted successfully.

\n"; out+="not_query + "\">Close and return"; } else { out+="

An error occurred while deleting this event.
"; out+="The event was not deleted.

\n"; out+="not_query + "\">Close and return"; } } else { out+="

Do you really want to delete this event?

\n"; out+="not_query + "?delete_event=" + VARIABLES->delete_event + "&really=1\">Really Delete Event | "; out+="not_query + "\">Close and return"; } } else { out+="

You do not have permission to delete this event.

"; out+="not_query + "\">Close and return"; } return out; } string display_event_properties(object cal, object today, object id) { string out=""; array event=get_event(VARIABLES->view_props, today, id); if(!event || sizeof(event)==0) return "Unable to find the requested event." "

not_query + "\">Continue"; string type; if(event[0]->starttime && event[0]->starttime!="") { type="appointment"; out+="Appointment Properties

\n"; } else { type="event"; out+="Event Properties

\n"; } out+="Event ID: " + VARIABLES->view_props + "
\n"; out+="Subject: " + event[0]->subject + "
\n"; out+="Created by: " + (event[0]->owner=="0"?"anonymous": id->conf->auth_module->user_info(event[0]->owner)->name) + "
\n"; out+="Created: " + event[0]->create_stamp + "
\n"; out+="Modified: " + event[0]->modify_stamp + "

\n"; out+="Calendar View: " + event[0]->view_name + "

\n"; if(type=="appointment") { out+="Scheduled: " + parse_date(event[0]->startdate, id) + " from " + parse_time(event[0]->starttime, id) + " to " + parse_time(event[0]->endtime, id) + "
\n"; } else if(type=="event") { out+="Scheduled: " + parse_date(event[0]->startdate, id) + " to " + parse_date(event[0]->enddate, id) + "

\n"; } out+="Description:

" + event[0]->description + "

\n"; out+="

\n"; out+="not_query + "\">Close and return "; if(is_acl_writeable(event[0]->acl, event[0]->owner, id)) { out+="| Edit event | "; out+="not_query + "?delete_event=" + event[0]->eventid + "\">Delete event"; } return out; } string display_add_event(object cal, object today, object id) { string out=""; out+="Add Event
"; out+="

\n"; if(!SESSION->event_data) SESSION->event_data=([]); if(VARIABLES->clear_values) { SESSION->event_data=([]); } if(VARIABLES->update_values || VARIABLES->add_event) { SESSION->event_data->subject=VARIABLES->subject; SESSION->event_data->view=VARIABLES->view; SESSION->event_data->description=VARIABLES->description; get_date("startdate", cal, id); get_date("enddate", cal, id); } if(VARIABLES->add_event) { if(do_add_event(id)) { out+="Event added successfully."; out+="
" "not_query + "?mode=browse\">continue   |   " "not_query + "?mode=add_event\">add another event"; SESSION->event_data=([]); } else { out+="Your event couldn't be added because of the following reason: " "

" + id->misc->add_event_error + "

" + "not_query + "\">" "click here to correct the problem and try again."; } } else { out+="

not_query + "\" method=post>\n" "\n"; out+="\n"; out+="\n"; out+=""; out+=""; out+="\n"; out+="
Save Event in " "\n"; out+="
Start Date " + get_date("startdate", cal, id) + "
End Date " + get_date("enddate", cal, id) + "
Subject event_data->subject||"") + "\">
Description
\n"; } return out; } string display_add_appointment(object cal, object today, object id) { string out=""; out+="Add Appointment
"; out+="

\n"; if(!SESSION->event_data) SESSION->event_data=([]); if(VARIABLES->clear_values) { SESSION->event_data=([]); } if(VARIABLES->update_values || VARIABLES->add_event) { SESSION->event_data->subject=VARIABLES->subject; SESSION->event_data->view=VARIABLES->view; SESSION->event_data->description=VARIABLES->description; SESSION->event_data->type="appointment"; get_date("startdate", cal, id); get_time("starttime", cal, id); get_time("endtime", cal, id); // get_date("enddate", cal, id); } if(VARIABLES->add_event) { if(do_add_appointment(id)) { out+="Appointment added successfully."; out+="
" "not_query + "?mode=browse\">continue   |   " "not_query + "?mode=add_appointment\">add another appointment"; SESSION->event_data=([]); } else { out+="Your appointment couldn't be added because of the following reason: " "

" + id->misc->add_event_error + "

" + "not_query + "\">" "click here to correct the problem and try again."; } } else { out+="

not_query + "\" method=post>\n" "\n"; out+="\n"; out+="\n"; out+="\n"; /* out+="\n"; */ out+=""; out+=""; out+="\n"; out+="
Save Appointment in " "\n"; out+="
Date " + get_date("startdate", cal, id) + "
Start Time " + get_time("starttime", cal, id) + "
End Time " + get_time("endtime", cal, id) + "
End Date " + get_date("enddate", cal, id) + "
Subject event_data->subject||"") + "\">
Description
\n"; } return out; } string display_preferences(object cal, object today, object id) { string out=""; out+="Preferences
"; return out; } string display_year(object cal, object today, object id) { string out=""; out+="" + cal->year_name() + "
\n"; int num_months=sizeof(cal->year()->months()); int month_number=1; out+="\n"; foreach(cal->year()->months(), object month){ if(month_number%2==1) out+="\n"; else out+="\n"; month_number++; } out+="
\n"; else out+="\n"; out+="not_query + "?view_as=month&move_to=JD" + month->jd + "\">

" + month->month_name() + "

\n"; out+=""; out+=""; foreach(month->weeks()[0]->days(), object day) out+="\n"; foreach(month->weeks(), object week){ out+=""; foreach(week->days(), object day) { if(day->month_name() != month->month_name()) // is the day in this month? out+="\n"; else if(day==today->day()) // is the day today? out+="\n"; else // is the day any ordinary day in our month? out+="\n"; } out+=""; } out+="
" + day->week_day_shortname() + "
" + day->month_day_name() + "" + day->month_day_name() + "" + day->month_day_name() + "
\n"; if(month_number%2==1) out+="

 
\n"; return out; } string display_month(object cal, object today, object id) { string out=""; out+="" + cal->month_name() + " " + cal->year_name() + "
\n"; int num_months=sizeof(cal->year()->months()); int month_number=1; out+="\n"; object month=cal->month(); { if(month_number%2==1) out+="\n"; else out+="\n"; month_number++; } out+="
\n"; else out+="\n"; out+=""; out+=""; foreach(month->weeks()[0]->days(), object day) out+="\n"; foreach(month->weeks(), object week){ out+=""; foreach(week->days(), object day) { if(day->month_name() != month->month_name()) // is the day in this month? { out+="\n"; continue; } else if(day==today->day()) // is the day today? out+=""; } out+="
" + day->week_day_shortname() + "
" + day->month_day_name() + "" "not_query + "?view_as=day&move_to=JD" + day->jd + "\">" + day->month_day_name() + "\n"; // is the day any ordinary day in our month? else if(!query("dayhilighting")) out+="not_query + "?view_as=day&move_to=JD" + day->jd + "\">" + day->month_day_name() + "\n"; else if(whichdayhilight(day)) out+="not_query + "?view_as=day&move_to=JD" + day->jd + "\">" + day->month_day_name() + "\n"; else out+="not_query + "?view_as=day&move_to=JD" + day->jd + "\">" + day->month_day_name() + "\n"; string itae=(is_today_an_event(day, id)*"
\n"); if(itae!="") out+="
" + itae + "\n"; array alldayevents=get_all_events(day, id); if(alldayevents) foreach(alldayevents, mapping ade) out+="
" + ade->subject + "\n"; } out+="
\n"; if(month_number%2==1) out+="
 
\n"; return out; } string display_week(object cal, object today, object id) { object w=cal->week(); string out=""; out+="Week " + (search(cal->month()->weeks(), w)+1)+ " of " + cal->month_name() + " " + cal->year_name() + "
\n"; int num_months=sizeof(cal->months()); int month_number=1; out+="\n"; foreach(w->days(), object day){ out+="" + (day==today->day()?"\n"; out+="\n"; } out+="
":"") + day->week_day_name() + "
" "" + day->month_day() + "" "not_query + "?view_as=day&move_to=JD" + day->jd + "\">view
"; string itae=(is_today_an_event(day, id)*"
\n"); if(itae!="") out+="
" + itae + "\n"; array alldayevents=get_all_day_events(day, id); out+="
\n"; if(alldayevents) foreach(alldayevents, mapping row) { out+="not_query + "?view_props=" + row->eventid + "\"> "; out+="" + js_tooltip(row->subject, " " + row->description + "
\\n Added by " + (row->owner=="0"?"anonymous": id->conf->auth_module->user_info(row->owner)->name)); out+="
\n"; } array partdayevents=get_part_day_events(day, id); if(partdayevents) foreach(partdayevents, mapping row) { // out+=sprintf("
%O
", row); out+="not_query + "?view_props=" + row->eventid + "\"> "; out+=""; out+=parse_time(row->starttime, id) + " - " + parse_time(row->endtime, id); out+=" " + js_tooltip(row->subject, " " + row->description + "
\\n Added by " + (row->owner=="0"?"anonymous": id->conf->auth_module->user_info(row->owner)->name)); out+="
\n"; } out+="
\n"; return out; } string js_tooltip(string text, string tip) { return "" + text + ""; } string display_day(object cal, object today, object id) { string out=""; out+="\n"; out+="\n"; array partdayevents=get_part_day_events(cal, id); foreach(cal->hours(), object hour) { out+="" + (hour==today->hour()?""; out+="\n"; } out+="
"; out+="" + cal->week_day_name() + " " + cal->month_name() + " " + cal->month_day_name() + ", " + cal->year_name() + "
\n"; out+="
"; string itae=(is_today_an_event(cal, id)*"
\n"); if(itae!="") out+="
" + itae + "\n"; array alldayevents=get_all_day_events(cal, id); out+="
"; if(alldayevents) foreach(alldayevents, mapping row) { out+="not_query + "?view_props=" + row->eventid + "\">"; out+="" + js_tooltip(row->subject, " " + row->description + "
\\n Added by " + (row->owner=="0"?"anonymous": id->conf->auth_module->user_info(row->owner)->name)) + "

\n"; } out+="
":"") + format_time(hour, id) + "   \n"; // is the first available event occurring in this hour? if(partdayevents && partdayevents[0] && Calendar.dwim_time(hour->format_ymd() + " " + partdayevents[0]->starttime)->hour()==hour) { do { out+="not_query + "?view_props=" + partdayevents[0]->eventid + "\"> "; out+=""; out+=parse_time(partdayevents[0]->starttime, id) + " - " + parse_time(partdayevents[0]->endtime, id); out+=" " + js_tooltip(partdayevents[0]->subject, " " + partdayevents[0]->description + "
\\n Added by " + (partdayevents[0]->owner=="0"?"anonymous": id->conf->auth_module->user_info(partdayevents[0]->owner)->name)); out+="
\n"; if(sizeof(partdayevents)<=1) break; partdayevents=partdayevents[1..]; } while (Calendar.dwim_time(hour->format_ymd() + " " + partdayevents[0]->starttime)->hour()==hour); } out+="
\n"; return out; } string format_time(object time, object id) { string retval; if(SESSION && SESSION->calprefs && SESSION->calprefs->format_time && SESSION->calprefs->format_time=="24h") return sprintf("%2d:%2d", time->hour_no(), time->minute_no()); int hour=time->hour_no(); string td; if(hour>=13) { hour=hour-12; td="PM"; } else if(hour==0) {hour=12; td="AM"; } // account for the midnight hour else if(hour==12) {hour=12; td="PM"; } // account for the noon hour else { td="AM"; } retval=hour + ":" + sprintf("%02d", time->minute()->minute_no()) + " " + td; return retval; } mapping query_container_callers() { return ([ "calendar":container_calendar, "calendar_events": container_events ]); } int add_event_to_calendar(mapping event, object id) { // adds a validated event to the event database. // assumes the input data is valid. // // event input mapping contains the following keys: // // owner: the username of the owner of the event // acl: the acl that controls access to the event // view: the calendar view to associate the event with // subject: short description of event // description: long description of event // occurrences: array of time/date combinations the event occurrs // data: xml/rxml data related to event // // each occurrence is a mapping containing the following keys: // // startdate: julianday number for start // enddate: julianday number for end // starttime (if not present, indicates an all day event, // format is that of format_tod()) // endtime (if not present, indicates an all day event) // format is that of format_tod()) // // returns event id number // int eventid; array x; // make sure we have exclusive access before we calculate our event id dbconn->query("LOCK TABLES events WRITE"); x=dbconn->query("SELECT MAX(eventid)+1 AS eventid FROM events"); eventid=(int)(x[0]->eventid); // event id zero is an undefined state, will cause "false errors", so we manually avoid it. if(eventid==0) eventid=1; if(catch(dbconn->query("INSERT INTO events (eventid, owner, acl, view, subject, " "description, data, create_stamp, modify_stamp) VALUES (" + eventid + ",'" + event->owner + "','" + event->acl + "','" + event->view + "','" + dbconn->quote(event->subject) + "'," + (event->description?("'"+dbconn->quote(event->description)+"'"):"NULL") + "," + (event->data?("'"+dbconn->quote(event->data)+"'"):"NULL") +",NOW(),NOW())"))) { id->misc->add_event_error="A database error has occurred: "+ dbconn->error(); dbconn->query("UNLOCK TABLES"); return 0; } // unlock the table so others may use it. dbconn->query("UNLOCK TABLES"); // now we add event occurrences (every event must have at least one.) foreach(event->occurrences, mapping occurrence) { int occurrenceid; // make sure we have exclusive access before we calculate our occurrence id dbconn->query("LOCK TABLES event_occurrences WRITE"); x=dbconn->query("SELECT MAX(occurrenceid)+1 AS occurrenceid FROM event_occurrences"); occurrenceid=x[0]->occurrenceid; if(catch(dbconn->query("INSERT INTO event_occurrences (eventid, occurrenceid, " "startdate, enddate, starttime, endtime) VALUES (" + eventid + "," + occurrenceid + ",'" + get_date_from_jd(occurrence->startdate) + "','" + get_date_from_jd(occurrence->enddate) + "'," + (occurrence->starttime?"'"+occurrence->starttime+"'":"NULL") + "," + (occurrence->endtime?"'"+occurrence->endtime+"'":"NULL") + ")"))) { id->misc->add_event_error="A database error has occurred: "+ dbconn->error(); dbconn->query("UNLOCK TABLES"); dbconn->query("DELETE FROM events WHERE eventid=" + eventid); return 0; } // we're done writing our event, so we can unlock the table. dbconn->query("UNLOCK TABLES"); } return eventid; } object hilightcal; int whichdayhilight(object day) { if(!hilightcal) hilightcal=Calendar.dwim_day("January 3, 2002"); return (((day->jd - hilightcal->jd)/4)%2); }