Refactoring
The main server owns the migrations, it's the server part, it's simpler. It's Yavsc, not one of its lib.
This commit is contained in:
parent
52edbff231
commit
b3d565b6d9
67 changed files with 130 additions and 164 deletions
|
|
@ -27,6 +27,7 @@ using IdentityModel;
|
|||
using System.Security.Cryptography;
|
||||
using System.Text.Unicode;
|
||||
using System.Text;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ using Yavsc.Services;
|
|||
using Yavsc.ViewModels.Manage;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
@ -709,7 +710,8 @@ namespace Yavsc.Controllers
|
|||
|
||||
private async Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return await _dbContext.Users.Include(u => u.PostalAddress).FirstOrDefaultAsync(u => u.Id == User.GetUserId());
|
||||
return await _dbContext.Users.Include(u => u.PostalAddress)
|
||||
.FirstOrDefaultAsync(u => u.Id == User.GetUserId());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Abstract.Identity;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.ViewModels;
|
||||
using Yavsc.ViewModels.Administration;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Yavsc.Server.Settings;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Models.Calendar;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.Extensions.Options;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.ViewModels.Blog;
|
||||
using Yavsc.Server.Exceptions;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Relationship;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Relationship;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Yavsc.Abstract.Models.Messaging;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Messaging;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace Yavsc.Controllers
|
|||
using Models;
|
||||
using Models.Workflow;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
[Authorize("AdministratorOnly")]
|
||||
public class ActivityController : Controller
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Auth;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Workflow;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Yavsc.Controllers
|
|||
using Models.Workflow;
|
||||
using Services;
|
||||
using Yavsc.Interface;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Settings;
|
||||
|
||||
public class CommandController : Controller
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Workflow;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace Yavsc.Controllers
|
|||
using System.Threading.Tasks;
|
||||
using Yavsc.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
[Authorize]
|
||||
public class DoController : Controller
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Forms;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace Yavsc.Controllers
|
|||
using Models;
|
||||
using Models.Musical;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
public class MusicalTendenciesController : Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Billing;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace Yavsc.Controllers.Generic
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Models;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Services;
|
||||
|
||||
[Authorize]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Drawing;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ namespace Yavsc.Controllers
|
|||
using Yavsc.Interface;
|
||||
using Yavsc.Settings;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
public class HairCutCommandController : CommandController
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Haircut;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc.Localization;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Yavsc.Models;
|
|||
using Yavsc.Server.Models.IT.SourceCode;
|
||||
using Yavsc.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Musical.Profiles;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
namespace Yavsc.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace Yavsc.Controllers
|
|||
using Models;
|
||||
using Models.Musical;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
|
||||
public class InstrumentsController : Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Yavsc.Helpers;
|
|||
using Yavsc.Migrations;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.ViewModels.Auth;
|
||||
|
||||
namespace Yavsc.Extensions;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,32 @@
|
|||
using System.Security.Claims;
|
||||
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))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
194
src/Yavsc/Services/BlogSpotService.cs
Normal file
194
src/Yavsc/Services/BlogSpotService.cs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
|
||||
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;
|
||||
using Yavsc.ViewModels.Blog;
|
||||
|
||||
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, BlogPostEditViewModel blogInput)
|
||||
{
|
||||
BlogPost post = new BlogPost
|
||||
{
|
||||
Title = blogInput.Title,
|
||||
Content = blogInput.Content,
|
||||
Photo = blogInput.Photo,
|
||||
AuthorId = userId
|
||||
};
|
||||
_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);
|
||||
}
|
||||
return BlogPostEditViewModel.From(blog);
|
||||
}
|
||||
|
||||
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.Content = blogEdit.Content;
|
||||
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/Services/ChatHubConnexionManager.cs
Normal file
343
src/Yavsc/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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,8 +23,15 @@ public class ClientStore : IClientStore
|
|||
ClientId = clientFromDb.Id,
|
||||
ClientName = clientFromDb.DisplayName,
|
||||
ClientSecrets = { new Secret(clientFromDb.Secret.Sha256()) },
|
||||
AllowedGrantTypes =[ GrantType.ClientCredentials, GrantType.DeviceFlow],
|
||||
AllowedScopes = ["openid", "profile", "scope1"]
|
||||
AllowedGrantTypes =
|
||||
[
|
||||
GrantType.AuthorizationCode,
|
||||
GrantType.DeviceFlow,
|
||||
GrantType.ClientCredentials
|
||||
],
|
||||
AllowedScopes = ["openid", "profile", "scope1"],
|
||||
AbsoluteRefreshTokenLifetime = clientFromDb.RefreshTokenLifeTime,
|
||||
AccessTokenLifetime = clientFromDb.AccessTokenLifetime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
101
src/Yavsc/Services/DiskUsageTracker.cs
Normal file
101
src/Yavsc/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();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
171
src/Yavsc/Services/YavscTemplateEngine.cs
Normal file
171
src/Yavsc/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
@using Microsoft.AspNetCore.Html;
|
||||
@using Microsoft.AspNetCore.Identity;
|
||||
@using Yavsc.Helpers;
|
||||
@using Yavsc.Server.Helpers;
|
||||
@using PayPal.PayPalAPIInterfaceService.Model;
|
||||
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue