changeset 188:49125b681709

Combinar
author juanjose.montesdeocaarbos
date Tue, 09 Aug 2011 08:55:08 -0300
parents 37bc622980b4 (current diff) 2d02adb79322 (diff)
children fe47f11f5f20 03cf6a377ee8
files Agendas/trunk/src/Agendas.Factories/AttributeFactory.cs Agendas/trunk/src/Agendas.Tests/Workflows/WorkflowTests.cs
diffstat 69 files changed, 1927 insertions(+), 668 deletions(-) [+]
line wrap: on
line diff
--- a/Agendas/trunk/src/Agendas.Blog/Impl/AgendarReunionPostWriter.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/AgendarReunionPostWriter.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -40,7 +40,7 @@
 		{
       string resourceName = getBodyResourceName(track);
 
-			var fecha = getFechaFormateada(track.Evento.Fecha);
+			var fecha = getFechaFormateada(track.Evento.FechaInicio);
       return string.Format(CultureInfo.InvariantCulture, resourceName,
 													 fecha, //Fecha y hora en GMT+0
 													 track.Evento.Ponente.Nombre, //Nombre y apellido del ponente
--- a/Agendas/trunk/src/Agendas.Blog/Impl/BlogPublicador.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/BlogPublicador.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -40,7 +40,7 @@
 				}
 				catch (Exception ex)
 				{
-					track.LogAdd(new TrackLog(TrackLogPropietario.Blog, ex.Message, track.Usuario, false));
+					track.LogAdd(new TrackLog(TrackLogPropietario.Blog, track.Usuario, ex));
 				}
 			}
 		}
--- a/Agendas/trunk/src/Agendas.Domain/Agenda.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Agenda.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -46,7 +46,7 @@
             return _eventosRepository.GetByState(EventoPublicadoState.GetInstance()) ?? new List<Evento>();
         }
 
-        public Resultado ModificarEvento(Guid eventoId, string titulo, Guid ponenteId, DateTime? fecha, string urlInvitacion)
+        public EventoResultado ModificarEvento(Guid eventoId, string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion)
         {
             Evento evento = GetEvento(eventoId);
             Persona persona = _personaRepository.Get(ponenteId);
@@ -54,22 +54,25 @@
             if (evento.Titulo != titulo)
                 evento.CambiarTitulo(titulo);
 
-            if (evento.Fecha == null && fecha != null)
-                evento.Agendar(persona, fecha, urlInvitacion);
-            else if (evento.Fecha != fecha || evento.Ponente != persona || evento.UrlInvitacion != urlInvitacion)
-                evento.Actualizar(persona, fecha, urlInvitacion);
+            if (evento.FechaInicio == null && fechaInicio != null && evento.FechaTermino == null && fechaTermino != null)
+                evento.Agendar(persona, fechaInicio, fechaTermino, urlInvitacion);
+            else if (evento.FechaInicio != fechaInicio || evento.Ponente != persona || evento.UrlInvitacion != urlInvitacion ||
+                    evento.FechaTermino != fechaTermino)
+                evento.Actualizar(persona, fechaInicio, fechaTermino, urlInvitacion);
 
             Notify(evento);
 
-            return new Resultado(true);
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
+
+			return new EventoResultado(true,"Evento modificado", warnings);
+		}
+
+		public EventoResultado ModificarPropuesta(Guid id, string titulo, Guid ponenteId, string urlInvitacion)
+        {
+            return ModificarEvento(id, titulo, ponenteId, null, null, urlInvitacion);
         }
 
-        public Resultado ModificarPropuesta(Guid id, string titulo, Guid ponenteId, string urlInvitacion)
-        {
-            return ModificarEvento(id, titulo, ponenteId, null, urlInvitacion);
-        }
-
-        public Resultado Proponer(string titulo, Guid? ponenteId, string urlInvitacion, TipoEvento tipo)
+		public EventoResultado Proponer(string titulo, Guid? ponenteId, string urlInvitacion, TipoEvento tipo)
         {
             Persona persona = null;
             if (ponenteId.HasValue)
@@ -78,39 +81,44 @@
             var evento = Evento.Proponer(titulo, persona, urlInvitacion, tipo);
 
             if (string.IsNullOrWhiteSpace(evento.Titulo))
-                return new Resultado(false);
+                return new EventoResultado(false,"Debe indicar el título del evento", null);
 
             Notify(evento);
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
+
+			return new EventoResultado(true,"Evento propuesto", warnings);
+		}
 
-        public Resultado Agendar(string titulo, Guid ponenteId, DateTime? fecha, string urlInvitacion, TipoEvento tipo)
+		public EventoResultado Agendar(string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion, TipoEvento tipo)
         {
-            if (!fecha.HasValue)
-                return new Resultado(false);
+            if (!fechaInicio.HasValue)
+                return new EventoResultado(false, "Debe indicar la fecha", null);
+            if (!fechaTermino.HasValue)
+                return new EventoResultado(false, "Debe indicar la hora y duración", null);
 
             Persona persona = _personaRepository.Get(ponenteId);
             if (persona == null)
-                return new Resultado(false)
-                           {Message = string.Format("No se encontró el ponente indicado ({0})", ponenteId)};
+                return new EventoResultado(false, string.Format("No se encontró el ponente indicado ({0})", ponenteId), null);
 
             Evento evento = _eventosRepository.GetPropuestaByTitulo(titulo);
             if (evento == null)
-                evento = Evento.Agendar(titulo, persona, fecha.Value, urlInvitacion, tipo);
+                evento = Evento.Agendar(titulo, persona, fechaInicio.Value, fechaTermino.Value, urlInvitacion, tipo);
             else
-                evento.Agendar(persona, fecha, urlInvitacion);
+                evento.Agendar(persona, fechaInicio, fechaTermino, urlInvitacion);
 
             Notify(evento);
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
 
-        public Resultado Confirmar(Guid eventoId)
+			return new EventoResultado(true, "Evento creado", warnings);
+		}
+
+		public EventoResultado Confirmar(Guid eventoId)
         {
             Evento evento = GetEvento(eventoId);
 
@@ -120,10 +128,12 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
+
+			return new EventoResultado(true, "Evento confirmado", warnings);
         }
 
-        public Resultado Publicar(Guid eventoId, short numeroOrden, string urlWiki, TimeSpan duracion)
+		public EventoResultado Publicar(Guid eventoId, short numeroOrden, string urlWiki, TimeSpan duracion)
         {
             if (numeroOrden <= 0)
                 throw new ArgumentOutOfRangeException("numeroOrden");
@@ -142,23 +152,12 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
 
-        private void Notify(Evento evento)
-        {
-            var tracks = evento.GetTrackNews();
-            if (_publicador != null)
-                _publicador.Publicar(tracks);
-        }
+			return new EventoResultado(true, "Evento publicado", warnings);
+		}
 
-        public void RegistrarPonente(string nombre, string mail, string twitter, string blog)
-        {
-            var ponente = new Persona(nombre, mail, twitter, blog);
-            _personaRepository.Save(ponente);
-        }
-
-        public Resultado Cancelar(Guid eventoId)
+		public EventoResultado Cancelar(Guid eventoId)
         {
             Evento evento = GetEvento(eventoId);
 
@@ -168,10 +167,12 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
 
-        public Resultado Descartar(Guid eventoId)
+			return new EventoResultado(true,"Evento cancelado", warnings);
+		}
+
+		public EventoResultado Descartar(Guid eventoId)
         {
             Evento evento = GetEvento(eventoId);
 
@@ -181,10 +182,12 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
 
-        public Resultado ReProponer(Guid eventoId)
+			return new EventoResultado(true, "Evento descartado", warnings);
+		}
+
+		public EventoResultado ReProponer(Guid eventoId)
         {
             Evento evento = GetEvento(eventoId);
 
@@ -194,10 +197,12 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
 
-        public Resultado ReAgendar(Guid eventoId)
+			return new EventoResultado(true,"Evento re-prpuesto", warnings);
+		}
+
+		public EventoResultado ReAgendar(Guid eventoId)
         {
             Evento evento = GetEvento(eventoId);
 
@@ -207,8 +212,10 @@
 
             _eventosRepository.Save(evento);
 
-            return new Resultado(true);
-        }
+			var warnings = evento.GetLogsNews().Where(l => !l.Successful);
+
+			return new EventoResultado(true,"Evento re-agendado", warnings);
+		}
 
         public void IndicarPatrocinadores(Guid eventoId, IEnumerable<Guid> patrocinadores)
         {
@@ -238,5 +245,20 @@
             foreach (var patrocinador in quitar)
                 evento.RemovePatrocinador(patrocinador);
         }
-    }
+
+		private void Notify(Evento evento)
+		{
+			var tracks = evento.GetTrackNews();
+			if (_publicador != null)
+				_publicador.Publicar(tracks);
+		}
+
+		//TODO: este método ya no se debería usar
+		public void RegistrarPonente(string nombre, string mail, string twitter, string blog)
+		{
+			var ponente = new Persona(nombre, mail, twitter, blog);
+			_personaRepository.Save(ponente);
+		}
+
+	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Domain/Agendas.Domain.csproj	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Agendas.Domain.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -70,6 +70,7 @@
     <Compile Include="Repositories\IPatrocinadorRepository.cs" />
     <Compile Include="Repositories\IPersonaRepository.cs" />
     <Compile Include="Resultado.cs" />
+    <Compile Include="Rol.cs" />
     <Compile Include="Services\PersonaService.cs" />
     <Compile Include="TipoEvento.cs" />
     <Compile Include="Track.cs" />
--- a/Agendas/trunk/src/Agendas.Domain/Evento.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Evento.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 
 namespace AltNetHispano.Agendas.Domain
 {
@@ -14,7 +15,7 @@
 		#region Propiedades del Evento
 
 		private readonly IList<Track> _tracks;
-		private ICollection<Track> _newTracks = new List<Track>();
+		private readonly ICollection<Track> _newTracks = new List<Track>();
 
 		/// <summary>
 		/// Título del evento
@@ -24,9 +25,14 @@
 		/// <summary>
 		/// Fecha para la que se encuentra agendado el evento
 		/// </summary>
-		public virtual DateTime? Fecha { get; private set; }
+		public virtual DateTime? FechaInicio { get; private set; }
 
-		/// <summary>
+        /// <summary>
+        /// Fecha de termino o finalización del evento.
+        /// </summary>
+        public virtual DateTime? FechaTermino { get; private set; }
+
+	    /// <summary>
 		/// Url con la invitacion realizada por el ponente (en la mayoria de los casos va a ser un link al thread de la lista de correo)
 		/// </summary>
 		public virtual string UrlInvitacion { get; private set; }
@@ -117,41 +123,45 @@
 			return evento;
 		}
 
-		/// <summary>
-		/// Agenda un evento que no estaba propuesto
-		/// </summary>
-		/// <param name="titulo">Título del evento a agendar</param>
-		/// <param name="persona">Ponente para el evento</param>
-		/// <param name="fecha">Fecha de realización del evento</param>
-		/// <param name="urlInvitacion">Url con la invitación realizada por el ponente</param>
-		/// <param name="tipo">Tipo del evento</param>
-		/// <returns></returns>
-		public static Evento Agendar(string titulo, Persona persona, DateTime fecha, string urlInvitacion, TipoEvento tipo)
+	    /// <summary>
+	    /// Agenda un evento que no estaba propuesto
+	    /// </summary>
+	    /// <param name="titulo">Título del evento a agendar</param>
+	    /// <param name="persona">Ponente para el evento</param>
+	    /// <param name="fechaInicio">Fecha de realización del evento</param>
+	    /// <param name="fechaTermino">Fecha de termino del evento</param>
+	    /// <param name="urlInvitacion">Url con la invitación realizada por el ponente</param>
+	    /// <param name="tipo">Tipo del evento</param>
+	    /// <returns></returns>
+	    public static Evento Agendar(string titulo, Persona persona, DateTime fechaInicio, DateTime fechaTermino, string urlInvitacion, TipoEvento tipo)
 		{
 			var evento = new Evento { Titulo = titulo, Tipo = tipo };
-			evento.Agendar(persona, fecha, urlInvitacion);
+			evento.Agendar(persona, fechaInicio, fechaTermino, urlInvitacion);
 
 			return evento;
 		}
 
-		/// <summary>
-		/// Agenda el evento actual
-		/// </summary>
-		/// <param name="persona">Ponente para el evento</param>
-		/// <param name="fecha">Fecha de realización del evento</param>
-		/// <param name="urlInvitacion">Url con la invitación realizada por el ponente</param>
-		public virtual void Agendar(Persona persona, DateTime? fecha, string urlInvitacion)
+	    /// <summary>
+	    /// Agenda el evento actual
+	    /// </summary>
+	    /// <param name="persona">Ponente para el evento</param>
+        /// <param name="fechaInicio">Fecha de realización del evento</param>
+	    /// <param name="fechaTermino">Fecha de termino del evento</param>
+	    /// <param name="urlInvitacion">Url con la invitación realizada por el ponente</param>
+	    public virtual void Agendar(Persona persona, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion)
 		{
 			Ponente = persona;
-			Fecha = fecha;
+            FechaInicio = fechaInicio;
+	        FechaTermino = fechaTermino;
 			UrlInvitacion = urlInvitacion;
 			Estado.Promover(this, Accion.Agendar);
 		}
 
