reorg
This commit is contained in:
parent
d000f77098
commit
40e8e08690
3487 changed files with 39 additions and 21 deletions
184
src/Yavsc.Org/Services/BlogSpotService.cs
Normal file
184
src/Yavsc.Org/Services/BlogSpotService.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
using System.Diagnostics;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Exceptions;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.ViewModels.Auth;
|
||||
|
||||
public class BlogSpotService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
|
||||
public BlogSpotService(ApplicationDbContext context,
|
||||
IAuthorizationService authorizationService)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public BlogPost Create(string userId, BlogPost post)
|
||||
{
|
||||
_context.BlogSpot.Add(post);
|
||||
_context.SaveChanges(userId);
|
||||
return post;
|
||||
}
|
||||
public async Task<BlogPostEditViewModel> GetPostForEdition(ClaimsPrincipal user, long blogPostId)
|
||||
{
|
||||
var blog = await _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).SingleAsync(m => m.Id == blogPostId);
|
||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
|
||||
if (!auth.Succeeded)
|
||||
{
|
||||
throw new AuthorizationFailureException(auth);
|
||||
}
|
||||
var pub = await _context.blogSpotPublications.AnyAsync(x => x.BlogpostId == blog.Id);
|
||||
|
||||
return new BlogPostEditViewModel(blog, pub);
|
||||
}
|
||||
|
||||
public async Task<BlogPost> Details(ClaimsPrincipal user, long blogPostId)
|
||||
{
|
||||
BlogPost blog = await _context.BlogSpot
|
||||
.Include(p => p.Author)
|
||||
.Include(p => p.Tags)
|
||||
.Include(p => p.Comments)
|
||||
.Include(p => p.ACL)
|
||||
.SingleAsync(m => m.Id == blogPostId);
|
||||
if (blog == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new ReadPermission());
|
||||
if (!auth.Succeeded)
|
||||
{
|
||||
throw new AuthorizationFailureException(auth);
|
||||
}
|
||||
foreach (var c in blog.Comments)
|
||||
{
|
||||
c.Author = _context.Users.First(u => u.Id == c.AuthorId);
|
||||
}
|
||||
return blog;
|
||||
}
|
||||
|
||||
public async Task Modify(ClaimsPrincipal user, BlogPostEditViewModel blogEdit)
|
||||
{
|
||||
var blog = _context.BlogSpot.SingleOrDefault(b => b.Id == blogEdit.Id);
|
||||
Debug.Assert(blog != null);
|
||||
var auth = await _authorizationService.AuthorizeAsync(user, blog, new EditPermission());
|
||||
if (!auth.Succeeded)
|
||||
{
|
||||
throw new AuthorizationFailureException(auth);
|
||||
}
|
||||
blog.Article = blogEdit.Article;
|
||||
blog.Title = blogEdit.Title;
|
||||
blog.Photo = blogEdit.Photo;
|
||||
blog.ACL = blogEdit.ACL;
|
||||
// saves the change
|
||||
_context.Update(blog);
|
||||
var publication = await _context.blogSpotPublications.SingleOrDefaultAsync
|
||||
(p => p.BlogpostId == blogEdit.Id);
|
||||
if (publication != null)
|
||||
{
|
||||
if (!blogEdit.Publish)
|
||||
{
|
||||
_context.blogSpotPublications.Remove(publication);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (blogEdit.Publish)
|
||||
{
|
||||
_context.blogSpotPublications.Add(
|
||||
new BlogSpotPublication
|
||||
{
|
||||
BlogpostId = blogEdit.Id
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
_context.SaveChanges(user.GetUserId());
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<IBlogPost>> Index(ClaimsPrincipal user, string id, int skip = 0, int take = 25)
|
||||
{
|
||||
IEnumerable<IBlogPost> posts;
|
||||
|
||||
if (user.Identity.IsAuthenticated)
|
||||
{
|
||||
string viewerId = user.GetUserId();
|
||||
long[] userCircles = await _context.Circle.Include(c => c.Members).
|
||||
Where(c => c.Members.Any(m => m.MemberId == viewerId))
|
||||
.Select(c => c.Id).ToArrayAsync();
|
||||
|
||||
posts = _context.BlogSpot
|
||||
.Include(b => b.Author)
|
||||
.Include(p => p.ACL)
|
||||
.Include(p => p.Tags)
|
||||
.Include(p => p.Comments)
|
||||
.Where(p => p.ACL == null
|
||||
|| p.ACL.Count == 0
|
||||
|| (p.AuthorId == viewerId)
|
||||
|| (userCircles != null &&
|
||||
p.ACL.Any(a => userCircles.Contains(a.CircleId)))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
posts = _context.blogSpotPublications
|
||||
.Include(p => p.BlogPost)
|
||||
.Include(b => b.BlogPost.Author)
|
||||
.Include(p => p.BlogPost.ACL)
|
||||
.Include(p => p.BlogPost.Tags)
|
||||
.Include(p => p.BlogPost.Comments)
|
||||
.Where(p => p.BlogPost.ACL == null
|
||||
|| p.BlogPost.ACL.Count == 0)
|
||||
.Select(p => p.BlogPost).ToArray();
|
||||
}
|
||||
|
||||
var data = posts.OrderByDescending(p => p.DateModified);
|
||||
return data;
|
||||
}
|
||||
|
||||
public async Task Delete(ClaimsPrincipal user, long id)
|
||||
{
|
||||
var uid = user.GetUserId();
|
||||
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
|
||||
|
||||
_context.BlogSpot.Remove(blog);
|
||||
_context.SaveChanges(user.GetUserId());
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<BlogPost>> UserPosts(
|
||||
string posterName,
|
||||
string? readerId,
|
||||
int pageLen = 10,
|
||||
int pageNum = 0)
|
||||
{
|
||||
string? posterId = (await _context.Users.SingleOrDefaultAsync(u => u.UserName == posterName))?.Id ?? null;
|
||||
if (posterId == null) return Array.Empty<BlogPost>();
|
||||
return _context.UserPosts(posterId, readerId);
|
||||
}
|
||||
|
||||
public object? GetTitle(string title)
|
||||
{
|
||||
return _context.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Where(x => x.Title == title).OrderByDescending(
|
||||
x => x.DateCreated
|
||||
).ToList();
|
||||
}
|
||||
|
||||
public async Task<BlogPost?> GetBlogPostAsync(long value)
|
||||
{
|
||||
return await _context.BlogSpot
|
||||
.Include(b => b.Author)
|
||||
.Include(b => b.ACL)
|
||||
.SingleOrDefaultAsync(x => x.Id == value);
|
||||
}
|
||||
|
||||
}
|
||||
343
src/Yavsc.Org/Services/ChatHubConnexionManager.cs
Normal file
343
src/Yavsc.Org/Services/ChatHubConnexionManager.cs
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Yavsc.Abstract.Chat;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.ViewModels.Chat;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Connexion Manager
|
||||
/// </summary>
|
||||
public class HubConnectionManager : IConnexionManager
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private Action<string, string>? _errorHandler;
|
||||
|
||||
/// <summary>
|
||||
/// by cx id
|
||||
/// </summary>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <returns></returns>
|
||||
|
||||
static readonly ConcurrentDictionary<string, string> ChatUserNames = new ConcurrentDictionary<string, string>();
|
||||
/// <summary>
|
||||
/// by user name
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static readonly ConcurrentDictionary<string, List<string>> ChatCxIds = new ConcurrentDictionary<string, List<string>>();
|
||||
|
||||
/// <summary>
|
||||
/// by user name,
|
||||
/// the list of its chat rooms
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
static readonly ConcurrentDictionary<string, List<string>> ChatRoomPresence = new ConcurrentDictionary<string, List<string>>();
|
||||
static readonly ConcurrentDictionary<string, bool> _isCop = new ConcurrentDictionary<string, bool>();
|
||||
|
||||
public static ConcurrentDictionary<string, ChatRoomInfo> Channels = new ConcurrentDictionary<string, ChatRoomInfo>();
|
||||
readonly ApplicationDbContext _dbContext;
|
||||
readonly IStringLocalizer _localizer;
|
||||
public HubConnectionManager(IServiceScopeFactory ssf )
|
||||
{
|
||||
var scope = ssf.CreateScope();
|
||||
_dbContext = scope.ServiceProvider.GetService<ApplicationDbContext>();
|
||||
var loggerFactory = scope.ServiceProvider.GetService<ILoggerFactory>();
|
||||
_logger = loggerFactory.CreateLogger<HubConnectionManager>();
|
||||
var stringLocFactory = scope.ServiceProvider.GetService<IStringLocalizerFactory>();
|
||||
_localizer = stringLocFactory.Create(typeof(HubConnectionManager));
|
||||
}
|
||||
|
||||
public void SetUserName(string cxId, string userName)
|
||||
{
|
||||
string oldUname;
|
||||
if (ChatUserNames.TryGetValue(cxId, out oldUname))
|
||||
{
|
||||
// this is a rename
|
||||
if (oldUname == userName) return;
|
||||
ChatCxIds[userName] = ChatCxIds[oldUname];
|
||||
ChatCxIds[oldUname] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a connexion
|
||||
ChatCxIds[userName] = new List<string>() { cxId };
|
||||
}
|
||||
ChatUserNames[cxId] = userName;
|
||||
}
|
||||
// Username must have been set before calling this method.
|
||||
public void OnConnected(string cxId, bool isCop)
|
||||
{
|
||||
var username = ChatUserNames[cxId];
|
||||
if (!IsConnected(username))
|
||||
ChatRoomPresence[username] = new List<string>();
|
||||
_isCop[username] = isCop;
|
||||
}
|
||||
|
||||
public bool IsConnected(string candidate)
|
||||
{
|
||||
return ChatRoomPresence.ContainsKey(candidate)
|
||||
&& ChatRoomPresence[candidate] != null;
|
||||
}
|
||||
|
||||
public bool IsPresent(string roomName, string userName)
|
||||
{
|
||||
return ChatRoomPresence[userName].Contains(roomName);
|
||||
}
|
||||
|
||||
public bool IsCop(string userName)
|
||||
{
|
||||
return _isCop[userName];
|
||||
}
|
||||
|
||||
public void OnDisctonnected(string connectionId)
|
||||
{
|
||||
string uname;
|
||||
|
||||
if (!ChatUserNames.TryRemove(connectionId, out uname))
|
||||
_logger.LogError($"Could not get removed user name for cx {connectionId}");
|
||||
else
|
||||
{
|
||||
List<string> cxIds;
|
||||
if (ChatCxIds.TryGetValue(uname, out cxIds))
|
||||
{
|
||||
cxIds.Remove(connectionId);
|
||||
foreach (var room in ChatRoomPresence[uname])
|
||||
{
|
||||
Part(connectionId, room, "connexion aborted");
|
||||
}
|
||||
}
|
||||
else
|
||||
_logger.LogError($"Could not remove user cx {connectionId}");
|
||||
|
||||
ChatRoomPresence[uname] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Part(string cxId, string roomName, string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (!chanInfo.Users.Contains(cxId))
|
||||
{
|
||||
// TODO NotifyErrorToCaller(roomName, "you didn't join.");
|
||||
return false;
|
||||
}
|
||||
// FIXME only remove cx, not username,
|
||||
// as long as he might be connected
|
||||
// from another device, to the same room
|
||||
chanInfo.Users.Remove(cxId);
|
||||
if (chanInfo.Users.Count == 0)
|
||||
{
|
||||
ChatRoomInfo deadchanInfo;
|
||||
if (Channels.TryRemove(roomName, out deadchanInfo))
|
||||
{
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
room.LatestJoinPart = DateTime.Now;
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
// TODO NotifyErrorToCallerInRoom(roomName, $"user could not part: no such room");
|
||||
}
|
||||
}
|
||||
|
||||
public ChatRoomInfo Join(string roomName, string cxId)
|
||||
{
|
||||
var userName = ChatUserNames[cxId];
|
||||
|
||||
_logger.LogInformation($"Join: {userName}=>{roomName}");
|
||||
ChatRoomInfo chanInfo;
|
||||
// if channel already is open
|
||||
if (Channels.ContainsKey(roomName))
|
||||
{
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (IsPresent(roomName, userName))
|
||||
{
|
||||
// TODO implement some unique connection sharing protocol
|
||||
// between all terminals from a single user.
|
||||
return chanInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsCop(userName))
|
||||
{
|
||||
chanInfo.Ops.Add(cxId);
|
||||
}
|
||||
else{
|
||||
chanInfo.Users.Add(cxId);
|
||||
}
|
||||
_logger.LogInformation($"existing room joint: {userName}=>{roomName}");
|
||||
if (!ChatRoomPresence[userName].Contains(roomName))
|
||||
ChatRoomPresence[userName].Add(roomName);
|
||||
return chanInfo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = "room seemd to be avaible ... but we could get no info on it.";
|
||||
_errorHandler(roomName, msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// room was closed.
|
||||
var room = _dbContext.ChatRoom.FirstOrDefault(r => r.Name == roomName);
|
||||
chanInfo = new ChatRoomInfo();
|
||||
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
chanInfo.Topic = room.Topic;
|
||||
chanInfo.Name = room.Name;
|
||||
chanInfo.Users.Add(cxId);
|
||||
}
|
||||
else
|
||||
{ // a first join, we create it.
|
||||
chanInfo.Name = roomName;
|
||||
chanInfo.Topic = _localizer.GetString(ChatHubConstants.JustCreatedBy)+userName;
|
||||
chanInfo.Ops.Add(cxId);
|
||||
}
|
||||
|
||||
if (Channels.TryAdd(roomName, chanInfo))
|
||||
{
|
||||
ChatRoomPresence[userName].Add(roomName);
|
||||
_logger.LogInformation("new room joint");
|
||||
return (chanInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = "Chan create failed unexpectly...";
|
||||
_errorHandler(roomName, msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Op(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Deop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Hop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Dehop(string roomName, string userName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetUserName(string cxId)
|
||||
{
|
||||
return ChatUserNames[cxId];
|
||||
}
|
||||
|
||||
public bool TryGetChanInfo(string room, out ChatRoomInfo chanInfo)
|
||||
{
|
||||
return Channels.TryGetValue(room, out chanInfo);
|
||||
}
|
||||
|
||||
public IEnumerable<ChannelShortInfo> ListChannels(string pattern)
|
||||
{
|
||||
if (pattern != null)
|
||||
return Channels.Where(c => c.Key.Contains(pattern))
|
||||
.OrderByDescending(c => c.Value.Users.Count).Select(c => new ChannelShortInfo { RoomName = c.Key, Topic = c.Value.Topic }).Take(10);
|
||||
|
||||
return Channels
|
||||
.OrderByDescending(c => c.Value.Users.Count).Select(c => new ChannelShortInfo { RoomName = c.Key, Topic = c.Value.Topic }).Take(10);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetConnexionIds(string userName)
|
||||
{
|
||||
return ChatCxIds.ContainsKey(userName) ? ChatCxIds[userName] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set on error as string couple action
|
||||
/// </summary>
|
||||
/// <param name="errorHandler"></param>
|
||||
public void SetErrorHandler(Action<string, string> errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
public bool Kick(string cxId, string userName, string roomName, string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
if (!Channels.ContainsKey(roomName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchChan).ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchChan).ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
var kickerName = GetUserName(cxId);
|
||||
if (!chanInfo.Ops.Contains(cxId))
|
||||
if (!chanInfo.Hops.Contains(cxId))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabYouNotOp).ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPresent(roomName, userName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.LabNoSuchUser).ToString());
|
||||
return false;
|
||||
}
|
||||
var ucxs = GetConnexionIds(userName);
|
||||
if (chanInfo.Hops.Contains(cxId))
|
||||
if (chanInfo.Ops.Any(c => ucxs.Contains(c)))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.HopWontKickOp).ToString());
|
||||
return false;
|
||||
}
|
||||
if (IsCop(userName))
|
||||
{
|
||||
_errorHandler(roomName, _localizer.GetString(ChatHubConstants.NoKickOnCop).ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// all good, time to kick :-)
|
||||
foreach (var ucx in ucxs) {
|
||||
if (chanInfo.Users.Contains(ucx))
|
||||
chanInfo.Users.Remove(ucx);
|
||||
|
||||
else if (chanInfo.Ops.Contains(ucx))
|
||||
chanInfo.Ops.Remove(ucx);
|
||||
|
||||
else if (chanInfo.Hops.Contains(ucx))
|
||||
chanInfo.Hops.Remove(ucx);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/Yavsc.Org/Services/DiskUsageTracker.cs
Normal file
101
src/Yavsc.Org/Services/DiskUsageTracker.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using Microsoft.Extensions.Options;
|
||||
using Yavsc;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Services;
|
||||
|
||||
|
||||
public class DiskUsageTracker : IDiskUsageTracker
|
||||
{
|
||||
public class DUTInfo
|
||||
{
|
||||
public DUTInfo()
|
||||
{
|
||||
Creation = DateTime.Now;
|
||||
}
|
||||
public long Usage { get; set; }
|
||||
public long Quota { get; set; }
|
||||
public readonly DateTime Creation;
|
||||
}
|
||||
|
||||
readonly Dictionary<string, DUTInfo> DiskUsage;
|
||||
readonly ApplicationDbContext context;
|
||||
readonly int ulistLength;
|
||||
public DiskUsageTracker(IOptions<SiteSettings> options, ApplicationDbContext context)
|
||||
{
|
||||
ulistLength = options.Value.DUUserListLen;
|
||||
DiskUsage = new Dictionary<string, DUTInfo>();
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
readonly static object userInfoLock = new object();
|
||||
|
||||
DUTInfo GetInfo(string username)
|
||||
{
|
||||
lock (userInfoLock)
|
||||
{
|
||||
if (!DiskUsage.ContainsKey(username))
|
||||
{
|
||||
var user = context.Users.SingleOrDefault(u => u.UserName == username);
|
||||
if (user == null) throw new Exception($"Not an user : {username}");
|
||||
DUTInfo usage = new DUTInfo
|
||||
{
|
||||
Usage = user.DiskUsage,
|
||||
Quota = user.DiskQuota
|
||||
};
|
||||
DiskUsage.Add(username, usage);
|
||||
if (DiskUsage.Count > ulistLength)
|
||||
{
|
||||
// remove the oldest
|
||||
var oldestts = DateTime.Now;
|
||||
DUTInfo oinfo = null;
|
||||
string ouname = null;
|
||||
foreach (var diskusage in DiskUsage)
|
||||
{
|
||||
if (oldestts > usage.Creation)
|
||||
{
|
||||
oldestts = diskusage.Value.Creation;
|
||||
ouname = diskusage.Key;
|
||||
oinfo = diskusage.Value;
|
||||
}
|
||||
}
|
||||
var ouser = context.Users.SingleOrDefault(u => u.UserName == ouname);
|
||||
ouser.DiskUsage = oinfo.Usage;
|
||||
context.SaveChanges();
|
||||
DiskUsage.Remove(ouname);
|
||||
}
|
||||
return usage;
|
||||
}
|
||||
return DiskUsage[username];
|
||||
}
|
||||
}
|
||||
public bool GetSpace(string userName, long space)
|
||||
{
|
||||
var info = GetInfo(userName);
|
||||
if (info.Quota < info.Usage + space) return false;
|
||||
info.Usage += space;
|
||||
#pragma warning disable CS4014
|
||||
SaveUserUsage(userName,info.Usage);
|
||||
#pragma warning restore CS4014
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Release(string userName, long space)
|
||||
{
|
||||
var info = GetInfo(userName);
|
||||
info.Usage -= space;
|
||||
#pragma warning disable CS4014
|
||||
SaveUserUsage(userName,info.Usage);
|
||||
#pragma warning restore CS4014
|
||||
}
|
||||
|
||||
async Task SaveUserUsage(string username, long usage)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var ouser = context.Users.SingleOrDefault(u => u.UserName == username);
|
||||
ouser.DiskUsage = usage;
|
||||
context.SaveChanges();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
32
src/Yavsc.Org/Services/ExternalIdentityManager.cs
Normal file
32
src/Yavsc.Org/Services/ExternalIdentityManager.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Models;
|
||||
|
||||
public class ExternalIdentityManager : IExternalIdentityManager
|
||||
{
|
||||
private ApplicationDbContext _applicationDbContext;
|
||||
private SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public ExternalIdentityManager(ApplicationDbContext applicationDbContext, SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_applicationDbContext = applicationDbContext;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
public ApplicationUser AutoProvisionUser(string provider, string providerUserId, List<Claim> claims)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApplicationUser?> FindByExternaleProviderAsync(string provider, string providerUserId)
|
||||
{
|
||||
|
||||
var user = await _applicationDbContext.UserLogins
|
||||
.FirstOrDefaultAsync(
|
||||
i => (i.LoginProvider == provider) && (i.ProviderKey == providerUserId)
|
||||
);
|
||||
if (user == null) return null;
|
||||
return await _applicationDbContext.Users.FirstOrDefaultAsync(u=>u.Id == user.UserId);
|
||||
}
|
||||
}
|
||||
173
src/Yavsc.Org/Services/YavscMessageSender.cs
Normal file
173
src/Yavsc.Org/Services/YavscMessageSender.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Yavsc.Interface;
|
||||
using Yavsc.Interfaces.Workflow;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Google.Messaging;
|
||||
using Yavsc.Models.Haircut;
|
||||
using Yavsc.Models.Messaging;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
public class YavscMessageSender : IYavscMessageSender
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
readonly ITrueEmailSender _emailSender;
|
||||
readonly SiteSettings siteSettings;
|
||||
readonly ApplicationDbContext _dbContext;
|
||||
readonly IConnexionManager _cxManager;
|
||||
private readonly IHubContext<ChatHub> hubContext;
|
||||
|
||||
public YavscMessageSender(
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<SiteSettings> sitesOptions,
|
||||
ITrueEmailSender emailSender,
|
||||
ApplicationDbContext dbContext,
|
||||
IConnexionManager cxManager,
|
||||
IHubContext<ChatHub> hubContext
|
||||
)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<MailSender>();
|
||||
_emailSender = emailSender;
|
||||
siteSettings = sitesOptions?.Value;
|
||||
this.hubContext = hubContext;
|
||||
_dbContext = dbContext;
|
||||
_cxManager = cxManager;
|
||||
}
|
||||
|
||||
public async Task<MessageWithPayloadResponse> NotifyEvent<Event>
|
||||
(IEnumerable<string> userIds, 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 (userIds == null)
|
||||
throw new Exception("Notify e No user id");
|
||||
|
||||
MessageWithPayloadResponse response = new MessageWithPayloadResponse();
|
||||
|
||||
var raa = userIds.ToArray();
|
||||
if (raa.Length < 1)
|
||||
throw new Exception("No dest id");
|
||||
|
||||
try
|
||||
{
|
||||
List<MessageWithPayloadResponse.Result> results = new List<MessageWithPayloadResponse.Result>();
|
||||
foreach (var userId in raa)
|
||||
{
|
||||
_logger.LogDebug($"For performer id : {userId}");
|
||||
MessageWithPayloadResponse.Result result = new MessageWithPayloadResponse.Result
|
||||
{
|
||||
registration_id = userId
|
||||
};
|
||||
|
||||
var user = _dbContext.Users.FirstOrDefault(u => u.Id == userId);
|
||||
if (user == null)
|
||||
{
|
||||
response.failure++;
|
||||
result.error = "no such user.";
|
||||
continue;
|
||||
}
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
response.failure++;
|
||||
result.error = "user has not confirmed his email address.";
|
||||
continue;
|
||||
}
|
||||
if (user.Email == null)
|
||||
{
|
||||
response.failure++;
|
||||
result.error = "user has no legacy email address.";
|
||||
continue;
|
||||
}
|
||||
|
||||
var body = ev.CreateBody();
|
||||
|
||||
|
||||
_logger.LogDebug($"Sending to {user.UserName} <{user.Email}> : {body}");
|
||||
|
||||
result.message_id = await _emailSender.SendEmailAsync(user.UserName, user.Email,
|
||||
$"{ev.Sender} (un client) vous demande un rendez-vous",
|
||||
body + Environment.NewLine);
|
||||
response.success++;
|
||||
|
||||
var cxids = _cxManager.GetConnexionIds(user.UserName);
|
||||
if (cxids == null)
|
||||
{
|
||||
_logger.LogDebug($"no cx to {user.UserName} <{user.Email}> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug($"Sending signal to {string.Join(" ", cxids)} : " + JsonConvert.SerializeObject(ev));
|
||||
|
||||
foreach (var cxid in cxids)
|
||||
{
|
||||
// from usr asp.net Id : var hubClient = hubContext.Clients.User(userId);
|
||||
var hubClient = hubContext.Clients.Client(cxid);
|
||||
var data = new Dictionary<string, object>
|
||||
{
|
||||
["event"] = JsonConvert.SerializeObject(ev)
|
||||
};
|
||||
await hubClient.SendAsync("push", ev.Topic, JsonConvert.SerializeObject(data));
|
||||
}
|
||||
|
||||
result.message_id = MimeKit.Utils.MimeUtils.GenerateMessageId(
|
||||
siteSettings.Authority
|
||||
);
|
||||
|
||||
response.success++;
|
||||
}
|
||||
results.Add(result);
|
||||
}
|
||||
response.results = results.ToArray();
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Quelque chose s'est mal passé à l'envoi: " + ex.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MessageWithPayloadResponse> NotifyBookQueryAsync(IEnumerable<string> userIds, RdvQueryEvent ev)
|
||||
{
|
||||
return await NotifyEvent<RdvQueryEvent>(userIds, ev);
|
||||
}
|
||||
|
||||
public async Task<MessageWithPayloadResponse> NotifyEstimateAsync(IEnumerable<string> userIds, EstimationEvent ev)
|
||||
{
|
||||
return await NotifyEvent<EstimationEvent>(userIds, ev);
|
||||
}
|
||||
|
||||
public async Task<MessageWithPayloadResponse> NotifyHairCutQueryAsync(
|
||||
IEnumerable<string> userIds, HairCutQueryEvent ev)
|
||||
{
|
||||
return await NotifyEvent<HairCutQueryEvent>(userIds, ev);
|
||||
}
|
||||
|
||||
public async Task<MessageWithPayloadResponse> NotifyAsync(IEnumerable<string> userIds, IEvent yaev)
|
||||
{
|
||||
return await NotifyEvent<IEvent>(userIds, yaev);
|
||||
}
|
||||
|
||||
/* SMS with Twilio:
|
||||
public Task SendSmsAsync(TwilioSettings twilioSettigns, string number, string message)
|
||||
{
|
||||
var Twilio = new TwilioRestClient(twilioSettigns.AccountSID, twilioSettigns.Token);
|
||||
var result = Twilio.SendMessage( twilioSettigns.SMSAccountFrom, number, message);
|
||||
// Status is one of Queued, Sending, Sent, Failed or null if the number is not valid
|
||||
Trace.TraceInformation(result.Status);
|
||||
// Twilio doesn't currently have an async API, so return success.
|
||||
|
||||
return Task.FromResult(result.Status != "Failed");
|
||||
|
||||
} */
|
||||
}
|
||||
}
|
||||
171
src/Yavsc.Org/Services/YavscTemplateEngine.cs
Normal file
171
src/Yavsc.Org/Services/YavscTemplateEngine.cs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
using System.Text;
|
||||
// // EMailer.cs
|
||||
// /*
|
||||
// paul 26/06/2018 12:18 20182018 6 26
|
||||
// */
|
||||
using Yavsc.Templates;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Services;
|
||||
using System.Reflection;
|
||||
using Yavsc.Abstract.Templates;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using RazorEngine.Configuration;
|
||||
using Yavsc.Interface;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
using RazorEngine.Compilation.ImpromptuInterface.Optimization;
|
||||
using RazorEngine.Compilation.ImpromptuInterface;
|
||||
|
||||
namespace Yavsc.Lib
|
||||
{
|
||||
public class YavscTemplateEngine
|
||||
{
|
||||
ISet<string> Namespaces = new System.Collections.Generic.HashSet<string> {
|
||||
"System",
|
||||
"Yavsc.Templates" ,
|
||||
"Yavsc.Models",
|
||||
"Yavsc.Models.Identity"};
|
||||
|
||||
readonly IStringLocalizer<YavscTemplateEngine> stringLocalizer;
|
||||
readonly ApplicationDbContext dbContext;
|
||||
|
||||
readonly ILogger logger;
|
||||
|
||||
public YavscTemplateEngine(ApplicationDbContext dbContext,
|
||||
IStringLocalizer<YavscTemplateEngine> localizer,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
stringLocalizer = localizer;
|
||||
this.dbContext = dbContext;
|
||||
|
||||
logger = loggerFactory.CreateLogger<YavscTemplateEngine>();
|
||||
}
|
||||
|
||||
public string RunUserTemplate(string templateCode)
|
||||
{
|
||||
|
||||
string subtemp = stringLocalizer["MonthlySubjectTemplate"].Value;
|
||||
|
||||
logger.LogInformation($"Generating SendMonthlyEmail {templateCode}");
|
||||
|
||||
|
||||
var templateInfo = dbContext.MailingTemplate.FirstOrDefault(t => t.Id == templateCode);
|
||||
Debug.Assert (templateInfo != null);
|
||||
var templatekey = RazorEngine.Engine.Razor.GetKey(templateInfo.Id);
|
||||
|
||||
logger.LogInformation($"Using code: {templateCode}, subject: {subtemp} ");
|
||||
logger.LogInformation("And body:\n" + templateInfo.Body);
|
||||
|
||||
|
||||
// Generate code for the template
|
||||
using (var inMemoryCsharpCode = new MemoryStream())
|
||||
{
|
||||
using (var writter = new StreamWriter(inMemoryCsharpCode))
|
||||
{
|
||||
RazorEngine.Engine.Razor.Run(templatekey, writter);
|
||||
inMemoryCsharpCode.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(Encoding.Default.GetString(inMemoryCsharpCode.ToArray()));
|
||||
|
||||
logger.LogInformation("CSharp parsed");
|
||||
List<MetadataReference> references = new List<MetadataReference>();
|
||||
|
||||
foreach (var type in new Type[] {
|
||||
typeof(object),
|
||||
typeof(Enumerable),
|
||||
typeof(IdentityUser),
|
||||
typeof(ApplicationUser),
|
||||
typeof(Template),
|
||||
typeof(UserOrientedTemplate),
|
||||
typeof(System.Threading.Tasks.TaskExtensions)
|
||||
})
|
||||
{
|
||||
var location = type.Assembly.Location;
|
||||
if (!string.IsNullOrWhiteSpace(location))
|
||||
{
|
||||
references.Add(
|
||||
MetadataReference.CreateFromFile(location)
|
||||
);
|
||||
logger.LogInformation($"Assembly for {type.Name} found at {location}");
|
||||
}
|
||||
else logger.LogWarning($"Assembly Not found for {type.Name}");
|
||||
}
|
||||
|
||||
logger.LogInformation("Compilation creation ...");
|
||||
|
||||
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||
.WithAllowUnsafe(true).WithOptimizationLevel(OptimizationLevel.Debug)
|
||||
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary).WithPlatform(Platform.AnyCpu)
|
||||
.WithUsings("Yavsc.Templates")
|
||||
;
|
||||
string assemblyName = "EMailSenderTemplate";
|
||||
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
syntaxTrees: new[] { syntaxTree },
|
||||
references: references,
|
||||
options: compilationOptions
|
||||
);
|
||||
|
||||
using (var inMemoryAssembly = new MemoryStream())
|
||||
{
|
||||
logger.LogInformation("Emitting result ...");
|
||||
EmitResult result = compilation.Emit(inMemoryAssembly);
|
||||
foreach (Diagnostic diagnostic in result.Diagnostics.Where(diagnostic =>
|
||||
diagnostic.Severity < DiagnosticSeverity.Error && !diagnostic.IsWarningAsError))
|
||||
{
|
||||
logger.LogWarning("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
|
||||
logger.LogWarning("{0}: {1}", diagnostic.Id, diagnostic.Location.GetLineSpan());
|
||||
}
|
||||
if (!result.Success)
|
||||
{
|
||||
|
||||
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
|
||||
diagnostic.IsWarningAsError ||
|
||||
diagnostic.Severity == DiagnosticSeverity.Error);
|
||||
foreach (Diagnostic diagnostic in failures)
|
||||
{
|
||||
logger.LogCritical("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
|
||||
logger.LogCritical("{0}: {1}", diagnostic.Id, diagnostic.Location.GetLineSpan());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var user in dbContext.ApplicationUser.Where(
|
||||
u => u.AllowMonthlyEmail
|
||||
))
|
||||
{
|
||||
|
||||
var template = result.CallActLike<UserOrientedTemplate>(user);
|
||||
return template.GeneratedText;
|
||||
}
|
||||
|
||||
/* result.CallActLike<>
|
||||
|
||||
inMemoryAssembly.Seek(0, SeekOrigin.Begin);
|
||||
Assembly assembly = Assembly.Load(inMemoryAssembly.ToArray());
|
||||
// UserOrientedTemplate userOrientedTemplate = (UserOrientedTemplate)
|
||||
// FIXME Activator.CreateInstance(Type.GetType(templateInfo.TemplateType));
|
||||
|
||||
foreach (var user in dbContext.ApplicationUser.Where(
|
||||
u => u.AllowMonthlyEmail
|
||||
))
|
||||
{
|
||||
logger.LogInformation("Generation for " + user.UserName);
|
||||
userOrientedTemplate.Init();
|
||||
userOrientedTemplate.User = user; */
|
||||
throw new NotImplementedException();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue