refactoring messages

This commit is contained in:
2018-02-03 20:17:29 +01:00
parent edd91faa96
commit 6c18f32f61
44 changed files with 603 additions and 304 deletions

11
Makefile Normal file
View File

@ -0,0 +1,11 @@
MAKE=make
SUBDIRS=Yavsc.Abstract Yavsc
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
.PHONY: all $(SUBDIRS)

View File

@ -1,6 +1,5 @@
namespace YaDaemon namespace YaDaemon
{ {
using YaDaemon;
public class TestDaemonStart public class TestDaemonStart
{ {

View File

@ -1,5 +1,5 @@
CONFIG=Release CONFIG=Release
VERSION=1.0.5-rc4 VERSION=1.0.5-rc5
PRJNAME=Yavsc.Abstract PRJNAME=Yavsc.Abstract
PKGFILENAME=$(PRJNAME).$(VERSION).nupkg PKGFILENAME=$(PRJNAME).$(VERSION).nupkg
DESTPATH=. DESTPATH=.

View File

@ -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";
}
}

View File

@ -25,4 +25,4 @@ using System.Reflection;
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.5.*")] [assembly: AssemblyVersion("1.0.5.*")]
[assembly: AssemblyFileVersion("1.0.5.2")] [assembly: AssemblyFileVersion("1.0.5.3")]

View File

@ -11,11 +11,8 @@ namespace Yavsc.Interfaces.Workflow {
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
string Sender { get; set ; } string Sender { get; set ; }
/// <summary>
/// The message string CreateBody();
/// </summary>
/// <returns></returns>
string Message { get; set; }
} }

View File

@ -1,6 +1,6 @@
namespace Yavsc namespace Yavsc
{ {
public interface ILocation public interface ILocation : IPosition
{ {
string Address { get; set; } string Address { get; set; }
long Id { get; set; } long Id { get; set; }

Binary file not shown.

View File

@ -11,7 +11,7 @@
<iconUrl>https://github.com/pazof/yavsc/blob/vnext/Yavsc/wwwroot/images/yavsc.png</iconUrl> <iconUrl>https://github.com/pazof/yavsc/blob/vnext/Yavsc/wwwroot/images/yavsc.png</iconUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance> <requireLicenseAcceptance>true</requireLicenseAcceptance>
<description> <description>
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.
</description> </description>
<summary> <summary>
</summary> </summary>

View File

@ -114,14 +114,16 @@ namespace Yavsc.Controllers
public IActionResult PostEstimate([FromBody] Estimate estimate) public IActionResult PostEstimate([FromBody] Estimate estimate)
{ {
var uid = User.GetUserId(); 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) if (uid != estimate.OwnerId)
{ {
ModelState.AddModelError("OwnerId","You can only create your own estimates"); ModelState.AddModelError("OwnerId","You can only create your own estimates");
return HttpBadRequest(ModelState); return HttpBadRequest(ModelState);
} }
} }
if (estimate.CommandId!=null) { if (estimate.CommandId!=null) {
var query = _context.RdvQueries.FirstOrDefault(q => q.Id == estimate.CommandId); var query = _context.RdvQueries.FirstOrDefault(q => q.Id == estimate.CommandId);
if (query == null) { if (query == null) {

View File

@ -47,23 +47,25 @@ namespace Yavsc.Controllers
long[] usercircles = _context.Circle.Include(c=>c.Members).Where(c=>c.Members.Any(m=>m.MemberId == uid)) long[] usercircles = _context.Circle.Include(c=>c.Members).Where(c=>c.Members.Any(m=>m.MemberId == uid))
.Select(c=>c.Id).ToArray(); .Select(c=>c.Id).ToArray();
IQueryable<BlogPost> posts ; IQueryable<BlogPost> posts ;
if (usercircles != null) { var allposts = _context.Blogspot
posts = _context.Blogspot.Include(b => b.Author) .Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags) .Include(p=>p.Tags)
.Include(p=>p.Comments) .Include(p=>p.Comments)
.Include(p=>p.ACL) .Where(p=>p.AuthorId == uid || p.Visible);
.Where(p=> p.AuthorId == uid || p.Visible &&
(p.ACL.Count == 0 || p.ACL.Any(a=> usercircles.Contains(a.CircleId)))) if (usercircles != null) {
; posts = allposts.Where(p=> p.ACL.Count==0 || p.ACL.Any(a=> usercircles.Contains(a.CircleId)))
;
} }
else { else {
posts = _context.Blogspot.Include(b => b.Author) posts = allposts.Where(p => p.ACL.Count == 0);
.Include(p=>p.ACL).Where(p=>p.AuthorId == uid || p.Visible && p.ACL.Count == 0);
} }
return View(posts.OrderByDescending( p=> p.DateCreated) var data = posts.OrderByDescending( p=> p.DateCreated).ToArray();
var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(maxLen);
.GroupBy(p=> p.Title).Skip(skip).Take(maxLen)); return View(grouped);
} }
[Route("/Title/{id?}")] [Route("/Title/{id?}")]

View File

@ -174,17 +174,18 @@ namespace Yavsc.Controllers
.Devices.Select(d => d.GCMRegistrationId); .Devices.Select(d => d.GCMRegistrationId);
grep = await _GCMSender.NotifyBookQueryAsync(_googleSettings,regids,yaev); grep = await _GCMSender.NotifyBookQueryAsync(_googleSettings,regids,yaev);
} }
// TODO setup a profile choice to allow notifications // TODO setup a profile choice to allow notifications
// both on mailbox and mobile // both on mailbox and mobile
// if (grep==null || grep.success<=0 || grep.failure>0) // if (grep==null || grep.success<=0 || grep.failure>0)
ViewBag.GooglePayload=grep; ViewBag.GooglePayload=grep;
await _emailSender.SendEmailAsync( ViewBag.EmailSent = await _emailSender.SendEmailAsync(
_siteSettings, _smtpSettings, _siteSettings, _smtpSettings,
command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.UserName,
command.PerformerProfile.Performer.Email, command.PerformerProfile.Performer.Email,
$"{command.Client.UserName} (un client) vous demande un rendez-vous", $"{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); ViewBag.Activity = _context.Activities.FirstOrDefault(a=>a.Code == command.ActivityCode);

View File

@ -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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> DeleteConfirmed(string id)
{
GoogleCloudMobileDeclaration googleCloudMobileDeclaration = await _context.GCMDevices.SingleAsync(m => m.DeviceId == id);
_context.GCMDevices.Remove(googleCloudMobileDeclaration);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
}
}

View File

@ -79,60 +79,30 @@ namespace Yavsc.Controllers
ViewData["paymentinfo"] = paymentInfo; ViewData["paymentinfo"] = paymentInfo;
command.Regularisation = paymentInfo.DbContent; command.Regularisation = paymentInfo.DbContent;
command.PaymentId = token; command.PaymentId = token;
if (paymentInfo != null) bool paymentOk = false;
if (paymentInfo.DetailsFromPayPal != null) if (paymentInfo.DetailsFromPayPal != null)
if (paymentInfo.DetailsFromPayPal.Ack == AckCodeType.SUCCESS) if (paymentInfo.DetailsFromPayPal.Ack == AckCodeType.SUCCESS)
if (command.ValidationDate == null) {
command.ValidationDate = DateTime.Now; // FIXME Assert (command.ValidationDate == null)
if (command.ValidationDate == null) {
paymentOk = true;
command.ValidationDate = DateTime.Now;
}
}
await _context.SaveChangesAsync(User.GetUserId()); await _context.SaveChangesAsync(User.GetUserId());
SetViewBagPaymentUrls(id); 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; MessageWithPayloadResponse grep = null;
var yaev = command.CreateEvent("PaymentConfirmation", var yaev = command.CreatePaymentEvent(paymentInfo, _localizer);
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()}
");
if (command.PerformerProfile.AcceptNotifications) if (command.PerformerProfile.AcceptNotifications)
{ {
if (command.PerformerProfile.Performer.Devices.Count > 0) if (command.PerformerProfile.Performer.Devices.Count > 0)
{ {
var regids = command.PerformerProfile.Performer var regids = command.PerformerProfile.Performer
.Devices.Select(d => d.GCMRegistrationId); .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 // TODO setup a profile choice to allow notifications
// both on mailbox and mobile // both on mailbox and mobile
@ -144,8 +114,8 @@ Le client final: {clientFinal}
_siteSettings, _smtpSettings, _siteSettings, _smtpSettings,
command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.UserName,
command.PerformerProfile.Performer.Email, command.PerformerProfile.Performer.Email,
yaev.Reason, yaev.Topic,
$"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" yaev.CreateBody()
); );
} }
else else
@ -321,7 +291,7 @@ Le client final: {clientFinal}
DateTime evdate = yaev.EventDate ?? new DateTime(); DateTime evdate = yaev.EventDate ?? new DateTime();
var result = await _calendarManager.CreateEventAsync(pro.Performer.Id, var result = await _calendarManager.CreateEventAsync(pro.Performer.Id,
pro.Performer.DedicatedGoogleCalendar, pro.Performer.DedicatedGoogleCalendar,
evdate, 3600, yaev.Topic, yaev.Message, evdate, 3600, yaev.Topic, yaev.Client.UserName + " : " + yaev.Reason,
yaev.Location?.Address, false yaev.Location?.Address, false
); );
if (result.Id == null) if (result.Id == null)
@ -333,8 +303,8 @@ Le client final: {clientFinal}
_siteSettings, _smtpSettings, _siteSettings, _smtpSettings,
pro.Performer.UserName, pro.Performer.UserName,
pro.Performer.Email, pro.Performer.Email,
yaev.Reason, $"{yaev.Client.UserName}: {yaev.Reason}",
$"{yaev.Message}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n" $"{yaev.Reason}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n"
); );
} }
else else
@ -456,6 +426,7 @@ Le client final: {clientFinal}
bp => bp.UserId == command.PerformerId bp => bp.UserId == command.PerformerId
); );
var yaev = command.CreateEvent(_localizer, brSettings); var yaev = command.CreateEvent(_localizer, brSettings);
string msg = yaev.CreateBoby();
MessageWithPayloadResponse grep = null; MessageWithPayloadResponse grep = null;
if (pro.AcceptNotifications if (pro.AcceptNotifications
@ -481,7 +452,7 @@ Le client final: {clientFinal}
await _calendarManager.CreateEventAsync( await _calendarManager.CreateEventAsync(
pro.Performer.Id, pro.Performer.Id,
pro.Performer.DedicatedGoogleCalendar, pro.Performer.DedicatedGoogleCalendar,
evdate, 3600, yaev.Topic, yaev.Message, evdate, 3600, yaev.Topic, msg,
yaev.Location?.ToString(), false yaev.Location?.ToString(), false
); );
} }
@ -491,7 +462,7 @@ Le client final: {clientFinal}
command.PerformerProfile.Performer.UserName, command.PerformerProfile.Performer.UserName,
command.PerformerProfile.Performer.Email, command.PerformerProfile.Performer.Email,
yaev.Topic + " " + yaev.Sender, 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); ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == command.ActivityCode);

