Sistema de gestión de horarios basado en Google Calendar

Transcripción

Sistema de gestión de horarios basado en Google Calendar
Memoria del proyecto
Sistema de gestión de horarios basado
en Google Calendar
Javier Garcés Niño
Proyectos Informáticos de Sistemas
Ingeniería Técnica en Informática de Sistemas
Universidad Jaume I
7 de septiembre de 2012
Proyecto dirigido por: Raul Montoliu Colás
Agradecimientos
La presente memoria del proyecto ha sido redactada con una plantilla de LATEX
creada por Sergio Barrachina Mir bajo la licencia Creative Commons AttributionNonCommercial-ShareAlike (CC BY-NC-SA):
Resumen
Este proyecto consiste en crear un sistema de reservas para organizar
mejor el horario de tutorías de los profesores de manera que puedan conocer los alumnos que van a atender para, de esta forma, poder preparar
con antelación las consultas en caso de necesitarlo.
El objetivo principal del proyecto es que los alumnos puedan acceder
a una página web para comprobar si existe alguna visita programada
con el profesor. Los alumnos que accedan podrán reservar tiempo del
horario de tutorías del profesor para realizar consultas, y en caso de
acceder el propio profesor éste podrá hacer una administración básica
de su calendario. Para ello se utilizará las API que ofrece Google para
trabajar con su servicio llamado Calendar.
Índice general
Índice general
I
Índice de figuras
1 Introducción
1.1. Motivación del proyecto
1.2. Objetivos del proyecto .
1.3. Entorno y estado inicial
1.4. Herramientas . . . . . .
III
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
3
3
2 Planificación y evaluación de recursos
2.1. Planificación . . . . . . . . . . . . . .
2.2. Identificación de tareas . . . . . . . . .
2.3. Seguimiento del proyecto . . . . . . . .
2.4. Evaluación de recursos . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
10
14
19
3 Análisis y diseño del sistema
3.1. Análisis de requisitos . . . .
3.2. Diseño del sistema . . . . .
3.2.1. Diseño del sistema .
3.3. Funciones y tipos de datos .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
21
23
23
27
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Desarrollo y resultados del proyecto
29
4.1. Desarrollo del proyecto . . . . . . . . . . . . . . . . . . . . . . . 29
4.2. Resultados del proyecto . . . . . . . . . . . . . . . . . . . . . . 33
5 Conclusiones y trabajo futuro
35
5.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2. Trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Bibliografía
39
A Apéndices
41
A.1. Apéndice I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
A.2. Apéndice II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
i
ii
Índice general
A.3. Apéndice III . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.4. Apéndice IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
62
Índice de figuras
1.1. Interfaz de control de XAMPP . . . . . . . . . . . . . . . . . . . .
1.2. Ventana del editor avanzado de texto Kate . . . . . . . . . . . . .
1.3. Ventana de HttpRequester, el complemento de Mozilla Firefox que
permite preparar y enviar peticiones HTTP . . . . . . . . . . . . .
1.4. Ventana del entorno de desarrollo en LATEX . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
6
7
8
2.1.
2.2.
2.3.
2.4.
2.5.
2.6.
2.7.
Lista de tareas planteadas para el desarrollo del proyecto
Duración ideal de las tareas . . . . . . . . . . . . . . . . .
Diagrama de Gantt ideal (realizado con MS Project 2010)
Duración real de las tareas . . . . . . . . . . . . . . . . .
Diagrama de Gantt real (realizado con MS Project 2010)
Ejemplo de límites inpuestos por Google en sus servicios .
Página para solicitar un incremento de la cuota . . . . . .
.
.
.
.
.
.
.
10
14
15
17
18
19
19
3.1.
3.2.
3.3.
3.4.
3.5.
Reservando tiempo de la tutoría del profesor . . . . . . . . . . . .
Reserva efectuada, posibilidad del alumno de cancelar la reserva .
Diagrama de flujo de la carga de la página del sistema de reservas
Página de reservas desde el punto de vista de un alumno . . . . . .
Diagrama simplificado de casos de uso . . . . . . . . . . . . . . . .
22
22
24
25
26
4.1. Para trabajar con información privada de una cuenta de Google el
sistema de seguridad empleado pide autorización . . . . . . . . . .
4.2. Diagrama de flujo para cuando se da de alta el profesor en el sistema de reservas . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3. Diagrama de flujo que muestra cómo opera el sistema de reservas
internamente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.1.
A.2.
A.3.
A.4.
A.5.
Google APIs Console: Creación de un nuevo proyecto . . . . . . .
Google APIs Console: Página principal . . . . . . . . . . . . . . . .
Google APIs Console: Lista de servicios de Google . . . . . . . . .
Google APIs Console: Estado actual de la API de Google Calendar
Google APIs Console: Términos de uso para permitir el uso de las
API, 1º parte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
iii
30
31
32
41
42
42
43
44
iv
Índice de figuras
A.6. Google APIs Console: Términos de uso para permitir el uso de las
API, 2º parte y última . . . . . . . . . . . . . . . . . . . . . . . . .
A.7. Google APIs Console: Activación éxitosa de la API de Google Calendar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.8. Google APIs Console: Vista de la pestaña API Access (Acceso a la
API) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.9. Google APIs Console: Configuración del nuevo proyecto . . . . . .
A.10.Google APIs Console: Configuración de un Client ID para aplicaciones web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.11.Google APIs Console: Vista de la pestaña API Access (Acceso a la
API) después de crear el primer ID de los 2 necesarios . . . . . . .
A.12.Google APIs Console: Vista de la pestaña API Access (Acceso a la
API) después de crear el primer ID de los 2 necesarios . . . . . . .
A.13.Google APIs Console: Vista de la pestaña API Access (Acceso a la
API) después de crear los 2 ID necesarios para el funcionamiento
del sistema de reservas . . . . . . . . . . . . . . . . . . . . . . . . .
A.14.Etapa inicial del proceso de alta del calendario del profesor en el
sistema de reservas . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.15.Etapa final del proceso de alta del calendario del profesor en el
sistema de reservas . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.16.Tutorial para crear reservas: Página inicial de pruebas del sistema
de reservas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.17.Tutorial para crear reservas: Pantalla de autenticación de Google .
A.18.Tutorial para crear reservas: Aviso para obligar la autenticación
desde el servicio de la UJI . . . . . . . . . . . . . . . . . . . . . . .
A.19.Tutorial para crear reservas: Autenticación de la cuenta de usuario
desde la UJI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.20.Tutorial para crear reservas: Autorización de Google para el uso de
datos privados . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.21.Tutorial para crear reservas: Página de prueba de reservas desde
una cuenta de usuario autenticada . . . . . . . . . . . . . . . . . .
A.22.Tutorial para crear reservas: Mostrando reservas de la semana seleccionada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.23.Tutorial para crear reservas: Vista gráfica del calendario de tutorías. En rojo aparecen las reservas existentes . . . . . . . . . . . .
A.24.Tutorial para crear reservas: Preparando la reserva . . . . . . . . .
A.25.Tutorial para crear reservas: Mostrando reservas de la semana seleccionada tras la creación de una nueva reserva . . . . . . . . . . .
A.26.Tutorial para crear reservas: Vista gráfica del calendario de tutorías
después de reservar tiempo de tutorías del profesor . . . . . . . . .
A.27.Tutorial para crear reservas: Mostrando reservas de la semana seleccionada (tras eliminación de reserva) . . . . . . . . . . . . . . .
44
45
45
46
46
47
48
49
50
51
52
53
53
54
55
56
57
58
59
60
60
61
Capítulo
1
Introducción
Índice
1.1.
1.2.
1.3.
1.4.
Motivación del proyecto
Objetivos del proyecto .
Entorno y estado inicial
Herramientas . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
3
3
Este proyecto se enfoca en la creación de una herramienta que permite
organizar de una manera más eficiente el tiempo de los profesores para atender consultas de los alumnos y a su vez evitar que el alumno espere largos
períodos de tiempo en caso de haber más alumnos esperando ser atendidos
por ese profesor.
Google Calendar, un calendario electrónico desarrollado por Google, tiene
implementado en el cliente un sistema de citas que podría haber sido utilizado
para el proyecto, desafortunadamente el sistema de Google es muy limitado
debido principalmente a la ausencia de este sistema de citas en la API (Application Programming Interface) de Google, impidiendo la implementación y
mejora del servicio por parte de programadores ajenos a Google. Es por ello
necesario utilizar la API existente para replicar dicho sistema y adaptarlo a
las necesidades del proyecto.
1.1.
Motivación del proyecto
Este proyecto se inspira en la migración de servicios que ha realizado la
Universidad Jaume I hacia los servicios de Google.
1
2
Introducción
Antes de la formalizar la propuesta del proyecto estaba planeado el diseño
el sistema de reservas con herramientas más comunes como una base de datos para almacenamiento de todos los datos. Sin embargo, tras descubrir las
posibilidades que el servicio de Google Calendar puede ofrecer al proyecto, la
novedad que supone adoptar dicha tecnología para el proyectando y la posible
experiencia adquirida para el futuro laboral se decidió aprendizaje del manejo
de las API del calendario de Google. Se sabía que delegar partes del proyecto
al servicio de calendarios de Google podría traer ventajas significativas, como
la liberarización de recursos en el servidor local, donde se localiza el sistema de
reservas. Además, si por cualquier incidencia el sistema de reservas se queda
inoperativo los calendarios podrían seguir siendo accesibles por otros servicios
que requieran esos datos.
1.2.
Objetivos del proyecto
Los objetivos que se desea cumplir durante la realización del proyecto son:
Aprendizaje en el servicio de Google Calendar y la API asociada al
servicio.
Creación de una web que permita consultar horarios de tutorías de algún
profesor.
Diseño y creación de la infraestructura necesaria que permita realizar
reservas de tiempo del horario de tutorías del profesor para hacerle consultas.
Administración básica del profesor con su horario de tutorías.
Durante el proceso de consulta de horarios de tutorías del profesor debe
mostrarse al usuario que acceda a la página web del sistema de reservas un
calendario donde aparezca las horas que han sido asignadas al profesor para
atender consultas a los alumnos. Toda reserva que se haya realizado también
aparecerá, permitiendo conocer al alumno las horas de tutoría libres que tiene
el profesor.
Después de la autenticación del alumno en el sistema de reservas este
obtendrán nuevos controles en la página web. Estos controles podrán ser utilizados para formalizar reservas en el caso que se quiera realizar una visita al
profesor en su horario de tutorías o cancelar sus propias reservas.
Además, si el usuario autenticado es el propietario del calendario podrá
administrar su horario de tutorías como es la cancelación de reservas de alumnos o reserva de su propio horario para inhabilitar las tutorías de un día en
1.3. Entorno y estado inicial
concreto.
Aunque inicialmente el sistema no ha sido desarrollado para ser parte de
otros proyectos de mayor envergadura se ha seleccionado un diseño austero de la página web del sistema de reservas, posibilitando la reutilización o
adaptación del sistema a otros proyectos.
1.3.
Entorno y estado inicial
Tras un largo período de tiempo de análisis, comprensión y aprendizaje del
funcionamiento de las API de Google Calendar y del protocolo de seguridad
OAuth 2.0 que soporta Google se ha procedido al planteamiento y posterior
desarrollo del sistema de reservas. Inmediatamente después se preparó las herramientas necesarias para realizar varios códigos de ejemplo y analizar los
resultados obtenidos por los ejemplos.
En cuanto al planteamiento de trabajo con el servicio de Google inicialmente se planteó un nivel de dificultad de manejo similar al de una base de
datos, con una página que administrase operaciones que los usuarios realizaran y una base de datos almacenase o retornara información. Pero debido a
dificultades técnicas no previstas con Google Calendar, como la ausencia en
la API de varias funciones existentes en la interfaz web de Google Calendar
de gran valor para el proyecto o la forma de funcionamiento del protocolo de
seguridad OAuth 2.0 empleado durante las pruebas ha sido necesario replantear la estructura y funcionamiento que tendría que tener el proyecto para que
fuera posible su realización sin desviarse significativamente de la idea original.
Se puede observar que no se puede implementar el proyecto con las facilidades que se había previsto inicialmente en el proyecto final, creando un
retraso en el desarrollo pero el resultado se puede considerar que es similar al
inicialmente propuesto.
Faltaría explicar los recursos humanos requeridos para la elaboración del
sistema de reservas pero en éste proyecto no es necesario realizar un estudio
debido a que ya se conoce de antemano que se realizará por una única persona
y que no variará durante todo el desarrollo. En caso de incumplir los plazos
previstos en determinadas tareas esto significará que no será posible arreglar
estos desfases introduciendo nuevos miembros al desarrollo de este proyecto.
1.4.
Herramientas
El proyecto se ha desarrollado y probado en 2 equipos, uno con el sistema
operativo Windows 7 profesional y otro con Kubuntu 12.04 LTS (Long Term
3
4
Introducción
Support), ambos de 64 bits.
En cuanto a la implementación del proyecto, se ha utilizado el editor de
texto avanzado de KDE, Kate, para la escritura del código fuente y la Google
API PHP client library, la biblioteca oficial de Google para acceder a datos
protegidos mediante la API de Google.
Otras herramientas utilizadas en el proyecto han sido las siguientes:
XAMPP
Apache
PHP
Navegadores web (Mozilla Firefox v14.0.1, Google Chrome v21, Internet
Explorer v9, Konqueror v4.8)
HttpRequester
Texmaker
1.4. Herramientas
5
XAMPP
Es un servidor independiente de plataforma y de software libre, que contiene la base de datos MySQL, el servidor web Apache y los intérpretes para
lenguajes de script PHP y Perl. Actúa como un servidor web libre, fácil de usar
y capaz de interpretar páginas dinámicas. Se actualiza frecuentemente para
incorporar las últimas versiones de Apache/MySQL/PHP y Perl [18] (ver Figura 1.1).
Página web oficial: http://www.apachefriends.org/es/xampp.html
Figura 1.1: Interfaz de control de XAMPP
Apache
Servidor Web de código abierto muy popular. Soporta gran cantidad de
características, muchas de ellas implementadas como módulos compilades para
darle nuevas funcionalidades al núcleo del servidor.
Página web oficial: http://www.apache.org/
PHP
PHP es un lenguaje de programación interpretado, diseñado originalmente
para la creación de páginas web dinámicas pero actualmente puede ser utilizado desde una interfaz de línea de comandos o en la creación de otros tipos
de programas incluyendo aplicaciones con interfaz gráfica [13].
Página web oficial: http://www.php.net
6
Introducción
Kate
Kate es un editor avanzado de texto para el entorno de escritorio KDE.
Se ha utilizado esta herramienta por ser la que mejor conoce el proyectando
para trabajar con código PHP (ver Figura 1.2).
Página web oficial: http://kate-editor.org
Figura 1.2: Ventana del editor avanzado de texto Kate
1.4. Herramientas
HttpRequester
Un complemento para Mozilla Firefox diseñado para realizar peticiones
HTTP, observar las respuestas y mantener un historial de transacciones (ver
Figura 1.3).
Página web oficial: https://addons.mozilla.org/es/firefox/addon/httprequester
Figura 1.3: Ventana de HttpRequester, el complemento de Mozilla Firefox que permite
preparar y enviar peticiones HTTP
7
8
Introducción
Textmaker
Es un entorno de desarrollo de LATEX multiplataforma y de código abierto
de fácil uso (ver Figura 1.4). Se ha empleado para la redacción de la memoria
del proyecto.
Página web oficial: http://www.xm1math.net/texmaker
Figura 1.4: Ventana del entorno de desarrollo en LATEX
Capítulo
2
Planificación y evaluación de
recursos
Índice
2.1.
2.2.
2.3.
2.4.
2.1.
Planificación . . . . . . .
Identificación de tareas .
Seguimiento del proyecto
Evaluación de recursos .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 9
. 10
. 14
. 19
Planificación
Con el objetivo de llevar un seguimiento de la duración del proyecto, se ha
realizado la identificación de cada una de las tareas y subtareas, estableciendo
un orden en el que se van a realizar. A cada tarea se le ha estimado un tiempo
que debería ser suficiente para su completo desarrollo.
Es necesario constatar que en la elaboración de las tareas no se han contabilizado fines de semana, y no hubo ningún tipo de progreso en el desarrollo
del proyecto los días 28 de diciembre al 8 de enero por corresponder con la
festividad de la navidad.
9
10
Planificación y evaluación de recursos
2.2.
Identificación de tareas
Durante el desarrollo del trabajo se estableció una lista de tareas que reflejarían con gran precisión las etapas de la elavoración del proyecto (ver Figura 2.1).
Figura 2.1: Lista de tareas planteadas para el desarrollo del proyecto
2.2. Identificación de tareas
A continuación se explica el objetivo de cada una de las tareas, por orden
de aparición en la figura 2.1:
Consultar al tutor: Se necesitaba la búsqueda de un tutor que quisiera
aceptar un proyecto planteado por el alumno.
Búsqueda de información y estudio del proyecto: Tras una serie de conversaciones con el tutor se acordó buscar información y estudiar la viabilidad del uso del servicio de Google Calendar en el sistema de reservas
planteado en esta fase del desarrollo.
Definición más detallada de objetivos: Se establecieron los objetivos definitivos con los que se pediría al tutor que aceptase el proyecto propuesto.
Aprobación del inicio: En este punto se espera que el tutor acepte el
proyecto propuesto y realice de alta el proyecto en la base de datos de
la asignatura de Proyectos Informáticos de Sistemas.
Instalación de herramientas a utilizar: Obtención, instalación y configuración de los elementos necesarios para desarrollar el proyecto.
Familiarización con el entorno de trabajo: Tras la instalación y configuración de las herramientas se procede al aprendizaje del entorno de
desarrollo con el que se va a realizar el proyecto. Esto es debido a la necesidad de descubrir si hacía falta más conocimientos para un correcto
manejo de algunas de las herramientas que se iba a emplear.
Separación de objetivos en varias etapas de desarrollo: Para abordar
con menor complejidad los objetivos a cumplir durante el desarrollo del
proyecto se procede a dividir las tareas en otras más simples con objetivos
más simples. De esta forma se puede conocer con mayor facilidad el
objetivo de cada una de las tareas.
Planificación inicial: Se estable un orden inicial de las tareas a realizar
durante la duración del proyecto y un tiempo acorde a la complejidad y
magnitud de la tarea a realizar.
Análisis del protocolo de seguridad OAuth 2.0 : Esta fase era importante
para entender el funcionamiento del la seguridad que se iba a emplear en
el proyecto. Tras la lectura de la documentación proporcionada por Google se realizaron una serie de pruebas para estudiar el comportamiento
de esta tecnología. En este punto se pudo comprobar si habrían problemas de difícil solución que pudieran retrasar el desarrollo del proyecto
más de lo inicialmente planificado.
Análisis de la API de Google Calendar: Se procede a estudiar toda la
documentación proporcionada por Google referente a la última versión
11
12
Planificación y evaluación de recursos
disponible de la API de Google Calendar. Debido a la gran cantidad de
documentación existente esta tarea tiene un mayor coste temporal que
todas las tareas realizadas con anterioridad. Finalmente sólo se va ha
utilizar un reducido subconjunto de acciones para el sistema de reservas
planteado en el proyecto.
Diseño del sistema de reservas: Como resultado de los análisis realizados
hasta la fecha se procede a diseñar la interfaz que podría llegar a tener
el sistema de reservas en cada uno de los escenarios establecidos por los
objetivos del proyecto y la estructura interna del sistema de reservas.
Programación: Una vez quede clara la estructura interna del sistema de
reservas se procederá a implementar las llamadas a la API de Google
Calendar para que pueda realizar consultas o cambios en el calendario
del profesor solicitado. A la vez que se desarrolla nuevas funciones se
irán incorporando a la interfaz web del sistema de reservas.
Búsqueda y solución de errores: Se realizarán diversas pruebas para encontrar pequeños errores que no se hubieran previsto durante la implementación del código y se forzará escenarios problemáticos para comprobar que el sistema podría ser capaz de resolver los problemas, en caso
negativo se procedería a corregir esos casos.
Pruebas finales: Al finalizar la implementación del sistema de reservas
se procede a comprobar todas y cada una de las características que
ofrece el sistema para descartar posibles regresiones introducidas tras la
corrección de errores.
Organizar documentación: Se guardará cualquier tipo de información e
imágenes de interés para poder realizar la memoria del proyecto.
Redactar apartados de la memoria: Con la idea de documentar todo el
proyecto, tanto la planificación de las tareas como el código empleado
por el sistema de reservas se elabora la presente memoria.
Revisión del tutor: Análisis de la memoria por parte del tutor encargado
en este proyecto.
Revisar memoria y otros trabajos: Tras la conversación realizada con el
tutor sobre la revisión de la memoria se procede a realizar aquellos cambios que se consideren necesarios para mejorar la calidad de la memoria
del proyecto.
Entrega de la memoria: Se procederá al envío definitivo de la memoria
del proyecto.
2.2. Identificación de tareas
Exposición oral: Para finalizar el proyecto se elaborará una serie de diapositivas en las que se deberá describir el proyecto desarrollado y posterior exposición ante un jurado. Debido a que se trata de una actividad
que ha de ocurrir posteriormente a la redacción y entrega de la memoria
ha sido incluida en la lista de tareas para que se tenga constancia de su
existencia.
13
14
Planificación y evaluación de recursos
2.3.
Seguimiento del proyecto
El proyecto se ha ido planificando idealmente para tener una duración de
136 días (ver Figura 2.2). Si las horas de trabajo dedicado en el proyecto fuera
de 2 horas y 15 minutos diarias las horas necesarias para finalizar el proyecto
requerirían unas 306 horas en total, siempre que se hablase de tiempo ideal.
En la Figura 2.3 se muestra el diagrama de Gantt correspondiente a la duración ideal del proyecto.
Figura 2.2: Duración ideal de las tareas
2.3. Seguimiento del proyecto
Figura 2.3: Diagrama de Gantt ideal (realizado con MS Project 2010)
15
16
Planificación y evaluación de recursos
En realidad la duración real ha terminado extendiéndose hasta los 223 días
(ver Figura 2.4) debido a varios errores de la documentación de Google que
han impedido finalizar la fase de programación en el tiempo establecido y a
un período de inactividad por razones laborales de 3 meses aproximadamente,
desde el 15 de marzo hasta el 24 de junio. Además, en la elaboración de la
memoria se ha alargado su duración de los 18 días ideales a 26 días por causas
ajenas al desarrollo del proyecto. En total, si se aplicase las 2 horas y 15
minutos de desarrollo al día utilizado en la planificación ideal del proyecto
la cantidad de horas se dispara hasta las 501 horas en total. Debido a que el
cálculo ha incluido los meses de inactividad, el cálculo se ha de realizar con los
136 días más los días de retraso ocurridos durante la fase de programación (28
días adicionales) y la de elaboración de la memoria (8 días adicionales): en total
son 172 días de desarrollo real que multiplicado por las 2 horas y 15 minutos
de trabajo en el proyecto deja un total de 387 horas de trabajo dedicado al
proyecto, 81 horas con respecto a la planificación ideal del proyecto. En la
Figura 2.5 se muestra el diagrama de Gantt correspondiente a la duración real
del proyecto.
2.3. Seguimiento del proyecto
Figura 2.4: Duración real de las tareas
17
18
Planificación y evaluación de recursos
Figura 2.5: Diagrama de Gantt real (realizado con MS Project 2010)
2.4. Evaluación de recursos
2.4.
Evaluación de recursos
La mayoría de los servicios de Google son gratuitos mientras no se supere
una serie de límites (ver Figura 2.6). En estos casos para seguir usando el
servicio requiere mejorar el servicio pagando. Actualmente en Google Calendar
se proporciona una cuota de 10.000 de peticiones al día, en caso de requerir
más cuota hay que realizar una petición en la siguiente dirección:
https://developers.google.com/google-apps/calendar/pricing
La página de petición de incremento de cuota es similar a la figura 2.7).
Figura 2.6: Ejemplo de límites inpuestos por Google en sus servicios
Figura 2.7: Página para solicitar un incremento de la cuota
19
20
Planificación y evaluación de recursos
La selección de herramientas basadas en software libre se debe primordialmente a la fiabilidad y la gratuidad para el desarrollador del proyecto. Además,
cualquier equipo informático con acceso a las herramientas mencionadas en la
sección 1.4 valdría para la elaboración del proyecto.
Sin embargo, si se realizase el mismo proyecto contratando personal cualificado para seguir las mismas fases de desarrollo, sería posible contabilizar el
coste necesario para su realización en base a las horas que han sido requeridas
para la finalización del proyecto. Para un correcto cálculo se reutilizará los datos obtenidos en la sección 2.3, concretamente, el número de horas reales que
han sido requeridas para su correcto desarrollo, 387 horas. Si el nuevo ingeniero técnico en informática cobrase 30 euros la hora obtendríamos el siguiente
coste total por las 387 horas:
Coste = horas_desarrollo ∗ coste/hora
Coste = 387 horas ∗ 30 euros/hora
Coste = 11,610 euros
También se debe contabilizar el equipo informático necesario para el nuevo
puesto de trabajo. Al no requerir gran potencia de cálculo para el desarrollo
web y posteriores pruebas del proyecto con un servidor en la propia máquina
cualquier equipo informático de bajo presupuesto puede cumplir con las expectativas cuyo rango de precios puede variar entre los 450 euros y los 600
euros. En el precio se incluye torre, monitor y periféricos esenciales en un
ordenador de sobremesa como son el teclado y el ratón. Como el proyecto establece que sólo existe una persona desarrollando el proyecto sólo se requerirá
una computadora. Por tanto, a los 11.610 euros del proyecto se le sumará un
equipo informático de valorado entre 450 y 600 euros.
Capítulo
3
Análisis y diseño del sistema
Índice
3.1. Análisis de requisitos . . . . . . . . . . . . . . . . . . . . . 21
3.2. Diseño del sistema . . . . . . . . . . . . . . . . . . . . . . . 23
3.3. Funciones y tipos de datos . . . . . . . . . . . . . . . . . . 27
En este capítulo se explican algunos conceptos sobre la API de Google, así
como funciones propias desarrolladas para este proyecto.
3.1.
Análisis de requisitos
Para el desarrollar el sistema de reservas es necesario conocer el tipo de
acciones a la que se someterá dicho sistema sin profundizar en los detalles. A
partir de ahí se diseña la interfaz con el que la página del sistema de reservas
se comunicará con los servicios de Google.
Se distinguen 2 grupos de acciones:
Consulta de información
Modificación del calendario
Consulta de información
Básicamente son peticiones al servicio de Google para obtener una serie
de datos. Los tipos de datos devueltos dependen del tipo de consulta que se
21
22
Análisis y diseño del sistema
realice, concretamente en el sistema de reservas trabajará básicamente con
calendarios y eventos.
Este tipo de acciones normalmente no las solicita directamente el usuario
que accede al sistema, es decir, son funciones que forman parte de otras tareas.
Es bastante frecuente que se haga una búsqueda de eventos en un calendario utilizando rangos de fechas como método para acotar los resultados que
pudiera proporcionar la consulta.
Modificación del calendario
Son las acciones que más control tienen los usuarios que acceden al sistema
de reservas y que dejan cambios permanentes en el calendario del profesor. Los
más comunes son las órdenes de creación y cancelación de reservas.
Estas acciones se describen a continuación:
Creación de reservas: Se redactará una descripción para que el profesor
conozca la razón de la reserva y seleccionará el tiempo de inicio y fin
de la reserva. El horario de tutorías se divide en franjas de 30 minutos
como unidad mínima para realizar una reserva pero se permite que el
alumno pueda seleccionar varios huecos de 30 minutos contiguos. (ver
Figura 3.1).
Cancelación de reservas: Al cancelar un reserva creada por el propio
usuario se devolverá las horas de la reserva para que otros usuarios puedan reservar esas horas (ver Figura 3.2)
Figura 3.1: Reservando tiempo de la tutoría del profesor
Figura 3.2: Reserva efectuada, posibilidad del alumno de cancelar la reserva
3.2. Diseño del sistema
3.2.
Diseño del sistema
3.2.1.
Diseño del sistema
El proyecto consta de 3 partes diferenciadas:
Página del sistema de reservas
Administración del calendario del profesor
Acciones del usuario autenticado
Página del sistema de reservas
Su diseño va a ser austero pero cumplirá con los objetivos propuestos. Debe
contener un botón para autenticarse con una cuenta de Google y el calendario
de tutorías del profesor y, en caso de existir, se mostrarán reservas. Tras la
autenticación el servicio de Google solicitará permiso para poder trabajar con
varios datos del usuario.
Tras la autenticación aparecerán nuevos controles para 2 tipos de acciones:
creación de reservas y cancelación.
23
24
Análisis y diseño del sistema
Acciones del usuario autenticado
Figura 3.3: Diagrama de flujo de la carga de la página del sistema de reservas
3.2. Diseño del sistema
Cualquier usuario autenticado en el sistema de reservas tendrá a su disposición de una lista que representará los horarios de tutorías de la semana y unos
controles para la realización de reservas. Además, Aparecerá un botón para
abortar aquellas reservas que el alumno haya realizado (ver Figura 3.3). Por
otro lado, el profesor dueño del calendario poseerá la autorización necesaria
para abortar las reservas de cualquier usuario (ver Figura 3.4).
Figura 3.4: Página de reservas desde el punto de vista de un alumno
25
26
Análisis y diseño del sistema
Administración del calendario del profesor
Las acciones realizadas por los usuarios serán transmitidas al sistema de
reservas como si fueran realizadas por el profesor, con la utilización de este
método se evita que se puedan modificar los eventos del calendario por otras
personas que no sean el propio profesor (ver Figura 3.5).
Figura 3.5: Diagrama simplificado de casos de uso
3.3. Funciones y tipos de datos
3.3.
Funciones y tipos de datos
A continuación se nombrarán las funciones más relevantes:
Función get_oauth2_token:
Retorna un string llamado ’Access Token’ que servirá como código de
autorización para realizar llamadas a la API usando OAuth 2. Dependiendo los parámetros y de la situación donde se use podrá obtener un
’Refresh Token’ que se almacenará en un fichero para futuros usos del
sistema de reservas.
Función read_calendarOwner_token:
Lectura de un fichero para devolver un string que es el ’refresh_token’
asociado al calendario del tutor. En caso de no poder leer correctamente
el fichero retornará una cadena vacía.
Función write_calendarOwner_token:
Salva a un fichero un string que corresponde al ’refresh_token’ asociado
al calendario del tutor.
Función send_post_query:
Realiza una petición HTTP a Google para insertar datos en Google
Calendar. Los datos a insertar dependerán del tipo que se hayan especificado en la URI utilizada. El dato que devuelva la función por defecto
será un código HTTP de respuesta, devolviendo el código ’200’ como
operación correcta. Además, se podrá especificar que retorne un string
que represente un código de identificación (ID) en caso de insertarse un
evento u objeto similar.
Función insertNewEvent:
Creación de un nuevo evento en el calendario de reservas del profesor.
El propietario del evento seguirá siendo el profesor pero se incluirán
datos del usuario autenticado que ha realizado la acción. Retorna el
valor verdadero si se ha insertado con éxito y falso en caso contrario.
Función send_delete_query:
Realiza petición HTTP a Google para eliminar datos en Google Calendar. Dependiendo del tipo de dato especificado eliminará un evento o un
calendario. El dato que devuelve la función por defecto será un código
HTTP de respuesta, retornando el código ’204’ como operación correcta.
Función deleteEvent:
Eliminará el evento seleccionado del calendario que se indique. Retornará
verdadero si se ha eliminado el evento y falso en caso contrario.
Función deleteCalendar:
Eliminará el calendario que se indique. Retorna verdadero si se ha eliminado el evento y falso en caso contrario.
27
28
Análisis y diseño del sistema
Función send_put_query:
Realiza una petición HTTP a Google para modificar datos en Google
Calendar. Los datos a modificar dependerán del tipo que se hayan especificado en la URI utilizada. El dato que devuelve la función por defecto
será un código HTTP de respuesta, retornando el código ’200’ como
operación correcta.
Función send_get_query:
Envía una petición HTTP a Google y devuelve una lista de elementos. Estos elementos serán del tipo que se hayan especificado en la URI
utilizada
Función loadEvents:
Dadas las fechas de inicio y de fin se realizará una búsqueda de eventos
en el calendario seleccionado. Retorna una lista de eventos.
Función insertNewTutoringCalendar:
Creación de un nuevo calendario en el que se pueda insertar horarios de
tutorías del profesor. Retorna el ID del calendario creado, cadena vacía
en caso de error.
Función insertNewBookingCalendar:
Creación de un nuevo calendario para que se pueda insertar reservas del
horario de tutorías del profesor. Retorna el ID del calendario creado,
cadena vacía en caso de error.
Función fill_calendarOwner_config:
Salva en un fichero todos los datos de configuración necesarios para que
el sistema de reservas pueda acceder a los calendarios del profesor.
Función weekStartDate:
Retorna la fecha del primer día de la semana, por defecto el de la semana
actual.
Función weekEndDate:
Retorna la fecha del último día de la semana, por defecto el de la semana
actual.
Capítulo
4
Desarrollo y resultados del proyecto
Índice
4.1. Desarrollo del proyecto . . . . . . . . . . . . . . . . . . . . 29
4.2. Resultados del proyecto . . . . . . . . . . . . . . . . . . . . 33
A continuación se explicarán los resultados obtenidos durante el desarrollo
del proyecto. Toda posible desviación con respecto a la planificación inicial
se detallarán y se justificarán. Para más información sobre el código fuente
revisar el Apéndice IV.
Para probar las especificaciones de la API de Google Calendar se debe
emepezar desarrollando la parte del sistema de reservas encargada de llamar
a las API de Google Calendar, el protocolo de seguridad OAuth y funciones
suplementarias conforme hiciera falta.
4.1.
Desarrollo del proyecto
A continuación se hablará de los siguientes apartados:
Implementación del sistema de seguridad OAuth
Posibles problemas con OAuth: los permisos de los usuarios
Implementación de funciones de consulta
Implementación de funciones de manipulación de calendarios
Desarrollo de funciones que emplearían los usuarios
29
30
Desarrollo y resultados del proyecto
Implementación del sistema de seguridad OAuth
En un primer acercamiento al sistema de seguridad OAuth se puede observar que requiere autorización explícita para acceder a información privada
del usuario autenticado (ver Figura 4.1). El funcionamiento por tanto difiere
ligeramente con el planeado para el nuevo sistema.
Figura 4.1: Para trabajar con información privada de una cuenta de Google el sistema
de seguridad empleado pide autorización
Durante el proceso de autorización se obtiene un código que hay que utilizarse para acceder a los datos privados del usuario almacenados en los servicios
de Google llamado ’Access Token’. Este dato sólo puede utilizarse durante un
breve período de tiempo, momento en que expirará y no se permitirá más
accesos válidos a datos privados en Google hasta se vuelva a obtener un nuevo
’Access Token’.
Posibles problemas con OAuth: los permisos de los usuarios
En lo que concierne a la manipulación de eventos de calendarios se puede
plantear que los alumnos puedan insertar eventos en el calendario del profesor.
Este metodología de trabajo requiere el envío de autorizaciones a los alumnos
que permitan, tras la aceptación de la invitación, trabajar sobre el calendario.
Si se estudia los posibles inconvenientes del sistema los alumnos tendrían privilegios suficientes para insertar eventos en áreas no destinadas para tutorías.
Por consiguiente este método se descarta.
Para permitir la inserción de eventos en calendarios de terceras personas
en Google Calendar se plantea un sistema que trabaje con datos del profesor
4.1. Desarrollo del proyecto
de manera similar a la forma de funcionamiento de una base de datos. Los
alumnos trabajarían con sus credenciales mientras internamente toda acción
realizada sobre el calendario utilizando el sistema de reservas pertenecería al
profesor. De esta forma nadie excepto el propio profesor puede manipular su
propio calendario.
Con el sistema propuesto requiere el uso de un código de autorización del
profesor y que siempre se renovase cuando se realizase una acción sobre el
calendario del profesor. Para ello se trabaja con un código de autorización
especial llamado ’Refesh Token’ muy utilizado en las aplicaciones de escritorio
para generar tantos ’Access Token’ como llamadas a los servicios de Google
sean necesarios sin pedir autorización explícita debido a que no posee fecha
de expiración. Sin embargo, este dato sólo se obtiene durante el proceso de
autorización para obtener el primer ’Access Token’ tras una primera autenticación por parte del usuario. Una vez realizado satisfactoriamente el proceso
mencionado anteriormente para la creación del ’Refresh Token’ se almacena
el código en un lugar seguro (ver Figura 4.2). Desde este momento ya se debe
poder utilizar el sistema de reservas con el planteamiento realizado.
Figura 4.2: Diagrama de flujo para cuando se da de alta el profesor en el sistema de
reservas
Para realizar las operaciones de este proceso se implementó la función
get_oauth2_token para que retornara un ’Access Token’ que permitiera al
usuario autenticado trabajar con el sistema de reservas. Además, si se realiza una llamada a la función get_oauth2_token durante el proceso de dar
de alta al profesor en el sistema de reservas ésta llamará a la función wri-
31
32
Desarrollo y resultados del proyecto
te_calendarOwner_token para que almacenase el ’Refresh Token’ obtenido.
Implementación de funciones de consulta
Toda acción solicitada al sistema de reservas trabajaría con los códigos
de autorización obtenidos mediante el sistema mencionado anteriormente (ver
Figura 4.3). Las acciones tienen como propietario el propio profesor, por lo
que las reservas aparecerán exclusivamente en el calendario del profesor y sólo
éste podrá alterar los eventos.
Figura 4.3: Diagrama de flujo que muestra cómo opera el sistema de reservas internamente
Las tareas más simples para realizar en los calendarios son las consultas
para que devuelvan una lista de eventos. Se procede a desarrollar la función
send_get_query lo más genérica que fuera posible para que partiendo de los
datos específicos devuelva una lista de elementos del tipo de datos solicitado,
como es el caso de la función loadEvents que pediría las fechas de inicio y fin
y el calendario al que se tenía que hacer la consulta.
4.2. Resultados del proyecto
Implementación de funciones de manipulación de calendarios
Se destaca el retraso producido por un fallo en la documentación de Google Calendar referente a la inserción/modificación de datos. Se utilizó sin éxito
una herramienta web de pruebas que proporciona Google llamada OAuth 2.0
Playground y que permite realizar peticiones de tipo REST a los servicios de
Google, en este caso a Google Calendar. Se descubrió el problema de la documentación tras detectar una inconsistencia en los parámetros necesarios para
realizar correctamente las peticiones REST contra los servicios de Google tras
el uso de una extensión de Firefox llamada HttpRequester.
Finalmente se implementan funciones de inserción send_post_query, de
eliminación send_delete_query y de modificación send_put_query de una
forma similar a la previemante declarada fución send_get_query para evitar duplicidad en el código.
Desarrollo de funciones que emplearían los usuarios
Se implementó funciones relacionadas con tareas que un usuario pudiera
realizar para darle un diseño básico pero funcional a la página del sistema de
reservas.
Por lo que respecta al acceso del usuario al sistema de reservas hay que
diferenciar del método empleado para procesar las peticiones de los usuarios
en el calendario del profesor con el método de autenticación del usuario en el
sistema de reservas. En el caso de los usuarios es suficiente almacenar temporalmente el ’Access Token’ del usuario en una variable de sesión y destruir
dicha variable de sesión cuando se realiza una desconexión del servicio de la
página web de reservas debido a que el usuario autenticado sólo se utiliza para
diferenciar los visitantes desconocidos que accediesen a la web de reservas de
los usuarios que tenrían autorización para realizar reservas. Sólo es preciso
implementar las funciones auxiliares getAccessToken y getRefreshToken que
se utilizarían únicamnete en un par de ocasiones en el código del proyecto
para leer en un objeto del tipo de datos JSON (JavaScript Object Notation)
el ’Access Token’ o el ’Refresh Token’ que aparecen en el objeto leído.
4.2.
Resultados del proyecto
Se puede declarar que se ha cumplido los objetivos planteados en la sección 1.2. A continuación se comentará cada objetivo:
Aprendizaje en el servicio de Google Calendar y la API asociada al servicio: Se ha probado los diferentes menús de la interfaz web del cliente
33
34
Desarrollo y resultados del proyecto
oficial de Google para estudiar los elementos que aparecen para tener
una idea de qué tipo de elementos han de utilizarse en el momento de
mostrar información al usuario que consultase un calendario de Google.
Debido que se ha analizado las limitaciones existentes por la actual implementación de la API se pudo descartar para el sistema de reservas
toda API no esencial para la realización del proyecto. Posteriormente se
procedía al diseño inicial del sistema con la API relevante.
Creación de una web que permita consultar horarios de tutorías de algún profesor: Se a realizado una interfaz web simple para acceder al
servicio y realizar una demostración completamente funcional del sistema con las posibles operaciones implementadas en el sistema de reservas
implementado.
Diseño y creación de la infraestructura necesaria que permita realizar
reservas de tiempo del horario de tutorías del profesor para hacerle consultas: Como se ha comentado anteriormente se ha diseñado la estructura del sistema de reservas para que cualquier usuario autenticado pueda
realizar operaciones sobre las horas de tutorías del calendario del profesor pero teniendo como dueño de estas operaciones el propio profesor
para evitar manipulación del calendario no deseada en el sistema de reservas. Finalmente, se ha realizado la implementación de funciones que
trabajen contra el servicio de Google Calendar, tanto para realización
de consultas como operaciones de inserción, modificación y eliminación
de elementos de los calendarios. Para facilitar estas tareas se ha desarrollado funciones adicionales que facilitan las acciones realizadas en el
sistema de reservas.
Administración básica del profesor con su horario de tutorías: Con el sistema de reservas previamente implementado sólo era necesario averiguar
si el tutor es el usuario autenticado en el sistema y en caso afirmativo
habilitar controles que no aparecen en caso de autenticarse alumnos, como puede ser la opción de cancelar cada una de las reservas de todos los
alumnos.
Capítulo
5
Conclusiones y trabajo futuro
Índice
5.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2. Trabajo futuro . . . . . . . . . . . . . . . . . . . . . . . . . 36
En este capítulo se mostrarán las conclusiones obtenidas una vez finalizado
el proyecto, así como sus futuras ampliaciones.
5.1.
Conclusiones
Tras la conclusión del proyecto, podemos afirmar que se ha logrado cumplir con los objetivos propuestos al inicio de este. Se ha conseguido diseñar e
implementar un sistema de reservas basándose en Google Calendar.
El servicio de Google Calendar tiene potencial para utilizarse en multitud
de proyectos de toda índole pero es posible que los esfuerzos de Google se enfoquen a la red social Google+, retrasando funciones muy útiles que deberían
haber aparecido hace años en la API como el sistema de reservas implementado en la interfaz web de Google Calendar o mayor personalización en los datos
que deberían mostrarse al público cuando se accede al calendario oficial.
En cuanto a la planificación de tareas hay que comentar que era adecuada,
aunque desafortunadamente un error en la documentación de Google produjera un gran retraso en fase de desarrollo del sistema de reservas.
35
36
Conclusiones y trabajo futuro
A nivel personal, el diseño de este tipo de sistemas sin recurrir a los elementos tradicionales como una base de datos supone una experiencia gratificante,
además de saber que ha contribuido al aprendizaje, al no ser material de estudio que ya se haya estudiado en otras asignaturas de la carrera. De normal en
la carrera te enfrentan a problemas relativamente sencillos y diseñados para
ser desarrollados durante un breve período de tiempo, todo lo contrario a lo
desarrollado durante este proyecto.
5.2.
Trabajo futuro
Hay que comentar que se pensó es más características o mejoras que podía
haberse incluido en el sistema de reservas pero como estamos ante un proyecto que no podía extenderse indefinidamente en el tiempo. Algunos ejemplos
podrían ser los siguientes:
Creación de una lista blanca de usuarios: Muchas veces es conveniente
que sólo pueda acceder a este tipo de herramientas un grupo de personas, por ejemplo alumnos y/o profesores. Actualmente el proyecto sólo
requiere que la cuenta sea compatible con la autenticación de Google,
como puede ser las cuentas de los alumnos de la Universidad Jaume I.
Creación de tutorías fuera del horario ordinal: Hay veces que se han dado
casos en que el profesor de una asignatura ha cambiado el horario de
tutorías de un día por cualquier razón que fuera. El sistema de reservas
actualmente no puede realizar ese tipo de casos y le proporcionaría mayor
libertad al profesor para manipular su horario de tutorías.
Anulación temporal de tutorías: A diferencia del punto anterior a veces
los profesores tienen que realizar viajes para asistir a conferencias o les
es imposible asistir a trabajar por diversas razones pero que se sabe que
van a volver al entorno laboral en un breve espacio de tiempo, ante estos
casos el sistema de reservas no puede conocer estos problemas y podría
seguir reservándose tutorías a pesar que no podrían ser atendidas. Se
quería dar la posibilidad al profesor o persona competente de anular u
ocupar de alguna manera el horario de reservas en las fechas afectadas
para evitar que nadie pueda crear nuevas reservas.
Mejorar la implementación actual: Como no se tenía experiencia en la
forma de trabajar con la API proporcionada por Google si se volviera a
implementar el código del sistema de reservas se enfocaría a la creación
de clases. Se podría adaptar el código actual pero se requiere más tiempo
del planeado para el proyecto, razón por la cual se deja como propuesta.
Seleccionar un profesor de una lista: A pesar que tiene lógica que exista
más de un profesor que pueda usar el sistema de reservas no entraba
5.2. Trabajo futuro
en los objetivos iniciales por lo que no se incluyó dicha característica en
la página de reservas. Actualmente toda la información del profesor que
se utiliza en el sistema de reservas se almacena en un fichero por lo que
cambiar de fichero de información dependiendo del profesor seleccionado
por el alumno debería ser sencillo de implementar.
37
Bibliografía
[1] API Reference organized by resource type,
https://developers.google.com/google-apps/calendar/v3/
reference/
[2] Google API Offline Access Using OAuth 2.0 Refresh Token,
http://www.jensbits.com/2012/01/09/google-api-offline-accessusing-oauth-2-0-refresh-token/
[3] Google APIs Console Help,
https://developers.google.com/console/help/
[4] Google Apps Calendar API Concepts and Use Cases,
https://developers.google.com/google-apps/calendar/concepts
[5] Google Calendar API,
https://developers.google.com/google-apps/calendar/
[6] Google Calendar API Forum,
https://groups.google.com/forum/embed/?place=forum/
google-calendar-api#!forum/google-calendar-api
[7] Google Developers,
https://developers.google.com/
[8] HTML,
http://en.wikipedia.org/wiki/HTML
[9] Hypertext Transfer Protocol,
http://en.wikipedia.org/wiki/HTTP
[10] JSON,
http://www.json.org/json-es.html
[11] OAuth,
http://es.wikipedia.org/wiki/OAuth
[12] OAuth2 and Configuring Your ‘Application’ With Google,
http://cornempire.net/2012/01/08/part-2-oauth2-and-configuring-yourapplication-with-google/
39
40
Bibliografía
[13] PHP,
http://es.wikipedia.org/wiki/PHP
[14] PHP Documentation,
http://php.net/docs.php
[15] REST,
http://en.wikipedia.org/wiki/Representational_state_transfer
[16] Using OAuth 2.0 to Access Google APIs,
https://developers.google.com/accounts/docs/OAuth2
[17] Write your First Google App,
https://developers.google.com/google-apps/calendar/firstapp
[18] XAMPP,
http://es.wikipedia.org/wiki/XAMPP
Apéndice
A
Apéndices
A.1.
Apéndice I
Darse de alta proyectos en Google
A continuación se explicará cómo preparar el proyecto para el sistema de
reservas funcione con las API que ofrece Google. Se empezará visitando la
página web:
https://code.google.com/apis/console/
Figura A.1: Google APIs Console: Creación de un nuevo proyecto
41
42
Apéndices
Figura A.2: Google APIs Console: Página principal
Desde la página principal visitamos a la pestaña Services (servicios), donde se ha de buscar la API de Google Calendar y activarla (pulsando en el
interruptor de ’ON - OFF’).
Figura A.3: Google APIs Console: Lista de servicios de Google
A.1. Apéndice I
Figura A.4: Google APIs Console: Estado actual de la API de Google Calendar
43
44
Apéndices
Para activar las API relacionadas a Google Calendar habrá que aceptar
los términos del servicio.
Figura A.5: Google APIs Console: Términos de uso para permitir el uso de las API,
1º parte
Figura A.6: Google APIs Console: Términos de uso para permitir el uso de las API,
2º parte y última
A.1. Apéndice I
Figura A.7: Google APIs Console: Activación éxitosa de la API de Google Calendar
A continuación se tendrá que crear 2 identificaciones de cliente para OAuth
2.0 (OAuth 2.0 Client ID). Primero se creará la identificación destinada para
aplicaciones web (Web Application)
Figura A.8: Google APIs Console: Vista de la pestaña API Access (Acceso a la API)
45
46
Apéndices
En la ventana que aparecerá se podrá especificar el nombre del proyecto
que aparecerá cada vez que OAuth nos solicite permisos para trabajar sobre
datos privados. Se pulsará en siguiente para continuar con el proceso.
Figura A.9: Google APIs Console: Configuración del nuevo proyecto
Finalmente se tendrá que configurar la ID de cliente. En el tipo de aplicación (Application type) se seleccionará ’Aplicación web’ (Web application)
y la dirección del sitio web donde se utilizará el proyecto, en caso de trabajar
en un servidor web en local se escribirá ’localhost’. Para finalizar el proceso se
pulsará en Crear ID de cliente (Create client ID).
Figura A.10: Google APIs Console: Configuración de un Client ID para aplicaciones
web
A.1. Apéndice I
En la pestaña de Acceso a la API (API Access) aparecerá nuevos datos para
su uso por aplicaciens web. Para crear la segunda ID de cliente que necesita el
proyecto se pulsará el botón ’Crear otro ID de cliente’ (Create another client
ID).
Figura A.11: Google APIs Console: Vista de la pestaña API Access (Acceso a la API)
después de crear el primer ID de los 2 necesarios
47
48
Apéndices
Aparecerá de nuevo la ventana de configuración la ID de cliente pero en vez
de aplicación web se seleccionará ’Aplicación instalada’ (Installed application).
En el tipo de aplicación instalada se seleccionará la opción ’Otros’ (Other) y
se finalizará el proceso.
Figura A.12: Google APIs Console: Vista de la pestaña API Access (Acceso a la API)
después de crear el primer ID de los 2 necesarios
A.1. Apéndice I
Con los datos obtenidos en este apéndice se deberá de usar en el sistema
de reservas para que funcione el calendario del profesor. El resultado final de
todo el proceso será similar a la figura A.13.
Figura A.13: Google APIs Console: Vista de la pestaña API Access (Acceso a la API)
después de crear los 2 ID necesarios para el funcionamiento del sistema de reservas
49
50
Apéndices
A.2.
Apéndice II
Dar de alta la cuenta del profesor en el sistema de reservas
Para dar de alta al profesor en el sistema de reservas hay que realizar
previamente los pasos del Apéndice I y utilizar los datos que aparecen en las
secciones de la figura A.13) en una página de administración diseñada para
ese propósito (ver Figura A.14).
Figura A.14: Etapa inicial del proceso de alta del calendario del profesor en el sistema
de reservas
A.2. Apéndice II
Una vez generada una parte de los datos del tutor será posible autenticarse
en la página del sistema de reservas, pero aún no estará operativo porque
requiere que el profesor acceda a su cuenta y active el servicio, momento el
cual ya estará el servicio de reservas activo, finalizando el proceso de alta del
profesor (ver Figura A.15).
Figura A.15: Etapa final del proceso de alta del calendario del profesor en el sistema
de reservas
51
52
Apéndices
A.3.
Apéndice III
Demostración del sistema de reservas
A continuación se explicará en varios pasos cómo realizar una reserva para
asistir a las tutorías del profesor. El objetivo de la demostración será solicitar
una tutoría para un lunes 12 de noviembre para realizar una serie de cuestiones al profesor relacionadas con el temario de clase:
1. Inicialmente se accede a la página de prueba, pudiéndose observar los
elementos básicos de la web disponibles cuando no se ha accedido al sistema de reservas. Al ser la página en modo consulta en la parte inferior
se muestra un calendario que puede utilizarse para observar el calendario del profesor. En color verde aparecerá los horarios de tutorías y en
color rojo se mostrarán las reservas realizadas por los alumnos. A continuación, para avanzar con el proceso se pulsará en ’Entrar’ para iniciar
la autenticación con la cuenta del alumno de Google o de la UJI (ver
Figura A.16).
Figura A.16: Tutorial para crear reservas: Página inicial de pruebas del sistema de
reservas
A.3. Apéndice III
2. Se accede a la pantalla de autenticación de cuentas de Google (ver Figura A.17). Para continuar se indica el usuario y la contraseña y se pulsará
en ’Iniciar sesión’. Si se accede al sistema de reservas con una cuenta de
la universidad es probable encontrar un aviso como el de la figura A.18
para obligar la autenticación desde el servicio de la UJI. Pulsando en
’Continuar’ se procede a la siguiente pantalla. Si no se accede mediante
una cuenta de la universidad se omite el paso 3.
Figura A.17: Tutorial para crear reservas: Pantalla de autenticación de Google
Figura A.18: Tutorial para crear reservas: Aviso para obligar la autenticación desde
el servicio de la UJI
53
54
Apéndices
3. Una vez accedido a la página de autenticación de la UJI (ver Figura A.19) se ingresan los campos de usuario y contraseña y se pulsará el
botón ’Continuar’.
Figura A.19: Tutorial para crear reservas: Autenticación de la cuenta de usuario desde
la UJI
A.3. Apéndice III
4. Una vez autenticada la cuenta de usuario se procede a la autorización de
Google para el uso de datos privados en sus servicios (ver Figura A.20).
Para continuar se pulsa en ’Permitir acceso’, de lo contrario no se podrá
utilizar el sistema de reservas.
Figura A.20: Tutorial para crear reservas: Autorización de Google para el uso de datos
privados
55
56
Apéndices
5. Una vez se ha regresado a la página de reservas se selecciona la semana
a la que se va a realizar la reserva. En este ejemplo hay que desplazarse
hasta noviembre. Para ello se pulsa en los controles de navegación [Hoy]
[ ->] Ir a [ ... ] hasta llegar a la semana donde se necesita realizar la
reserva (ver Figura A.21).
Figura A.21: Tutorial para crear reservas: Página de prueba de reservas desde una
cuenta de usuario autenticada
A.3. Apéndice III
6. A continuación hay que buscar el día de tutorías donde se quiere realizar
la reserva, por si hay huecos libres (ver Figura A.22). En este caso en el
día 12 aún existe un hueco desde las 12:00 hasta las 13:00 para solicitar
la tutoría con el profesor.
Figura A.22: Tutorial para crear reservas: Mostrando reservas de la semana seleccionada
57
58
Apéndices
7. Se puede observar en la parte inferior de la página de forma gráfica las
reservas que existen para esa semana antes de la creación de la reserva
(ver Figura A.23).
Figura A.23: Tutorial para crear reservas: Vista gráfica del calendario de tutorías. En
rojo aparecen las reservas existentes
A.3. Apéndice III
8. Como no se cree necesario que haga falta reservar la hora entera para que
el profesor solucione todas las dudas se selecciona el tiempo de reserva
mínimo que acepta el sistema de reservas y se especifica la razón de la
reserva (ver Figura A.24). De esta manera el profesor podrá conocer la
razón de la tutoría con antelación y prepararse si fuera necesario. Para
dar de alta la reserva se pulsa sobre ’Reservar hora’.
Figura A.24: Tutorial para crear reservas: Preparando la reserva
59
60
Apéndices
9. Finalmente la nueva reserva estará visible tanto en la lista de reservas
de esa semana (ver Figura A.25) como en la vista gráfica de la parte
inferior de la página de reservas (ver Figura A.26).
Figura A.25: Tutorial para crear reservas: Mostrando reservas de la semana seleccionada tras la creación de una nueva reserva
Figura A.26: Tutorial para crear reservas: Vista gráfica del calendario de tutorías
después de reservar tiempo de tutorías del profesor
A.3. Apéndice III
10. Si por alguna razón ha ocurrido alguna confusión con la fecha de la
reserva, se prefiere cambiar la hora a otra más apropiada para el alumno
o ya no se quiere asistir a la tutoría del profesor el alumno podrá anular
sus propias reservas. Para realizar esa acción se pulsará en el botón
’Cancelar’ de la reserva que se desea anular (ver Figura A.25). Tras
la operación se retornará el espacio de tiempo ocupado por la reserva
al sistema, dejando la posibilidad de realizar nuevas reservas a nuevos
alumnos (ver Figura A.27).
Figura A.27: Tutorial para crear reservas: Mostrando reservas de la semana seleccionada (tras eliminación de reserva)
61
62
Apéndices
A.4.
Apéndice IV
Código fuente de other_functions.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
// F u n c i o n e s de ambito g e n e r a l
// Dado un rango de h o r a s para t u t o r i a s y una l i s t a de r e s e r v a s ←d e v u e l v e una m a t r i z con l a s h o r a s l i b r e s .
// Cada e l e m e n t o de l a m a t r i z t e n d r a una m a t r i z de 2 e l e m e n t o s , con ←l a s h o r a s de i n i c i o y f i n d e l hueco l i b r e e n c o n t r a d o .
function f i n d F r e e B o o k S l o t s ( $startDate , $endDate , $bookedSlots )
{
// S o l o s e va a t r a b a j a r con l a s h o r a s .
$startTime = s t r t o t i m e ( $startDate ) ;
$endTime = s t r t o t i m e ( $endDate ) ;
$freeSlotList = a r r a y ( ) ;
$i = 0 ;
// En c a s o de r e c i b i r l a l i s t a de r e s e r v a s de todo e l d i a s e ←f i l t r a r a a q u e l l a s r e s e r v a s a n t e r i o r e s a l a hora de i n i c i o ←deseada .
w h i l e ( i s s e t ( $bookedSlots [ $i ] ) && s t r t o t i m e ( $bookedSlots [ $i]−>end ←−>dateTime ) <= s t r t o t i m e ( $startDate ) )
{
$i++;
}
$start = $startTime ;
// Se a n a l i z a e l h o r a r i o en e s p a c i o s de 30 minutos .
w h i l e ( $start < $endTime )
{
i f ( i s s e t ( $bookedSlots [ $i ] ) && $start >= s t r t o t i m e ( ←$bookedSlots [ $i]−>start−>dateTime ) && $start < s t r t o t i m e ( ←$bookedSlots [ $i]−>end−>dateTime ) )
{
// Se e v i t a n l a s h o r a s r e s e r v a d a s
i f ( $start >= s t r t o t i m e ( $bookedSlots [ $i]−>start−>dateTime ) ←&& $start < s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime←))
{
$start = s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime ) ;
}
$i++;
}
else
{
// Se a v e r i g u a e l rango de h o r a s d e l hueco l i b r e ←encontrado
$end = $start ;
i f ( i s s e t ( $bookedSlots [ $i ] ) )
{
w h i l e ( $end < $endTime && $end < s t r t o t i m e ( ←$bookedSlots [ $i]−>start−>dateTime ) )
{
$end = $end + ( 3 0 ∗ 6 0 ) ;
}
A.4. Apéndice IV
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}
else
{
}
}
}
}
63
w h i l e ( $end < $endTime )
{
$end = $end + ( 3 0 ∗ 6 0 ) ;
}
$freeSlotList [ ] = a r r a y ( d a t e ( "Y−m−d\TH: i : s \Z " , $start ) , ←d a t e ( "Y−m−d\TH: i : s \Z " , $end ) ) ;
$start = $end ;
return $freeSlotList ;
// Dado un rango de h o r a s para t u t o r i a s y una l i s t a de r e s e r v a s ←d e v u e l v e una m a t r i z con l a s h o r a s l i b r e s y l a s h o r a s ocupadas por ←reservas .
// Cada e l e m e n t o de l a m a t r i z que s e a una r e s e r v a t e n d r a una c o p i a d e l ←e l e m e n t o o r i g i n a l y cada hueco l i b r e s e r a una m a t r i z de 2 ←e l e m e n t o s , con l a s h o r a s de i n i c i o y f i n d e l hueco l i b r e ←encontrado .
function findAllSlots ( $startDate , $endDate , $bookedSlots )
{
// S o l o s e va a t r a b a j a r con l a s h o r a s .
$startTime = s t r t o t i m e ( $startDate ) ;
$endTime = s t r t o t i m e ( $endDate ) ;
$freeSlotList = a r r a y ( ) ;
$i = 0 ;
// En c a s o de r e c i b i r l a l i s t a de r e s e r v a s de todo e l d i a s e ←f i l t r a r a a q u e l l a s r e s e r v a s a n t e r i o r e s a l a hora de i n i c i o ←deseada .
w h i l e ( i s s e t ( $bookedSlots [ $i ] ) && s t r t o t i m e ( $bookedSlots [ $i]−>end ←−>dateTime ) <= s t r t o t i m e ( $startDate ) )
{
$i++;
}
$start = $startTime ;
// Se a n a l i z a e l h o r a r i o en e s p a c i o s de 30 minutos .
w h i l e ( $start < $endTime )
{
i f ( i s s e t ( $bookedSlots [ $i ] ) && $start >= s t r t o t i m e ( ←$bookedSlots [ $i]−>start−>dateTime ) && $start < s t r t o t i m e ( ←$bookedSlots [ $i]−>end−>dateTime ) )
{
// Se e v i t a n l a s h o r a s r e s e r v a d a s
i f ( $start >= s t r t o t i m e ( $bookedSlots [ $i]−>start−>dateTime ) ←&& $start < s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime←))
{
$freeSlotList [ ] = $bookedSlots [ $i ] ;
$start = s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime ) ;
}
$i++;
}
64
Apéndices
94
95
96
else
{
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
}
}
}
// Se a v e r i g u a e l rango de h o r a s d e l hueco l i b r e ←encontrado
$end = $start ;
i f ( i s s e t ( $bookedSlots [ $i ] ) )
{
w h i l e ( $end < $endTime && $end < s t r t o t i m e ( ←$bookedSlots [ $i]−>start−>dateTime ) )
{
$end = $end + ( 3 0 ∗ 6 0 ) ;
}
}
else
{
w h i l e ( $end < $endTime )
{
$end = $end + ( 3 0 ∗ 6 0 ) ;
}
}
$freeSlotList [ ] = a r r a y ( d a t e ( "Y−m−d\TH: i : s \Z " , $start ) , ←d a t e ( "Y−m−d\TH: i : s \Z " , $end ) ) ;
$start = $end ;
return $freeSlotList ;
// Dado un rango de h o r a s que queremos a n a l i z a r y una l i s t a de ←r e s e r v a s d e v u e l v e v e r d a d e r o s i e l rango de h o r a s a n a l i z a d a s e s t a ←l i b r e de r e s e r v a s , f a l s o en c a s o c o n t r a r i o .
function isFree BookSlot ( $startDate , $endDate , $bookedSlots )
{
d a t e _ d e f a u l t _ t i m e z o n e _ s e t ( " Europe / Madrid " ) ;
$start = s t r t o t i m e ( $startDate ) ;
$end = s t r t o t i m e ( $endDate ) ;
$i = 0 ;
// En c a s o de r e c i b i r l a l i s t a de r e s e r v a s de todo e l d i a s e ←f i l t r a r a a q u e l l a s r e s e r v a s a n t e r i o r e s a l a hora de i n i c i o ←deseada .
w h i l e ( i s s e t ( $bookedSlots [ $i ] ) && s t r t o t i m e ( $bookedSlots [ $i]−>end ←−>dateTime ) <= s t r t o t i m e ( $startDate ) )
{
$i++;
}
// Se a n a l i z a e l h o r a r i o en e s p a c i o s de 30 minutos .
w h i l e ( $start < $end && $i < count ( $bookedSlots ) )
{
i f ( i s s e t ( $bookedSlots [ $i ] ) )
{
// S i l a s hora a n a l i z a d a e s t a r e s e r v a d a s e a b o r t a e l ←proceso
i f ( $start >= s t r t o t i m e ( $bookedSlots [ $i]−>start−>dateTime ) ←&& $start < s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime←))
{
return f a l s e ;
}
A.4. Apéndice IV
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
65
$start = $start + ( 3 0 ∗ 6 0 ) ;
}
else
{
}
}
}
i f ( s t r t o t i m e ( $bookedSlots [ $i]−>end−>dateTime ) <= $start )
{
$i++;
}
return t r u e ;
return t r u e ;
// Dado un rango de h o r a s que queremos a n a l i z a r y una l i s t a de h o r a s ←de t u t o r i a s d e v u e l v e v e r d a d e r o s i e l rango de h o r a s a n a l i z a d a s ←e s t a d e n t r o de a l g u n a t u t o r i a , f a l s e en c a s o c o n t r a r i o .
function i sV a li dB oo k Sl ot ( $startDate , $endDate , $tut oringSlo ts )
{
d a t e _ d e f a u l t _ t i m e z o n e _ s e t ( " Europe / Madrid " ) ;
$start = s t r t o t i m e ( $startDate ) ;
$end = s t r t o t i m e ( $endDate ) ;
$i = 0 ;
// En c a s o de r e c i b i r l a l i s t a de t u t o r i a s de todo e l d i a s e ←f i l t r a r a a q u e l l a s r e s e r v a s a n t e r i o r e s a l a hora de i n i c i o ←deseada .
w h i l e ( i s s e t ( $tut oringSlo ts [ $i ] ) && s t r t o t i m e ( $tut oringSlo ts [ $i]−>←end−>dateTime ) <= s t r t o t i m e ( $startDate ) )
{
$i++;
}
// Se a n a l i z a e l h o r a r i o en e s p a c i o s de 30 minutos .
w h i l e ( $start < $end )
{
i f ( i s s e t ( $tut oringSlo ts [ $i ] ) )
{
// S i l a s hora a n a l i z a d a e s t a r e s e r v a d a s e a b o r t a e l ←proceso
i f ( $start >= s t r t o t i m e ( $tut oringSlo ts [ $i]−>start−>←dateTime ) && $start < s t r t o t i m e ( $tuto ringSlot s [ $i]−>←end−>dateTime ) )
{
}
else
{
}
}
else
$start = $start + ( 3 0 ∗ 6 0 ) ;
return f a l s e ;
i f ( s t r t o t i m e ( $tut oringSlo ts [ $i]−>end−>dateTime ) <= $start←)
{
$i++;
}
66
Apéndices
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
{
}
}
}
return f a l s e ;
return t r u e ;
function s o r t T u t o r i n g _ h o u r s ( $ tu to ri n g_ ho ur s )
{
// L i s t a c o m p l e t a de t u t o r i a s de l a semana
i f ( ! i s s e t ( $tutoring_hours−>items ) )
{
return ;
}
f o r ( $i = 0 ; $i < count ( $tutoring_hours−>items ) ; $i++)
{
$str CurrentD ay = d a t e ( "w" , s t r t o t i m e ( $tutoring_hours−>items [ $i←]−>start−>dateTime ) ) ;
}
}
$tutoringList [ $str CurrentD ay ] [ ] = $tutoring_hours−>items [ $i ] ;
return $tutoringList ;
function sortBo ok_hours ( $book_hours )
{
// L i s t a de r e s e r v a s de l a semana
f o r ( $i = 0 ; $i < 7 ; $i++)
{
$bookList [ $i ] = a r r a y ( ) ;
}
i f ( i s s e t ( $book_hours−>items ) )
{
f o r ( $i = 0 ; $i < count ( $book_hours−>items ) ; $i++)
{
$str CurrentD ay = d a t e ( "w" , s t r t o t i m e ( $book_hours−>items [ $i←]−>start−>dateTime ) ) ;
}
}
}
$bookList [ $str CurrentD ay ] [ ] = $book_hours−>items [ $i ] ;
return $bookList ;
// Dada una f e c h a c o m p l e t a en f o r m a t o UTC cambia unicamente l a zona ←horaria sin modificar la fecha .
function U T C _ t i m e Z o n e R e p l a c e r ( $oldDate )
{
d a t e _ d e f a u l t _ t i m e z o n e _ s e t ( " Europe / Madrid " ) ;
$newDate = s t r t o t i m e ( gmdate ( " d−m−Y\TH: i : s " , s t r t o t i m e ( $oldDate ) ) ) ;
$newDate = d a t e ( " d−m−Y\TH: i : sP " , $newDate ) ;
}
return $newDate ;
// Devuelve t r u e s i l a f e c h a de e n t r a d a e s a n t e r i o r a l a f e c h a a c t u a l ←y f a l s e en c a s o c o n t r a r i o .
A.4. Apéndice IV
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
function isOldEvent ( $selectedDate , $format = "Y−m−d\TH: i " )
{
i f ( s t r t o t i m e ( d a t e ( $format , s t r t o t i m e ( $selectedDate ) ) ) >= ←s t r t o t i m e ( d a t e ( $format ) ) )
{
return f a l s e ;
}
}
// Dado un rango de h o r a s de i n i c i o y f i n s e c r e a l o s c o n t r o l e s HTML5 ←que a p a r e c e r a n en e l l u g a r donde s e ha r e a l i z a d o l a l l a m a d a a e s t a ←f u n c i o n . Las l i s t a s d e s p l e g a b l e s c o n t i e n e n h o r a s v a l i d a s para ←realizar reservas .
function d r a w N e w B o o k B u t t o n ( $start , $end )
{
w h i l e ( isOldEvent ( gmdate ( "Y−m−d\TH: i " , $start ) ) )
{
$start += ( 3 0 ∗ 6 0 ) ;
}
$n = ( $end − $start ) / ( 3 0 ∗ 6 0 ) ;
i f ( $n <= 0 )
{
return " " ;
}
$aux = $start ;
$temp = '<i n p u t t y p e =" bu tt on " v a l u e =" R e s e r v a r hora " o n c l i c k ="←createNewBook ( \ ' ' . $start . '_ ' . $end . ' \ ' ) " /> I n i c i o : < s e l e c t i d ←="from_ ' . $start . '_ ' . $end . ' " onChange="checkBookTimes ( \ ' from_ ' . ←$start . '_ ' . $end . ' \ ' , \ ' to_ ' . $start . '_ ' . $end . ' \ ' ) "> ' ;
282
283
284
285
f o r ( $i = 0 ; $i < $n ; $i++)
{
$temp .= '<o p t i o n v a l u e = " ' . $aux . ' "> ' . gmdate ( "H: i " , $aux ) . '</←option>' ;
$aux += ( 3 0 ∗ 6 0 ) ;
}
$temp .= '</ s e l e c t > ' ;
286
287
288
289
290
$temp .= ' − Fin : < s e l e c t i d ="to_ ' . $start . '_ ' . $end . ' " onChange="←checkBookTimes ( \ ' from_ ' . $start . '_ ' . $end . ' \ ' , \ ' to_ ' . $start . '_ ' ←. $end . ' \ ' ) "> ' ;
$aux = $start + ( 3 0 ∗ 6 0 ) ;
291
292
293
294
295
f o r ( $i = 0 ; $i < $n ; $i++)
{
$temp .= '<o p t i o n v a l u e =" ' . $aux . ' "> ' . gmdate ( "H: i " , $aux ) . '</←option>' ;
$aux += ( 3 0 ∗ 6 0 ) ;
}
$temp .= '</ s e l e c t > <i n p u t t y p e =" t e x t " i d ="desc_ ' . $start . '_ ' . $end . ←' " p l a c e h o l d e r =" I n d i c a l a r a z o n de l a r e s e r v a " s i z e =50 /> ' ;
296
297
298
299
300
301
302
303
return t r u e ;
}
return $temp ;
// Dado un i d e n t i f i c a d o r de e v e n t o para Google C a l e n d a r s e c r e a l o s ←c o n t r o l e s HTML5 que a p a r e c e r a n en e l l u g a r donde s e ha r e a l i z a d o ←l a l l a m a d a a e s t a f u n c i o n . El boton de C a n c e l a r s i r v e para ←-
67
68
Apéndices
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
e l i m i n a r una r e s e r v a d e l c a l e n d a r i o de r e s e r v a s d e l Tutor .
function d r a w Ca n c e l B u t t o n ( $event_id )
{
return '<i n p u t t y p e =" bu tt on " v a l u e =" C a n c e l a r " o n c l i c k =" d e l e t e B o o k ←( \ ' ' . $event_id . ' \ ' ) " /><i n p u t t y p e =" h id de n " name="eid_ ' . ←$event_id . ' " i d ="eid_ ' . $event_id . ' " v a l u e =" ' . $event_id . ' " /> ' ;
}
// Anadir b o t o n e s de n a v e g a c i o n para d e s p l a z a r s e e n t r e l a s semanas d e l ←c a l e n d a r i o . Para su c o r r e c t o f u n c i o n a m i e n t o r e q u i e r e implementar ←l a f u n c i o n de J a v a s c r i p t l o a d U r l ( ) , e j e m p l o de c o d i g o :
// < s c r i p t t y p e =" t e x t / j a v a s c r i p t ">
// f u n c t i o n l o a d U r l ( l o c a t i o n )
// {
//
window . l o c a t i o n . h r e f = l o c a t i o n ;
// }
//</ s c r i p t >
function d r a w W e e k B r o w s e r B u t t o n s ( $week_selected , $yea r_select ed )
{
i f ( ! i s s e t ( $wee k_select ed ) | | ! i s s e t ( $yea r_select ed ) )
{
return ' ' ;
}
$yea r_select ed = d a t e ( 'Y ' ) ;
i f ( $wee k_select ed < ( d a t e ( 'W' ) − 1 ) )
{
// En c a s o de s o l i c i t a r semanas a n t e r i o r e s a l a a c t u a l s e ←devuelve la actual .
$wee k_select ed = d a t e ( 'W' ) − 1 ;
}
w h i l e ( $wee k_select ed > 5 1 )
{
$wee k_select ed −= 5 2 ;
$yea r_select ed++;
}
$temp = '<i n p u t t y p e =" bu tt on " v a l u e ="Hoy " o n c l i c k =" l o a d U r l ( \ ' ' . ←h t m l e n t i t i e s ( $_SERVER [ 'PHP_SELF ' ] ) . ' \ ' ) ; " /> ' ;
i f ( $wee k_select ed > ( d a t e ( "W" ) − 1 ) )
{
$temp .= '<i n p u t t y p e =" bu tt on " v a l u e ="<" o n c l i c k =" l o a d U r l ( \ ' ' . ←h t m l e n t i t i e s ( $_SERVER [ 'PHP_SELF ' ] ) . ' ? week= ' . ( ←$week _selecte d ) . ' \ ' ) ; " /> ' ;
}
$temp .= '<i n p u t t y p e =" bu tt on " v a l u e =">" o n c l i c k =" l o a d U r l ( \ ' ' . ←h t m l e n t i t i e s ( $_SERVER [ 'PHP_SELF ' ] ) . ' ? week= ' . ( $week _selecte d + ←2 ) . ' \ ' ) ; " /> ' ;
$temp .= ' I r a : < s e l e c t onChange=" l o a d U r l ( \ ' ' . h t m l e n t i t i e s ( ←$_SERVER [ 'PHP_SELF ' ] ) . ' ? week =\ ' + t h i s . o p t i o n s [ t h i s . ←s e l e c t e d I n d e x ] . v a l u e ) ;" > ' ;
$strMonthDays = a r r a y ( 1 => " Enero " , 2 => " F e b r e r o " , 3 => " Marzo " , ←4 => " A b r i l " , 5 => " Mayo " , 6 => " J u n i o " , 7 => " J u l i o " , 8 => " ←Agosto " , 9 => " S e p t i e m b r e " , 10 => " Octubre " , 11 => " Noviembre " ←, 12 => " D i c i e m b r e " ) ;
$aux_date = d a t e ( " c " ) ;
A.4. Apéndice IV
350
351
352
353
354
f o r ( $i = 0 ; $i < 1 2 ; $i++)
{
$year = ( d a t e ( "Y" , s t r t o t i m e ( $aux_date ) ) ) ;
$month = d a t e ( " n " , s t r t o t i m e ( $aux_date ) ) ;
$week_index = d a t e ( "W" , s t r t o t i m e ( $aux_date ) ) + ( 5 2 ∗ ( d a t e ( "Y←" , s t r t o t i m e ( $aux_date ) ) − d a t e ( "Y" ) ) ) ;
355
356
$temp .= '<o p t i o n v a l u e =" ' . $week_index . ' "> ' . $strMonthDays [ ←$month ] . ' , ' . $year . '</o p t i o n > ' ;
357
358
359
360
361
362
363
364
365
366
367
368
// Apuntando a l s i g u i e n t e mes
$wk_ts = s t r t o t i m e ( $year . d a t e ( "m" , s t r t o t i m e ( $aux_date ) ) . ' 01 ' ) ←;
$mon_ts = s t r t o t i m e ( '+1 month ' , $wk_ts ) ;
$aux_date = d a t e ( " c " , $mon_ts ) ;
}
$temp .= '</ s e l e c t > ' ;
}
?>
return $temp ;
69
70
Apéndices
Código fuente de: calendar_userlogin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
// Nota : a l g u n a s f u n c i o n e s r e q u i e r e n l a s l i b r e r i a s para a c c e d e r a l a s ←API de Google . Hay que d e s c a r g a r l o de l a s i g u i e n t e URL:
// h t t p : / / code . g o o g l e . com/p/ g o o g l e −api −php−c l i e n t /
if
{
}
if
{
}
( ! session_id () )
session_start () ;
( ! i s s e t ( $calendarOwnerFile ) )
$calendarOwnerFile = ' ' ;
i f ( i s s e t ( $ c a l e n d a r O w n e r F i l e ) && s t r l e n ( $ c a l e n d a r O w n e r F i l e ) > 0 && ←f i l e _ e x i s t s ( " $ c a l e n d a r O w n e r F i l e . php " ) )
{
include_once ( " $ c a l e n d a r O w n e r F i l e . php " ) ;
i f ( i s s e t ( $_GET [ ' s t a t e ' ] ) && $_GET [ ' s t a t e ' ] == " p r o f i l e " )
{
// Se p r o c e d e a l a a u t e n t i c a c i o n d e s a t e n d i d a d e l t u t o r para l a ←c a r g a d e l c a l e n d a r i o de r e s e r v a s .
include_once ( " c a l e n d a r _ a u t o l o g i n . php " ) ;
}
}
else
{
d i e ( " E r r o r : ' $ c a l e n d a r O w n e r F i l e . php ' no e x i s t e o no s e puede ←a c c e d e r . No s e puede c o n t i n u a r con e l p r o c e s o .< br />" ) ;
}
require_once ' . / s r c / a p i C l i e n t . php ' ;
$client = new apiClient ( ) ;
$client−>setScopes ( $ u s e r l o g i n _ sc o p e ) ;
$client−>setClientId ( $ u s e r l o g i n _ c l i e n t _ i d ) ;
$client−>s et Cl ie n tS ec re t ( $ u s e r l o g i n _ c l i e n t _ s e c r e t ) ;
$client−>setR edirectU ri ( $ u s e r l o g i n _ r e d i r e c t _ u r i ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
i f ( i s s e t ( $_REQUEST [ ' l o g o u t ' ] ) )
{
u n s e t ( $_SESSION [ ' u s e r l o g i n ' ] ) ;
u n s e t ( $_SESSION [ ' a c c e s s _ t o k e n ' ] ) ;
}
i f ( i s s e t ( $_GET [ ' code ' ] ) )
{
$client−>authenticate ( ) ;
$_SESSION [ ' a c c e s s _ t o k e n ' ] = $client−>getA ccessToke n ( ) ;
h e a d e r ( ' L o c a t i o n : h t t p : / / ' . $_SERVER [ 'HTTP_HOST ' ] . $_SERVER [ ' ←PHP_SELF ' ] ) ;
}
i f ( i s s e t ( $_SESSION [ ' a c c e s s _ t o k e n ' ] ) )
A.4. Apéndice IV
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
{
}
$client−>setA ccessTok en ( $_SESSION [ ' a c c e s s _ t o k e n ' ] ) ;
i f ( $client−>getA ccessTok en ( ) )
{
$_SESSION [ ' a c c e s s _ t o k e n ' ] = $client−>getA ccessTok en ( ) ;
}
else
{
}
$ us er lo g in _d on e = t r u e ;
$authUrl = $client−>createAuthUrl ( ) ;
$ us er lo g in _d on e = f a l s e ;
// −−−−−−−−−−−−−−−−−−−−−−−− FUNCIONES ESENCIALES ←−−−−−−−−−−−−−−−−−−−−−−−−
function getAcc essToken ( $jsonText )
{
$responseObj = json_decode ( $jsonText ) ;
// s u b s t r
i f ( i s s e t ( $responseObj−>access_token ) )
{
return $responseObj−>access_token ;
}
}
return " " ;
function g et R ef re sh T ok en ( $jsonText )
{
$responseObj = json_decode ( $jsonText ) ;
// s u b s t r
i f ( i s s e t ( $responseObj−>refresh_token ) )
{
return $responseObj−>refresh_token ;
}
}
return " " ;
// I n f o r m a c i o n b a s i c a d e l u s u a r i o a u t e n t i c a d o
function g e t C l i e n t U s e r I n f o ( $ j s o n _ a c c e s s T o k e n )
{
$accessToken = json_decode ( $ j s o n _ a c c e s s T o k e n ) ;
$accessToken = $accessToken−>access_token ;
$query = " h t t p s : / /www. g o o g l e a p i s . com/ oauth2 / v1 / u s e r i n f o ?←a c c e s s _ t o k e n=" . $accessToken ;
$curl = c u r l _ i n i t ( $query ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_HTTPAUTH , CURLAUTH_ANY ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_RETURNTRANSFER , 1 ) ;
$curlheader [ 0 ] = " A u t h o r i z a t i o n : B e a r e r " . $accessToken ;
c u r l _ s e t o p t ( $curl , CURLOPT_HTTPHEADER , $curlheader ) ;
$jso n_respon se = c u r l _ e x e c ( $curl ) ;
c u r l _ c l o s e ( $curl ) ;
$responseObj = json_decode ( $jso n_respon se ) ;
71
72
Apéndices
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
return $responseObj ;
}
?>
// Devuelve l a s i g u i e n t e i n f o r m a c i o n :
/∗
{
" i d " : "##################",
" e m a i l " : "############@gmail . com " ,
" v e r i f i e d _ e m a i l " : true ,
" name " : " nombre a p e l l i d o 1 " ,
" given_name " : " nombre " ,
" family_name " : " a p e l l i d o 1 " ,
" l i n k " : " h t t p s : / / p l u s . g o o g l e . com/#########",
" g e n d e r " : " male " ,
" b i r t h d a y " : "0000 −08 −08" ,
" l o c a l e " : " es "
}
∗/
A.4. Apéndice IV
Código fuente de: calendar_autologin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
// Nota : a l g u n a s f u n c i o n e s r e q u i e r e n l a s l i b r e r i a s para a c c e d e r a l a s ←API de Google . Hay que d e s c a r g a r l o de l a s i g u i e n t e URL:
// h t t p : / / code . g o o g l e . com/p/ g o o g l e −api −php−c l i e n t /
// DATOS NECESARIOS DEL TUTOR
$tokenFileExt = ' . r t o k e n ' ;
i f ( ! i s s e t ( $calendarOwnerFile ) )
{
$calendarOwnerFile = ' ' ;
}
i f ( i s s e t ( $ c a l e n d a r O w n e r F i l e ) && s t r l e n ( $ c a l e n d a r O w n e r F i l e ) > 0 && ←f i l e _ e x i s t s ( " $ c a l e n d a r O w n e r F i l e . php " ) )
{
include_once ( " $ c a l e n d a r O w n e r F i l e . php " ) ;
}
else
{
}
d i e ( " E r r o r : ' $ c a l e n d a r O w n e r F i l e . php ' no e x i s t e o no s e puede ←a c c e d e r . No s e puede c o n t i n u a r con e l p r o c e s o .< br />" ) ;
// F i n a l malo
// A u t o r i z a c i o n i n i c i a l de l a c u e n t a d e l t u t o r . Para t e n e r a c c e s o por ←e l u s u a r i o s e r e t o r n a e l parametro URL
$accessToken = ' ' ;
i f ( i s s e t ( $_REQUEST [ ' code ' ] ) )
{
// A u t o r i z a c i o n i n i c i a l de l a c u e n t a d e l t u t o r . F u t u r o s a c c e s o s no←n e c e s i t a r a c o n f i r m a c i o n i n t e r a c t i v a h a s t a que s e e l i m i n e e l ←f i c h e r o a s o c i a d o a l t u t o r con e l " r e f r e s h t o k e n " v a l i d o .
$accessToken = g e t _ o a u t h 2 _ to k e n ( $_REQUEST [ ' code ' ] , " o n l i n e " ) ;
i f ( s t r l e n ( $ t u t o r i n g _ c a l e n d a r _ i d ) == 0 | | s t r l e n ( $ b o o k _ c a l e n d a r _ i d ←) == 0 )
{
$tutoring_calendar_id = insertNewTutoringCalendar ( ) ;
$book_calendar_id = insertNewBookingCalendar ( ) ;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$refreshToken = r e a d _ c a l e n d a r O w n e r _ t o k e n ( " ←$calendarOwnerFile$tokenFileExt " ) ;
}
}
if
{
}
f i l l _ c a l e n d a r O w n e r _ c o n f i g ( " $ c a l e n d a r O w n e r F i l e . php " ) ;
// Limpiar l a URL
h e a d e r ( ' L o c a t i o n : h t t p : / / ' . $_SERVER [ 'HTTP_HOST ' ] . $_SERVER [ ' ←PHP_SELF ' ] ) ;
( ! ( i s s e t ( $accessToken ) && s t r l e n ( $accessToken ) > 1 ) )
$accessToken = g e t _ o a u t h 2 _ to k e n ( $refreshToken , " o f f l i n e " ) ;
73
74
Apéndices
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
i f ( s t r l e n ( $accessToken ) == 0 | | ! ( i s s e t ( $ t u t o r i n g _ c a l e n d a r _ i d ) && ←i s s e t ( $ b o o k _ c a l e n d a r _ i d ) && s t r l e n ( $ t u t o r i n g _ c a l e n d a r _ i d ) > 0 && ←s t r l e n ( $book_calendar_id ) > 0) )
{
$ au to lo g in _d on e = f a l s e ;
}
else
{
$ j s o n _ a c c e s s T o k e n = ' { " a c c e s s _ t o k e n " : " ' . $accessToken . ' " , " ←token_type " : " B e a r e r " , " e x p i r e s _ i n " : 3 6 0 0 , " c r e a t e d " : 1 , " ←r e f r e s h _ t o k e n " : " ' . $refreshToken . ' " } ' ;
echo "<br />" ;
}
i f ( s t r l e n ( $accessToken ) != 0 )
{
$ au to lo g in _d on e = t r u e ;
}
else
{
$ au to lo g in _d on e = f a l s e ;
}
// −−−−−−−−−−−−−−−−−−−−−−−− FUNCIONES ESENCIALES ←−−−−−−−−−−−−−−−−−−−−−−−−
// Devuelve e l un s t r i n g l l a m a d o " A c c e s s Token " que s e r v i r a como ←c o d i g o de a u t o r i z a c i o n para r e a l i z a r l l a m a d a s a l a API usando ←OAuth 2 .
// Dependiendo l o s p a r a m e t r o s y de l a s i t u a c i o n donde s e u s e podra ←o b t e n e r un " R e f r e s h Token " que s e a l m a c e n a r a en un f i c h e r o para ←f u t u r o s u s o s d e l s i s t e m a de r e s e r v a s .
function send_g et_query ( $query , $aToken )
{
$curl = c u r l _ i n i t ( $query ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_HTTPAUTH , CURLAUTH_ANY ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
c u r l _ s e t o p t ( $curl , CURLOPT_RETURNTRANSFER , 1 ) ;
$curlheader [ 0 ] = " A u t h o r i z a t i o n : B e a r e r " . $aToken ;
c u r l _ s e t o p t ( $curl , CURLOPT_HTTPHEADER , $curlheader ) ;
$jso n_respon se = c u r l _ e x e c ( $curl ) ;
c u r l _ c l o s e ( $curl ) ;
$responseObj = json_decode ( $jso n_respon se ) ;
}
return $responseObj ;
// Lee de un f i c h e r o un s t r i n g que e s e l " r e f r e s h \ _token " a s o c i a d o a l ←c a l e n d a r i o d e l t u t o r . En c a s o de no poder l e e r c o r r e c t a m e n t e e l ←f i c h e r o d e v o l v e r a una cadena v a c i a .
function r e a d _ c a l e n d a r O w n e r _ t o k e n ( $ c a l O w n e r F i l e N a m e )
{
i f ( f i l e _ e x i s t s ( $calOwnerFileName ) )
{
$oFile = f o p e n ( $calOwnerFileName , ' r ' ) or d i e ( " E r r o r : ' ←$calOwnerFileName ' e x i s t e p e r o no s e puede a c c e d e r a su ←c o n t e n i d o .< br />" ) ;
$tokenStr = f r e a d ( $oFile ,
f i l e s i z e ( $calOwnerFileName ) ) ;
A.4. Apéndice IV
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
75
f c l o s e ( $oFile ) ;
}
else
{
}
}
return $tokenStr ;
return ' ' ;
// S a l v a a un f i c h e r o un s t r i n g que e s e l " r e f r e s h \ _token " a s o c i a d o a l ←calendario del tutor .
function w r i t e _ c a l e n d a r O w n e r _ t o k e n ( $calOwnerFileName , $tokenStr )
{
$oFile = f o p e n ( $calOwnerFileName , 'w ' ) or d i e ( " E r r o r : No s e puede ←a b r i r e l f i c h e r o ' $calOwnerFileName ' para e s c r i t u r a .< br />" ) ;
fwrite ( $oFile , $tokenStr ) ;
}
f c l o s e ( $oFile ) ;
// Devuelve e l un s t r i n g l l a m a d o " A c c e s s Token " que s e r v i r a como ←c o d i g o de a u t o r i z a c i o n para r e a l i z a r l l a m a d a s a l a API usando ←OAuth 2 .
// Dependiendo l o s p a r a m e t r o s y de l a s i t u a c i o n donde s e u s e podra ←o b t e n e r un " R e f r e s h Token " que s e a l m a c e n a r a en un f i c h e r o para ←f u t u r o s u s o s d e l s i s t e m a de r e s e r v a s .
function g e t _ oa u t h 2 _ t o k e n ( $grantCode , $grantType )
{
global $client_id ;
global $clien t_secret ;
global $redirect_uri ;
global $ c a l e n d a r O w n e r F i l e ;
global $tokenFileExt ;
$ o a u t h 2 t o k e n _u r l = " h t t p s : / / a c c o u n t s . g o o g l e . com/ o / oauth2 / t o k e n " ;
$clienttoken_post = array (
" c l i e n t _ i d " => $client_id ,
" c l i e n t _ s e c r e t " => $cli ent_secr et
);
i f ( $grantType === " o n l i n e " )
{
$ c l i e n t t o k e n _ p o s t [ " code " ] = $grantCode ;
$ c l i e n t t o k e n _ p o s t [ " r e d i r e c t _ u r i " ] = $redirect_uri ;
$ c l i e n t t o k e n _ p o s t [ " grant_type " ] = " a u t h o r i z a t i o n _ c o d e " ;
}
i f ( $grantType === " o f f l i n e " )
{
$ c l i e n t t o k e n _ p o s t [ " r e f r e s h _ t o k e n " ] = $grantCode ;
$ c l i e n t t o k e n _ p o s t [ " grant_type " ] = " r e f r e s h _ t o k e n " ;
}
$curl = c u r l _ i n i t ( $ o a u t h 2 t o k e n_ u r l ) ;
c u r l _ s e t o p t ( $curl
c u r l _ s e t o p t ( $curl
c u r l _ s e t o p t ( $curl
c u r l _ s e t o p t ( $curl
,
,
,
,
CURLOPT_POST , t r u e ) ;
CURLOPT_POSTFIELDS , $ c l i e n t t o k e n _ p o s t ) ;
CURLOPT_HTTPAUTH , CURLAUTH_ANY ) ;
CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
76
Apéndices
155
156
157
158
159
160
161
162
163
c u r l _ s e t o p t ( $curl , CURLOPT_RETURNTRANSFER , 1 ) ;
$jso n_respon se = c u r l _ e x e c ( $curl ) ;
c u r l _ c l o s e ( $curl ) ;
$authObj = json_decode ( $jso n_respon se ) ;
// S i s e ha s o l i c i t a d o e l a c c e s o o f f l i n e , r e g o g e r e l " r e f r e s h ←token "
i f ( i s s e t ( $authObj−>refresh_token ) )
{
global $refreshToken ;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
$refreshToken = $authObj−>refresh_token ;
// Se s a l v a e l R e f r e s h Token para f u t u r o s a c c e s o s
w r i t e _ c a l e n d a r O w n e r _ t o k e n ( " $ c a l e n d a r O w n e r F i l e $ t o k e n F i l e E x t " , ←$refreshToken ) ;
}
}
i f ( i s s e t ( $authObj−>access_token ) )
{
return $authObj−>access_token ;
}
else
{
return NULL ;
}
// Envia una p e t i c i o n HTTP a Google para i n s e r t a r d a t o s en Google ←C a l e n d a r . Los d a t o s a i n s e r t a r dependeran d e l t i p o que s e hayan ←e s p e c i f i c a d o en l a URI u t i l i z a d a . El dato que d e v u e l v e l a f u n c i o n ←por d e f e c t o s e r a un c o d i g o HTTP de r e s p u e s t a , d e v o l v i e n d o ' 2 0 0 ' ←como o p e r a c i o n c o r r e c t a . Ademas , s e podra e s p e c i f i c a r que d e v u e l v a ←una s t r i n g que r e p r e s e n t e un c o d i g o de i d e n t i f i c a c i o n ( ID ) en ←c a s o de i n s e r t a r s e un e v e n t o u o b j e t o s i m i l a r .
function s en d _p os t_ q ue ry ( $postArgs , $aToken , $URL , $return = " b o o l e a n " ←)
{
$session = c u r l _ i n i t ( ) ;
c u r l _ s e t o p t ( $session , CURLOPT_POST , t r u e ) ;
c u r l _ s e t o p t ( $session , CURLOPT_URL , $URL ) ;
c u r l _ s e t o p t ( $session , CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
c u r l _ s e t o p t ( $session , CURLOPT_RETURNTRANSFER , 1 ) ;
$curlheader [ 0 ] = " Content−Type : a p p l i c a t i o n / j s o n " ;
$curlheader [ 1 ] = " A u t h o r i z a t i o n : OAuth " . $aToken ;
c u r l _ s e t o p t ( $session , CURLOPT_HTTPHEADER , $curlheader ) ;
c u r l _ s e t o p t ( $session , CURLOPT_POSTFIELDS , $postArgs ) ;
i f ( $return == " i d " )
{
$jso n_respon se = c u r l _ e x e c ( $session ) ;
c u r l _ c l o s e ( $session ) ;
$responseObj = json_decode ( $jso n_respon se ) ;
i f ( i s s e t ( $responseObj−>id ) )
{
return $responseObj−>id ;
}
else
{
A.4. Apéndice IV
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
}
}
return " " ;
// Caso g e n e r a l : d e v o l v e r s i s e ha r e a l i z a d o c o r r e c t a m e n t e o no
c u r l _ e x e c ( $session ) ;
$response = c u r l _ g e t i n f o ( $session ) ;
c u r l _ c l o s e ( $session ) ;
}
return $response [ ' http_code ' ] ;
// Cre ara un nuevo e v e n t o en e l c a l e n d a r i o de r e s e r v a s d e l p r o f e s o r . ←El p r o p i e t a r i o d e l e v e n t o s e g u i r a s i e n d o e l p r o f e s o r p e r o s e ←i n c l u i r a n d a t o s d e l u s u a r i o a u t e n t i c a d o que ha r e a l i z a d o l a a c c i o n ←. Devuelve v e r d a d e r o s i s e ha i n s e r t a d o con e x i t o y f a l s o en c a s o ←contrario .
function insert NewEvent ( $startDateTime , $endDateTime , ←$calendarOwnerOffice , $description , $user , $email )
{
d a t e _ d e f a u l t _ t i m e z o n e _ s e t ( " Europe / Madrid " ) ;
$sta rtDateTi me = U T C _ t i m e Z o n e R e p l a c e r ( $sta rtDateTi me ) ;
$endDateTime = U T C _ t i m e Z o n e R e p l a c e r ( $endDateTime ) ;
require_once ' . / s r c / a p i C l i e n t . php ' ;
require_once ' . / s r c / c o n t r i b / a p i C a l e n d a r S e r v i c e . php ' ;
global $api_key ;
global $ j s o n _ a c c e s s T o k e n ;
global $accessToken ;
global $refreshToken ;
global $ b o o k _ c a l e n d a r _ i d ;
global $ t u t o r i n g _ c a l e n d a r _ i d ;
global $redirect_uri ;
global $clien t_secret ;
global $client_id ;
global $scope ;
$client = new apiClient ( ) ;
$client−>setScopes ( $scope ) ;
$client−>setClientId ( $client_id ) ;
$client−>s et Cl ie n tS ec re t ( $cli ent_secr et ) ;
$client−>setR edirectU ri ( $redirect_uri ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
$client−>refreshToken ( $refreshToken ) ;
$sta rtDateTi me = d a t e ( " c " , s t r t o t i m e ( $sta rtDateTi me ) ) ;
$endDateTime = d a t e ( " c " , s t r t o t i m e ( $endDateTime ) ) ;
{
$description = u t f 8 _ e n c o d e ( "<br />T u t o r i a s o l i c i t a d a por :< br />" . ←utf8_decode ( $user ) . " ( $ e m a i l )<br /><br />Razon:< br />←$ d e s c r i p t i o n <br />" ) ;
$summary = u t f 8 _ e n c o d e ( " T u t o r i a en $ c a l e n d a r O w n e r O f f i c e " ) ;
$tex t_portAr gs = <<<JSON
" end " :
{
" dateTime " : " $endDateTime "
},
" start " :
{
" dateTime " : " $ s t a r t D a t e T i m e "
77
78
Apéndices
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
},
" extendedProperties " :
{
" private " :
{
" booker_email " : " $ e m a i l " ,
" booker_displayName " : " $ u s e r "
}
},
" summary " : " $summary " ,
" description " : " $description " ,
" v i s i b i l i t y " : " public " ,
" guestsCanInviteOthers " : false ,
" anyoneCanAddSelf " : f a l s e ,
" guestsCanModify " : f a l s e ,
" guestsCanSeeOtherGuests " : f a l s e
}
JSON ;
$responseObj = json_decode ( $client−>getA ccessTok en ( ) ) ;
i f ( i s s e t ( $responseObj−>access_token ) )
{
// S e l e c c i o n a n d o rango de f e c h a s que abarquen l a semana ←completa
$startDate = weekStartDate ( d a t e ( "W" , s t r t o t i m e ( $sta rtDateTi me ) ←) − 1 , d a t e ( "Y" , s t r t o t i m e ( $sta rtDateTi me ) ) ) ;
$endDate = weekEndDate ( d a t e ( "W" , s t r t o t i m e ( $endDateTime ) ) − 1 , ←d a t e ( "Y" , s t r t o t i m e ( $endDateTime ) ) ) ;
// Cargando l i s t a s de e v e n t o s , s i hay
$book_hours = loadEvents ( $startDate , $endDate , ←$book_calendar_id ) ;
// L i s t a de r e s e r v a s de l a semana
$bookList = sort Book_hou rs ( $book_hours ) ;
if
{
}
( ! isFr eeBookSl ot ( $startDateTime , $endDateTime , $bookList [ ←d a t e ( 'N ' , s t r t o t i m e ( $star tDateTim e ) ) ] ) )
echo "DEBUG: hueco de r e s e r v a s en uso .< br />" ;
return f a l s e ;
// Cargando l i s t a s de e v e n t o s , s i hay
$ tu to ri n g_ ho ur s = loadEvents ( $startDate , $endDate , ←$tutoring_calendar_id ) ;
// L i s t a c o m p l e t a de t u t o r i a s de l a semana
$tutoringList = s o r t T u t o r i n g _ h o u r s ( $ tu to ri n g_ ho ur s ) ;
if
{
}
( ! i sV al id B oo kS lo t ( $startDateTime , $endDateTime , ←$tutoringList [ ( d a t e ( 'N ' , s t r t o t i m e ( $star tDateTim e ) ) ) ] ) )
echo "DEBUG: El hueco s e l e c c i o n a d o no p e r t e n e c e a l h o r a r i o ←de t u t o r i a s .< br />" ;
return f a l s e ;
i f ( s t r t o t i m e ( d a t e ( " c " ) ) > s t r t o t i m e ( $sta rtDateTi me ) )
{
echo "DEBUG: No s e p e r m i t e s o l i c i t a r h o r a s de t u t o r i a s que←ya han pasado ( a no s e r que t e n g a un D e l o r e a n con ←-
A.4. Apéndice IV
316
317
318
319
320
}
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
}
else
{
c o n d e n s a d o r de F l u z o ) .< br />" ;
return f a l s e ;
echo "DEBUG: Reservando hueco . . . < br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$book_calendar_id / e v e n t s " ;
$response = s en d_ po s t_ qu er y ( $text_portArgs , $responseObj−>←access_token , $URL ) ;
echo "DEBUG: POST r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 200 " )
{
return f a l s e ;
}
return f a l s e ;
}
return t r u e ;
}
// E l i m i n a r a e l e v e n t o s e l e c c i o n a d o d e l c a l e n d a r i o que s e i n d i q u e . ←D e v o l v e r a v e r d a d e r o s i s e ha e l i m i n a d o e l e v e n t o y f a l s o en c a s o ←contrario .
function deleteEvent ( $event_id )
{
require_once ' . / s r c / a p i C l i e n t . php ' ;
require_once ' . / s r c / c o n t r i b / a p i C a l e n d a r S e r v i c e . php ' ;
global $api_key ;
global $accessToken ;
global $refreshToken ;
global $ b o o k _ c a l e n d a r _ i d ;
global $redirect_uri ;
global $clien t_secret ;
global $client_id ;
global $scope ;
$client = new apiClient ( ) ;
$client−>setScopes ( $scope ) ;
$client−>setClientId ( $client_id ) ;
$client−>s et Cl ie n tS ec re t ( $cli ent_secr et ) ;
$client−>setR edirectU ri ( $redirect_uri ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
$client−>refreshToken ( $refreshToken ) ;
$responseObj = json_decode ( $client−>getA ccessTok en ( ) ) ;
i f ( i s s e t ( $responseObj−>access_token ) )
{
$response = s e n d _ d e l e t e _ q u e r y ( $event_id , $responseObj−>←access_token , $ b o o k _ c a l e n d a r _ i d ) ;
echo "DEBUG: DELETE r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 204 " )
{
return f a l s e ;
}
}
else
{
return f a l s e ;
79
80
Apéndices
372
373
374
375
376
377
378
379
380
381
}
}
// Envia una p e t i c i o n HTTP a Google para e l i m i n a r d a t o s en Google ←C a l e n d a r . Dependiendo d e l t i p o de dato e s p e c i f i c a d o e l i m i n a r a un ←e v e n t o o un c a l e n d a r i o . El dato que d e v u e l v e l a f u n c i o n por ←d e f e c t o s e r a un c o d i g o HTTP de r e s p u e s t a , d e v o l v i e n d o ' 2 0 4 ' como ←operacion correcta .
function s e n d _ d e l e t e _ q u e r y ( $event_id , $aToken , $calendar_id , ←$objectType = " e v e n t " )
{
// E x i s t e n 2 t i p o s de b o r r a d o d e p e n d i e n d o d e l o b j e t o a e l i m i n a r : ←c a l e n d a r i o o evento
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$calendar_id / events / $event_id " ;
i f ( $objectType == " c a l e n d a r " )
{
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$calendar_id " ;
}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
return t r u e ;
$session = c u r l _ i n i t ( ) ;
c u r l _ s e t o p t ( $session , CURLOPT_URL , $URL ) ;
c u r l _ s e t o p t ( $session , CURLOPT_CUSTOMREQUEST , "DELETE" ) ;
c u r l _ s e t o p t ( $session , CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
$curlheader [ 0 ] = " A u t h o r i z a t i o n : OAuth " . $aToken ;
c u r l _ s e t o p t ( $session , CURLOPT_HTTPHEADER , $curlheader ) ;
c u r l _ e x e c ( $session ) ;
$response = c u r l _ g e t i n f o ( $session ) ;
c u r l _ c l o s e ( $session ) ;
}
return $response [ ' http_code ' ] ;
// E l i m i n a r a e l c a l e n d a r i o que s e i n d i q u e . D e v o l v e r a v e r d a d e r o s i s e ←ha e l i m i n a d o e l e v e n t o y f a l s o en c a s o c o n t r a r i o .
function delete Calendar ( $calendar_id )
{
require_once ' . / s r c / a p i C l i e n t . php ' ;
require_once ' . / s r c / c o n t r i b / a p i C a l e n d a r S e r v i c e . php ' ;
global $api_key ;
global $accessToken ;
global $refreshToken ;
global $redirect_uri ;
global $clien t_secret ;
global $client_id ;
global $scope ;
$client = new apiClient ( ) ;
$client−>setScopes ( $scope ) ;
$client−>setClientId ( $client_id ) ;
$client−>s et Cl ie n tS ec re t ( $cli ent_secr et ) ;
$client−>setR edirectU ri ( $redirect_uri ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
$client−>refreshToken ( $refreshToken ) ;
$responseObj = json_decode ( $client−>getA ccessTok en ( ) ) ;
A.4. Apéndice IV
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
i f ( i s s e t ( $responseObj−>access_token ) )
{
$response = s e n d _ d e l e t e _ q u e r y ( " " , $responseObj−>access_token , ←$calendar_id , " c a l e n d a r " ) ;
echo "DEBUG: DELETE r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 204 " )
{
return f a l s e ;
}
}
else
{
return f a l s e ;
}
}
return t r u e ;
// Envia una p e t i c i o n HTTP a Google para m o d i f i c a r d a t o s en Google ←C a l e n d a r . Los d a t o s a m o d i f i c a r dependeran d e l t i p o que s e hayan ←e s p e c i f i c a d o en l a URI u t i l i z a d a . El dato que d e v u e l v e l a f u n c i o n ←por d e f e c t o s e r a un c o d i g o HTTP de r e s p u e s t a , d e v o l v i e n d o ' 2 0 0 ' ←como o p e r a c i o n c o r r e c t a .
function send_p ut_query ( $postArgs , $aToken , $URL )
{
$session = c u r l _ i n i t ( ) ;
c u r l _ s e t o p t ( $session , CURLOPT_URL , $URL ) ;
c u r l _ s e t o p t ( $session , CURLOPT_CUSTOMREQUEST , "PUT" ) ;
c u r l _ s e t o p t ( $session , CURLOPT_SSL_VERIFYPEER , f a l s e ) ;
c u r l _ s e t o p t ( $session , CURLOPT_RETURNTRANSFER , 1 ) ;
$curlheader [ 0 ] = " Content−Type : a p p l i c a t i o n / j s o n " ;
$curlheader [ 1 ] = " A u t h o r i z a t i o n : OAuth " . $aToken ;
c u r l _ s e t o p t ( $session , CURLOPT_HTTPHEADER , $curlheader ) ;
c u r l _ s e t o p t ( $session , CURLOPT_POSTFIELDS , $postArgs ) ;
c u r l _ e x e c ( $session ) ;
$response = c u r l _ g e t i n f o ( $session ) ;
c u r l _ c l o s e ( $session ) ;
}
return $response [ ' http_code ' ] ;
function loadEvents ( $startDate , $endDate , $calendar_id )
{
global $accessToken ;
$book_query = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$ c a l e n d a r _ i d / e v e n t s ? orderBy=s t a r t T i m e&s i n g l e E v e n t s=t r u e&←timeMin=$ s t a r t D a t e&timeMax=$endDate " ;
}
return send_g et_query ( $book_query , $accessToken ) ;
// Cre ara un c a l e n d a r i o en e l que s e pueda i n s e r t a r h o r a r i o s de ←t u t o r i a s d e l p r o f e s o r . D e v o l v e r a e l ID d e l c a l e n d a r i o c r e a d o , ←cadena v a c i a en c a s o de e r r o r .
function i n s e r t N e w T u t o r i n g C a l e n d a r ( )
{
require_once ' . / s r c / a p i C l i e n t . php ' ;
require_once ' . / s r c / c o n t r i b / a p i C a l e n d a r S e r v i c e . php ' ;
global $api_key ;
global $ j s o n _ a c c e s s T o k e n ;
global $accessToken ;
81
82
Apéndices
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
global
global
global
global
global
$refreshToken ;
$redirect_uri ;
$clien t_secret ;
$client_id ;
$scope ;
$client = new apiClient ( ) ;
$client−>setScopes ( $scope ) ;
$client−>setClientId ( $client_id ) ;
$client−>s et Cl ie n tS ec re t ( $cli ent_secr et ) ;
$client−>setR edirectU ri ( $redirect_uri ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
$client−>refreshToken ( $refreshToken ) ;
{
$ pa rt 1_ p or tA rg s = <<<JSON
" summary " : " T u t o r i a s − HORARIOS" ,
" timeZone " : " Europe / Madrid "
}
JSON ;
{
$ pa rt 2_ p or tA rg s = <<<JSON
" c o l o r I d " : " 10 " ,
" s e l e c t e d " : true ,
" defaultReminders " : [
{
" method " : " e m a i l " ,
" m in ut e s " : 1440
}
]
}
JSON ;
{
$ pa rt 3_ p or tA rg s = <<<JSON
" role " : " reader " ,
" scope " :
{
" type " : " d e f a u l t " ,
" v a l u e " : " __public_principal__@public . c a l e n d a r . g o o g l e . com "
},
" k i n d " : " c a l e n d a r#a c l R u l e " ,
" id " : " default "
}
JSON ;
$calendar_id = " " ;
$responseObj = json_decode ( $client−>getA ccessTok en ( ) ) ;
i f ( i s s e t ( $responseObj−>access_token ) )
{
echo "DEBUG: Creando c a l e n d a r i o de t u t o r i a s . . . < br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s " ;
$calendar_id = s en d_ po s t_ qu er y ( $part1_portArgs , $responseObj−>←access_token , $URL , " i d " ) ;
echo "DEBUG: C a l e n d a r ID r e s p o n s e : $ c a l e n d a r _ i d <br />" ;
i f ( s t r l e n ( $calendar_id ) == 0 )
{
return " " ;
}
A.4. Apéndice IV
539
540
echo "DEBUG: C o n f i g u r a n d o c a l e n d a r i o de t u t o r i a s ( 1 de 2 ) . . . < ←br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / u s e r s /me/←calendarList / $calendar_id " ;
$response = send _put_que ry ( $part2_portArgs , $responseObj−>←access_token , $URL ) ;
echo "DEBUG: POST r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 200 " )
{
echo "DEBUG: E r r o r d u r a n t e e l p r o c e s o , b o r r a n d o e l ←c a l e n d a r i o i n c o m p l e t o . . . < br />" ;
dele teCalend ar ( $calendar_id ) ;
541
542
543
544
545
546
547
548
549
550
551
552
}
echo "DEBUG: C o n f i g u r a n d o c a l e n d a r i o de t u t o r i a s ( 2 de 2 ) . . . < ←br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$calendar_id / ac l " ;
$response = s en d_ po s t_ qu er y ( $part3_portArgs , $responseObj−>←access_token , $URL ) ;
echo "DEBUG: POST r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 200 " )
{
echo "DEBUG: E r r o r d u r a n t e e l p r o c e s o , b o r r a n d o e l ←c a l e n d a r i o i n c o m p l e t o . . . < br />" ;
dele teCalend ar ( $calendar_id ) ;
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
return " " ;
}
else
{
}
}
}
return " " ;
return " " ;
return $calendar_id ;
// Cre ara un c a l e n d a r i o para que s e pueda i n s e r t a r r e s e r v a s d e l ←h o r a r i o de t u t o r i a s d e l p r o f e s o r . D e v o l v e r a e l ID d e l c a l e n d a r i o ←c r e a d o , cadena v a c i a en c a s o de e r r o r .
function i n s e r t N e w B o o k i n g C a l e n d a r ( )
{
require_once ' . / s r c / a p i C l i e n t . php ' ;
require_once ' . / s r c / c o n t r i b / a p i C a l e n d a r S e r v i c e . php ' ;
global $api_key ;
global $ j s o n _ a c c e s s T o k e n ;
global $accessToken ;
global $refreshToken ;
global $redirect_uri ;
global $clien t_secret ;
global $client_id ;
global $scope ;
$client = new apiClient ( ) ;
$client−>setScopes ( $scope ) ;
$client−>setClientId ( $client_id ) ;
$client−>s et Cl ie n tS ec re t ( $cli ent_secr et ) ;
83
84
Apéndices
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
$client−>setR edirectU ri ( $redirect_uri ) ;
$client−>s et De ve l op er Ke y ( $api_key ) ;
$client−>refreshToken ( $refreshToken ) ;
{
$ pa rt 1_ p or tA rg s = <<<JSON
" summary " : " T u t o r i a s − RESERVAS" ,
" timeZone " : " Europe / Madrid "
}
JSON ;
{
$ pa rt 2_ p or tA rg s = <<<JSON
" colorId " : "2" ,
" s e l e c t e d " : true ,
" defaultReminders " : [
{
" method " : " e m a i l " ,
" m in ut e s " : 1440
}
]
}
JSON ;
{
$ pa rt 3_ p or tA rg s = <<<JSON
" r o l e " : " freeBusyReader " ,
" scope " :
{
" type " : " d e f a u l t " ,
" v a l u e " : " __public_principal__@public . c a l e n d a r . g o o g l e . com "
},
" k i n d " : " c a l e n d a r#a c l R u l e " ,
" id " : " default "
}
JSON ;
$calendar_id = " " ;
$responseObj = json_decode ( $client−>getA ccessTok en ( ) ) ;
i f ( i s s e t ( $responseObj−>access_token ) )
{
echo "DEBUG: Creando c a l e n d a r i o de r e s e r v a s . . . < br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s " ;
$calendar_id = s en d_ po s t_ qu er y ( $part1_portArgs , $responseObj−>←access_token , $URL , " i d " ) ;
echo "DEBUG: C a l e n d a r ID r e s p o n s e : $ c a l e n d a r _ i d <br />" ;
i f ( s t r l e n ( $calendar_id ) == 0 )
{
return " " ;
}
echo "DEBUG: C o n f i g u r a n d o c a l e n d a r i o de r e s e r v a s ( 1 de 2 ) . . . < ←br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / u s e r s /me/←calendarList / $calendar_id " ;
$response = send _put_que ry ( $part2_portArgs , $responseObj−>←access_token , $URL ) ;
echo "DEBUG: POST r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 200 " )
{
A.4. Apéndice IV
648
echo "DEBUG: E r r o r d u r a n t e e l p r o c e s o , b o r r a n d o e l ←c a l e n d a r i o i n c o m p l e t o . . . < br />" ;
dele teCalend ar ( $calendar_id ) ;
649
650
651
652
653
654
}
echo "DEBUG: C o n f i g u r a n d o c a l e n d a r i o de r e s e r v a s ( 2 de 2 ) . . . < ←br />" ;
$URL = " h t t p s : / /www. g o o g l e a p i s . com/ c a l e n d a r / v3 / c a l e n d a r s /←$calendar_id / ac l " ;
$response = s en d_ po s t_ qu er y ( $part3_portArgs , $responseObj−>←access_token , $URL ) ;
echo "DEBUG: POST r e s p o n s e code : $ r e s p o n s e <br />" ;
i f ( $response != " 200 " )
{
echo "DEBUG: E r r o r d u r a n t e e l p r o c e s o , b o r r a n d o e l ←c a l e n d a r i o i n c o m p l e t o . . . < br />" ;
dele teCalend ar ( $calendar_id ) ;
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
return " " ;
}
else
{
}
}
}
return " " ;
return " " ;
return $calendar_id ;
// S a l v a en un f i c h e r o t o d o s l o s d a t o s de c o n f i g u r a c i o n n e c e s a r i o s ←para que e l s i s t e m a de r e s e r v a s pueda a c c e d e r a l o s c a l e n d a r i o s ←del profesor .
function f i l l _ c a l e n d a r O w n e r _ c o n f i g ( $ c a l O w n e r F i l e N a m e )
{
$oFile = f o p e n ( $calOwnerFileName , 'w ' ) or d i e ( " E r r o r : No s e puede ←a b r i r e l f i c h e r o ' $calOwnerFileName ' para e s c r i t u r a .< br />" ) ;
global
global
global
global
global
global
global
global
global
global
global
global
global
global
$calendarOwnerOffice ;
$client_id ;
$clien t_secret ;
$redirect_uri ;
$scope ;
$state ;
$access_type ;
$tutoring_calendar_id ;
$book_calendar_id ;
$userlogin_client_id ;
$userlogin_client_secret ;
$userlogin_redirect_uri ;
$ u s er l o g i n _ s c o p e ;
$api_key ;
$dataToSave =
'<?php ' . PHP_EOL .
' // Datos p e r s o n a l e s d e l t u t o r n e c e s a r i o s ' . PHP_EOL .
' $ c a l e n d a r O w n e r O f f i c e = " ' . $ c a l e n d a r O w n e r O f f i c e . ' " ; // Despacho ←d e l t u t o r ' . PHP_EOL .
' $ t u t o r i n g _ c a l e n d a r _ i d = " ' . $ t u t o r i n g _ c a l e n d a r _ i d . ' " ; // ←C a l e n d a r i o de t u t o r i a s d i s p o n i b l e ' . PHP_EOL .
85
86
Apéndices
699
' $book_calendar_id = " ' . $ b o o k _ c a l e n d a r _ i d . ' " ; // L i s t a de r e s e r v a s ←r e a l i z a d a s ' . PHP_EOL .
' ' . PHP_EOL .
' // Parametros d e l u s u a r i o para e l URL de a c c e s o ' . PHP_EOL .
' $ c l i e n t _ i d = " ' . $client_id . ' " ; ' . PHP_EOL .
' $ c l i e n t _ s e c r e t = " ' . $cli ent_secr et . ' " ; ' . PHP_EOL .
' $ r e d i r e c t _ u r i = " ' . $redirect_uri . ' " ; ' . PHP_EOL .
' $ s c o p e = " ' . $scope . ' " ; ' . PHP_EOL .
' $ s t a t e = " ' . $state . ' " ; // O p c i o n a l − puede s e r c u a l q u i e r v a l o r ←que q u i e r a s ' . PHP_EOL .
' $ a c c e s s _ t y p e = " ' . $access_type . ' " ; // No cambiar e l v a l o r " ←o f f l i n e " , n e c e s a r i o para l a r e c u p e r a c i o n d e l " r e f r e s h _ t o k e n " ' . ←PHP_EOL .
' ' . PHP_EOL .
' // Parametros d e l u s u a r i o para e l a c c e s o de u s u a r i o s l o g e a d o s ' . ←PHP_EOL .
' $ u s e r l o g i n _ c l i e n t _ i d = " ' . $ u s e r l o g i n _ c l i e n t _ i d . ' " ; ' . PHP_EOL .
' $ u s e r l o g i n _ c l i e n t _ s e c r e t = " ' . $ u s e r l o g i n _ c l i e n t _ s e c r e t . ' " ; ' . ←PHP_EOL .
' $ u s e r l o g i n _ r e d i r e c t _ u r i = " ' . $ u s e r l o g i n _ r e d i r e c t _ u r i . ' " ; ' . PHP_EOL←.
' $ u s e r l o g i n _ s c o p e = " ' . $ u s e r l o g i n _ sc o p e . ' " ; ' . PHP_EOL .
' ' . PHP_EOL .
' // API de a c c e s s o s i m p l e ' . PHP_EOL .
' $api_key = " ' . $api_key . ' " ; ' . PHP_EOL .
' ?> ' . PHP_EOL .
' ' . PHP_EOL ;
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
fwrite ( $oFile , $dataToSave ) ;
}
f c l o s e ( $oFile ) ;
// Devuelve l a f e c h a d e l p r i m e r d i a de l a semana
function weekStartDate ( $wk_num , $yr , $first = 1 , $format = "Y−m−d\TH: i ←: s \Z " )
{
$wk_ts = s t r t o t i m e ( '+ ' . $wk_num . ' weeks ' , s t r t o t i m e ( $yr . ' 0101 ' ) ) ;
$mon_ts = s t r t o t i m e ( '− ' . d a t e ( 'w ' , $wk_ts ) + $first . ' days ' , $wk_ts←);
}
return d a t e ( $format , $mon_ts ) ;
// Devuelve l a f e c h a d e l u l t i m o d i a de l a semana
function weekEndDate ( $wk_num , $yr , $first = 7 , $format = "Y−m−d\TH: i : s ←\Z " )
{
return weekStartDate ( $wk_num , $yr , $first , $format ) ;
}
?>
A.4. Apéndice IV
Código fuente de: index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<! DOCTYPE html>
<html>
<head>
<meta charset=iso −8859−15>
<body>
<script type=" t e x t / j a v a s c r i p t ">
// V e r i f i c a s i l a s h o r a s de i n i c i o y f i n a l son c o h e r e n t e s , en c a s o ←c o n t r a r i o c o r r i g e l a hora f i n a l con r e s p e c t o a l a de i n c i o .
function checkB ookTimes ( divFrom , divTo )
{
var df = document . getE lementBy Id ( divFrom ) ;
var dt = document . getE lementBy Id ( divTo ) ;
}
i f ( df . options [ df . selectedIndex ] . value >= dt . options [ dt . ←selectedIndex ] . value )
{
dt . selectedIndex = df . selectedIndex ;
}
// Prepara l o s campos de f o r m u l a r i o u t i l i z a d o s por e l s e r v i d o r
function createNewBook ( half_id )
{
var df = document . getE lementBy Id ( ' from_ ' + half_id ) ;
var dt = document . getE lementBy Id ( ' to_ ' + half_id ) ;
var desc = document . getE lementBy Id ( ' desc_ ' + half_id ) ;
var form_dtf = document . getE lementBy Id ( ' dateTimeFrom ' ) ;
var form_dtt = document . getE lementBy Id ( ' dateTimeTo ' ) ;
var form_desc = document . getE lementBy Id ( ' d e s c r i p t i o n ' ) ;
var form_action = document . getE lementBy Id ( ' a c t i o n ' ) ;
form_dtf . value = df . options [ df . selectedIndex ] . value ;
form_dtt . value = dt . options [ dt . selectedIndex ] . value ;
form_desc . value = desc . value ;
form_action . value = ' c r e a t e _ b o o k ' ;
}
document . booking_menu . submit ( ) ;
// Prepara l o s campos de f o r m u l a r i o u t i l i z a d o s por e l s e r v i d o r
function deleteBook ( half_id )
{
var eid = document . getE lementBy Id ( ' eid_ ' + half_id ) ;
var form_action = document . getE lementBy Id ( ' a c t i o n ' ) ;
var form_eid = document . getE lementBy Id ( ' e v e n t _ i d ' ) ;
form_eid . value = eid . value ;
form_action . value = ' d e l e t e _ b o o k ' ;
}
document . booking_menu . submit ( ) ;
// Dada una URL c a r g a una nueva p a g i n a
function loadUrl ( location )
{
window . location . href = location ;
}
</script>
87
88
Apéndices
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
if
{
( ! session_id () )
session_start () ;
}
if
{
( ! i s s e t ( $calendarOwnerFile ) )
}
$ c a l e n d a r O w n e r F i l e = ' p r o f e s o r . t e s t s @ g m a i l . com ' ;
$ au to lo g in _d on e = f a l s e ;
i f ( i s s e t ( $ c a l e n d a r O w n e r F i l e ) && s t r l e n ( $ c a l e n d a r O w n e r F i l e ) > 0 && ←f i l e _ e x i s t s ( " $ c a l e n d a r O w n e r F i l e . php " ) )
{
include_once ( " $ c a l e n d a r O w n e r F i l e . php " ) ;
}
else
{
d i e ( " El t u t o r con l a c u e n t a de c o r r e o \ " $ c a l e n d a r O w n e r F i l e \ " no ha←a c t i v a d o t o d a v i a e l s i s t e m a de r e s e r v a s para t u t o r i a s . E s p e r e ←a que e l t u t o r a c t i v e e l s e r v i c i o o s e l e c c i o n e o t r o t u t o r . " ) ;
}
// Se p r o c e d e a l a a u t e n t i c a c i o n d e l v i s i t a n t e
include_once ( " c a l e n d a r _ u s e r l o g i n . php " ) ;
// Se i n c l u y e n f u n c i o n e s de ambito g e n e r a l
include_once ( " o t h e r _ f u n c t i o n s . php " ) ;
// S i s e ha c a r g a d o con e x i t o l a c u e n t a d e l t u t o r y s e ha c o n s u l t a d o ←l o s c a l e n d a r i o s de t u t o r i a s e p e r m i t e e l a c c e s o de u s u a r i o s a l ←s i s t e m a de r e s e r v a s .
$calendarOwnerLogged = f a l s e ;
echo "<h2>CUENTA DE USUARIO</h2>" ;
i f ( ! $ us er lo g in _d on e )
{
p r i n t "<a c l a s s =' l o g i n ' h r e f =' $ a u t h U r l '> Entrar </a><br />" ;
}
else
{
i f ( count ( g et Re fr e sh To ke n ( $_SESSION [ ' a c c e s s _ t o k e n ' ] ) ) > 0 )
{
$client−>refreshToken ( g et Re fr e sh To ke n ( $_SESSION [ ' a c c e s s _ t o k e n ' ←]) ) ;
$_SESSION [ ' a c c e s s _ t o k e n ' ] = $client−>getA ccessToke n ( ) ;
}
$userInfo = g e t C l i e n t U s e r I n f o ( $client−>getA ccessTok en ( ) ) ;
echo " U s u a r i o a u t e n t i c a d o : " . utf8_decode ( $userInfo−>name ) . "<br />←Cor reo : " . utf8_decode ( $userInfo−>email ) . "<br />" ;
p r i n t "<a c l a s s =' l o g o u t ' h r e f = '? l o g o u t '> S a l i r </a><br />" ;
i f ( i s s e t ( $ t u t o r i n g _ c a l e n d a r _ i d ) && i s s e t ( $ b o o k _ c a l e n d a r _ i d ) && ←s t r l e n ( $ t u t o r i n g _ c a l e n d a r _ i d ) > 0 && s t r l e n ( $ b o o k _ c a l e n d a r _ i d ) ←> 0)
{
// Se p r o c e d e a l a a u t e n t i c a c i o n d e s a t e n d i d a d e l t u t o r para l a ←c a r g a d e l c a l e n d a r i o de r e s e r v a s .
A.4. Apéndice IV
109
110
111
112
113
114
115
116
}
include_once ( " c a l e n d a r _ a u t o l o g i n . php " ) ;
i f ( $ c a l e n d a r O w n e r F i l e == $userInfo−>email )
{
$calendarOwnerLogged = t r u e ;
echo "<br /><s t r o n g >A d m i n i s t r a c i o n d e l c a l e n d a r i o a c t i v a d a </←s t r o n g ><br />" ;
117
118
// Se p r o c e d e a l a a u t e n t i c a c i o n d e s a t e n d i d a d e l t u t o r para l a ←c a r g a d e l c a l e n d a r i o de r e s e r v a s .
include_once ( " c a l e n d a r _ a u t o l o g i n . php " ) ;
119
120
121
i f ( s t r l e n ( $accessToken ) == 0 | | ! ( i s s e t ( $ t u t o r i n g _ c a l e n d a r _ i d ) ←&& i s s e t ( $ b o o k _ c a l e n d a r _ i d ) && s t r l e n ( ←$ t u t o r i n g _ c a l e n d a r _ i d ) > 0 && s t r l e n ( $ b o o k _ c a l e n d a r _ i d ) > ←0) )
{
$loginUrl = ' h t t p s : / / a c c o u n t s . g o o g l e . com/ o / oauth2 / auth ?←s c o p e= ' . $scope . '&s t a t e= ' . $state . '&r e d i r e c t _ u r i= ' . ←$redirect_uri . '&r e s p o n s e _ t y p e=code&c l i e n t _ i d= ' . ←$client_id . '&a c c e s s _ t y p e= ' . $access_type ;
122
123
124
125
echo '<h2>AVISO : Aun no e s t a c o n f i g u r a d a l a c u e n t a d e l ←t u t o r . </h2>
<p><a c l a s s =" bu tt on " h r e f =" ' . $loginUrl . ' "> A c t i v a r l a ←c u e n t a d e l t u t o r \ ' ' . $ c a l e n d a r O w n e r F i l e . ' \ ' </a></p> ' ;
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
}
else
{
}
}
$ au to lo g in _d on e = f a l s e ;
$calendarOwnerLogged = f a l s e ;
}
// En c a s o de haber e n v i a d o un f o r m u l a r i o a l s e r v i d o r a t e n d e r l a para ←que f u t u r a s p e t i c i o n e s a l o s c a l e n d a r i o s e s t e n a c t u l i z a d a s .
i f ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST ' )
{
i f ( i s s e t ( $_POST [ ' a c t i o n ' ] ) )
{
s w i t c h ( $_POST [ ' a c t i o n ' ] )
{
case ' delete_book ' :
i f ( i s s e t ( $_POST [ ' e v e n t _ i d ' ] ) )
{
deleteEvent ( $_POST [ ' e v e n t _ i d ' ] ) ;
}
break ;
case ' create_book ' :
i f ( i s s e t ( $_POST [ ' dateTimeFrom ' ] ) && i s s e t ( $_POST [ ' ←dateTimeTo ' ] ) )
{
inse rtNewEve nt ( gmdate ( "Y−m−d\TH: i : sP " , $_POST [ ' ←dateTimeFrom ' ] ) , gmdate ( "Y−m−d\TH: i : sP " , $_POST←-
89
90
Apéndices
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
}
break ;
}
}
}
[ ' dateTimeTo ' ] ) , $calendarOwnerOffice , $_POST [ ←' d e s c r i p t i o n ' ] , $userInfo−>name , $userInfo−>←email ) ;
default :
// I g n o r a r p e t i c i o n
break ;
i f ( $ au to lo g in _d on e )
{
// S e l e c c i o n a n d o rango de f e c h a s que abarquen l a semana c o m p l e t a
i f ( i s s e t ( $_GET [ " week " ] ) && preg_match ( ' /^\d+$ / ' , $_GET [ ' week ' ] ) )
{
// Una semana s o l i c i t a d a en l a URL
$wee k_select ed = $_GET [ " week " ] − 1 ;
$yea r_select ed = i n t v a l ( d a t e ( "Y" ) ) ;
i f ( $wee k_select ed < ( d a t e ( "W" ) − 1 ) )
{
// En c a s o de s o l i c i t a r semanas a n t e r i o r e s a l a a c t u a l s e ←devuelve la actual .
$wee k_select ed = d a t e ( "W" ) − 1 ;
}
}
else
{
w h i l e ( $wee k_select ed > 5 1 )
{
$wee k_select ed −= 5 2 ;
$yea r_select ed++;
}
// Semana a c t u a l
$wee k_select ed = d a t e ( "W" ) − 1 ;
$yea r_select ed = d a t e ( "Y" ) ;
}
$startDate = weekStartDate ( $week_selected , $yea r_select ed ) ;
$endDate = weekEndDate ( $week_selected , $yea r_select ed ) ;
// Cargando l i s t a s de e v e n t o s , s i hay
$book_hours = loadEvents ( $startDate , $endDate , $ b o o k _ c a l e n d a r _ i d ) ;
$ tu to ri n g_ ho ur s = loadEvents ( $startDate , $endDate , ←$tutoring_calendar_id ) ;
// $ c u r r e n t D a t e = d a t e ( " Y−m−d\TH: i : s \Z " ) ;
$strWeekDays = a r r a y ( 1 => " Lunes " , 2 => " Martes " , 3 => " M i e r c o l e s " ←, 4 => " J u e v e s " , 5 => " V i e r n e s " , 6 => " Sabado " , 0 => " Domingo " ←);
// L i s t a c o m p l e t a de t u t o r i a s de l a semana
$tutoringList = s o r t T u t o r i n g _ h o u r s ( $ tu to ri n g_ ho ur s ) ;
// L i s t a de r e s e r v a s de l a semana
$bookList = sort Book_hou rs ( $book_hours ) ;
A.4. Apéndice IV
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
91
echo "<br />−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−<br←/>" ;
echo "<h2>R e s e r v a s de h o r a r i o para t u t o r i a s </h2>" ;
p r i n t "<h4>Semana " . ( $wee k_select ed + 1 ) . " , d e l " . d a t e ( " d−m−Y" , ←s t r t o t i m e ( $startDate ) ) . " a l " . d a t e ( " d−m−Y" , s t r t o t i m e ( $endDate←) ) . "</h4>" ;
// Anyadir b o t o n e s de n a v e g a c i o n para d e s p l a z a r s e e n t r e l a s ←semanas d e l c a l e n d a r i o .
echo d r a w W e e k B r o w s e r B u t t o n s ( $week_selected , $yea r_select ed ) . "<br ←/>" ;
echo '<form name="booking_menu " method=" p o s t " a c t i o n =" ' . ←h t m l e n t i t i e s ( $_SERVER [ 'PHP_SELF ' ] ) . ' "> ' ;
echo '<i n p u t t y p e =" hi dd en " name="dateTimeFrom " i d ="dateTimeFrom " ←v a l u e ="" /> ' ;
echo '<i n p u t t y p e =" hi dd en " name="dateTimeTo " i d ="dateTimeTo " v a l u e ←="" /> ' ;
echo '<i n p u t t y p e =" hi dd en " name=" d e s c r i p t i o n " i d =" d e s c r i p t i o n " ←v a l u e ="" /> ' ;
echo '<i n p u t t y p e =" hi dd en " name=" e v e n t _ i d " i d =" e v e n t _ i d " v a l u e ="" ←/> ' ;
echo '<i n p u t t y p e =" hi dd en " name=" a c t i o n " i d =" a c t i o n " v a l u e ="" /> ' ;
f o r ( $i = 0 ; $i < 7 ; $i++)
{
i f ( i s s e t ( $tutoringList [ $i % 7 ] ) && ( s t r t o t i m e ( d a t e ( "Y−m−d " , ←s t r t o t i m e ( $tutoringList [ $i % 7][0] − > start−>dateTime ) ) ) >= ←s t r t o t i m e ( d a t e ( "Y−m−d " ) ) ) )
{
echo "<h4>− " . $strWeekDays [ $i % 7 ] . " " . d a t e ( " j " , s t r t o t i m e ←( $tutoringList [ $i % 7][0] − > start−>dateTime ) ) . " , ←tutorias : " ;
f o r ( $j = 0 ; $j < count ( $tutoringList [ $i % 7 ] ) ; $j++)
{
i f ( $j > 0 )
{
echo " , " ;
}
echo " [ " . d a t e ( "H: i " , s t r t o t i m e ( $tutoringList [ $i % 7 ] [ ←$j]−>start−>dateTime ) ) . "−" . d a t e ( "H: i " , s t r t o t i m e ( ←$tutoringList [ $i % 7 ] [ $j]−>end−>dateTime ) ) . " ] " ;
}
echo "</h4>" ;
//
$m
$n
if
{
L i s t a de h u e c o s l i b r e s / r e s e r v a s :
= 0;
= 0;
( i s s e t ( $bookList [ $i % 7 ] ) )
$AllSlotsList = a r r a y ( ) ;
f o r ( $l = 0 ; $l < count ( $tutoringList [ $i % 7 ] ) ; $l++)
{
$AllSlotsList [ ] = findAllSlots ( $tutoringList [ $i % ←7 ] [ $l]−>start−>dateTime , $tutoringList [ $i % ←7 ] [ $l]−>end−>dateTime , $bookList [ $i % 7 ] ) ;
}
}
f o r ( $m = 0 ; $m < count ( $AllSlotsList ) ; $m++)
92
Apéndices
256
257
258
259
260
261
{
262
263
f o r ( $n = 0 ; $n < count ( $AllSlotsList [ $m ] ) ; $n++)
{
i f ( count ( $AllSlotsList [ $m ] [ $n ] ) == 2 )
{
echo " [ " . gmdate ( "H: i " , s t r t o t i m e ( $AllSlotsList←[ $m ] [ $n ] [ 0 ] ) ) . "−" . gmdate ( "H: i " , s t r t o t i m e ( ←$AllSlotsList [ $m ] [ $n ] [ 1 ] ) ) . " ] LIBRE" ;
264
265
266
267
268
269
270
271
}
else
{
272
273
i f ( $ us er lo g in _d on e && ! isOldEvent ( ←$AllSlotsList [ $m ] [ $n ] [ 1 ] ) )
{
echo " " . d r a w N e w B o o k B u t t o n ( s t r t o t i m e ( ←$AllSlotsList [ $m ] [ $n ] [ 0 ] ) , s t r t o t i m e ( ←$AllSlotsList [ $m ] [ $n ] [ 1 ] ) ) ;
}
echo "<br />" ;
echo " [ " . d a t e ( "H: i " , s t r t o t i m e ( $AllSlotsList [ ←$m ] [ $n]−>start−>dateTime ) ) . "−" . d a t e ( "H: i " , ←s t r t o t i m e ( $AllSlotsList [ $m ] [ $n]−>end−>←dateTime ) ) . " ] RESERVADO" ;
if
274
275
{
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
}
296
297
298
299
}
}
}
( ! isOldEvent ( $AllSlotsList [ $m ] [ $n]−>start−>←dateTime ) && ( $ c a l e n d a r O w n e r L o g g e d | | ( ←i s s e t ( $AllSlotsList [ $m ] [ $n]−>←extendedProperties−>private−>booker_email ) ←&& i s s e t ( $userInfo−>email ) && ←$AllSlotsList [ $m ] [ $n]−>extendedProperties ←−>private−>booker_email == $userInfo−>←email ) ) )
echo " " . d r a w C a n c e l B ut t o n ( $AllSlotsList [ $m←] [ $n]−>id ) ;
echo "<br />" ;
}
}
echo '</form> ' ;
}
echo "<br />−−−−−−−−−−−−−−−−−<br />" ;
i f ( i s s e t ( $ c a l e n d a r O w n e r F i l e ) && s t r l e n ( $ c a l e n d a r O w n e r F i l e ) > 0 && ←i s s e t ( $ t u t o r i n g _ c a l e n d a r _ i d ) && s t r l e n ( $ t u t o r i n g _ c a l e n d a r _ i d ) > 0 ←&& i s s e t ( $ b o o k _ c a l e n d a r _ i d ) && s t r l e n ( $ b o o k _ c a l e n d a r _ i d ) > 0 )
{
?>
<br />
<h4>Calendario del tutor <?php echo $ c a l e n d a r O w n e r F i l e ; ?></h4>
A.4. Apéndice IV
300
301
302
303
304
305
306
<iframe src=" h t t p s : / /www. g o o g l e . com/ c a l e n d a r /embed? s h o w T i t l e=0&amp ; ←showTabs=0&amp ; showCalendars=0&amp ; showTz=0&amp ; mode=WEEK&amp ; ←h e i g h t =600&amp ; wkst=2&amp ; h l=e s&amp ; b g c o l o r= %23FFFFFF&amp ; s r c =<?←php echo $ t u t o r i n g _ c a l e n d a r _ i d ; ?>&amp ; c o l o r= %232F6213&amp ; s r c =<?←php echo $book_calendar_id ; ?>&amp ; c o l o r = %23691426&amp ; c t z=Europe←%2FMadrid " style=" b o r d e r −width : 0 " width=" 900 " height=" 1100 " ←frameborder=" 0 " scrolling=" no "></iframe>
<?php
}
?>
</body>
</html>
93
94
Apéndices
Código fuente de: admin_new_tutor.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<! DOCTYPE html>
<html>
<head>
<meta charset=iso −8859−15>
<body>
<h2>Admi nistraci on del sistema de reservas : dar de alta nuevo tutor </←h2>
<?php
// DATOS NECESARIOS DEL TUTOR
$tokenFileExt = ' . r t o k e n ' ;
$ c a l e n d a r O w n e r F i l e = ' p r o f e s o r . t e s t s @ g m a i l . com ' ;
i f ( $_SERVER [ 'REQUEST_METHOD' ] == 'POST ' )
{
i f ( i s s e t ( $_POST [ ' calendarOwnerEmail ' ] ) &&
i s s e t ( $_POST [ ' c a l e n d a r O w n e r O f f i c e ' ] ) &&
i s s e t ( $_POST [ ' a u t o l o g i n _ c i d ' ] ) &&
i s s e t ( $_POST [ ' a u t o l o g i n _ s e c r e t ' ] ) &&
i s s e t ( $_POST [ ' a u t o l o g i n _ r e d i r e c t ' ] ) &&
i s s e t ( $_POST [ ' a u t o l o g i n _ s c o p e ' ] ) &&
i s s e t ( $_POST [ ' u s e r l o g i n _ c i d ' ] ) &&
i s s e t ( $_POST [ ' u s e r l o g i n _ s e c r e t ' ] ) &&
i s s e t ( $_POST [ ' u s e r l o g i n _ r e d i r e c t ' ] ) &&
i s s e t ( $_POST [ ' u s e r l o g i n _ s c o p e ' ] ) &&
i s s e t ( $_POST [ ' api_key ' ] ) )
{
i f ( s t r l e n ( $_POST [ ' calendarOwnerEmail ' ] ) > 0 &&
s t r l e n ( $_POST [ ' c a l e n d a r O w n e r O f f i c e ' ] ) > 0 &&
s t r l e n ( $_POST [ ' a u t o l o g i n _ c i d ' ] ) > 0 &&
s t r l e n ( $_POST [ ' a u t o l o g i n _ s e c r e t ' ] ) > 0 &&
s t r l e n ( $_POST [ ' a u t o l o g i n _ s c o p e ' ] ) > 0 &&
s t r l e n ( $_POST [ ' u s e r l o g i n _ c i d ' ] ) > 0 &&
s t r l e n ( $_POST [ ' u s e r l o g i n _ s e c r e t ' ] ) > 0 &&
s t r l e n ( $_POST [ ' u s e r l o g i n _ s c o p e ' ] ) > 0 &&
s t r l e n ( $_POST [ ' api_key ' ] ) > 0 )
{
w r i t e _ c a l e n d a r O w n e r _ c o n f i g ( $_POST [ ' calendarOwnerEmail ' ] . " . ←php " , $_POST [ ' c a l e n d a r O w n e r O f f i c e ' ] , $_POST [ ' ←a u t o l o g i n _ c i d ' ] , $_POST [ ' a u t o l o g i n _ s e c r e t ' ] , $_POST [ ' ←a u t o l o g i n _ r e d i r e c t ' ] , $_POST [ ' a u t o l o g i n _ s c o p e ' ] , ←$_POST [ ' u s e r l o g i n _ c i d ' ] , $_POST [ ' u s e r l o g i n _ s e c r e t ' ] , ←$_POST [ ' u s e r l o g i n _ r e d i r e c t ' ] , $_POST [ ' u s e r l o g i n _ s c o p e ' ←] , $_POST [ ' api_key ' ] ) ;
}
else
{
}
}
}
echo "DEBUG: Terminado . Ahora e l t u t o r t i e n e que e n t r a r en←e l s i s t e m a de t u t o r i a s y a c t i v a r e l s e r v i c i o para que←o t r o s u s u a r i o s puedan h a c e r r e s e r v a s .< br />" ;
echo " E r r o r : Hay campos o b l i g a t o r i o s s i n r e l l e n a r .< br />" ;
A.4. Apéndice IV
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
echo '<form name=" t u t o r _ a d m i n i s t r a t i o n " method=" p o s t " a c t i o n =" ' . ←h t m l e n t i t i e s ( $_SERVER [ 'PHP_SELF ' ] ) . ' "> ' ;
// Datos d e l t u t o r
echo '<br />Datos d e l Tutor :< br /> ' ;
echo '< l a b e l f o r =" calendarOwnerEmail "> Co rreo : </ l a b e l ><i n p u t t y p e ="←t e x t " name=" calendarOwnerEmail " i d =" calendarOwnerEmail " s i z e =100 ←v a l u e ="" /><br /> ' ;
echo '< l a b e l f o r =" c a l e n d a r O w n e r O f f i c e ">Despacho de T u t o r i a s : </ l a b e l ><←i n p u t t y p e =" t e x t " name=" c a l e n d a r O w n e r O f f i c e " i d ="←c a l e n d a r O w n e r O f f i c e " s i z e =100 v a l u e ="" /><br /> ' ;
// C l i e n t ID f o r i n s t a l l e d a p p l i c a t i o n s
echo '<br /> C l i e n t ID para a p l i c a c i o n e s i n s t a l a d a s ( C l i e n t ID f o r ←i n s t a l l e d a p p l i c a t i o n s ) :< br /> ' ;
echo '< l a b e l f o r =" a u t o l o g i n _ c i d "> C l i e n t ID : </ l a b e l ><i n p u t t y p e =" t e x t " ←name=" a u t o l o g i n _ c i d " i d =" a u t o l o g i n _ c i d " s i z e =100 v a l u e ="" /><br ←/> ' ;
echo '< l a b e l f o r =" a u t o l o g i n _ s e c r e t "> C l i e n t s e c r e t : </ l a b e l ><i n p u t t y p e ←=" t e x t " name=" a u t o l o g i n _ s e c r e t " i d =" a u t o l o g i n _ s e c r e t " s i z e =100 ←v a l u e ="" /><br /> ' ;
echo '< l a b e l f o r =" a u t o l o g i n _ r e d i r e c t "> R e d i r e c t URIs : </ l a b e l ><i n p u t ←t y p e =" t e x t " name=" a u t o l o g i n _ r e d i r e c t " i d =" a u t o l o g i n _ r e d i r e c t " s i z e ←=100 v a l u e ="" p l a c e h o l d e r =" h t t p : / / l o c a l h o s t " /><br /> ' ;
echo '< l a b e l f o r =" a u t o l o g i n _ s c o p e ">Scope : </ l a b e l ><i n p u t t y p e =" t e x t " ←name=" a u t o l o g i n _ s c o p e " i d =" a u t o l o g i n _ s c o p e " s i z e =100 v a l u e ="" /><←br /> ' ;
// C l i e n t ID f o r web a p p l i c a t i o n s
echo '<br /> C l i e n t ID para a p l i c a c i o n e s web ( C l i e n t ID f o r web ←a p p l i c a t i o n s ) :< br /> ' ;
echo '< l a b e l f o r =" u s e r l o g i n _ c i d "> C l i e n t ID : </ l a b e l ><i n p u t t y p e =" t e x t " ←name=" u s e r l o g i n _ c i d " i d =" u s e r l o g i n _ c i d " s i z e =100 v a l u e ="" /><br ←/> ' ;
echo '< l a b e l f o r =" u s e r l o g i n _ s e c r e t "> C l i e n t s e c r e t : </ l a b e l ><i n p u t t y p e ←=" t e x t " name=" u s e r l o g i n _ s e c r e t " i d =" u s e r l o g i n _ s e c r e t " s i z e =100 ←v a l u e ="" /><br /> ' ;
echo '< l a b e l f o r =" u s e r l o g i n _ r e d i r e c t "> R e d i r e c t URIs : </ l a b e l ><i n p u t ←t y p e =" t e x t " name=" u s e r l o g i n _ r e d i r e c t " i d=u s e r l o g i n _ r e d i r e c t " " s i z e ←=100 v a l u e ="" p l a c e h o l d e r =" h t t p : / / l o c a l h o s t " /><br /> ' ;
echo '< l a b e l f o r =" u s e r l o g i n _ s c o p e "> S c o p e s : </ l a b e l ><i n p u t t y p e =" t e x t " ←name=" u s e r l o g i n _ s c o p e " i d =" u s e r l o g i n _ s c o p e " s i z e =100 v a l u e ="" /><←br /> ' ;
// S im pl e API A c c e s s ( API Key )
echo '<br />Acceso s i m p l e a l a API ( S im pl e API A c c e s s ) :< br /> ' ;
echo '< l a b e l f o r ="api_key">API key : </ l a b e l ><i n p u t t y p e =" t e x t " name="←api_key " i d ="api_key " s i z e =100 v a l u e ="" /><br /> ' ;
echo '<br /><i n p u t t y p e =" submit " v a l u e ="Dar de a l t a Tutor " /><br /> ' ;
echo '</form> ' ;
// −−−−−−−−−−−−−−−−−−−−−−−− FUNCIONES −−−−−−−−−−−−−−−−−−−−−−−−
// S a l v a l o s d a t o s de c o n f i g u r a c i o n n e c e s a r i o s para e l a c c e s o a l o s ←calendarios del tutor .
function w r i t e _ c a l e n d a r O w n e r _ c o n f i g ( $calOwnerFileName , ←$calendarOwnerOffice , $client_id , $client_secret , $redirect_uri , ←$scope , $userlogin_client_id , $userlogin_client_secret , ←$userlogin_redirect_uri , $userlogin_scope , $api_key )
{
95
96
Apéndices
83
$oFile = f o p e n ( $calOwnerFileName , 'w ' ) or d i e ( " E r r o r : No s e puede ←a b r i r e l f i c h e r o ' $calOwnerFileName ' para e s c r i t u r a .< br />" ) ;
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
$state = " p r o f i l e " ;
$access_type = " o f f l i n e " ;
$tutoring_calendar_id = " " ;
$book_calendar_id = " " ;
i f ( s t r l e n ( $redirect_uri ) == 0 )
{
$redirect_uri = " h t t p : / / l o c a l h o s t " ;
}
i f ( s t r l e n ( $ u s e r l o g i n _ r e d i r e c t _ u r i ) == 0 )
{
$userlogin_redirect_uri = " http : / / l o c a l h o s t " ;
}
$dataToSave =
'<?php ' . PHP_EOL .
' // Datos p e r s o n a l e s d e l t u t o r n e c e s a r i o s ' . PHP_EOL .
' $ c a l e n d a r O w n e r O f f i c e = " ' . $ c a l e n d a r O w n e r O f f i c e . ' " ; // Despacho ←d e l t u t o r ' . PHP_EOL .
' $ t u t o r i n g _ c a l e n d a r _ i d = " ' . $ t u t o r i n g _ c a l e n d a r _ i d . ' " ; // ←C a l e n d a r i o de t u t o r i a s d i s p o n i b l e ' . PHP_EOL .
' $book_calendar_id = " ' . $ b o o k _ c a l e n d a r _ i d . ' " ; // L i s t a de r e s e r v a s ←r e a l i z a d a s ' . PHP_EOL .
' ' . PHP_EOL .
' // Parametros d e l u s u a r i o para e l URL de a c c e s o ' . PHP_EOL .
' $ c l i e n t _ i d = " ' . $client_id . ' " ; ' . PHP_EOL .
' $ c l i e n t _ s e c r e t = " ' . $cli ent_secr et . ' " ; ' . PHP_EOL .
' $ r e d i r e c t _ u r i = " ' . $redirect_uri . ' " ; ' . PHP_EOL .
' $ s c o p e = " ' . $scope . ' " ; ' . PHP_EOL .
' $ s t a t e = " ' . $state . ' " ; // O p c i o n a l − puede s e r c u a l q u i e r v a l o r ←que q u i e r a s ' . PHP_EOL .
' $ a c c e s s _ t y p e = " ' . $access_type . ' " ; // No cambiar e l v a l o r " ←o f f l i n e " , n e c e s a r i o para l a r e c u p e r a c i o n d e l " r e f r e s h _ t o k e n " ' . ←PHP_EOL .
' ' . PHP_EOL .
' // Parametros d e l u s u a r i o para e l a c c e s o de u s u a r i o s l o g e a d o s ' . ←PHP_EOL .
' $ u s e r l o g i n _ c l i e n t _ i d = " ' . $ u s e r l o g i n _ c l i e n t _ i d . ' " ; ' . PHP_EOL .
' $ u s e r l o g i n _ c l i e n t _ s e c r e t = " ' . $ u s e r l o g i n _ c l i e n t _ s e c r e t . ' " ; ' . ←PHP_EOL .
' $ u s e r l o g i n _ r e d i r e c t _ u r i = " ' . $ u s e r l o g i n _ r e d i r e c t _ u r i . ' " ; ' . PHP_EOL←.
' $ u s e r l o g i n _ s c o p e = " ' . $ u s e r l o g i n _ sc o p e . ' " ; ' . PHP_EOL .
' ' . PHP_EOL .
' // API de a c c e s s o s i m p l e ' . PHP_EOL .
' $api_key = " ' . $api_key . ' " ; ' . PHP_EOL .
' ?> ' . PHP_EOL .
' ' . PHP_EOL ;
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
fwrite ( $oFile , $dataToSave ) ;
}
f c l o s e ( $oFile ) ;
?>
</body>
</html>

Documentos relacionados