changeset 219:b9850b647a4e

Agregando alta de ponente durante la carga del evento
author nelopauselli
date Thu, 08 Sep 2011 11:22:10 -0300
parents cc1ed131c9e6
children 42a1068e73c8
files Agendas/trunk/src/Agendas.Domain/Resultado.cs Agendas/trunk/src/Agendas.Domain/Services/PersonaService.cs Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrud.cs Agendas/trunk/src/Agendas.Tests/PersonaServiceTests.cs Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj Agendas/trunk/src/Agendas.Web/Content/loader.gif Agendas/trunk/src/Agendas.Web/Content/subpanels-0.9.css Agendas/trunk/src/Agendas.Web/Controllers/PersonaApiController.cs Agendas/trunk/src/Agendas.Web/Scripts/subpanels-0.9.js Agendas/trunk/src/Agendas.Web/Views/PersonaApi/Nueva.cshtml Agendas/trunk/src/Agendas.Web/Views/Shared/DefaultEditor.cshtml Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Ponente.cshtml
diffstat 13 files changed, 315 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/Agendas/trunk/src/Agendas.Domain/Resultado.cs	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Resultado.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 
 namespace AltNetHispano.Agendas.Domain
 {
@@ -14,6 +15,22 @@
         public string Message { get; internal set; }
 	}
 
+	public class ResultadoAdd : Resultado
+	{
+		public Guid Id { get; set; }
+		public string Nombre { get; set; }
+
+		public ResultadoAdd(bool succeful, string message, Guid id, string nombre) : base(succeful, message)
+		{
+			Id = id;
+			Nombre = nombre;
+		}
+
+		public ResultadoAdd(string message) : base(false, message)
+		{
+		}
+	}
+
 	public class EventoResultado : Resultado
 	{
 		public EventoResultado(bool succeful, string message, IEnumerable<TrackLog> warnings)
--- a/Agendas/trunk/src/Agendas.Domain/Services/PersonaService.cs	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/Services/PersonaService.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -81,9 +81,17 @@
 	        return _personaRepository.Get(id);
 	    }
 
-		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};
+		public ResultadoAdd Add(string nombre, string twitter, string mail, string blog, IEnumerable<string> roles)
+		{
+			var persona = _personaRepository.GetByNombre(nombre);
+			if (persona!=null)
+				return new ResultadoAdd("Ya existe una persona con el nombre " + nombre);
+
+			persona = _personaRepository.GetByTwitter(twitter);
+			if (persona != null)
+				return new ResultadoAdd("Ya existe una persona con el twitter " + twitter);
+
+			persona = new Persona(nombre) {Twitter = twitter, Mail = mail, Blog = blog};
 
 			if (!string.IsNullOrWhiteSpace(twitter))
 				persona.AddCuenta(new Cuenta(IdentityProviderEnum.Twitter, twitter));
@@ -101,7 +109,7 @@
 
 			_personaRepository.Save(persona);
 
-            return new Resultado(true, "Persona Agregada");
+			return new ResultadoAdd(true, "Persona Agregada", persona.Id, persona.Nombre);
         }
 
 		public Resultado Update(Guid id, string nombre, string twitter, string mail, string blog, IEnumerable<string> roles)
--- a/Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrud.cs	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Cruds/PersonaCrud.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -24,15 +24,21 @@
 
 		public Guid CreateAdministrador()
 		{
+			Guid id;
 			using (_requestEmulator.Invoke())
 			{
-				_personaService.Add("Nelo Pauselli", "nelopauselli", "nelopauselli@gmail.com", "http://nelopauselli.blogspot.com", null);
+				var r = _personaService.Add("Nelo Pauselli", "nelopauselli", "nelopauselli@gmail.com", "http://nelopauselli.blogspot.com", null);
+				Assert.AreEqual("Nelo Pauselli", r.Nombre);
+				Assert.AreNotEqual(Guid.Empty, r.Id);
+
+				id = r.Id;
 			}
 
 			using (_requestEmulator.Invoke())
 			{
 				var persona = _personaRepository.GetByNombre("Nelo Pauselli");
 				Assert.IsNotNull(persona);
+				Assert.AreEqual(id, persona.Id);
 				return persona.Id;
 			}
 		}