-		public virtual void Actualizar(Persona persona, DateTime? fecha, string urlInvitacion)
+		public virtual void Actualizar(Persona persona, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion)
 		{
 			Ponente = persona;
-			Fecha = fecha;
+			FechaInicio = fechaInicio;
+		    FechaTermino = fechaTermino;
 			UrlInvitacion = urlInvitacion;
 
 			AddTrack(new Track(this, Accion.Modificar));
@@ -207,5 +217,13 @@
 		{
 			return _newTracks;
 		}
+
+		public virtual IEnumerable<TrackLog> GetLogsNews()
+		{
+			var logs = new List<TrackLog>();
+			foreach (var track in _newTracks)
+				logs.AddRange(track.GetLogsNews());
+			return logs;
+		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Domain/IdentityContext.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/IdentityContext.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using AltNetHispano.Agendas.Domain.Exceptions;
 using AltNetHispano.Agendas.Domain.Repositories;
 
@@ -46,5 +48,17 @@
 			var cuenta = _personaRepository.GetCuenta(identification.IdentityProvider, identification.LogonName);
 			return cuenta != null ? cuenta.Persona : null;
 		}
+
+		public static bool IsInRole(IEnumerable<string> roles)
+		{
+			var persona = GetUsuario();
+			return IsInRole(persona, roles);
+		}
+
+		public static bool IsInRole(Persona persona, IEnumerable<string> roles)
+		{
+			if (persona == null) return false;
+			return roles.Any(role => persona.Roles.Contains(role));
+		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Domain/Persona.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Persona.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -23,6 +23,7 @@
 		{
 			Nombre = nombre;
 			_cuentas = new List<Cuenta>();
+			Roles = new List<string>();
 		}
 
 		public virtual string Nombre { get; set; }
@@ -33,6 +34,8 @@
 
 		public virtual string Blog { get; set; }
 
+		public virtual IList<string> Roles { get; set; }
+
 		public virtual IEnumerable<Cuenta> Cuentas
 		{
 			get { return _cuentas; }
--- a/Agendas/trunk/src/Agendas.Domain/Resultado.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Resultado.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,13 +1,27 @@
-namespace AltNetHispano.Agendas.Domain
+using System.Collections.Generic;
+
+namespace AltNetHispano.Agendas.Domain
 {
 	public class Resultado
 	{
-		public Resultado(bool succeful)
+		public Resultado(bool succeful, string message)
 		{
 			Succeful = succeful;
+			Message = message;
 		}
 
 		public bool Succeful { get; private set; }
         public string Message { get; internal set; }
-    }
+	}
+
+	public class EventoResultado : Resultado
+	{
+		public EventoResultado(bool succeful, string message, IEnumerable<TrackLog> warnings)
+			: base(succeful, message)
+		{
+			Warnings = warnings ?? new List<TrackLog>();
+		}
+
+		public IEnumerable<TrackLog> Warnings { get; set; }
+	}
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Domain/Rol.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,8 @@
+namespace AltNetHispano.Agendas.Domain
+{
+	public static class Roles
+	{
+		public const string Administrador = "Administrador";
+		public const string Usuario = "Usuario";
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Domain/Services/PersonaService.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Services/PersonaService.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -31,11 +31,27 @@
                 if (identityProvider == IdentityProviderEnum.Twitter)
                     persona.Twitter = username;
 
+            	SetDefaultGroups(persona);
+
                 _personaRepository.Save(persona);
             }
 		    return true;
 		}
 
+		private static void SetDefaultGroups(Persona persona)
+		{
+#if DEBUG
+			var administradores = new[] {"nelopauselli", "alabras", "jjmoa", "jrowies"};
+#else
+			var administradores = new[] {"alabras", "jrowies", "jorgegamba"};
+#endif
+			if (administradores.Contains(persona.Twitter))
+			{
+				persona.Roles.Add(Roles.Usuario);
+				persona.Roles.Add(Roles.Administrador);
+			}
+		}
+
 		public void AddCuenta(IdentityProviderEnum identityProvider, string username)
 		{
 			var persona = IdentityContext.GetUsuario();
@@ -63,20 +79,34 @@
 	        return _personaRepository.Get(id);
 	    }
 
-        public Resultado Add(string nombre, string twitter, string mail, string blog)
+		public Resultado Add(string nombre, string twitter, string mail, string blog, IEnumerable<string> roles)
         {
             var persona = new Persona(nombre) {Twitter = twitter, Mail = mail, Blog = blog};
-            _personaRepository.Save(persona);
+
+			if (!string.IsNullOrWhiteSpace(twitter))
+				persona.AddCuenta(new Cuenta(IdentityProviderEnum.Twitter, twitter));
+
+			SetDefaultGroups(persona);
 
-            return new Resultado(true);
+			if (roles != null)
+			{
+				persona.Roles.Clear();
+				foreach (var rol in roles)
+				{
+					persona.Roles.Add(rol);
+				}
+			}
+
+			_personaRepository.Save(persona);
+
+            return new Resultado(true, "Persona Agregada");
         }
 
-		public Resultado Update(Guid id, string nombre, string twitter, string mail, string blog)
+		public Resultado Update(Guid id, string nombre, string twitter, string mail, string blog, IEnumerable<string> roles)
 	    {
 	        var persona = _personaRepository.Get(id);
             if (persona == null)
-                return new Resultado(false)
-                           {Message = string.Format("No se pudo encontrar la persona cuyo Id sea {0}", id)};
+                return new Resultado(false, string.Format("No se pudo encontrar la persona cuyo Id sea {0}", id));
 
 	        persona.Nombre = nombre;
 	        persona.Twitter = twitter;
@@ -85,7 +115,16 @@
 
 			//TODO: ¿que hacemos con la cuenta de twitter asociada?
 
-	        return new Resultado(true);
+			if (roles!=null)
+			{
+				persona.Roles.Clear();
+				foreach (var rol in roles)
+				{
+					persona.Roles.Add(rol);
+				}
+			}
+
+			return new Resultado(true, "Datos actualizados");
 	    }
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Domain/Track.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Track.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -6,6 +6,7 @@
 	public class Track : Identificable
 	{
 		private readonly IList<TrackLog> _logs;
+		private readonly ICollection<TrackLog> _newLogs = new List<TrackLog>();
 
 		protected Track()
 		{
@@ -34,6 +35,13 @@
 		{
 			trackLog.Track = this;
 			_logs.Add(trackLog);
+			_newLogs.Add(trackLog);
+
+		}
+
+		public virtual IEnumerable<TrackLog> GetLogsNews()
+		{
+			return _newLogs;
 		}
 	}
 
--- a/Agendas/trunk/src/Agendas.Domain/TrackLog.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/TrackLog.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -8,29 +8,58 @@
 		{
 		}
 
-		public TrackLog(TrackLogPropietario propietario, string mensaje, Persona usuario, bool successful)
+		private TrackLog(TrackLogPropietario propietario, Persona usuario)
 		{
 			Propietario = propietario;
+			Usuario = usuario;
+			Fecha = DateTime.Now;
+		}
+
+		public TrackLog(TrackLogPropietario propietario, string mensaje, Persona usuario, bool successful)
+			: this(propietario, usuario)
+		{
 			Mensaje = mensaje;
-		  Fecha = DateTime.Now;
-		  Usuario = usuario;
-		  Successful = successful;
+			Successful = successful;
+		}
+
+		public TrackLog(TrackLogPropietario propietario, Persona usuario, Exception exception)
+			: this(propietario, usuario)
+		{
+			while (exception.InnerException != null)
+				exception = exception.InnerException;
+
+			Mensaje = exception.Message;
 		}
 
 		public virtual TrackLogPropietario Propietario { get; set; }
 		public virtual string Mensaje { get; set; }
 		public virtual Track Track { get; set; }
-    public virtual Persona Usuario { get; set; }
-	  public virtual bool Successful { get; set; }
-	  public virtual DateTime Fecha { get; set; }
+		public virtual Persona Usuario { get; set; }
+		public virtual bool Successful { get; set; }
+		public virtual DateTime Fecha { get; set; }
+
+		public virtual string WarningMessage
+		{
+			get
+			{
+				switch (Propietario)
+				{
+					case TrackLogPropietario.Twitter:
+						return "No se pudo enviar los twitters: " + Mensaje;
+					case TrackLogPropietario.Calendario:
+						return "No se pudo escribir en el calendario: " + Mensaje;
+					case TrackLogPropietario.Blog:
+						return "No se pudo escribir en el blog: " + Mensaje;
+				}
+				return Mensaje;
+			}
+		}
 	}
 
 	public enum TrackLogPropietario
 	{
 		Twitter = 1,
-        Blog = 2,
-        Calendario = 3
+		Blog = 2,
+		Calendario = 3
 	}
-
-
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Factories/Agendas.Factories.csproj	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Factories/Agendas.Factories.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -45,7 +45,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AgendaFactory.cs" />
-    <Compile Include="AttributeFactory.cs" />
+    <Compile Include="NHibernateFactory.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
--- a/Agendas/trunk/src/Agendas.Factories/AttributeFactory.cs	Tue Aug 09 08:53:38 2011 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-using System.Web.Mvc;
-using Agendas.NHibernate;
-
-namespace AltNetHispano.Agendas.Factories
-{
-	public class AttributeFactory
-	{
-		public static ActionFilterAttribute GetNHibernateSessionPerAction()
-		{
-			return new NHibernateSessionPerActionAttribute(NhHelper.GetSessionFactory());
-		}
-	}
-}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Factories/NHibernateFactory.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,19 @@
+using System;
+using System.Web.Mvc;
+using Agendas.NHibernate;
+
+namespace AltNetHispano.Agendas.Factories
+{
+	public static class NHibernateFactory
+	{
+		public static ActionFilterAttribute GetNHibernateSessionPerAction()
+		{
+			return new NHibernateSessionPerActionAttribute(NhHelper.GetSessionFactory());
+		}
+
+		public static IDisposable GetSessionScope()
+		{
+			return new SessionScope(NhHelper.GetSessionFactory());
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Google.Test/GCalendarTest.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google.Test/GCalendarTest.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -10,13 +10,14 @@
     [TestFixture]
     public class GCalendarTest : TestBase
     {
-        private readonly DateTime _fechaEvento = new DateTime(2011, 07, 16);
+        private readonly DateTime _fechaEvento = new DateTime(2011, 07, 16, 18, 0, 0, DateTimeKind.Utc);
+        private readonly DateTime _fechaTermino = new DateTime(2011, 07, 16, 20, 0, 0, DateTimeKind.Utc);
 
         [Test]
         public void CrearEventoGoogleCalendar()
         {
             var gCalendar = new GCalendarAdapter("VAN");
-            var ev = Evento.Agendar("Evento Test", null, _fechaEvento, "url", TipoEvento.Cafe);
+            var ev = Evento.Agendar("Evento Test", null, _fechaEvento, _fechaTermino, "url", TipoEvento.Cafe);
             string message;
             var detail = new CafeGEventDetail();
             detail.Generate(ev);
--- a/Agendas/trunk/src/Agendas.Google.Test/PublicadorTest.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google.Test/PublicadorTest.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -16,7 +16,9 @@
         public void CuandoPublicarEventoDadoAccionAgendarEntoncesEventoCreado()
         {
             var adapter = new Mock<IGCalendarAdapter>();
-            var message="";
+            string message;
+            var fechaInicio = new DateTime(2011, 07, 09, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
             adapter.Setup(ad => ad.CreateEvent(It.IsAny<IGEventDetail>(), out message)).Returns(true);
 
             var publicador = new GooglePublicador(adapter.Object);
@@ -25,7 +27,10 @@
             agenda.Proponer("Agile Patterns", null, null, TipoEvento.Van);
             adapter.Verify(ad => ad.CreateEvent(It.IsAny<IGEventDetail>(), out message), Times.Never());
 
-            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), new DateTime(2011, 07, 09), "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion", TipoEvento.Van);
+
+            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), fechaInicio,
+                           fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+                           TipoEvento.Van);
             adapter.Verify(ad => ad.CreateEvent(It.IsAny<IGEventDetail>(), out message), Times.Once());
         }
 
@@ -34,11 +39,15 @@
         {
             var adapter = new Mock<IGCalendarAdapter>();
             var detail = new VanGEventDetail();
+            var fechaInicio = new DateTime(2011, 07, 09, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
 
             var publicador = new GooglePublicador(adapter.Object);
 			var agenda = new Agenda(publicador, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
             agenda.Proponer("Agile Patterns", null, null, TipoEvento.Van);
-            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), new DateTime(2011, 07, 09), "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion", TipoEvento.Van);
+            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), fechaInicio,
+                           fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+                           TipoEvento.Van);
 
             var ev = DefaultEventoRepository.GetActivos()[0];
             detail.Generate(ev);
@@ -48,15 +57,15 @@
             
             Assert.AreEqual(DateTimeKind.Utc, detail.StartEvent.Kind);
             Assert.AreEqual(18, detail.StartEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.StartEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.StartEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.StartEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.StartEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.StartEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.StartEvent.Year);
 
             Assert.AreEqual(DateTimeKind.Utc, detail.EndEvent.Kind);
             Assert.AreEqual(20, detail.EndEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.EndEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.EndEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.EndEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.EndEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.EndEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.EndEvent.Year);
 
             Assert.AreEqual("La comunidad ALT.NET Hispano (http://altnethispano.org) realizará una VAN sobre Agile Patterns, con Alejandro Labra." +
                            "\n\rFecha: sábado, 09 de julio de 2011 a las 18:00 hrs. Hora Internacional (GMT/UTC), con una duración aproximada de 2 horas." +
@@ -70,11 +79,15 @@
         {
             var adapter = new Mock<IGCalendarAdapter>();
             var detail = new CafeGEventDetail();
+            var fechaInicio = new DateTime(2011, 07, 09, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
 
             var publicador = new GooglePublicador(adapter.Object);
 			var agenda = new Agenda(publicador, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
             agenda.Proponer("Agile Patterns", null, null, TipoEvento.Cafe);
-            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), new DateTime(2011, 07, 09), "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion", TipoEvento.Cafe);
+            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), fechaInicio,
+                           fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+                           TipoEvento.Cafe);
 
             var ev = DefaultEventoRepository.GetActivos()[0];
             detail.Generate(ev);
@@ -84,15 +97,15 @@
 
             Assert.AreEqual(DateTimeKind.Utc, detail.StartEvent.Kind);
             Assert.AreEqual(18, detail.StartEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.StartEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.StartEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.StartEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.StartEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.StartEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.StartEvent.Year);
 
             Assert.AreEqual(DateTimeKind.Utc, detail.EndEvent.Kind);
             Assert.AreEqual(20, detail.EndEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.EndEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.EndEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.EndEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.EndEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.EndEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.EndEvent.Year);
 
             Assert.AreEqual("La comunidad ALT.NET Hispano (http://altnethispano.org) realizará un Alt.Net Cafe virtual con el tema Agile Patterns." +
                            "\n\rFecha: sábado, 09 de julio de 2011 a las 18:00 hrs. Hora Internacional (GMT/UTC), con una duración aproximada de 2 horas." +
@@ -106,11 +119,15 @@
         {
             var adapter = new Mock<IGCalendarAdapter>();
             var detail = new EstudioGEventDetail();
+            var fechaInicio = new DateTime(2011, 07, 09, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
 
             var publicador = new GooglePublicador(adapter.Object);
 			var agenda = new Agenda(publicador, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
             agenda.Proponer("Agile Patterns", null, null, TipoEvento.GrupoEstudio);
-            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), new DateTime(2011, 07, 09), "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion", TipoEvento.GrupoEstudio);
+            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), fechaInicio,
+                           fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+                           TipoEvento.GrupoEstudio);
 
             var ev = DefaultEventoRepository.GetActivos()[0];
             detail.Generate(ev);
@@ -120,15 +137,15 @@
 
             Assert.AreEqual(DateTimeKind.Utc, detail.StartEvent.Kind);
             Assert.AreEqual(18, detail.StartEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.StartEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.StartEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.StartEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.StartEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.StartEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.StartEvent.Year);
 
             Assert.AreEqual(DateTimeKind.Utc, detail.EndEvent.Kind);
             Assert.AreEqual(20, detail.EndEvent.Hour);
-            Assert.AreEqual(ev.Fecha.Value.Day, detail.EndEvent.Day);
-            Assert.AreEqual(ev.Fecha.Value.Month, detail.EndEvent.Month);
-            Assert.AreEqual(ev.Fecha.Value.Year, detail.EndEvent.Year);
+            Assert.AreEqual(ev.FechaInicio.Value.Day, detail.EndEvent.Day);
+            Assert.AreEqual(ev.FechaInicio.Value.Month, detail.EndEvent.Month);
+            Assert.AreEqual(ev.FechaInicio.Value.Year, detail.EndEvent.Year);
 
             Assert.AreEqual("La comunidad ALT.NET Hispano (http://altnethispano.org) realizará un grupo de estudio sobre Agile Patterns." +
                            "\n\rFecha: sábado, 09 de julio de 2011 a las 18:00 hrs. Hora Internacional (GMT/UTC), con una duración aproximada de 2 horas." +
@@ -141,7 +158,9 @@
         public void CuandoPublicarEventoDadoAccionCancelarEntoncesEventoEliminado()
         {
             var adapter = new Mock<IGCalendarAdapter>();
-            var message = "";
+            string message;
+            var fechaInicio = new DateTime(2011, 07, 09, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
             adapter.Setup(ad => ad.DeleteEvent(It.IsAny<DateTime>(), It.IsAny<DateTime>(), out message)).Returns(true);
 
             var publicador = new GooglePublicador(adapter.Object);
@@ -150,7 +169,9 @@
             agenda.Proponer("Agile Patterns", null, null, TipoEvento.Van);
             adapter.Verify(ad => ad.DeleteEvent(It.IsAny<DateTime>(), It.IsAny<DateTime>(), out message), Times.Never());
 
-            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), new DateTime(2011, 07, 09), "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion", TipoEvento.Van);
+            agenda.Agendar("Agile Patterns", TestsHelper.GetOrCreatePonente("Alejandro Labra"), fechaInicio,
+                           fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+                           TipoEvento.Van);
             adapter.Verify(ad => ad.DeleteEvent(It.IsAny<DateTime>(), It.IsAny<DateTime>(), out message), Times.Never());
 
             var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Agile Patterns");
--- a/Agendas/trunk/src/Agendas.Google/DetailsEvents/CafeGEventDetail.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google/DetailsEvents/CafeGEventDetail.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -23,8 +23,8 @@
         {
             Title = "Alt.Net Café " + evento.Titulo;
             Location = "http://snipr.com/virtualaltnet";
-            if (evento.Fecha != null)
-                StartEvent = new DateTime(evento.Fecha.Value.Year, evento.Fecha.Value.Month, evento.Fecha.Value.Day,
+            if (evento.FechaInicio != null)
+                StartEvent = new DateTime(evento.FechaInicio.Value.Year, evento.FechaInicio.Value.Month, evento.FechaInicio.Value.Day,
                                           18, 0, 0, DateTimeKind.Utc);
             EndEvent = StartEvent.AddHours(2);
 
--- a/Agendas/trunk/src/Agendas.Google/DetailsEvents/EstudioGEventDetail.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google/DetailsEvents/EstudioGEventDetail.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -23,8 +23,8 @@
         {
             Title = "Grupo de Estudio " + evento.Titulo;
             Location = "http://snipr.com/virtualaltnet";
-            if (evento.Fecha != null)
-                StartEvent = new DateTime(evento.Fecha.Value.Year, evento.Fecha.Value.Month, evento.Fecha.Value.Day,
+            if (evento.FechaInicio != null)
+                StartEvent = new DateTime(evento.FechaInicio.Value.Year, evento.FechaInicio.Value.Month, evento.FechaInicio.Value.Day,
                                           18, 0, 0, DateTimeKind.Utc);
             EndEvent = StartEvent.AddHours(2);
 
--- a/Agendas/trunk/src/Agendas.Google/DetailsEvents/VanGEventDetail.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google/DetailsEvents/VanGEventDetail.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -24,8 +24,8 @@
         {
             Title = "VAN sobre " + evento.Titulo;
             Location = "http://snipr.com/virtualaltnet";
-            if (evento.Fecha != null)
-                StartEvent = new DateTime(evento.Fecha.Value.Year, evento.Fecha.Value.Month, evento.Fecha.Value.Day,
+            if (evento.FechaInicio != null)
+                StartEvent = new DateTime(evento.FechaInicio.Value.Year, evento.FechaInicio.Value.Month, evento.FechaInicio.Value.Day,
                                           18, 0, 0, DateTimeKind.Utc);
             EndEvent = StartEvent.AddHours(2);
 
--- a/Agendas/trunk/src/Agendas.Google/GooglePublicador.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google/GooglePublicador.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using AltNetHispano.Agendas.Configurations;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Google.DetailsEvents;
@@ -31,34 +32,41 @@
 
 		    foreach (var track in tracks)
 		    {
-                switch (track.Accion)
-                {
-                    case Accion.Agendar:
-                        PublicarAccionAgendar(track);
-                        break;
-                    case Accion.Cancelar:
-                        PublicarAccionCancelar(track);
-                        break;
-                }
+		    	try
+		    	{
+		    		switch (track.Accion)
+		    		{
+		    			case Accion.Agendar:
+		    				PublicarAccionAgendar(track);
+		    				break;
+		    			case Accion.Cancelar:
+		    				PublicarAccionCancelar(track);
+		    				break;
+		    		}
+		    	}
+		    	catch (Exception ex)
+		    	{
+		    		track.LogAdd(new TrackLog(TrackLogPropietario.Calendario, track.Usuario, ex));
+		    	}
 		    }
 		}
 
 	    private void PublicarAccionCancelar(Track track)
 	    {
             string message;
-	        var result= _adapter.DeleteEvent(track.Evento.Fecha.Value, track.Evento.Fecha.Value.AddHours(2), out message);
+	        var result= _adapter.DeleteEvent(track.Evento.FechaInicio.Value, track.Evento.FechaInicio.Value.AddHours(2), out message);
             track.LogAdd(new TrackLog(TrackLogPropietario.Calendario, message, track.Usuario, result));
 	    }
 
-	    private void PublicarAccionAgendar(Track track)
-        {
-            string message;
-            _gEventDetails[track.Evento.Tipo].Generate(track.Evento);
-            var result = _adapter.CreateEvent(_gEventDetails[track.Evento.Tipo], out message);
-            track.LogAdd(new TrackLog(TrackLogPropietario.Calendario, message, track.Usuario, result));
-        }
+		private void PublicarAccionAgendar(Track track)
+		{
+			_gEventDetails[track.Evento.Tipo].Generate(track.Evento);
+			string message;
+			var result = _adapter.CreateEvent(_gEventDetails[track.Evento.Tipo], out message);
+			track.LogAdd(new TrackLog(TrackLogPropietario.Calendario, message, track.Usuario, result));
+		}
 
-        public GooglePublicador()
+		public GooglePublicador()
             : this(new GCalendarAdapter("VAN", GetUserName, GetPassword, GetCalendarId))
         {
         }
--- a/Agendas/trunk/src/Agendas.NHibernate/Agendas.NHibernate.csproj	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.NHibernate/Agendas.NHibernate.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -58,6 +58,7 @@
     <Compile Include="NhHelper.cs" />
     <Compile Include="NHibernateSessionPerActionAttribute.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SessionScope.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.NHibernate/SessionScope.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,27 @@
+using System;
+using NHibernate;
+using NHibernate.Context;
+
+namespace Agendas.NHibernate
+{
+	public class SessionScope : IDisposable
+	{
+		private readonly ISessionFactory _sessionFactory;
+
+		public SessionScope(ISessionFactory sessionFactory)
+		{
+			_sessionFactory = sessionFactory;
+
+			var session = _sessionFactory.OpenSession();
+			CurrentSessionContext.Bind(session);
+		}
+
+		public void Dispose()
+		{
+			var session = _sessionFactory.GetCurrentSession();
+
+			session.Flush();
+			session.Close();
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.Designer.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.Designer.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,10 +1,10 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
-//     Este código fue generado por una herramienta.
-//     Versión de runtime:4.0.30319.235
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.235
 //
-//     Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
-//     se vuelve a generar el código.
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
 // </auto-generated>
 //------------------------------------------------------------------------------
 
@@ -13,12 +13,12 @@
     
     
     /// <summary>
-    ///   Clase de recurso con establecimiento inflexible de tipos, para buscar cadenas traducidas, etc.
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
     /// </summary>
-    // StronglyTypedResourceBuilder generó automáticamente esta clase
-    // a través de una herramienta como ResGen o Visual Studio.
-    // Para agregar o quitar un miembro, edite el archivo .ResX y, a continuación, vuelva a ejecutar ResGen
-    // con la opción /str o vuelva a generar su proyecto de VS.
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
@@ -33,7 +33,7 @@
         }
         
         /// <summary>
-        ///   Devuelve la instancia de ResourceManager almacenada en caché utilizada por esta clase.
+        ///   Returns the cached ResourceManager instance used by this class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
         public static global::System.Resources.ResourceManager ResourceManager {
@@ -47,8 +47,8 @@
         }
         
         /// <summary>
-        ///   Reemplaza la propiedad CurrentUICulture del subproceso actual para todas las
-        ///   búsquedas de recursos mediante esta clase de recurso con establecimiento inflexible de tipos.
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
         public static global::System.Globalization.CultureInfo Culture {
@@ -61,7 +61,16 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Duración.
+        ///   Looks up a localized string similar to Duración.
+        /// </summary>
+        public static string Duracion {
+            get {
+                return ResourceManager.GetString("Duracion", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Duración.
         /// </summary>
         public static string DuracionReal {
             get {
@@ -70,7 +79,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Tiempo que duró la presentación..
+        ///   Looks up a localized string similar to Tiempo que duró la presentación..
         /// </summary>
         public static string DuracionRealDescription {
             get {
@@ -79,7 +88,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Correo electrónico.
+        ///   Looks up a localized string similar to Correo electrónico.
         /// </summary>
         public static string EMail {
             get {
@@ -88,7 +97,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Correo electrónico de la persona para contactarse con ella.
+        ///   Looks up a localized string similar to Correo electrónico de la persona para contactarse con ella.
         /// </summary>
         public static string EMailDescription {
             get {
@@ -97,7 +106,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a debe ingresar la fecha del evento.
+        ///   Looks up a localized string similar to debe ingresar la fecha del evento.
         /// </summary>
         public static string FechaRequired {
             get {
@@ -106,7 +115,16 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Nombre de la persona que identifica a esta persona entre todas.
+        ///   Looks up a localized string similar to Hora (GMT +0).
+        /// </summary>
+        public static string Hora {
+            get {
+                return ResourceManager.GetString("Hora", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Nombre de la persona que identifica a esta persona entre todas.
         /// </summary>
         public static string NombreDescription {
             get {
@@ -115,7 +133,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Nro. de Orden.
+        ///   Looks up a localized string similar to Nro. de Orden.
         /// </summary>
         public static string NroOrden {
             get {
@@ -124,7 +142,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Un número consecutivo que identifica al evento en el tiempo..
+        ///   Looks up a localized string similar to Un número consecutivo que identifica al evento en el tiempo..
         /// </summary>
         public static string NroOrdenDescription {
             get {
@@ -133,7 +151,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a El valor debe ser entre {1} y {2}.
+        ///   Looks up a localized string similar to El valor debe ser entre {1} y {2}.
         /// </summary>
         public static string NroOrdenRange {
             get {
@@ -142,7 +160,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Debe ingresar el número de orden del evento.
+        ///   Looks up a localized string similar to Debe ingresar el número de orden del evento.
         /// </summary>
         public static string NroOrdenRequired {
             get {
@@ -151,7 +169,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Seleccione el ponente o responsable del evento.
+        ///   Looks up a localized string similar to Seleccione el ponente o responsable del evento.
         /// </summary>
         public static string PonenteDescription {
             get {
@@ -160,7 +178,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a debe ingresar el nombre del ponente.
+        ///   Looks up a localized string similar to debe ingresar el nombre del ponente.
         /// </summary>
         public static string PonenteRequired {
             get {
@@ -169,7 +187,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Tipo de evento.
+        ///   Looks up a localized string similar to Tipo de evento.
         /// </summary>
         public static string TipoEvento {
             get {
@@ -178,7 +196,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Define las características que tendrá el evento como objetivo, dinámica del evento, etc..
+        ///   Looks up a localized string similar to Define las características que tendrá el evento como objetivo, dinámica del evento, etc..
         /// </summary>
         public static string TipoEventoDescription {
             get {
@@ -187,7 +205,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Título.
+        ///   Looks up a localized string similar to Título.
         /// </summary>
         public static string Titulo {
             get {
@@ -196,7 +214,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Título del evento, el mismo lo identifica entre todos los eventos.
+        ///   Looks up a localized string similar to Título del evento, el mismo lo identifica entre todos los eventos.
         /// </summary>
         public static string TituloDescription {
             get {
@@ -205,7 +223,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a debe ingresar el título.
+        ///   Looks up a localized string similar to debe ingresar el título.
         /// </summary>
         public static string TituloRequired {
             get {
@@ -214,7 +232,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Cuenta de Twitter de la persona, con esta cuenta podrá autenticarse.
+        ///   Looks up a localized string similar to Cuenta de Twitter de la persona, con esta cuenta podrá autenticarse.
         /// </summary>
         public static string TwitterDescription {
             get {
@@ -223,7 +241,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Url de la invitación.
+        ///   Looks up a localized string similar to Url de la invitación.
         /// </summary>
         public static string UrlInvitacion {
             get {
@@ -232,7 +250,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Ingrese la url de la cadena de mails donde se realizó la invitación para el evento.
+        ///   Looks up a localized string similar to Ingrese la url de la cadena de mails donde se realizó la invitación para el evento.
         /// </summary>
         public static string UrlInvitacionDescription {
             get {
@@ -241,7 +259,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a La url ingresada no es válida.
+        ///   Looks up a localized string similar to La url ingresada no es válida.
         /// </summary>
         public static string UrlInvitacionUrl {
             get {
@@ -250,7 +268,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a Url de la Wiki.
+        ///   Looks up a localized string similar to Url de la Wiki.
         /// </summary>
         public static string UrlWiki {
             get {
@@ -259,7 +277,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a La url donde se publica la presentación..
+        ///   Looks up a localized string similar to La url donde se publica la presentación..
         /// </summary>
         public static string UrlWikiDescription {
             get {
@@ -268,7 +286,7 @@
         }
         
         /// <summary>
-        ///   Busca una cadena traducida similar a La url ingresada no es válida.
+        ///   Looks up a localized string similar to La url ingresada no es válida.
         /// </summary>
         public static string UrlWikiUrl {
             get {
--- a/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.resx	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Resources/Properties/DataAnnotationResources.resx	Tue Aug 09 08:55:08 2011 -0300
@@ -117,6 +117,9 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <data name="Duracion" xml:space="preserve">
+    <value>Duración</value>
+  </data>
   <data name="DuracionReal" xml:space="preserve">
     <value>Duración</value>
   </data>
@@ -132,6 +135,9 @@
   <data name="FechaRequired" xml:space="preserve">
     <value>debe ingresar la fecha del evento</value>
   </data>
+  <data name="Hora" xml:space="preserve">
+    <value>Hora (GMT +0)</value>
+  </data>
   <data name="NombreDescription" xml:space="preserve">
     <value>Nombre de la persona que identifica a esta persona entre todas</value>
   </data>
--- a/Agendas/trunk/src/Agendas.Tests/AgendarTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/AgendarTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -31,8 +31,12 @@
 
 			var agenda = new Agenda(publicador.Object, repository.Object, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			Assert.Throws<Exception>(
-                () => agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now, urlInvitacion, TipoEvento.Van));
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    Assert.Throws<Exception>(
+		        () =>
+		        agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                       urlInvitacion, TipoEvento.Van));
 			Assert.AreEqual(0, agenda.GetEventosActivos().Count);
 
 			publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(1));
@@ -49,9 +53,12 @@
 
 			var agenda = new Agenda(publicador.Object, repository.Object, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			Assert.Throws<IdentityContextNotConfiguredException>(
-				() => agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		  urlInvitacion, TipoEvento.Van));
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    Assert.Throws<IdentityContextNotConfiguredException>(
+		        () =>
+		        agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                       urlInvitacion, TipoEvento.Van));
 			repository.Verify(p => p.Save(It.IsAny<Evento>()), Times.Exactly(0));
 		}
 
@@ -65,8 +72,12 @@
 
 			var agenda = new Agenda(publicador.Object, repository.Object, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			Assert.Throws<UsuarioNoAutenticadoException>(() => agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		urlInvitacion, TipoEvento.Van));
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    Assert.Throws<UsuarioNoAutenticadoException>(
+		        () =>
+		        agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                       urlInvitacion, TipoEvento.Van));
 
 			publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(0));
 			repository.Verify(p => p.Save(It.IsAny<Evento>()), Times.Exactly(0));
@@ -77,8 +88,9 @@
 		{
 			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			var r = agenda.Agendar("Van para publicar", Guid.Empty, DateTime.Now,
-		urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    var r = agenda.Agendar("Van para publicar", Guid.Empty, fechaInicio, fechaTermino, urlInvitacion, TipoEvento.Van);
 
 			Assert.IsFalse(r.Succeful);
 		}
@@ -94,8 +106,10 @@
 			var agenda = new Agenda(new CompositePublicador(new[] { publicador1.Object, publicador2.Object }),
 															repository.Object, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                   urlInvitacion, TipoEvento.Van);
 
 			publicador1.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(1));
 			publicador2.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(1));
@@ -109,8 +123,10 @@
 
 			var agenda = new Agenda(publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                   urlInvitacion, TipoEvento.Van);
 
 			Assert.AreEqual(0, agenda.GetEventosActivos(EventoPropuestoState.GetInstance()).Count);
 
@@ -131,29 +147,36 @@
 			var publicador = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador.Object, repository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
+		    var fechaInicioVanPublicar = DateTime.Now.ToUniversalTime();
+		    var fechaTerminoVanPublicar = fechaInicioVanPublicar.AddHours(2);
 
-			agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		urlInvitacion, TipoEvento.Van);
+		    agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicioVanPublicar,
+		                   fechaTerminoVanPublicar,
+		                   urlInvitacion, TipoEvento.Van);
 
 			publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(1));
 
 			var evento = repository.GetActivos().First();
 			Assert.AreNotEqual(Guid.Empty, evento.Id);
-			Assert.IsNotNull(evento.Fecha);
+			Assert.IsNotNull(evento.FechaInicio);
 
-			DateTime fecha = evento.Fecha.Value.AddDays(7);
-			agenda.ModificarEvento(evento.Id, "otro titulo", TestsHelper.GetOrCreatePonente("otro ponente"), fecha, urlInvitacion);
+			var fechaInicio = evento.FechaInicio.Value.AddDays(7);
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.ModificarEvento(evento.Id, "otro titulo", TestsHelper.GetOrCreatePonente("otro ponente"), fechaInicio,
+		                           fechaTermino, urlInvitacion);
 
 			publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
 
 			evento = repository.GetActivos().First();
 			Assert.AreEqual("otro titulo", evento.Titulo);
 			Assert.AreEqual("otro ponente", evento.Ponente.Nombre);
-			Assert.AreEqual(fecha, evento.Fecha);
+			Assert.AreEqual(fechaInicio, evento.FechaInicio);
 
 			var idEventoNoExistente = new Guid("99999999999999999999999999999999");
-			Assert.Throws<EventoNotFoundException>(
-				() => agenda.ModificarEvento(idEventoNoExistente, "algún título", TestsHelper.GetOrCreatePonente("un ponente"), DateTime.Now, urlInvitacion));
+		    Assert.Throws<EventoNotFoundException>(
+		        () =>
+		        agenda.ModificarEvento(idEventoNoExistente, "algún título", TestsHelper.GetOrCreatePonente("un ponente"),
+		                               DateTime.Now, DateTime.Now.AddHours(2), urlInvitacion));
 		}
 
 		[Test, Ignore("Por ahora no existe el concepto de recordar")]
@@ -165,8 +188,10 @@
 			var agenda = new Agenda(new CompositePublicador(new[] { publicador1.Object, publicador2.Object }),
 															DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-			agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-		urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Van para publicar", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                   urlInvitacion, TipoEvento.Van);
 
 			var van = agenda.GetEventosActivos().Single(v => v.Titulo == "Van para publicar");
 			//agenda.Recordar(van.Id);
@@ -192,7 +217,10 @@
 			var publicado = agenda.GetEventosActivos(EventoPropuestoState.GetInstance()).First();
 			Assert.AreEqual(1, publicado.Tracks.Count());
 
-			agenda.ModificarEvento(publicado.Id, "Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Today.AddDays(5), urlInvitacion);
+		    var fechaInicio = DateTime.Today.AddDays(5).ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.ModificarEvento(publicado.Id, "Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio,
+		                           fechaTermino, urlInvitacion);
 			Assert.AreEqual(0, agenda.GetEventosActivos(EventoPropuestoState.GetInstance()).Count);
 			Assert.AreEqual(1, agenda.GetEventosActivos(EventoAgendadoState.GetInstance()).Count);
 			Assert.AreEqual(1, agenda.GetEventosActivos().Count);
@@ -226,7 +254,10 @@
 			var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-			agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.MinValue.ToUniversalTime();
+		    var fechatermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechatermino, urlInvitacion,
+		                   TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 
@@ -240,7 +271,10 @@
             var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.MinValue.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
 
             var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 
@@ -257,7 +291,10 @@
             var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.MinValue.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
 
             var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 
@@ -275,7 +312,10 @@
 			var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-			agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.MinValue.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 
@@ -293,7 +333,10 @@
 			var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-			agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.MinValue.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino, urlInvitacion,
+		                   TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 
@@ -312,7 +355,10 @@
 			var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-			agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.MinValue.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino, urlInvitacion,
+		                   TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 			agenda.Confirmar(evento.Id);
@@ -366,7 +412,10 @@
             var publicador1 = new Mock<IPublicador>();
 
             var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.MinValue.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
 
             var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
             agenda.Confirmar(evento.Id);
@@ -384,7 +433,10 @@
             var publicador1 = new Mock<IPublicador>();
 
             var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.MinValue.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
 
             var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
             agenda.Confirmar(evento.Id);
@@ -400,7 +452,10 @@
 			var publicador1 = new Mock<IPublicador>();
 
 			var agenda = new Agenda(publicador1.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-			agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.MinValue, urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.MinValue.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino, urlInvitacion,
+		                   TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().Single(e => e.Titulo == "Html 5");
 			agenda.Confirmar(evento.Id);
--- a/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -76,13 +76,18 @@
     <Compile Include="Blog\PublicadorTests.cs" />
     <Compile Include="Cruds\EventoCrud.cs" />
     <Compile Include="Cruds\EventoCrudNhTests.cs" />
+    <Compile Include="Cruds\IPersonaCrudTest.cs" />
     <Compile Include="Cruds\PatrocinadorCrud.cs" />
     <Compile Include="Cruds\PatrocinadorCrudMemoryTests.cs" />
     <Compile Include="Cruds\PatrocinadorCrudNhTests.cs" />
+    <Compile Include="Cruds\PersonaCrud.cs" />
+    <Compile Include="Cruds\PersonaCrudMemoryTests.cs" />
+    <Compile Include="Cruds\PersonaCrudNhTests.cs" />
     <Compile Include="Cruds\RequestEmulator.cs" />
     <Compile Include="DateTimeFormattingTests.cs" />
     <Compile Include="EventoStateTests.cs" />
     <Compile Include="Eventos_y_patrocinadores_tests.cs" />
+    <Compile Include="IdentityContextTests.cs" />
     <Compile Include="PersonaServiceTests.cs" />
     <Compile Include="PonentesTests.cs" />
     <Compile Include="PropuestasTests.cs" />
@@ -93,7 +98,8 @@
     <Compile Include="TestsHelper.cs" />
     <Compile Include="TrackTests.cs" />
     <Compile Include="Workflows\Workflow.cs" />
-    <Compile Include="Workflows\WorkflowTests.cs" />
+    <Compile Include="Workflows\WorkflowNhTests.cs" />
+    <Compile Include="Workflows\WorkflowMemoryTests.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Agendas.Blog\Agendas.Blog.csproj">
--- a/Agendas/trunk/src/Agendas.Tests/Cruds/EventoCrud.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/EventoCrud.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -62,6 +62,8 @@
 		public void Update()
 		{
 			Guid eventoId = Create();
+		    var fechaInicio = new DateTime(2010, 04, 17).ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
 
 			using (_requestEmulator.Invoke())
 			{
@@ -74,7 +76,7 @@
 				var otroPonente = new Persona("José");
 				_personaRepository.Save(otroPonente);
 
-				van.Actualizar(otroPonente, new DateTime(2010, 04, 17), null);
+				van.Actualizar(otroPonente, fechaInicio, fechaTermino, null);
 
 				_eventoRepository.Update(van);
 			}
@@ -87,7 +89,8 @@
 				Assert.IsNotNull(van.Ponente);
 				Assert.AreEqual("José", van.Ponente.Nombre);
 				Assert.AreEqual("TDD & Ejemplos", van.Titulo);
-				Assert.AreEqual(new DateTime(2010, 04, 17), van.Fecha);
+				Assert.AreEqual(new DateTime(2010, 04, 17).ToUniversalTime(), van.FechaInicio);
+                Assert.AreEqual(fechaTermino, van.FechaTermino);
 
 				var ponente1 = _personaRepository.GetByNombre("Carlos Blé");
 				Assert.IsNotNull(ponente1);
@@ -133,7 +136,7 @@
 				Evento evento = _eventoRepository.Get(eventoId);
 				Assert.AreEqual(EventoPropuestoState.GetInstance(), evento.Estado);
 
-				evento.Agendar(evento.Ponente, evento.Fecha, null);
+				evento.Agendar(evento.Ponente, evento.FechaInicio, evento.FechaTermino, null);
 			}
 
 			using (_requestEmulator.Invoke())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/IPersonaCrudTest.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,22 @@
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Cruds
+{
+	public interface IPersonaCrudTest
+	{
+		[Test]
+		void CreateAdministrador();
+
+		[Test]
+		void ReadAdministrador();
+
+		[Test]
+		void CreateUsuario();
+
+		[Test]
+		void ReadUsuario();
+
+		[Test]
+		void Update();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrud.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,122 @@
+using System;
+using System.Linq;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Domain.Repositories;
+using AltNetHispano.Agendas.Domain.Services;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Cruds
+{
+	public class PersonaCrud
+	{
+		private readonly IPersonaRepository _personaRepository;
+		private readonly Func<IDisposable> _requestEmulator;
+		private readonly PersonaService _personaService;
+
+		public PersonaCrud(Func<IPersonaRepository> createpersonaRepository, Func<IDisposable> requestEmulator)
+		{
+			_personaRepository = createpersonaRepository.Invoke();
+			_personaService = new PersonaService(_personaRepository);
+			_requestEmulator = requestEmulator;
+		}
+
+		public Guid CreateAdministrador()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				_personaService.Add("Nelo Pauselli", "nelopauselli", "nelopauselli@gmail.com", "http://nelopauselli.blogspot.com", null);
+			}
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.GetByNombre("Nelo Pauselli");
+				Assert.IsNotNull(persona);
+				return persona.Id;
+			}
+		}
+
+		public void ReadAdministrador()
+		{
+			Guid personaId = CreateAdministrador();
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.Get(personaId);
+
+				Assert.IsNotNull(persona);
+				Assert.AreEqual("Nelo Pauselli", persona.Nombre);
+				Assert.AreEqual("nelopauselli", persona.Twitter);
+				Assert.AreEqual("nelopauselli@gmail.com", persona.Mail);
+				Assert.AreEqual("http://nelopauselli.blogspot.com", persona.Blog);
+
+				Assert.IsTrue(persona.Cuentas.Any());
+				Assert.AreEqual("nelopauselli", persona.Cuentas.First().LogonName);
+				Assert.AreEqual(IdentityProviderEnum.Twitter, persona.Cuentas.First().IdentityProvider);
+
+				Assert.IsTrue(persona.Roles.Any());
+				Assert.IsTrue(persona.Roles.Contains(Roles.Usuario));
+				Assert.IsTrue(persona.Roles.Contains(Roles.Administrador));
+			}
+		}
+
+		public Guid CreateUsuario()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				_personaService.Add("Pablo Morales", "pablomorales", "pablomorales@gmail.com", "http://pablomorales.blogspot.com", new[]{Roles.Usuario});
+			}
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.GetByNombre("Pablo Morales");
+				Assert.IsNotNull(persona);
+				return persona.Id;
+			}
+		}
+
+		public void ReadUsuario()
+		{
+			Guid personaId = CreateUsuario();
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.Get(personaId);
+
+				Assert.IsNotNull(persona);
+				Assert.AreEqual("Pablo Morales", persona.Nombre);
+				Assert.AreEqual("pablomorales", persona.Twitter);
+				Assert.AreEqual("pablomorales@gmail.com", persona.Mail);
+				Assert.AreEqual("http://pablomorales.blogspot.com", persona.Blog);
+
+				Assert.IsTrue(persona.Cuentas.Any());
+				Assert.AreEqual("pablomorales", persona.Cuentas.First().LogonName);
+				Assert.AreEqual(IdentityProviderEnum.Twitter, persona.Cuentas.First().IdentityProvider);
+
+				Assert.IsTrue(persona.Roles.Any());
+				Assert.IsTrue(persona.Roles.Contains(Roles.Usuario));
+				Assert.IsFalse(persona.Roles.Contains(Roles.Administrador));
+			}
+		}
+
+		public void Update()
+		{
+			Guid personaId = CreateAdministrador();
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.Get(personaId);
+				Assert.IsNotNull(persona);
+
+				persona.Nombre = "Nelo Mariano Pauselli";
+			}
+
+			using (_requestEmulator.Invoke())
+			{
+				var persona = _personaRepository.Get(personaId);
+
+				Assert.IsNotNull(persona);
+				Assert.AreEqual("Nelo Mariano Pauselli", persona.Nombre);
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrudMemoryTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,68 @@
+using System;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Repositories.Memory;
+using Moq;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Cruds
+{
+	[TestFixture]
+	public class PersonaCrudMemoryTests : IPersonaCrudTest
+	{
+		private PersonaCrud _test;
+
+		#region SetUp
+
+		[SetUp]
+		public void BorrarRepositorios()
+		{
+			PersonaRepository.Clear();
+		}
+
+		[SetUp]
+		public void SetearUsuario()
+		{
+			var seguridad = new Mock<ISeguridad>();
+			seguridad.Setup(s => s.GetUserName()).Returns("neluz");
+			IdentityContext.Init(seguridad.Object, new PersonaRepository());
+		}
+
+		[SetUp]
+		public void CreateCrud()
+		{
+			_test = new PersonaCrud(() => new PersonaRepository(), () => new Mock<IDisposable>().Object);
+		}
+
+		#endregion
+
+		[Test]
+		public void CreateAdministrador()
+		{
+			_test.CreateAdministrador();
+		}
+
+		[Test]
+		public void ReadAdministrador()
+		{
+			_test.ReadAdministrador();
+		}
+
+		[Test]
+		public void CreateUsuario()
+		{
+			_test.CreateUsuario();
+		}
+
+		[Test]
+		public void ReadUsuario()
+		{
+			_test.ReadUsuario();
+		}
+
+		[Test]
+		public void Update()
+		{
+			_test.Update();
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrudNhTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,74 @@
+using Agendas.NHibernate;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Repositories.NHibernate;
+using Moq;
+using NHibernate;
+using NHibernate.Cfg;
+using NHibernate.Tool.hbm2ddl;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Cruds
+{
+	[TestFixture]
+	public class PersonaCrudNhTests : IPersonaCrudTest
+	{
+		private PersonaCrud _test;
+
+		#region SetUp
+
+		[SetUp]
+		public void BorrarRepositorios()
+		{
+			Configuration cfg = NhHelper.GetConfiguration();
+			var schemaExport = new SchemaExport(cfg);
+			schemaExport.Create(false, true);
+		}
+
+		[SetUp]
+		public void SetearUsuario()
+		{
+			var seguridad = new Mock<ISeguridad>();
+			seguridad.Setup(s => s.GetUserName()).Returns("neluz");
+			IdentityContext.Init(seguridad.Object, new PersonaRepository(NhHelper.GetSessionFactory()));
+		}
+
+		[SetUp]
+		public void CreateCrud()
+		{
+			ISessionFactory sessionFactory = NhHelper.GetSessionFactory();
+			_test = new PersonaCrud(() => new PersonaRepository(sessionFactory), () => new RequestEmulator(sessionFactory));
+		}
+
+		#endregion
+
+		[Test]
+		public void CreateAdministrador()
+		{
+			_test.CreateAdministrador();
+		}
+
+		[Test]
+		public void ReadAdministrador()
+		{
+			_test.ReadAdministrador();
+		}
+
+		[Test]
+		public void CreateUsuario()
+		{
+			_test.CreateUsuario();
+		}
+
+		[Test]
+		public void ReadUsuario()
+		{
+			_test.ReadUsuario();
+		}
+
+		[Test]
+		public void Update()
+		{
+			_test.Update();
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Tests/Eventos_y_patrocinadores_tests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Eventos_y_patrocinadores_tests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -31,7 +31,7 @@
 
 			var evento = DefaultEventoRepository.GetActivos().First();
 			Assert.AreNotEqual(Guid.Empty, evento.Id);
-			Assert.IsNotNull(evento.Fecha);
+			Assert.IsNotNull(evento.FechaInicio);
 			Assert.IsNotNull(evento.Patrocinadores);
 			Assert.IsTrue(evento.Patrocinadores.Any());
 			Assert.IsTrue(evento.Patrocinadores.Any(p => p.Nombre == "Apress"));
@@ -98,7 +98,9 @@
 
 		private Guid CrearEvento()
 		{
-            _agenda.Agendar("ADFS", TestsHelper.GetOrCreatePonente("Nelo Pauselli"), DateTime.Today.AddDays(7), null, TipoEvento.Van);
+		    var fechaInicio = DateTime.Today.AddDays(7).ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+            _agenda.Agendar("ADFS", TestsHelper.GetOrCreatePonente("Nelo Pauselli"), fechaInicio, fechaTermino, null, TipoEvento.Van);
 
 			var evento = DefaultEventoRepository.GetActivos().First();
 			return evento.Id;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/IdentityContextTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,19 @@
+using AltNetHispano.Agendas.Domain;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests
+{
+	[TestFixture]
+	public class IdentityContextTests : TestBase
+	{
+		[Test]
+		public void IsInRole()
+		{
+			var persona = new Persona("Nelo");
+			persona.Roles.Add(Roles.Usuario);
+
+			Assert.IsTrue(IdentityContext.IsInRole(persona, new[] { Roles.Usuario }));
+			Assert.IsFalse(IdentityContext.IsInRole(persona, new[] { Roles.Administrador }));
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Tests/PersonaServiceTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/PersonaServiceTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -66,7 +66,7 @@
             var personaRepository = DefaultPersonaRepository;
 
             var personaService = new PersonaService(personaRepository);
-            var r = personaService.Add("Mariano Pauselli", "marianopauselli", string.Empty, string.Empty);
+			var r = personaService.Add("Mariano Pauselli", "marianopauselli", string.Empty, string.Empty, null);
             Assert.IsTrue(r.Succeful);
 
             var todas = personaService.GetAll();
@@ -81,7 +81,7 @@
             Assert.AreEqual(p1, p2);
             Assert.AreSame(p1, p2);
 
-            personaService.Update(personaId, p1.Nombre, p1.Twitter, "marianopauselli@gmail.com", string.Empty);
+            personaService.Update(personaId, p1.Nombre, p1.Twitter, "marianopauselli@gmail.com", string.Empty,null);
 
             var p3 = personaService.GetById(personaId);
             Assert.IsNotNull(p3);
--- a/Agendas/trunk/src/Agendas.Tests/PonentesTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/PonentesTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -19,11 +19,16 @@
             Assert.AreEqual(1, DefaultPersonaRepository.GetAll().Count);
 
             var agenda = new Agenda(publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
+            var fechaInicioNHibernate = new DateTime(2011, 2, 26, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTerminoNHibernate = fechaInicioNHibernate.AddHours(2);
 
-            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"), new DateTime(2011, 2, 26),
-        urlInvitacion, TipoEvento.Van);
-            agenda.Agendar("Conform - Parte 2", TestsHelper.GetOrCreatePonente("Fabio Maulo"), new DateTime(2011, 3, 5),
-        urlInvitacion, TipoEvento.Van);
+            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"),
+                           fechaInicioNHibernate, fechaTerminoNHibernate, urlInvitacion, TipoEvento.Van);
+            
+            var fechaInicioConform = new DateTime(2011, 3, 5, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTerminoConform = fechaInicioNHibernate.AddHours(2);
+            agenda.Agendar("Conform - Parte 2", TestsHelper.GetOrCreatePonente("Fabio Maulo"), fechaInicioConform,
+                           fechaTerminoConform, urlInvitacion, TipoEvento.Van);
 
             var eventos = agenda.GetEventosActivos();
             Assert.AreEqual(2, eventos.Count);
@@ -48,8 +53,10 @@
             var agenda = new Agenda(publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
             agenda.RegistrarPonente("Fabio Maulo", "fabiomaulo@gmail.com", "@fabiomaulo", "http://fabiomaulo.blogspot.com");
-
-            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"), new DateTime(2011, 2, 26), urlInvitacion, TipoEvento.Van);
+            var fechaInicio = new DateTime(2011, 2, 26, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"),
+                           fechaInicio, fechaTermino, urlInvitacion, TipoEvento.Van);
 
             Assert.AreEqual(1, agenda.GetEventosActivos().Count);
 
@@ -72,8 +79,10 @@
 
             var agenda = new Agenda(publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"), new DateTime(2011, 2, 26),
-        urlInvitacion, TipoEvento.Van);
+            var fechaInicio = new DateTime(2011, 2, 26, 18, 0, 0, DateTimeKind.Utc);
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Audit (parallel model) con NHibernate 3", TestsHelper.GetOrCreatePonente("Fabio Maulo"),
+                           fechaInicio, fechaTermino, urlInvitacion, TipoEvento.Van);
 
             Assert.AreEqual(1, agenda.GetEventosActivos().Count);
 
--- a/Agendas/trunk/src/Agendas.Tests/PropuestasTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/PropuestasTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -38,7 +38,10 @@
 				Assert.AreEqual("otro ponente", evento.Ponente.Nombre);
 			}
 
-			var r = agenda.Agendar("Van 2", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now, urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    var r = agenda.Agendar("Van 2", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                           urlInvitacion, TipoEvento.Van);
 			Assert.IsTrue(r.Succeful);
 			{
 				IList<Evento> eventosPropuestos = agenda.GetEventosActivos(EventoPropuestoState.GetInstance());
@@ -61,8 +64,8 @@
 			{
 				var van = agenda.GetEventosActivos(EventoPropuestoState.GetInstance()).FirstOrDefault();
 				Assert.IsNotNull(van);
-				var r = agenda.Agendar(van.Titulo, TestsHelper.GetOrCreatePonente("Ponente"), null,
-		  urlInvitacion, TipoEvento.Van);
+			    var r = agenda.Agendar(van.Titulo, TestsHelper.GetOrCreatePonente("Ponente"), null, null,
+			                           urlInvitacion, TipoEvento.Van);
 				Assert.IsFalse(r.Succeful);
 			}
 		}
@@ -80,9 +83,11 @@
 				var van = agenda.GetEventosActivos(EventoPropuestoState.GetInstance()).FirstOrDefault();
 				Assert.IsNotNull(van);
 
-				van.Actualizar(null, DateTime.Today.AddDays(5), urlInvitacion);
-				var r = agenda.Agendar(van.Titulo, Guid.Empty, van.Fecha,
-		  urlInvitacion, TipoEvento.Van);
+			    var fechaInicio = DateTime.Today.AddDays(5).ToUniversalTime();
+			    var fechaTermino = fechaInicio.AddHours(2);
+			    van.Actualizar(null, fechaInicio, fechaTermino, urlInvitacion);
+			    var r = agenda.Agendar(van.Titulo, Guid.Empty, van.FechaInicio, van.FechaTermino,
+			                           urlInvitacion, TipoEvento.Van);
 				Assert.IsFalse(r.Succeful);
 			}
 		}
@@ -138,8 +143,10 @@
 			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
 			agenda.Proponer("Van propuesta", null, urlInvitacion, TipoEvento.Van);
-			var r = agenda.Agendar("Van publicada", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-			                       urlInvitacion, TipoEvento.Van);
+		    var fechaInicio = DateTime.Now.ToUniversalTime();
+		    var fechaTermino = fechaInicio.AddHours(2);
+		    var r = agenda.Agendar("Van publicada", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino,
+		                           urlInvitacion, TipoEvento.Van);
 			Assert.IsTrue(r.Succeful);
 
 			IList<Evento> eventosPropuestos = agenda.GetEventosActivos(EventoPropuestoState.GetInstance());
--- a/Agendas/trunk/src/Agendas.Tests/TrackTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/TrackTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -17,8 +17,9 @@
 
             var agenda = new Agenda(null, repository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
 
-            var fecha = DateTime.Now.AddDays(5);
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fecha, urlInvitacion, TipoEvento.Van);
+            var fechaInicio = DateTime.Now.AddDays(5).ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), fechaInicio, fechaTermino, urlInvitacion, TipoEvento.Van);
             var evento = repository.GetActivos().First();
 
             Assert.AreEqual(1, evento.Tracks.Count());
@@ -28,7 +29,7 @@
             Assert.IsNotNull(ultimo.Usuario);
             Assert.AreEqual("Nelo Pauselli", ultimo.Usuario.Nombre);
 
-            agenda.ModificarEvento(evento.Id, "Html 5", TestsHelper.GetOrCreatePonente("otro ponente"), fecha, urlInvitacion);
+            agenda.ModificarEvento(evento.Id, "Html 5", TestsHelper.GetOrCreatePonente("otro ponente"), fechaInicio, fechaTermino, urlInvitacion);
             Assert.AreEqual(2, evento.Tracks.Count());
             ultimo = evento.Tracks.Last();
             Assert.AreEqual(evento, ultimo.Evento);
@@ -36,7 +37,7 @@
             Assert.IsNotNull(ultimo.Usuario);
             Assert.AreEqual("Nelo Pauselli", ultimo.Usuario.Nombre);
 
-            agenda.ModificarEvento(evento.Id, "Html 5 y Css 3", TestsHelper.GetOrCreatePonente("otro ponente"), fecha, urlInvitacion);
+            agenda.ModificarEvento(evento.Id, "Html 5 y Css 3", TestsHelper.GetOrCreatePonente("otro ponente"), fechaInicio, fechaTermino, urlInvitacion);
             Assert.AreEqual(3, evento.Tracks.Count());
             ultimo = evento.Tracks.Last();
             Assert.AreEqual(evento, ultimo.Evento);
@@ -51,9 +52,11 @@
             var repository = DefaultEventoRepository;
 
             var agenda = new Agenda(null, repository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
+            var fechaInicio = DateTime.Now.ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
 
-            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now,
-        urlInvitacion, TipoEvento.Van);
+            agenda.Agendar("Html 5", TestsHelper.GetOrCreatePonente("jjmontes"), DateTime.Now, fechaTermino,
+                           urlInvitacion, TipoEvento.Van);
             var evento = repository.GetActivos().First();
 
             Assert.AreEqual(1, evento.Tracks.Count());
--- a/Agendas/trunk/src/Agendas.Tests/Workflows/Workflow.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Workflows/Workflow.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Domain.Repositories;
 using NUnit.Framework;
@@ -7,61 +8,107 @@
 {
 	internal class Workflow
 	{
+		private readonly Func<IDisposable> _requestEmulator;
 		private readonly Agenda _agenda;
+		private readonly IEventoRepository _eventoRepository;
+		private Guid _eventoId;
 
-		public Workflow(IPublicador publicador, IEventoRepository eventoRepository, IPersonaRepository personaRepository, IPatrocinadorRepository patrocinadorRepository)
+		public Workflow(IPublicador publicador, IEventoRepository eventoRepository, IPersonaRepository personaRepository,
+		                IPatrocinadorRepository patrocinadorRepository, Func<IDisposable> requestEmulator)
 		{
+			_requestEmulator = requestEmulator;
+			_eventoRepository = eventoRepository;
 			_agenda = new Agenda(publicador, eventoRepository, personaRepository, patrocinadorRepository);
 		}
 
 		public void Proponer()
 		{
-
-            var resultado = _agenda.Proponer("SOLID", TestsHelper.GetOrCreatePonente("Jorge"), null, TipoEvento.Van);
-			Assert.IsTrue(resultado.Succeful);
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.Proponer("SOLID", TestsHelper.GetOrCreatePonente("Jorge"), null, TipoEvento.Van);
+				Assert.IsTrue(resultado.Succeful);
+			}
+			
+			GetId();
 		}
 
 
 		public void Agendar()
 		{
-      var resultado = _agenda.Agendar("SOLID", TestsHelper.GetOrCreatePonente("Jorge"), DateTime.Today.AddDays(5), null, TipoEvento.Van);
-			Assert.IsTrue(resultado.Succeful);
+			using (_requestEmulator.Invoke())
+			{
+			    var fechaInicio = DateTime.Today.AddDays(5).ToUniversalTime();
+			    var fechaTermino = fechaInicio.AddHours(2);
+			    var resultado = _agenda.Agendar("SOLID", TestsHelper.GetOrCreatePonente("Jorge"), fechaInicio, fechaTermino, null,
+			                                    TipoEvento.Van);
+				Assert.IsTrue(resultado.Succeful);
+			}
+			
+			GetId();
 		}
 
-		public void Confirmar(Guid eventoId)
+		private void GetId()
 		{
-			var resultado = _agenda.Confirmar(eventoId);
-			Assert.IsTrue(resultado.Succeful);
+			using (_requestEmulator.Invoke())
+			{
+				var evento = _eventoRepository.GetActivos().SingleOrDefault();
+				Assert.IsNotNull(evento);
+				_eventoId = evento.Id;
+			}
 		}
 
-		public void Publicar(Guid eventoId)
+		public void Confirmar()
 		{
-			var resultado = _agenda.Publicar(eventoId, 1, "http://www.altnethispano.org/", new TimeSpan(2, 11, 0));
-			Assert.IsTrue(resultado.Succeful);
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.Confirmar(_eventoId);
+				Assert.IsTrue(resultado.Succeful);
+			}
 		}
 
-	    public void Cancelar(Guid eventoId)
-	    {
-	        var resultado = _agenda.Cancelar(eventoId);
-            Assert.IsTrue(resultado.Succeful);
-	    }
+		public void Publicar()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.Publicar(_eventoId, 1, "http://www.altnethispano.org/", new TimeSpan(2, 11, 0));
+				Assert.IsTrue(resultado.Succeful);
+			}
+		}
 
-	    public void Descartar(Guid eventoId)
-	    {
-            var resultado = _agenda.Descartar(eventoId);
-            Assert.IsTrue(resultado.Succeful);
-	    }
+		public void Cancelar()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.Cancelar(_eventoId);
+				Assert.IsTrue(resultado.Succeful);
+			}
+		}
 
-	    public void ReProponer(Guid eventoId)
-	    {
-	        var resultado = _agenda.ReProponer(eventoId);
-            Assert.IsTrue(resultado.Succeful);
-	    }
+		public void Descartar()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.Descartar(_eventoId);
+				Assert.IsTrue(resultado.Succeful);
+			}
+		}
 
-        public void ReAgendar(Guid eventoId)
-        {
-            var resultado = _agenda.ReAgendar(eventoId);
-            Assert.IsTrue(resultado.Succeful);
-        }
+		public void ReProponer()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.ReProponer(_eventoId);
+				Assert.IsTrue(resultado.Succeful);
+			}
+		}
+
+		public void ReAgendar()
+		{
+			using (_requestEmulator.Invoke())
+			{
+				var resultado = _agenda.ReAgendar(_eventoId);
+				Assert.IsTrue(resultado.Succeful);
+			}
+		}
 	}
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Workflows/WorkflowMemoryTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,165 @@
+using System;
+using System.Collections.Generic;
+using AltNetHispano.Agendas.Domain;
+using Moq;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Workflows
+{
+	[TestFixture]
+	public class WorkflowMemoryTests : TestBase
+	{
+		private Mock<IPublicador> _publicador;
+		private Workflow _workflow;
+
+		[SetUp]
+		public void InitPublicador()
+		{
+			_publicador = new Mock<IPublicador>();
+			_workflow = new Workflow(_publicador.Object, DefaultEventoRepository, DefaultPersonaRepository,
+			                         DefaultPatrocinadorRepository, () => new Mock<IDisposable>().Object);
+		}
+
+		[Test]
+		public void Proponer()
+		{
+			_workflow.Proponer();
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Once());
+		}
+
+		[Test]
+		public void Proponer_y_agendar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
+		}
+
+        [Test]
+        public void Proponer_agendar_y_cancelar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _publicador.Verify(p=>p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
+        }
+
+        [Test]
+        public void Proponer_agendar_cancelar_y_reagendar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _workflow.ReAgendar();
+
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+        }
+
+        [Test]
+        public void Proponer_agendar_cancelar_reproponer_agendar_y_confirmar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _workflow.ReProponer();
+
+            _workflow.Agendar();
+
+            _workflow.Confirmar();
+
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(6));
+        }
+
+        [Test]
+        public void Proponer_agendar_cancelar_reagendar_y_confirmar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _workflow.ReAgendar();
+
+            _workflow.Confirmar();
+
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(5));
+        }
+
+	    [Test]
+        public void Proponer_agendar_cancelar_y_reproponer()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _workflow.ReProponer();
+
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+        }
+
+        [Test]
+        public void Proponer_y_descartar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Descartar();
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
+        }
+
+	    [Test]
+        public void Proponer_agendar_cancelar_y_descartar()
+        {
+            _workflow.Proponer();
+
+            _workflow.Agendar();
+
+            _workflow.Cancelar();
+
+            _workflow.Descartar();
+
+            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+        }
+
+	    [Test]
+		public void Proponer_agendar_y_confirmar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Confirmar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
+		}
+
+		[Test]
+		public void Proponer_agendar_confirmar_publicar()
+		{
+            const string urlWiki = "http://www.altnethispano.org/wiki/van-2010-10-21-mono-cecil.ashx";
+
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Confirmar();
+
+			_workflow.Publicar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/Workflows/WorkflowNhTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,164 @@
+using System.Collections.Generic;
+using Agendas.NHibernate;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Tests.Cruds;
+using Moq;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests.Workflows
+{
+	[TestFixture]
+	public class WorkflowNhTests : TestBase
+	{
+		private Mock<IPublicador> _publicador;
+		private Workflow _workflow;
+
+		[SetUp]
+		public void InitPublicador()
+		{
+			_publicador = new Mock<IPublicador>();
+			_workflow = new Workflow(_publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository, () => new RequestEmulator(NhHelper.GetSessionFactory()));
+		}
+
+		[Test]
+		public void Proponer()
+		{
+			_workflow.Proponer();
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Once());
+		}
+
+		[Test]
+		public void Proponer_y_agendar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
+		}
+		[Test]
+		public void Proponer_agendar_y_cancelar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
+		}
+
+		[Test]
+		public void Proponer_agendar_cancelar_y_reagendar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_workflow.ReAgendar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+		}
+
+		[Test]
+		public void Proponer_agendar_cancelar_reproponer_agendar_y_confirmar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_workflow.ReProponer();
+
+			_workflow.Agendar();
+
+			_workflow.Confirmar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(6));
+		}
+
+		[Test]
+		public void Proponer_agendar_cancelar_reagendar_y_confirmar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_workflow.ReAgendar();
+
+			_workflow.Confirmar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(5));
+		}
+
+		[Test]
+		public void Proponer_agendar_cancelar_y_reproponer()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_workflow.ReProponer();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+		}
+
+		[Test]
+		public void Proponer_y_descartar()
+		{
+			_workflow.Proponer();
+			
+			_workflow.Descartar();
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
+		}
+
+		[Test]
+		public void Proponer_agendar_cancelar_y_descartar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Cancelar();
+
+			_workflow.Descartar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+		}
+
+		[Test]
+		public void Proponer_agendar_y_confirmar()
+		{
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Confirmar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
+		}
+
+		[Test]
+		public void Proponer_agendar_confirmar_publicar()
+		{
+			const string urlWiki = "http://www.altnethispano.org/wiki/van-2010-10-21-mono-cecil.ashx";
+
+			_workflow.Proponer();
+
+			_workflow.Agendar();
+
+			_workflow.Confirmar();
+
+			_workflow.Publicar();
+
+			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Tests/Workflows/WorkflowTests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using AltNetHispano.Agendas.Domain;
-using Moq;
-using NUnit.Framework;
-
-namespace AltNetHispano.Agendas.Tests.Workflows
-{
-	[TestFixture]
-	public class WorkflowTests : TestBase
-	{
-		private Mock<IPublicador> _publicador;
-		private Workflow _workflow;
-
-		[SetUp]
-		public void InitPublicador()
-		{
-			_publicador = new Mock<IPublicador>();
-			_workflow = new Workflow(_publicador.Object, DefaultEventoRepository, DefaultPersonaRepository, DefaultPatrocinadorRepository);
-		}
-
-		[Test]
-		public void Proponer()
-		{
-			_workflow.Proponer();
-			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Once());
-		}
-
-		[Test]
-		public void Proponer_y_agendar()
-		{
-			_workflow.Proponer();
-
-			_workflow.Agendar();
-
-			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
-		}
-        [Test]
-        public void Proponer_agendar_y_cancelar()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _publicador.Verify(p=>p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
-        }
-
-        [Test]
-        public void Proponer_agendar_cancelar_y_reagendar()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _workflow.ReAgendar(evento.Id);
-
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
-        }
-
-        [Test]
-        public void Proponer_agendar_cancelar_reproponer_agendar_y_confirmar()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _workflow.ReProponer(evento.Id);
-
-            _workflow.Agendar();
-
-            _workflow.Confirmar(evento.Id);
-
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(6));
-        }
-
-        [Test]
-        public void Proponer_agendar_cancelar_reagendar_y_confirmar()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _workflow.ReAgendar(evento.Id);
-
-            _workflow.Confirmar(evento.Id);
-
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(5));
-        }
-
-	    [Test]
-        public void Proponer_agendar_cancelar_y_reproponer()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _workflow.ReProponer(evento.Id);
-
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
-        }
-
-        [Test]
-        public void Proponer_y_descartar()
-        {
-            _workflow.Proponer();
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Descartar(evento.Id);
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(2));
-        }
-
-	    [Test]
-        public void Proponer_agendar_cancelar_y_descartar()
-        {
-            _workflow.Proponer();
-
-            _workflow.Agendar();
-
-            var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-            Assert.IsNotNull(evento);
-
-            _workflow.Cancelar(evento.Id);
-
-            _workflow.Descartar(evento.Id);
-
-            _publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
-        }
-
-	    [Test]
-		public void Proponer_agendar_y_confirmar()
-		{
-			_workflow.Proponer();
-
-			_workflow.Agendar();
-
-			var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-			Assert.IsNotNull(evento);
-
-			_workflow.Confirmar(evento.Id);
-
-			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(3));
-		}
-
-		[Test]
-		public void Proponer_agendar_confirmar_publicar()
-		{
-            const string urlWiki = "http://www.altnethispano.org/wiki/van-2010-10-21-mono-cecil.ashx";
-
-			_workflow.Proponer();
-
-			_workflow.Agendar();
-
-			var evento = DefaultEventoRepository.GetActivos().SingleOrDefault();
-			Assert.IsNotNull(evento);
-
-			_workflow.Confirmar(evento.Id);
-
-			_workflow.Publicar(evento.Id);
-
-			_publicador.Verify(p => p.Publicar(It.IsAny<IEnumerable<Track>>()), Times.Exactly(4));
-		}
-	}
-}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter.Tests/Publicador_tests.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter.Tests/Publicador_tests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -37,6 +37,8 @@
 
 			string message;
 			string twitt = null;
+            var fechaInicio = DateTime.Today.AddDays(7).ToUniversalTime();
+            var fechaTermino = fechaInicio.AddHours(2);
 			adapter.Setup(a => a.Update(It.IsAny<string>(), out message)).Returns(true).Callback<string, string>((status, m) => twitt = status);
 
 			var publicador = new TwitterPublicador(adapter.Object);
@@ -46,7 +48,8 @@
 
 			adapter.Verify(a => a.Update(It.IsAny<string>(), out message), Times.Once());
 
-			agenda.Agendar("Identity Providers", TestsHelper.GetOrCreatePonente("Nelo Pauselli"), DateTime.Today.AddDays(7), null, TipoEvento.GrupoEstudio);
+		    agenda.Agendar("Identity Providers", TestsHelper.GetOrCreatePonente("Nelo Pauselli"), fechaInicio, fechaTermino,
+		                   null, TipoEvento.GrupoEstudio);
 
 			adapter.Verify(a => a.Update(It.IsAny<string>(), out message), Times.Exactly(2));
 
--- a/Agendas/trunk/src/Agendas.Twitter/TwitterPublicador.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/TwitterPublicador.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using AltNetHispano.Agendas.Configurations;
 using AltNetHispano.Agendas.Domain;
@@ -43,9 +44,16 @@
 				var twitt = BuildTwitt(track);
 				if (!string.IsNullOrWhiteSpace(twitt))
 				{
-					string message;
-					bool success = _twitterAdapter.Update(twitt, out message);
-					track.LogAdd(new TrackLog(TrackLogPropietario.Twitter, message, track.Usuario, success));
+					try
+					{
+						string message;
+						bool success = _twitterAdapter.Update(twitt, out message);
+						track.LogAdd(new TrackLog(TrackLogPropietario.Twitter, message, track.Usuario, success));
+					}
+					catch(Exception ex)
+					{
+						track.LogAdd(new TrackLog(TrackLogPropietario.Twitter, track.Usuario, ex));
+					}
 				}
 			}
 		}
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/AgendarTwitterWriter.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/AgendarTwitterWriter.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -11,8 +11,8 @@
 			
 			body += " con " + TwitterHelper.GetPonente(track.Evento.Ponente);
 
-			if (track.Evento.Fecha.HasValue)
-				body += " para el " + track.Evento.Fecha.Value.ToShortDateString();
+			if (track.Evento.FechaInicio.HasValue)
+				body += " para el " + track.Evento.FechaInicio.Value.ToShortDateString();
 			return body;
 		}
 	}
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/ConfirmarTwitterWriter.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/ConfirmarTwitterWriter.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -7,8 +7,8 @@
 		public string Write(Track track)
 		{
 			{
-				if (track.Evento.Fecha.HasValue)
-					return "Se confirma para el " + track.Evento.Fecha.Value.ToShortDateString() + " el evento " + track.Evento.Titulo +
+				if (track.Evento.FechaInicio.HasValue)
+					return "Se confirma para el " + track.Evento.FechaInicio.Value.ToShortDateString() + " el evento " + track.Evento.Titulo +
 						   " con " + TwitterHelper.GetPonente(track.Evento.Ponente);
 				return string.Empty;
 			}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/Agendas.Web.Tests.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{10FECBBD-F07F-4721-87DA-D3184CF86C90}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Agendas.Web.Tests</RootNamespace>
+    <AssemblyName>Agendas.Web.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="nunit.framework">
+      <HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AutorizationsTests.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Agendas.Domain\Agendas.Domain.csproj">
+      <Project>{A14907DF-02E4-4FA7-BE27-4292AF50AA22}</Project>
+      <Name>Agendas.Domain</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Agendas.Web\Agendas.Web.csproj">
+      <Project>{319A8E3D-C61E-455F-A1BF-A6B1B1636BAB}</Project>
+      <Name>Agendas.Web</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Web.Controllers;
+using NUnit.Framework;
+
+namespace Agendas.Web.Tests
+{
+	[TestFixture]
+	public class Autorizaciones
+	{
+		private IEnumerable<MethodInfo> _methods;
+
+		[TestFixtureSetUp]
+		public void ReadMethods()
+		{
+			var types = typeof (HomeController).Assembly.GetTypes().ToList();
+			var controllers = types.Where(t => typeof (Controller).IsAssignableFrom(t)).ToList();
+
+			var methods = new List<MethodInfo>();
+			foreach (var controller in controllers)
+			{
+				var temp =
+					controller.GetMethods(BindingFlags.Public | BindingFlags.Instance | ~BindingFlags.FlattenHierarchy).Where(
+						m => !m.IsPrivate && typeof (ActionResult).IsAssignableFrom(m.ReturnType));
+				
+				methods.AddRange(temp);
+			}
+
+			_methods = methods;
+		}
+
+		[Test]
+		public void Acciones_publicas()
+		{
+			var acciones = new[]
+			               	{
+			               		"HomeController.Index", "HomeController.About", "EventoController.Index", "AccountController.LogOn",
+			               		"AccountController.LogOff", "AccountController.TwitterLogOn", "HistoricoController.Index",
+			               		"PersonaController.Index", "ErrorController.NoAutorizado"
+			               	};
+
+			#region Asserts
+
+			bool fail = false;
+			foreach (var method in _methods)
+			{
+				var action = method.DeclaringType.Name + "." + method.Name;
+				if (acciones.Contains(action))
+				{
+					if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser público");
+					}
+				}
+				else
+				{
+					if (!method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser seguro");
+					}
+				}
+			}
+
+			Assert.IsFalse(fail);
+
+			#endregion
+		}
+
+		[Test]
+		public void Acciones_privadas()
+		{
+			var acciones = new[]
+			               	{
+			               		"PerfilController.Index", "PerfilController.AddGoogleAccount", "PerfilController.AddTwitterAccount",
+			               		"PerfilController.Remove", "PerfilController.Modificar"
+			               	};
+
+			VerficarAccionesSeguras(acciones, Roles.Usuario, "debe ser privado");
+		}
+
+		[Test]
+		public void Acciones_del_administrador()
+		{
+			var acciones = new[]
+			               	{
+			               		"EventoController.Agendar", "EventoController.Confirmar", "EventoController.Nuevo",
+			               		"EventoController.Publicar", "EventoController.Modificar", "EventoController.Proponer",
+			               		"EventoController.Cancelar", "EventoController.Descartar", "EventoController.ReAgendar",
+			               		"EventoController.ReProponer", "PersonaController.Nueva", "PersonaController.Modificar"
+			               	};
+
+			VerficarAccionesSeguras(acciones, Roles.Administrador, "debe ser de uso exclusivo de los administradores");
+		}
+
+		private void VerficarAccionesSeguras(IEnumerable<string> acciones, string rol, string mensaje)
+		{
+			bool fail = false;
+			foreach (var method in _methods)
+			{
+				var action = method.DeclaringType.Name + "." + method.Name;
+				if (acciones.Contains(action))
+				{
+					if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						var found =
+							method.GetCustomAttributesData().Any(d => d.NamedArguments.Any(a => rol.Equals(a.TypedValue.Value)));
+
+						if (!found)
+						{
+							fail = true;
+							Console.WriteLine(action + " " + mensaje);
+						}
+					}
+					else
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser seguro");
+					}
+				}
+				else if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+				{
+					var found =
+						method.GetCustomAttributesData().Any(d => d.NamedArguments.Any(a => rol.Equals(a.TypedValue.Value)));
+
+					if (found)
+					{
+						fail = true;
+						Console.WriteLine(action + " no " + mensaje);
+					}
+				}
+			}
+			Assert.IsFalse(fail);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/Properties/AssemblyInfo.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Agendas.Web.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Agendas.Web.Tests")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8464a0e5-fb7f-4b26-a0cd-5f86655f13f1")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- a/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Tue Aug 09 08:55:08 2011 -0300
@@ -62,6 +62,8 @@
   <ItemGroup>
     <Compile Include="Controllers\AccountController.cs" />
     <Compile Include="Controllers\ControllerMessageExtensions.cs" />
+    <Compile Include="Controllers\CustomAuthorizeAttribute.cs" />
+    <Compile Include="Controllers\ErrorController.cs" />
     <Compile Include="Controllers\EventoController.cs" />
     <Compile Include="Controllers\HistoricoController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
@@ -228,6 +230,12 @@
   <ItemGroup>
     <Content Include="Views\Shared\EditorTemplates\Url.cshtml" />
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="Views\Shared\SinPermisos.cshtml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Views\Shared\EditorTemplates\Roles.cshtml" />
+  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
--- a/Agendas/trunk/src/Agendas.Web/Controllers/AccountController.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/AccountController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,24 +1,21 @@
 using System.Web.Mvc;
 using System.Web.Routing;
-using System.Web.Security;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
 using AltNetHispano.Agendas.Twitter;
-using AltNetHispano.Agendas.Web.Models;
 using AltNetHispano.Agendas.Web.Services;
 
 namespace AltNetHispano.Agendas.Web.Controllers
 {
     public class AccountController : Controller
     {
-
-        public IFormsAuthenticationService FormsService { get; set; }
+    	private IFormsAuthenticationService _formsService;
 
         protected override void Initialize(RequestContext requestContext)
         {
-            if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
-
-            base.Initialize(requestContext);
+            if (_formsService == null) { _formsService = new FormsAuthenticationService(); }
+            
+			base.Initialize(requestContext);
         }
 
         public ActionResult LogOn()
@@ -60,7 +57,7 @@
 				var personaService = AgendaFactory.GetPersonaService();
 				personaService.CreateIfNotExist(IdentityProviderEnum.Twitter, username, nombre);
 
-				FormsService.SignIn(Identification.Map[(int)IdentityProviderEnum.Twitter]+username, false);
+				_formsService.SignIn(Identification.Map[(int)IdentityProviderEnum.Twitter]+username, false);
 				return RedirectToAction("Index", "Home");
 			}
 
@@ -71,7 +68,7 @@
 
         public ActionResult LogOff()
         {
-            FormsService.SignOut();
+            _formsService.SignOut();
             return RedirectToAction("Index", "Home");
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/CustomAuthorizeAttribute.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,46 @@
+using System.Web;
+using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Factories;
+
+namespace AltNetHispano.Agendas.Web.Controllers
+{
+	public class CustomAuthorizeAttribute : AuthorizeAttribute
+	{
+		public string RedirectResultUrl { get; set; }
+
+		public CustomAuthorizeAttribute()
+		{
+			RedirectResultUrl = "~/Error/NoAutorizado";
+		}
+
+		protected override bool AuthorizeCore(HttpContextBase httpContext)
+		{
+			if (!httpContext.User.Identity.IsAuthenticated || !IdentityContext.IsAuthenticated())
+				return false;
+
+			if (!string.IsNullOrWhiteSpace(Roles))
+			{
+				using (NHibernateFactory.GetSessionScope())
+				{
+					var roles = Roles.Split(',');
+					if (!IdentityContext.IsInRole(roles))
+					{
+						httpContext.Response.StatusCode = 403;
+						return false;
+					}
+				}
+			}
+
+			return true;
+		}
+
+		protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
+		{
+			if (filterContext.HttpContext.Response.StatusCode == 403)
+				filterContext.Result = new RedirectResult(RedirectResultUrl);
+			else
+				base.HandleUnauthorizedRequest(filterContext);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/ErrorController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,12 @@
+using System.Web.Mvc;
+
+namespace AltNetHispano.Agendas.Web.Controllers
+{
+	public class ErrorController : Controller
+	{
+		public ActionResult NoAutorizado()
+		{
+			return View("SinPermisos");
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Controllers/EventoController.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/EventoController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -13,71 +13,69 @@
 		{
 			var agenda = AgendaFactory.GetAgenda();
 
-			var model = new EventoIndexModel
-			            	{
-			            		ProximosEventos = from e in agenda.GetEventosActivos()
-			            		                  orderby e.Fecha
-			            		                  select new EventoDto
-			            		                         	{
-			            		                         		Id = e.Id.ToString(),
-			            		                         		Titulo = e.Titulo,
-			            		                         		Fecha = e.Fecha.HasValue ? e.Fecha.Value.ToShortDateString() : string.Empty,
-																Estado = e.Estado.Descripcion,
-			            		                         		PuedeAgendar = e.Estado.PuedePromover(Accion.Agendar),
-			            		                         		PuedeModificar = e.Estado.PuedePromover(Accion.Modificar),
-			            		                         		PuedeConfirmar = e.Estado.PuedePromover(Accion.Confirmar),
-			            		                         		PuedePublicar = e.Estado.PuedePromover(Accion.Publicar),
-                                                                PuedeCancelar = e.Estado.PuedePromover(Accion.Cancelar),
-                                                                PuedeDescartar = e.Estado.PuedePromover(Accion.Descartar),
-                                                                PuedeReAgendar = e.Estado.PuedePromover(Accion.ReAgendar),
-                                                                PuedeReProponer = e.Estado.PuedePromover(Accion.ReProponer)
-			            		                         	}
-			            	};
+		    var model = new EventoIndexModel
+		                    {
+		                        ProximosEventos = from e in agenda.GetEventosActivos()
+		                                          orderby e.FechaInicio
+		                                          select new EventoDto
+		                                                     {
+		                                                         Id = e.Id.ToString(),
+		                                                         Titulo = e.Titulo,
+		                                                         Fecha =
+		                                                             e.FechaInicio.HasValue
+		                                                                 ? e.FechaInicio.Value.ToShortDateString() + " " +
+                                                                           e.FechaInicio.Value.ToShortTimeString()
+		                                                                 : string.Empty,
+		                                                         Duracion =
+		                                                             e.FechaInicio.HasValue && e.FechaTermino.HasValue
+		                                                                 ? e.FechaTermino.Value.Subtract(e.FechaInicio.Value).
+		                                                                       ToString("c")
+		                                                                 : string.Empty,
+		                                                         Estado = e.Estado.Descripcion,
+		                                                         PuedeAgendar = e.Estado.PuedePromover(Accion.Agendar),
+		                                                         PuedeModificar = e.Estado.PuedePromover(Accion.Modificar),
+		                                                         PuedeConfirmar = e.Estado.PuedePromover(Accion.Confirmar),
+		                                                         PuedePublicar = e.Estado.PuedePromover(Accion.Publicar),
+		                                                         PuedeCancelar = e.Estado.PuedePromover(Accion.Cancelar),
+		                                                         PuedeDescartar = e.Estado.PuedePromover(Accion.Descartar),
+		                                                         PuedeReAgendar = e.Estado.PuedePromover(Accion.ReAgendar),
+		                                                         PuedeReProponer = e.Estado.PuedePromover(Accion.ReProponer)
+		                                                     }
+		                    };
 			return View(model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Nuevo()
 		{
-		    var model = new EventoNewModel {Fecha = DateTime.Now};
+            var model = new EventoNewModel { Fecha = DateTime.Now, Duracion = new TimeSpan(2, 0, 0), Hora = new TimeSpan(18, 0, 0) };
 		    return View("Defaulteditor", model);
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Nuevo(EventoNewModel model)
 		{
-			if (ModelState.IsValid)
-			{
-				var agenda = AgendaFactory.GetAgenda();
-
-				var r = agenda.Agendar(model.Titulo, model.Ponente, model.Fecha,
-				  model.UrlInvitacion, (TipoEvento)model.TipoEvento);
-				if (r.Succeful)
-				{
-					this.AddNotification("Evento creado");
-					return RedirectToAction("Index");
-				}
-				ModelState.AddModelError("error", r.ToString());
-			}
-            return View("Defaulteditor", model);
+		    return
+		        GenericAction(
+		            (agenda, m) => agenda.Agendar(m.Titulo, m.Ponente, GenerarFechaInicio(m.Fecha, m.Hora),
+		                                          GenerarFechaTermino(m.Fecha, m.Hora, m.Duracion), m.UrlInvitacion,
+		                                          (TipoEvento) m.TipoEvento),
+		            m => View("Defaulteditor", m),
+		            model);
 		}
 
-		[Authorize]
+    	[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Confirmar(string id)
 		{
-			var agenda = AgendaFactory.GetAgenda();
-			
-			var r = agenda.Confirmar(new Guid(id));
-			if (r.Succeful)
-				this.AddNotification("Evento confirmado");
-			else
-				this.AddError("Evento confirmado");
-
-			return RedirectToAction("Index");
+			return
+				GenericAction(
+					(agenda, m) => agenda.Confirmar(m),
+					m => View("Index", m),
+					new Guid(id));
 		}
 
-    	[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Publicar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -95,25 +93,17 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Publicar(EventoPublicarModel model)
 		{
-			if (ModelState.IsValid)
-			{
-				var agenda = AgendaFactory.GetAgenda();
-
-				var r = agenda.Publicar(new Guid(model.Id), model.NroOrden, model.UrlWiki, model.DuracionReal);
-				if (r.Succeful)
-				{
-					this.AddNotification(string.Format("Evento publicado {0}", model.Titulo));
-					return RedirectToAction("Index");
-				}
-				ModelState.AddModelError("error", r.ToString());
-			}
-			return View("Defaulteditor", model);
+			return
+					GenericAction(
+						(agenda, m) => agenda.Publicar(new Guid(m.Id), m.NroOrden, m.UrlWiki, m.DuracionReal),
+						m => View("Defaulteditor", m),
+						model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Modificar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -124,32 +114,28 @@
 				Id = id,
 				Titulo = evento.Titulo,
 				Ponente = evento.Ponente != null ? evento.Ponente.Id : Guid.Empty,
-				Fecha = evento.Fecha,
+				Fecha = evento.FechaInicio,
+                Hora = evento.FechaInicio != null ? evento.FechaInicio.Value.TimeOfDay : (TimeSpan?)null,
+                Duracion = evento.FechaInicio!=null && evento.FechaTermino!=null ? evento.FechaTermino.Value.Subtract(evento.FechaInicio.Value) : (TimeSpan?) null,
 				UrlInvitacion = evento.UrlInvitacion
 			};
             return View("Defaulteditor", model);
 		}
 		
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Modificar(EventoEditModel model)
 		{
-			if (ModelState.IsValid)
-			{
-				var agenda = AgendaFactory.GetAgenda();
-
-				var r = agenda.ModificarEvento(new Guid(model.Id), model.Titulo, model.Ponente, model.Fecha.Value, model.UrlInvitacion);
-				if (r.Succeful)
-				{
-					this.AddNotification("evento modificado");
-					return RedirectToAction("Index");
-				}
-				ModelState.AddModelError("error", r.ToString());
-			}
-            return View("Defaulteditor", model);
+		    return
+		        GenericAction(
+		            (agenda, m) =>
+		            agenda.ModificarEvento(new Guid(m.Id), m.Titulo, m.Ponente, GenerarFechaInicio(m.Fecha, m.Hora),
+		                                   GenerarFechaTermino(m.Fecha, m.Hora, m.Duracion), m.UrlInvitacion),
+		            m => View("Defaulteditor", m),
+		            model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Agendar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -160,32 +146,28 @@
 				Id = id,
 				Titulo = evento.Titulo,
 				Ponente = evento.Ponente != null ? evento.Ponente.Id : Guid.Empty,
-				Fecha = evento.Fecha,
+				Fecha = evento.FechaInicio,
+                Hora = evento.FechaInicio != null ? evento.FechaInicio.Value.TimeOfDay : (TimeSpan?)null,
+                Duracion = evento.FechaInicio != null && evento.FechaTermino != null ? evento.FechaTermino.Value.Subtract(evento.FechaInicio.Value) : (TimeSpan?)null,
 				UrlInvitacion = evento.UrlInvitacion
 			};
             return View("Defaulteditor", model);
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Agendar(EventoAgendarModel model)
 		{
-			if (ModelState.IsValid)
-			{
-				var agenda = AgendaFactory.GetAgenda();
-
-				var r = agenda.ModificarEvento(new Guid(model.Id), model.Titulo, model.Ponente, model.Fecha.Value, model.UrlInvitacion);
-				if (r.Succeful)
-				{
-					this.AddNotification("evento agendado");
-					return RedirectToAction("Index");
-				}
-				ModelState.AddModelError("error", r.ToString());
-			}
-            return View("Defaulteditor", model);
+		    return
+		        GenericAction(
+		            (agenda, m) =>
+		            agenda.ModificarEvento(new Guid(m.Id), m.Titulo, m.Ponente, GenerarFechaInicio(m.Fecha, m.Hora),
+		                                   GenerarFechaTermino(m.Fecha, m.Hora, m.Duracion), m.UrlInvitacion),
+		            m => View("Defaulteditor", m),
+		            model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Proponer()
 		{
 			var model = new PropuestaNewModel();
@@ -193,62 +175,89 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Proponer(PropuestaNewModel model)
 		{
+			return
+				GenericAction(
+					(agenda, m) => agenda.Proponer(m.Titulo, m.Ponente, m.UrlInvitacion, (TipoEvento)m.TipoEvento),
+					m => View("Defaulteditor", m),
+					model);
+		}
+
+		[CustomAuthorize(Roles = Roles.Administrador)]
+	    public ActionResult Cancelar(string id)
+		{
+			return
+				GenericAction(
+					(agenda, m) => agenda.Cancelar(m),
+					m => View("Index", m),
+					new Guid(id));
+		}
+
+    	[CustomAuthorize(Roles = Roles.Administrador)]
+	    public ActionResult Descartar(string id)
+    	{
+    		return
+    			GenericAction(
+    				(agenda, m) => agenda.Descartar(m),
+    				m => View("Index", m),
+    				new Guid(id));
+    	}
+
+    	[CustomAuthorize(Roles = Roles.Administrador)]
+	    public ActionResult ReAgendar(string id)
+    	{
+    		return
+    			GenericAction(
+    				(agenda, m) => agenda.ReAgendar(m),
+    				m => View("Index", m),
+    				new Guid(id));
+    	}
+
+    	[CustomAuthorize(Roles = Roles.Administrador)]
+	    public ActionResult ReProponer(string id)
+    	{
+			return
+    			GenericAction(
+    				(agenda, m) => agenda.ReProponer(m),
+    				m => View("Index", m),
+    				new Guid(id));
+    	}
+
+		private ActionResult GenericAction<TModel>(Func<Agenda, TModel, EventoResultado> action, Func<TModel, ActionResult> actionresultOnFail, TModel model)
+		{
 			if (ModelState.IsValid)
 			{
 				var agenda = AgendaFactory.GetAgenda();
 
-				var r = agenda.Proponer(model.Titulo, model.Ponente, model.UrlInvitacion, (TipoEvento)model.TipoEvento);
+				var r = action.Invoke(agenda, model);
 				if (r.Succeful)
 				{
-					this.AddNotification("Evento propuesto");
+					this.AddNotification(r.Message);
+					foreach (var log in r.Warnings)
+						this.AddWarning(log.WarningMessage);
 					return RedirectToAction("Index");
 				}
 				ModelState.AddModelError("error", r.ToString());
 			}
-            return View("Defaulteditor", model);
+			return actionresultOnFail.Invoke(model);
 		}
-        
-        [Authorize]
-	    public ActionResult Cancelar(string id)
-	    {
-            var agenda = AgendaFactory.GetAgenda();
-            agenda.Cancelar(new Guid(id));
-
-            this.AddNotification("Evento cancelado");
-            return RedirectToAction("Index");
-	    }
-
-        [Authorize]
-	    public ActionResult Descartar(string id)
-	    {
-            var agenda = AgendaFactory.GetAgenda();
-            agenda.Descartar(new Guid(id));
 
-            this.AddNotification("Evento descartado");
-            return RedirectToAction("Index");
-	    }
-
-        [Authorize]
-	    public ActionResult ReAgendar(string id)
-	    {
-            var agenda = AgendaFactory.GetAgenda();
-            agenda.ReAgendar(new Guid(id));
+        private DateTime? GenerarFechaInicio(DateTime? fecha, TimeSpan? hora)
+        {
+            return fecha.HasValue && hora.HasValue
+                       ? new DateTime(fecha.Value.Year, fecha.Value.Month, fecha.Value.Day, hora.Value.Hours,
+                                      hora.Value.Minutes, hora.Value.Seconds, DateTimeKind.Utc)
+                       : (DateTime?) null;
+        }
+        private DateTime? GenerarFechaTermino(DateTime? fecha, TimeSpan? hora, TimeSpan? duracion)
+        {
+            return fecha.HasValue && hora.HasValue && duracion.HasValue
+                       ? new DateTime(fecha.Value.Year, fecha.Value.Month, fecha.Value.Day, hora.Value.Hours,
+                                      hora.Value.Minutes, hora.Value.Seconds, DateTimeKind.Utc).Add(duracion.Value)
+                       : (DateTime?) null;
+        }
 
-            this.AddNotification("Evento re-agendado");
-            return RedirectToAction("Index");
-	    }
-
-        [Authorize]
-	    public ActionResult ReProponer(string id)
-	    {
-            var agenda = AgendaFactory.GetAgenda();
-            agenda.ReProponer(new Guid(id));
-
-            this.AddNotification("Evento re-propuesto");
-            return RedirectToAction("Index");
-	    }
 	}
 }
--- a/Agendas/trunk/src/Agendas.Web/Controllers/HistoricoController.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/HistoricoController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -14,12 +14,12 @@
 			var model = new HistoricoIndexModel
 			            	{
 			            		Items = from e in agenda.GetHistorico()
-			            		        orderby e.Fecha
+			            		        orderby e.FechaInicio
 			            		        select new HistoricoDto
 			            		               	{
 			            		               		Id = e.Id.ToString(),
 			            		               		Titulo = e.Titulo,
-			            		               		Fecha = e.Fecha.HasValue ? e.Fecha.Value.ToShortDateString() : string.Empty,
+			            		               		Fecha = e.FechaInicio.HasValue ? e.FechaInicio.Value.ToShortDateString() : string.Empty,
 			            		               		Wiki = e.UrlWiki,
 													Ponente = e.Ponente.Nombre,
                                                     Numero = e.NumeroOrden.ToString(),
--- a/Agendas/trunk/src/Agendas.Web/Controllers/PerfilController.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/PerfilController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -10,7 +10,8 @@
 {
     public class PerfilController : Controller
     {
-        public ActionResult Index()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Index()
         {
         	var persona = IdentityContext.GetUsuario();
 
@@ -35,12 +36,14 @@
         	return View(model);
         }
 
-        public ActionResult AddGoogleAccount()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult AddGoogleAccount()
         {
             throw new NotImplementedException();
         }
 
-        public ActionResult AddTwitterAccount()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult AddTwitterAccount()
 		{
 			var oAuth = new OAuthTwitter();
 
@@ -66,6 +69,7 @@
 			return RedirectToAction("Index");
 		}
 
+		[CustomAuthorize(Roles = Roles.Usuario)]
 		public ActionResult Remove(string identityProvider, string username)
 		{
 			var personaService = AgendaFactory.GetPersonaService();
@@ -81,5 +85,47 @@
 
 			return RedirectToAction("Index");
 		}
-    }
+
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Modificar()
+		{
+			var persona = IdentityContext.GetUsuario();
+			if (persona == null)
+			{
+				this.AddError("No se encontró la persona que intenta modificar");
+				return RedirectToAction("Index");
+			}
+
+			var model = new PerfilEditModel
+			{
+				Nombre = persona.Nombre,
+				Twitter = persona.Twitter,
+				EMail = persona.Mail,
+				Blog = persona.Blog
+			};
+
+			return View("Defaulteditor", model);
+		}
+
+		[HttpPost]
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Modificar(PerfilEditModel model)
+		{
+			if (ModelState.IsValid)
+			{
+				var persona = IdentityContext.GetUsuario();
+
+				var personas = AgendaFactory.GetPersonaService();
+				var r = personas.Update(persona.Id, model.Nombre, model.Twitter, model.EMail, model.Blog, null);
+				if (r.Succeful)
+				{
+					this.AddNotification("Los datos fueron guardados");
+					return RedirectToAction("Index");
+				}
+				this.AddError(r.Message);
+			}
+
+			return View("Defaulteditor", model);
+		}
+	}
 }
--- a/Agendas/trunk/src/Agendas.Web/Controllers/PersonaController.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/PersonaController.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
 using AltNetHispano.Agendas.Web.Models;
 
@@ -17,19 +18,21 @@
             return View(model);
         }
 
-        public ActionResult Nueva()
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Nueva()
         {
             var model = new PersonaNewModel();
             return View("Defaulteditor", model);
         }
 
         [HttpPost]
+		[CustomAuthorize(Roles = Roles.Administrador)]
         public ActionResult Nueva(PersonaNewModel model)
         {
             if (ModelState.IsValid)
             {
                 var personas = AgendaFactory.GetPersonaService();
-                var r = personas.Add(model.Nombre, model.Twitter, model.EMail,model.Blog);
+                var r = personas.Add(model.Nombre, model.Twitter, model.EMail,model.Blog, model.Roles);
                 if (r.Succeful)
                 {
                     this.AddNotification("Los datos fueron guardados");
@@ -41,7 +44,8 @@
             return View("Defaulteditor", model);
         }
 
-        public ActionResult Modificar(string id)
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Modificar(string id)
         {
             var personas = AgendaFactory.GetPersonaService();
 
@@ -58,19 +62,21 @@
         	            		Nombre = persona.Nombre,
         	            		Twitter = persona.Twitter,
         	            		EMail = persona.Mail,
-        	            		Blog = persona.Blog
+        	            		Blog = persona.Blog,
+								Roles = persona.Roles.ToArray()
         	            	};
 
             return View("Defaulteditor", model);
         }
 
         [HttpPost]
-        public ActionResult Modificar(PersonaEditModel model)
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Modificar(PersonaEditModel model)
         {
             if (ModelState.IsValid)
             {
                 var personas = AgendaFactory.GetPersonaService();
-                var r = personas.Update(new Guid(model.Id), model.Nombre, model.Twitter, model.EMail, model.Blog);
+				var r = personas.Update(new Guid(model.Id), model.Nombre, model.Twitter, model.EMail, model.Blog, model.Roles);
                 if (r.Succeful)
                 {
                     this.AddNotification("Los datos fueron guardados");
--- a/Agendas/trunk/src/Agendas.Web/DataProviders.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/DataProviders.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
 using AltNetHispano.Agendas.Web.Models;
 
@@ -23,5 +24,10 @@
                    select
                        new SelectListItem {Text = p.Nombre, Value = p.Id.ToString(), Selected = p.Id.Equals(id)};
         }
-    }
+
+		public static IEnumerable<string> GetRoles(this HtmlHelper helper)
+		{
+			return new[] {Roles.Administrador, Roles.Usuario};
+		}
+	}
 }
--- a/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -15,7 +15,7 @@
     	private static void RegisterGlobalFilters(GlobalFilterCollection filters)
         {
             filters.Add(new HandleErrorAttribute());
-			filters.Add(AttributeFactory.GetNHibernateSessionPerAction());
+			filters.Add(NHibernateFactory.GetNHibernateSessionPerAction());
         }
 
     	private static void RegisterRoutes(RouteCollection routes)
--- a/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -25,7 +25,13 @@
 		[Required]
 		public DateTime Fecha { get; set; }
 
-		[Url]
+        [Required]
+	    public TimeSpan Hora { get; set; }
+
+        [Required]
+        public TimeSpan Duracion { get; set; }
+
+	    [Url]
 		public string UrlInvitacion { get; set; }
 	}
 
@@ -43,6 +49,12 @@
 		[Required]
 		public DateTime? Fecha { get; set; }
 
+        [Required]
+        public TimeSpan? Hora { get; set; }
+
+        [Required]
+        public TimeSpan? Duracion { get; set; }
+
 		[Url]
 		public string UrlInvitacion { get; set; }
 	}
@@ -61,6 +73,12 @@
 		[Required]
 		public DateTime? Fecha { get; set; }
 
+        [Required]
+        public TimeSpan? Hora { get; set; }
+
+        [Required]
+        public TimeSpan? Duracion { get; set; }
+
 		[Url]
 		public string UrlInvitacion { get; set; }
 	}
@@ -75,7 +93,6 @@
 		public string Titulo { get; set; }
 
 		[Required]
-		[UIHint("NroOrden")]
 		[Range(1, short.MaxValue)]
 		public short NroOrden { get; set; }
 
@@ -84,7 +101,6 @@
 		public string UrlWiki { get; set; }
 
 		[Required]
-		[UIHint("DuracionReal")]
 		public TimeSpan DuracionReal { get; set; }
 	}
 
@@ -94,8 +110,9 @@
 		public string Titulo { get; set; }
 		public string Estado { get; set; }
 		public string Fecha { get; set; }
+        public string Duracion { get; set; }
 
-		public bool PuedeAgendar { get; set; }
+	    public bool PuedeAgendar { get; set; }
 		public bool PuedeModificar { get; set; }
 		public bool PuedeConfirmar { get; set; }
 		public bool PuedePublicar { get; set; }
--- a/Agendas/trunk/src/Agendas.Web/Models/PerfilModel.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/PerfilModel.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -24,6 +24,21 @@
 		public IEnumerable<CuentaDto> Cuentas { get; set; }
 	}
 
+	public class PerfilEditModel
+	{
+		[Required]
+		public string Nombre { get; set; }
+
+		[Required]
+		public string Twitter { get; set; }
+
+		[Required]
+		public string EMail { get; set; }
+
+		[DataType(DataType.Url)]
+		public string Blog { get; set; }
+	}
+
 	public class CuentaDto
 	{
 		public string IdentityProvider { get; set; }
--- a/Agendas/trunk/src/Agendas.Web/Models/PersonaModel.cs	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/PersonaModel.cs	Tue Aug 09 08:55:08 2011 -0300
@@ -22,6 +22,8 @@
 
 		[DataType(DataType.Url)]
     	public string Blog { get; set; }
+
+		public string[] Roles { get; set; }
     }
 
     public class PersonaEditModel
@@ -41,6 +43,8 @@
 
 		[DataType(DataType.Url)]
     	public string Blog { get; set; }
+
+		public string[] Roles { get; set; }
     }
 
     public class PersonaDto
--- a/Agendas/trunk/src/Agendas.Web/Views/Evento/Index.cshtml	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Evento/Index.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -7,7 +7,8 @@
 	<table>
 		<thead>
 			<tr>
-				<th>Fecha</th>
+				<th>Fecha (GMT +0)</th>
+                <th>Duraci&oacute;n</th>
 				<th>Evento</th>
 				<th>Estado</th>
 				<th>Acciones</th>
@@ -18,6 +19,7 @@
 			{
 				<tr>
 					<td>@item.Fecha</td>
+                    <td>@item.Duracion</td>
 					<td>@item.Titulo</td>
 					<td>@item.Estado</td>
 					<td class="buttons">
@@ -56,11 +58,13 @@
 							@Html.ActionLink("Re-Agendar", "ReAgendar", new { id = item.Id })
 							<span>&nbsp;</span>
 						}
+						<!--
 						@if (item.PuedeReProponer)
 						{
 							@Html.ActionLink("Re-Proponer", "ReProponer", new { id = item.Id })
 							<span>&nbsp;</span>
 						}
+						-->
 					</td>
 				</tr>
 			}
@@ -69,5 +73,4 @@
 </div>
 <div class="buttons">
 	@Html.ActionLink("Nuevo", "Nuevo")
-	@Html.ActionLink("Proponer", "Proponer")
 </div>
--- a/Agendas/trunk/src/Agendas.Web/Views/Perfil/Index.cshtml	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Perfil/Index.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -33,6 +33,6 @@
 	<br/>
 	@Html.ActionLink("Asociar cuenta de Google", "AddGoogleAccount")
 	-->
-	@Html.ActionLink("Modificar datos", "Modificar", "Persona", new {id=Model.Id}, null)
+	@Html.ActionLink("Modificar datos", "Modificar")
 </div>
 <br/>
--- a/Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Object.cshtml	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Object.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -5,7 +5,7 @@
         @ViewData.ModelMetadata.SimpleDisplayText
     }
 } else {
-    foreach (var prop in ViewData.ModelMetadata.Properties.Where(metadata => metadata.ShowForEdit && !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata)))
+    foreach (var prop in ViewData.ModelMetadata.Properties.Where(metadata => metadata.ShowForEdit && !ViewData.TemplateInfo.Visited(metadata)))
 	{
         if (prop.HideSurroundingHtml) {
             @Html.Editor(prop.PropertyName)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Roles.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,6 @@
+@model IList<string>
+@foreach (var item in Html.GetRoles())
+{
+	<input type="checkbox" name="Roles" value="@item" @(Model != null && Model.Contains(item) ? "checked" : string.Empty) />@item
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/SinPermisos.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -0,0 +1,1 @@
+<h2>Usted no tiene permisos para realizar la acción solicitada</h2>
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Views/Shared/_Messages.cshtml	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/_Messages.cshtml	Tue Aug 09 08:55:08 2011 -0300
@@ -2,11 +2,11 @@
 {
 	<div class="errorbox"><label>@TempData["error"]</label></div>
 }
+@if (TempData.ContainsKey("notification"))
+{
+	<div class="notificationbox"><label>@TempData["notification"]</label></div>
+}
 @if (TempData.ContainsKey("warning"))
 {
 	<div class="warningbox"><label>@TempData["warning"]</label></div>
-}
-@if (TempData.ContainsKey("notification"))
-{
-	<div class="notificationbox"><label>@TempData["notification"]</label></div>
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.sln	Tue Aug 09 08:53:38 2011 -0300
+++ b/Agendas/trunk/src/Agendas.sln	Tue Aug 09 08:55:08 2011 -0300
@@ -38,6 +38,8 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Configurations.Tests", "Agendas.Configurations.Tests\Agendas.Configurations.Tests.csproj", "{BBE36765-6AAB-4689-B2F3-6D18E3F11746}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Web.Tests", "Agendas.Web.Tests\Agendas.Web.Tests.csproj", "{10FECBBD-F07F-4721-87DA-D3184CF86C90}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -104,6 +106,10 @@
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Release|Any CPU.Build.0 = Release|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE