This commit is contained in:
Paul Schneider 2026-02-28 21:17:54 +00:00
commit 40e8e08690
3487 changed files with 39 additions and 21 deletions

View file

@ -0,0 +1,60 @@
// // AnsiToHtmlEncoder.cs
// /*
// paul schneider <paul@pschneider.fr> 19/06/2018 15:58 20182018 6 19
// */
using System.IO;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Yavsc.Helpers
{
public static class AnsiToHtmlEncoder
{
const string DocStart = "<!doctype html>\n<html>\n<head>"+
"<style>body {\ncolor: grey;\nbackground-color: black;\nfont-family:fixed;}\n</style>\n</head>"+
"<body><pre><code>\n";
const string DocEnd = "</code></pre></body></html>";
public static Stream GetStream(StreamReader reader)
{
// FIXME get some more stable alternative
var procStart = new ProcessStartInfo("node", "node_modules/ansi-to-html/bin/ansi-to-html")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
// procStart.RedirectStandardError = true;
var mem = new MemoryStream();
var writer = new StreamWriter(mem);
var proc = Process.Start(procStart);
Task.Run(() => {
while (reader.Peek()>-1)
{
proc.StandardInput.WriteLine(reader.ReadLine());
}
proc.StandardInput.Close();
});
writer.WriteLine(DocStart);
while (proc.StandardOutput.Peek()>-1)
{
writer.WriteLine(proc.StandardOutput.ReadLine());
}
writer.WriteLine(DocEnd);
writer.Flush();
mem.Seek(0,SeekOrigin.Begin);
return mem;
}
public static Stream GetStream(Stream inner)
{
var reader = new StreamReader(inner);
return GetStream(reader);
}
}
}

View file

@ -0,0 +1,57 @@
using System.Web;
using AsciiDocSharp;
using AsciiDocSharp.Converters.Html;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Yavsc.Helpers
{
public class AsciidocTagHelper : TagHelper
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
//await base.ProcessAsync(context, output);
var content = await output.GetChildContentAsync();
string text = HttpUtility.HtmlDecode(content.GetContent());
if (string.IsNullOrWhiteSpace(text)) return;
try
{
if (context.AllAttributes.ContainsName("summary"))
{
var summaryLength = context.AllAttributes["summary"].Value;
if (summaryLength is HtmlString sumLenStr)
{
if (int.TryParse(sumLenStr.Value, out var sumLen))
{
if (text.Length > sumLen)
{
text = text.Substring(0, sumLen) + "(...)";
}
}
}
}
var processor = new AsciiDocProcessor(
);
var htmlConverter = new HtmlDocumentConverter();
var document = processor.ParseFromText(text);
var htmlResult = processor.ConvertDocument(document, htmlConverter);
output.Content.AppendHtml(htmlResult);
}
catch (ArgumentException ex)
{
// silently render the text
output.Content.AppendHtml("<pre>" + text + "</pre>\n");
// and an error
output.Content.AppendHtml("<pre class=\"parsingError\">" + ex.Message + "</pre>\n");
}
}
}
}

View file

@ -0,0 +1,19 @@
namespace Yavsc.Helpers
{
using Models.Bank;
public static class BankInfoHelpers
{
public static bool IsValid(this BankIdentity info) { 
return ByIbanBIC(info) || ByAccountNumber(info) ;
}
public static bool ByIbanBIC(this BankIdentity info) {
return (info.BIC != null && info.IBAN != null) ;
}
public static bool ByAccountNumber(this BankIdentity info){ 
return (info.BankCode != null && info.WicketCode != null && info.AccountNumber != null && info.BankedKey >0);
}
}
}

View file

