changeset 234:cc71f96ac134

Combinar
author juanjose.montesdeocaarbos
date Tue, 04 Oct 2011 20:36:27 -0300
parents 32e4e0e7a140 (current diff) e5959f3405e0 (diff)
children 04d6b386afa7 717fce60f200
files
diffstat 22 files changed, 372 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/Agendas/trunk/src/Agendas.Blog/Impl/AgendarReunionPostWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Blog/Impl/AgendarReunionPostWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -3,7 +3,6 @@
 using Agendas.Blog.Exceptions;
 using Agendas.Blog.Properties;
 using AltNetHispano.Agendas.Domain;
-using System.Linq;
 
 namespace Agendas.Blog.Impl
 {
@@ -17,10 +16,9 @@
     {
       string resourceName = getTitleResourceName(track);
 
-      return string.Format(CultureInfo.InvariantCulture, resourceName,
-													 track.Evento.Ponente.Nombre, //Nombre y apellido del ponente
-													 track.Evento.Titulo //Tema a tratar en la reunion
-				);
+    	return string.Format(CultureInfo.InvariantCulture, resourceName,
+    	                     track.Evento.GetPonentesAsString(p => p.Nombre), //Nombre y apellido del ponente
+							 track.Evento.Titulo); //Tema a tratar en la reunion
     }
 
 	  private string getTitleResourceName(Track track)
@@ -43,7 +41,7 @@
 			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
+													 track.Evento.GetPonentesAsString(p => p.Nombre), //Nombre y apellido del ponente
 													 track.Evento.Titulo, //Tema a tratar en la reunion
 													 getUrlInvitacion(track.Evento), //Url a la invitacion realizada por el ponente (por lo general es el thread en la lista de correo)
 													 GetNombreUsuario(track) //Usuario que postea en el blog
--- a/Agendas/trunk/src/Agendas.Domain/Agenda.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Agenda.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -48,9 +48,19 @@
 
         public EventoResultado ModificarEvento(Guid eventoId, string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion)
         {
-            Evento evento = GetEvento(eventoId);
-            Persona persona = _personaRepository.Get(ponenteId);
+			Evento evento = GetEvento(eventoId);
+
+			if (evento.Tipo == TipoEvento.Van && ponenteId == Guid.Empty)
+				return new EventoResultado(false, "Debe indicar el ponente para este tipo de evento", null);
 
+			Persona persona = null;
+			if (ponenteId != Guid.Empty)
+			{
+				persona = _personaRepository.Get(ponenteId);
+				if (persona == null)
+					return new EventoResultado(false, string.Format("No se encontró el ponente indicado ({0})", ponenteId), null);
+			} 
+			
             if (evento.Titulo != titulo)
                 evento.CambiarTitulo(titulo);
 
@@ -92,23 +102,24 @@
 			return new EventoResultado(true,"Evento propuesto", warnings);
 		}
 
-		public EventoResultado Agendar(string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion, TipoEvento tipo)
-		{
-			return Agendar(titulo, ponenteId, fechaInicio, fechaTermino, urlInvitacion, tipo, null);
-		}
-
-    	public EventoResultado Agendar(string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion, TipoEvento tipo, IEnumerable<Guid> colaboradoresId)
+    	public EventoResultado Agendar(string titulo, Guid ponenteId, DateTime? fechaInicio, DateTime? fechaTermino, string urlInvitacion, TipoEvento tipo, IEnumerable<Guid> colaboradoresId = null)
         {
             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);
+			if (tipo==TipoEvento.Van && ponenteId == Guid.Empty)
+				return new EventoResultado(false, "Debe indicar el ponente para este tipo de evento", null);
 
-            Persona persona = _personaRepository.Get(ponenteId);
-            if (persona == null)
-                return new EventoResultado(false, string.Format("No se encontró el ponente indicado ({0})", ponenteId), null);
+    		Persona persona = null;
+			if (ponenteId != Guid.Empty)
+    		{
+    			persona = _personaRepository.Get(ponenteId);
+    			if (persona == null)
+    				return new EventoResultado(false, string.Format("No se encontró el ponente indicado ({0})", ponenteId), null);
+    		}
 
-		    var existeOtroEvento = _eventosRepository.GetNoPropuestoByTitulo(titulo);
+    		var existeOtroEvento = _eventosRepository.GetNoPropuestoByTitulo(titulo);
             if (existeOtroEvento != null)
                 return new EventoResultado(false,
                                            string.Format(
--- a/Agendas/trunk/src/Agendas.Domain/Evento.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Evento.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -98,6 +98,11 @@
 			get { return _otrosPonentes; }
 		}
 
+		public virtual IEnumerable<Persona> Ponentes
+		{
+			get { return Ponente != null ? new List<Persona> {Ponente}.Union(OtrosPonentes) : OtrosPonentes; }
+		}
+
 		public virtual void ActualizarOtrosPonentes(IEnumerable<Persona> otrosPonentes)
 		{
 			foreach (var otro in otrosPonentes)
@@ -244,5 +249,21 @@
 				logs.AddRange(track.GetLogsNews());
 			return logs;
 		}
+
+		public virtual string GetPonentesAsString(Func<Persona, string> predicate)
+		{
+    		var nombres = Ponentes.Select(predicate.Invoke).ToArray();
+			string texto = string.Empty;
+			for (int i = 0; i < nombres.Length; i++)
+			{
+				var nombre = nombres[i];
+				if (i == nombres.Length - 1 && i>0)
+					texto += " y ";
+				else if (i != 0)
+					texto += ", ";
+				texto += nombre;
+			}
+			return texto;
+		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Google.Test/PublicadorTest.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google.Test/PublicadorTest.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -179,5 +179,49 @@
             agenda.Cancelar(evento.Id);
             adapter.Verify(ad => ad.DeleteEvent(It.IsAny<DateTime>(), It.IsAny<DateTime>(), out message), Times.Once());
         }
+
+		[Test]
+		public void PublicarConMasDeUnPonente()
+		{
+			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);
+			agenda.Agendar("Identity Providers Públicos y Empresariales", TestsHelper.GetOrCreatePonente("Carlos Peix"), fechaInicio,
+						   fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+						   TipoEvento.Van, new[] { TestsHelper.GetOrCreatePonente("Nelo Pauselli") });
+
+			var ev = DefaultEventoRepository.GetActivos()[0];
+			detail.Generate(ev);
+
+			Assert.That(detail.Summary, Is.StringContaining("Carlos Peix y Nelo Pauselli."));
+		}
+
+		[Test]
+		public void PublicarSinPonente()
+		{
+			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);
+			agenda.Agendar("Identity Providers Públicos y Empresariales", Guid.Empty, fechaInicio,
+						   fechaTermino, "https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion",
+						   TipoEvento.Cafe);
+
+			var ev = DefaultEventoRepository.GetActivos()[0];
+			detail.Generate(ev);
+
+			Assert.AreEqual("La comunidad ALT.NET Hispano (http://altnethispano.org) realizará un Café sobre Identity Providers Públicos y Empresariales." +
+						   "\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." +
+						   "\n\rPueden plantear sus comentarios e inquietudes sobre el tema de la reunión en: https://groups.google.com/d/topic/altnet-hispano/arYEMsPiAtY/discussion" +
+						   "\n\rPara mayor información sobre cómo atender la reunión consulten: http://tinyurl.com/van-hispano" +
+						   "\n\rPueden vincular el Google Calendar al suyo (http://screenr.com/nr7)", detail.Summary);
+		}
     }
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Google/DetailsEvents/VanGEventDetail.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Google/DetailsEvents/VanGEventDetail.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -1,5 +1,7 @@
 using System;
