yavsc/web/Controllers/FrontOfficeController.cs
Paul Schneider a99232ba2b Implémente un formulaire simple
de réservation d'un préstataire

* p8-av4.xxs.jpg:
* p8-av4.xxs.png: inutile

* NoLogin.master:
* Entity.cs:
* OAuth2.cs:
* ApiClient.cs:
* PeopleApi.cs:
* MapTracks.cs:
* SkillManager.cs:
* Skills.aspx:
* EntityQuery.cs:
* CalendarApi.cs:
* SimpleJsonPostMethod.cs:
* GoogleHelpers.cs:
* EventPub.aspx:
* GoogleController.cs:
* Notification.cs:
* UserSkills.aspx:
* BackOfficeController.cs:
* BackOfficeController.cs:
* Notification.cs:
* MessageWithPayLoad.cs:
* MessageWithPayloadResponse.cs: refabrication

* IContentProvider.cs:
* NpgsqlBlogProvider.cs: xml doc

* NpgsqlContentProvider.cs: implemente un listing des prestataire du
  code APE en base.

* NpgsqlSkillProvider.cs: implemente un listing des domaines de
  compétence du préstataire en base.

* XmlCatalogProvider.cs: Le catalogue de vente implémente mainenant
  l'interface d'un fournisseur de donnée comme les autres.
Il pourrait par exemple vouloir définir des activité et des
  compétences.
Pour l'instant, il n'est pas activé par la configuration, et reste le
  fournisseur du catalogue legacy (voir </FrontOffice/Catalog> ).

* FrontOfficeController.cs: format du code

* Global.asax.cs: Une route customisée pour le Front Office : /do
  (genre, ici, ça bouge.)

* activity.sql: implémente en base de donnée le modèle des activités
  et compétences,
ajoute aussi deux activités : l'edition logicielle et "Artiste"

* style.css: changement de mes images de fond ... tombées du camion de
  Xavier et onlinehome.us

* p8-av4.s.jpg: changement de taille

* AccountController.cs: Met le code MEA à "none" quand il est spécifié
  non disponible.

* BlogsController.cs: fixe un bug de l'edition d'un billet

* FrontOfficeController.cs: implemente le contrôle booking simple

* HomeController.cs: ajoute l'assemblage du catalog dans le listing
  dédié

* YavscAjaxHelper.cs: Implemente un outil de representation JSon des
  objets côté serveur

* parallax.js: deux fois plus de mouvement autout de x dans le
  parallax

* yavsc.rate.js: imlemente un callback JS pour le rating

* Activities.aspx: Des labels au formulaire de déclaration des
  activités

* Activity.ascx: un panneau activité descent

* Booking.aspx: implemente l'UI web du booking simple.

* EavyBooking.aspx: refabrication du booking lourd

* Index.aspx: supprime le panneau du tag Accueil, affiche les
  activités en cours du site (avec au moins un préstataire valide pour
  cette activité)

* Web.config: Implemente une cote utilisateur, par une nouvelle valeur
  de son profile (Rate).

* Yavsc.csproj: refabrique du code API Google, qui part dans le model.

* MarkdownDeep.dll: le tag <p> ne convenait pas, le remplacer par le
  tag <span> non plus.
Maintenant ça devrait être correct, c'est un div, mais que en cas de
  tag englobant non défini.

* BookingQuery.cs: Le booking lourd devient une commande basée sur des
  activités concernée par l'intervention

* ChangeLog: nettoyage

* CatalogProvider.cs: implemente l'interface d'un fournissseur de
  contenu

* PerformerProfile.cs: implemente le profile prestataire

* SimpleBookingQuery.cs: Les besoin sont exprimé sous forme d'un
  tableau de valeur du parametrage de la commande

* LocalizedText.resx:
* LocalizedText.fr.resx:
* LocalizedText.Designer.cs:
* LocalizedText.fr.Designer.cs: internationalisation

* Profile.cs: implemente un accès à l'id d'enregistrement Google GCM

* SkillEntity.cs: La compétence appartient à un domaine d'activité, on
  lui associe un et un seul code APE

* SkillProvider.cs: Fait chercher les compétences à partir d'un code
  activité

* WorkFlowManager.cs: implemente l'accès à la liste des préstataires
de telle activité

* YavscModel.csproj: refabrications

* Skills.sql: vient de passer dans activity.Sql