View File

@ -50,7 +50,7 @@ namespace Yavsc.Controllers
} }
else clicked = DbContext.DimissClicked.Where(d=>d.UserId == uid).Select(d=>d.NotificationId).ToArray(); else clicked = DbContext.DimissClicked.Where(d=>d.UserId == uid).Select(d=>d.NotificationId).ToArray();
var notes = DbContext.Notification.Where( var notes = DbContext.Notification.Where(
n=> !clicked.Any(c=>n.Id==c) n=> !clicked.Contains(n.Id)
); );
this.Notify(notes); this.Notify(notes);
ViewData["HaircutCommandCount"] = DbContext.HairCutQueries.Where( ViewData["HaircutCommandCount"] = DbContext.HairCutQueries.Where(

View File

@ -122,9 +122,10 @@ namespace Yavsc.Controllers
EmailConfirmed = await _userManager.IsEmailConfirmedAsync(user) EmailConfirmed = await _userManager.IsEmailConfirmedAsync(user)
}; };
model.HaveProfessionalSettings = _dbContext.Performers.Any(x => x.PerformerId == user.Id); 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(); model.Activity = _dbContext.UserActivities.Include(a=>a.Does).Where(u=>u.UserId == user.Id).ToList();
return View(model); return View(model);
} }

View File