+using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using AltNetHispano.Agendas.Domain;
 
 namespace AltNetHispano.Agendas.Google.DetailsEvents
@@ -7,7 +9,7 @@
     public class VanGEventDetail : IGEventDetail
     {
         private const string TextoVan =
-           "La comunidad ALT.NET Hispano (http://altnethispano.org) realizará una VAN sobre [NOMBRE], con [NOMBRE_EXPOSITOR]." +
+           "La comunidad ALT.NET Hispano (http://altnethispano.org) realizará [EVENTO_TIPO] sobre [NOMBRE][NOMBRE_EXPOSITOR]." +
            "\n\rFecha: [FECHA] a las 18:00 hrs. Hora Internacional (GMT/UTC), con una duración aproximada de 2 horas." +
            "\n\rPueden plantear sus comentarios e inquietudes sobre el tema de la reunión en: [URL_DISCUCION]" +
            "\n\rPara mayor información sobre cómo atender la reunión consulten: http://tinyurl.com/van-hispano" +
@@ -28,10 +30,32 @@
             EndEvent = evento.FechaTermino.Value;
             var cultureInfo = new CultureInfo( "es-ES", false ).DateTimeFormat;
 
-            Summary = TextoVan.Replace("[NOMBRE]", evento.Titulo).
-                Replace("[NOMBRE_EXPOSITOR]", evento.Ponente.Nombre).
+            Summary = TextoVan.Replace("[EVENTO_TIPO]", GetEventoTipo(evento.Tipo)).
+				Replace("[NOMBRE]", evento.Titulo).
+				Replace("[NOMBRE_EXPOSITOR]", GetPonentes(evento)).
                 Replace("[FECHA]", StartEvent.ToString("D", cultureInfo)).
                 Replace("[URL_DISCUCION]", evento.UrlInvitacion);
         }