--- a/Agendas/trunk/src/Agendas.Tests/PersonaServiceTests.cs	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/PersonaServiceTests.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -37,6 +37,38 @@
 			Assert.AreEqual(1, persona.Cuentas.Count());
 		}
 
+		[Test]
+		public void Crear_persona_duplicada_por_nombre()
+		{
+			var personaRepository = new Mock<IPersonaRepository>();
+			
+			var persona = new Persona("Nelo Pauselli");
+			personaRepository.Setup(r => r.GetByNombre(It.IsAny<string>())).Returns(persona);
+			var personaService = new PersonaService(personaRepository.Object, DefaultEventoRepository);
+
+			var result = personaService.Add("Nelo Pauselli", "nelopauselli", "nelopauselli@gmail.com", null, null);
+			Assert.IsFalse(result.Succeful);
+			Assert.AreEqual("Ya existe una persona con el nombre Nelo Pauselli", result.Message);
+
+			personaRepository.Verify(r => r.Save(It.IsAny<Persona>()), Times.Never());
+		}
+
+		[Test]
+		public void Crear_persona_duplicada_por_twitter()
+		{
+			var personaRepository = new Mock<IPersonaRepository>();
+
+			var persona = new Persona("Nelo Pauselli");
+			personaRepository.Setup(r => r.GetByTwitter(It.IsAny<string>())).Returns(persona);
+			var personaService = new PersonaService(personaRepository.Object, DefaultEventoRepository);
+
+			var result = personaService.Add("Nelo Pauselli", "nelopauselli", "nelopauselli@gmail.com", null, null);
+			Assert.IsFalse(result.Succeful);
+			Assert.AreEqual("Ya existe una persona con el twitter nelopauselli", result.Message);
+
+			personaRepository.Verify(r => r.Save(It.IsAny<Persona>()), Times.Never());
+		}
+
         [Test]
         public void Asociar_persona_existente_por_twitter()
         {
--- a/Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -93,7 +93,7 @@
 			               		"EventoController.Publicar", "EventoController.Modificar", "EventoController.Proponer",
 			               		"EventoController.Cancelar", "EventoController.Descartar", "EventoController.ReAgendar",
 			               		"EventoController.ReProponer", "PersonaController.Nueva", "PersonaController.Modificar",
-                                "PersonaController.Quitar"
+                                "PersonaController.Quitar", "PersonaApiController.Nueva"
 			               	};
 
 			VerficarAccionesSeguras(acciones, Roles.Administrador, "debe ser de uso exclusivo de los administradores");
--- a/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Thu Sep 08 11:22:10 2011 -0300
@@ -68,6 +68,7 @@
     <Compile Include="Controllers\HistoricoController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
     <Compile Include="Controllers\PerfilController.cs" />
+    <Compile Include="Controllers\PersonaApiController.cs" />
     <Compile Include="Controllers\PersonaController.cs" />
     <Compile Include="DataProviders.cs" />
     <Compile Include="EditorDefaultExtensions.cs" />
@@ -92,7 +93,9 @@
   <ItemGroup>
     <Content Include="Content\AltNetHispanoVans.css" />
     <Content Include="Content\altnetlogo.png" />
+    <Content Include="Content\loader.gif" />
     <Content Include="Content\question.jpg" />
+    <Content Include="Content\subpanels-0.9.css" />
     <Content Include="Content\themes\altnethispano\images\div_content.gif" />
     <Content Include="Content\themes\altnethispano\images\div_wrapperIn.gif" />
     <Content Include="Content\themes\altnethispano\images\header-background.gif" />
@@ -106,6 +109,7 @@
     <Content Include="hibernate.cfg.xml">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
+    <Content Include="Scripts\subpanels-0.9.js" />
     <Content Include="Web.config">
       <SubType>Designer</SubType>
     </Content>