@ -15,12 +15,7 @@ namespace Yavsc.Helpers
var yaev = new RdvQueryEvent(subtopic) var yaev = new RdvQueryEvent(subtopic)
{ {
Sender = query.ClientId, Sender = query.ClientId,
Message = string.Format(SR["RdvToPerf"], Reason = query.Reason,
query.Client.UserName,
query.EventDate.ToString("dddd dd/MM/yyyy à HH:mm"),
query.Location.Address,
query.ActivityCode)+
"\n"+query.Reason,
Client = new ClientProviderInfo {  Client = new ClientProviderInfo { 
UserName = query.Client.UserName , UserName = query.Client.UserName ,
UserId = query.ClientId, UserId = query.ClientId,
@ -46,21 +41,7 @@ namespace Yavsc.Helpers
var yaev = query.CreateEvent("NewHairCutQuery", var yaev = query.CreateEvent("NewHairCutQuery",
string.Format(Startup.GlobalLocalizer["HairCutQueryValidation"],query.Client.UserName), string.Format(Startup.GlobalLocalizer["HairCutQueryValidation"],query.Client.UserName),
$"{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()}
") ;
return yaev; return yaev;
} }
@ -74,11 +55,7 @@ Facture prévue (non réglée):
var yaev = new HairCutQueryEvent("newCommand") var yaev = new HairCutQueryEvent("newCommand")
{ {
Sender = query.ClientId, 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 {  Client = new ClientProviderInfo { 
UserName = query.Client.UserName , UserName = query.Client.UserName ,
UserId = query.ClientId, UserId = query.ClientId,

View File

@ -23,67 +23,29 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; 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 namespace Yavsc.Helpers
{ {
using Models.Google.Messaging;
using Models.Messaging;
using Models; using Models;
using Interfaces.Workflow; using Models.Calendar;
using Yavsc.Models.Calendar; using Services;
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;
/// <summary> /// <summary>
/// Google helpers. /// Google helpers.
/// </summary> /// </summary>
public static class GoogleHelpers public static class GoogleHelpers
{ {
public static async Task <MessageWithPayloadResponse> NotifyEvent<Event>
(this GoogleAuthSettings googleSettings, IEnumerable<string> 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<Event>()
{
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<MessageWithPayloadResponse>(msg);
}
}
catch (Exception ex) {
throw new Exception ("Quelque chose s'est mal passé à l'envoi",ex);
}
}
public static ServiceAccountCredential OupsGetCredentialForApi(IEnumerable<string> scopes) public static ServiceAccountCredential OupsGetCredentialForApi(IEnumerable<string> scopes)
{ {
var initializer = new ServiceAccountCredential.Initializer(Startup.GoogleSettings.Account.client_email); var initializer = new ServiceAccountCredential.Initializer(Startup.GoogleSettings.Account.client_email);

View File

@ -59,7 +59,6 @@ namespace Yavsc.Models.Billing
set { AttachedFiles = value.Split(':').ToList(); } set { AttachedFiles = value.Split(':').ToList(); }
} }
[Required]
public string OwnerId { get; set; } public string OwnerId { get; set; }
[ForeignKey("OwnerId"),JsonIgnore] [ForeignKey("OwnerId"),JsonIgnore]

View File

@ -29,12 +29,17 @@ namespace Yavsc.Models.Calendar
/// <summary> /// <summary>
/// Provided event. /// Provided event.
/// </summary> /// </summary>
public class ProvidedEvent : YaEvent { public class ProvidedEvent : BaseEvent {
/// <summary> /// <summary>
/// The privacy. /// The privacy.
/// </summary> /// </summary>
[Required] [Required]
public Publishing Privacy; public Publishing Privacy;
}
public override string CreateBody()
{
throw new System.NotImplementedException();
}
}
} }

View File

@ -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()}
";
}
}
}

View File

@ -10,6 +10,9 @@ using System.Globalization;
using Yavsc.Helpers; using Yavsc.Helpers;
using Yavsc.Models.Messaging; using Yavsc.Models.Messaging;
using System.Linq; using System.Linq;
using Microsoft.Extensions.Localization;
using Yavsc.ViewModels.PayPal;
using Yavsc.Models.HairCut;
namespace Yavsc.Models.Haircut namespace Yavsc.Models.Haircut
{ {
@ -369,9 +372,15 @@ Prestation.Gender == HairCutGenders.Women ?
return bill; return bill;
} }
public HairCutPayementEvent CreatePaymentEvent(PaymentInfo info, IStringLocalizer localizer)
{
return new HairCutPayementEvent(Client.UserName,info,this, localizer);
}
public virtual BrusherProfile SelectedProfile { get; set; } 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 evdate = EventDate?.ToString("dddd dd/MM/yyyy à HH:mm")??"[pas de date spécifiée]";
string address = Location?.Address??"[pas de lieu spécifié]"; string address = Location?.Address??"[pas de lieu spécifié]";
@ -393,8 +402,7 @@ Prestation.Gender == HairCutGenders.Women ?
Id = Id, Id = Id,
ActivityCode = ActivityCode, ActivityCode = ActivityCode,
Reason = reason, Reason = reason,
Sender = sender, Sender = Client.GetSender()
Message = message
}; };
return yaev; return yaev;
} }

View File

@ -6,14 +6,20 @@ namespace Yavsc.Models.Haircut
{ {
public HairCutQueryEvent(string subTopic) public HairCutQueryEvent(string subTopic)
{ {
Topic = "/topic/HairCutQuery";
Topic = GetType().Name+"/"+subTopic; 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 public string Sender

View File

@ -4,7 +4,7 @@ using Yavsc.Interfaces;
namespace Yavsc.Models.Messaging namespace Yavsc.Models.Messaging
{ {
public enum Reason { public enum Reason: byte {
Private, Private,
Corporate, Corporate,
SearchingAPro, SearchingAPro,
@ -24,5 +24,11 @@ namespace Yavsc.Models.Messaging
[ForeignKey("OwnerId")] [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}";
}
} }
} }

View File

@ -28,7 +28,7 @@ namespace Yavsc.Models.Messaging
/// /// Base event. /// /// Base event.
/// </summary> /// </summary>
public class BaseEvent : IEvent { public abstract class BaseEvent : IEvent {
public BaseEvent() public BaseEvent()
{ {
Topic = GetType().Name; Topic = GetType().Name;
@ -39,7 +39,8 @@ namespace Yavsc.Models.Messaging
} }
public string Topic { get; private set; } public string Topic { get; private set; }
public string Sender { get; set; } public string Sender { get; set; }
public string Message { get; set; }
abstract public string CreateBody();
} }

View File

@ -28,7 +28,7 @@ namespace Yavsc.Models.Messaging
/// <summary> /// <summary>
/// Event pub. /// Event pub.
/// </summary> /// </summary>
public class CircleEvent: YaEvent public class CircleEvent: BaseEvent
{ {
/// <summary> /// <summary>
/// Gets or sets the circles. /// Gets or sets the circles.
@ -37,7 +37,12 @@ namespace Yavsc.Models.Messaging
[Required(ErrorMessageResourceName="DoSpecifyCircles"), [Required(ErrorMessageResourceName="DoSpecifyCircles"),
Display(Name="Circles")] Display(Name="Circles")]
public virtual List<Circle> Circles{ get; set; } public virtual List<Circle> Circles{ get; set; }
}
public override string CreateBody()
{
throw new System.NotImplementedException();
}
}
} }

View File

@ -7,6 +7,7 @@ namespace Yavsc.Models.Messaging
using Interfaces.Workflow; using Interfaces.Workflow;
using Billing; using Billing;
using Yavsc.Helpers; using Yavsc.Helpers;
using Yavsc.Models.Workflow;
public class EstimationEvent: IEvent public class EstimationEvent: IEvent
{ {
@ -14,7 +15,7 @@ namespace Yavsc.Models.Messaging
{ {
Topic = "Estimation"; Topic = "Estimation";
Estimation = estimate; Estimation = estimate;
var perfer = context.Performers.Include( perfer = context.Performers.Include(
p=>p.Performer p=>p.Performer
).FirstOrDefault( ).FirstOrDefault(
p => p.PerformerId == estimate.OwnerId p => p.PerformerId == estimate.OwnerId
@ -27,12 +28,16 @@ namespace Yavsc.Models.Messaging
UserId = perfer.PerformerId UserId = perfer.PerformerId
}; };
Sender = perfer.Performer.UserName; Sender = perfer.Performer.UserName;
Message = string.Format(SR["EstimationMessageToClient"],perfer.Performer.UserName, _localizer = SR;
estimate.Title,estimate.Bill.Addition());
} }
// TODO via e-mail only: Message = string.Format(
// SR["EstimationMessageToClient"],perfer.Performer.UserName, estimate.Title,estimate.Bill.Addition());
//
ProviderClientInfo ProviderInfo { get; set; } ProviderClientInfo ProviderInfo { get; set; }
Estimate Estimation { get; set; } Estimate Estimation { get; set; }
private PerformerProfile perfer;
public string Topic public string Topic
{ {
get; set; get; set;
@ -43,9 +48,11 @@ namespace Yavsc.Models.Messaging
get; set; 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());
} }
} }
} }