+
+    	private static string GetPonentes(Evento evento)
+    	{
+    		var ponentes = evento.GetPonentesAsString(p => p.Nombre);
+    		return !string.IsNullOrWhiteSpace(ponentes) ? string.Format(", con {0}", ponentes) : string.Empty;
+    	}
+
+    	private static string GetEventoTipo(TipoEvento tipo)
+    	{
+			switch (tipo)
+			{
+				case TipoEvento.Van:
+					return "una VAN";
+				case TipoEvento.Cafe:
+					return "un Café";
+				case TipoEvento.GrupoEstudio:
+					return "un Grupo de estudio";
+				default:
+					return string.Empty;
+			}
+		}
     }
 }
--- a/Agendas/trunk/src/Agendas.Tests/AgendarTests.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/AgendarTests.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -84,7 +84,7 @@
 		}
 
 		[Test]
-		public void Intentar_agendar_evento_sin_ponente()
+		public void Intentar_agendar_van_sin_ponente()
 		{
 			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository);
 
@@ -96,6 +96,30 @@
 		}
 
 		[Test]
+		public void Agendar_cafe_sin_ponente()
+		{
+			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository);
+
+			var fechaInicio = DateTime.Now.ToUniversalTime();
+			var fechaTermino = fechaInicio.AddHours(2);
+			var r = agenda.Agendar("Cafe para publicar", Guid.Empty, fechaInicio, fechaTermino, urlInvitacion, TipoEvento.Cafe);
+
+			Assert.IsTrue(r.Succeful);
+		}
+
+		[Test]
+		public void Agendar_grupo_de_estudio_sin_ponente()
+		{
+			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository);
+
+			var fechaInicio = DateTime.Now.ToUniversalTime();
+			var fechaTermino = fechaInicio.AddHours(2);
+			var r = agenda.Agendar("GrupoEstudio para publicar", Guid.Empty, fechaInicio, fechaTermino, urlInvitacion, TipoEvento.GrupoEstudio);
+
+			Assert.IsTrue(r.Succeful);
+		}
+
+		[Test]
 		public void Agendar_evento_con_multiples_publicadores()
 		{
 			var publicador1 = new Mock<IPublicador>();
--- a/Agendas/trunk/src/Agendas.Tests/PonentesTests.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/PonentesTests.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -94,35 +94,68 @@
         }
 
         [Test]
