Mercurial > altnet-hispano
changeset 219:b9850b647a4e
Agregando alta de ponente durante la carga del evento
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.
--- /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