From 6c18f32f613ac179cf015ece897fdbfc9602682a Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 3 Feb 2018 20:17:29 +0100 Subject: [PATCH] refactoring messages --- Makefile | 11 +++ YaDaemon/TestDaemonStart.cs | 1 - Yavsc.Abstract/Makefile | 2 +- Yavsc.Abstract/Messaging/Topics.cs | 9 ++ Yavsc.Abstract/Properties/AssemblyInfo.cs | 2 +- Yavsc.Abstract/Workflow/IEvent.cs | 7 +- Yavsc.Abstract/Workflow/ILocation.cs | 2 +- Yavsc.Abstract/Yavsc.Abstract.1.0.5-rc4.nupkg | Bin 12883 -> 13026 bytes Yavsc.Abstract/Yavsc.Abstract.1.0.5-rc5.nupkg | Bin 0 -> 13031 bytes Yavsc.Abstract/Yavsc.Abstract.nuspec | 2 +- Yavsc/ApiControllers/EstimateApiController.cs | 6 +- Yavsc/Controllers/BlogspotController.cs | 24 +++--- Yavsc/Controllers/CommandController.cs | 5 +- Yavsc/Controllers/GCMDevicesController.cs | 78 ++++++++++++++++++ .../Haircut/HairCutCommandController.cs | 73 +++++----------- Yavsc/Controllers/HomeController.cs | 2 +- Yavsc/Controllers/ManageController.cs | 5 +- Yavsc/Helpers/EventHelpers.cs | 29 +------ Yavsc/Helpers/GoogleHelpers.cs | 66 ++++----------- Yavsc/Models/Billing/Estimate.cs | 1 - Yavsc/Models/Calendar/ProvidedEvent.cs | 9 +- Yavsc/Models/HairCut/HairCutPaymentEvent.cs | 76 +++++++++++++++++ Yavsc/Models/HairCut/HairCutQuery.cs | 14 +++- Yavsc/Models/HairCut/HairCutQueryEvent.cs | 16 ++-- Yavsc/Models/Messaging/Announce.cs | 10 ++- Yavsc/Models/Messaging/BaseEvent.cs | 5 +- Yavsc/Models/Messaging/CircleEvent.cs | 9 +- Yavsc/Models/Messaging/EstimationEvent.cs | 17 ++-- Yavsc/Models/Messaging/GeneralEvent.cs | 43 ---------- Yavsc/Models/Messaging/RdvQueryEvent.cs | 23 ++++-- Yavsc/Models/Messaging/YaEvent.cs | 48 ----------- Yavsc/Models/Relationship/Location.cs | 2 +- .../Yavsc.Resources.YavscLocalisation.fr.resx | 23 ++++++ Yavsc/Services/IGoogleCloudMessageSender.cs | 7 +- Yavsc/Services/MessageServices.cs | 70 ++++++++++++++-- Yavsc/Startup/Startup.SanityChecks.cs | 9 +- .../Views/Command/CommandConfirmation.cshtml | 8 +- Yavsc/Views/GCMDevices/Delete.cshtml | 52 ++++++++++++ Yavsc/Views/GCMDevices/Details.cshtml | 48 +++++++++++ Yavsc/Views/GCMDevices/Index.cshtml | 52 ++++++++++++ Yavsc/Views/_ViewImports.cshtml | 1 + test/UnitTest1.cs | 19 +++++ test/global.json | 12 +-- test/packages.config | 7 ++ 44 files changed, 602 insertions(+), 303 deletions(-) create mode 100644 Makefile create mode 100644 Yavsc.Abstract/Messaging/Topics.cs create mode 100644 Yavsc.Abstract/Yavsc.Abstract.1.0.5-rc5.nupkg create mode 100644 Yavsc/Controllers/GCMDevicesController.cs create mode 100644 Yavsc/Models/HairCut/HairCutPaymentEvent.cs delete mode 100644 Yavsc/Models/Messaging/GeneralEvent.cs delete mode 100644 Yavsc/Models/Messaging/YaEvent.cs create mode 100644 Yavsc/Views/GCMDevices/Delete.cshtml create mode 100644 Yavsc/Views/GCMDevices/Details.cshtml create mode 100644 Yavsc/Views/GCMDevices/Index.cshtml create mode 100644 test/packages.config diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2c609879 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +MAKE=make +SUBDIRS=Yavsc.Abstract Yavsc + +all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +.PHONY: all $(SUBDIRS) + diff --git a/YaDaemon/TestDaemonStart.cs b/YaDaemon/TestDaemonStart.cs index cb5261b5..e062338d 100644 --- a/YaDaemon/TestDaemonStart.cs +++ b/YaDaemon/TestDaemonStart.cs @@ -1,6 +1,5 @@ namespace YaDaemon { - using YaDaemon; public class TestDaemonStart { diff --git a/Yavsc.Abstract/Makefile b/Yavsc.Abstract/Makefile index 60311884..72f14d69 100644 --- a/Yavsc.Abstract/Makefile +++ b/Yavsc.Abstract/Makefile @@ -1,5 +1,5 @@ CONFIG=Release -VERSION=1.0.5-rc4 +VERSION=1.0.5-rc5 PRJNAME=Yavsc.Abstract PKGFILENAME=$(PRJNAME).$(VERSION).nupkg DESTPATH=. diff --git a/Yavsc.Abstract/Messaging/Topics.cs b/Yavsc.Abstract/Messaging/Topics.cs new file mode 100644 index 00000000..ee0ec9b9 --- /dev/null +++ b/Yavsc.Abstract/Messaging/Topics.cs @@ -0,0 +1,9 @@ +namespace Yavsc.Abstract.Messaging +{ + public static class MessagingConstants { + public static readonly string TopicGeneral = "/topic/general"; + public static readonly string TopicRdvQuery = "/topic/RdvQuery"; + public static readonly string TopicEstimation = "/topic/Estimation"; + public static readonly string TopicHairCutQuery = "/topic/HairCutQuery"; + } +} \ No newline at end of file diff --git a/Yavsc.Abstract/Properties/AssemblyInfo.cs b/Yavsc.Abstract/Properties/AssemblyInfo.cs index 616e1b27..1bde8739 100644 --- a/Yavsc.Abstract/Properties/AssemblyInfo.cs +++ b/Yavsc.Abstract/Properties/AssemblyInfo.cs @@ -25,4 +25,4 @@ using System.Reflection; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.5.*")] -[assembly: AssemblyFileVersion("1.0.5.2")] +[assembly: AssemblyFileVersion("1.0.5.3")] diff --git a/Yavsc.Abstract/Workflow/IEvent.cs b/Yavsc.Abstract/Workflow/IEvent.cs index 4e6cf601..8471c1ce 100644 --- a/Yavsc.Abstract/Workflow/IEvent.cs +++ b/Yavsc.Abstract/Workflow/IEvent.cs @@ -11,11 +11,8 @@ namespace Yavsc.Interfaces.Workflow { /// /// string Sender { get; set ; } - /// - /// The message - /// - /// - string Message { get; set; } + + string CreateBody(); } diff --git a/Yavsc.Abstract/Workflow/ILocation.cs b/Yavsc.Abstract/Workflow/ILocation.cs index 926b56bd..797bc9ca 100644 --- a/Yavsc.Abstract/Workflow/ILocation.cs +++ b/Yavsc.Abstract/Workflow/ILocation.cs @@ -1,6 +1,6 @@ namespace Yavsc { - public interface ILocation + public interface ILocation : IPosition { string Address { get; set; } long Id { get; set; } diff --git a/Yavsc.Abstract/Yavsc.Abstract.1.0.5-rc4.nupkg b/Yavsc.Abstract/Yavsc.Abstract.1.0.5-rc4.nupkg index 8e0062fa848ed140c90f28673020fc8896c2d172..03f8a953e496d8c3bea6862a53a15fdc94e650a3 100644 GIT binary patch delta 11432 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 D0X28f delta 11287 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 H|Aqbodie|} literal 0 HcmV?d00001 diff --git a/Yavsc.Abstract/Yavsc.Abstract.nuspec b/Yavsc.Abstract/Yavsc.Abstract.nuspec index feb13a19..3a1af260 100644 --- a/Yavsc.Abstract/Yavsc.Abstract.nuspec +++ b/Yavsc.Abstract/Yavsc.Abstract.nuspec @@ -11,7 +11,7 @@ https://github.com/pazof/yavsc/blob/vnext/Yavsc/wwwroot/images/yavsc.png true - A shared model for a little client/sever app + A shared model for a little client/server app, dealing about establishing some contract, between some human client and provider. diff --git a/Yavsc/ApiControllers/EstimateApiController.cs b/Yavsc/ApiControllers/EstimateApiController.cs index c9f90276..2d16be4b 100644 --- a/Yavsc/ApiControllers/EstimateApiController.cs +++ b/Yavsc/ApiControllers/EstimateApiController.cs @@ -114,14 +114,16 @@ namespace Yavsc.Controllers public IActionResult PostEstimate([FromBody] Estimate estimate) { var uid = User.GetUserId(); - if (!User.IsInRole(Constants.AdminGroupName)) - { + if (estimate.OwnerId==null) estimate.OwnerId = uid; + + if (!User.IsInRole(Constants.AdminGroupName)) { if (uid != estimate.OwnerId) { ModelState.AddModelError("OwnerId","You can only create your own estimates"); return HttpBadRequest(ModelState); } } + if (estimate.CommandId!=null) { var query = _context.RdvQueries.FirstOrDefault(q => q.Id == estimate.CommandId); if (query == null) { diff --git a/Yavsc/Controllers/BlogspotController.cs b/Yavsc/Controllers/BlogspotController.cs index b788bb86..873c1ff7 100644 --- a/Yavsc/Controllers/BlogspotController.cs +++ b/Yavsc/Controllers/BlogspotController.cs @@ -47,23 +47,25 @@ namespace Yavsc.Controllers long[] usercircles = _context.Circle.Include(c=>c.Members).Where(c=>c.Members.Any(m=>m.MemberId == uid)) .Select(c=>c.Id).ToArray(); IQueryable posts ; - if (usercircles != null) { - posts = _context.Blogspot.Include(b => b.Author) + var allposts = _context.Blogspot + .Include(b => b.Author) + .Include(p=>p.ACL) .Include(p=>p.Tags) .Include(p=>p.Comments) - .Include(p=>p.ACL) - .Where(p=> p.AuthorId == uid || p.Visible && - (p.ACL.Count == 0 || p.ACL.Any(a=> usercircles.Contains(a.CircleId)))) - ; + .Where(p=>p.AuthorId == uid || p.Visible); + + if (usercircles != null) { + posts = allposts.Where(p=> p.ACL.Count==0 || p.ACL.Any(a=> usercircles.Contains(a.CircleId))) + ; } else { - posts = _context.Blogspot.Include(b => b.Author) - .Include(p=>p.ACL).Where(p=>p.AuthorId == uid || p.Visible && p.ACL.Count == 0); + posts = allposts.Where(p => p.ACL.Count == 0); } - return View(posts.OrderByDescending( p=> p.DateCreated) - - .GroupBy(p=> p.Title).Skip(skip).Take(maxLen)); + var data = posts.OrderByDescending( p=> p.DateCreated).ToArray(); + var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(maxLen); + + return View(grouped); } [Route("/Title/{id?}")] diff --git a/Yavsc/Controllers/CommandController.cs b/Yavsc/Controllers/CommandController.cs index 5603c554..d8d20c7a 100644 --- a/Yavsc/Controllers/CommandController.cs +++ b/Yavsc/Controllers/CommandController.cs @@ -174,17 +174,18 @@ namespace Yavsc.Controllers .Devices.Select(d => d.GCMRegistrationId); grep = await _GCMSender.NotifyBookQueryAsync(_googleSettings,regids,yaev); } + // TODO setup a profile choice to allow notifications // both on mailbox and mobile // if (grep==null || grep.success<=0 || grep.failure>0) ViewBag.GooglePayload=grep; - await _emailSender.SendEmailAsync( + ViewBag.EmailSent = await _emailSender.SendEmailAsync( _siteSettings, _smtpSettings, command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.Email, $"{command.Client.UserName} (un client) vous demande un rendez-vous", - $"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" + $"{yaev.CreateBody()}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" ); } ViewBag.Activity = _context.Activities.FirstOrDefault(a=>a.Code == command.ActivityCode); diff --git a/Yavsc/Controllers/GCMDevicesController.cs b/Yavsc/Controllers/GCMDevicesController.cs new file mode 100644 index 00000000..76813e39 --- /dev/null +++ b/Yavsc/Controllers/GCMDevicesController.cs @@ -0,0 +1,78 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; + +using Microsoft.AspNet.Mvc; +using Microsoft.Data.Entity; + + +namespace Yavsc.Controllers +{ + using Models; + using Models.Identity; + + public class GCMDevicesController : Controller + { + private ApplicationDbContext _context; + + public GCMDevicesController(ApplicationDbContext context) + { + _context = context; + } + + // GET: GCMDevices + public async Task Index() + { + var uid = User.GetUserId(); + + var applicationDbContext = _context.GCMDevices.Include(g => g.DeviceOwner).Where(d=>d.DeviceOwnerId == uid); + return View(await applicationDbContext.ToListAsync()); + } + + // GET: GCMDevices/Details/5 + public async Task Details(string id) + { + if (id == null) + { + return HttpNotFound(); + } + + GoogleCloudMobileDeclaration googleCloudMobileDeclaration = await _context.GCMDevices.SingleAsync(m => m.DeviceId == id); + if (googleCloudMobileDeclaration == null) + { + return HttpNotFound(); + } + + return View(googleCloudMobileDeclaration); + } + + // GET: GCMDevices/Delete/5 + [ActionName("Delete")] + public async Task Delete(string id) + { + if (id == null) + { + return HttpNotFound(); + } + + GoogleCloudMobileDeclaration googleCloudMobileDeclaration = await _context.GCMDevices.SingleAsync(m => m.DeviceId == id); + if (googleCloudMobileDeclaration == null) + { + return HttpNotFound(); + } + + return View(googleCloudMobileDeclaration); + } + + // POST: GCMDevices/Delete/5 + [HttpPost, ActionName("Delete")] + [ValidateAntiForgeryToken] + public async Task DeleteConfirmed(string id) + { + GoogleCloudMobileDeclaration googleCloudMobileDeclaration = await _context.GCMDevices.SingleAsync(m => m.DeviceId == id); + _context.GCMDevices.Remove(googleCloudMobileDeclaration); + await _context.SaveChangesAsync(); + return RedirectToAction("Index"); + } + } +} diff --git a/Yavsc/Controllers/Haircut/HairCutCommandController.cs b/Yavsc/Controllers/Haircut/HairCutCommandController.cs index e06378c3..7b14c994 100644 --- a/Yavsc/Controllers/Haircut/HairCutCommandController.cs +++ b/Yavsc/Controllers/Haircut/HairCutCommandController.cs @@ -79,60 +79,30 @@ namespace Yavsc.Controllers ViewData["paymentinfo"] = paymentInfo; command.Regularisation = paymentInfo.DbContent; command.PaymentId = token; - if (paymentInfo != null) - if (paymentInfo.DetailsFromPayPal != null) - if (paymentInfo.DetailsFromPayPal.Ack == AckCodeType.SUCCESS) - if (command.ValidationDate == null) - command.ValidationDate = DateTime.Now; + bool paymentOk = false; + if (paymentInfo.DetailsFromPayPal != null) + if (paymentInfo.DetailsFromPayPal.Ack == AckCodeType.SUCCESS) + { + // FIXME Assert (command.ValidationDate == null) + if (command.ValidationDate == null) { + paymentOk = true; + command.ValidationDate = DateTime.Now; + } + } await _context.SaveChangesAsync(User.GetUserId()); SetViewBagPaymentUrls(id); - if (command.PerformerProfile.AcceptPublicContact) + if (command.PerformerProfile.AcceptPublicContact && paymentOk) { - var invoiceId = paymentInfo.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.InvoiceID; - var payerName = paymentInfo.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Name; - var phone = paymentInfo.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Phone; - var payerEmail = paymentInfo.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Payer; - var amount = string.Join(", ", - paymentInfo.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PaymentDetails.Select( - p => $"{p.OrderTotal.value} {p.OrderTotal.currencyID}")); - var gender = command.Prestation.Gender; - var date = command.EventDate?.ToString("dd MM yyyy hh:mm"); - var lieu = command.Location.Address; - string clientFinal = (gender == HairCutGenders.Women) ? _localizer["Women"] + - " " + _localizer[command.Prestation.Length.ToString()] : _localizer[gender.ToString()]; MessageWithPayloadResponse grep = null; - var yaev = command.CreateEvent("PaymentConfirmation", - this._localizer["PaymentConfirmation"], - command.Client.GetSender(), -$@"# Paiment confirmé: {amount} - -Effectué par : {payerName} [{payerEmail}] -Identifiant PayPal du paiment: {token} -Identifiant PayPal du payeur: {PayerID} -Identifiant de la facture sur site: {invoiceId} - - -# La prestation concernée: - -Demandeur: {command.Client.UserName} - -Date: {date} - -Lieu: {lieu} - -Le client final: {clientFinal} - -{command.GetBillText()} - -"); - + var yaev = command.CreatePaymentEvent(paymentInfo, _localizer); if (command.PerformerProfile.AcceptNotifications) { if (command.PerformerProfile.Performer.Devices.Count > 0) { var regids = command.PerformerProfile.Performer .Devices.Select(d => d.GCMRegistrationId); - grep = await _GCMSender.NotifyHairCutQueryAsync(_googleSettings, regids, yaev); + + grep = await _GCMSender.NotifyAsync(_googleSettings, regids, yaev); } // TODO setup a profile choice to allow notifications // both on mailbox and mobile @@ -144,8 +114,8 @@ Le client final: {clientFinal} _siteSettings, _smtpSettings, command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.Email, - yaev.Reason, - $"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" + yaev.Topic, + yaev.CreateBody() ); } else @@ -321,7 +291,7 @@ Le client final: {clientFinal} DateTime evdate = yaev.EventDate ?? new DateTime(); var result = await _calendarManager.CreateEventAsync(pro.Performer.Id, pro.Performer.DedicatedGoogleCalendar, - evdate, 3600, yaev.Topic, yaev.Message, + evdate, 3600, yaev.Topic, yaev.Client.UserName + " : " + yaev.Reason, yaev.Location?.Address, false ); if (result.Id == null) @@ -333,8 +303,8 @@ Le client final: {clientFinal} _siteSettings, _smtpSettings, pro.Performer.UserName, pro.Performer.Email, - yaev.Reason, - $"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" + $"{yaev.Client.UserName}: {yaev.Reason}", + $"{yaev.Reason}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" ); } else @@ -456,6 +426,7 @@ Le client final: {clientFinal} bp => bp.UserId == command.PerformerId ); var yaev = command.CreateEvent(_localizer, brSettings); + string msg = yaev.CreateBoby(); MessageWithPayloadResponse grep = null; if (pro.AcceptNotifications @@ -481,7 +452,7 @@ Le client final: {clientFinal} await _calendarManager.CreateEventAsync( pro.Performer.Id, pro.Performer.DedicatedGoogleCalendar, - evdate, 3600, yaev.Topic, yaev.Message, + evdate, 3600, yaev.Topic, msg, yaev.Location?.ToString(), false ); } @@ -491,7 +462,7 @@ Le client final: {clientFinal} command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.Email, yaev.Topic + " " + yaev.Sender, - $"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" + $"{msg}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" ); } ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == command.ActivityCode); diff --git a/Yavsc/Controllers/HomeController.cs b/Yavsc/Controllers/HomeController.cs index 615d710a..03104317 100644 --- a/Yavsc/Controllers/HomeController.cs +++ b/Yavsc/Controllers/HomeController.cs @@ -50,7 +50,7 @@ namespace Yavsc.Controllers } else clicked = DbContext.DimissClicked.Where(d=>d.UserId == uid).Select(d=>d.NotificationId).ToArray(); var notes = DbContext.Notification.Where( - n=> !clicked.Any(c=>n.Id==c) + n=> !clicked.Contains(n.Id) ); this.Notify(notes); ViewData["HaircutCommandCount"] = DbContext.HairCutQueries.Where( diff --git a/Yavsc/Controllers/ManageController.cs b/Yavsc/Controllers/ManageController.cs index dd0ad469..3413ff9d 100644 --- a/Yavsc/Controllers/ManageController.cs +++ b/Yavsc/Controllers/ManageController.cs @@ -122,9 +122,10 @@ namespace Yavsc.Controllers EmailConfirmed = await _userManager.IsEmailConfirmedAsync(user) }; model.HaveProfessionalSettings = _dbContext.Performers.Any(x => x.PerformerId == user.Id); - var usrActs = _dbContext.UserActivities.Include(a=>a.Does).Where(a=> a.UserId == user.Id); + var usrActs = _dbContext.UserActivities.Include(a=>a.Does).Where(a=> a.UserId == user.Id).ToArray(); - model.HaveActivityToConfigure = usrActs.Where( a => ( a.Does.SettingsClassName != null )).Count( a => a.Settings == null)>0; + var usrActToSet = usrActs.Where( a => ( a.Settings == null && a.Does.SettingsClassName != null )).ToArray(); + model.HaveActivityToConfigure = usrActToSet .Count()>0; model.Activity = _dbContext.UserActivities.Include(a=>a.Does).Where(u=>u.UserId == user.Id).ToList(); return View(model); } diff --git a/Yavsc/Helpers/EventHelpers.cs b/Yavsc/Helpers/EventHelpers.cs index a011b066..ccc36795 100644 --- a/Yavsc/Helpers/EventHelpers.cs +++ b/Yavsc/Helpers/EventHelpers.cs @@ -15,12 +15,7 @@ namespace Yavsc.Helpers var yaev = new RdvQueryEvent(subtopic) { Sender = query.ClientId, - Message = string.Format(SR["RdvToPerf"], - query.Client.UserName, - query.EventDate.ToString("dddd dd/MM/yyyy à HH:mm"), - query.Location.Address, - query.ActivityCode)+ - "\n"+query.Reason, + Reason = query.Reason, Client = new ClientProviderInfo {  UserName = query.Client.UserName , UserId = query.ClientId, @@ -46,21 +41,7 @@ namespace Yavsc.Helpers var yaev = query.CreateEvent("NewHairCutQuery", string.Format(Startup.GlobalLocalizer["HairCutQueryValidation"],query.Client.UserName), - $"{query.Client.UserName}", -$@"Un client vient de valider une demande de prestation à votre encontre: - - Prestation: {strprestation} - Client : {query.Client.UserName} - Date: {evdate}, - Adresse: {address} - ------ -{query.AdditionalInfo} - -Facture prévue (non réglée): - -{query.GetBillText()} -") ; + $"{query.Client.UserName}") ; return yaev; } @@ -74,11 +55,7 @@ Facture prévue (non réglée): var yaev = new HairCutQueryEvent("newCommand") { Sender = query.ClientId, - Message = string.Format(SR["RdvToPerf"], - query.Client.UserName, - query.EventDate.ToString("dddd dd/MM/yyyy à HH:mm"), - query.Location.Address, - query.ActivityCode), + Client = new ClientProviderInfo {  UserName = query.Client.UserName , UserId = query.ClientId, diff --git a/Yavsc/Helpers/GoogleHelpers.cs b/Yavsc/Helpers/GoogleHelpers.cs index 54aad5ea..83326a7d 100644 --- a/Yavsc/Helpers/GoogleHelpers.cs +++ b/Yavsc/Helpers/GoogleHelpers.cs @@ -23,67 +23,29 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Data.Entity; +using Microsoft.AspNet.Identity.EntityFramework; + +using Google.Apis.Auth.OAuth2; +using Google.Apis.Services; +using Google.Apis.Compute.v1; +using Google.Apis.Auth.OAuth2.Flows; +using Google.Apis.Util.Store; +using Google.Apis.Auth.OAuth2.Responses; +using Google.Apis.Util; + namespace Yavsc.Helpers { - using Models.Google.Messaging; - using Models.Messaging; using Models; - using Interfaces.Workflow; - using Yavsc.Models.Calendar; - using Google.Apis.Auth.OAuth2; - using Microsoft.Data.Entity; - using Microsoft.AspNet.Identity.EntityFramework; - using Yavsc.Services; - using Google.Apis.Services; - using Google.Apis.Compute.v1; - using Google.Apis.Auth.OAuth2.Flows; - using Google.Apis.Util.Store; - using Google.Apis.Auth.OAuth2.Responses; - using Google.Apis.Util; - - - - + using Models.Calendar; + using Services; /// /// Google helpers. /// public static class GoogleHelpers { - public static async Task NotifyEvent - (this GoogleAuthSettings googleSettings, IEnumerable regids, Event ev) - where Event : IEvent - { - if (ev == null) - throw new Exception("Spécifier un évènement"); - if (ev.Message == null) - throw new Exception("Spécifier un message"); - if (ev.Sender == null) - throw new Exception("Spécifier un expéditeur"); - - if (regids == null) - throw new NotImplementedException("Notify & No GCM reg ids"); - - var msg = new MessageWithPayload() - { - notification = new Notification() - { - title = ev.Topic+" "+ev.Sender, - body = ev.Message, - icon = "icon" - }, - data = ev, - registration_ids = regids.ToArray() - }; - try { - using (var m = new SimpleJsonPostMethod("https://gcm-http.googleapis.com/gcm/send",$"key={googleSettings.ApiKey}")) { - return await m.Invoke(msg); - } - } - catch (Exception ex) { - throw new Exception ("Quelque chose s'est mal passé à l'envoi",ex); - } - } + public static ServiceAccountCredential OupsGetCredentialForApi(IEnumerable scopes) { var initializer = new ServiceAccountCredential.Initializer(Startup.GoogleSettings.Account.client_email); diff --git a/Yavsc/Models/Billing/Estimate.cs b/Yavsc/Models/Billing/Estimate.cs index a159a817..4473b059 100644 --- a/Yavsc/Models/Billing/Estimate.cs +++ b/Yavsc/Models/Billing/Estimate.cs @@ -59,7 +59,6 @@ namespace Yavsc.Models.Billing set { AttachedFiles = value.Split(':').ToList(); } } - [Required] public string OwnerId { get; set; } [ForeignKey("OwnerId"),JsonIgnore] diff --git a/Yavsc/Models/Calendar/ProvidedEvent.cs b/Yavsc/Models/Calendar/ProvidedEvent.cs index 837bdf50..9f061b13 100644 --- a/Yavsc/Models/Calendar/ProvidedEvent.cs +++ b/Yavsc/Models/Calendar/ProvidedEvent.cs @@ -29,12 +29,17 @@ namespace Yavsc.Models.Calendar /// /// Provided event. /// - public class ProvidedEvent : YaEvent { + public class ProvidedEvent : BaseEvent { /// /// The privacy. /// [Required] public Publishing Privacy; - } + + public override string CreateBody() + { + throw new System.NotImplementedException(); + } + } } diff --git a/Yavsc/Models/HairCut/HairCutPaymentEvent.cs b/Yavsc/Models/HairCut/HairCutPaymentEvent.cs new file mode 100644 index 00000000..f6ca7a7e --- /dev/null +++ b/Yavsc/Models/HairCut/HairCutPaymentEvent.cs @@ -0,0 +1,76 @@ +using Microsoft.Extensions.Localization; +using System.Linq; + +using Yavsc.Interfaces.Workflow; +using Yavsc.Models.Haircut; +using Yavsc.ViewModels.PayPal; +using Yavsc.Helpers; + +namespace Yavsc.Models.HairCut +{ + public class HairCutPayementEvent: IEvent + { + public HairCutPayementEvent(string sender, PaymentInfo info, HairCutQuery query, IStringLocalizer localizer) + { + Sender = sender; + this.query = query; + invoiceId = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.InvoiceID; + payerName = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Name; + phone = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Address.Phone; + payerEmail = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.Payer; + amount = string.Join(", ", + info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PaymentDetails.Select( + p => $"{p.OrderTotal.value} {p.OrderTotal.currencyID}")); + gender = query.Prestation.Gender; + date = query.EventDate?.ToString("dd MM yyyy hh:mm"); + lieu = query.Location.Address; + clientFinal = (gender == HairCutGenders.Women) ? localizer["Women"] + + " " + localizer[query.Prestation.Length.ToString()] : localizer[gender.ToString()]; + token = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.Token; + payerId = info.DetailsFromPayPal.GetExpressCheckoutDetailsResponseDetails.PayerInfo.PayerID; + } + + public string Topic => "/topic/HaircutPayment"; + + public string Sender { get; set; } + + HairCutQuery query; + + private string invoiceId; + private string payerName; + private string phone; + private string payerEmail; + private string amount; + private HairCutGenders gender; + private string date; + private string lieu; + private string clientFinal; + private string token; + private string payerId; + + public string CreateBody() + { + return $@"# Paiment confirmé: {amount} + +Effectué par : {payerName} [{payerEmail}] +Identifiant PayPal du paiment: {token} +Identifiant PayPal du payeur: {payerId} +Identifiant de la facture sur site: {invoiceId} + + +# La prestation concernée: + +Demandeur: {query.Client.UserName} + +Date: {date} + +Lieu: {lieu} + +Le client final: {clientFinal} + +{query.GetBillText()} + +"; + } + } +} \ No newline at end of file diff --git a/Yavsc/Models/HairCut/HairCutQuery.cs b/Yavsc/Models/HairCut/HairCutQuery.cs index 62871efc..7e7b4aab 100644 --- a/Yavsc/Models/HairCut/HairCutQuery.cs +++ b/Yavsc/Models/HairCut/HairCutQuery.cs @@ -10,6 +10,9 @@ using System.Globalization; using Yavsc.Helpers; using Yavsc.Models.Messaging; using System.Linq; +using Microsoft.Extensions.Localization; +using Yavsc.ViewModels.PayPal; +using Yavsc.Models.HairCut; namespace Yavsc.Models.Haircut { @@ -369,9 +372,15 @@ Prestation.Gender == HairCutGenders.Women ? return bill; } + public HairCutPayementEvent CreatePaymentEvent(PaymentInfo info, IStringLocalizer localizer) + { + + return new HairCutPayementEvent(Client.UserName,info,this, localizer); + } + public virtual BrusherProfile SelectedProfile { get; set; } - public HairCutQueryEvent CreateEvent(string subTopic, string reason, string sender, string message) { + public HairCutQueryEvent CreateEvent(string subTopic, string reason, string sender) { string evdate = EventDate?.ToString("dddd dd/MM/yyyy à HH:mm")??"[pas de date spécifiée]"; string address = Location?.Address??"[pas de lieu spécifié]"; @@ -393,8 +402,7 @@ Prestation.Gender == HairCutGenders.Women ? Id = Id, ActivityCode = ActivityCode, Reason = reason, - Sender = sender, - Message = message + Sender = Client.GetSender() }; return yaev; } diff --git a/Yavsc/Models/HairCut/HairCutQueryEvent.cs b/Yavsc/Models/HairCut/HairCutQueryEvent.cs index e176fbd3..af1c6e2f 100644 --- a/Yavsc/Models/HairCut/HairCutQueryEvent.cs +++ b/Yavsc/Models/HairCut/HairCutQueryEvent.cs @@ -6,14 +6,20 @@ namespace Yavsc.Models.Haircut { public HairCutQueryEvent(string subTopic) { - - Topic = GetType().Name+"/"+subTopic; + Topic = "/topic/HairCutQuery"; + if (subTopic!=null) Topic+="/"+subTopic; } - public string Message + public string CreateBody() { - get; + return $"{Reason}\r\n-- \r\n{Previsional}\r\n{EventDate}\r\n"; + } - set; + public string CreateBoby() + { + return string.Format(Startup.GlobalLocalizer["RdvToPerf"], Client.UserName, + EventDate?.ToString("dddd dd/MM/yyyy à HH:mm"), + Location.Address, + ActivityCode); } public string Sender diff --git a/Yavsc/Models/Messaging/Announce.cs b/Yavsc/Models/Messaging/Announce.cs index 2b17d983..54e8c04c 100644 --- a/Yavsc/Models/Messaging/Announce.cs +++ b/Yavsc/Models/Messaging/Announce.cs @@ -4,7 +4,7 @@ using Yavsc.Interfaces; namespace Yavsc.Models.Messaging { - public enum Reason { + public enum Reason: byte { Private, Corporate, SearchingAPro, @@ -23,6 +23,12 @@ namespace Yavsc.Models.Messaging public string OwnerId { get; set; } [ForeignKey("OwnerId")] - public virtual ApplicationUser Owner { get; set; } + public virtual ApplicationUser Owner { get; set; } + + public string Message { get; set; } + public override string CreateBody() + { + return $"Annonce de {Owner.UserName}: {For}\n\n{Message}"; + } } } \ No newline at end of file diff --git a/Yavsc/Models/Messaging/BaseEvent.cs b/Yavsc/Models/Messaging/BaseEvent.cs index ca78c918..3fd5286f 100644 --- a/Yavsc/Models/Messaging/BaseEvent.cs +++ b/Yavsc/Models/Messaging/BaseEvent.cs @@ -28,7 +28,7 @@ namespace Yavsc.Models.Messaging /// /// Base event. /// - public class BaseEvent : IEvent { + public abstract class BaseEvent : IEvent { public BaseEvent() { Topic = GetType().Name; @@ -39,7 +39,8 @@ namespace Yavsc.Models.Messaging } public string Topic { get; private set; } public string Sender { get; set; } - public string Message { get; set; } + + abstract public string CreateBody(); } diff --git a/Yavsc/Models/Messaging/CircleEvent.cs b/Yavsc/Models/Messaging/CircleEvent.cs index c85b90cd..57374f44 100644 --- a/Yavsc/Models/Messaging/CircleEvent.cs +++ b/Yavsc/Models/Messaging/CircleEvent.cs @@ -28,7 +28,7 @@ namespace Yavsc.Models.Messaging /// /// Event pub. /// - public class CircleEvent: YaEvent + public class CircleEvent: BaseEvent { /// /// Gets or sets the circles. @@ -37,7 +37,12 @@ namespace Yavsc.Models.Messaging [Required(ErrorMessageResourceName="DoSpecifyCircles"), Display(Name="Circles")] public virtual List Circles{ get; set; } - } + + public override string CreateBody() + { + throw new System.NotImplementedException(); + } + } } diff --git a/Yavsc/Models/Messaging/EstimationEvent.cs b/Yavsc/Models/Messaging/EstimationEvent.cs index d856af3e..b846df34 100644 --- a/Yavsc/Models/Messaging/EstimationEvent.cs +++ b/Yavsc/Models/Messaging/EstimationEvent.cs @@ -7,6 +7,7 @@ namespace Yavsc.Models.Messaging using Interfaces.Workflow; using Billing; using Yavsc.Helpers; + using Yavsc.Models.Workflow; public class EstimationEvent: IEvent { @@ -14,7 +15,7 @@ namespace Yavsc.Models.Messaging { Topic = "Estimation"; Estimation = estimate; - var perfer = context.Performers.Include( + perfer = context.Performers.Include( p=>p.Performer ).FirstOrDefault( p => p.PerformerId == estimate.OwnerId @@ -27,12 +28,16 @@ namespace Yavsc.Models.Messaging UserId = perfer.PerformerId }; Sender = perfer.Performer.UserName; - Message = string.Format(SR["EstimationMessageToClient"],perfer.Performer.UserName, - estimate.Title,estimate.Bill.Addition()); + _localizer = SR; } + // TODO via e-mail only: Message = string.Format( + // SR["EstimationMessageToClient"],perfer.Performer.UserName, estimate.Title,estimate.Bill.Addition()); + // ProviderClientInfo ProviderInfo { get; set; } Estimate Estimation { get; set; } + private PerformerProfile perfer; + public string Topic { get; set; @@ -43,9 +48,11 @@ namespace Yavsc.Models.Messaging get; set; } - public string Message + private IStringLocalizer _localizer; + + public string CreateBody() { - get; set; + return string.Format(_localizer["EstimationMessageToClient"], perfer.Performer.UserName, this.Estimation.Bill.Addition()); } } } diff --git a/Yavsc/Models/Messaging/GeneralEvent.cs b/Yavsc/Models/Messaging/GeneralEvent.cs deleted file mode 100644 index a9572d6d..00000000 --- a/Yavsc/Models/Messaging/GeneralEvent.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// BaseEvent.cs -// -// Author: -// Paul Schneider -// -// Copyright (c) 2015 GNU GPL -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . - -using System.ComponentModel.DataAnnotations; - -namespace Yavsc.Models.Messaging -{ -public class GeneralEvent: BaseEvent, ITitle - { - /// - /// The title. - /// - [Required(ErrorMessageResourceName="ChooseATitle")] - [Display(Name="Title")] - public string Title { get; set; } - /// - /// The description. - /// - [Required(ErrorMessageResourceName="ChooseADescription")] - [Display(Name="Description")] - public string Description { get; set; } - - } - -} diff --git a/Yavsc/Models/Messaging/RdvQueryEvent.cs b/Yavsc/Models/Messaging/RdvQueryEvent.cs index 35a27e8f..3158ce4b 100644 --- a/Yavsc/Models/Messaging/RdvQueryEvent.cs +++ b/Yavsc/Models/Messaging/RdvQueryEvent.cs @@ -22,20 +22,19 @@ namespace Yavsc.Models.Messaging { using Interfaces.Workflow; + using Yavsc.Abstract.Messaging; - - -public class RdvQueryEvent: RdvQueryProviderInfo, IEvent + public class RdvQueryEvent: RdvQueryProviderInfo, IEvent { - - public RdvQueryEvent(string subTopic) + public string SubTopic { - Topic = GetType().Name+"/"+subTopic; + get; private set; } - public string Message + public RdvQueryEvent(string subTopic) { - get; set; + Topic = MessagingConstants.TopicRdvQuery; + SubTopic = subTopic; } public string Sender @@ -47,6 +46,14 @@ public class RdvQueryEvent: RdvQueryProviderInfo, IEvent { get; private set; } + + public string CreateBody() + { + return string.Format(Startup.GlobalLocalizer["RdvToPerf"], Client.UserName, + EventDate?.ToString("dddd dd/MM/yyyy à HH:mm"), + Location.Address, + ActivityCode); + } } } diff --git a/Yavsc/Models/Messaging/YaEvent.cs b/Yavsc/Models/Messaging/YaEvent.cs deleted file mode 100644 index ce7304bd..00000000 --- a/Yavsc/Models/Messaging/YaEvent.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// NFEvent.cs -// -// Author: -// Paul Schneider -// -// Copyright (c) 2015 Paul Schneider -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see . - -using System.ComponentModel.DataAnnotations; - -namespace Yavsc.Models.Messaging -{ - /// - /// NF event. - /// - public class YaEvent : BaseEvent - { - /// - /// The NF provider identifier. - /// - [Display(Name="From")] - public string FromUserName { get; set; } - - /// - /// The event web page. - /// - [Display(Name="EventWebPage")] - public string EventWebPage { get; set; } - /// - /// The image locator. - /// - [Display(Name="Photo")] - public string Photo { get; set; } - } -} diff --git a/Yavsc/Models/Relationship/Location.cs b/Yavsc/Models/Relationship/Location.cs index 6afa336e..29e8dd7d 100644 --- a/Yavsc/Models/Relationship/Location.cs +++ b/Yavsc/Models/Relationship/Location.cs @@ -7,7 +7,7 @@ namespace Yavsc.Models.Relationship /// /// Position. /// - public class Position + public class Position: IPosition { /// /// The longitude. diff --git a/Yavsc/Resources/Yavsc.Resources.YavscLocalisation.fr.resx b/Yavsc/Resources/Yavsc.Resources.YavscLocalisation.fr.resx index 3968f78f..78d04a37 100644 --- a/Yavsc/Resources/Yavsc.Resources.YavscLocalisation.fr.resx +++ b/Yavsc/Resources/Yavsc.Resources.YavscLocalisation.fr.resx @@ -240,6 +240,7 @@ Nom complet L'envoi du message push a échoué, mais un e-mail a été envoyé Message push envoyé + L'evoi du message Google Cloud a échoué ... Dites en plus, ci àprès, à propos de cet évennement Google n'a pas pu identifier ce lieu Agenda Google @@ -463,5 +464,27 @@ Pour ce faire, suivez le lien suivant : <{1}>. d'au moins {0} et d'au plus {1} caractère(s). Ce champ est d'au plus {0} caractère(s) ({1} en excès). +Un message éléctronique a été envoyé au préstataire. +Un client vient de valider une demande de prestation à votre encontre: + Prestation: {0} + Client : {1} + Date: {2}, + Adresse: {3} + +----- +{4} + +Facture prévue (non réglée): {5} +Un client vient de valider une demande de prestation à votre encontre: + + Prestation: {0} + Client : {1} + Date: {2}, + Adresse: {3} + +----- +{4} + +Facture réglée: {5} diff --git a/Yavsc/Services/IGoogleCloudMessageSender.cs b/Yavsc/Services/IGoogleCloudMessageSender.cs index c6ad796f..f59cab4b 100644 --- a/Yavsc/Services/IGoogleCloudMessageSender.cs +++ b/Yavsc/Services/IGoogleCloudMessageSender.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Yavsc.Interfaces.Workflow; using Yavsc.Models.Google.Messaging; using Yavsc.Models.Haircut; using Yavsc.Models.Messaging; @@ -23,7 +24,9 @@ namespace Yavsc.Services GoogleAuthSettings googlesettings, IEnumerable registrationId, HairCutQueryEvent ev); - - + Task NotifyAsync( + GoogleAuthSettings _googleSettings, + IEnumerable regids, + IEvent yaev); } } diff --git a/Yavsc/Services/MessageServices.cs b/Yavsc/Services/MessageServices.cs index ff3191f7..088a721e 100755 --- a/Yavsc/Services/MessageServices.cs +++ b/Yavsc/Services/MessageServices.cs @@ -11,6 +11,10 @@ using Yavsc.Models; using Yavsc.Models.Google.Messaging; using System.Collections.Generic; using Yavsc.Models.Haircut; +using Yavsc.Interfaces.Workflow; +using System.Linq; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace Yavsc.Services { @@ -19,6 +23,49 @@ namespace Yavsc.Services // For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 public class AuthMessageSender : IEmailSender, IGoogleCloudMessageSender { + private ILogger _logger; + + public AuthMessageSender(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + public async Task NotifyEvent + ( GoogleAuthSettings googleSettings, IEnumerable regids, Event ev) + where Event : IEvent + { + if (ev == null) + throw new Exception("Spécifier un évènement"); + + if (ev.Sender == null) + throw new Exception("Spécifier un expéditeur"); + + if (regids == null ) + throw new NotImplementedException("Notify & No GCM reg ids"); + var raa = regids.ToArray(); + if (raa.Length<1) + throw new NotImplementedException("No GCM reg ids"); + var msg = new MessageWithPayload() + { + notification = new Notification() + { + title = ev.Topic+" "+ev.Sender, + body = ev.CreateBody(), + icon = "icon" + }, + data = ev, + registration_ids = regids.ToArray() + }; + _logger.LogInformation("Sendding to Google : "+JsonConvert.SerializeObject(msg)); + try { + using (var m = new SimpleJsonPostMethod("https://gcm-http.googleapis.com/gcm/send",$"key={googleSettings.ApiKey}")) { + return await m.Invoke(msg); + } + } + catch (Exception ex) { + throw new Exception ("Quelque chose s'est mal passé à l'envoi",ex); + } + } + /// /// /// @@ -30,18 +77,18 @@ namespace Yavsc.Services /// public async Task NotifyBookQueryAsync(GoogleAuthSettings googleSettings, IEnumerable registrationIds, RdvQueryEvent ev) { - return await googleSettings.NotifyEvent(registrationIds, ev); + return await NotifyEvent(googleSettings,registrationIds, ev); } public async Task NotifyEstimateAsync(GoogleAuthSettings googleSettings, IEnumerable registrationIds, EstimationEvent ev) { - return await googleSettings.NotifyEvent(registrationIds, ev); + return await NotifyEvent(googleSettings,registrationIds, ev); } public async Task NotifyHairCutQueryAsync(GoogleAuthSettings googleSettings, IEnumerable registrationIds, HairCutQueryEvent ev) { - return await googleSettings.NotifyEvent(registrationIds, ev); + return await NotifyEvent(googleSettings, registrationIds, ev); } public Task SendEmailAsync(SiteSettings siteSettings, SmtpSettings smtpSettings, string username, string email, string subject, string message) @@ -78,16 +125,21 @@ namespace Yavsc.Services { throw new NotImplementedException(); } + + public Task NotifyAsync(GoogleAuthSettings _googleSettings, IEnumerable regids, IEvent yaev) + { + throw new NotImplementedException(); + } /* SMS with Twilio: public Task SendSmsAsync(TwilioSettings twilioSettigns, string number, string message) { - var Twilio = new TwilioRestClient(twilioSettigns.AccountSID, twilioSettigns.Token); - var result = Twilio.SendMessage( twilioSettigns.SMSAccountFrom, number, message); - // Status is one of Queued, Sending, Sent, Failed or null if the number is not valid - Trace.TraceInformation(result.Status); - // Twilio doesn't currently have an async API, so return success. +var Twilio = new TwilioRestClient(twilioSettigns.AccountSID, twilioSettigns.Token); +var result = Twilio.SendMessage( twilioSettigns.SMSAccountFrom, number, message); +// Status is one of Queued, Sending, Sent, Failed or null if the number is not valid +Trace.TraceInformation(result.Status); +// Twilio doesn't currently have an async API, so return success. - return Task.FromResult(result.Status != "Failed"); +return Task.FromResult(result.Status != "Failed"); } */ } diff --git a/Yavsc/Startup/Startup.SanityChecks.cs b/Yavsc/Startup/Startup.SanityChecks.cs index 744dfb2f..de80cd71 100644 --- a/Yavsc/Startup/Startup.SanityChecks.cs +++ b/Yavsc/Startup/Startup.SanityChecks.cs @@ -28,19 +28,20 @@ namespace Yavsc var appData = Environment.GetEnvironmentVariable("APPDATA"); if (appData == null) { + logger.LogWarning("AppData was not found in environment variables"); if (SiteSetup.DataDir == null) { SiteSetup.DataDir = "AppData"+env.EnvironmentName; - } else logger.LogWarning("existing setting: "+SiteSetup.DataDir); + logger.LogInformation("Using: "+SiteSetup.DataDir); + } else logger.LogInformation("Using value from settings: "+SiteSetup.DataDir); DirectoryInfo di = new DirectoryInfo(SiteSetup.DataDir); if (!di.Exists) { di.Create(); logger.LogWarning("Created dir : "+di.FullName); - } else logger.LogWarning("existing: "+di.Name); + } else logger.LogInformation("Using existing directory: "+di.Name); SiteSetup.DataDir = Path.Combine(Directory.GetCurrentDirectory(),di.Name); Environment.SetEnvironmentVariable("APPDATA", SiteSetup.DataDir); - logger.LogWarning("AppData was not found in env vars, it has been set to : "+ - Environment.GetEnvironmentVariable("APPDATA")); + logger.LogWarning("It has been set to : "+Environment.GetEnvironmentVariable("APPDATA")); } var creds = GoogleSettings?.Account?.private_key; diff --git a/Yavsc/Views/Command/CommandConfirmation.cshtml b/Yavsc/Views/Command/CommandConfirmation.cshtml index fcb061cf..0d4471f4 100644 --- a/Yavsc/Views/Command/CommandConfirmation.cshtml +++ b/Yavsc/Views/Command/CommandConfirmation.cshtml @@ -22,12 +22,14 @@ if (ViewBag.GooglePayload.failure>0) {

@SR["GCM Notification sending failed"]

- } - else { - +
@Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.GooglePayload)
} } } + @if (ViewBag.EmailSent) + { +

@SR["EmailSentToPerformer"]

+ } diff --git a/Yavsc/Views/GCMDevices/Delete.cshtml b/Yavsc/Views/GCMDevices/Delete.cshtml new file mode 100644 index 00000000..3720f916 --- /dev/null +++ b/Yavsc/Views/GCMDevices/Delete.cshtml @@ -0,0 +1,52 @@ +@model Yavsc.Models.Identity.GoogleCloudMobileDeclaration + +@{ + ViewData["Title"] = "Delete"; +} + +