View File

@ -1,43 +0,0 @@
//
// BaseEvent.cs
//
// Author:
// Paul Schneider <paul@pschneider.fr>
//
// 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 <http://www.gnu.org/licenses/>.
using System.ComponentModel.DataAnnotations;
namespace Yavsc.Models.Messaging
{
public class GeneralEvent: BaseEvent, ITitle
{
/// <summary>
/// The title.
/// </summary>
[Required(ErrorMessageResourceName="ChooseATitle")]
[Display(Name="Title")]
public string Title { get; set; }
/// <summary>
/// The description.
/// </summary>
[Required(ErrorMessageResourceName="ChooseADescription")]
[Display(Name="Description")]
public string Description { get; set; }
}
}

View File

@ -22,20 +22,19 @@
namespace Yavsc.Models.Messaging namespace Yavsc.Models.Messaging
{ {
using Interfaces.Workflow; using Interfaces.Workflow;
using Yavsc.Abstract.Messaging;
public class RdvQueryEvent: RdvQueryProviderInfo, IEvent
public class RdvQueryEvent: RdvQueryProviderInfo, IEvent
{ {
public string SubTopic
{
get; private set;
}
public RdvQueryEvent(string subTopic) public RdvQueryEvent(string subTopic)
{ {
Topic = GetType().Name+"/"+subTopic; Topic = MessagingConstants.TopicRdvQuery;
} SubTopic = subTopic;
public string Message
{
get; set;
} }
public string Sender public string Sender
@ -47,6 +46,14 @@ public class RdvQueryEvent: RdvQueryProviderInfo, IEvent
{ {
get; private set; 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);
}
} }
} }

