From 571bf2c715522c09552ee1fea492d842c0dc121a Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 1 Dec 2016 17:42:34 +0100 Subject: [PATCH 001/100] clean & update project refs --- Yavsc/ApiControllers/PdfEstimateController.cs | 9 +++++++ Yavsc/Avatars/Paul.png | Bin 44364 -> 0 bytes Yavsc/Avatars/Paul.s.png | Bin 11974 -> 0 bytes Yavsc/Avatars/Paul.xs.png | Bin 3269 -> 0 bytes Yavsc/Helpers/FileSystemHelpers.cs | 25 +++++++++++++++--- Yavsc/Views/Manage/SetActivity.cshtml | 2 +- Yavsc/project.json | 6 ++++- Yavsc/project.lock.json | 4 ++- 8 files changed, 39 insertions(+), 7 deletions(-) delete mode 100644 Yavsc/Avatars/Paul.png delete mode 100644 Yavsc/Avatars/Paul.s.png delete mode 100644 Yavsc/Avatars/Paul.xs.png diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs index 91965303..9fb1dd11 100644 --- a/Yavsc/ApiControllers/PdfEstimateController.cs +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -8,6 +8,7 @@ using Microsoft.AspNet.Razor; namespace Yavsc.ApiControllers { using Models; + using Helpers; [Route("api/pdfestimate"), Authorize] public class PdfEstimateController : Controller @@ -87,5 +88,13 @@ namespace Yavsc.ApiControllers { return ViewComponent("Estimate",new object[] { id, "Pdf" } ); } + + [HttpPost("prosign/{id}")] + public IActionResult ProSign(long id) + { + if (Request.Form.Files.Count!=1) + return new BadRequestResult(); + return Ok (User.ReceiveProSignature(id,Request.Form.Files[0])); + } } } \ No newline at end of file diff --git a/Yavsc/Avatars/Paul.png b/Yavsc/Avatars/Paul.png deleted file mode 100644 index cff89237c12487e8a2b7b04e3bc822eed7855760..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44364 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 diff --git a/Yavsc/Avatars/Paul.s.png b/Yavsc/Avatars/Paul.s.png deleted file mode 100644 index 89b956bf672f4c8627936baf7dda31bc702093dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11974 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 DSJMyw diff --git a/Yavsc/Helpers/FileSystemHelpers.cs b/Yavsc/Helpers/FileSystemHelpers.cs index cc294e89..27ebac41 100644 --- a/Yavsc/Helpers/FileSystemHelpers.cs +++ b/Yavsc/Helpers/FileSystemHelpers.cs @@ -1,5 +1,6 @@ +using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -101,10 +102,6 @@ namespace Yavsc.Helpers item.FileName = user.UserName + ".png"; var destFileName = Path.Combine(Startup.SiteSetup.UserFiles.Avatars, item.FileName); - ImageProcessor.ImageFactory f = new ImageProcessor.ImageFactory(); - - ImageProcessor.Web.Processors.Resize r = new ImageProcessor.Web.Processors.Resize(); - var fi = new FileInfo(destFileName); if (fi.Exists) item.Overriden = true; Rectangle cropRect = new Rectangle(); @@ -166,5 +163,25 @@ namespace Yavsc.Helpers dir, xsmallname), ImageFormat.Png); } } + + public static FileRecievedInfo ReceiveProSignature(this ClaimsPrincipal user, long estimateId, IFormFile formFile) + { + var item = new FileRecievedInfo(); + item.FileName = $"estimate-prosign-{estimateId}.png"; + var destFileName = Path.Combine(Startup.SiteSetup.UserFiles.Blog, item.FileName); + + var fi = new FileInfo(destFileName); + if (fi.Exists) item.Overriden = true; + + using (var org = formFile.OpenReadStream()) + { + Image i = Image.FromStream(org); + using (Bitmap source = new Bitmap(i)) + { + source.Save(destFileName, ImageFormat.Png); + } + } + throw new NotImplementedException(); + } } } diff --git a/Yavsc/Views/Manage/SetActivity.cshtml b/Yavsc/Views/Manage/SetActivity.cshtml index 0dd745c0..ba11b351 100644 --- a/Yavsc/Views/Manage/SetActivity.cshtml +++ b/Yavsc/Views/Manage/SetActivity.cshtml @@ -101,7 +101,7 @@ } }); }); - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } } +

@ViewData["Title"].