Delete

+ +

Are you sure you want to delete this?

+
diff --git a/Yavsc/Views/GCMDevices/Details.cshtml b/Yavsc/Views/GCMDevices/Details.cshtml new file mode 100644 index 00000000..3c10cab8 --- /dev/null +++ b/Yavsc/Views/GCMDevices/Details.cshtml @@ -0,0 +1,48 @@ +@model Yavsc.Models.Identity.GoogleCloudMobileDeclaration + +@{ + ViewData["Title"] = "Details"; +} + +

Details

+ +
+

GoogleCloudMobileDeclaration

+
+
+
+ @Html.DisplayNameFor(model => model.DeclarationDate) +
+
+ @Html.DisplayFor(model => model.DeclarationDate) +
+
+ @Html.DisplayNameFor(model => model.GCMRegistrationId) +
+
+ @Html.DisplayFor(model => model.GCMRegistrationId) +
+
+ @Html.DisplayNameFor(model => model.Model) +
+
+ @Html.DisplayFor(model => model.Model) +
+
+ @Html.DisplayNameFor(model => model.Platform) +
+
+ @Html.DisplayFor(model => model.Platform) +
+
+ @Html.DisplayNameFor(model => model.Version) +
+
+ @Html.DisplayFor(model => model.Version) +
+
+
+