View File

@ -1,48 +0,0 @@
//
// NFEvent.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// 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 <http://www.gnu.org/licenses/>.
using System.ComponentModel.DataAnnotations;
namespace Yavsc.Models.Messaging
{
/// <summary>
/// NF event.
/// </summary>
public class YaEvent : BaseEvent
{
/// <summary>
/// The NF provider identifier.
/// </summary>
[Display(Name="From")]
public string FromUserName { get; set; }
/// <summary>
/// The event web page.
/// </summary>
[Display(Name="EventWebPage")]
public string EventWebPage { get; set; }
/// <summary>
/// The image locator.
/// </summary>
[Display(Name="Photo")]
public string Photo { get; set; }
}
}

View File

@ -7,7 +7,7 @@ namespace Yavsc.Models.Relationship
/// <summary> /// <summary>
/// Position. /// Position.
/// </summary> /// </summary>
public class Position public class Position: IPosition
{ {
/// <summary> /// <summary>
/// The longitude. /// The longitude.

View File

@ -240,6 +240,7 @@
<data name="Full name"><value>Nom complet</value></data> <data name="Full name"><value>Nom complet</value></data>
<data name="EGCMBUTEMAIL"><value>L'envoi du message push a échoué, mais un e-mail a été envoyé</value></data> <data name="EGCMBUTEMAIL"><value>L'envoi du message push a échoué, mais un e-mail a été envoyé</value></data>
<data name="GCM Notifications sent"><value>Message push envoyé</value></data> <data name="GCM Notifications sent"><value>Message push envoyé</value></data>
<data name="GCM Notification sending failed"><value>L'evoi du message Google Cloud a échoué ...</value></data>
<data name="GiveAnExplicitReason"><value>Dites en plus, ci àprès, à propos de cet évennement</value></data> <data name="GiveAnExplicitReason"><value>Dites en plus, ci àprès, à propos de cet évennement</value></data>
<data name="GoogleDidntGeoLocalized"><value>Google n'a pas pu identifier ce lieu</value></data> <data name="GoogleDidntGeoLocalized"><value>Google n'a pas pu identifier ce lieu</value></data>
<data name="Google calendar"><value>Agenda Google</value></data> <data name="Google calendar"><value>Agenda Google</value></data>
@ -463,5 +464,27 @@ Pour ce faire, suivez le lien suivant : &lt;{1}&gt;.
d'au moins {0} et d'au plus {1} caractère(s). </value></data> d'au moins {0} et d'au plus {1} caractère(s). </value></data>
<data name="DetailledMaxStringLength"><value>Ce champ est <data name="DetailledMaxStringLength"><value>Ce champ est
d'au plus {0} caractère(s) ({1} en excès). </value></data> d'au plus {0} caractère(s) ({1} en excès). </value></data>
<data name="EmailSentToPerformer"><value>Un message éléctronique a été envoyé au préstataire.</value></data>
<data name="QueryValidatedNonReg"><value>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}</value></data>
<data name="QueryValidatedRegular"><value>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}</value></data>
</root> </root>

