Paul Schneider 9 years ago
commit 60d9270fb3
16 changed files with 156 additions and 45 deletions

@ -6,33 +6,43 @@ using Microsoft.Data.Entity;
namespace Yavsc.Controllers namespace Yavsc.Controllers
{ {
using Microsoft.AspNet.Identity;
using Models; using Models;
using ViewModels.Chat; using ViewModels.Chat;
[Route("api/chat")] [Route("api/chat")]
public class ChatApiController : Controller public class ChatApiController : Controller
{ {
ApplicationDbContext dbContext;
UserManager<ApplicationUser> userManager;
public ChatApiController(ApplicationDbContext dbContext,
UserManager<ApplicationUser> userManager)
{
this.dbContext = dbContext;
this.userManager = userManager;
}
[HttpGet("users")] [HttpGet("users")]
public List<ChatUserInfo> GetUserList() public IEnumerable<ChatUserInfo> GetUserList()
{ {
using (var db = new ApplicationDbContext()) {
var cxsQuery = db.Connections.Include(c=>c.Owner).GroupBy( c => c.ApplicationUserId );
List<ChatUserInfo> result = new List<ChatUserInfo>(); var cxsQuery = dbContext.Connections?.Include(c=>c.Owner).GroupBy( c => c.ApplicationUserId );
// List<ChatUserInfo> result = new List<ChatUserInfo>();
if (cxsQuery!=null)
foreach (var g in cxsQuery) { foreach (var g in cxsQuery) {
var uid = g.Key; var uid = g.Key;
var cxs = g.ToList(); var cxs = g.ToList();
if (cxs !=null)
if (cxs.Count>0) {
var user = cxs.First().Owner; var user = cxs.First().Owner;
result.Add(new ChatUserInfo { UserName = user.UserName, yield return new ChatUserInfo { UserName = user.UserName,
UserId = user.Id, Avatar = user.Avatar, Connections = cxs } ); UserId = user.Id, Avatar = user.Avatar, Connections = cxs,
Roles = ( userManager.GetRolesAsync(user) ).Result.ToArray() };
} }
return result;
} }
} }
} }
} }

@ -2,11 +2,12 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
using Yavsc.Models; using Yavsc.Models;
using YavscLib;
namespace Yavsc.Model.Chat namespace Yavsc.Model.Chat
{ {
public class Connection public class Connection : IConnection
{ {
[JsonIgnore] [JsonIgnore]
public string ApplicationUserId { get; set; } public string ApplicationUserId { get; set; }

@ -1,9 +1,12 @@
using System.IO; using System.IO;
using System.Security.Claims;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.StaticFiles; using Microsoft.AspNet.StaticFiles;
using Yavsc.ViewModels.Auth;
namespace Yavsc namespace Yavsc
{ {
@ -14,7 +17,7 @@ namespace Yavsc
public static FileServerOptions AvatarsOptions { get; set; } public static FileServerOptions AvatarsOptions { get; set; }
public void ConfigureFileServerApp(IApplicationBuilder app, public void ConfigureFileServerApp(IApplicationBuilder app,
SiteSettings siteSettings, IHostingEnvironment env) SiteSettings siteSettings, IHostingEnvironment env, IAuthorizationService authorizationService)
{ {
var userFilesDirInfo = new DirectoryInfo( siteSettings.UserFiles.Blog ); var userFilesDirInfo = new DirectoryInfo( siteSettings.UserFiles.Blog );
UserFilesDirName = userFilesDirInfo.FullName; UserFilesDirName = userFilesDirInfo.FullName;
@ -27,6 +30,14 @@ namespace Yavsc
RequestPath = new PathString(Constants.UserFilesPath), RequestPath = new PathString(Constants.UserFilesPath),
EnableDirectoryBrowsing = env.IsDevelopment() EnableDirectoryBrowsing = env.IsDevelopment()
}; };
UserFilesOptions.StaticFileOptions.OnPrepareResponse += async context =>
{
var uname = context.Context.User.GetUserName();
var path = context.Context.Request.Path;
var result = await authorizationService.AuthorizeAsync(context.Context.User, new ViewFileContext
{ UserName = uname, File = context.File, Path = path } , new ViewRequirement());
};
var avatarsDirInfo = new DirectoryInfo(Startup.SiteSetup.UserFiles.Avatars); var avatarsDirInfo = new DirectoryInfo(Startup.SiteSetup.UserFiles.Avatars);
if (!avatarsDirInfo.Exists) avatarsDirInfo.Create(); if (!avatarsDirInfo.Exists) avatarsDirInfo.Create();
AvatarsDirName = avatarsDirInfo.FullName; AvatarsDirName = avatarsDirInfo.FullName;

@ -15,7 +15,7 @@ namespace Yavsc
app.UseWebSockets(); app.UseWebSockets();
app.UseSignalR("/api/signalr"); app.UseSignalR("/api/signalr");
/*
var _sockets = new ConcurrentBag<WebSocket>(); var _sockets = new ConcurrentBag<WebSocket>();
app.Use( app.Use(
@ -56,7 +56,7 @@ namespace Yavsc
await next(); await next();
} }
} }
); ); */
} }
} }
} }

@ -183,6 +183,7 @@ namespace Yavsc
services.AddSingleton<IAuthorizationHandler, CommandViewHandler>(); services.AddSingleton<IAuthorizationHandler, CommandViewHandler>();
services.AddSingleton<IAuthorizationHandler, PostUserFileHandler>(); services.AddSingleton<IAuthorizationHandler, PostUserFileHandler>();
services.AddSingleton<IAuthorizationHandler, EstimateViewHandler>(); services.AddSingleton<IAuthorizationHandler, EstimateViewHandler>();
services.AddSingleton<IAuthorizationHandler, ViewFileHandler>();
services.AddMvc(config => services.AddMvc(config =>
{ {
@ -230,6 +231,7 @@ namespace Yavsc
IOptions<RequestLocalizationOptions> localizationOptions, IOptions<RequestLocalizationOptions> localizationOptions,
IOptions<OAuth2AppSettings> oauth2SettingsContainer, IOptions<OAuth2AppSettings> oauth2SettingsContainer,
RoleManager<IdentityRole> roleManager, RoleManager<IdentityRole> roleManager,
IAuthorizationService authorizationService,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
SiteSetup = siteSettings.Value; SiteSetup = siteSettings.Value;
@ -330,7 +332,7 @@ namespace Yavsc
Audience = siteSettings.Value.Audience; Audience = siteSettings.Value.Audience;
ConfigureOAuthApp(app, siteSettings.Value); ConfigureOAuthApp(app, siteSettings.Value);
ConfigureFileServerApp(app, siteSettings.Value, env); ConfigureFileServerApp(app, siteSettings.Value, env, authorizationService);
ConfigureWebSocketsApp(app, siteSettings.Value, env); ConfigureWebSocketsApp(app, siteSettings.Value, env);
app.UseRequestLocalization(localizationOptions.Value, (RequestCulture)new RequestCulture((string)"en")); app.UseRequestLocalization(localizationOptions.Value, (RequestCulture)new RequestCulture((string)"en"));

@ -54,7 +54,18 @@ namespace Yavsc {
} }
public class ViewFileHandler : AuthorizationHandler<ViewRequirement, ViewFileContext>
{
protected override void Handle(AuthorizationContext context, ViewRequirement requirement, ViewFileContext fileContext)
{
// TODO file access rules
if (fileContext.Path.StartsWith("/pub/"))
context.Succeed(requirement);
else {
context.Succeed(requirement);
}
}
}
public class CommandViewHandler : AuthorizationHandler<ViewRequirement, BookQuery> public class CommandViewHandler : AuthorizationHandler<ViewRequirement, BookQuery>
{ {

@ -0,0 +1,11 @@
using Microsoft.AspNet.FileProviders;
namespace Yavsc.ViewModels.Auth
{
public class ViewFileContext
{
public string UserName { get; set; }
public IFileInfo File { get; set; }
public string Path { get; set; }
}
}

@ -2,7 +2,7 @@ using System.Collections.Generic;
using Yavsc.Model.Chat; using Yavsc.Model.Chat;
namespace Yavsc.ViewModels.Chat {  namespace Yavsc.ViewModels.Chat { 
public class ChatUserInfo public class ChatUserInfo : IChatUserInfo
{ {
public List<Connection> Connections { get; set; } public List<Connection> Connections { get; set; }
@ -13,5 +13,19 @@ public class ChatUserInfo
public string Avatar { get; set; } public string Avatar { get; set; }
public string[] Roles { get; set; }
}
public interface IChatUserInfo
{
List<Connection> Connections { get; set; }
string UserId { get; set; }
string UserName { get; set; }
string Avatar { get; set; }
string[] Roles { get; set; }
} }
} }

@ -52,14 +52,20 @@
var getUsers = function() { var getUsers = function() {
$('#userlist').empty(); $('#userlist').empty();
$('#to').empty(); $('#to').empty();
chat.server.getUserList().done( $.get("/api/chat/users").done(
function(users) { function(users) {
$.each(users, function () { $.each(users, function () {
var user = this; var user = this;
document.userList[user.UserId]=user; var existent = $('#userlist li').filterByData("name",user.UserName);
$('#userlist').append('<li class="user">' + htmlEncode(user.UserName) + '</li>'); if (existent.length>0) existent.remove();
var li = $('<li class="user">'+htmlEncode(user.UserName)+'</li>');
$('#to').append('<option value="'+user.UserId+'">'+user.UserName+'</option>'); var cxids = [];
$.each(user.Connections,function() {
cxids.push(this.ConnectionId);
});
li.data("name",user.UserName);
li.data("cxids",cxids);
li.appendTo('#userlist');
}); });
} }
@ -80,11 +86,33 @@
$('#discussion').append('<li class="pv"><strong>' + htmlEncode(name) $('#discussion').append('<li class="pv"><strong>' + htmlEncode(name)
+ '</strong>: ' + htmlEncode(message) + '</li>'); + '</strong>: ' + htmlEncode(message) + '</li>');
}; };
var onUserConnected = function (cxid, username) { $.fn.filterByData = function(prop, val) {
$('#userlist').append('<li class="user">'+username+'</li>') return this.filter(
}; function() { return $(this).data(prop)==val; }
);
}
var onUserDisconnected = function (cxid, username) { var onUserDisconnected = function (cxid, username) {
$('#userlist li[data-uid='+cxid+']').remove(); $('#userlist li').filter (function() {
var nids = $(this).data("cxids").filter(function() {
return $(this) !== cxid
});
if (nids.Length==0) $(this).remove();
else $(this).data("cxids",nids)
});
};
var onUserConnected = function (cxid, username) {
var connected = $('#userlist li').filterByData("name",username);
if (connected.length>0) {
var ids = connected.data("cxids");
ids.push(cxid);
connected.data("cxids",ids);
} else {
var li = $('<li class="user">'+username+'</li>');
li.data("name",username);
li.data("cxids",[cxid]);
li.appendTo('#userlist');
}
}; };
chat.client.notify = function (tag, message, data) { chat.client.notify = function (tag, message, data) {
if (data) { if (data) {

@ -45,11 +45,10 @@
</div> </div>
<div class="navbar-collapse collapse"> <div class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index" class="navbar-link">@SR["Home"]</a></li>
<li><a asp-controller="Blogspot" asp-action="Index" class="navbar-link">@SR["Blogs"]</a></li> <li><a asp-controller="Blogspot" asp-action="Index" class="navbar-link">@SR["Blogs"]</a></li>
<li><a asp-controller="Home" asp-action="About" class="navbar-link">@SR["About"] @SiteSettings.Value.Title</a> </li>
<li><a asp-controller="Home" asp-action="Chat" class="navbar-link">@SR["Chat"]</a></li> <li><a asp-controller="Home" asp-action="Chat" class="navbar-link">@SR["Chat"]</a></li>
<li><a asp-controller="Home" asp-action="Contact" class="navbar-link">@SR["Contact"]</a></li> <li><a asp-controller="Home" asp-action="Contact" class="navbar-link">@SR["Contact"]</a></li>
<li><a asp-controller="Home" asp-action="About" class="navbar-link">@SR["About"] @SiteSettings.Value.Title</a> </li>
</ul> </ul>
@await Html.PartialAsync("_LoginPartial") @await Html.PartialAsync("_LoginPartial")
</div> </div>

@ -1,5 +1,5 @@
{ {
"name": "Yavsc", "name": "yavsc",
"version": "0.0.0", "version": "0.0.0",
"devDependencies": { "devDependencies": {
"grunt": "^1.0.1", "grunt": "^1.0.1",

@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace YavscLib
{
public interface IConnection
{
string ConnectionId { get; set; }
string UserAgent { get; set; }
bool Connected { get; set; }
}
public interface IChatUserInfo
{
IConnection[] Connections { get; set; }
string UserId { get; set; }
string UserName { get; set; }
string Avatar { get; set; }
string[] Roles { get; set; }
}
}

@ -57,6 +57,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="project.json" /> <Content Include="project.json" />
<Compile Include="IChatUserInfo.cs" />
<Compile Include="IBlackListed.cs" /> <Compile Include="IBlackListed.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />

@ -20,7 +20,6 @@
"System.Runtime": "4.0.0", "System.Runtime": "4.0.0",
"System.Globalization": "4.0.0", "System.Globalization": "4.0.0",
"System.Resources.ResourceManager": "4.0.0", "System.Resources.ResourceManager": "4.0.0",
"System.Resources.Reader": "4.0.0"
} }
} }
} }

@ -3,19 +3,20 @@
"version": 2, "version": 2,
"targets": { "targets": {
".NETFramework,Version=v4.5.1": {}, ".NETFramework,Version=v4.5.1": {},
".NETPortable,Version=v4.5,Profile=Profile111": {} ".NETPortable,Version=v4.5,Profile=Profile111": {},
".NETFramework,Version=v4.5.1/debian.8-x86": {},
".NETFramework,Version=v4.5.1/debian.8-x64": {},
".NETPortable,Version=v4.5,Profile=Profile111/debian.8-x86": {},
".NETPortable,Version=v4.5,Profile=Profile111/debian.8-x64": {}
}, },
"libraries": {}, "libraries": {},
"projectFileDependencyGroups": { "projectFileDependencyGroups": {
"": [], "": [],
".NETFramework,Version=v4.5.1": [], ".NETFramework,Version=v4.5.1": [],
".NETPortable,Version=v4.5,Profile=Profile111": [ ".NETPortable,Version=v4.5,Profile=Profile111": [
"System.Globalization >= 4.0.0", "fx/System.Runtime >= 4.0.0",
"System.Resources.Reader >= 4.0.0", "fx/System.Globalization >= 4.0.0",
"System.Resources.ResourceManager >= 4.0.0", "fx/System.Resources.ResourceManager >= 4.0.0"
"System.Runtime >= 4.0.0"
] ]
}, }
"tools": {},
"projectFileToolGroups": {}
} }

File diff suppressed because one or more lines are too long
Loading…