diff --git a/.gitignore b/.gitignore index 34a910a..627cc5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,21 @@ -# configuration file -/www/load.php +# configuration files +/admin/load.php +/api/load.php # GNU Gettext compiled .po files *.mo # Some proprietary IDE .idea/ # Generated by tagliatella.php each time it's run schedule.xml # https://www.vagrantup.com/ /.vagrant # Adminer (fuck you @lvps) /adminer.php # our unuseful framework - some people place it here /includes/suckless-php diff --git a/api/load-example.php b/api/load-example.php new file mode 100644 index 0000000..c749495 --- /dev/null +++ b/api/load-example.php @@ -0,0 +1,5 @@ +. -require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'load.php'; +// require configuration file +require 'load.php'; // In case something goes wrong... http_response_code( 500 ); $uid = isset( $_GET[ 'conference' ] ) ? $_GET[ 'conference' ] : CURRENT_CONFERENCE_UID; $conference_row = FullConference::factoryFromUID( $uid ) ->queryRow(); if( ! $conference_row ) { throw new LogicException( sprintf( "Conference with uid '%s' does not exists!", esc_html( $uid ) ) ); } $xml = new DOMDocument( '1.0', 'UTF-8' ); $schedule = $xml->createElement( 'schedule' ); $schedule = $xml->appendChild( $schedule ); $conference = $xml->createElement( 'conference' ); $conference = $schedule->appendChild( $conference ); $conference_fields = [ 'title' => $conference_row->getConferenceTitle(), 'subtitle' => $conference_row->getConferenceSubtitle(), 'acronym' => $conference_row->get( Conference::ACRONYM ), 'days' => $conference_row->get( Conference::DAYS ), 'persons_url' => $conference_row->get( Conference::PERSONS_URL ), 'events_url' => $conference_row->get( Conference::EVENTS_URL ), ]; foreach( $conference_fields as $xml_field => $db_field ) { add_child( $xml, $conference, $xml_field, $db_field ); } add_child( $xml, $conference, 'start', $conference_row->getConferenceStart( 'Y-m-d H:i:s' ) ); add_child( $xml, $conference, 'end', $conference_row->getConferenceEnd( 'Y-m-d H:i:s' ) ); add_child( $xml, $conference, 'city', $conference_row->getLocationAddress() ); add_child( $xml, $conference, 'venue', $conference_row->getLocationNoteHTML() ); // Yes, these are hardcoded. asd add_child( $xml, $conference, 'day_change', '09:00:00' ); add_child( $xml, $conference, 'timeslot_duration', '00:30:00' ); $events = FullEvent::factoryByConference( $conference_row->getConferenceID() ) ->orderBy( Event::START ) ->orderBy( Room::ID_ ) ->queryGenerator(); // Room names indexed by room_ID $room_names = []; $events_by_date_then_room = []; foreach( $events as $event ) { $day = $event->getEventStart( 'Y-m-d' ); // Add various levels to the array, if they don't already exists if( ! isset( $events_by_date_then_room[ $day ] ) ) { $events_by_date_then_room[ $day ] = []; } $room = $event->getRoomID(); if( ! isset( $events_by_date_then_room[ $day ][ $room ] ) ) { $events_by_date_then_room[ $day ][ $room ] = []; } $room_names[ $room ] = $event->getRoomName(); // And finally, add the event itself $events_by_date_then_room[ $day ][$room ][] = $event; } // These are database event fields whose content can be taken straight from the database. // Others need a little more work to convert to the correct format. $keys = [ 'subtitle' => Event::SUBTITLE, 'language' => Event::LANGUAGE, ]; $day_index = 1; $events_by_id = []; foreach( $events_by_date_then_room as $day_date => $rooms ) { $dayxml = add_child( $xml, $schedule, 'day', NULL ); $dayxml->setAttribute( 'index', $day_index ); $dayxml->setAttribute( 'date', $day_date ); foreach( $rooms as $room_ID => $events ) { $roomxml = add_child( $xml, $dayxml, 'room', NULL ); // 9 agosto 2016 22:30 Ludovico says that this does not exist. OK. // 9 agosto 2016 22:31 Ludovico says that this exists. OK. $roomxml->setAttribute( 'name', $room_names[ $room_ID ] ); foreach( $events as $event ) { $event_ID = $event->getEventID(); $eventxml = add_child( $xml, $roomxml, 'event', NULL ); $eventxml->setAttribute( 'id', $event_ID ); $events_by_id[ $event_ID ] = $eventxml; // this stops PHPStorm from complaining, but most of these elements are really just strings... /** @var $event DateTime[] */ // Same exact format, two different parameters since 'start' is a DateTime and 'duration' a DateInterval. Why, PHP, WHY? add_child( $xml, $eventxml, 'title', $event->getEventTitle() ); add_child( $xml, $eventxml, 'slug', $event->getEventUID() ); add_child( $xml, $eventxml, 'start', $event->getEventStart( 'H:i' ) ); add_child( $xml, $eventxml, 'duration', $event->getEventDuration( '%H:%I' ) ); add_child( $xml, $eventxml, 'room', $event->getRoomName() ); add_child( $xml, $eventxml, 'track', $event->getTrackName() ); add_child( $xml, $eventxml, 'type', $event->getChapterName() ); $description = null; if( $event->hasEventDescription() ) { $description = $event->getEventDescriptionHTML(); } add_child( $xml, $eventxml, 'description', $description ); $abstract = null; if( $event->hasEventAbstract() ) { $abstract = $event->getEventAbstractHTML(); } add_child( $xml, $eventxml, 'abstract', $abstract ); // Add event fields that don't need any further processing foreach( $keys as $xml_key => $db_key ) { add_child( $xml, $eventxml, $xml_key, $event->get( $db_key ) ); } } } $day_index++; } $people = EventUser::factory() ->select( [ Event::ID_, User::ID_, User::UID, User::NAME, User::SURNAME ] ) ->from( [ Event::T, User::T, ] ) ->whereInt( Conference::ID , $conference_row->getConferenceID() ) ->equals( EventUser::EVENT_, Event::ID_ ) ->equals( EventUser::USER_, User ::ID_ ) ->orderBy( Event::ID ) ->queryGenerator(); $lastid = NULL; $lastpersons = NULL; foreach( $people as $row ) { // This works only because rows are sorted by events $event_ID = $row->getEventID(); if( $lastid !== $event_ID ) { $event = $event_ID; $lastid = $event; $personsxml = $xml->createElement( 'persons' ); $personsxml = $events_by_id[ $event ]->appendChild( $personsxml ); $lastpersons = $personsxml; } $personxml = add_child( $xml, $lastpersons, 'person', $row->getUserFullname() ); $personxml->setAttribute( 'id', $row->getUserID() ); $personxml->setAttribute( 'slug', $row->getUserUID() ); } http_response_code( 200 ); header( 'Content-type: text/xml; charset=' . CHARSET ); echo $xml->saveXML(); // ---------------------------------------------------------------------------- /** * Add child to an element and return it * * @param $xml DOMDocument * @param $parent DOMNode * @param $tagname string * @param $content string * @return DOMElement */ function add_child( & $xml, $parent, $tagname, $content ) { $child = $xml->createElement( $tagname ); if( null !== $content && '' !== $content ) { $child->nodeValue = $content; } return $parent->appendChild( $child ); } diff --git a/admin/api/tropical.php b/api/tropical.php similarity index 98% rename from admin/api/tropical.php rename to api/tropical.php index 384fb8b..5e06928 100644 --- a/admin/api/tropical.php +++ b/api/tropical.php @@ -1,194 +1,194 @@ . /* * This is the Linux Day Torino Tropical (trop-iCal) API * * It print a (hopefully) valid iCal file of a Linux Day Torino event. */ -// load the framework -require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'load.php'; +// require configuration file +require 'load.php'; // die if missing Conference UIR if( empty( $_GET['conference'] ) ) { http_response_code( 404 ); die( "Missing 'conference' argument" ); } $event = null; $conference = FullConference::factoryFromUID( $_GET['conference'] ) ->queryRow(); // die if missing Conference if( !$conference ) { http_response_code( 404 ); die( "Conference not found" ); } // die if missing Event UID if( isset( $_GET['event'] ) ) { $event = FullEvent::factoryFromConferenceAndEventUID( $conference, $_GET['event'] ) ->queryRow(); if( !$event ) { http_response_code( 404 ); die( "Event not found" ); } } $event_url = null; if( $event ) { $event_ID = $event->getEventID(); $event_title = $event->getEventTitle(); $event_start = $event->getEventStart(); $event_end = $event->getEventEnd(); $event_desc = $event->getEventDescription(); if( $event->hasEventPermalink() ) { $event_url = $event->getEventURL( true ); } } else { $event_ID = $conference->getConferenceID(); $event_title = $conference->getConferenceTitle(); $event_url = $conference->getConferenceURL(); $event_start = $conference->getConferenceStart(); $event_end = $conference->getConferenceEnd(); $event_desc = $conference->getConferenceDescription(); } $event_uid = $conference->getConferenceUID(); if( $event ) { $event_uid .= '-' . $event->getEventUID(); } if( $event ) { $event_stable_guid = $conference->getConferenceUID() . '-' . $event_ID . '@linuxdaytorino.org'; } else { $event_stable_guid = $conference->getConferenceUID() . '@linuxdaytorino.org'; } $event_location = null; // TODO: get this one (e.g. "Room A" or "Via Fasulla 123, Springfield") $event_geo_lat = null; $event_geo_lng = null; if( $conference->locationHasGeo() ) { $event_geo_lat = $conference->getLocationGeoLat(); $event_geo_lng = $conference->getLocationGeoLng(); } if( empty( $_GET['debug'] ) ) { header( 'Content-Type: text/calendar' ); header( sprintf( 'Content-Disposition: attachment; filename=%s.ics', $event_uid ) ); } else { header( 'Content-Type: text/plain' ); } echo get_ical( $event_stable_guid, $event_title, $event_start, $event_end, $event_url, $event_desc, $event_location, $event_geo_lat, $event_geo_lng ); function timestamp_to_ical( $timestamp ) { return date( 'Ymd\THis\Z', $timestamp ); } /** * Get an event (or conference as a single event) in iCal format. * * @param string $id Unique ID for this event * @param string $title Event title * @param int $start Start time (UNIX timestamp) * @param int $end End time (UNIX timestamp) * @param string $url Event URL * @param string $description Longer description of the event * @param string $location Name of event location, e.g. "Room A" * @param float $geo_lat Latitude of the location * @param float $geo_lon Longitude of the location * * @return string the event in iCal format */ function get_ical( $id, $title, $start, $end, $url = null, $description = null, $location = null, $geo_lat = null, $geo_lng = null ) { $dtstart = timestamp_to_ical( $start->getTimestamp() ); $dtend = timestamp_to_ical( $end->getTimestamp() ); $dtstamp = timestamp_to_ical( time() ); $id = htmlspecialchars( $id ); $title = htmlspecialchars( $title ); if( !$description ) { $opt_description = ''; } else { $description = str_replace( "\n", " ", $description ); $description = strip_tags( $description ); $description = htmlspecialchars( $description ); $opt_description = "DESCRIPTION:$description"; } if( !$url ) { $opt_url = ''; } else { $opt_url = 'URL;VALUE=URI:' . htmlspecialchars( $url ); } if( !$geo_lat || !$geo_lng ) { $opt_geo = ''; } else { $opt_geo = "GEO:$geo_lat;$geo_lng"; } if( !$location ) { $opt_location = ''; } else { $location = htmlspecialchars( $location ); $opt_location = "LOCATION:$location"; } $ics = []; $ics[] = 'BEGIN:VCALENDAR'; $ics[] = 'VERSION:2.0'; $ics[] = 'PRODID:-//ldto/asd//NONSGML v1.0//EN'; $ics[] = 'CALSCALE:GREGORIAN'; $ics[] = 'BEGIN:VEVENT'; $ics[] = "UID:$id"; $ics[] = "SUMMARY:$title"; if( $opt_description ) { $ics[] = $opt_description; } if( $opt_url ) { $ics[] = $opt_url; } if( $opt_location ) { $ics[] = $opt_location; } if( $opt_geo ) { $ics[] = $opt_geo; } $ics[] = "DTSTART:$dtstart"; $ics[] = "DTEND:$dtend"; $ics[] = "DTSTAMP:$dtstamp"; $ics[] = 'END:VEVENT'; $ics[] = 'END:VCALENDAR'; return implode( "\r\n", $ics ); }