@ -0,0 +1,73 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Yavsc.Abstract.Models.Messaging;
namespace Yavsc.Helpers
{
public static class ControllerHelpers
{
public static void NotifyWarning(this Controller controller, string title, string body)
{
var notifs = SetupNotificationList(controller);
notifs.Add(new Notification { title = title, body = body });
}
public static void NotifyInfo(this Controller controller, string title, string body)
{
var notifs = SetupNotificationList(controller);
notifs.Add(new Notification { title = title, body = body });
}
public static void Notify(this Controller controller, IEnumerable<Notification> notes)
{
var notifs = SetupNotificationList(controller);
notifs.AddRange(notes);
}
private static List<Notification> SetupNotificationList(this Controller controller)
{
List<Notification> notifs = (List<Notification>)controller.ViewData["Notify"];
if (notifs == null)
{
controller.ViewData["Notify"] = notifs = new List<Notification>();
}
return notifs;
}
/// <summary>
/// If Json is accepted, serve json,
/// if not, serve a web page.
/// </summary>
/// <param name="controller"></param>
/// <param name="model"></param>
/// <returns></returns>
public static IActionResult ViewOk(this Controller controller, object model)
{
IActionResult result;
if (JsonResponse(controller, model, out result)) return result;
else return controller.View(model);
}
static bool JsonResponse(this Controller controller, object model, out IActionResult result){
if (controller.Request.Headers.Keys.Contains("Accept")) {
var accepted = controller.Request.Headers["Accept"];
if (accepted == "application/json")
{
if (controller.ModelState.ErrorCount>0)
result = controller.BadRequest(controller.ModelState);
else
result = controller.Ok(model);
return true;
}
}
result = null;
return false;
}
public static IActionResult ViewOk(this Controller controller, string viewname, object model = null)
{
IActionResult result;
if (JsonResponse(controller, model, out result)) return result;
else return controller.View(viewname, model);
}
}
}

View file

@ -0,0 +1,77 @@
using Microsoft.Extensions.Localization;
namespace Yavsc.Helpers
{
using Models.Workflow;
using Models.Messaging;
using Yavsc.Models.Haircut;
using Yavsc.Models;
using Yavsc.Models.Billing;
using Yavsc.Abstract.Identity;
public static class EventHelpers
{
public static RdvQueryEvent CreateEvent(this RdvQuery query, string subtopic)
{
var yaev = new RdvQueryEvent(subtopic)
{
Sender = query.ClientId,
Reason = query.Reason,
Client = new ClientProviderInfo { 
UserName = query.Client.UserName ,
UserId = query.ClientId,
Avatar = query.Client.Avatar } ,
Previsional = query.Previsional,
EventDate = query.EventDate,
Location = query.Location,
Id = query.Id,
ActivityCode = query.ActivityCode,
BillingCode = BillingCodes.Rdv
};
return yaev;
}
public static HairCutQueryEvent CreateNewHairCutQueryEvent(this HairCutQuery query,
IStringLocalizer<HairCutQuery> SR)
{
string evdate = query.EventDate?.ToString("dddd dd/MM/yyyy à hh:mm")??"[pas de date spécifiée]";
string address = query.Location?.Address??"[pas de lieu spécifié]";
var p = query.Prestation;
string strprestation = query.Description;
var yaev = query.CreateEvent("NewHairCutQuery",
string.Format(SR["HairCutQueryValidation"],query.Client.UserName),
$"{query.Client.Id}");
return yaev;
}
public static string GetSender(this ApplicationUser user)
{
return user.UserName+" ["+user.Id+"@"+Config.Authority+"]";
}
public static HairCutQueryEvent CreateEvent(this HairMultiCutQuery query,
IStringLocalizer SR, BrusherProfile bpr)
{
var yaev = new HairCutQueryEvent("newCommand")
{
Sender = query.ClientId,
Client = new ClientProviderInfo { 
UserName = query.Client.UserName ,
UserId = query.ClientId,
Avatar = query.Client.Avatar } ,
Previsional = query.Previsional,
EventDate = query.EventDate,
Location = query.Location,
Id = query.Id,
Reason = "Commande groupée!",
ActivityCode = query.ActivityCode,
BillingCode = BillingCodes.MBrush
};
return yaev;
}
}
}

View file