+ Edit | + Back to List +

diff --git a/Yavsc/Views/GCMDevices/Index.cshtml b/Yavsc/Views/GCMDevices/Index.cshtml new file mode 100644 index 00000000..425af934 --- /dev/null +++ b/Yavsc/Views/GCMDevices/Index.cshtml @@ -0,0 +1,52 @@ +@model IEnumerable + +@{ + ViewData["Title"] = "Index"; +} + +

Index

+ + + + + + + + + + + +@foreach (var item in Model) { + + + + + + + + +} +
+ @Html.DisplayNameFor(model => model.DeclarationDate) + + @Html.DisplayNameFor(model => model.GCMRegistrationId) + + @Html.DisplayNameFor(model => model.Model) + + @Html.DisplayNameFor(model => model.Platform) + + @Html.DisplayNameFor(model => model.Version) +
+ @Html.DisplayFor(modelItem => item.DeclarationDate) + + @Html.DisplayFor(modelItem => item.GCMRegistrationId) + + @Html.DisplayFor(modelItem => item.Model) + + @Html.DisplayFor(modelItem => item.Platform) + + @Html.DisplayFor(modelItem => item.Version) + + Details | + Delete +
diff --git a/Yavsc/Views/_ViewImports.cshtml b/Yavsc/Views/_ViewImports.cshtml index 20e370f6..f0626605 100755 --- a/Yavsc/Views/_ViewImports.cshtml +++ b/Yavsc/Views/_ViewImports.cshtml @@ -41,6 +41,7 @@ @using Microsoft.Extensions.PlatformAbstractions; @using PayPal.PayPalAPIInterfaceService.Model; + @inject IViewLocalizer LocString @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Yavsc" diff --git a/test/UnitTest1.cs b/test/UnitTest1.cs index 0df16748..9f4a9702 100755 --- a/test/UnitTest1.cs +++ b/test/UnitTest1.cs @@ -10,5 +10,24 @@ namespace test1 { } + + + [Fact] + public void PassingTest() + { + Assert.Equal(4, Add(2, 2)); + } + + [Fact] + public void FailingTest() + { + Assert.Equal(5, Add(2, 2)); + } + + int Add(int x, int y) + { + return x + y; + } + } } diff --git a/test/global.json b/test/global.json index 63264e7e..717248e6 100644 --- a/test/global.json +++ b/test/global.json @@ -1,7 +1,7 @@ { - "sdk": { - "version": "2.0.4", - "runtime": "mono", - "architecture": "x64" - } -} + "sdk": { + "version": "2.0.4", + "runtime": "mono", + "architecture": "x64" + } +} \ No newline at end of file diff --git a/test/packages.config b/test/packages.config new file mode 100644 index 00000000..7edb886c --- /dev/null +++ b/test/packages.config @@ -0,0 +1,7 @@ + + + + + + +