View File

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Yavsc.Interfaces.Workflow;
using Yavsc.Models.Google.Messaging; using Yavsc.Models.Google.Messaging;
using Yavsc.Models.Haircut; using Yavsc.Models.Haircut;
using Yavsc.Models.Messaging; using Yavsc.Models.Messaging;
@ -23,7 +24,9 @@ namespace Yavsc.Services
GoogleAuthSettings googlesettings, GoogleAuthSettings googlesettings,
IEnumerable<string> registrationId, IEnumerable<string> registrationId,
HairCutQueryEvent ev); HairCutQueryEvent ev);
Task<MessageWithPayloadResponse> NotifyAsync(
GoogleAuthSettings _googleSettings,
IEnumerable<string> regids,
IEvent yaev);
} }
} }

View File

@ -11,6 +11,10 @@ using Yavsc.Models;
using Yavsc.Models.Google.Messaging; using Yavsc.Models.Google.Messaging;
using System.Collections.Generic; using System.Collections.Generic;
using Yavsc.Models.Haircut; using Yavsc.Models.Haircut;
using Yavsc.Interfaces.Workflow;
using System.Linq;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Yavsc.Services namespace Yavsc.Services
{ {
@ -19,6 +23,49 @@ namespace Yavsc.Services
// For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 // For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713
public class AuthMessageSender : IEmailSender, IGoogleCloudMessageSender public class AuthMessageSender : IEmailSender, IGoogleCloudMessageSender
{ {
private ILogger _logger;
public AuthMessageSender(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AuthMessageSender>();
}
public async Task <MessageWithPayloadResponse> NotifyEvent<Event>
( GoogleAuthSettings googleSettings, IEnumerable<string> 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<Event>()
{
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<MessageWithPayloadResponse>(msg);
}
}
catch (Exception ex) {
throw new Exception ("Quelque chose s'est mal passé à l'envoi",ex);
}
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -30,18 +77,18 @@ namespace Yavsc.Services
/// </returns> /// </returns>
public async Task<MessageWithPayloadResponse> NotifyBookQueryAsync(GoogleAuthSettings googleSettings, IEnumerable<string> registrationIds, RdvQueryEvent ev) public async Task<MessageWithPayloadResponse> NotifyBookQueryAsync(GoogleAuthSettings googleSettings, IEnumerable<string> registrationIds, RdvQueryEvent ev)
{ {
return await googleSettings.NotifyEvent<RdvQueryEvent>(registrationIds, ev); return await NotifyEvent<RdvQueryEvent>(googleSettings,registrationIds, ev);
} }
public async Task<MessageWithPayloadResponse> NotifyEstimateAsync(GoogleAuthSettings googleSettings, IEnumerable<string> registrationIds, EstimationEvent ev) public async Task<MessageWithPayloadResponse> NotifyEstimateAsync(GoogleAuthSettings googleSettings, IEnumerable<string> registrationIds, EstimationEvent ev)
{ {
return await googleSettings.NotifyEvent<EstimationEvent>(registrationIds, ev); return await NotifyEvent<EstimationEvent>(googleSettings,registrationIds, ev);
} }
public async Task<MessageWithPayloadResponse> NotifyHairCutQueryAsync(GoogleAuthSettings googleSettings, public async Task<MessageWithPayloadResponse> NotifyHairCutQueryAsync(GoogleAuthSettings googleSettings,
IEnumerable<string> registrationIds, HairCutQueryEvent ev) IEnumerable<string> registrationIds, HairCutQueryEvent ev)
{ {
return await googleSettings.NotifyEvent<HairCutQueryEvent>(registrationIds, ev); return await NotifyEvent<HairCutQueryEvent>(googleSettings, registrationIds, ev);
} }
public Task<bool> SendEmailAsync(SiteSettings siteSettings, SmtpSettings smtpSettings, string username, string email, string subject, string message) public Task<bool> SendEmailAsync(SiteSettings siteSettings, SmtpSettings smtpSettings, string username, string email, string subject, string message)
@ -78,16 +125,21 @@ namespace Yavsc.Services
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<MessageWithPayloadResponse> NotifyAsync(GoogleAuthSettings _googleSettings, IEnumerable<string> regids, IEvent yaev)
{
throw new NotImplementedException();
}
/* SMS with Twilio: /* SMS with Twilio:
public Task SendSmsAsync(TwilioSettings twilioSettigns, string number, string message) public Task SendSmsAsync(TwilioSettings twilioSettigns, string number, string message)
{ {
var Twilio = new TwilioRestClient(twilioSettigns.AccountSID, twilioSettigns.Token); var Twilio = new TwilioRestClient(twilioSettigns.AccountSID, twilioSettigns.Token);
var result = Twilio.SendMessage( twilioSettigns.SMSAccountFrom, number, message); var result = Twilio.SendMessage( twilioSettigns.SMSAccountFrom, number, message);
// Status is one of Queued, Sending, Sent, Failed or null if the number is not valid // Status is one of Queued, Sending, Sent, Failed or null if the number is not valid
Trace.TraceInformation(result.Status); Trace.TraceInformation(result.Status);
// Twilio doesn't currently have an async API, so return success. // Twilio doesn't currently have an async API, so return success.
return Task.FromResult(result.Status != "Failed"); return Task.FromResult(result.Status != "Failed");
} */ } */
} }

View File

@ -28,19 +28,20 @@ namespace Yavsc
var appData = Environment.GetEnvironmentVariable("APPDATA"); var appData = Environment.GetEnvironmentVariable("APPDATA");
if (appData == null) if (appData == null)
{ {
logger.LogWarning("AppData was not found in environment variables");
if (SiteSetup.DataDir == null) { if (SiteSetup.DataDir == null) {
SiteSetup.DataDir = "AppData"+env.EnvironmentName; 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); DirectoryInfo di = new DirectoryInfo(SiteSetup.DataDir);
if (!di.Exists) if (!di.Exists)
{ {
di.Create(); di.Create();
logger.LogWarning("Created dir : "+di.FullName); 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); SiteSetup.DataDir = Path.Combine(Directory.GetCurrentDirectory(),di.Name);
Environment.SetEnvironmentVariable("APPDATA", SiteSetup.DataDir); Environment.SetEnvironmentVariable("APPDATA", SiteSetup.DataDir);
logger.LogWarning("AppData was not found in env vars, it has been set to : "+ logger.LogWarning("It has been set to : "+Environment.GetEnvironmentVariable("APPDATA"));
Environment.GetEnvironmentVariable("APPDATA"));
} }
var creds = GoogleSettings?.Account?.private_key; var creds = GoogleSettings?.Account?.private_key;

View File

@ -22,12 +22,14 @@
if (ViewBag.GooglePayload.failure>0) if (ViewBag.GooglePayload.failure>0)
{ {
<h4>@SR["GCM Notification sending failed"]</h4> <h4>@SR["GCM Notification sending failed"]</h4>
} <pre><code>@Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.GooglePayload)</code></pre>
else {
<!-- email sent -->
} }
} }
} }
@if (ViewBag.EmailSent)
{
<h4>@SR["EmailSentToPerformer"]</h4>
}
</div> </div>