* T.cs: la traduction est faite plus simple à appeler (sans cast vers
  `string`).
2015-11-28 18:34:52 +01:00

457 lines
13 KiB
C#

using System;
using Yavsc;
using System.Web.Mvc;
using System.Web;
using System.Text.RegularExpressions;
using System.IO;
using Yavsc.Controllers;
using System.Collections.Generic;
using Yavsc.Model;
using Yavsc.Model.WorkFlow;
using System.Web.Security;
using System.Threading;
using Yavsc.Model.FrontOffice;
using Yavsc.Model.FileSystem;
using Yavsc.Model.Calendar;
using System.Configuration;
using Yavsc.Helpers;
using Yavsc.Model.FrontOffice.Catalog;
using Yavsc.Model.Skill;
using System.Web.Profile;
using Yavsc.Model.Google.Api;
using System.Net;
using System.Linq;
namespace Yavsc.Controllers
{
/// <summary>
/// Front office controller.
/// Access granted to all
/// </summary>
public class FrontOfficeController : Controller
{
/// <summary>
/// Index this instance.
/// </summary>
public ActionResult Index ()
{
return View ();
}
/// <summary>
/// Pub the Event
/// </summary>
/// <returns>The pub.</returns>
/// <param name="model">Model.</param>
public ActionResult EventPub (EventPub model)
{
return View (model);
}
/// <summary>
/// Estimates released to this client
/// </summary>
[Authorize]
public ActionResult Estimates (string client)
{
var u = Membership.GetUser ();
if (u == null) // There was no redirection to any login page
throw new ConfigurationErrorsException ("no redirection to any login page");
string username = u.UserName;
Estimate[] estims = WorkFlowManager.GetUserEstimates (username);
ViewData ["UserName"] = username;
ViewData ["ResponsibleCount"] =
Array.FindAll (
estims,
x => x.Responsible == username).Length;
ViewData ["ClientCount"] =
Array.FindAll (
estims,
x => x.Client == username).Length;
return View (estims);
}
/// <summary>
/// Estimate wearing the specified id.
/// </summary>
/// <param name="id">Estim Identifier.</param>
public ActionResult Get (long id)
{
Estimate f = WorkFlowManager.GetEstimate (id);
if (f == null) {
ModelState.AddModelError ("Id", "Wrong Id");
return View (new Estimate () { Id = id });
}
return View (f);
}
/// <summary>
/// Estimate the specified model and submit.
/// </summary>
/// <param name="model">Model.</param>
/// <param name="submit">Submit.</param>
[Authorize]
public ActionResult Estimate (Estimate model, string submit)
{
string username = Membership.GetUser ().UserName;
// Obsolete, set in master page
ViewData ["WebApiBase"] = Url.Content (Yavsc.WebApiConfig.UrlPrefixRelative);
ViewData ["WABASEWF"] = ViewData ["WebApiBase"] + "/WorkFlow";
if (submit == null) {
if (model.Id > 0) {
Estimate f = WorkFlowManager.GetEstimate (model.Id);
if (f == null) {
ModelState.AddModelError ("Id", "Wrong Id");
return View (model);
}
model = f;
ModelState.Clear ();
if (username != model.Responsible
&& username != model.Client
&& !Roles.IsUserInRole ("FrontOffice"))
throw new UnauthorizedAccessException ("You're not allowed to view this estimate");
} else if (model.Id == 0) {
if (string.IsNullOrWhiteSpace (model.Responsible))
model.Responsible = username;
}
} else {
if (model.Id == 0) // if (submit == "Create")
if (string.IsNullOrWhiteSpace (model.Responsible))
model.Responsible = username;
if (username != model.Responsible
&& !Roles.IsUserInRole ("FrontOffice"))
throw new UnauthorizedAccessException ("You're not allowed to modify this estimate");
if (ModelState.IsValid) {
if (model.Id == 0)
model = WorkFlowManager.CreateEstimate (
username,
model.Client, model.Title, model.Description);
else {
WorkFlowManager.UpdateEstimate (model);
model = WorkFlowManager.GetEstimate (model.Id);
}
}
}
return View (model);
}
/// <summary>
/// Catalog this instance.
/// </summary>
[AcceptVerbs ("GET")]
public ActionResult Catalog ()
{
return View (
CatalogManager.GetCatalog ()
);
}
/// <summary>
/// Catalog this instance.
/// </summary>
[AcceptVerbs ("GET")]
public ActionResult Brand (string brandid)
{
Catalog c = CatalogManager.GetCatalog ();
ViewData ["BrandName"] = brandid;
return View (c.GetBrand (brandid));
}
/// <summary>
/// get the product category
/// </summary>
/// <returns>The category object.</returns>
/// <param name="brandid">Brand id.</param>
/// <param name="pcid">Product category Id.</param>
[AcceptVerbs ("GET")]
public ActionResult ProductCategory (string brandid, string pcid)
{
ViewData ["BrandId"] = brandid;
ViewData ["ProductCategoryId"] = pcid;
var cat = CatalogManager.GetCatalog ();
if (cat == null)
throw new Exception ("No catalog");
var brand = cat.GetBrand (brandid);
if (brand == null)
throw new Exception ("Not a brand id: " + brandid);
var pcat = brand.GetProductCategory (pcid);
if (pcat == null)
throw new Exception ("Not a product category id in this brand: " + pcid);
return View (pcat);
}
/// <summary>
/// Product the specified id, pc and pref.
/// </summary>
/// <param name="id">Brand Identifier.</param>
/// <param name="pc">Production catalog reference.</param>
/// <param name="pref">Preference.</param>
[AcceptVerbs ("GET")]
public ActionResult Product (string id, string pc, string pref)
{
Product p = null;
ViewData ["BrandName"] = id;
ViewData ["ProdCatRef"] = pc;
ViewData ["ProdRef"] = pref;
Catalog cat = CatalogManager.GetCatalog ();
if (cat == null) {
YavscHelpers.Notify (ViewData, "Catalog introuvable");
ViewData ["RefType"] = "Catalog";
return View ("ReferenceNotFound");
}
Brand b = cat.GetBrand (id);
if (b == null) {
ViewData ["RefType"] = "Brand";
return View ("ReferenceNotFound");
}
ProductCategory pcat = b.GetProductCategory (pc);
if (pcat == null) {
ViewData ["RefType"] = "ProductCategory";
return View ("ReferenceNotFound");
}
ViewData ["ProdCatName"] = pcat.Name;
p = pcat.GetProduct (pref);
if (p.CommandForm == null)
p.CommandForm = b.DefaultForm;
return View ((p is Service) ? "Service" : "Product", p);
}
/// <summary>
/// Basket this instance.
/// </summary>
[Authorize]
public ActionResult Basket ()
{
return View (WorkFlowManager.GetCommands (Membership.GetUser ().UserName));
}
/// <summary>
/// Command the specified collection.
/// </summary>
/// <param name="collection">Collection.</param>
[HttpPost]
[Authorize]
public ActionResult Command (FormCollection collection)
{
try {
// Add specified product command to the basket,
// saves it in db
new Command (collection, HttpContext.Request.Files);
YavscHelpers.Notify (ViewData, LocalizedText.Item_added_to_basket);
return View (collection);
} catch (Exception e) {
YavscHelpers.Notify (ViewData, "Exception:" + e.Message);
return View (collection);
}
}
/// <summary>
/// Booking the specified model.
/// </summary>
/// <param name="model">Model.</param>
public ActionResult EavyBooking (BookingQuery model)
{
return View (model);
}
/// <summary>
/// Skills the specified model.
/// </summary>
[Authorize (Roles = "Admin")]
public ActionResult Skills (string search)
{
if (search == null)
search = "%";
var skills = SkillManager.FindSkill (search);
return View (skills);
}
/// <summary>
/// Performers on this MEA.
/// fr
/// Liste des prestataires dont
/// l'activité principale est celle spécifiée
/// </summary>
/// <param name="id">Identifiant APE de l'activité.</param>
public ActionResult Performers (string id)
{
throw new NotImplementedException ();
}
/// <summary>
/// Activities the specified search and toPower.
/// </summary>
/// <param name="search">Search.</param>
/// <param name="toPower">If set to <c>true</c> to power.</param>
public ActionResult Activities (string id, bool toPower = false)
{
if (id == null)
id = "%";
var activities = WorkFlowManager.FindActivity (id, !toPower);
return View (activities);
}
/// <summary>
/// Activity at the specified id.
/// </summary>
/// <param name="id">Identifier.</param>
public ActionResult Activity (string id)
{
return View (WorkFlowManager.GetActivity (id));
}
/// <summary>
/// Display and should
/// offer Ajax edition of
/// user's skills.
/// </summary>
/// <param name="id">the User name.</param>
[Authorize ()]
public ActionResult UserSkills (string id)
{
if (id == null)
id = User.Identity.Name;
// TODO or not to do, handle a skills profile update,
// actually performed via the Web API :-°
// else if (ModelState.IsValid) {}
var usp = SkillManager.GetUserSkills (id);
var skills = SkillManager.FindSkill ("%");
ViewData ["SiteSkills"] = skills;
return View (usp);
}
/// <summary>
/// Dates the query.
/// </summary>
/// <returns>The query.</returns>
/// <param name="model">Model.</param>
[Authorize,HttpPost]
public ActionResult Book (BookingQuery model)
{
DateTime mindate = DateTime.Now;
if (model.StartDate.Date < mindate.Date) {
ModelState.AddModelError ("StartDate", LocalizedText.FillInAFutureDate);
}
if (model.EndDate < model.StartDate)
ModelState.AddModelError ("EndDate", LocalizedText.StartDateAfterEndDate);
if (ModelState.IsValid) {
var result = new List<PerformerProfile> ();
foreach (string meacode in model.MEACodes) {
foreach (PerformerProfile profile in WorkFlowManager.FindPerformer(meacode)) {
try {
var events = ProfileBase.Create (profile.UserName).GetEvents (model.StartDate, model.EndDate);
if (events.items.Length == 0)
result.Add (profile);
} catch (WebException ex) {
string response;
using (var stream = ex.Response.GetResponseStream ()) {
using (var reader = new StreamReader (stream)) {
response = reader.ReadToEnd ();
stream.Close ();
}
YavscHelpers.Notify (ViewData,
string.Format (
"Google calendar API exception {0} : {1}<br><pre>{2}</pre>",
ex.Status.ToString (),
ex.Message,
response));
}
}
}
}
return View ("Performers", result.ToArray ());
}
return View (model);
}
/// <summary>
/// Booking the specified model.
/// </summary>
/// <param name="MEACode">MEA Code.</param>
/// <param name="model">Model.</param>
public ActionResult Booking (SimpleBookingQuery model)
{
// In order to present this form
// with no need selected and without
// validation error display,
// we only check the need here, not at validation time.
// Although, the need is indeed cruxial requirement,
// but we already have got a MEA code
if (ModelState.IsValid)
if (model.Needs != null) {
var result = new List<PerformerAvailability> ();
foreach (PerformerProfile profile in WorkFlowManager.FindPerformer(model.MEACode)) {
if (profile.HasCalendar ()) {
try {
var events = ProfileBase.Create (profile.UserName)
.GetEvents (
model.PreferedDate.Date,
model.PreferedDate.AddDays (1).Date);
// TODO replace (events.items.Length == 0)
// with a descent computing of dates and times claims, calendar,
// AND performer preferences, perhaps also client preferences
result.Add (profile.CreateAvailability (model.PreferedDate, (events.items.Length == 0)));
} catch (WebException ex) {
HandleWebException (ex, "Google Calendar Api");
}
} else
result.Add (profile.CreateAvailability (model.PreferedDate, false));
}
return View ("Performers", result.ToArray ());
} else {
// A first Get
var needs = SkillManager.FindSkill ("%", model.MEACode);
ViewData ["Needs"] = needs;
model.Needs = needs.Select (
x => string.Format ("{0}:{1}", x.Id, x.Rate)).ToArray ();
}
var activity = WorkFlowManager.GetActivity (model.MEACode);
ViewData ["Activity"] = activity;
ViewData ["Title"] = activity.Title;
ViewData ["Comment"] = activity.Comment;
ViewData ["Photo"] = activity.Photo;
if (model.PreferedDate < DateTime.Now)
model.PreferedDate = DateTime.Now;
return View (model);
}
private void HandleWebException (WebException ex, string context)
{
string response = "";
using (var stream = ex.Response.GetResponseStream ()) {
if (stream.CanRead) {
var reader = new StreamReader (stream);
response = reader.ReadToEnd ();
reader.Close ();
reader.DiscardBufferedData ();
reader.Dispose ();
}
stream.Close ();
stream.Dispose ();
}
YavscHelpers.Notify (ViewData,
string.Format (
"{3} exception {0} : {1}<br><pre>{2}</pre>",
ex.Status.ToString (),
ex.Message,
response,
context
));
}
}
}