@@ -239,6 +243,9 @@
   <ItemGroup>
     <Content Include="Views\Shared\EditorTemplates\Recordatorios.cshtml" />
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="Views\PersonaApi\Nueva.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. 
Binary file Agendas/trunk/src/Agendas.Web/Content/loader.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Content/subpanels-0.9.css	Thu Sep 08 11:22:10 2011 -0300
@@ -0,0 +1,13 @@
+.sp-header {
+	padding: 5px 10px 5px;
+	font-size: 1.2em;
+}
+
+.sp-buttons {
+	padding: 5px 5px 5px 5px;
+	text-align: right;
+}
+
+.ajax-button {
+	display: inline-block;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/PersonaApiController.cs	Thu Sep 08 11:22:10 2011 -0300
@@ -0,0 +1,32 @@
+using System;
+using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Factories;
+using AltNetHispano.Agendas.Web.Models;
+
+namespace AltNetHispano.Agendas.Web.Controllers
+{
+	public class PersonaApiController : Controller
+	{
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public PartialViewResult Nueva()
+		{
+			var model = new PersonaNewModel();
+			return PartialView(model);
+		}
+
+		[HttpPost]
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public JsonResult Nueva(PersonaNewModel model)
+		{
+			if (ModelState.IsValid)
+			{
+				var personas = AgendaFactory.GetPersonaService();
+				var r = personas.Add(model.Nombre, model.Twitter, model.EMail, model.Blog, model.Roles);
+				return Json(r);
+			}
+
+			return Json(new Resultado(false, string.Join(",", ModelState.Values)));
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Scripts/subpanels-0.9.js	Thu Sep 08 11:22:10 2011 -0300
@@ -0,0 +1,149 @@
+jQuery.fn.subpanel = function () {
+	var panel = $(this[0]);
+	var settings = arguments[0] || {};
+
+	var closeLink = null;
+	var openLink = null;
+	var main = null;
+	var loading = null;
+
+	this.create = function () {
+		// botón para abrir el panel
+		openLink = $('<a></a>').addClass('ajax-button ui-widget ui-state-default ui-corner-all').click(this.open).appendTo(panel);
+		var openSpan = $('<span></span>').addClass('ui-icon ui-icon-plusthick').appendTo(openLink);
+
+		closeLink = $('<a></a>').addClass('ajax-button ui-widget ui-state-default ui-corner-all').css('display', 'none').click(this.close).appendTo(panel);
+		var closeSpan = $('<span></span>').addClass('ui-icon ui-icon-minusthick').appendTo(closeLink);
+
+		// panel principal
+		main = $('<div></div>')
+			.addClass('ui-widget')
+			.addClass('ui-widget-content')
+			.addClass('ui-corner-all')
+			.width(settings.width || '400px')
+			.css('display', 'none')
+			.appendTo(panel);
+	};
+
+	this.close = function () {
+		if (loading !== undefined && loading !== null) {
+			loading.abort();
+			settings.aborting();
+		}
+
+		$(this).hide();
+		openLink.show();
+		main.hide();
+		main.html('');
+	};
+
+	this.open = function () {
+		$(this).hide();
+		closeLink.show();
+		main.show();
+
+		// si hay título, creamos el header
+		if (settings.title !== undefined) {
+			var header = $('<div></div>')
+				.addClass('sp-header').addClass('ui-widget-header')
+				.appendTo(main);
+
+			var title = $('<span><span>')
+				.html(settings.title)
+				.appendTo(header);
+		}
+
+		// div que contendrá el html del panel
+		var content = $('<div></div>')
+			.appendTo(main);
+
+		var imgdiv = $('<div></div>').css('text-align', 'center').css('padding-top', '10px').appendTo(content);
+		var img = $('<img />').attr('src', '/Content/loader.gif').attr('alt', 'loading...').appendTo(imgdiv);
+
+		// se invoca la acción con un GET para obtener el contenido del panel
+		loading = $.ajax({
+			url: settings.action,
+			cache: false,
+			success: function (data) {
+				loading = null;
+
+				// cuando se recibe el contenido del panel, lo agregamos al div contenedor
+				content.html(data);
+
+				// form dentro del cual se ejecutará el panel, y del que luego se hará el POST
+				var form = $('form', content);
+
+				form.submit(function (event) {
+					// prevenimos que se ejecute el submit ya que lo haremos manualmente.
+					event.preventDefault();
+
+					var self = $(this);
+
+					/* preguntamos si el formulario es validable y válido, con esto tenemos un problema 
+					ya que no se están generando los validadores por un problema entre jquery.validate 
+					y ajax */
+					var valid = self.valid();
+					if (valid === undefined || valid) {
+
+						// tomamos la acción y serializamos el form
+						var action = self.attr("action");
+						var data = self.serialize();
+
+						// ejecutamos el POST
+						$.post(action, data, function (data) {
+							// cuando termina de ejecutarse el POST, ejecutamos la acción configurada
+							var r = settings.successful(data);
+
+							// si esta acción no devuelve false, cerramos el panel
+							if (r === undefined || r)
+								closeLink.click();
+						});
+					}
+				});
+
+				$.validator.unobtrusive.parse(form);
+
+				$('input:submit', form).each(function () { $(this).button(); });
+
+				// y seteamos el foco en el primer input
+				var nextInput = $("input:visible:first", form);
+				nextInput.focus();
+			},
+			error: function (xhr, text) {
+				loading = null;
+
+				if (xhr.status !== 0) {
+					content.html(xhr.responseText)
+					.addClass('ui-state-error');
+				}
+				else {
+					closeLink.click();
+				}
+			}
+		});
+
+		/*
+		var buttons = $('<div></div>')
+		.addClass('sp-buttons')
+		.appendTo(form);
+
+		var confirm = $('<input/>')
+		.attr('type', 'submit')
+		.attr('value', settings.confirmButton || 'Save')
+		.button()
+		.appendTo(buttons);
+
+		var x = $('<a></a>')
+		.html(settings.cancelButton || 'Cancel')
+		.button()
+		.click(function (e) {
+		e.preventDefault();
+		closeLink.click();
+		settings.cancel();
+		})
+		.appendTo(buttons);
+		*/
+	};
+
+	this.create();
+}		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Views/PersonaApi/Nueva.cshtml	Thu Sep 08 11:22:10 2011 -0300
@@ -0,0 +1,5 @@
+@model AltNetHispano.Agendas.Web.Models.PersonaNewModel
+@using (Html.BeginForm()) {
+	@Html.EditorForModel()
+	<input type="submit" value="agregar" />
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Views/Shared/DefaultEditor.cshtml	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/DefaultEditor.cshtml	Thu Sep 08 11:22:10 2011 -0300
@@ -6,6 +6,9 @@
 <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
 
+<script src="@Url.Content("~/Scripts/subpanels-0.9.js")" type="text/javascript"></script>
+<link rel="stylesheet" href="@Url.Content("~/Content/subpanels-0.9.css")" type="text/css" />
+
 @using (Html.BeginForm())
 {
     @Html.ValidationSummary(true)
--- a/Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Ponente.cshtml	Thu Sep 08 09:38:47 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/EditorTemplates/Ponente.cshtml	Thu Sep 08 11:22:10 2011 -0300
@@ -1,2 +1,37 @@
 @model Guid
-@Html.DropDownList(string.Empty, Html.GetPonentes(Model))
+<script type="text/javascript">
+	$(document).ready(function () {
+		$("#agregarPonente").subpanel({ successful: recargar, confirmButton: "Agregar", action: '/PersonaApi/Nueva' });
+	});
+
+	function recargar(data) {
+		if (data.Succeful) {
+			// obtenemos el dropdown
+			var ponentes = $("#Ponente");
+
+			// agregamos el ponente
+			var opcion = $("<option></option>").attr("value", data.Id).html(data.Nombre).appendTo(ponentes);
+
+			// ordenamos los ponentes
+			var options = $("option", ponentes);
+
+			options.sort(function (a, b) {
+				if (a.text > b.text) return 1;
+				else if (a.text < b.text) return -1;
+				else return 0
+			})
+
+			ponentes.empty().append(options);
+
+			// seleccionamos el ponente que acabamos de agregar
+			ponentes.attr("value", data.Id);
+		}
+		else {
+			alert(data.Message);
+			return false;
+		}
+	}
+
+</script>
+@Html.DropDownList(string.Empty, Html.GetPonentes(Model), new { style = "vertical-align: top;" })
+<div id="agregarPonente" style="display: inline-block"></div>
\ No newline at end of file