View File

@ -0,0 +1,52 @@
@model Yavsc.Models.Identity.GoogleCloudMobileDeclaration
@{
ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>GoogleCloudMobileDeclaration</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.DeclarationDate)
</dt>
<dd>
@Html.DisplayFor(model => model.DeclarationDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.GCMRegistrationId)
</dt>
<dd>
@Html.DisplayFor(model => model.GCMRegistrationId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Model)
</dt>
<dd>
@Html.DisplayFor(model => model.Model)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Platform)
</dt>
<dd>
@Html.DisplayFor(model => model.Platform)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Version)
</dt>
<dd>
@Html.DisplayFor(model => model.Version)
</dd>
</dl>
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</div>
</form>
</div>

View File

@ -0,0 +1,48 @@
@model Yavsc.Models.Identity.GoogleCloudMobileDeclaration
@{
ViewData["Title"] = "Details";
}
<h2>Details</h2>
<div>
<h4>GoogleCloudMobileDeclaration</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.DeclarationDate)
</dt>
<dd>
@Html.DisplayFor(model => model.DeclarationDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.GCMRegistrationId)
</dt>
<dd>
@Html.DisplayFor(model => model.GCMRegistrationId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Model)
</dt>
<dd>
@Html.DisplayFor(model => model.Model)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Platform)
</dt>
<dd>
@Html.DisplayFor(model => model.Platform)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Version)
</dt>
<dd>
@Html.DisplayFor(model => model.Version)
</dd>
</dl>
</div>
<p>
<a asp-action="Edit" asp-route-id="@Model.DeviceId">Edit</a> |
<a asp-action="Index">Back to List</a>
</p>