-        public void Quitar_ponente_de_un_evento()
+        public void Quitar_ponente_de_una_van()
         {
             var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository);
 
             const string titulo = "Audit (parallel model) con NHibernate 3";
             Guid eventoId;
 
-            agenda.Proponer(titulo, TestsHelper.GetOrCreatePonente("Fabio"), urlInvitacion, TipoEvento.Van);
-            Persona persona;
-            {
-                var eventos = agenda.GetEventosActivos(EventoPropuestoState.GetInstance());
+        	DateTime fechaInicio=DateTime.Now;
+
+        	var r = agenda.Agendar(titulo, TestsHelper.GetOrCreatePonente("Fabio"), fechaInicio, fechaInicio.AddHours(2), urlInvitacion, TipoEvento.Van);
+        	{
+				Assert.IsTrue(r.Succeful);
+
+				var eventos = agenda.GetEventosActivos(EventoAgendadoState.GetInstance());
                 Assert.AreEqual(1, eventos.Count);
 
                 Evento evento = eventos[0];
                 Assert.AreEqual("Fabio", evento.Ponente.Nombre);
 
                 eventoId = evento.Id;
-                persona = evento.Ponente;
             }
 
-            agenda.ModificarPropuesta(eventoId, titulo, Guid.Empty, urlInvitacion);
-            {
-                var eventos = agenda.GetEventosActivos(EventoPropuestoState.GetInstance());
-                Assert.AreEqual(1, eventos.Count);
+        	r = agenda.ModificarEvento(eventoId, titulo, Guid.Empty, fechaInicio, fechaInicio.AddHours(2), urlInvitacion);
+			Assert.IsFalse(r.Succeful);
+
+        }
+
+		[Test]
+		public void Quitar_ponente_de_un_cafe()
+		{
+			var agenda = new Agenda(null, DefaultEventoRepository, DefaultPersonaRepository);
+
+			const string titulo = "Audit (parallel model) con NHibernate 3";
+			Guid eventoId;
+
+			DateTime fechaInicio = DateTime.Now;
+
+			var r = agenda.Agendar(titulo, TestsHelper.GetOrCreatePonente("Fabio"), fechaInicio, fechaInicio.AddHours(2), urlInvitacion, TipoEvento.Cafe);
+			{
+				Assert.IsTrue(r.Succeful);
 
-                Evento evento = eventos[0];
-                Assert.IsNull(evento.Ponente);
-            }
-        }
+				var eventos = agenda.GetEventosActivos(EventoAgendadoState.GetInstance());
+				Assert.AreEqual(1, eventos.Count);
+
+				Evento evento = eventos[0];
+				Assert.AreEqual("Fabio", evento.Ponente.Nombre);
+
+				eventoId = evento.Id;
+			}
+
+			r = agenda.ModificarEvento(eventoId, titulo, Guid.Empty, fechaInicio, fechaInicio.AddHours(2), urlInvitacion);
+			{
+				Console.WriteLine(r.Message);
+				Assert.IsTrue(r.Succeful);
+
+				var eventos = agenda.GetEventosActivos(EventoAgendadoState.GetInstance());
+				Assert.AreEqual(1, eventos.Count);
+
+				Evento evento = eventos[0];
+				Assert.IsNull(evento.Ponente);
+			}
+		}
 
         [Test]
         public void Cambiar_ponente_de_un_evento()
--- a/Agendas/trunk/src/Agendas.Twitter.Tests/Publicador_tests.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter.Tests/Publicador_tests.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Tests;
 using AltNetHispano.Agendas.Twitter;
@@ -56,5 +58,79 @@
 			Assert.That(twitt, Is.StringContaining("@nelopauselli"));
 
 		}
