Creando su startup: Exportando archivos iCal a eventos de calendario
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)



Introducción
Este tutorial forma parte de la serie Creando su startup con PHP en Envato Tuts +. En esta serie, te estoy guiando a través del lanzamiento de un inicio de concepto a realidad utilizando mi aplicación de Meeting Planner como un ejemplo de la vida real. Cada paso a lo largo del camino, voy a lanzar el código de Meeting Planner como ejemplos de código abierto que puede aprender. También me ocuparé de asuntos relacionados con el inicio de negocios a medida que surjan.
También me complace anunciar que Meeting Planner está listo para probar. Puede enviar invitaciones a reuniones, recopilar comentarios de su participante y finalizar la reunión, importando el archivo iCal que describiré hoy en sus calendarios. Por lo tanto, visite MeetingPlanner.io y dele una oportunidad.
¿Qué cubre este episodio?



En el último tutorial, describí cómo construí enlaces de comandos y operaciones codificadas para los participantes que comienzan a responder a invitaciones por correo electrónico, es decir, viendo la página de la reunión o aceptando o rechazando un lugar o una hora.
También mencioné cómo una mujer que había estado saliendo sugirió que ella no sabía si o cuándo me vería otra vez sin una invitación del Meeting Planner, que proporcioné pronto. Y luego dijo que no sabría cuándo ni dónde aparecer sin una entrada de calendario de Google. En el tutorial de hoy, describiré cómo construí la característica iCal para entregar un archivo .ics que podría importar para una cita exitosa. Siempre es útil tener a alguien motivando el desarrollo, pero usualmente son colegas o un gerente de desarrollo.
Apenas un recordatorio, todo el código para el planificador de la reunión se escribe en el marco de Yii2 para PHP. Si desea obtener más información sobre Yii2, consulte nuestra serie paralela Programación con Yii2 en Envato Tuts +.
Participo en los hilos de los comentario de abajo y estoy especialmente interesado si tiene ideas adicionales o desea sugerir temas para futuros tutoriales. También puede contactarme en Twitter @reifman.
¿Qué es un archivo iCal?
Definiendo iCalendar, Wikipedia dice:
ICalendar es un formato de archivo informático que permite a los usuarios de Internet enviar solicitudes de reunión y tareas a otros usuarios de Internet, por correo electrónico o compartir archivos con una extensión de .ics.
Básicamente, es un archivo con la extensión .ics que incluye información pertinente sobre una reunión, el organizador y los asistentes, la fecha, hora y duración, la ubicación y más, todo en un formato que una variedad de plataformas y servicios de calendario pueden reconocer.
Aunque iCalendar tiene funciones avanzadas, en esta etapa del MVP (MVP) de Meeting Planner , quería asegurar que nuestras reuniones programadas se podían importar fácilmente a Google Calendar, Apple Calendar y Microsoft Outlook y ser reconocidas por los servicios de correo web. Trabajaré más adelante para ampliar su funcionalidad.
A través de tutoriales anteriores, había creado la funcionalidad que recogía toda la información necesaria, como participantes, fechas y horas y ubicaciones. Ahora, sólo necesitaba publicar los detalles del evento en un archivo adjunto y entregarlo por correo electrónico.
Creación del archivo .ics
En lugar de escribir código de .ics desde cero, comencé con el Generador de Archivos ics de Ahmad Amin y lo personalizé. Coloqué el código en /common/models/Calendar.php.
Los archivos iCal dependen de quién es el usuario. En otras palabras, deben ser personalizados para la entrega. Principalmente, los vínculos de regreso a Meeting Planner deben ser personalizados para la autenticación para el titular de ese archivo .ics en particular.
Durante el proceso de finalización de la reunión, creamos un archivo de eventos para cada participante con enlaces únicos y autenticados:
1 |
foreach ($attendees as $cnt=>$a) {
|
2 |
... |
3 |
$icsPath = Meeting::buildCalendar($this->id,$chosenPlace,$chosenTime,$attendees); |
Dentro del modelo Meeting, el método buildCalendar reúne todos los datos que el generador necesitará para cada usuario:
1 |
public static function buildCalendar($id,$chosenPlace,$chosenTime,$attendees) {
|
2 |
$meeting = Meeting::findOne($id); |
3 |
$invite = new \common\models\Calendar(); |
4 |
$start_time = $chosenTime->start+(3600*7); // temp timezone adjust |
5 |
$end_time = $start_time+3600; // to do - allow length on meetings for end time calculation |
6 |
$sdate = new \DateTime(date("Y-m-d h:i:sA",$start_time), new \DateTimeZone('PST'));
|
7 |
$edate = new \DateTime(date("Y-m-d h:i:sA",$end_time), new \DateTimeZone('PST'));
|
8 |
$description = $meeting->message; |
9 |
// check if its a conference with no location |
10 |
if ($chosenPlace!==false) {
|
11 |
if ($chosenPlace->place->website<>'') {
|
12 |
$description.=' Website: '.$chosenPlace->place->website; |
13 |
} |
14 |
$location = str_ireplace(',',' ',$chosenPlace->place->name.' '.str_ireplace(', United States','',$chosenPlace->place->full_address));
|
15 |
} else {
|
16 |
$location =''; |
17 |
} |
18 |
$invite |
19 |
->setSubject($meeting->subject) |
20 |
->setDescription($description) |
21 |
->setStart($sdate) |
22 |
->setEnd($edate) |
23 |
->setLocation($location) |
24 |
->setOrganizer($meeting->owner->email, $meeting->owner->username); |
25 |
foreach ($attendees as $a) {
|
26 |
$invite |
27 |
->addAttendee($a['email'], $a['username']) |
28 |
->setUrl(\common\components\MiscHelpers::buildCommand($id,Meeting::COMMAND_VIEW,0,$a['user_id'],$a['auth_key'])); |
29 |
} |
30 |
$invite->generate() // generate the invite |
31 |
->save(); // save it to a file; |
32 |
$downloadLink = $invite->getSavedPath(); |
33 |
return $downloadLink; |
34 |
} |
Si hay una ubicación (para reuniones en persona), incluyo un enlace al sitio web del lugar (si está disponible) y una dirección para los mapas incrustados. He decidido codificar fechas y horas en formato UTC para simplificar.
Se establece la información común de la reunión y, a continuación, se agregan el organizador y los asistentes.
A continuación se muestra un ejemplo de archivo cuando se completa:
1 |
BEGIN:VCALENDAR |
2 |
VERSION:2.0 |
3 |
CALSCALE:GREGORIAN |
4 |
METHOD:PUBLISH |
5 |
BEGIN:VEVENT |
6 |
UID:9832@meetingplanner.io |
7 |
DTSTART:20160506T013000Z |
8 |
DTEND:20160506T023000Z |
9 |
DTSTAMP:20160506T013000Z |
10 |
ORGANIZER;CN=admin:mailto:jeff@lookahead.io |
11 |
URL;VALUE=URI:http://localhost:8888/mp/index.php/meeting/command?id=45&cmd=10&actor_id=1&k=ESxJU_2ZRhZIgzHFyJAIiC39RhZuLiM_&obj_id=0 |
12 |
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=robsmith;X-NUM-GUESTS=0:mailto:robsmith@lookahead.me |
13 |
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=admin;X-NUM-GUESTS=0:mailto:jeff@lookahead.io |
14 |
CREATED: |
15 |
DESCRIPTION:It was fun running into you - let's definitely grab that beer! Website: http://www.patxispizza.com/ |
16 |
LAST-MODIFIED:20160506T013000Z |
17 |
LOCATION:Patxi's Pizza Ballard 5323 Ballard Ave NW Seattle WA 98107 |
18 |
SUMMARY:Meetup for Pizza and Long Delayed Conversation |
19 |
SEQUENCE:0 |
20 |
TRANSP:OPAQUE |
21 |
END:VEVENT |
22 |
END:VCALENDAR |
Entrega del archivo .ics como archivo adjunto
En este tutorial anterior, describí el uso de la compatibilidad de correo incorporada de Yii2 con la extensión SwiftMailer para entregar invitaciones a reuniones. Para la entrega de transporte, utilicé la integración del servicio SMTP de Mailgun.
Ciertamente, en el pasado, integrar adjuntos en mensajes era complicado, pero ahora es bastante fácil con Yii. Aquí está el código para agregar el archivo a la invitación de la reunión saliente:
1 |
// send the message
|
2 |
$message = Yii::$app->mailer->compose([ |
3 |
'html' => 'finalize-html', |
4 |
'text' => 'finalize-text' |
5 |
],
|
6 |
[
|
7 |
'meeting_id' => $this->id, |
8 |
'noPlaces' => $noPlaces, |
9 |
'participant_id' => 0, |
10 |
'owner' => $this->owner->username, |
11 |
'user_id' => $a['user_id'], |
12 |
'auth_key' => $a['auth_key'], |
13 |
'intro' => $this->message, |
14 |
'links' => $links, |
15 |
'header' => $header, |
16 |
'chosenPlace' => $chosenPlace, |
17 |
'chosenTime' => $chosenTime, |
18 |
'notes' => $notes, |
19 |
'meetingSettings' => $this->meetingSettings, |
20 |
]);
|
21 |
$icsPath = Meeting::buildCalendar($this->id,$chosenPlace,$chosenTime,$attendees); |
22 |
$message->setFrom(array('support@meetingplanner.com'=>$this->owner->email)); |
23 |
$message->attachContent(file_get_contents($icsPath), ['fileName' => 'meeting.ics', 'contentType' => 'text/plain']); |
24 |
$message->setTo($a['email']) |
25 |
->setSubject(Yii::t('frontend','Meeting Confirmed: ').$this->subject) |
26 |
->send(); |
Solo
necesitaba usar el $icsPath devuelto anteriormente y usar el método
attachContent para incluirlo con el correo electrónico de invitación.
Esto es como se veia cuando llega a Gmail:



Cuando abrí el archivo de invitación en Mac OS, Apple Calendar presentó este primer paso para seleccionar un calendario para agregar el evento a:



Asi es como se ve en la vista de día de mi calendario:



Una vez que el evento se añade, se verá así al hacer clic en él:



En general, la generación de eventos resultó ser una cantidad bastante modesta de trabajo y exitosa en sus implementaciones. Las personas alfa estaban impresionadas, y lo usamos para reuniones reales en persona.
Problemas durante el desarrollo
Mientras estaba aprendiendo sobre .ics y experimentando con él, mis cuentas de webmail en FastMail sólo intermitentemente reconoció mis archivos .ics como invitaciones de calendario. Necesitaba actualizar las propiedades que incluía para que se reconozca de una manera amistosa.
Una estructuración más correcta del contenido del archivo .ics permitió a FastMail reconocer el archivo adjunto automáticamente:



Desafortunadamente, el botón Agregar al calendario vincula a su propio calendario, que no utilizo. Una vez más, para agregar a Apple Calendar, como con Gmail, tuve que descargar y abrir el archivo .ics.
Mac OS parecía reconocer los archivos tan pronto como se abrieron. Me dirigiría hacia un par de pasos para crear un evento de Apple Calendar (mostrado arriba).
También necesitaba establecer una identificación única para los eventos para que pudiéramos enviar actualizaciones en el futuro. Por ahora, nuestro ID de reunión de base de datos con '@meetingplanner.io' es suficiente, ejemplo: Uid = 23522@meetingplanner.io.
Garantizar que las zonas horarias se entregaran adecuadamente en formato de archivo .ics requería un poco de investigación adicional. Para simplificar, me baso en el generador de ics de Amin para codificar fechas y horas en formato UTC. Tengo más trabajo en Meeting Planner para gestionar las zonas horarias de los usuarios.
También había dejado de lado la duración y el tiempo de finalización de Meeting Planner. Esto será algo que tengo que remendar pronto, es probable que acaba de añadir una duración (en horas) para la reunión promedio y permitir a las personas ampliarlo según sea necesario.
Problemas futuros
En última instancia, me gustaría Meeting Planner para utilizar una mayor amplitud de la funcionalidad de iCal. Inicialmente, sólo quería que la funcionalidad principal funcionara para el MVP. Aquí hay algunas ideas a continuación.
Es
posible que desee crear una configuración de usuario en Meeting Planner
que agregue alarmas a las entradas de calendario de las personas. En iCal, esto se denomina VALARM, por ejemplo:
1 |
BEGIN:VALARM |
2 |
TRIGGER:-PT1440M |
3 |
ACTION:DISPLAY |
4 |
DESCRIPTION:Reminder |
5 |
END:VALARM |
Cuando las personas actualicen el evento original, incluso después de finalizado, quiero actualizar el evento en su calendario. Esto requiere entregar un VEVENT con un UID idéntico pero con una SEQUENCE incremental (via TutorialsBag):
1 |
BEGIN:VCALENDAR |
2 |
VERSION:2.0 |
3 |
CALSCALE:GREGORIAN |
4 |
METHOD:REQUEST |
5 |
BEGIN:VEVENT |
6 |
UID:vicky@tutorialsbag.com |
7 |
DTSTART:20130617T050000Z |
8 |
DTEND:20130617T075900Z |
9 |
DTSTAMP:20130616T050000Z |
10 |
ORGANIZER;mailto:chvivek10@gmail.com |
11 |
DESCRIPTION:The is a test invite for you to see how this thing actually works |
12 |
LAST-MODIFIED:20130616T050000Z |
13 |
LOCATION:Queens, New York |
14 |
SUMMARY:Test Demo Invite |
15 |
SEQUENCE:1 |
16 |
TRANSP:OPAQUE |
17 |
END:VEVENT |
18 |
END:VCALENDAR |
Actualmente, no estoy rastreando un campo secuencial para actualizaciones.
También quiero apoyar los archivos de cancelación que eliminan el evento de los calendarios. Por lo tanto, si una persona cancela con Meeting Planner, enviamos un archivo iCal a los asistentes que elimina el evento de su calendario:
1 |
METHOD:CANCEL |
2 |
STATUS:CANCELLED |
Con el tiempo, me gustaría usar cache en archivos .ics para cada evento y participante para problemas de rendimiento y almacenamiento. Me gustaría proporcionar una gestión de archivos para reducir el espacio en disco necesario para almacenar estos, ya que sólo se necesitan por un corto período de tiempo y se puede regenerar fácilmente a petición.
También quiero asegurar que el directorio en el que están almacenados esté protegido de manera que no puedan ser comprometidos, ya que incluyen mucha información personal y privada, como direcciones de correo electrónico y exactamente donde puede encontrar personas específicas en un momento específico .
En el futuro, también me gustaría intentar integrar las funciones avanzadas menos utilizadas de iCal para conectarse directamente a Meeting Planner. Por ejemplo, podremos cancelar o reprogramar reuniones de su programa de calendario iCal utilizando las interfaces programáticas de Meeting Planner, en lugar de tener que volver al sitio web de Meeting Planner.
¿Que sigue?
Vea los próximos tutoriales en la sección la serie Creando su startup con PHP. En el próximo episodio, describiré cómo agregar soporte para el registro a través de Google, Facebook y Twitter, así como conectar las cuentas existentes a estas redes sociales con el propósito de acelerar la adopción y simplificar el uso.
Una vez más, Meeting Planner está listo para que usted comience a usar. Pruébelo y programe una reunión ahora!
Por favor, no dude en agregar sus preguntas y comentarios a continuación; Trato de participar en las discusiones regularmente. También puede contactarme en Twitter @reifman.
También estoy empezando a experimentar con WeFunder basado en la implementación de las nuevas reglas de crowdfunding de la SEC. Por favor considere seguir nuestro perfil. Puedo escribir sobre esto más como parte de esta serie.



