
The main server owns the migrations, it's the server part, it's simpler. It's Yavsc, not one of its lib.
472 lines
21 KiB
C#
472 lines
21 KiB
C#
using System.Security.Claims;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Identity;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Localization;
|
||
|
||
namespace Yavsc.Controllers
|
||
{
|
||
using Yavsc.Helpers;
|
||
using Yavsc.Models;
|
||
using Yavsc.Models.Google.Messaging;
|
||
using Yavsc.Models.Relationship;
|
||
using Yavsc.Services;
|
||
using Newtonsoft.Json;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Yavsc.Extensions;
|
||
using Yavsc.Models.Haircut;
|
||
using System.Globalization;
|
||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||
using System.Collections.Generic;
|
||
using Yavsc.Models.Messaging;
|
||
using PayPal.PayPalAPIInterfaceService.Model;
|
||
using Microsoft.Extensions.Options;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||
using Yavsc.Interface;
|
||
using Yavsc.Settings;
|
||
using Yavsc.Abstract.Models.Messaging;
|
||
using Yavsc.Server.Helpers;
|
||
|
||
public class HairCutCommandController : CommandController
|
||
{
|
||
readonly PayPalSettings payPalSettings;
|
||
public HairCutCommandController(ApplicationDbContext context,
|
||
IOptions<PayPalSettings> payPalSettings,
|
||
IOptions<GoogleAuthSettings> googleSettings,
|
||
IYavscMessageSender GCMSender,
|
||
UserManager<ApplicationUser> userManager,
|
||
IStringLocalizer<Yavsc.YavscLocalization> localizer,
|
||
ITrueEmailSender emailSender,
|
||
IOptions<SmtpSettings> smtpSettings,
|
||
IOptions<SiteSettings> siteSettings,
|
||
ICalendarManager calManager,
|
||
ILoggerFactory loggerFactory) : base(context, googleSettings, GCMSender, userManager,
|
||
calManager, localizer, emailSender, smtpSettings, siteSettings, loggerFactory)
|
||
{
|
||
this.payPalSettings = payPalSettings.Value;
|
||
}
|
||
|
||
|
||
private async Task<HairCutQuery> GetQuery(long id)
|
||
{
|
||
var query = await _context.HairCutQueries
|
||
.Include(x => x.Location)
|
||
.Include(x => x.PerformerProfile)
|
||
.Include(x => x.Prestation)
|
||
.Include(x => x.PerformerProfile.Performer)
|
||
.Include(x => x.PerformerProfile.Performer.DeviceDeclaration)
|
||
.Include(x => x.Regularisation)
|
||
.SingleAsync(m => m.Id == id);
|
||
query.SelectedProfile = await _context.BrusherProfile.SingleAsync(b => b.UserId == query.PerformerId);
|
||
return query;
|
||
}
|
||
public async Task<IActionResult> ClientCancel(long id)
|
||
{
|
||
HairCutQuery command = await GetQuery(id);
|
||
if (command == null)
|
||
{
|
||
return NotFound();
|
||
}
|
||
SetViewBagPaymentUrls(id);
|
||
return View(command);
|
||
}
|
||
public async Task<IActionResult> PaymentConfirmation([FromRoute] long id, string token, string PayerID)
|
||
{
|
||
HairCutQuery command = await GetQuery(id);
|
||
if (command == null)
|
||
{
|
||
return NotFound();
|
||
}
|
||
var paymentInfo = await _context.ConfirmPayment(User.GetUserId(), PayerID, token);
|
||
ViewData["paymentinfo"] = paymentInfo;
|
||
command.Regularisation = paymentInfo.DbContent;
|
||
command.PaymentId = token;
|
||
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;
|
||
}
|
||
else _logger.LogError
|
||
("This Command were yet validated, and is now paied one more ...");
|
||
}
|
||
await _context.SaveChangesAsync(User.GetUserId());
|
||
SetViewBagPaymentUrls(id);
|
||
if (paymentOk)
|
||
{
|
||
MessageWithPayloadResponse grep = null;
|
||
var yaev = command.CreatePaymentEvent(paymentInfo, _localizer);
|
||
if (command.PerformerProfile.AcceptNotifications)
|
||
{
|
||
if (command.PerformerProfile.Performer.DeviceDeclaration.Count > 0)
|
||
{
|
||
var regid = command.PerformerProfile.PerformerId;
|
||
grep = await _MessageSender.NotifyAsync(new [] {regid}, 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;
|
||
}
|
||
|
||
ViewBag.EmailSent = await _emailSender.SendEmailAsync(
|
||
command.PerformerProfile.Performer.UserName,
|
||
command.PerformerProfile.Performer.Email,
|
||
yaev.Topic,
|
||
yaev.CreateBody()
|
||
);
|
||
}
|
||
|
||
ViewData["Notify"] = new List<Notification> {
|
||
new Notification {
|
||
title= "Paiment PayPal",
|
||
body = "Votre paiment a été accépté."
|
||
}
|
||
};
|
||
return View("Details", command);
|
||
}
|
||
|
||
private void SetViewBagPaymentUrls(long id)
|
||
{
|
||
ViewBag.CreatePaymentUrl = Request.ToAbsolute("api/haircut/createpayment/" + id);
|
||
ViewBag.ExecutePaymentUrl = Request.ToAbsolute("api/payment/execute");
|
||
ViewBag.Urls = Request.GetPaymentUrls("HairCutCommand", id.ToString());
|
||
}
|
||
public async Task<IActionResult> ClientCancelConfirm(long id)
|
||
{
|
||
var query = await GetQuery(id); if (query == null)
|
||
{
|
||
return NotFound();
|
||
}
|
||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
if (query.ClientId != uid)
|
||
return new ChallengeResult();
|
||
_context.HairCutQueries.Remove(query);
|
||
await _context.SaveChangesAsync();
|
||
return await Index();
|
||
}
|
||
/// <summary>
|
||
/// List client's queries (and only client's ones)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override async Task<IActionResult> Index()
|
||
{
|
||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
return View("Index", await _context.HairCutQueries
|
||
.Include(x => x.Client)
|
||
.Include(x => x.PerformerProfile)
|
||
.Include(x => x.PerformerProfile.Performer)
|
||
.Include(x => x.Location)
|
||
.Where(x => x.ClientId == uid)
|
||
.ToListAsync());
|
||
}
|
||
|
||
public override async Task<IActionResult> Details(long id)
|
||
{
|
||
HairCutQuery command = await _context.HairCutQueries
|
||
.Include(x => x.Location)
|
||
.Include(x => x.PerformerProfile)
|
||
.Include(x => x.Prestation)
|
||
.Include(x => x.PerformerProfile.Performer)
|
||
.Include(x => x.Regularisation)
|
||
.SingleOrDefaultAsync(m => m.Id == id);
|
||
if (command == null)
|
||
{
|
||
return NotFound();
|
||
}
|
||
SetViewBagPaymentUrls(id);
|
||
return View(command);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Crée une requête en coiffure à domicile
|
||
///
|
||
/// </summary>
|
||
/// <param name="model"></param>
|
||
/// <param name="taintIds"></param>
|
||
/// <returns></returns>
|
||
[HttpPost, Authorize]
|
||
[ValidateAntiForgeryToken]
|
||
public async Task<IActionResult> CreateHairCutQuery(HairCutQuery model, string taintIds)
|
||
{
|
||
// TODO utiliser Markdown-av+tags
|
||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
model.ClientId = uid;
|
||
|
||
var prid = model.PerformerId;
|
||
var brusherProfile = await _context.BrusherProfile.SingleAsync(p => p.UserId == prid);
|
||
long[] longtaintIds = null;
|
||
List<HairTaint> colors = null;
|
||
|
||
if (string.IsNullOrWhiteSpace(uid)
|
||
|| string.IsNullOrWhiteSpace(prid))
|
||
throw new InvalidOperationException(
|
||
"This method needs a PerformerId"
|
||
);
|
||
|
||
|
||
if (!model.Consent)
|
||
ModelState.AddModelError("Consent", "Vous devez accepter les conditions générales de vente de ce service");
|
||
|
||
if (ModelState.IsValid)
|
||
{
|
||
_logger.LogInformation("le Model _est_ valide.");
|
||
var pro = _context.Performers.Include(
|
||
u => u.Performer
|
||
).Include(u => u.Performer.DeviceDeclaration)
|
||
.FirstOrDefault(
|
||
x => x.PerformerId == model.PerformerId
|
||
);
|
||
|
||
|
||
if (taintIds != null)
|
||
{
|
||
longtaintIds = taintIds.Split(',').Select(s => long.Parse(s)).ToArray();
|
||
colors = _context.HairTaint.Where(t => longtaintIds.Contains(t.Id)).ToList();
|
||
// a Prestation is required
|
||
model.Prestation.Taints = colors.Select(c =>
|
||
new HairTaintInstance { Taint = c }).ToList();
|
||
}
|
||
|
||
// Une prestation pour enfant ou homme inclut toujours la coupe.
|
||
if (model.Prestation.Gender != HairCutGenders.Women)
|
||
model.Prestation.Cut = true;
|
||
if (model.Location != null)
|
||
{
|
||
var existingLocation = await _context.Locations.FirstOrDefaultAsync(x => x.Address == model.Location.Address
|
||
&& x.Longitude == model.Location.Longitude && x.Latitude == model.Location.Latitude);
|
||
|
||
if (existingLocation != null)
|
||
{
|
||
model.Location = existingLocation;
|
||
}
|
||
else _context.Attach<Location>(model.Location);
|
||
}
|
||
var existingPrestation = await _context.HairPrestation.FirstOrDefaultAsync(x => model.PrestationId == x.Id);
|
||
|
||
if (existingPrestation != null)
|
||
{
|
||
model.Prestation = existingPrestation;
|
||
}
|
||
else _context.Attach<HairPrestation>(model.Prestation);
|
||
|
||
_context.HairCutQueries.Add(model);
|
||
|
||
await _context.SaveChangesAsync(uid);
|
||
_logger.LogInformation("la donnée _est_ sauvée:");
|
||
MessageWithPayloadResponse grep = null;
|
||
model.SelectedProfile = brusherProfile;
|
||
model.Client = await _userManager.FindByIdAsync(uid);
|
||
_logger.LogInformation(JsonConvert.SerializeObject(model));
|
||
var yaev = model.CreateNewHairCutQueryEvent(_localizer);
|
||
|
||
if (pro.AcceptPublicContact)
|
||
{
|
||
if (pro.AcceptNotifications)
|
||
{
|
||
if (pro.Performer.DeviceDeclaration.Count > 0)
|
||
{
|
||
var uids = new[] { pro.PerformerId };
|
||
grep = await _MessageSender.NotifyHairCutQueryAsync(uids, 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;
|
||
if (grep != null)
|
||
_logger.LogWarning($"Performer: {pro.Performer.UserName} success: {grep.success} failure: {grep.failure}");
|
||
}
|
||
// TODO if pro.AllowCalendarEventInsert
|
||
if (pro.Performer.DedicatedGoogleCalendar != null && yaev.EventDate != null)
|
||
{
|
||
_logger.LogInformation("Inserting an event in the calendar");
|
||
DateTime evdate = yaev.EventDate ?? new DateTime();
|
||
var result = await _calendarManager.CreateEventAsync(pro.Performer.Id,
|
||
pro.Performer.DedicatedGoogleCalendar,
|
||
evdate, 3600, yaev.Topic, yaev.Client.UserName + " : " + yaev.Reason,
|
||
yaev.Location?.Address, false
|
||
);
|
||
if (result.Id == null)
|
||
_logger.LogWarning("Something went wrong, calendar event not created");
|
||
}
|
||
else _logger.LogWarning($"Calendar: {pro.Performer.DedicatedGoogleCalendar != null}\nEventDate: {yaev.EventDate != null}");
|
||
|
||
await _emailSender.SendEmailAsync(
|
||
pro.Performer.UserName,
|
||
pro.Performer.Email,
|
||
$"{yaev.Client.UserName}: {yaev.Reason}",
|
||
$"{yaev.Reason}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
// TODO if (AcceptProContact) try & find a bookmaker to send him this query
|
||
}
|
||
ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == model.ActivityCode);
|
||
ViewBag.GoogleSettings = _googleSettings;
|
||
var items = model.GetBillItems();
|
||
var addition = items.Addition();
|
||
ViewBag.Addition = addition.ToString("C", CultureInfo.CurrentUICulture);
|
||
return View("CommandConfirmation", model);
|
||
}
|
||
ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == model.ActivityCode);
|
||
ViewBag.GoogleSettings = _googleSettings;
|
||
model.SelectedProfile = brusherProfile;
|
||
|
||
SetViewData(model.ActivityCode, model.PerformerId, model.Prestation);
|
||
return View("HairCut", model);
|
||
}
|
||
|
||
|
||
public async Task<ActionResult> HairCut(string performerId, string activityCode)
|
||
{
|
||
HairPrestation pPrestation = null;
|
||
var prestaJson = HttpContext.Session.GetString("HairCutPresta");
|
||
if (prestaJson != null)
|
||
{
|
||
pPrestation = JsonConvert.DeserializeObject<HairPrestation>(prestaJson);
|
||
}
|
||
else
|
||
{
|
||
pPrestation = new HairPrestation { };
|
||
}
|
||
|
||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
var user = await _userManager.FindByIdAsync(uid);
|
||
|
||
SetViewData(activityCode, performerId, pPrestation);
|
||
|
||
var perfer = _context.Performers.Include(
|
||
p => p.Performer
|
||
).Single(p => p.PerformerId == performerId);
|
||
var result = new HairCutQuery
|
||
{
|
||
PerformerProfile = perfer,
|
||
PerformerId = perfer.PerformerId,
|
||
ClientId = uid,
|
||
Prestation = pPrestation,
|
||
Client = user,
|
||
Location = new Location { Address = "" },
|
||
EventDate = new DateTime()
|
||
};
|
||
return View(result);
|
||
}
|
||
private void SetViewData(string activityCode, string performerId, HairPrestation pPrestation)
|
||
{
|
||
ViewBag.HairTaints = _context.HairTaint.Include(t => t.Color);
|
||
ViewBag.HairTaintsItems = _context.HairTaint.Include(t => t.Color).Select(
|
||
c =>
|
||
new SelectListItem
|
||
{
|
||
Text = c.Color.Name + " " + c.Brand,
|
||
Value = c.Id.ToString()
|
||
}
|
||
);
|
||
ViewBag.HairTechnos = EnumExtensions.GetSelectList(typeof(HairTechnos), _localizer);
|
||
ViewBag.HairLength = EnumExtensions.GetSelectList(typeof(HairLength), _localizer);
|
||
ViewBag.Activity = _context.Activities.First(a => a.Code == activityCode);
|
||
ViewBag.Gender = EnumExtensions.GetSelectList(typeof(HairCutGenders), _localizer, HairCutGenders.Women);
|
||
ViewBag.HairDressings = EnumExtensions.GetSelectList(typeof(HairDressings), _localizer);
|
||
ViewBag.ColorsClass = (pPrestation.Tech == HairTechnos.Color
|
||
|| pPrestation.Tech == HairTechnos.Mech) ? "" : "hidden";
|
||
ViewBag.TechClass = (pPrestation.Gender == HairCutGenders.Women) ? "" : "hidden";
|
||
ViewData["PerfPrefs"] = _context.BrusherProfile.Single(p => p.UserId == performerId);
|
||
}
|
||
|
||
[HttpPost, Authorize]
|
||
[ValidateAntiForgeryToken]
|
||
public async Task<IActionResult> CreateHairMultiCutQuery(HairMultiCutQuery command)
|
||
{
|
||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||
var prid = command.PerformerId;
|
||
if (string.IsNullOrWhiteSpace(uid)
|
||
|| string.IsNullOrWhiteSpace(prid))
|
||
throw new InvalidOperationException(
|
||
"This method needs a PerformerId"
|
||
);
|
||
var pro = _context.Performers.Include(
|
||
u => u.Performer
|
||
).Include(u => u.Performer.DeviceDeclaration)
|
||
.FirstOrDefault(
|
||
x => x.PerformerId == command.PerformerId
|
||
);
|
||
var user = await _userManager.FindByIdAsync(uid);
|
||
command.Client = user;
|
||
command.ClientId = uid;
|
||
command.PerformerProfile = pro;
|
||
// FIXME Why!!
|
||
// ModelState.ClearValidationState("PerformerProfile.Avatar");
|
||
// ModelState.ClearValidationState("Client.Avatar");
|
||
// ModelState.ClearValidationState("ClientId");
|
||
ModelState.MarkFieldSkipped("ClientId");
|
||
|
||
if (ModelState.IsValid)
|
||
{
|
||
var existingLocation = _context.Locations.FirstOrDefault(x => x.Address == command.Location.Address
|
||
&& x.Longitude == command.Location.Longitude && x.Latitude == command.Location.Latitude);
|
||
|
||
if (existingLocation != null)
|
||
{
|
||
command.Location = existingLocation;
|
||
}
|
||
else _context.Attach<Location>(command.Location);
|
||
|
||
_context.HairMultiCutQueries.Add(command);
|
||
_context.SaveChanges(User.GetUserId());
|
||
var brSettings = await _context.BrusherProfile.SingleAsync(
|
||
bp => bp.UserId == command.PerformerId
|
||
);
|
||
var yaev = command.CreateEvent(_localizer, brSettings);
|
||
string msg = yaev.CreateBoby();
|
||
MessageWithPayloadResponse grep = null;
|
||
|
||
if (pro.AcceptNotifications
|
||
&& pro.AcceptPublicContact)
|
||
{
|
||
if (pro.Performer.DeviceDeclaration?.Count > 0)
|
||
{
|
||
var uids = new [] { command.PerformerProfile.PerformerId };
|
||
grep = await _MessageSender.NotifyHairCutQueryAsync(uids, yaev);
|
||
}
|
||
// TODO setup a profile choice to allow notifications
|
||
// both on mailbox and mobile, and to allow calendar event insertion.
|
||
// if (grep==null || grep.success<=0 || grep.failure>0)
|
||
ViewBag.GooglePayload = grep;
|
||
if (grep != null)
|
||
_logger.LogWarning($"Performer: {command.PerformerProfile.Performer.UserName} success: {grep.success} failure: {grep.failure}");
|
||
|
||
|
||
if (pro.Performer.DedicatedGoogleCalendar != null && yaev.EventDate != null)
|
||
{
|
||
DateTime evdate = yaev.EventDate ?? new DateTime();
|
||
await _calendarManager.CreateEventAsync(
|
||
pro.Performer.Id,
|
||
pro.Performer.DedicatedGoogleCalendar,
|
||
evdate, 3600, yaev.Topic, msg,
|
||
yaev.Location?.ToString(), false
|
||
);
|
||
}
|
||
|
||
await _emailSender.SendEmailAsync(
|
||
command.PerformerProfile.Performer.UserName,
|
||
command.PerformerProfile.Performer.Email,
|
||
yaev.Topic + " " + yaev.Sender,
|
||
$"{msg}\r\n-- \r\n{yaev.Previsional}\r\n{yaev.EventDate}\r\n"
|
||
);
|
||
}
|
||
ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == command.ActivityCode);
|
||
ViewBag.GoogleSettings = _googleSettings;
|
||
return View("CommandConfirmation", command);
|
||
}
|
||
ViewBag.Activity = _context.Activities.FirstOrDefault(a => a.Code == command.ActivityCode);
|
||
ViewBag.GoogleSettings = _googleSettings;
|
||
return View("HairCut", command);
|
||
}
|
||
}
|
||
}
|