+
+		[Test]
+		public void Twitter_texto_largo()
+		{
+			var adapter = new Mock<ITwitterAdapter>();
+
+			string message;
+			var twitters= new List<string>();
+			adapter.Setup(a => a.Update(It.IsAny<string>(), out message)).Returns(true).Callback<string, string>((status, m) => twitters.Add(status));
+
+			var publicador = new TwitterPublicador(adapter.Object);
+			var agenda = new Agenda(publicador, DefaultEventoRepository, DefaultPersonaRepository);
+
+			var ponente = new Persona("Carlos Peix", "carlospeix@gmail.com", "carlospeix", "http://www.carlospeix.com.ar");
+			DefaultPersonaRepository.Save(ponente);
+
+			var otrosPonentes = new Persona("Nelo Pauselli", "nelopauselli@gmail.com", "nelopauselli",
+			                                "http://nelopauselli.blogspot.com/");
+			DefaultPersonaRepository.Save(otrosPonentes);
+
+			var inicio = DateTime.Now.AddDays(3);
+
+			agenda.Agendar("Identity Providers Públicos y Empresariales", ponente.Id, inicio, inicio.AddHours(2), null, TipoEvento.Van,
+			               new[] {otrosPonentes.Id});
+
+			Assert.IsTrue(twitters.Any());
+			var joined = string.Empty;
+			foreach (var twitter in twitters)
+			{
+				Console.WriteLine(twitter);
+				Assert.LessOrEqual(twitter.Length, 140);
+				joined += twitter;
+			}
+			Assert.That(joined, Is.StringContaining("Identity Providers Públicos y Empresariales"));
+			Assert.That(joined, Is.StringContaining("@carlospeix"));
+			Assert.That(joined, Is.StringContaining("@nelopauselli"));
+
+			Assert.AreEqual(2, twitters.Count());
+			Assert.AreEqual("Se ha agendando el evento Identity Providers Públicos y Empresariales con @carlospeix y @nelopauselli para el 01/10/2011...", twitters.First());
+			Assert.AreEqual("...por http://snipr.com/virtualaltnet", twitters.Last());
+
+			adapter.Verify(a => a.Update(It.IsAny<string>(), out message), Times.Exactly(2));
+
+		}
+
+		[Test]
+		public void Evento_sin_ponente()
+		{
+			var adapter = new Mock<ITwitterAdapter>();
+
+			string message;
+			var twitters = new List<string>();
+			adapter.Setup(a => a.Update(It.IsAny<string>(), out message)).Returns(true).Callback<string, string>((status, m) => twitters.Add(status));
+
+			var publicador = new TwitterPublicador(adapter.Object);
+			var agenda = new Agenda(publicador, DefaultEventoRepository, DefaultPersonaRepository);
+
+			var inicio = DateTime.Now.AddDays(3);
+
+			agenda.Agendar("Identity Providers Públicos y Empresariales", Guid.Empty, inicio, inicio.AddHours(2), null, TipoEvento.Cafe);
+
+			Assert.IsTrue(twitters.Any());
+			var joined = string.Empty;
+			foreach (var twitter in twitters)
+			{
+				Console.WriteLine(twitter);
+				Assert.LessOrEqual(twitter.Length, 140);
+				joined += twitter;
+			}
+			Assert.AreEqual("Se ha agendando el evento Identity Providers Públicos y Empresariales para el 01/10/2011 por http://snipr.com/virtualaltnet", joined);
+
+			adapter.Verify(a => a.Update(It.IsAny<string>(), out message), Times.Once());
+
+		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/ITwitterWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/ITwitterWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -4,6 +4,6 @@
 {
 	public interface ITwitterWriter
 	{
-		string Write(Track track);
+		string[] Write(Track track);
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/Recordatorios.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Recordatorios.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -19,8 +19,8 @@
 
 			for (int hora = 3; hora > 0; hora--)
 			{
-				var mensaje = TwitterStringHelper.TipoEvento(evento.Tipo) + " sobre " + evento.Titulo + " con " +
-				              TwitterStringHelper.Ponente(evento.Ponente) + " inicia en [" + hora + "] hora" +
+				var mensaje = TwitterStringHelper.TipoEvento(evento.Tipo) + " sobre " + evento.Titulo + 
+				              TwitterStringHelper.Ponentes(evento) + " inicia en [" + hora + "] hora" +
 				              (hora > 1 ? "s" : string.Empty) + " " +
 				              TwitterStringHelper.Hora(fechaInicio) + " http://snipr.com/virtualaltnet";
 
@@ -28,8 +28,8 @@
 				Items.Add(new RecordatorioItem(fechaRecordatorio, mensaje));
 			}
 
-			var mensaje15 = TwitterStringHelper.TipoEvento(evento.Tipo) + " sobre " + evento.Titulo + " con " +
-						  TwitterStringHelper.Ponente(evento.Ponente) + " inicia en [15] minutos " +
+			var mensaje15 = TwitterStringHelper.TipoEvento(evento.Tipo) + " sobre " + evento.Titulo + 
+						  TwitterStringHelper.Ponentes(evento) + " inicia en [15] minutos " +
 						  TwitterStringHelper.Hora(fechaInicio) + " http://snipr.com/virtualaltnet";
 
 			var fechaRecordatorio15 = fechaInicio.AddMinutes(-15);
--- a/Agendas/trunk/src/Agendas.Twitter/TwitterPublicador.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/TwitterPublicador.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -30,7 +30,7 @@
 			_twitterAdapter = twitterAdapter;
 		}
 
-		private const int LIMITE_MENSAJE = 140;
+		private const int LIMITE_MENSAJE = 134;
 
 		public void Publicar(IEnumerable<Track> tracks)
 		{
@@ -42,12 +42,19 @@
 				if (track.Logs.Any(l => l.Propietario == TrackLogPropietario.Twitter && l.Successful)) continue;
 
 				var twitt = BuildTwitt(track);
-				if (!string.IsNullOrWhiteSpace(twitt))
+				if (twitt.Length>0)
 				{
 					try
 					{
-						string message;
-						bool success = _twitterAdapter.Update(twitt, out message);
+						bool success=true;
+						string message=string.Empty;
+						
+						foreach (var t in twitt)
+						{
+							string m;
+							success &= _twitterAdapter.Update(t, out m);
+							message += m;
+						}
 						track.LogAdd(new TrackLog(TrackLogPropietario.Twitter, message, track.Usuario, success));
 					}
 					catch(Exception ex)
@@ -58,15 +65,43 @@
 			}
 		}
 
-		private string BuildTwitt(Track track)
+		private string[] BuildTwitt(Track track)
 		{
 			ITwitterWriter writer;
 			if (!_writers.TryGetValue(track.Accion, out writer))
-				return string.Empty;
+				return new[] {string.Empty};
+
+			var partes = writer.Write(track).Where(t => !string.IsNullOrWhiteSpace(t)).ToArray();
+
+			var twitters = new List<string>();
+
+			string twitter = string.Empty;
+			for (int index = 0; index < partes.Length; index++)
+			{
+				string parte = partes[index];
 
-			string body = writer.Write(track);
+				var nuevo = twitter + parte;
+				if (nuevo.Length < LIMITE_MENSAJE)
+					twitter = nuevo;
+				else
+				{
+					if (index<parte.Length-1)
+						twitter += "...";
+					if (twitters.Any())
+						twitter = "..." + twitter;
 
-			return body.Length > LIMITE_MENSAJE ? body.Substring(0, LIMITE_MENSAJE - 1) : body;
+					twitters.Add(twitter);
+					twitter = parte.Trim();
+				}
+			}
+			if (!string.IsNullOrWhiteSpace(twitter))
+			{
+				if (twitters.Any())
+					twitter = "..." + twitter;
+				twitters.Add(twitter);
+			}
+
+			return twitters.ToArray();
 		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/TwitterStringHelper.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/TwitterStringHelper.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -20,9 +20,10 @@
 			}
 		}
 
-		public static string Ponente(Persona ponente)
+		public static string Ponentes(Evento evento)
 		{
-			return "@"+ponente.Twitter;
+			var ponentes = evento.GetPonentesAsString(p => "@" + p.Twitter);
+			return !string.IsNullOrWhiteSpace(ponentes) ? " con " + ponentes : string.Empty;
 		}
 
 		public static string Hora(DateTime fechaInicio)
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/AgendarTwitterWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/AgendarTwitterWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -1,19 +1,22 @@
-using System;
-using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Domain;
 
 namespace AltNetHispano.Agendas.Twitter.Writers
 {
 	public class AgendarTwitterWriter : ITwitterWriter
 	{
-		public string Write(Track track)
+		public string[] Write(Track track)
 		{
-			var body = "Se ha agendando el evento " + track.Evento.Titulo;
-			
-			body += " con " + TwitterHelper.GetPonente(track.Evento.Ponente);
+			return new[]
+			       	{
+			       		"Se ha agendando el evento " + track.Evento.Titulo,
+			       		TwitterHelper.GetPonentes(track.Evento),
+			       		track.Evento.FechaInicio.HasValue
+			       			? " para el " + track.Evento.FechaInicio.Value.ToShortDateString()
+			       			: string.Empty,
+			       		" por http://snipr.com/virtualaltnet"
+			       	};
 
-			if (track.Evento.FechaInicio.HasValue)
-				body += " para el " + track.Evento.FechaInicio.Value.ToShortDateString();
-			return body;
+
 		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/ConfirmarTwitterWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/ConfirmarTwitterWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -4,13 +4,17 @@
 {
 	public class ConfirmarTwitterWriter : ITwitterWriter
 	{
-		public string Write(Track track)
+		public string[] Write(Track track)
 		{
 			{
 				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;
+					return new[]
+					       	{
+					       		"Se confirma para el " + track.Evento.FechaInicio.Value.ToShortDateString(),
+					       		" el evento " + track.Evento.Titulo,
+					       		TwitterHelper.GetPonentes(track.Evento)
+					       	};
+				return new[] {string.Empty};
 			}
 		}
 	}
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/ProponerTwitterWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/ProponerTwitterWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -4,10 +4,10 @@
 {
 	public class ProponerTwitterWriter : ITwitterWriter
 	{
-		public string Write(Track track)
+		public string[] Write(Track track)
 		{
 			var sust = track.Evento.Tipo == TipoEvento.Van ? "una nueva VAN" : "un nuevo " + track.Evento.Tipo;
-			return "Se ha propuesto " + sust + " sobre " + track.Evento.Titulo;
+			return new[] {"Se ha propuesto " + sust, " sobre " + track.Evento.Titulo};
 		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/PublicarTwitterWriter.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/PublicarTwitterWriter.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -1,12 +1,17 @@
-using AltNetHispano.Agendas.Domain;
+using System;
+using AltNetHispano.Agendas.Domain;
 
 namespace AltNetHispano.Agendas.Twitter.Writers
 {
 	public class PublicarTwitterWriter : ITwitterWriter
 	{
-		public string Write(Track track)
+		public string[] Write(Track track)
 		{
-			return "Se ha publicado el video del evento " + track.Evento.Titulo + " con " + TwitterHelper.GetPonente(track.Evento.Ponente);
+			return new[]
+			       	{
+			       		"Se ha publicado el video del evento " + track.Evento.Titulo,
+			       		TwitterHelper.GetPonentes(track.Evento)
+			       	};
 		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Twitter/Writers/TwitterHelper.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Twitter/Writers/TwitterHelper.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -4,11 +4,18 @@
 {
 	public static class TwitterHelper
 	{
-		public static string GetPonente(Persona ponente)
+		public static string GetPonentes(Evento evento)
+		{
+			var ponentes = evento.GetPonentesAsString(GetPonente);
+			return !string.IsNullOrWhiteSpace(ponentes) ? " con " + ponentes : string.Empty;
+		}
+
+		private static string GetPonente(Persona ponente)
 		{
 			if (!string.IsNullOrWhiteSpace(ponente.Twitter))
 				return "@" + ponente.Twitter;
 			return ponente.Nombre;
 		}
+
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Controllers/HistoricoController.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/HistoricoController.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -21,7 +21,7 @@
 			            		               		Titulo = e.Titulo,
 			            		               		Fecha = e.FechaInicio.HasValue ? e.FechaInicio.Value.ToShortDateString() : string.Empty,
 			            		               		Wiki = e.UrlWiki,
-													Ponente = e.Ponente.Nombre,
+													Ponentes = e.Ponentes.Select(p=>p.Nombre),
                                                     Numero = e.NumeroOrden.ToString(),
                                                     Tipo = e.Tipo.ToString(),
 													Duracion = e.Duracion.ToString(@"hh\:mm")
--- a/Agendas/trunk/src/Agendas.Web/DataProviders.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/DataProviders.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -18,11 +18,15 @@
 
         public static IEnumerable<SelectListItem> GetPonentes(this HtmlHelper helper, Guid id)
         {
-            var personas = AgendaFactory.GetPersonaService();
-            return from p in personas.GetAll()
-                   orderby p.Nombre
-                   select
-                       new SelectListItem {Text = p.Nombre, Value = p.Id.ToString(), Selected = p.Id.Equals(id)};
+        	var lista = new List<SelectListItem> {new SelectListItem {Text = "[Ninguno]", Value = Guid.Empty.ToString()}};
+
+            var personaService = AgendaFactory.GetPersonaService();
+        	var personas = from p in personaService.GetAll()
+        	               orderby p.Nombre
+        	               select
+        	               	new SelectListItem {Text = p.Nombre, Value = p.Id.ToString(), Selected = p.Id.Equals(id)};
+
+        	return lista.Union(personas);
         }
 
 		public static IEnumerable<SelectListItem> GetOtrosPonentes(this HtmlHelper helper, IEnumerable<Guid> ids)
--- a/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/EventoModel.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -20,7 +20,6 @@
 		[Required]
 		public string Titulo { get; set; }
 
-		[Required]
         public Guid Ponente { get; set; }
 
 		public Guid[] OtrosPonentes { get; set; }
@@ -46,7 +45,6 @@
 		[Required]
 		public string Titulo { get; set; }
 
-		[Required]
         public Guid Ponente { get; set; }
 
 		[Required]
@@ -70,7 +68,6 @@
 		[Required]
 		public string Titulo { get; set; }
 
-		[Required]
         public Guid Ponente { get; set; }
 
 		[Required]
--- a/Agendas/trunk/src/Agendas.Web/Models/HistoricoModel.cs	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/HistoricoModel.cs	Tue Oct 04 20:36:27 2011 -0300
@@ -16,7 +16,7 @@
 		public string Titulo { get; set; }
 		public string Fecha { get; set; }
 		public string Wiki { get; set; }
-		public string Ponente { get; set; }
+		public IEnumerable<string> Ponentes { get; set; }
 		public string Duracion { get; set; }
 	}
 
--- a/Agendas/trunk/src/Agendas.Web/Views/Historico/Index.cshtml	Tue Oct 04 20:34:46 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Historico/Index.cshtml	Tue Oct 04 20:36:27 2011 -0300
@@ -22,7 +22,11 @@
             <td>@item.Fecha</td>
             <td>@item.Tipo</td>
             <td><a href="@item.Wiki">@item.Titulo</a></td>
-            <td>@item.Ponente</td>
+            <td>
+				@foreach(var ponente in item.Ponentes) {
+					@ponente<br />
+				}
+			</td>
             <td>@item.Duracion</td>
         </tr>
 		}