View File

@ -0,0 +1,52 @@
@model IEnumerable<Yavsc.Models.Identity.GoogleCloudMobileDeclaration>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.DeclarationDate)
</th>
<th>
@Html.DisplayNameFor(model => model.GCMRegistrationId)
</th>
<th>
@Html.DisplayNameFor(model => model.Model)
</th>
<th>
@Html.DisplayNameFor(model => model.Platform)
</th>
<th>
@Html.DisplayNameFor(model => model.Version)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.DeclarationDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.GCMRegistrationId)
</td>
<td>
@Html.DisplayFor(modelItem => item.Model)
</td>
<td>
@Html.DisplayFor(modelItem => item.Platform)
</td>
<td>
@Html.DisplayFor(modelItem => item.Version)
</td>
<td>
<a asp-action="Details" asp-route-id="@item.DeviceId">Details</a> |
<a asp-action="Delete" asp-route-id="@item.DeviceId">Delete</a>
</td>
</tr>
}
</table>

View File

@ -41,6 +41,7 @@
@using Microsoft.Extensions.PlatformAbstractions; @using Microsoft.Extensions.PlatformAbstractions;
@using PayPal.PayPalAPIInterfaceService.Model; @using PayPal.PayPalAPIInterfaceService.Model;
@inject IViewLocalizer LocString @inject IViewLocalizer LocString
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers" @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*, Yavsc" @addTagHelper "*, Yavsc"

View File

@ -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;
}
} }
} }

View File

@ -1,7 +1,7 @@
{ {
"sdk": { "sdk": {
"version": "2.0.4", "version": "2.0.4",
"runtime": "mono", "runtime": "mono",
"architecture": "x64" "architecture": "x64"
} }
} }

7
test/packages.config Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.NET.Test.Sdk" version="15.5.0" targetFramework="net45" />
<package id="xunit" version="2.3.1" targetFramework="net45" />
<package id="xunit.runner.visualstudio" version="2.3.1" targetFramework="net45" />
<package id="xunit.runner.console" version="2.3.1" targetFramework="net45" />
</packages>