@ -0,0 +1,125 @@
//
// GoogleHelpers.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;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
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;
using Yavsc.Models;
using Yavsc.Models.Calendar;
using Yavsc.Services;
using Yavsc.Server.Helpers;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Yavsc.Server.Models.Calendar;
namespace Yavsc.Helpers
{
/// <summary>
/// Google helpers.
/// </summary>
public static class GoogleHelpers
{
public static async Task<GoogleCredential> GetCredentialForApi(IEnumerable<string> scopes)
{
GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync();
var baseClientService = new BaseClientService.Initializer()
{
HttpClientInitializer = credential
};
var compute = new ComputeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
if (credential.IsCreateScopedRequired)
{
credential = credential.CreateScoped(scopes);
}
return credential;
}
public static async Task<IdentityUserLogin<string>> GetGoogleUserLoginAsync(
this ApplicationDbContext context,
string yavscUserId)
{
var user = context.Users.FirstOrDefaultAsync(u=>u.Id==yavscUserId);
if (user==null) return null;
var googleLogin = await context.UserLogins.FirstOrDefaultAsync(
x => x.UserId == yavscUserId && x.LoginProvider == "Google"
);
return googleLogin;
}
public static async Task<UserCredential> GetGoogleCredential(GoogleAuthSettings googleAuthSettings, IDataStore store, string googleUserLoginKey)
{
if (string.IsNullOrEmpty(googleUserLoginKey))
throw new InvalidOperationException("No Google login");
var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer());
var token = await store.GetAsync<TokenResponse>(googleUserLoginKey);
// token != null
var c = SystemClock.Default;
if (token.IsStale) {
token = await RefreshToken(googleAuthSettings, token);
}
return new UserCredential(flow, googleUserLoginKey, token);
}
public static async Task<Period[]> GetFreeTime (this ICalendarManager manager, string calId, DateTime startDate, DateTime endDate)
{
var evlist = await manager.GetCalendarAsync(calId, startDate, endDate, null) ;
var result = evlist.Items
.Where(
ev => ev.Transparency == "transparent"
)
.Select(
ev => new Period {
Start = ev.Start.DateTime.Value,
End = ev.End.DateTime.Value
}
);
return result.ToArray();
}
public static async Task<TokenResponse> RefreshToken(this GoogleAuthSettings settings, TokenResponse oldResponse)
{
string ep = " https://www.googleapis.com/oauth2/v4/token";
// refresh_token client_id client_secret grant_type=refresh_token
try {
using (var m = new SimpleJsonPostMethod(ep)) {
return await m.Invoke<TokenResponse>(
new { refresh_token= oldResponse.RefreshToken, client_id=Config.GoogleWebClientConfiguration["web:client_id"],
client_secret=Config.GoogleWebClientConfiguration["web:client_secret"],
grant_type="refresh_token" }
);
}
}
catch (Exception ex) {
throw new Exception ("No refresh token for Google service account",ex);
}
}
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Rendering;
using Yavsc.Models;
using Yavsc.Models.Workflow;
namespace Yavsc.Helpers {
public static class ListItemHelpers {
public static List<SelectListItem> ActivityItems(
this ApplicationDbContext _dbContext, List<UserActivity> activity)
{
var activities = activity.ToArray();
List<SelectListItem> items = _dbContext.Activities.Select(
x=> new SelectListItem() {
Value = x.Code, Text = x.Name, Selected = activities.Any(a=>a.DoesCode == x.Code)
} ).ToList();
return items;
}
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Security.Cryptography;
namespace Yavsc.Helpers {
public class Helper
{
public static string GetHash(string input)
{
HashAlgorithm hashAlgorithm = SHA256CryptoServiceProvider.Create();
byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(input);
byte[] byteHash = hashAlgorithm.ComputeHash(byteValue);
return Convert.ToBase64String(byteHash);
}
}
}

View file

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Localization;
namespace Yavsc.Server.Helpers
{
public static class PageHelpers
{
public static List<SelectListItem> CreateSelectListItems<T> (this IStringLocalizer<T> localisation, Type enumType, object selectedValue =null)
{
string selectedName = (selectedValue != null) ? enumType.GetEnumName(selectedValue) : null;
var items = new List<SelectListItem> ();
var names = enumType.GetEnumNames();
var values = enumType.GetEnumValues();
for (int index = 0; index < names.Length; index++)
{
var itemName = names[index];
items.Add(new SelectListItem() {
Value = values.GetValue(index).ToString(), Text = localisation[itemName], Selected = ( itemName == selectedName)
}) ;
}
var list = new SelectList(items);
return items;
}
public static List<SelectListItem> AddNull(this List<SelectListItem> selectList, string displayNull, object selectedValue = null)
{
selectList.Add(new SelectListItem { Text = displayNull, Value = "", Selected = selectedValue == null });
return selectList;
}
public static List<SelectListItem> CreateSelectListItems<T> (this IEnumerable<T>data,
Func<T,string> dataField,
Func<T,string> displayField = null, object selectedValue =null) where T : class
{
if (displayField == null) displayField = dataField;
var items = new List<SelectListItem> ();
foreach (var dataItem in data)
{
var itemVal = dataField(dataItem);
var itemName = displayField(dataItem);
items.Add(new SelectListItem() {
Value = itemVal, Text = itemName, Selected = ( selectedValue?.Equals(itemVal) ?? false )
}) ;
}
return items;
}
}
}

View file

@ -0,0 +1,201 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
namespace Yavsc.Helpers
{
using Microsoft.AspNetCore.Mvc.Infrastructure;
using ViewModels.Gen;
public class TeXString : HtmlString
{
public TeXString(TeXString teXString): base(teXString.ToString())
{
}
public TeXString(string str) : base(str)
{
}
public static TeXString operator+ (TeXString a, TeXString b) {
return new TeXString(a.ToString()+b.ToString());
}
}
public class Replacement
{
string target;
string replacement;
public Replacement(string target, string replacement)
{
this.target = target;
this.replacement = replacement;
}
public string Execute(string source)
{
return source?.Replace(target, replacement) ?? null;
}
}
public static class TeXHelpers
{
public static readonly Replacement[] SpecialCharsDefaultRendering =
{
new Replacement("<","\\textless"),
new Replacement(">","\\textgreater"),
new Replacement("©","\\copyright"),
new Replacement("®","\\textregistered"),
new Replacement("\\","\\textbackslash"),
new Replacement("™","\\texttrademark"),
new Replacement("¶","\\P"),
new Replacement("|","\\textbar"),
new Replacement("%","\\%"),
new Replacement("{","\\{"),
new Replacement("}","\\}"),
new Replacement("_","\\_"),
new Replacement("#","\\#"),
new Replacement("$","\\$"),
new Replacement("_","\\_"),
new Replacement("¿","\\textquestiondown"),
new Replacement("§","\\S"),
new Replacement("£","\\pounds"),
new Replacement("&","\\&"),
new Replacement("¡","\\textexclamdown"),
new Replacement("†","\\dag"),
new Replacement("","\\textendash"),
new Replacement("°","\\textdegree")
};
public static TeXString ToTeX(this string source, string defaultValue="\\textit{néant}")
{
if (source==null) return new TeXString(defaultValue);
string result=source;
foreach (var r in SpecialCharsDefaultRendering)
{
result = r.Execute(result);
}
return new TeXString(result);
}
public static TeXString ToTeXCell(this string source, string defaultValue="\\textit{néant}")
{
if (source==null) return new TeXString(defaultValue);
string result=source;
foreach (var r in SpecialCharsDefaultRendering)
{
result = r.Execute(result);
}
result = result.Replace("\n","\\tabularnewline ");
return new TeXString(result);
}
public static string NewLinesWith(this string target, string separator)
{
var items = target.Split(new char[] { '\n' }).Where(
s => !string.IsNullOrWhiteSpace(s));
return string.Join(separator, items);
}
public static TeXString ToTeXLines(this string source, string defaultValue, string lineSeparator = "\n\\\\")
{
if (source == null) return new TeXString(defaultValue);
return new TeXString( source.ToTeX().ToString().NewLinesWith(lineSeparator) );
}
public static TeXString SplitAddressToTeX (this string source, string lineSeparator = "\n\\\\", string defaultValue = "\\textit{pas d'adresse postale}")
{
if (string.IsNullOrWhiteSpace(source)) return new TeXString(defaultValue);
var alines = source.Split(',');
var texlines = alines.Select(l=>l.ToTeX().ToString());
return new TeXString(string.Join(lineSeparator,texlines));
}
public static bool GenerateEstimatePdf(this PdfGenerationViewModel Model)
{
string errorMsg = null;
var billdir = Model.DestDir;
var tempdir = Config.SiteSetup.TempDir;
string name = Model.BaseFileName;
string fullname = new FileInfo(
System.IO.Path.Combine(tempdir, name)).FullName;
string ofullname = new FileInfo(
System.IO.Path.Combine(billdir, name)).FullName;
FileInfo fi = new FileInfo(fullname + ".tex");
FileInfo fo = new FileInfo(ofullname + ".pdf");
using (StreamWriter sw = new StreamWriter(fi.FullName))
{
sw.Write(Model.TeXSource);
}
if (!fi.Exists)
{
errorMsg = "Source write failed";
}
else
{
using (Process p = new Process())
{
p.StartInfo.WorkingDirectory = tempdir;
p.StartInfo = new ProcessStartInfo
{
UseShellExecute = false,
WorkingDirectory = tempdir,
FileName = "/usr/bin/texi2pdf",
Arguments = $"--batch --build-dir=. -o {fo.FullName} {fi.FullName}"
};
p.Start();
p.WaitForExit();
if (p.ExitCode != 0)
{
errorMsg = $"Pdf generation failed with exit code: {p.ExitCode}";
}
else
{
fi.Delete();
var di = new DirectoryInfo(Path.Combine(tempdir,$"{Model.BaseFileName}.t2d"));
di.Delete(true);
}
}
}
Model.Generated = fo.Exists;
Model.GenerationErrorMessage = new HtmlString(errorMsg);
return fo.Exists;
}
public static string RenderViewToString(
this Controller controller, IViewEngine engine,
IActionContextAccessor contextAccessor,
string viewName, object model, bool isMainPage = true)
{
using (var sw = new StringWriter())
{
if (engine == null)
throw new InvalidOperationException("no engine");
// try to find the specified view
controller.TryValidateModel(model);
ViewEngineResult viewResult = engine.FindView(contextAccessor.ActionContext, viewName, isMainPage);
// create the associated context
ViewContext viewContext = new ViewContext();
viewContext.ActionDescriptor = contextAccessor.ActionContext.ActionDescriptor;
viewContext.HttpContext = contextAccessor.ActionContext.HttpContext;
viewContext.TempData = controller.TempData;
viewContext.View = viewResult.View;
viewContext.Writer = sw;
// write the render view with the given context to the stringwriter
viewResult.View.RenderAsync(viewContext).Wait();
return sw.GetStringBuilder().ToString();
}
}
}
}

View file

@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Blog;
namespace Yavsc.Helpers
{
public static class UserHelpers
{
public static IEnumerable<BlogPost> UserPosts(this ApplicationDbContext dbContext, string posterId, string? readerId)
{
if (readerId == null)
{
var userPosts = dbContext.blogSpotPublications.Include(
b => b.BlogPost
).Where(x => x.BlogPost.AuthorId == posterId)
.Select(x => x.BlogPost).ToArray();
return userPosts;
}
else
{
long[] readerCirclesMemberships =
dbContext.Circle.Include(c => c.Members)
.Where(c => c.Members.Any(m => m.MemberId == readerId))
.Select(c => c.Id).ToArray();
return dbContext.BlogSpot.Include(
b => b.Author
).Include(p => p.ACL).Where(x => x.Author.Id == posterId &&
(x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
}
}
}
}