diff --git a/Yavsc/project.json b/Yavsc/project.json index 37ea5b50..d4aeaeb5 100755 --- a/Yavsc/project.json +++ b/Yavsc/project.json @@ -118,7 +118,11 @@ "gen": "Microsoft.Extensions.CodeGeneration" }, "frameworks": { - "dnx451": {} + "dnx451": { + "frameworkAssemblies": { + "System.Drawing": "4.0.0.0" + } + } }, "exclude": [ "wwwroot", diff --git a/Yavsc/project.lock.json b/Yavsc/project.lock.json index adb98b1b..2924b4e0 100644 --- a/Yavsc/project.lock.json +++ b/Yavsc/project.lock.json @@ -11423,6 +11423,8 @@ "Microsoft.AspNet.OWin >= 1.0.0-rc1-final", "System.Json >= 4.0.20126.16343" ], - "DNX,Version=v4.5.1": [] + "DNX,Version=v4.5.1": [ + "fx/System.Drawing >= 4.0.0" + ] } } \ No newline at end of file From 0e46342cb11f70087f077a54c042aee051a1df4a Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Fri, 2 Dec 2016 11:57:19 +0100 Subject: [PATCH 002/100] refactoring authorizations --- Yavsc/ApiControllers/PdfEstimateController.cs | 31 ------------------- Yavsc/Controllers/BlogspotController.cs | 1 + Yavsc/Startup/Startup.cs | 1 + .../ViewModels/Auth/AuthorisationHandlers.cs | 26 ++-------------- Yavsc/ViewModels/Auth/BlogViewHandler.cs | 21 +++++++++++++ Yavsc/ViewModels/Auth/EditRequirement.cs | 11 +++++++ Yavsc/ViewModels/Auth/EstimateViewHandler.cs | 26 ++++++++++++++++ .../Auth/PrivateChatEntryRequirement.cs | 8 +++++ Yavsc/Views/Shared/_Layout.cshtml | 3 +- 9 files changed, 71 insertions(+), 57 deletions(-) create mode 100644 Yavsc/ViewModels/Auth/BlogViewHandler.cs create mode 100644 Yavsc/ViewModels/Auth/EditRequirement.cs create mode 100644 Yavsc/ViewModels/Auth/EstimateViewHandler.cs create mode 100644 Yavsc/ViewModels/Auth/PrivateChatEntryRequirement.cs diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs index 9fb1dd11..cba15c99 100644 --- a/Yavsc/ApiControllers/PdfEstimateController.cs +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -3,7 +3,6 @@ using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Mvc; using System.Web.Routing; using Microsoft.AspNet.Mvc.ViewComponents; -using Microsoft.AspNet.Razor; namespace Yavsc.ApiControllers { @@ -14,13 +13,6 @@ namespace Yavsc.ApiControllers public class PdfEstimateController : Controller { ApplicationDbContext dbContext; - DefaultViewComponentHelper helper; - IViewComponentDescriptorCollectionProvider provider; - IViewComponentInvokerFactory factory; - RazorEngineHost host; - RazorTemplateEngine engine; - IViewComponentSelector selector; - public PdfEstimateController( IViewComponentDescriptorCollectionProvider provider, @@ -29,30 +21,7 @@ namespace Yavsc.ApiControllers ApplicationDbContext context) { - this.selector = selector; - this.provider = provider; - this.factory = factory; - helper = new DefaultViewComponentHelper(provider, selector, factory); dbContext = context; - - var language = new CSharpRazorCodeLanguage(); - host = new RazorEngineHost(language) - { - DefaultBaseClass = "RazorPage", - DefaultClassName = "Estimate", - DefaultNamespace = "Yavsc", - }; - - // Everyone needs the System namespace, right? - host.NamespaceImports.Add("System"); - engine = new RazorTemplateEngine(host); - - - /* - GeneratorResults razorResult = - engine.GenerateCode( - - ) */ } diff --git a/Yavsc/Controllers/BlogspotController.cs b/Yavsc/Controllers/BlogspotController.cs index 32e2beb7..b6d21470 100644 --- a/Yavsc/Controllers/BlogspotController.cs +++ b/Yavsc/Controllers/BlogspotController.cs @@ -10,6 +10,7 @@ using Microsoft.AspNet.Authorization; using Microsoft.Data.Entity; using Microsoft.Extensions.OptionsModel; using Yavsc.Models; +using Yavsc.ViewModels.Auth; // For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index 9a4638fb..ef727716 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -26,6 +26,7 @@ using Microsoft.Net.Http.Headers; using Yavsc.Formatters; using Yavsc.Models; using Yavsc.Services; +using Yavsc.ViewModels.Auth; namespace Yavsc { diff --git a/Yavsc/ViewModels/Auth/AuthorisationHandlers.cs b/Yavsc/ViewModels/Auth/AuthorisationHandlers.cs index 05e5b0b0..6960ac01 100644 --- a/Yavsc/ViewModels/Auth/AuthorisationHandlers.cs +++ b/Yavsc/ViewModels/Auth/AuthorisationHandlers.cs @@ -4,18 +4,9 @@ using System.Security.Claims; using Microsoft.AspNet.Authorization; using Yavsc.Models; using Yavsc.Models.Booking; +using Yavsc.ViewModels.Auth; namespace Yavsc { - public class PrivateChatEntryRequirement : IAuthorizationRequirement - { - } - - public class EditRequirement : IAuthorizationRequirement - { - public EditRequirement() - { - } - } public class FileSpotInfo : IAuthorizationRequirement { @@ -63,20 +54,7 @@ namespace Yavsc { } -public class BlogViewHandler : AuthorizationHandler - { - protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Blog resource) - { - if (context.User.IsInRole("Moderator")) - context.Succeed(requirement); - else if (context.User.Identity.IsAuthenticated) - if (resource.AuthorId == context.User.GetUserId()) - context.Succeed(requirement); - else if (resource.Visible) - // TODO && ( resource.Circles == null || context.User belongs to resource.Circles ) - context.Succeed(requirement); - } - } + public class CommandViewHandler : AuthorizationHandler { diff --git a/Yavsc/ViewModels/Auth/BlogViewHandler.cs b/Yavsc/ViewModels/Auth/BlogViewHandler.cs new file mode 100644 index 00000000..da4a3a6c --- /dev/null +++ b/Yavsc/ViewModels/Auth/BlogViewHandler.cs @@ -0,0 +1,21 @@ +using System.Security.Claims; +using Microsoft.AspNet.Authorization; +using Yavsc.Models; + +namespace Yavsc.ViewModels.Auth +{ + public class BlogViewHandler : AuthorizationHandler + { + protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Blog resource) + { + if (context.User.IsInRole("Moderator")) + context.Succeed(requirement); + else if (context.User.Identity.IsAuthenticated) + if (resource.AuthorId == context.User.GetUserId()) + context.Succeed(requirement); + else if (resource.Visible) + // TODO && ( resource.Circles == null || context.User belongs to resource.Circles ) + context.Succeed(requirement); + } + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Auth/EditRequirement.cs b/Yavsc/ViewModels/Auth/EditRequirement.cs new file mode 100644 index 00000000..40e0e5f5 --- /dev/null +++ b/Yavsc/ViewModels/Auth/EditRequirement.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNet.Authorization; + +namespace Yavsc.ViewModels.Auth +{ + public class EditRequirement : IAuthorizationRequirement + { + public EditRequirement() + { + } + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Auth/EstimateViewHandler.cs b/Yavsc/ViewModels/Auth/EstimateViewHandler.cs new file mode 100644 index 00000000..b4a8dd84 --- /dev/null +++ b/Yavsc/ViewModels/Auth/EstimateViewHandler.cs @@ -0,0 +1,26 @@ +using System.Security.Claims; +using Microsoft.AspNet.Authorization; +using Yavsc.Models.Billing; + +namespace Yavsc.ViewModels.Auth +{ + public class EstimateViewHandler : AuthorizationHandler + { + protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Estimate resource) + { + if (context.User.IsInRole("Moderator")) + context.Succeed(requirement); + else if (!context.User.Identity.IsAuthenticated) + context.Fail(); + else { + var uid = context.User.GetUserId(); + + if (resource.OwnerId == uid || resource.Query.ClientId == uid) + context.Succeed(requirement); + else + // TODO && ( resource.Circles == null || context.User belongs to resource.Circles ) + context.Fail(); + } + } + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Auth/PrivateChatEntryRequirement.cs b/Yavsc/ViewModels/Auth/PrivateChatEntryRequirement.cs new file mode 100644 index 00000000..c3c5f92a --- /dev/null +++ b/Yavsc/ViewModels/Auth/PrivateChatEntryRequirement.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNet.Authorization; + +namespace Yavsc.ViewModels.Auth +{ + public class PrivateChatEntryRequirement : IAuthorizationRequirement + { + } +} \ No newline at end of file diff --git a/Yavsc/Views/Shared/_Layout.cshtml b/Yavsc/Views/Shared/_Layout.cshtml index 9e3e6b35..30634434 100755 --- a/Yavsc/Views/Shared/_Layout.cshtml +++ b/Yavsc/Views/Shared/_Layout.cshtml @@ -21,13 +21,12 @@ - @RenderSection("header", required: false) From d6de99d9a04882ea791658b0b82cbc1872d2662d Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Fri, 2 Dec 2016 13:22:39 +0100 Subject: [PATCH 003/100] estimate view authorization --- Yavsc/ApiControllers/PdfEstimateController.cs | 27 ++++++++++++++----- Yavsc/Controllers/EstimateController.cs | 12 +++++++-- Yavsc/Startup/Startup.cs | 1 + Yavsc/ViewModels/Auth/BlogEditHandler.cs | 19 +++++++++++++ Yavsc/ViewModels/Auth/BlogViewHandler.cs | 3 ++- Yavsc/ViewModels/Auth/EstimateViewHandler.cs | 21 +++++++-------- Yavsc/Views/_ViewImports.cshtml | 16 ++++++----- 7 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 Yavsc/ViewModels/Auth/BlogEditHandler.cs diff --git a/Yavsc/ApiControllers/PdfEstimateController.cs b/Yavsc/ApiControllers/PdfEstimateController.cs index cba15c99..7c940bbc 100644 --- a/Yavsc/ApiControllers/PdfEstimateController.cs +++ b/Yavsc/ApiControllers/PdfEstimateController.cs @@ -2,32 +2,47 @@ using System.IO; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Mvc; using System.Web.Routing; -using Microsoft.AspNet.Mvc.ViewComponents; namespace Yavsc.ApiControllers { using Models; using Helpers; + using System.Linq; + using Microsoft.Data.Entity; + using System.Threading.Tasks; + using Microsoft.Extensions.Logging; [Route("api/pdfestimate"), Authorize] public class PdfEstimateController : Controller { ApplicationDbContext dbContext; + private IAuthorizationService authorizationService; + + private ILogger logger; public PdfEstimateController( - IViewComponentDescriptorCollectionProvider provider, - IViewComponentSelector selector, - IViewComponentInvokerFactory factory, + IAuthorizationService authorizationService, + ILoggerFactory loggerFactory, ApplicationDbContext context) { - + this.authorizationService = authorizationService; dbContext = context; + logger = loggerFactory.CreateLogger(); } [HttpGet("get/{id}", Name = "Get"), Authorize] - public IActionResult Get(long id) + public async Task Get(long id) { + var estimate = dbContext.Estimates.Include( + e=>e.Query + ).FirstOrDefault(e=>e.Id == id); + logger.LogWarning($"#######ESTIMATE OWNER ID {estimate.OwnerId} ########"); + if (!await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())) + { + return new ChallengeResult(); + } + var filename = $"estimate-{id}.pdf"; var cd = new System.Net.Mime.ContentDisposition diff --git a/Yavsc/Controllers/EstimateController.cs b/Yavsc/Controllers/EstimateController.cs index e9aeaefa..f57d3216 100644 --- a/Yavsc/Controllers/EstimateController.cs +++ b/Yavsc/Controllers/EstimateController.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Net.Mime; using System.Security.Claims; +using System.Threading.Tasks; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc; @@ -21,10 +22,13 @@ namespace Yavsc.Controllers private ApplicationDbContext _context; private SiteSettings _site; - public EstimateController(ApplicationDbContext context, IOptions siteSettings) + IAuthorizationService authorizationService; + + public EstimateController(ApplicationDbContext context, IAuthorizationService authorizationService, IOptions siteSettings) { _context = context; _site = siteSettings.Value; + this.authorizationService = authorizationService; } // GET: Estimate @@ -41,7 +45,7 @@ namespace Yavsc.Controllers } // GET: Estimate/Details/5 - public IActionResult Details(long? id) + public async Task Details(long? id) { var uid = User.GetUserId(); if (id == null) @@ -62,6 +66,10 @@ namespace Yavsc.Controllers { return HttpNotFound(); } + if (!await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())) + { + return new ChallengeResult(); + } return View(estimate); } diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index ef727716..e5be5a7c 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -181,6 +181,7 @@ namespace Yavsc services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddMvc(config => { diff --git a/Yavsc/ViewModels/Auth/BlogEditHandler.cs b/Yavsc/ViewModels/Auth/BlogEditHandler.cs new file mode 100644 index 00000000..599d2afa --- /dev/null +++ b/Yavsc/ViewModels/Auth/BlogEditHandler.cs @@ -0,0 +1,19 @@ +using System.Security.Claims; +using Microsoft.AspNet.Authorization; +using Yavsc.Models; + +namespace Yavsc.ViewModels.Auth +{ + public class BlogEditHandler : AuthorizationHandler + { + protected override void Handle(AuthorizationContext context, EditRequirement requirement, Blog resource) + { + if (context.User.IsInRole(Constants.BlogModeratorGroupName)) + context.Succeed(requirement); + else if (context.User.Identity.IsAuthenticated) + if (resource.AuthorId == context.User.GetUserId()) + context.Succeed(requirement); + } + + } +} \ No newline at end of file diff --git a/Yavsc/ViewModels/Auth/BlogViewHandler.cs b/Yavsc/ViewModels/Auth/BlogViewHandler.cs index da4a3a6c..7a3c1dbc 100644 --- a/Yavsc/ViewModels/Auth/BlogViewHandler.cs +++ b/Yavsc/ViewModels/Auth/BlogViewHandler.cs @@ -8,7 +8,8 @@ namespace Yavsc.ViewModels.Auth { protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Blog resource) { - if (context.User.IsInRole("Moderator")) + if (context.User.IsInRole(Constants.BlogModeratorGroupName) + || context.User.IsInRole(Constants.AdminGroupName)) context.Succeed(requirement); else if (context.User.Identity.IsAuthenticated) if (resource.AuthorId == context.User.GetUserId()) diff --git a/Yavsc/ViewModels/Auth/EstimateViewHandler.cs b/Yavsc/ViewModels/Auth/EstimateViewHandler.cs index b4a8dd84..04eecdd9 100644 --- a/Yavsc/ViewModels/Auth/EstimateViewHandler.cs +++ b/Yavsc/ViewModels/Auth/EstimateViewHandler.cs @@ -6,20 +6,17 @@ namespace Yavsc.ViewModels.Auth { public class EstimateViewHandler : AuthorizationHandler { - protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Estimate resource) + protected override void Handle(AuthorizationContext context, ViewRequirement requirement, Estimate resource) { - if (context.User.IsInRole("Moderator")) - context.Succeed(requirement); - else if (!context.User.Identity.IsAuthenticated) - context.Fail(); - else { - var uid = context.User.GetUserId(); - if (resource.OwnerId == uid || resource.Query.ClientId == uid) - context.Succeed(requirement); - else - // TODO && ( resource.Circles == null || context.User belongs to resource.Circles ) - context.Fail(); + if (context.User.IsInRole(Constants.AdminGroupName) + || context.User.IsInRole(Constants.FrontOfficeGroupName)) + context.Succeed(requirement); + else if (context.User.Identity.IsAuthenticated) { + var uid = context.User.GetUserId(); + if (resource.OwnerId == uid || resource.ClientId == uid) + context.Succeed(requirement); + // TODO && ( resource.Circles == null || context.User belongs to resource.Circles ) } } } diff --git a/Yavsc/Views/_ViewImports.cshtml b/Yavsc/Views/_ViewImports.cshtml index d29ca532..513a301a 100755 --- a/Yavsc/Views/_ViewImports.cshtml +++ b/Yavsc/Views/_ViewImports.cshtml @@ -1,3 +1,11 @@ + +@using Microsoft.AspNet.Identity; +@using Microsoft.AspNet.Mvc; +@using Microsoft.Extensions.Localization; +@using Microsoft.AspNet.Mvc.Localization; +@using Microsoft.AspNet.Authorization; +@using Microsoft.Extensions.OptionsModel; +@using System.Web.Optimization; @using Yavsc; @using Yavsc.Models; @using Yavsc.Models.Google; @@ -8,13 +16,7 @@ @using Yavsc.ViewModels.Account; @using Yavsc.ViewModels.Manage; @using Yavsc.ViewModels.Calendar; -@using Microsoft.AspNet.Identity; -@using Microsoft.AspNet.Mvc; -@using Microsoft.Extensions.Localization; -@using Microsoft.AspNet.Mvc.Localization; -@using Microsoft.AspNet.Authorization; -@using Microsoft.Extensions.OptionsModel; -@using System.Web.Optimization; +@using Yavsc.ViewModels.Auth; @inject IViewLocalizer LocString @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" From 28ac2bf4727d9452b3c144967486a12ca9b48b9b Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 3 Dec 2016 00:37:45 +0100 Subject: [PATCH 004/100] Renders the background color property --- BookAStar/BookAStar.Droid/Markdown/MarkdownViewRenderer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BookAStar/BookAStar.Droid/Markdown/MarkdownViewRenderer.cs b/BookAStar/BookAStar.Droid/Markdown/MarkdownViewRenderer.cs index e5680ea7..9480e863 100644 --- a/BookAStar/BookAStar.Droid/Markdown/MarkdownViewRenderer.cs +++ b/BookAStar/BookAStar.Droid/Markdown/MarkdownViewRenderer.cs @@ -55,10 +55,14 @@ namespace BookAStar.Droid { // Subscribe editorTemplate.Model = new Markdown.MarkdownViewModel - { Content = e.NewElement.Markdown, Editable = e.NewElement.Editable }; + { + Content = e.NewElement.Markdown, Editable = e.NewElement.Editable + }; var html = editorTemplate.GenerateString(); EditorView.LoadDataWithBaseURL("file:///android_asset/", html, "text/html", "utf-8", null); + EditorView.SetBackgroundColor(e.NewElement.BackgroundColor.ToAndroid()); + } } From 7917f9db81b587841c31a99fec14b7daed88aa4a Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 3 Dec 2016 00:38:26 +0100 Subject: [PATCH 005/100] more strings --- BookAStar/BookAStar/Strings.resx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/BookAStar/BookAStar/Strings.resx b/BookAStar/BookAStar/Strings.resx index 8d5461a7..c4b023af 100644 --- a/BookAStar/BookAStar/Strings.resx +++ b/BookAStar/BookAStar/Strings.resx @@ -117,9 +117,15 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Annuler la validation + Faire un devis + + Valider le devis sans signer + Editer le devis @@ -137,6 +143,12 @@ Étoile montante + + Signer + + + Signer le devis? + Incontournable @@ -144,6 +156,6 @@ À ne manquer sous aucun prétexte - Voir le devis + Voir les devis validés \ No newline at end of file From 5e180158d33e44d7a28da985604082e7e255b063 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Mon, 5 Dec 2016 05:51:24 +0100 Subject: [PATCH 006/100] =?UTF-8?q?une=20signature=20cot=C3=A9=20serveur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Markdown/MarkdownEditor.cs | 2 +- .../Markdown/MarkdownViewModel.cs | 2 + BookAStar/BookAStar/App.xaml.cs | 2 + .../Behaviors/EditorMaxLengthValidator.cs | 42 +++++++++ .../Behaviors/EmailValidatorBehavior.cs | 31 +------ .../Behaviors/MarkdownViewLengthValidator.Cs | 39 ++++++++ .../BookAStar/Behaviors/MaxLengthValidator.cs | 63 ------------- .../Behaviors/RegexValidatorBehavior.cs | 53 +++++++++++ BookAStar/BookAStar/BookAStar.csproj | 24 ++++- .../BookAStar/Data/ApiCallFailedException.cs | 21 +++++ BookAStar/BookAStar/Data/DataManager.cs | 4 +- BookAStar/BookAStar/Data/EstimateEntity.cs | 62 +++++++++++++ BookAStar/BookAStar/Data/LocalState.cs | 16 ---- .../BookAStar/Data/NonCrUD/RemoteFiles.cs | 7 -- BookAStar/BookAStar/Data/RemoteEntity.cs | 31 ++++--- .../BookAStar/Model/Workflow/Estimate.cs | 9 +- BookAStar/BookAStar/Pages/DocSigning.xaml | 2 +- BookAStar/BookAStar/Pages/DocSigning.xaml.cs | 4 +- .../EstimatePages/EditBillingLinePage.xaml | 4 +- .../Pages/EstimatePages/EditEstimatePage.xaml | 8 +- .../EstimatePages/EditEstimatePage.xaml.cs | 58 ++++++------ .../EstimatePages/EstimateSigningPage.xaml | 80 ++++++++++++++++ .../EstimatePages/EstimateSigningPage.xaml.cs | 84 +++++++++++++++++ .../Pages/EstimatePages/ViewEstimatePage.xaml | 3 - .../Pages/UserProfile/UserProfilePage.xaml.cs | 28 +++++- BookAStar/BookAStar/Strings.Designer.cs | 92 ++++++++++++++++++- BookAStar/BookAStar/Strings.resx | 18 ++++ .../BookAStar/ViewModels/EditingViewModel.cs | 37 +++++++- .../BillingLineViewModel.cs | 30 ++++-- .../EditEstimateViewModel.cs | 16 +++- .../ViewModels/Signing/DocSigningViewModel.cs | 17 ---- .../Signing/EstimateSigningViewModel.cs | 15 +++ BookAStar/BookAStar/Views/MarkdownView.cs | 5 +- 33 files changed, 698 insertions(+), 211 deletions(-) create mode 100644 BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs create mode 100644 BookAStar/BookAStar/Behaviors/MarkdownViewLengthValidator.Cs delete mode 100644 BookAStar/BookAStar/Behaviors/MaxLengthValidator.cs create mode 100644 BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs create mode 100644 BookAStar/BookAStar/Data/ApiCallFailedException.cs create mode 100644 BookAStar/BookAStar/Data/EstimateEntity.cs delete mode 100644 BookAStar/BookAStar/Data/LocalState.cs create mode 100644 BookAStar/BookAStar/Pages/EstimatePages/EstimateSigningPage.xaml create mode 100644 BookAStar/BookAStar/Pages/EstimatePages/EstimateSigningPage.xaml.cs delete mode 100644 BookAStar/BookAStar/ViewModels/Signing/DocSigningViewModel.cs create mode 100644 BookAStar/BookAStar/ViewModels/Signing/EstimateSigningViewModel.cs diff --git a/BookAStar/BookAStar.Droid/Markdown/MarkdownEditor.cs b/BookAStar/BookAStar.Droid/Markdown/MarkdownEditor.cs index 63160726..f6dea44a 100644 --- a/BookAStar/BookAStar.Droid/Markdown/MarkdownEditor.cs +++ b/BookAStar/BookAStar.Droid/Markdown/MarkdownEditor.cs @@ -17,7 +17,7 @@ using System.Linq; using System.Text; -[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorTemplatePreprocessor", "4.2.0.703")] +[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorTemplatePreprocessor", "4.2.1.62")] public partial class MarkdownEditor : MarkdownEditorBase { diff --git a/BookAStar/BookAStar.Droid/Markdown/MarkdownViewModel.cs b/BookAStar/BookAStar.Droid/Markdown/MarkdownViewModel.cs index ef482e8e..5a310f0b 100644 --- a/BookAStar/BookAStar.Droid/Markdown/MarkdownViewModel.cs +++ b/BookAStar/BookAStar.Droid/Markdown/MarkdownViewModel.cs @@ -9,6 +9,7 @@ using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; +using Android.Graphics; namespace BookAStar.Droid.Markdown { @@ -17,6 +18,7 @@ namespace BookAStar.Droid.Markdown protected static MarkdownDeep.Markdown markdown = new MarkdownDeep.Markdown(); public string Content { get; set; } public bool Editable { get; set; } + public string GetHtml() { return markdown.Transform(Content); diff --git a/BookAStar/BookAStar/App.xaml.cs b/BookAStar/BookAStar/App.xaml.cs index c90b1eef..a909593a 100644 --- a/BookAStar/BookAStar/App.xaml.cs +++ b/BookAStar/BookAStar/App.xaml.cs @@ -27,6 +27,7 @@ namespace BookAStar using ViewModels.UserProfile; using Pages.UserProfile; using ViewModels.EstimateAndBilling; + using Pages.EstimatePages; public partial class App : Application // superclass new in 1.3 { @@ -150,6 +151,7 @@ namespace BookAStar ViewFactory.Register(); ViewFactory.Register(); ViewFactory.Register(); + ViewFactory.Register(); ConfigManager = new GenericConfigSettingsMgr(s => MainSettings.AppSettings.GetValueOrDefault(s, MainSettings.SettingsDefault), null); } diff --git a/BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs b/BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs new file mode 100644 index 00000000..d712eb27 --- /dev/null +++ b/BookAStar/BookAStar/Behaviors/EditorMaxLengthValidator.cs @@ -0,0 +1,42 @@ +using System; +using Xamarin.Forms; + +namespace BookAStar.Behaviors +{ + public class EditorMaxLengthValidator : Behavior + { + public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(EditorMaxLengthValidator), 0); + public static readonly BindableProperty MinLengthProperty = BindableProperty.Create("MinLength", typeof(int), typeof(EditorMaxLengthValidator), 0); + + public int MaxLength + { + get { return (int)GetValue(MaxLengthProperty); } + set { SetValue(MaxLengthProperty, value); } + } + public int MinLength + { + get { return (int)GetValue(MinLengthProperty); } + set { SetValue(MinLengthProperty, value); } + } + + protected override void OnAttachedTo(Editor bindable) + { + bindable.TextChanged += bindable_TextChanged; + } + + public bool IsValid { get; set; } + + private void bindable_TextChanged(object sender, TextChangedEventArgs e) + { + IsValid = e.NewTextValue == null? false : ( e.NewTextValue.Length >= MinLength && e.NewTextValue.Length <= MaxLength ) ; + if (!IsValid) if (e.NewTextValue!=null) if (e.NewTextValue.Length > MaxLength) + ((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength); + } + + protected override void OnDetachingFrom(Editor bindable) + { + bindable.TextChanged -= bindable_TextChanged; + } + } + +} diff --git a/BookAStar/BookAStar/Behaviors/EmailValidatorBehavior.cs b/BookAStar/BookAStar/Behaviors/EmailValidatorBehavior.cs index 78371a4a..76765708 100644 --- a/BookAStar/BookAStar/Behaviors/EmailValidatorBehavior.cs +++ b/BookAStar/BookAStar/Behaviors/EmailValidatorBehavior.cs @@ -8,39 +8,14 @@ using Xamarin.Forms; namespace BookAStar.Behaviors { - public class EmailValidatorBehavior : Behavior + public class EmailValidatorBehavior : RegexValidatorBehavior { const string emailRegex = @"^(?("")("".+?(? + { + public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MarkdownViewLengthValidator), 0); + public static readonly BindableProperty MinLengthProperty = BindableProperty.Create("MinLength", typeof(int), typeof(MarkdownViewLengthValidator), 0); + public int MaxLength + { + get { return (int)GetValue(MaxLengthProperty); } + set { SetValue(MaxLengthProperty, value); } + } + public int MinLength + { + get { return (int)GetValue(MinLengthProperty); } + set { SetValue(MinLengthProperty, value); } + } + protected override void OnAttachedTo(MarkdownView bindable) + { + bindable.Modified += bindable_TextChanged; + } + + public bool IsValid { get; set; } + + private void bindable_TextChanged(object sender, TextChangedEventArgs e) + { + IsValid = e.NewTextValue == null ? false : (e.NewTextValue.Length >= MinLength && e.NewTextValue.Length <= MaxLength); + if (!IsValid) if (e.NewTextValue != null) if (e.NewTextValue.Length > MaxLength) + ((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength); + } + + protected override void OnDetachingFrom(MarkdownView bindable) + { + bindable.Modified -= bindable_TextChanged; + } + } +} diff --git a/BookAStar/BookAStar/Behaviors/MaxLengthValidator.cs b/BookAStar/BookAStar/Behaviors/MaxLengthValidator.cs deleted file mode 100644 index b70f5896..00000000 --- a/BookAStar/BookAStar/Behaviors/MaxLengthValidator.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Xamarin.Forms; - -namespace BookAStar.Behaviors -{ - public class EditorMaxLengthValidator : Behavior - { - public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MaxLengthValidator), 0); - - public int MaxLength - { - get { return (int)GetValue(MaxLengthProperty); } - set { SetValue(MaxLengthProperty, value); } - } - - protected override void OnAttachedTo(Editor bindable) - { - bindable.TextChanged += bindable_TextChanged; - } - - public bool IsValid { get; set; } - - private void bindable_TextChanged(object sender, TextChangedEventArgs e) - { - IsValid = e.NewTextValue == null? false : ( e.NewTextValue.Length > 0 && e.NewTextValue.Length <= MaxLength ) ; - if (!IsValid) if (e.NewTextValue!=null) if (e.NewTextValue.Length > MaxLength) - ((Editor)sender).Text = e.NewTextValue.Substring(0, MaxLength); - } - - protected override void OnDetachingFrom(Editor bindable) - { - bindable.TextChanged -= bindable_TextChanged; - } - } - public class MaxLengthValidator : Behavior - { - public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create("MaxLength", typeof(int), typeof(MaxLengthValidator), 0); - - public int MaxLength - { - get { return (int)GetValue(MaxLengthProperty); } - set { SetValue(MaxLengthProperty, value); } - } - - protected override void OnAttachedTo(Entry bindable) - { - bindable.TextChanged += bindable_TextChanged; - } - - private void bindable_TextChanged(object sender, TextChangedEventArgs e) - { - //if (MaxLength != null && MaxLength.HasValue) - if (e.NewTextValue.Length > MaxLength) - ((Entry)sender).Text = e.NewTextValue.Substring(0, MaxLength); - } - - protected override void OnDetachingFrom(Entry bindable) - { - bindable.TextChanged -= bindable_TextChanged; - - } - - } -} diff --git a/BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs b/BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs new file mode 100644 index 00000000..9b06ec05 --- /dev/null +++ b/BookAStar/BookAStar/Behaviors/RegexValidatorBehavior.cs @@ -0,0 +1,53 @@ +using System; +using System.Text.RegularExpressions; +using Xamarin.Forms; + +namespace BookAStar.Behaviors +{ + public class RegexValidatorBehavior : Behavior + { + private string regexp = @"^([\d\w]+)$"; + // Creating BindableProperties with Limited write access: http://iosapi.xamarin.com/index.aspx?link=M%3AXamarin.Forms.BindableObject.SetValue(Xamarin.Forms.BindablePropertyKey%2CSystem.Object) + + static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(RegexValidatorBehavior), false); + + public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty; + + public bool IsValid + { + get { return (bool)base.GetValue(IsValidProperty); } + private set { base.SetValue(IsValidPropertyKey, value); } + } + + protected string Regexp + { + get + { + return regexp; + } + + set + { + regexp = value; + } + } + + protected override void OnAttachedTo(Entry bindable) + { + bindable.TextChanged += HandleTextChanged; + } + + + void HandleTextChanged(object sender, TextChangedEventArgs e) + { + IsValid = (Regex.IsMatch(e.NewTextValue, regexp, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250))); + ((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red; + } + + protected override void OnDetachingFrom(Entry bindable) + { + bindable.TextChanged -= HandleTextChanged; + + } + } +} diff --git a/BookAStar/BookAStar/BookAStar.csproj b/BookAStar/BookAStar/BookAStar.csproj index 86ee64c2..8aa906b8 100644 --- a/BookAStar/BookAStar/BookAStar.csproj +++ b/BookAStar/BookAStar/BookAStar.csproj @@ -44,14 +44,17 @@ - + + + - + + @@ -59,6 +62,9 @@ + + EstimateSigningPage.xaml + EstimatesClientPage.xaml @@ -89,7 +95,7 @@ DocSigning.xaml - + @@ -272,6 +278,12 @@ ..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll + + ..\..\packages\Xam.Plugin.Media.2.3.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Plugin.Media.dll + + + ..\..\packages\Xam.Plugin.Media.2.3.0\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Plugin.Media.Abstractions.dll + ..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.dll True @@ -478,6 +490,12 @@ Designer + + + MSBuild:UpdateDesignTimeXaml + Designer + + diff --git a/BookAStar/BookAStar/Data/ApiCallFailedException.cs b/BookAStar/BookAStar/Data/ApiCallFailedException.cs new file mode 100644 index 00000000..aca74183 --- /dev/null +++ b/BookAStar/BookAStar/Data/ApiCallFailedException.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BookAStar.Data +{ + class ApiCallFailedException : Exception + { + public ApiCallFailedException(string message) : base(message) + { + + } + + public ApiCallFailedException(string message, Exception inner) : base(message, inner) + { + + } + } +} diff --git a/BookAStar/BookAStar/Data/DataManager.cs b/BookAStar/BookAStar/Data/DataManager.cs index 84e08776..68d076f4 100644 --- a/BookAStar/BookAStar/Data/DataManager.cs +++ b/BookAStar/BookAStar/Data/DataManager.cs @@ -13,7 +13,7 @@ { // TODO estimatetemplate rating service product tag public RemoteEntityRO BookQueries { get; set; } - public RemoteEntity Estimates { get; set; } + public EstimateEntity Estimates { get; set; } public RemoteEntity Blogspot { get; set; } internal RemoteFilesEntity RemoteFiles { get; set; } @@ -41,7 +41,7 @@ public DataManager() { BookQueries = new RemoteEntityRO("bookquery", q => q.Id); - Estimates = new RemoteEntity("estimate", x => x.Id); + Estimates = new EstimateEntity(); Blogspot = new RemoteEntity("blog", x=>x.Id); Contacts = new LocalEntity(c => c.UserId); diff --git a/BookAStar/BookAStar/Data/EstimateEntity.cs b/BookAStar/BookAStar/Data/EstimateEntity.cs new file mode 100644 index 00000000..6504478c --- /dev/null +++ b/BookAStar/BookAStar/Data/EstimateEntity.cs @@ -0,0 +1,62 @@ + +namespace BookAStar.Data +{ + using Helpers; + using Model.Workflow; + using Newtonsoft.Json; + using System; + using System.Diagnostics; + using System.IO; + using System.Net.Http; + + public class EstimateEntity : RemoteEntity + { + public EstimateEntity() : base("estimate", e => e.Id) + { + } + + public async void SignAsProvider(Estimate estimate, Stream pngStream) + { + + if (estimate.Id == 0) + { + var ok = await this.Create(estimate); + if (!ok) + { + await App.DisplayAlert("Erreur d'accès au serveur", "Echec de l'envoi de l'estimation"); + return; + } + this.Add(estimate); + } + using (HttpClient client = UserHelpers.CreateClient()) + { + try + { + var requestContent = new MultipartFormDataContent(); + var content = new StreamContent(pngStream); + var filename = $"prosign-{estimate.Id}.png"; + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); + content.Headers.Add("Content-Disposition", $"form-data; name=\"file\"; filename=\"{filename}\""); + requestContent.Add(content, "file", filename); + using (var response = await client.PostAsync( + Constants.YavscApiUrl + $"/pdfestimate/prosign/{estimate.Id}", requestContent)) + { + if (!response.IsSuccessStatusCode) + { + var errContent = await response.Content.ReadAsStringAsync(); + throw new ApiCallFailedException($"SignAsProvider: {response.StatusCode} / {errContent}"); + } + var json = await response.Content.ReadAsStringAsync(); + JsonConvert.PopulateObject(json, estimate); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + this.SaveEntity(); + } + + } +} diff --git a/BookAStar/BookAStar/Data/LocalState.cs b/BookAStar/BookAStar/Data/LocalState.cs deleted file mode 100644 index bdb82ae7..00000000 --- a/BookAStar/BookAStar/Data/LocalState.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BookAStar.Data -{ - public enum LocalState - { - UpToDate = 0, - New, - Edited, - Removed - } -} diff --git a/BookAStar/BookAStar/Data/NonCrUD/RemoteFiles.cs b/BookAStar/BookAStar/Data/NonCrUD/RemoteFiles.cs index aa7e6eaa..be0fe1db 100644 --- a/BookAStar/BookAStar/Data/NonCrUD/RemoteFiles.cs +++ b/BookAStar/BookAStar/Data/NonCrUD/RemoteFiles.cs @@ -6,13 +6,6 @@ namespace BookAStar.Data.NonCrUD { using Helpers; using Model.FileSystem; - using System.Linq; - /* - public class DirectoryEntryChangingEvent : EventArgs - { - public UserDirectoryInfo OldItem { get; set; } - public UserDirectoryInfo NewItem { get; set; } - }*/ public class RemoteFilesEntity : RemoteEntity { diff --git a/BookAStar/BookAStar/Data/RemoteEntity.cs b/BookAStar/BookAStar/Data/RemoteEntity.cs index 3a4b8b62..edc962df 100644 --- a/BookAStar/BookAStar/Data/RemoteEntity.cs +++ b/BookAStar/BookAStar/Data/RemoteEntity.cs @@ -22,7 +22,7 @@ namespace BookAStar.Data public bool CanExecute(object parameter) { - return !IsExecuting && (MainSettings.CurrentUser != null); + return !IsExecuting; } public RemoteEntity(string controllerName, Func getKey) : base(getKey) @@ -36,7 +36,7 @@ namespace BookAStar.Data protected void BeforeExecute() { if (IsExecuting) - throw new InvalidOperationException("Already executing"); + throw new InvalidOperationException(Strings.AlreadyExecuting); IsExecuting = true; if (CanExecuteChanged != null) CanExecuteChanged.Invoke(this, new EventArgs()); @@ -71,7 +71,7 @@ namespace BookAStar.Data } catch (WebException webex) { - throw new ServiceNotAvailable("No remote entity", webex); + throw new ServiceNotAvailable(Strings.ENoRemoteEntity, webex); } } @@ -123,23 +123,27 @@ namespace BookAStar.Data return item; } - public virtual async void Create(V item) + public virtual async Task Create(V item) { + bool created = false; BeforeExecute(); using (HttpClient client = UserHelpers.CreateClient()) { var stringContent = JsonConvert.SerializeObject(item); + HttpContent content = new StringContent( stringContent, Encoding.UTF8, "application/json" ); using (var response = await client.PostAsync(ControllerUri, content)) { - if (!response.IsSuccessStatusCode) + created = response.IsSuccessStatusCode; + if (!created) { // TODO throw custom exception, and catch to inform user var errcontent = await response.Content.ReadAsStringAsync(); - Debug.WriteLine($"Create failed posting {stringContent} @ {ControllerUri.AbsoluteUri}: {errcontent}"); + Debug.WriteLine(string.Format(Strings.CreationFailed)); + Debug.WriteLine(errcontent); } else { @@ -148,14 +152,15 @@ namespace BookAStar.Data JsonConvert.PopulateObject(recontent, item); } } - } CurrentItem = item; AfterExecuting(); + return created; } - public virtual async void Update(V item) + public virtual async Task Update(V item) { + var updated = false; BeforeExecute(); var uri = GetUri(GetKey(item)); @@ -166,13 +171,16 @@ namespace BookAStar.Data ); using (var response = await client.PutAsync(uri, content)) { - if (!response.IsSuccessStatusCode) + updated = response.IsSuccessStatusCode; + if (!updated) {// TODO throw custom exception, and catch to inform user if (response.StatusCode == HttpStatusCode.BadRequest) { - var recontent = await response.Content.ReadAsStringAsync(); + var errorcontent = await response.Content.ReadAsStringAsync(); + Debug.WriteLine(string.Format(Strings.UpdateFailed)); + Debug.WriteLine(errorcontent); + } - else Debug.WriteLine($"Update failed ({item} @ {uri.AbsolutePath} )"); } @@ -188,6 +196,7 @@ namespace BookAStar.Data CurrentItem = item; AfterExecuting(); + return updated; } public virtual async void Delete(K key) diff --git a/BookAStar/BookAStar/Model/Workflow/Estimate.cs b/BookAStar/BookAStar/Model/Workflow/Estimate.cs index 586c8185..2640e744 100644 --- a/BookAStar/BookAStar/Model/Workflow/Estimate.cs +++ b/BookAStar/BookAStar/Model/Workflow/Estimate.cs @@ -77,9 +77,14 @@ namespace BookAStar.Model.Workflow return Bill?.Aggregate((decimal)0, (t, l) => t + l.Count * l.UnitaryCost) ?? (decimal)0; } } - - public DateTime LatestValidationDate { get; set; } + /// + /// This validation comes from the provider. + /// As long as it's an estimate, no client validation + /// is formaly needed + /// + public DateTime ProviderValidationDate { get; set; } public DateTime ClientApprouvalDate { get; set; } + } } diff --git a/BookAStar/BookAStar/Pages/DocSigning.xaml b/BookAStar/BookAStar/Pages/DocSigning.xaml index fe1dec3e..284d5707 100644 --- a/BookAStar/BookAStar/Pages/DocSigning.xaml +++ b/BookAStar/BookAStar/Pages/DocSigning.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms" xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar" - x:Class="BookAStar.ViewModels.Signing.DocSigning"> + x:Class="BookAStar.ViewModels.Signing.Signing"> - + - + diff --git a/BookAStar/BookAStar/Pages/EstimatePages/EditEstimatePage.xaml b/BookAStar/BookAStar/Pages/EstimatePages/EditEstimatePage.xaml index 4dbb56b3..955ef2e7 100644 --- a/BookAStar/BookAStar/Pages/EstimatePages/EditEstimatePage.xaml +++ b/BookAStar/BookAStar/Pages/EstimatePages/EditEstimatePage.xaml @@ -4,6 +4,7 @@ x:Class="BookAStar.Pages.EditEstimatePage" xmlns:views="clr-namespace:BookAStar.Views;assembly=BookAStar" xmlns:local="clr-namespace:BookAStar;assembly=BookAStar" + xmlns:behaviors="clr-namespace:BookAStar.Behaviors;assembly=BookAStar" Style="{StaticResource PageStyle}"> @@ -36,7 +37,12 @@ Editable="True" HorizontalOptions="FillAndExpand" Markdown="{Binding Description, Mode=TwoWay}" - VerticalOptions="Start" /> + VerticalOptions="Start" > + + + + + { - bill.Add(com); + bill.Add(new BillingLineViewModel(com)); DataManager.Current.EstimationCache.SaveEntity(); })}; - lineView.PropertyChanged += LineView_PropertyChanged; App.NavigationService.NavigateTo( true, lineView ); } protected void OnEditLine(object sender, ItemTappedEventArgs e) { - var line = (BillingLine)e.Item; - var bill = ((EditEstimateViewModel)BindingContext).Bill; - var lineView = new BillingLineViewModel(line) + var line = (BillingLineViewModel)e.Item; + line.ValidateCommand = new Command(() => { - ValidateCommand = new Command(() => { - DataManager.Current.EstimationCache.SaveEntity(); - }) - }; - lineView.PropertyChanged += LineView_PropertyChanged; + DataManager.Current.EstimationCache.SaveEntity(); + }); - lineView.PropertyChanged += LineView_PropertyChanged; App.NavigationService.NavigateTo( - true, lineView ); + true, line ); } - - private void LineView_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + protected async void OnEstimateValidated(object sender, EventArgs e) { - DataManager.Current.EstimationCache.SaveEntity(); - } - - protected void OnEstimateValidated(object sender, EventArgs e) - { - var evm = (EditEstimateViewModel)BindingContext; - if (evm.Data.Id == 0) + var thisPage = this; + var evm = (EditEstimateViewModel) BindingContext; + var cmd = new Command( async (validated) => { - DataManager.Current.Estimates.Create(evm.Data); - // we have to manually add this item in our local collection, - // since we could prefer to update the whole collection - // from server, or whatever other scenario - DataManager.Current.Estimates.Add(evm.Data); - } else + if (validated) { + DataManager.Current.EstimationCache.Remove(evm); + DataManager.Current.EstimationCache.SaveEntity(); + } + await thisPage.Navigation.PopAsync(); + }); + var response = await App.DisplayActionSheet(Strings.SignOrNot, Strings.DonotsignEstimate, Strings.CancelValidation, new string[] { Strings.Sign }); + if (response == Strings.Sign) { - DataManager.Current.Estimates.Update(evm.Data); + App.NavigationService.NavigateTo(true, + new EstimateSigningViewModel(evm.Data) { ValidationCommand = cmd }); } - DataManager.Current.Estimates.SaveEntity(); - DataManager.Current.EstimationCache.Remove(evm); - DataManager.Current.EstimationCache.SaveEntity(); - Navigation.PopAsync(); + else if (response == Strings.CancelValidation) + return; + else cmd.Execute(true); + } } } diff --git a/BookAStar/BookAStar/Pages/EstimatePages/EstimateSigningPage.xaml b/BookAStar/BookAStar/Pages/EstimatePages/EstimateSigningPage.xaml new file mode 100644 index 00000000..65faecfb --- /dev/null +++ b/BookAStar/BookAStar/Pages/EstimatePages/EstimateSigningPage.xaml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +