Compare commits
4 Commits
52ba9ff3a8
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
50be1ea726 | |||
fe6f1581dd | |||
f322e3f485 | |||
c4dc16dde4 |
@ -44,7 +44,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
dotnet-version: 8.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
7
.github/workflows/main.yml
vendored
Normal file
7
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
on: workflow_call
|
||||
jobs:
|
||||
my_first_job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run my action
|
||||
uses: ./.github/worklflows/dotnet
|
31
.vscode/launch.json
vendored
31
.vscode/launch.json
vendored
@ -4,32 +4,6 @@
|
||||
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "C#: sampleWebAsWebApiClient Debug",
|
||||
"type": "dotnet",
|
||||
"request": "launch",
|
||||
"projectPath": "${workspaceFolder}/src/sampleWebAsWebApiClient/sampleWebAsWebApiClient.csproj"
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/bin/Debug/<target-framework>/<project-name.dll>",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/* {
|
||||
@ -109,11 +83,6 @@
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"presentation": {
|
||||
"hidden": false,
|
||||
"group": "run",
|
||||
"order": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
|
6
.vscode/tasks.json
vendored
6
.vscode/tasks.json
vendored
@ -9,12 +9,8 @@
|
||||
"args": [
|
||||
"build",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign",
|
||||
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"group": "build",
|
||||
"isBuildCommand": true,
|
||||
"isTestCommand": false,
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
|
@ -15,13 +15,14 @@ WorkingDirectory=/srv/www/yavsc/
|
||||
ExecStart=/srv/www/yavsc/Yavsc
|
||||
Restart=always
|
||||
Environment="HOME=/srv/www/yavsc"
|
||||
Environment="ASPNETCORE_ENVIRONMENT=Production"
|
||||
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=YOUR Postgresql CONNECTION STRING"
|
||||
Environment="ASPNETCORE_ENVIRONMENT=lua"
|
||||
Environment="ASPNETCORE_ConnectionStrings__DefaultConnection=Server=localhost;Port=5432;Database=lua;Username=lua;Password=f3s-*Vx$;"
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=yavsc
|
||||
SyslogIdentifier=isnd
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
|
@ -111,9 +111,9 @@ namespace Yavsc.ApiControllers
|
||||
var user = dbContext.Users.Single(
|
||||
u => u.Id == uid
|
||||
);
|
||||
var info = user.MoveUserFileToDir(query.Id, query.To);
|
||||
var info = user.MoveUserFileToDir(query.id, query.to);
|
||||
if (!info.Done) return new BadRequestObjectResult(info);
|
||||
return Ok(new { moved = query.Id });
|
||||
return Ok(new { moved = query.id });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -124,21 +124,21 @@ namespace Yavsc.ApiControllers
|
||||
if (!ModelState.IsValid) {
|
||||
var idvr = new ValidRemoteUserFilePathAttribute();
|
||||
|
||||
return this.BadRequest(new { id = idvr.IsValid(query.Id), to = idvr.IsValid(query.To), errors = ModelState });
|
||||
return this.BadRequest(new { id = idvr.IsValid(query.id), to = idvr.IsValid(query.to), errors = ModelState });
|
||||
}
|
||||
_logger.LogInformation($"Valid move query: {query.Id} => {query.To}");
|
||||
_logger.LogInformation($"Valid move query: {query.id} => {query.to}");
|
||||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var user = dbContext.Users.Single(
|
||||
u => u.Id == uid
|
||||
);
|
||||
try {
|
||||
if (Config.UserFilesOptions.FileProvider.GetFileInfo(Path.Combine(user.UserName, query.Id)).Exists)
|
||||
if (Config.UserFilesOptions.FileProvider.GetFileInfo(Path.Combine(user.UserName, query.id)).Exists)
|
||||
{
|
||||
var result = user.MoveUserFile(query.Id, query.To);
|
||||
var result = user.MoveUserFile(query.id, query.to);
|
||||
if (!result.Done) return new BadRequestObjectResult(result);
|
||||
}
|
||||
else {
|
||||
var result = user.MoveUserDir(query.Id, query.To);
|
||||
var result = user.MoveUserDir(query.id, query.to);
|
||||
if (!result.Done) return new BadRequestObjectResult(result);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,23 @@
|
||||
using Yavsc.Attributes.Validation;
|
||||
namespace Yavsc.Models.FileSystem
|
||||
{
|
||||
public class RenameFileQuery {
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public string id { get; set; }
|
||||
|
||||
public class MoveFileQuery
|
||||
{
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public required string Id { get; set; }
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public string to { get; set; }
|
||||
}
|
||||
public class MoveFileQuery {
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public string id { get; set; }
|
||||
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public required string To { get; set; }
|
||||
}
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public string to { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
using Yavsc.Attributes.Validation;
|
||||
namespace Yavsc.Models.FileSystem
|
||||
{
|
||||
public class RenameFileQuery
|
||||
{
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public required string Id { get; set; }
|
||||
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public required string To { get; set; }
|
||||
}
|
||||
|
||||
}
|
@ -37,7 +37,7 @@ namespace Yavsc.Controllers
|
||||
}
|
||||
// GET: api/Estimate{?ownerId=User.GetUserId()}
|
||||
[HttpGet]
|
||||
public IActionResult GetEstimates(string? ownerId = null)
|
||||
public IActionResult GetEstimates(string ownerId = null)
|
||||
{
|
||||
if (ownerId == null) ownerId = User.GetUserId();
|
||||
else if (!UserIsAdminOrThis(ownerId)) // throw new Exception("Not authorized") ;
|
||||
|
@ -40,7 +40,7 @@ namespace Yavsc.ApiControllers
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("query/accept")]
|
||||
[HttpPost("query/reject")]
|
||||
public IActionResult AcceptQuery(string billingCode, long queryId)
|
||||
{
|
||||
if (billingCode == null) return BadRequest("billingCode");
|
||||
@ -51,6 +51,7 @@ namespace Yavsc.ApiControllers
|
||||
billing.Decided = true;
|
||||
dbContext.SaveChanges();
|
||||
return Ok();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,7 @@ public class NativeConfidentialController : Controller
|
||||
[FromBody] DeviceDeclaration declaration)
|
||||
{
|
||||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
if (uid == null)
|
||||
throw new InvalidOperationException("no name identifier from claims");
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
_logger.LogError("Invalid model for GCMD");
|
||||
|
@ -6,7 +6,6 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Api.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Yavsc.WebApi.Controllers
|
||||
{
|
||||
@ -31,9 +30,9 @@ namespace Yavsc.WebApi.Controllers
|
||||
return new BadRequestObjectResult(
|
||||
new { error = "user not found" });
|
||||
var uid = User.GetUserId();
|
||||
Debug.Assert(uid != null, "uid is null");
|
||||
|
||||
var userData = await GetUserData(uid);
|
||||
Debug.Assert(userData != null, "userData is null");
|
||||
|
||||
var user = new Yavsc.Models.Auth.Me(userData.Id, userData.UserName, userData.Email,
|
||||
userData.Avatar,
|
||||
userData.PostalAddress, userData.DedicatedGoogleCalendar);
|
||||
@ -58,7 +57,7 @@ namespace Yavsc.WebApi.Controllers
|
||||
[HttpGet("myhost")]
|
||||
public IActionResult MyHost ()
|
||||
{
|
||||
return Ok(new { host = Request.ForwardedFor() });
|
||||
return Ok(new { host = Request.ForHost() });
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,8 +13,8 @@ namespace Yavsc.Api.Helpers
|
||||
public static class RequestHelpers
|
||||
{
|
||||
// Check for some apache proxy header, if any
|
||||
public static string? ForwardedFor(this HttpRequest request) {
|
||||
string? host = request.Headers["X-Forwarded-For"];
|
||||
public static string ForHost(this HttpRequest request) {
|
||||
string host = request.Headers["X-Forwarded-For"];
|
||||
if (string.IsNullOrEmpty(host)) {
|
||||
host = request.Host.Value;
|
||||
} else { // Using X-Forwarded-For last address
|
||||
|
@ -9,7 +9,7 @@ namespace Yavsc.Api.Helpers
|
||||
{
|
||||
public static class UserHelpers
|
||||
{
|
||||
public static string? GetUserId(this ClaimsPrincipal user)
|
||||
public static string GetUserId(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
*/
|
||||
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Helpers;
|
||||
@ -61,8 +63,7 @@ internal class Program
|
||||
options.IncludeErrorDetails = true;
|
||||
options.Authority = "https://localhost:5001";
|
||||
options.TokenValidationParameters =
|
||||
new() { ValidateAudience = false, RoleClaimType = JwtClaimTypes.Role };
|
||||
options.MapInboundClaims = true;
|
||||
new() { ValidateAudience = false };
|
||||
});
|
||||
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
@ -73,9 +74,9 @@ internal class Program
|
||||
.AddTransient<ICalendarManager, CalendarManager>();
|
||||
services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
|
||||
/*
|
||||
services.AddIdentityApiEndpoints<ApplicationUser>();
|
||||
services.AddSingleton<IConnexionManager, HubConnectionManager>();
|
||||
services.AddSingleton<ILiveProcessor, LiveProcessor>();
|
||||
services.AddIdentityApiEndpoints<ApplicationUser>();
|
||||
services.AddSession();
|
||||
*/
|
||||
WorkflowHelpers.ConfigureBillingService();
|
||||
@ -100,10 +101,15 @@ internal class Program
|
||||
app.MapDefaultControllerRoute();
|
||||
app.MapGet("/identity", (HttpContext context) =>
|
||||
new JsonResult(context?.User?.Claims.Select(c => new { c.Type, c.Value }))
|
||||
);
|
||||
);
|
||||
|
||||
// app.UseSession();
|
||||
await app.RunAsync();
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
|
||||
|
||||
|
||||
using Yavsc.Abstract.Identity;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
public interface IBlogPostPayLoad
|
||||
{
|
||||
string? Content { get; set; }
|
||||
string? Photo { get; set; }
|
||||
string Content { get; set; }
|
||||
string Photo { get; set; }
|
||||
|
||||
}
|
||||
public interface IBlogPost : IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
|
||||
public interface IBlogPost :IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
|
||||
{
|
||||
string AuthorId { get; set; }
|
||||
IApplicationUser Author { get; }
|
||||
}
|
||||
}
|
||||
|
@ -5,21 +5,21 @@ namespace Yavsc
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly Scope[] SiteScopes = {
|
||||
new Scope { Id = "profile", Description = "Your profile informations" },
|
||||
new Scope { Id = "book" , Description ="Your booking interface"},
|
||||
new Scope { Id = "blog" , Description ="Your blogging interface"},
|
||||
new Scope { Id = "estimate" , Description ="Your estimation interface"},
|
||||
new Scope { Id = "contract" , Description ="Your contract signature access"},
|
||||
new Scope { Id = "admin" , Description ="Your administration rights on this site"},
|
||||
new Scope { Id = "moderation" , Description ="Your moderator interface"},
|
||||
public static readonly Scope[] SiteScopes = {
|
||||
new Scope { Id = "profile", Description = "Your profile informations" },
|
||||
new Scope { Id = "book" , Description ="Your booking interface"},
|
||||
new Scope { Id = "blog" , Description ="Your blogging interface"},
|
||||
new Scope { Id = "estimate" , Description ="Your estimation interface"},
|
||||
new Scope { Id = "contract" , Description ="Your contract signature access"},
|
||||
new Scope { Id = "admin" , Description ="Your administration rights on this site"},
|
||||
new Scope { Id = "moderation" , Description ="Your moderator interface"},
|
||||
new Scope { Id = "frontoffice" , Description ="Your front office interface" }
|
||||
};
|
||||
|
||||
public const string CompanyClaimType = "https://schemas.pschneider.fr/identity/claims/Company";
|
||||
public const string UserNameRegExp = @"^[a-zA-Z][a-zA-Z0-9._-]*$";
|
||||
public const string UserFileNamePatternRegExp = @"^([a-zA-Z0-9._-]*/)*[a-zA-Z0-9._-]+$";
|
||||
|
||||
|
||||
public const string LoginPath = "/signin";
|
||||
public const string LogoutPath = "/signout";
|
||||
|
||||
@ -52,7 +52,9 @@ namespace Yavsc
|
||||
public const int MaxUserNameLength = 26;
|
||||
|
||||
public const string LivePath = "/live/cast";
|
||||
|
||||
|
||||
public const string StreamingPath = "/api/stream/put";
|
||||
|
||||
public const string RoleClaimName = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace Yavsc.Models.Google.Messaging
|
||||
/// <summary>
|
||||
/// The error.
|
||||
/// </summary>
|
||||
public string? error;
|
||||
public string error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,10 +3,10 @@
|
||||
public interface IApplicationUser
|
||||
{
|
||||
string Id { get; set; }
|
||||
string? UserName { get; set; }
|
||||
string? Avatar { get ; set; }
|
||||
IAccountBalance? AccountBalance { get; }
|
||||
string? DedicatedGoogleCalendar { get; }
|
||||
ILocation? PostalAddress { get; }
|
||||
string UserName { get; set; }
|
||||
string Avatar { get ; set; }
|
||||
IAccountBalance AccountBalance { get; set; }
|
||||
string DedicatedGoogleCalendar { get; set; }
|
||||
ILocation PostalAddress { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ namespace Yavsc.Abstract.Identity.Security
|
||||
public interface ICircleAuthorized
|
||||
{
|
||||
long Id { get; set; }
|
||||
string AuthorId { get; }
|
||||
string OwnerId { get; }
|
||||
bool AuthorizeCircle(long circleId);
|
||||
ICircleAuthorization [] GetACL();
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "9.0.6",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
@ -80,12 +80,12 @@ public static class Config
|
||||
PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc",
|
||||
"http://localhost:5002/signout-callback-oidc" },
|
||||
|
||||
AllowedScopes = {
|
||||
AllowedScopes = {
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
IdentityServerConstants.StandardScopes.Profile,
|
||||
IdentityServerConstants.StandardScopes.Email,
|
||||
IdentityServerConstants.StandardScopes.OfflineAccess,
|
||||
"scope2" },
|
||||
"scope2" }
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
namespace Yavsc.Server.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class AuthorizationFailureException : Exception
|
||||
{
|
||||
public AuthorizationFailureException(Microsoft.AspNetCore.Authorization.AuthorizationResult auth) : base(auth?.Failure?.ToString()??auth?.ToString()??"AuthorizationResult failure")
|
||||
{
|
||||
}
|
||||
|
||||
public AuthorizationFailureException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public AuthorizationFailureException(string? message, Exception? innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace Yavsc.Helpers
|
||||
|
||||
public static string GetUserName(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.FindFirstValue("name");
|
||||
return user.FindFirstValue(ClaimTypes.Name);
|
||||
}
|
||||
|
||||
public static bool IsSignedIn(this ClaimsPrincipal user)
|
||||
@ -24,14 +24,13 @@ namespace Yavsc.Helpers
|
||||
return user.Identity.IsAuthenticated;
|
||||
}
|
||||
|
||||
public static IEnumerable<BlogPost> UserPosts(this ApplicationDbContext dbContext, string posterId, string? readerId)
|
||||
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();
|
||||
var userPosts = dbContext.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Where(x => ((x.AuthorId == posterId))).ToArray();
|
||||
return userPosts;
|
||||
}
|
||||
else
|
||||
|
@ -29,13 +29,11 @@ using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Yavsc
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Models;
|
||||
using Models.Chat;
|
||||
using Yavsc.Abstract.Chat;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Services;
|
||||
public partial class ChatHub : Hub, IDisposable
|
||||
{
|
||||
@ -194,11 +192,10 @@ namespace Yavsc
|
||||
NotifyUserInRoom(NotificationTypes.Error, room, "already registered.");
|
||||
return;
|
||||
}
|
||||
Debug.Assert(Context.User != null);
|
||||
string userName = Context.User.GetUserName();
|
||||
string userName = Context.User.Identity.Name;
|
||||
var user = _dbContext.Users.FirstOrDefault(u => u.UserName == userName);
|
||||
|
||||
var newroom = new ChatRoom { Name = room, OwnerId = Context.User.GetUserId() };
|
||||
var newroom = new ChatRoom { Name = room, OwnerId = user.Id };
|
||||
ChatRoomInfo chanInfo;
|
||||
if (_cxManager.TryGetChanInfo(room, out chanInfo))
|
||||
{
|
||||
@ -322,7 +319,7 @@ namespace Yavsc
|
||||
|
||||
async Task NotifyUser(string type, string targetId, string message)
|
||||
{
|
||||
_logger.LogInformation($"notifying user {type} {targetId} : {message}");
|
||||
_logger.LogInformation("notifying user {type} {targetId} : {message}");
|
||||
await Clients.Caller.SendAsync("notifyUser", type, targetId, message);
|
||||
}
|
||||
|
||||
@ -334,8 +331,6 @@ namespace Yavsc
|
||||
[Authorize]
|
||||
public async Task SendPV(string userName, string message)
|
||||
{
|
||||
// Authorized code
|
||||
Debug.Assert(Context.User != null);
|
||||
_logger.LogInformation($"Sending pv to {userName}");
|
||||
|
||||
if (!InputValidator.ValidateUserName(userName))
|
||||
@ -349,21 +344,19 @@ namespace Yavsc
|
||||
return ;
|
||||
}
|
||||
_logger.LogInformation($"Message form is validated.");
|
||||
var identityUserName = Context.User.GetUserName();
|
||||
|
||||
if (userName[0] != '?' && Context.User!=null)
|
||||
if (userName[0] != '?')
|
||||
if (!Context.User.IsInRole(Constants.AdminGroupName))
|
||||
{
|
||||
|
||||
var bl = _dbContext.BlackListed
|
||||
.Include(r => r.User)
|
||||
.Include(r => r.Owner)
|
||||
.Where(r => r.User.UserName == identityUserName && r.Owner.UserName == userName)
|
||||
.Where(r => r.User.UserName == Context.User.Identity.Name && r.Owner.UserName == userName)
|
||||
.Select(r => r.OwnerId);
|
||||
|
||||
if (bl.Count() > 0)
|
||||
{
|
||||
_logger.LogError($"Black listed : {identityUserName}");
|
||||
_logger.LogError($"Black listed : {Context.User.Identity.Name}");
|
||||
await NotifyUser(NotificationTypes.PrivateMessageDenied, userName, "you are black listed.");
|
||||
return;
|
||||
}
|
||||
@ -379,7 +372,7 @@ namespace Yavsc
|
||||
_logger.LogInformation($"cx: {connectionId}");
|
||||
var cli = Clients.Client(connectionId);
|
||||
_logger.LogInformation($"cli: {cli.ToString()}");
|
||||
await cli.SendAsync("addPV", identityUserName, message);
|
||||
await cli.SendAsync("addPV", Context.User.Identity.Name, message);
|
||||
_logger.LogInformation($"Sent pv to cx {connectionId}");
|
||||
}
|
||||
}
|
||||
@ -387,9 +380,6 @@ namespace Yavsc
|
||||
[Authorize]
|
||||
public async Task SendStream(string connectionId, long streamId, string message)
|
||||
{
|
||||
// Authorized code
|
||||
Debug.Assert(Context.User != null);
|
||||
Debug.Assert(Context.User.Identity != null);
|
||||
if (!InputValidator.ValidateMessage(message)) return;
|
||||
var sender = Context.User.Identity.Name;
|
||||
var cli = Clients.Client(connectionId);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,108 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ActivityNulls : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserModified",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserCreated",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "SettingsClassName",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Photo",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "ModeratorGroupName",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserModified",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserCreated",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "SettingsClassName",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Photo",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "ModeratorGroupName",
|
||||
table: "Activities",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class BrusherProfileSchedulerId : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
|
||||
table: "BrusherProfile");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "ScheduleOwnerId",
|
||||
table: "BrusherProfile",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
|
||||
table: "BrusherProfile",
|
||||
column: "ScheduleOwnerId",
|
||||
principalTable: "Schedule",
|
||||
principalColumn: "OwnerId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
|
||||
table: "BrusherProfile");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "ScheduleOwnerId",
|
||||
table: "BrusherProfile",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_BrusherProfile_Schedule_ScheduleOwnerId",
|
||||
table: "BrusherProfile",
|
||||
column: "ScheduleOwnerId",
|
||||
principalTable: "Schedule",
|
||||
principalColumn: "OwnerId",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class blogPostPub : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "blogspotPublications",
|
||||
columns: table => new
|
||||
{
|
||||
BlogpostId = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_blogspotPublications", x => x.BlogpostId);
|
||||
table.ForeignKey(
|
||||
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
|
||||
column: x => x.BlogpostId,
|
||||
principalTable: "BlogSpot",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "blogspotPublications");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class blogPusb2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
|
||||
table: "blogspotPublications");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_blogspotPublications",
|
||||
table: "blogspotPublications");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "blogspotPublications",
|
||||
newName: "blogSpotPublications");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Publish",
|
||||
table: "BlogSpot",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_blogSpotPublications",
|
||||
table: "blogSpotPublications",
|
||||
column: "BlogpostId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_blogSpotPublications_BlogSpot_BlogpostId",
|
||||
table: "blogSpotPublications",
|
||||
column: "BlogpostId",
|
||||
principalTable: "BlogSpot",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_blogSpotPublications_BlogSpot_BlogpostId",
|
||||
table: "blogSpotPublications");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_blogSpotPublications",
|
||||
table: "blogSpotPublications");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Publish",
|
||||
table: "BlogSpot");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "blogSpotPublications",
|
||||
newName: "blogspotPublications");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_blogspotPublications",
|
||||
table: "blogspotPublications",
|
||||
column: "BlogpostId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_blogspotPublications_BlogSpot_BlogpostId",
|
||||
table: "blogspotPublications",
|
||||
column: "BlogpostId",
|
||||
principalTable: "BlogSpot",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class blogPub2 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,54 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class commentAllowed : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Comment",
|
||||
table: "CircleAuthorizationToBlogPost",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Avatar",
|
||||
table: "AspNetUsers",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
defaultValue: "/images/Users/icon_user.png",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldDefaultValue: "/images/Users/icon_user.png");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Comment",
|
||||
table: "CircleAuthorizationToBlogPost");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Avatar",
|
||||
table: "AspNetUsers",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "/images/Users/icon_user.png",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true,
|
||||
oldDefaultValue: "/images/Users/icon_user.png");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class noPublishColumn : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Publish",
|
||||
table: "BlogSpot");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Publish",
|
||||
table: "BlogSpot",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
}
|
||||
}
|
@ -303,9 +303,6 @@ namespace Yavsc.Migrations
|
||||
b.Property<long>("BlogPostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Comment")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("CircleId", "BlogPostId");
|
||||
|
||||
b.HasIndex("BlogPostId");
|
||||
@ -341,6 +338,7 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
@ -859,16 +857,6 @@ namespace Yavsc.Migrations
|
||||
b.ToTable("Comment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b =>
|
||||
{
|
||||
b.Property<long>("BlogpostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("BlogpostId");
|
||||
|
||||
b.ToTable("blogSpotPublications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b =>
|
||||
{
|
||||
b.Property<string>("OwnerId")
|
||||
@ -1135,6 +1123,7 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ScheduleOwnerId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("ShampooPrice")
|
||||
@ -2092,6 +2081,7 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ModeratorGroupName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -2102,18 +2092,22 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Rate")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("SettingsClassName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UserCreated")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UserModified")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Code");
|
||||
@ -2775,17 +2769,6 @@ namespace Yavsc.Migrations
|
||||
b.Navigation("Post");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b =>
|
||||
{
|
||||
b.HasOne("Yavsc.Models.Blog.BlogPost", "BlogPost")
|
||||
.WithMany()
|
||||
.HasForeignKey("BlogpostId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("BlogPost");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b =>
|
||||
{
|
||||
b.HasOne("Yavsc.Models.ApplicationUser", "Owner")
|
||||
@ -2857,7 +2840,9 @@ namespace Yavsc.Migrations
|
||||
{
|
||||
b.HasOne("Yavsc.Models.Calendar.Schedule", "Schedule")
|
||||
.WithMany()
|
||||
.HasForeignKey("ScheduleOwnerId");
|
||||
.HasForeignKey("ScheduleOwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "BaseProfile")
|
||||
.WithMany()
|
||||
@ -3392,7 +3377,8 @@ namespace Yavsc.Migrations
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Navigation("AccountBalance");
|
||||
b.Navigation("AccountBalance")
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("BankInfo");
|
||||
|
||||
|
@ -8,8 +8,8 @@ namespace Yavsc.Models.Access
|
||||
|
||||
public class CircleAuthorizationToBlogPost : ICircleAuthorization
|
||||
{
|
||||
public long CircleId { get; set; }
|
||||
public long BlogPostId { get; set; }
|
||||
public long CircleId { get; set; }
|
||||
public long BlogPostId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey("BlogPostId")]
|
||||
@ -17,10 +17,7 @@ namespace Yavsc.Models.Access
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey("CircleId")]
|
||||
public virtual Circle Allowed { get; set; }
|
||||
|
||||
public bool Comment { get; set; }
|
||||
|
||||
public virtual Circle Allowed { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Yavsc.Models.Haircut;
|
||||
using Yavsc.Models.IT.Evolution;
|
||||
using Yavsc.Models.IT.Fixing;
|
||||
@ -6,6 +10,7 @@ using Yavsc.Server.Models.EMailing;
|
||||
using Yavsc.Server.Models.IT.SourceCode;
|
||||
using Yavsc.Server.Models.IT;
|
||||
using Yavsc.Models.Streaming;
|
||||
using Yavsc.Models.Musical;
|
||||
|
||||
namespace Yavsc.Models
|
||||
{
|
||||
@ -27,6 +32,7 @@ namespace Yavsc.Models
|
||||
using Attributes;
|
||||
using Bank;
|
||||
using Payment;
|
||||
using Calendar;
|
||||
using Blog;
|
||||
using Yavsc.Abstract.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -42,12 +48,10 @@ namespace Yavsc.Models
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
@ -57,7 +61,7 @@ namespace Yavsc.Models
|
||||
builder.Entity<Contact>().HasKey(x => new { x.OwnerId, x.UserId });
|
||||
builder.Entity<DeviceDeclaration>().Property(x => x.DeclarationDate).HasDefaultValueSql("LOCALTIMESTAMP");
|
||||
builder.Entity<BlogTag>().HasKey(x => new { x.PostId, x.TagId });
|
||||
|
||||
|
||||
builder.Entity<ApplicationUser>().Property(u => u.FullName).IsRequired(false);
|
||||
builder.Entity<ApplicationUser>().Property(u => u.DedicatedGoogleCalendar).IsRequired(false);
|
||||
builder.Entity<ApplicationUser>().HasMany<ChatConnection>(c => c.Connections);
|
||||
@ -77,7 +81,7 @@ namespace Yavsc.Models
|
||||
builder.Entity<Models.Cratie.Option>().HasKey(o => new { o.Code, o.CodeScrutin });
|
||||
builder.Entity<Notification>().Property(n => n.icon).HasDefaultValue("exclam");
|
||||
builder.Entity<ChatRoomAccess>().HasKey(p => new { room = p.ChannelName, user = p.UserId });
|
||||
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument = i.InstrumentId, owner = i.OwnerId });
|
||||
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument= i.InstrumentId, owner = i.OwnerId });
|
||||
|
||||
foreach (var et in builder.Model.GetEntityTypes())
|
||||
{
|
||||
@ -85,22 +89,23 @@ namespace Yavsc.Models
|
||||
et.FindProperty("DateCreated").SetAfterSaveBehavior(Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore);
|
||||
}
|
||||
|
||||
builder.Entity<Activity>().Property(a => a.ParentCode).IsRequired(false);
|
||||
// builder.Entity<IdentityUserLogin<String>>().HasKey(i=> new { i.LoginProvider, i.UserId, i.ProviderKey });
|
||||
builder.Entity<Activity>().Property(a=>a.ParentCode).IsRequired(false);
|
||||
//builder.Entity<BlogPost>().HasOne(p => p.Author).WithMany(a => a.Posts);
|
||||
|
||||
}
|
||||
|
||||
// this is not a failback procedure.
|
||||
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
var appSetup = (string)AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
|
||||
if (!string.IsNullOrWhiteSpace(appSetup))
|
||||
var appSetup = (string) AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
|
||||
if (!string.IsNullOrWhiteSpace(appSetup))
|
||||
{
|
||||
optionsBuilder.UseNpgsql(appSetup);
|
||||
return;
|
||||
}
|
||||
var envSetup = Environment.GetEnvironmentVariable(Constants.YavscConnectionStringEnvName);
|
||||
if (envSetup != null)
|
||||
if (envSetup!=null)
|
||||
optionsBuilder.UseNpgsql(envSetup);
|
||||
else optionsBuilder.UseNpgsql();
|
||||
}
|
||||
@ -120,7 +125,7 @@ namespace Yavsc.Models
|
||||
/// Users posts
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DbSet<BlogPost> BlogSpot { get; set; }
|
||||
public DbSet<Blog.BlogPost> BlogSpot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skills powered by this site
|
||||
@ -221,14 +226,14 @@ namespace Yavsc.Models
|
||||
((ITrackedEntity)entity.Entity).UserModified = userId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int SaveChanges(string userId)
|
||||
{
|
||||
AddTimestamps(userId);
|
||||
return base.SaveChanges();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<int> SaveChangesAsync(string userId, CancellationToken ctoken = default(CancellationToken))
|
||||
{
|
||||
@ -277,7 +282,7 @@ namespace Yavsc.Models
|
||||
public DbSet<Comment> Comment { get; set; }
|
||||
|
||||
public DbSet<Announce> Announce { get; set; }
|
||||
|
||||
|
||||
// TODO remove and opt for for memory only storing,
|
||||
// as long as it must be set empty each time the service is restarted,
|
||||
// and that chatting should be kept as must as possible independent from db context
|
||||
@ -290,7 +295,7 @@ namespace Yavsc.Models
|
||||
public DbSet<GitRepositoryReference> GitRepositoryReference { get; set; }
|
||||
|
||||
public DbSet<Project> Project { get; set; }
|
||||
|
||||
|
||||
[Obsolete("use signaled flows")]
|
||||
public DbSet<LiveFlow> LiveFlow { get; set; }
|
||||
|
||||
@ -299,8 +304,6 @@ namespace Yavsc.Models
|
||||
public DbSet<InstrumentRating> InstrumentRating { get; set; }
|
||||
|
||||
public DbSet<Scope> Scopes { get; set; }
|
||||
|
||||
public DbSet<BlogSpotPublication> blogSpotPublications{ get; set; }
|
||||
// public DbSet<IdentityUserLogin<String>> AspNetUserLogins { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,10 @@ using Yavsc.Models.Identity;
|
||||
using Yavsc.Models.Chat;
|
||||
using Yavsc.Models.Bank;
|
||||
using Yavsc.Models.Access;
|
||||
using Yavsc.Abstract.Identity;
|
||||
|
||||
namespace Yavsc.Models
|
||||
{
|
||||
[Table("AspNetUsers")]
|
||||
public class ApplicationUser : IdentityUser, IApplicationUser
|
||||
public class ApplicationUser : IdentityUser
|
||||
{
|
||||
/// <summary>
|
||||
/// Another me, as a byte array.TG7@Eu%80rufzkhbb
|
||||
@ -24,10 +22,10 @@ namespace Yavsc.Models
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MaxLength(512)]
|
||||
public string? Avatar { get; set; }
|
||||
public string Avatar { get; set; }
|
||||
|
||||
[MaxLength(512)]
|
||||
public string? FullName { get; set; }
|
||||
public string FullName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -35,31 +33,32 @@ namespace Yavsc.Models
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Display(Name = "Account balance")]
|
||||
public virtual AccountBalance? AccountBalance { get; set; }
|
||||
public virtual AccountBalance AccountBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User's posts
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[InverseProperty("Author"), JsonIgnore]
|
||||
public virtual List<Blog.BlogPost>? Posts { get; set; }
|
||||
public virtual List<Blog.BlogPost> Posts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User's contact list
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[InverseProperty("Owner"), JsonIgnore]
|
||||
public virtual List<Contact>? Book { get; set; }
|
||||
public virtual List<Contact> Book { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// External devices using the API
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[InverseProperty("DeviceOwner"), JsonIgnore]
|
||||
public virtual List<DeviceDeclaration>? DeviceDeclaration { get; set; }
|
||||
public virtual List<DeviceDeclaration> DeviceDeclaration { get; set; }
|
||||
|
||||
[InverseProperty("Owner"), JsonIgnore]
|
||||
public virtual List<ChatConnection>? Connections { get; set; }
|
||||
public virtual List<ChatConnection> Connections { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// User's circles
|
||||
@ -67,7 +66,7 @@ namespace Yavsc.Models
|
||||
/// <returns></returns>
|
||||
[InverseProperty("Owner"), JsonIgnore]
|
||||
|
||||
public virtual List<Circle>? Circles { get; set; }
|
||||
public virtual List<Circle> Circles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Billing postal address
|
||||
@ -82,14 +81,14 @@ namespace Yavsc.Models
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MaxLength(512)]
|
||||
public string? DedicatedGoogleCalendar { get; set; }
|
||||
public string DedicatedGoogleCalendar { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Id + " " + this.AccountBalance?.Credits.ToString() + this.Email + " " + this.UserName + " $" + this.AccountBalance?.Credits.ToString();
|
||||
}
|
||||
|
||||
public virtual List<BankIdentity>? BankInfo { get; set; }
|
||||
public virtual List<BankIdentity> BankInfo { get; set; }
|
||||
|
||||
public long DiskQuota { get; set; } = 512 * 1024 * 1024;
|
||||
public long DiskUsage { get; set; } = 0;
|
||||
@ -98,24 +97,21 @@ namespace Yavsc.Models
|
||||
|
||||
[JsonIgnore]
|
||||
[InverseProperty("Owner")]
|
||||
public virtual List<BlackListed>? BlackList { get; set; }
|
||||
public virtual List<BlackListed> BlackList { get; set; }
|
||||
|
||||
public bool AllowMonthlyEmail { get; set; } = false;
|
||||
|
||||
[JsonIgnore]
|
||||
[InverseProperty("Owner")]
|
||||
public virtual List<ChatRoom>? Rooms { get; set; }
|
||||
public virtual List<ChatRoom> Rooms { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[InverseProperty("User")]
|
||||
public virtual List<ChatRoomAccess>? RoomAccess { get; set; }
|
||||
public virtual List<ChatRoomAccess> RoomAccess { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[InverseProperty("Member")]
|
||||
public virtual List<CircleMember>? Membership { get; set; }
|
||||
public virtual List<CircleMember> Membership { get; set; }
|
||||
|
||||
IAccountBalance? IApplicationUser.AccountBalance => AccountBalance;
|
||||
|
||||
ILocation? IApplicationUser.PostalAddress { get => PostalAddress; }
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using Yavsc;
|
||||
using Yavsc.Abstract.Identity;
|
||||
using Yavsc.Abstract.Identity.Security;
|
||||
using Yavsc.Attributes.Validation;
|
||||
using Yavsc.Interfaces;
|
||||
@ -16,8 +14,7 @@ using Yavsc.ViewModels.Blog;
|
||||
|
||||
namespace Yavsc.Models.Blog
|
||||
{
|
||||
public class BlogPost : BlogPostBase,
|
||||
IBlogPost, ICircleAuthorized, ITaggable<long>
|
||||
public class BlogPost : BlogPostInputViewModel, IBlogPost, ICircleAuthorized, ITaggable<long>, IIdentified<long>
|
||||
{
|
||||
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Display(Name="Identifiant du post")]
|
||||
@ -88,6 +85,7 @@ namespace Yavsc.Models.Blog
|
||||
[InverseProperty("Post")]
|
||||
public virtual List<Comment> Comments { get; set; }
|
||||
|
||||
IApplicationUser IBlogPost.Author { get => this.Author; }
|
||||
[NotMapped]
|
||||
public string OwnerId => AuthorId;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Yavsc.Models.Blog;
|
||||
|
||||
namespace Yavsc.Models
|
||||
{
|
||||
public class BlogSpotPublication
|
||||
{
|
||||
[Key]
|
||||
public long BlogpostId { get; set; }
|
||||
|
||||
[ForeignKey("BlogpostId")]
|
||||
public virtual BlogPost BlogPost{ get; set; }
|
||||
}
|
||||
}
|
@ -60,7 +60,7 @@ namespace Yavsc.Models.Haircut
|
||||
|
||||
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Pas d'emploi du temps spécifié]")]
|
||||
[Display(Name="Emploi du temps")]
|
||||
public virtual Schedule? Schedule { get; set; }
|
||||
public virtual Schedule Schedule { get; set; }
|
||||
|
||||
[Display(Name="Coupe femme cheveux longs"),DisplayFormat(DataFormatString="{0:C}")]
|
||||
|
||||
|
@ -1,33 +0,0 @@
|
||||
namespace Yavsc.Models.Auth
|
||||
{
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
public class YaIdentityUserLogin
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the login provider for the login (e.g. facebook, google)
|
||||
/// </summary>
|
||||
public virtual string LoginProvider { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique provider identifier for this login.
|
||||
/// </summary>
|
||||
public virtual string ProviderKey { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the friendly name used in a UI for this login.
|
||||
/// </summary>
|
||||
public virtual string? ProviderDisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the primary key of the user associated with this login.
|
||||
/// </summary>
|
||||
public String UserId { get; set; } = default!;
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public virtual ApplicationUser User { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ namespace Yavsc.Models.Workflow
|
||||
[YaStringLength(512)]
|
||||
[Display(Name = "Code du parent")]
|
||||
[ForeignKey("Parent")]
|
||||
public string? ParentCode { get; set; }
|
||||
public string ParentCode { get; set; }
|
||||
|
||||
[Display(Name = "Activité parent"), JsonIgnore]
|
||||
public virtual Activity Parent { get; set; }
|
||||
@ -41,7 +41,7 @@ namespace Yavsc.Models.Workflow
|
||||
public string Description { get; set; }
|
||||
|
||||
[Display(Name = "Photo")]
|
||||
public string? Photo { get; set; }
|
||||
public string Photo { get; set; }
|
||||
|
||||
[InverseProperty("Context")]
|
||||
[DisplayAttribute(Name = "Services liés")]
|
||||
@ -52,7 +52,7 @@ namespace Yavsc.Models.Workflow
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayAttribute(Name = "Groupe de modération")]
|
||||
public string? ModeratorGroupName { get; set; }
|
||||
public string ModeratorGroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// indice de recherche de cette activité
|
||||
@ -64,7 +64,7 @@ namespace Yavsc.Models.Workflow
|
||||
[DisplayFormatAttribute(DataFormatString="{0}%")]
|
||||
public int Rate { get; set; }
|
||||
[DisplayAttribute(Name = "Classe de paramétrage")]
|
||||
public string? SettingsClassName { get; set; }
|
||||
public string SettingsClassName { get; set; }
|
||||
|
||||
[InverseProperty("Context")]
|
||||
[Display(Name="Formulaires de commande")]
|
||||
@ -77,7 +77,7 @@ namespace Yavsc.Models.Workflow
|
||||
}
|
||||
|
||||
[Display(Name="Createur")]
|
||||
public string? UserCreated
|
||||
public string UserCreated
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@ -89,7 +89,7 @@ namespace Yavsc.Models.Workflow
|
||||
}
|
||||
|
||||
[Display(Name="Utilisateur ayant modifié le dernier")]
|
||||
public string? UserModified
|
||||
public string UserModified
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ namespace Yavsc.Models.societe.com
|
||||
public class CompanyInfoMessage
|
||||
{
|
||||
public bool success { get; set; }
|
||||
public string? errorType { get; set; }
|
||||
public string? errorCode { get; set; }
|
||||
public string? errorMessage { get; set; }
|
||||
public CompanyInfo? result { get; set; }
|
||||
public string errorType { get; set; }
|
||||
public string errorCode { get; set; }
|
||||
public string errorMessage { get; set; }
|
||||
public CompanyInfo result { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
using Yavsc.Models.Blog;
|
||||
|
||||
public class BlogPostEdition
|
||||
{
|
||||
public string Content { get; internal set; }
|
||||
public string Title { get; internal set; }
|
||||
public string Photo { get; internal set; }
|
||||
|
||||
internal static BlogPostEdition From(BlogPost blog)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
}
|
@ -130,6 +130,7 @@ namespace Yavsc.Services
|
||||
public bool Part(string cxId, string roomName, string reason)
|
||||
{
|
||||
ChatRoomInfo chanInfo;
|
||||
var userName = ChatUserNames[cxId];
|
||||
if (Channels.TryGetValue(roomName, out chanInfo))
|
||||
{
|
||||
if (!chanInfo.Users.Contains(cxId))
|
||||
|
@ -1,9 +1,13 @@
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit.Security;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using Yavsc.Abstract.Manage;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Yavsc.Interface;
|
||||
using Yavsc.Settings;
|
||||
@ -23,7 +27,8 @@ namespace Yavsc.Services
|
||||
public MailSender(
|
||||
IOptions<SiteSettings> sitesOptions,
|
||||
IOptions<SmtpSettings> smtpOptions,
|
||||
ILoggerFactory loggerFactory
|
||||
ILoggerFactory loggerFactory,
|
||||
IStringLocalizer<Yavsc.YavscLocalization> localizer
|
||||
)
|
||||
{
|
||||
this.localizer = localizer;
|
||||
|
@ -57,18 +57,18 @@ namespace Yavsc.Services
|
||||
var roles = await this._userManager.GetRolesAsync(user);
|
||||
if (roles.Count()>0)
|
||||
{
|
||||
claims.AddRange(roles.Select(r => new Claim(JwtClaimTypes.Role, r)));
|
||||
claims.AddRange(roles.Select(r => new Claim(Constants.RoleClaimName, r)));
|
||||
}
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
{
|
||||
var subjectId = GetSubjectId(context.Subject);
|
||||
if (subjectId == null) return;
|
||||
if (subjectId==null) return;
|
||||
var user = await _userManager.FindByIdAsync(subjectId);
|
||||
if (user == null) return;
|
||||
if (user==null) return ;
|
||||
context.IssuedClaims = await GetClaimsFromUserAsync(context, user);
|
||||
}
|
||||
|
||||
|
@ -6,9 +6,7 @@ namespace Yavsc
|
||||
public class SiteSettings
|
||||
{
|
||||
public string Title { get; set; } = "Yavsc";
|
||||
|
||||
public string Slogan { get; set; } = "";
|
||||
public string Banner { get; set; } = "";
|
||||
|
||||
public string StyleSheet { get; set; } = "site.css";
|
||||
public string FavIcon { get; set; } = "favicon.ico";
|
||||
|
@ -1,50 +1,11 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Yavsc.Models.Blog;
|
||||
|
||||
namespace Yavsc.ViewModels.Blog;
|
||||
|
||||
|
||||
public class BlogPostCreateViewModel : BlogPostBase
|
||||
{
|
||||
public bool Publish { get; set; }
|
||||
}
|
||||
|
||||
public class BlogPostEditViewModel : BlogPostCreateViewModel
|
||||
public class BlogPostEditViewModel : BlogPostInputViewModel
|
||||
{
|
||||
|
||||
[Required]
|
||||
|
||||
public required long Id { get; set; }
|
||||
|
||||
|
||||
public BlogPostEditViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static BlogPostEditViewModel From(BlogPost blogInput)
|
||||
{
|
||||
return new BlogPostEditViewModel
|
||||
{
|
||||
Id = blogInput.Id,
|
||||
Title = blogInput.Title,
|
||||
Publish = false,
|
||||
Photo = blogInput.Photo,
|
||||
Content = blogInput.Content,
|
||||
ACL = blogInput.ACL
|
||||
};
|
||||
}
|
||||
public static BlogPostEditViewModel FromViewModel(BlogPostEditViewModel blogInput)
|
||||
{
|
||||
return new BlogPostEditViewModel
|
||||
{
|
||||
Id = blogInput.Id,
|
||||
Title = blogInput.Title,
|
||||
Publish = false,
|
||||
Photo = blogInput.Photo,
|
||||
Content = blogInput.Content,
|
||||
ACL = blogInput.ACL
|
||||
};
|
||||
}
|
||||
public required long Id { get; set; }
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ using Yavsc.Models.Access;
|
||||
|
||||
namespace Yavsc.ViewModels.Blog
|
||||
{
|
||||
public class BlogPostBase
|
||||
{
|
||||
public class BlogPostInputViewModel
|
||||
{
|
||||
[StringLength(1024)]
|
||||
public string? Photo { get; set; }
|
||||
|
||||
@ -18,8 +18,8 @@ namespace Yavsc.ViewModels.Blog
|
||||
public string? Content { get; set; }
|
||||
|
||||
[InverseProperty("Target")]
|
||||
[Display(Name = "Liste de contrôle d'accès")]
|
||||
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
|
||||
[Display(Name="Liste de contrôle d'accès")]
|
||||
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
|
||||
|
||||
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="5.0.17" />
|
||||
@ -19,14 +19,20 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
|
||||
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.69.0.3746" />
|
||||
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.60.0.2993" />
|
||||
<PackageReference Include="PayPalMerchantSDK" Version="2.16.250" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
|
||||
<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />
|
||||
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||
<PackageReference Include="MimeKit" Version="4.13.0" />
|
||||
<PackageReference Include="MailKit" Version="4.12.1" />
|
||||
<PackageReference Include="MimeKit" Version="4.12.0" />
|
||||
<PackageReference Include="pazof.rules" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
|
||||
</ItemGroup>
|
||||
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/
|
||||
|
||||
Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
Source code and license this software can be found
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
using System.Security.Claims;
|
||||
using IdentityModel;
|
||||
using IdentityServer8;
|
||||
using IdentityServer8.Events;
|
||||
using IdentityServer8.Services;
|
||||
using IdentityServer8.Stores;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc;
|
||||
using Yavsc.Extensions;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace IdentityServerHost.Quickstart.UI;
|
||||
|
||||
[SecurityHeaders]
|
||||
[AllowAnonymous]
|
||||
public class ExternalController : Controller
|
||||
{
|
||||
private readonly IIdentityServerInteractionService _interaction;
|
||||
private readonly IClientStore _clientStore;
|
||||
private readonly ILogger<ExternalController> _logger;
|
||||
private readonly IEventService _events;
|
||||
private IExternalIdentityManager _users;
|
||||
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly RoleManager<IdentityRole> _roleManager;
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public ExternalController(
|
||||
IIdentityServerInteractionService interaction,
|
||||
IClientStore clientStore,
|
||||
IEventService events,
|
||||
ILogger<ExternalController> logger,
|
||||
IExternalIdentityManager externalIdentityProviderManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
ApplicationDbContext dbContext,
|
||||
RoleManager<IdentityRole> roleManager
|
||||
)
|
||||
{
|
||||
// if the TestUserStore is not in DI, then we'll just use the global users collection
|
||||
// this is where you would plug in your own custom identity management library (e.g. ASP.NET Identity)
|
||||
_users = externalIdentityProviderManager;
|
||||
_interaction = interaction;
|
||||
_clientStore = clientStore;
|
||||
_logger = logger;
|
||||
_events = events;
|
||||
_signInManager = signInManager;
|
||||
_roleManager = roleManager;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initiate roundtrip to external authentication provider
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Challenge(string scheme, string returnUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(returnUrl)) returnUrl = "~/";
|
||||
|
||||
// validate returnUrl - either it is a valid OIDC URL or back to a local page
|
||||
if (Url.IsLocalUrl(returnUrl) == false && _interaction.IsValidReturnUrl(returnUrl) == false)
|
||||
{
|
||||
// user might have clicked on a malicious link - should be logged
|
||||
throw new Exception("invalid return URL");
|
||||
}
|
||||
|
||||
// start challenge and roundtrip the return URL and scheme
|
||||
var props = new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = Url.Action(nameof(Callback)),
|
||||
Items =
|
||||
{
|
||||
{ "returnUrl", returnUrl },
|
||||
{ "scheme", scheme },
|
||||
}
|
||||
};
|
||||
|
||||
return Challenge(props, scheme);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post processing of external authentication
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Callback()
|
||||
{
|
||||
// read external identity from the temporary cookie
|
||||
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
|
||||
if (result?.Succeeded != true)
|
||||
{
|
||||
throw new Exception("External authentication error");
|
||||
}
|
||||
|
||||
if (_logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
|
||||
_logger.LogDebug("External claims: {@claims}", externalClaims);
|
||||
}
|
||||
|
||||
// lookup our user and external provider info
|
||||
var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);
|
||||
if (user == null)
|
||||
{
|
||||
// this might be where you might initiate a custom workflow for user registration
|
||||
// in this sample we don't show how that would be done, as our sample implementation
|
||||
// simply auto-provisions new external user
|
||||
user = AutoProvisionUser(provider, providerUserId, claims);
|
||||
}
|
||||
|
||||
// this allows us to collect any additional claims or properties
|
||||
// for the specific protocols used and store them in the local auth cookie.
|
||||
// this is typically used to store data needed for signout from those protocols.
|
||||
var additionalLocalClaims = new List<Claim>();
|
||||
var localSignInProps = new AuthenticationProperties();
|
||||
ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);
|
||||
|
||||
// issue authentication cookie for user
|
||||
var isuser = new IdentityServerUser(user.Id)
|
||||
{
|
||||
DisplayName = user.UserName,
|
||||
IdentityProvider = provider,
|
||||
AdditionalClaims = additionalLocalClaims
|
||||
};
|
||||
await HttpContext.SignInAsync(isuser, localSignInProps);
|
||||
//await HttpContext.SignInAsync(user, _roleManager, false, _dbContext);
|
||||
|
||||
// delete temporary cookie used during external authentication
|
||||
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
|
||||
// retrieve return URL
|
||||
var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";
|
||||
|
||||
// check if external login is in the context of an OIDC request
|
||||
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
|
||||
await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName, true, context?.Client.ClientId));
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
if (context.IsNativeClient())
|
||||
{
|
||||
// The client is native, so this change in how to
|
||||
// return the response is for better UX for the end user.
|
||||
return this.LoadingPage("Redirect", returnUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
|
||||
private async Task<(ApplicationUser user,
|
||||
string provider,
|
||||
string providerUserId,
|
||||
IEnumerable<Claim> claims)>
|
||||
FindUserFromExternalProvider(AuthenticateResult result)
|
||||
{
|
||||
var externalUser = result.Principal;
|
||||
|
||||
// try to determine the unique id of the external user (issued by the provider)
|
||||
// the most common claim type for that are the sub claim and the NameIdentifier
|
||||
// depending on the external provider, some other claim type might be used
|
||||
var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ??
|
||||
externalUser.FindFirst(ClaimTypes.NameIdentifier) ??
|
||||
throw new Exception("Unknown userid");
|
||||
|
||||
// remove the user id claim so we don't include it as an extra claim if/when we provision the user
|
||||
var claims = externalUser.Claims.ToList();
|
||||
claims.Remove(userIdClaim);
|
||||
|
||||
var provider = result.Properties.Items["scheme"];
|
||||
var providerUserId = userIdClaim.Value;
|
||||
|
||||
// find external user
|
||||
|
||||
ApplicationUser? user = await _users.FindByExternaleProviderAsync (provider, providerUserId);
|
||||
|
||||
return (user, provider, providerUserId, claims);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new user by external id
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="providerUserId"></param>
|
||||
/// <param name="claims"></param>
|
||||
/// <returns></returns>
|
||||
private ApplicationUser AutoProvisionUser(string provider, string providerUserId, IEnumerable<Claim> claims)
|
||||
{
|
||||
var user = _users.AutoProvisionUser(provider, providerUserId, claims.ToList());
|
||||
return user;
|
||||
}
|
||||
|
||||
// if the external login is OIDC-based, there are certain things we need to preserve to make logout work
|
||||
// this will be different for WS-Fed, SAML2p or other protocols
|
||||
private void ProcessLoginCallback(AuthenticateResult externalResult, List<Claim> localClaims, AuthenticationProperties localSignInProps)
|
||||
{
|
||||
// if the external system sent a session id claim, copy it over
|
||||
// so we can use it for single sign-out
|
||||
var sid = externalResult.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);
|
||||
if (sid != null)
|
||||
{
|
||||
localClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
|
||||
}
|
||||
|
||||
// if the external provider issued an id_token, we'll keep it for signout
|
||||
var idToken = externalResult.Properties.GetTokenValue("id_token");
|
||||
if (idToken != null)
|
||||
{
|
||||
localSignInProps.StoreTokens(new[] { new AuthenticationToken { Name = "id_token", Value = idToken } });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/
|
||||
|
||||
Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
Source code and license this software can be found
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
using System.Security.Claims;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace Yavsc.Interfaces;
|
||||
|
||||
public interface IExternalIdentityManager
|
||||
{
|
||||
ApplicationUser AutoProvisionUser(string provider, string providerUserId, List<Claim> claims);
|
||||
Task<ApplicationUser?> FindByExternaleProviderAsync(string provider, string providerUserId);
|
||||
}
|
@ -1,15 +1,22 @@
|
||||
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.ViewModels.Auth;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.Helpers;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Diagnostics;
|
||||
using Yavsc.ViewModels.Blog;
|
||||
using Yavsc.Server.Exceptions;
|
||||
using System.Collections;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
@ -22,70 +29,111 @@ namespace Yavsc.Controllers
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
readonly RequestLocalizationOptions _localisationOptions;
|
||||
|
||||
readonly BlogSpotService blogSpotService;
|
||||
public BlogspotController(
|
||||
ApplicationDbContext context,
|
||||
ILoggerFactory loggerFactory,
|
||||
IAuthorizationService authorizationService,
|
||||
IOptions<RequestLocalizationOptions> localisationOptions,
|
||||
BlogSpotService blogSpotService)
|
||||
IOptions<RequestLocalizationOptions> localisationOptions)
|
||||
{
|
||||
_context = context;
|
||||
_logger = loggerFactory.CreateLogger<AccountController>();
|
||||
_authorizationService = authorizationService;
|
||||
_localisationOptions = localisationOptions.Value;
|
||||
this.blogSpotService = blogSpotService;
|
||||
}
|
||||
|
||||
// GET: Blog
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Index(string id, int skip = 0, int take = 25)
|
||||
public async Task<IActionResult> Index(string id, int skip=0, int take=25)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
return View("UserPosts",
|
||||
await blogSpotService.UserPosts(id, User.GetUserId(),
|
||||
skip, take));
|
||||
if (!string.IsNullOrEmpty(id)) {
|
||||
return View("UserPosts", await UserPosts(id));
|
||||
}
|
||||
IEnumerable<IBlogPost> index = await this.blogSpotService.Index(User, id, skip, take);
|
||||
return View(index);
|
||||
IEnumerable<BlogPost> 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.Count == 0)
|
||||
|| (p.AuthorId == viewerId)
|
||||
|| (usercircles != null && p.ACL.Any(a => usercircles.Contains(a.CircleId)))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
posts = _context.BlogSpot
|
||||
.Include(b => b.Author)
|
||||
.Include(p=>p.ACL)
|
||||
.Include(p=>p.Tags)
|
||||
.Include(p=>p.Comments)
|
||||
.Where(p => p.ACL.Count == 0 ).ToArray();
|
||||
}
|
||||
|
||||
var data = posts.OrderByDescending( p=> p.DateCreated);
|
||||
var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(take);
|
||||
|
||||
return View(grouped);
|
||||
}
|
||||
|
||||
[Route("~/Title/{id?}")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Title(string id)
|
||||
{
|
||||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
ViewData["Title"] = id;
|
||||
return View("Title", blogSpotService.GetTitle(id));
|
||||
return View("Title", _context.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Where(x => x.Title == id && (x.AuthorId == uid )).OrderByDescending(
|
||||
x => x.DateCreated
|
||||
).ToList());
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<BlogPost>> UserPosts(string userName, int pageLen = 10, int pageNum = 0)
|
||||
private async Task<IEnumerable<BlogPost>> UserPosts(string userName, int pageLen=10, int pageNum=0)
|
||||
{
|
||||
return await blogSpotService.UserPosts(userName, User.GetUserId(), pageLen, pageNum);
|
||||
|
||||
string posterId = (await _context.Users.SingleOrDefaultAsync(u=>u.UserName == userName))?.Id ?? null ;
|
||||
return _context.UserPosts(posterId, User.Identity.Name);
|
||||
}
|
||||
// GET: Blog/Details/5
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Details(long? id)
|
||||
{
|
||||
if (id == null) return this.NotFound();
|
||||
try
|
||||
if (id == null)
|
||||
{
|
||||
var blog = await blogSpotService.Details(User, id.Value);
|
||||
ViewData["apicmtctlr"] = "/api/blogcomments";
|
||||
ViewData["moderatoFlag"] = User.IsInRole(Constants.BlogModeratorGroupName);
|
||||
|
||||
return View(blog);
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
catch (AuthorizationFailureException ex)
|
||||
|
||||
BlogPost blog = _context.BlogSpot
|
||||
.Include(p => p.Author)
|
||||
.Include(p => p.Tags)
|
||||
.Include(p => p.Comments)
|
||||
.Include(p => p.ACL)
|
||||
.Single(m => m.Id == id);
|
||||
if (blog == null)
|
||||
{
|
||||
return Challenge();
|
||||
return NotFound();
|
||||
}
|
||||
if ( _authorizationService.AuthorizeAsync(User, blog, new ReadPermission()).IsFaulted)
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
foreach (var c in blog.Comments) {
|
||||
c.Author = _context.Users.First(u=>u.Id==c.AuthorId);
|
||||
}
|
||||
ViewData["apicmtctlr"] = "/api/blogcomments";
|
||||
ViewData["moderatoFlag"] = User.IsInRole(Constants.BlogModeratorGroupName);
|
||||
return View(blog);
|
||||
}
|
||||
void SetLangItems()
|
||||
{
|
||||
ViewBag.LangItems = _localisationOptions.SupportedUICultures?.Select
|
||||
ViewBag.LangItems = _localisationOptions.SupportedUICultures.Select
|
||||
(
|
||||
sc => new SelectListItem { Value = sc.IetfLanguageTag, Text = sc.NativeName, Selected = System.Globalization.CultureInfo.CurrentUICulture == sc }
|
||||
);
|
||||
@ -95,25 +143,33 @@ namespace Yavsc.Controllers
|
||||
[Authorize()]
|
||||
public IActionResult Create(string title)
|
||||
{
|
||||
var result = new BlogPostCreateViewModel
|
||||
{
|
||||
Title = title
|
||||
var result = new BlogPostInputViewModel{Title=title
|
||||
};
|
||||
ViewData["PostTarget"]="Create";
|
||||
SetLangItems();
|
||||
return View(result);
|
||||
}
|
||||
|
||||
// POST: Blog/Create
|
||||
[HttpPost, Authorize, ValidateAntiForgeryToken]
|
||||
public IActionResult Create(BlogPostEditViewModel blogInput)
|
||||
public IActionResult Create(BlogPostInputViewModel blogInput)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
BlogPost post = blogSpotService.Create(User.GetUserId(),
|
||||
BlogPostEditViewModel.FromViewModel(blogInput));
|
||||
BlogPost post = new BlogPost
|
||||
{
|
||||
Title = blogInput.Title,
|
||||
Content = blogInput.Content,
|
||||
Photo = blogInput.Photo,
|
||||
AuthorId = User.GetUserId()
|
||||
};
|
||||
_context.BlogSpot.Add(post);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
return View("Edit", blogInput);
|
||||
ModelState.AddModelError("Unknown","Invalid Blog posted ...");
|
||||
ViewData["PostTarget"]="Create";
|
||||
return View("Edit",blogInput);
|
||||
}
|
||||
|
||||
[Authorize()]
|
||||
@ -124,18 +180,37 @@ namespace Yavsc.Controllers
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
try
|
||||
{
|
||||
var blog = await blogSpotService.GetPostForEdition(User, id.Value);
|
||||
if (blog == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
SetLangItems();
|
||||
return View(blog);
|
||||
|
||||
ViewData["PostTarget"]="Edit";
|
||||
BlogPost blog = _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).Single(m => m.Id == id);
|
||||
|
||||
if (blog == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
catch (AuthorizationFailureException)
|
||||
if (!_authorizationService.AuthorizeAsync(User, blog, new EditPermission()).IsFaulted)
|
||||
{
|
||||
ViewBag.ACL = _context.Circle.Where(
|
||||
c=>c.OwnerId == blog.AuthorId)
|
||||
.Select(
|
||||
c => new SelectListItem
|
||||
{
|
||||
Text = c.Name,
|
||||
Value = c.Id.ToString(),
|
||||
Selected = blog.AuthorizeCircle(c.Id)
|
||||
}
|
||||
);
|
||||
SetLangItems();
|
||||
return View(new BlogPostEditViewModel
|
||||
{
|
||||
Id = blog.Id,
|
||||
Title = blog.Title,
|
||||
Content = blog.Content,
|
||||
ACL = blog.ACL,
|
||||
Photo = blog.Photo
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
@ -143,41 +218,65 @@ namespace Yavsc.Controllers
|
||||
|
||||
// POST: Blog/Edit/5
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken, Authorize()]
|
||||
[ValidateAntiForgeryToken,Authorize()]
|
||||
public async Task<IActionResult> Edit(BlogPostEditViewModel blogEdit)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
await blogSpotService.Modify(User, blogEdit);
|
||||
var blog = _context.BlogSpot.SingleOrDefault(b=>b.Id == blogEdit.Id);
|
||||
if (blog == null) {
|
||||
ModelState.AddModelError("Id", "not found");
|
||||
return View();
|
||||
}
|
||||
if (!(await _authorizationService.AuthorizeAsync(User, blog, new EditPermission())).Succeeded) {
|
||||
ViewData["StatusMessage"] = "Accès restreint";
|
||||
return new ChallengeResult();
|
||||
}
|
||||
blog.Content=blogEdit.Content;
|
||||
blog.Title = blogEdit.Title;
|
||||
blog.Photo = blogEdit.Photo;
|
||||
blog.ACL = blogEdit.ACL;
|
||||
// saves the change
|
||||
_context.Update(blog);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
ViewData["StatusMessage"] = "Post modified";
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
ViewData["PostTarget"]="Edit";
|
||||
return View(blogEdit);
|
||||
}
|
||||
|
||||
// GET: Blog/Delete/5
|
||||
[ActionName("Delete"), Authorize()]
|
||||
public async Task<IActionResult> Delete(long? id)
|
||||
[ActionName("Delete"),Authorize()]
|
||||
public IActionResult Delete(long? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var blog = await blogSpotService.GetBlogPostAsync(id.Value);
|
||||
BlogPost blog = _context.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Single(m => m.Id == id);
|
||||
if (blog == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(blog);
|
||||
}
|
||||
|
||||
// POST: Blog/Delete/5
|
||||
[HttpPost, ActionName("Delete"), Authorize("TheAuthor")]
|
||||
[HttpPost, ActionName("Delete"), Authorize("IsTheAuthor")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DeleteConfirmed(long id)
|
||||
public IActionResult DeleteConfirmed(long id)
|
||||
{
|
||||
await blogSpotService.Delete(User, id);
|
||||
var uid = User.GetUserId();
|
||||
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
|
||||
|
||||
_context.BlogSpot.Remove(blog);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
@ -33,337 +33,13 @@ using Yavsc.Server.Helpers;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.IdentityModel.Protocols.Configuration;
|
||||
using IdentityModel;
|
||||
using System.Security.Claims;
|
||||
using IdentityServer8.Security;
|
||||
using Yavsc.Interfaces;
|
||||
|
||||
namespace Yavsc.Extensions;
|
||||
|
||||
|
||||
public static class HostingExtensions
|
||||
{
|
||||
|
||||
internal static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services = LoadConfiguration(builder);
|
||||
|
||||
services.AddSession();
|
||||
|
||||
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
|
||||
|
||||
|
||||
// Add the system clock service
|
||||
_ = services.AddSingleton<ISystemClock, SystemClock>();
|
||||
_ = services.AddSingleton<IConnexionManager, HubConnectionManager>();
|
||||
_ = services.AddSingleton<ILiveProcessor, LiveProcessor>();
|
||||
_ = services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
|
||||
|
||||
AddIdentityDBAndStores(builder).AddDefaultTokenProviders();
|
||||
AddIdentityServer(builder);
|
||||
|
||||
services.AddSignalR(o =>
|
||||
{
|
||||
o.EnableDetailedErrors = true;
|
||||
});
|
||||
|
||||
services.AddMvc(config =>
|
||||
{
|
||||
/* var policy = new AuthorizationPolicyBuilder()
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
config.Filters.Add(new AuthorizeFilter(policy)); */
|
||||
config.Filters.Add(new ProducesAttribute("application/json"));
|
||||
// config.ModelBinders.Insert(0,new MyDateTimeModelBinder());
|
||||
// config.ModelBinders.Insert(0,new MyDecimalModelBinder());
|
||||
config.EnableEndpointRouting = true;
|
||||
}).AddFormatterMappings(
|
||||
config => config.SetMediaTypeMappingForFormat("text/pdf",
|
||||
new MediaTypeHeaderValue("text/pdf"))
|
||||
).AddFormatterMappings(
|
||||
config => config.SetMediaTypeMappingForFormat("text/x-tex",
|
||||
new MediaTypeHeaderValue("text/x-tex"))
|
||||
)
|
||||
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
|
||||
options =>
|
||||
{
|
||||
options.ResourcesPath = "Resources";
|
||||
}).AddDataAnnotationsLocalization();
|
||||
|
||||
services.AddTransient<ITrueEmailSender, MailSender>()
|
||||
.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailSender>()
|
||||
.AddTransient<IYavscMessageSender, YavscMessageSender>()
|
||||
.AddTransient<IBillingService, BillingService>()
|
||||
.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false))
|
||||
.AddTransient<ICalendarManager, CalendarManager>()
|
||||
.AddTransient<BlogSpotService>();
|
||||
|
||||
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
|
||||
_ = services.AddLocalization(options =>
|
||||
{
|
||||
options.ResourcesPath = "Resources";
|
||||
});
|
||||
var dataDirConfig = builder.Configuration["Site:DataDir"] ?? "DataDir";
|
||||
|
||||
var dataDir = new DirectoryInfo(dataDirConfig);
|
||||
// Add session related services.
|
||||
|
||||
services.AddDataProtection().PersistKeysToFileSystem(dataDir);
|
||||
AddYavscPolicies(services);
|
||||
|
||||
services.AddScoped<IAuthorizationHandler, PermissionHandler>();
|
||||
services.AddTransient<IExternalIdentityManager, ExternalIdentityManager>();
|
||||
|
||||
|
||||
AddAuthentication(builder);
|
||||
// accepts any access token issued by identity server
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services = builder.Services;
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
||||
|
||||
return services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
|
||||
}
|
||||
|
||||
private static void AddYavscPolicies(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("ApiScope", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser()
|
||||
.RequireClaim("scope", "scope2");
|
||||
});
|
||||
options.AddPolicy("Performer", policy =>
|
||||
{
|
||||
policy
|
||||
.RequireAuthenticatedUser()
|
||||
.RequireClaim(JwtClaimTypes.Role, "Performer");
|
||||
});
|
||||
options.AddPolicy("AdministratorOnly", policy =>
|
||||
{
|
||||
_ = policy
|
||||
.RequireAuthenticatedUser()
|
||||
.RequireClaim(JwtClaimTypes.Role, Constants.AdminGroupName);
|
||||
});
|
||||
|
||||
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
|
||||
|
||||
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
|
||||
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
|
||||
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
|
||||
options.AddPolicy("TheAuthor", policy => policy.Requirements.Add(new EditPermission()));
|
||||
})
|
||||
.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("default", builder =>
|
||||
{
|
||||
_ = builder.WithOrigins("*")
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static IServiceCollection LoadConfiguration(this WebApplicationBuilder builder)
|
||||
{
|
||||
var siteSection = builder.Configuration.GetSection("Site");
|
||||
var smtpSection = builder.Configuration.GetSection("Smtp");
|
||||
var paypalSection = builder.Configuration.GetSection("Authentication:PayPal");
|
||||
// OAuth2AppSettings
|
||||
var googleAuthSettings = builder.Configuration.GetSection("Authentication:Google");
|
||||
|
||||
//LoadGoogleConfig(builder.Configuration);
|
||||
|
||||
|
||||
var services = builder.Services;
|
||||
_ = services.AddControllersWithViews()
|
||||
.AddNewtonsoftJson();
|
||||
|
||||
services.Configure<SiteSettings>(siteSection);
|
||||
services.Configure<SmtpSettings>(smtpSection);
|
||||
services.Configure<PayPalSettings>(paypalSection);
|
||||
services.Configure<GoogleAuthSettings>(googleAuthSettings);
|
||||
ConfigureRequestLocalization(services);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void AddAuthentication(WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services=builder.Services;
|
||||
IConfigurationRoot configurationRoot=builder.Configuration;
|
||||
string? googleClientId = configurationRoot["Authentication:Google:ClientId"];
|
||||
string? googleClientSecret = configurationRoot["Authentication:Google:ClientSecret"];
|
||||
|
||||
var authenticationBuilder = services.AddAuthentication();
|
||||
|
||||
if (googleClientId!=null && googleClientSecret!=null)
|
||||
authenticationBuilder.AddGoogle(options =>
|
||||
{
|
||||
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
|
||||
|
||||
// register your IdentityServer with Google at https://console.developers.google.com
|
||||
// enable the Google+ API
|
||||
// set the redirect URI to https://localhost:5001/signin-google
|
||||
options.ClientId = googleClientId;
|
||||
options.ClientSecret = googleClientSecret;
|
||||
|
||||
});
|
||||
}
|
||||
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
|
||||
{
|
||||
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
|
||||
{
|
||||
options.Events.RaiseErrorEvents = true;
|
||||
options.Events.RaiseInformationEvents = true;
|
||||
options.Events.RaiseFailureEvents = true;
|
||||
options.Events.RaiseSuccessEvents = true;
|
||||
|
||||
// see https://IdentityServer8.readthedocs.io/en/latest/topics/resources.html
|
||||
options.EmitStaticAudienceClaim = true;
|
||||
})
|
||||
.AddInMemoryIdentityResources(Config.IdentityResources)
|
||||
.AddInMemoryClients(Config.Clients)
|
||||
.AddInMemoryApiScopes(Config.ApiScopes)
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
;
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
identityServerBuilder.AddDeveloperSigningCredential();
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = builder.Configuration["SigningCert:Path"];
|
||||
var pass = builder.Configuration["SigningCert:Password"];
|
||||
if (path == null)
|
||||
throw new InvalidConfigurationException("No signing cert path");
|
||||
FileInfo certFileInfo = new FileInfo(path);
|
||||
Debug.Assert(certFileInfo.Exists);
|
||||
RSA rsa = RSA.Create();
|
||||
rsa.ImportFromPem(File.ReadAllText(certFileInfo.FullName));
|
||||
var signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256)
|
||||
{
|
||||
CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
|
||||
};
|
||||
identityServerBuilder.AddSigningCredential(signingCredentials);
|
||||
}
|
||||
return identityServerBuilder;
|
||||
}
|
||||
|
||||
private static void ConfigureRequestLocalization(IServiceCollection services)
|
||||
{
|
||||
services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
CultureInfo[] supportedCultures = new[]
|
||||
{
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("fr"),
|
||||
new CultureInfo("pt")
|
||||
};
|
||||
|
||||
CultureInfo[] supportedUICultures = new[]
|
||||
{
|
||||
new CultureInfo("fr"),
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("pt")
|
||||
};
|
||||
|
||||
// You must explicitly state which cultures your application supports.
|
||||
// These are the cultures the app supports for formatting numbers, dates, etc.
|
||||
options.SupportedCultures = supportedCultures;
|
||||
|
||||
// These are the cultures the app supports for UI strings, i.e. we have localized resources for.
|
||||
options.SupportedUICultures = supportedUICultures;
|
||||
|
||||
options.RequestCultureProviders = new List<IRequestCultureProvider>
|
||||
{
|
||||
new QueryStringRequestCultureProvider { Options = options },
|
||||
new CookieRequestCultureProvider { Options = options, CookieName="ASPNET_CULTURE" },
|
||||
new AcceptLanguageHeaderRequestCultureProvider { Options = options }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
internal async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
|
||||
{
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
await db.Database.MigrateAsync();
|
||||
}
|
||||
}
|
||||
app.Use(async (context, next) => {
|
||||
if (context.Request.Path.StartsWithSegments("/robots.txt")) {
|
||||
var robotsTxtPath = System.IO.Path.Combine(app.Environment.WebRootPath, $"robots.txt");
|
||||
string output = "User-agent: * \nDisallow: /";
|
||||
if (File.Exists(robotsTxtPath)) {
|
||||
output = await File.ReadAllTextAsync(robotsTxtPath);
|
||||
}
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync(output);
|
||||
} else await next();
|
||||
});
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.UseIdentityServer();
|
||||
app.UseAuthorization();
|
||||
app.UseCors("default");
|
||||
app.MapDefaultControllerRoute();
|
||||
//app.MapRazorPages();
|
||||
app.MapHub<ChatHub>("/chatHub");
|
||||
|
||||
WorkflowHelpers.ConfigureBillingService();
|
||||
|
||||
var services = app.Services;
|
||||
ILoggerFactory loggerFactory = services.GetRequiredService<ILoggerFactory>();
|
||||
var siteSettings = services.GetRequiredService<IOptions<SiteSettings>>();
|
||||
var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>();
|
||||
var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>();
|
||||
var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>();
|
||||
var localization = services.GetRequiredService<IStringLocalizer<YavscLocalization>>();
|
||||
Startup.Configure(app, siteSettings, smtpSettings,
|
||||
payPalSettings, googleAuthSettings, localization, loggerFactory,
|
||||
app.Environment.EnvironmentName);
|
||||
app.ConfigureFileServerApp();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void LoadGoogleConfig(IConfigurationRoot configuration)
|
||||
{
|
||||
string? googleClientFile = configuration["Authentication:Google:GoogleWebClientJson"];
|
||||
string? googleServiceAccountJsonFile = configuration["Authentication:Google:GoogleServiceAccountJson"];
|
||||
if (googleClientFile != null)
|
||||
{
|
||||
Config.GoogleWebClientConfiguration = new ConfigurationBuilder().AddJsonFile(googleClientFile).Build();
|
||||
}
|
||||
|
||||
if (googleServiceAccountJsonFile != null)
|
||||
{
|
||||
FileInfo safile = new FileInfo(googleServiceAccountJsonFile);
|
||||
Config.GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
|
||||
}
|
||||
}
|
||||
|
||||
#region files config
|
||||
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
|
||||
bool enableDirectoryBrowsing = false)
|
||||
{
|
||||
@ -415,5 +91,321 @@ public static class HostingExtensions
|
||||
return app;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
internal static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services = LoadConfiguration(builder);
|
||||
|
||||
//services.AddRazorPages();
|
||||
|
||||
|
||||
services.AddSession();
|
||||
|
||||
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
|
||||
|
||||
|
||||
// Add the system clock service
|
||||
_ = services.AddSingleton<ISystemClock, SystemClock>();
|
||||
_ = services.AddSingleton<IConnexionManager, HubConnectionManager>();
|
||||
_ = services.AddSingleton<ILiveProcessor, LiveProcessor>();
|
||||
_ = services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
|
||||
|
||||
AddIdentityDBAndStores(builder).AddDefaultTokenProviders();
|
||||
AddIdentityServer(builder);
|
||||
|
||||
services.AddSignalR(o =>
|
||||
{
|
||||
o.EnableDetailedErrors = true;
|
||||
});
|
||||
|
||||
services.AddMvc(config =>
|
||||
{
|
||||
/* var policy = new AuthorizationPolicyBuilder()
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
config.Filters.Add(new AuthorizeFilter(policy)); */
|
||||
config.Filters.Add(new ProducesAttribute("application/json"));
|
||||
// config.ModelBinders.Insert(0,new MyDateTimeModelBinder());
|
||||
// config.ModelBinders.Insert(0,new MyDecimalModelBinder());
|
||||
config.EnableEndpointRouting = true;
|
||||
}).AddFormatterMappings(
|
||||
config => config.SetMediaTypeMappingForFormat("text/pdf",
|
||||
new MediaTypeHeaderValue("text/pdf"))
|
||||
).AddFormatterMappings(
|
||||
config => config.SetMediaTypeMappingForFormat("text/x-tex",
|
||||
new MediaTypeHeaderValue("text/x-tex"))
|
||||
)
|
||||
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
|
||||
options =>
|
||||
{
|
||||
options.ResourcesPath = "Resources";
|
||||
}).AddDataAnnotationsLocalization();
|
||||
|
||||
services.AddTransient<ITrueEmailSender, MailSender>()
|
||||
.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, MailSender>()
|
||||
.AddTransient<IYavscMessageSender, YavscMessageSender>()
|
||||
.AddTransient<IBillingService, BillingService>()
|
||||
.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false))
|
||||
.AddTransient<ICalendarManager, CalendarManager>();
|
||||
|
||||
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
|
||||
_ = services.AddLocalization(options =>
|
||||
{
|
||||
options.ResourcesPath = "Resources";
|
||||
});
|
||||
var dataDirConfig = builder.Configuration["Site:DataDir"] ?? "DataDir";
|
||||
|
||||
var dataDir = new DirectoryInfo(dataDirConfig);
|
||||
// Add session related services.
|
||||
|
||||
services.AddDataProtection().PersistKeysToFileSystem(dataDir);
|
||||
AddYavscPolicies(services);
|
||||
|
||||
services.AddScoped<IAuthorizationHandler, PermissionHandler>();
|
||||
|
||||
|
||||
AddAuthentication(builder);
|
||||
// accepts any access token issued by identity server
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services = builder.Services;
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
|
||||
|
||||
return services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
|
||||
}
|
||||
|
||||
private static void AddYavscPolicies(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("ApiScope", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser()
|
||||
.RequireClaim("scope", "scope2");
|
||||
});
|
||||
options.AddPolicy("Performer", policy =>
|
||||
{
|
||||
policy
|
||||
.RequireAuthenticatedUser()
|
||||
.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Performer");
|
||||
});
|
||||
options.AddPolicy("AdministratorOnly", policy =>
|
||||
{
|
||||
_ = policy.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Constants.AdminGroupName);
|
||||
});
|
||||
|
||||
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
|
||||
|
||||
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
|
||||
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
|
||||
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
|
||||
options.AddPolicy("IsTheAuthor", policy => policy.Requirements.Add(new EditPermission()));
|
||||
})
|
||||
.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("default", builder =>
|
||||
{
|
||||
_ = builder.WithOrigins("*")
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public static IServiceCollection LoadConfiguration(this WebApplicationBuilder builder)
|
||||
{
|
||||
var siteSection = builder.Configuration.GetSection("Site");
|
||||
var smtpSection = builder.Configuration.GetSection("Smtp");
|
||||
var paypalSection = builder.Configuration.GetSection("Authentication:PayPal");
|
||||
// OAuth2AppSettings
|
||||
var googleAuthSettings = builder.Configuration.GetSection("Authentication:Google");
|
||||
|
||||
string? googleClientFile = builder.Configuration["Authentication:Google:GoogleWebClientJson"];
|
||||
string? googleServiceAccountJsonFile = builder.Configuration["Authentication:Google:GoogleServiceAccountJson"];
|
||||
if (googleClientFile != null)
|
||||
{
|
||||
Config.GoogleWebClientConfiguration = new ConfigurationBuilder().AddJsonFile(googleClientFile).Build();
|
||||
}
|
||||
|
||||
if (googleServiceAccountJsonFile != null)
|
||||
{
|
||||
FileInfo safile = new FileInfo(googleServiceAccountJsonFile);
|
||||
Config.GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
|
||||
}
|
||||
var services = builder.Services;
|
||||
_ = services.AddControllersWithViews()
|
||||
.AddNewtonsoftJson();
|
||||
LoadGoogleConfig(builder.Configuration);
|
||||
|
||||
services.Configure<SiteSettings>(siteSection);
|
||||
services.Configure<SmtpSettings>(smtpSection);
|
||||
services.Configure<PayPalSettings>(paypalSection);
|
||||
services.Configure<GoogleAuthSettings>(googleAuthSettings);
|
||||
ConfigureRequestLocalization(services);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void AddAuthentication(WebApplicationBuilder builder)
|
||||
{
|
||||
IServiceCollection services=builder.Services;
|
||||
IConfigurationRoot configurationRoot=builder.Configuration;
|
||||
string? googleClientId = configurationRoot["Authentication:Google:ClientId"];
|
||||
string? googleClientSecret = configurationRoot["Authentication:Google:ClientSecret"];
|
||||
|
||||
var authenticationBuilder = services.AddAuthentication();
|
||||
|
||||
if (googleClientId!=null && googleClientSecret!=null)
|
||||
authenticationBuilder.AddGoogle(options =>
|
||||
{
|
||||
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
|
||||
|
||||
// register your IdentityServer with Google at https://console.developers.google.com
|
||||
// enable the Google+ API
|
||||
// set the redirect URI to https://localhost:5001/signin-google
|
||||
options.ClientId = googleClientId;
|
||||
options.ClientSecret = googleClientSecret;
|
||||
});
|
||||
}
|
||||
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IProfileService,ProfileService>();
|
||||
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
|
||||
{
|
||||
options.Events.RaiseErrorEvents = true;
|
||||
options.Events.RaiseInformationEvents = true;
|
||||
options.Events.RaiseFailureEvents = true;
|
||||
options.Events.RaiseSuccessEvents = true;
|
||||
|
||||
// see https://IdentityServer8.readthedocs.io/en/latest/topics/resources.html
|
||||
options.EmitStaticAudienceClaim = true;
|
||||
})
|
||||
.AddInMemoryIdentityResources(Config.IdentityResources)
|
||||
.AddInMemoryClients(Config.Clients)
|
||||
.AddInMemoryApiScopes(Config.ApiScopes)
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
.AddProfileService<ProfileService>()
|
||||
;
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
identityServerBuilder.AddDeveloperSigningCredential();
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = builder.Configuration["SigningCert:Path"];
|
||||
var pass = builder.Configuration["SigningCert:Password"];
|
||||
if (path == null)
|
||||
throw new InvalidConfigurationException("No signing cert path");
|
||||
FileInfo certFileInfo = new FileInfo(path);
|
||||
Debug.Assert(certFileInfo.Exists);
|
||||
RSA rsa = RSA.Create();
|
||||
rsa.ImportFromPem(File.ReadAllText(certFileInfo.FullName));
|
||||
var signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256)
|
||||
{
|
||||
CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
|
||||
};
|
||||
identityServerBuilder.AddSigningCredential(signingCredentials);
|
||||
}
|
||||
return identityServerBuilder;
|
||||
}
|
||||
|
||||
private static void ConfigureRequestLocalization(IServiceCollection services)
|
||||
{
|
||||
services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
CultureInfo[] supportedCultures = new[]
|
||||
{
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("fr"),
|
||||
new CultureInfo("pt")
|
||||
};
|
||||
|
||||
CultureInfo[] supportedUICultures = new[]
|
||||
{
|
||||
new CultureInfo("fr"),
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("pt")
|
||||
};
|
||||
|
||||
// You must explicitly state which cultures your application supports.
|
||||
// These are the cultures the app supports for formatting numbers, dates, etc.
|
||||
options.SupportedCultures = supportedCultures;
|
||||
|
||||
// These are the cultures the app supports for UI strings, i.e. we have localized resources for.
|
||||
options.SupportedUICultures = supportedUICultures;
|
||||
|
||||
options.RequestCultureProviders = new List<IRequestCultureProvider>
|
||||
{
|
||||
new QueryStringRequestCultureProvider { Options = options },
|
||||
new CookieRequestCultureProvider { Options = options, CookieName="ASPNET_CULTURE" },
|
||||
new AcceptLanguageHeaderRequestCultureProvider { Options = options }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
internal static WebApplication ConfigurePipeline(this WebApplication app)
|
||||
{
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
app.UseIdentityServer();
|
||||
app.UseAuthorization();
|
||||
app.UseCors("default");
|
||||
app.MapDefaultControllerRoute();
|
||||
//pp.MapRazorPages();
|
||||
app.MapHub<ChatHub>("/chatHub");
|
||||
|
||||
WorkflowHelpers.ConfigureBillingService();
|
||||
|
||||
var services = app.Services;
|
||||
ILoggerFactory loggerFactory = services.GetRequiredService<ILoggerFactory>();
|
||||
var siteSettings = services.GetRequiredService<IOptions<SiteSettings>>();
|
||||
var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>();
|
||||
var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>();
|
||||
var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>();
|
||||
var localization = services.GetRequiredService<IStringLocalizer<YavscLocalization>>();
|
||||
Startup.Configure(app, siteSettings, smtpSettings,
|
||||
payPalSettings, googleAuthSettings, localization, loggerFactory,
|
||||
app.Environment.EnvironmentName);
|
||||
app.ConfigureFileServerApp();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void LoadGoogleConfig(IConfigurationRoot configuration)
|
||||
{
|
||||
string? googleClientFile = configuration["Authentication:Google:GoogleWebClientJson"];
|
||||
string? googleServiceAccountJsonFile = configuration["Authentication:Google:GoogleServiceAccountJson"];
|
||||
if (googleClientFile != null)
|
||||
{
|
||||
Config.GoogleWebClientConfiguration = new ConfigurationBuilder().AddJsonFile(googleClientFile).Build();
|
||||
}
|
||||
|
||||
if (googleServiceAccountJsonFile != null)
|
||||
{
|
||||
FileInfo safile = new FileInfo(googleServiceAccountJsonFile);
|
||||
Config.GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RazorEngine.Compilation.ImpromptuInterface.Optimization;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Migrations;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Blog;
|
||||
using Yavsc.ViewModels.Auth;
|
||||
@ -34,10 +32,6 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else if (context.User.IsInRole("Administrator"))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
else if (requirement is EditPermission || requirement is DeletePermission)
|
||||
{
|
||||
@ -55,33 +49,18 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
if (resource is BlogPost blogPost)
|
||||
{
|
||||
return
|
||||
applicationDbContext.blogSpotPublications
|
||||
.Any(p=>p.BlogpostId == blogPost.Id);
|
||||
if (blogPost.ACL.Count==0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsOwner(ClaimsPrincipal user, object? resource)
|
||||
private static bool IsOwner(ClaimsPrincipal user, object? resource)
|
||||
{
|
||||
if (resource is BlogPost blogPost)
|
||||
{
|
||||
return blogPost.AuthorId == user.GetUserId();
|
||||
}
|
||||
else
|
||||
if (resource is DefaultHttpContext httpContext)
|
||||
{
|
||||
if (httpContext.Request.Path.StartsWithSegments("/blogpost/Delete", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string postId = (string)httpContext.GetRouteValue("id");
|
||||
if (long.TryParse(postId, out long id))
|
||||
{
|
||||
BlogPost b = applicationDbContext.BlogSpot.FirstOrDefault(b => b.Id == id && b.AuthorId == user.GetUserId());
|
||||
return b != null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -91,7 +70,7 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
return applicationDbContext.CircleMembers
|
||||
.Include(c => c.Circle)
|
||||
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.AuthorId)
|
||||
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.OwnerId)
|
||||
.Any();
|
||||
}
|
||||
return true;
|
||||
|
@ -1,50 +1,27 @@
|
||||
using System.Text.Encodings.Web;
|
||||
using AsciiDocNet;
|
||||
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)
|
||||
public override async Task ProcessAsync (TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
|
||||
if (context.AllAttributes.ContainsName ("summary"))
|
||||
{
|
||||
var summaryLength = context.AllAttributes["summary"].Value;
|
||||
}
|
||||
await base.ProcessAsync(context, output);
|
||||
var content = await output.GetChildContentAsync();
|
||||
string text = 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) + "(...)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Document document = Document.Parse(text);
|
||||
var html = document.ToHtml(2);
|
||||
using var stringWriter = new StringWriter();
|
||||
html.WriteTo(stringWriter, HtmlEncoder.Default);
|
||||
var processedHere = stringWriter.ToString();
|
||||
output.Content.AppendHtml(processedHere);
|
||||
}
|
||||
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");
|
||||
}
|
||||
Document document = Document.Parse(text);
|
||||
var html = document.ToHtml(2);
|
||||
using var stringWriter = new StringWriter();
|
||||
html.WriteTo(stringWriter, HtmlEncoder.Default);
|
||||
var processedHere = stringWriter.ToString();
|
||||
output.Content.AppendHtml(processedHere);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ namespace Yavsc.Helpers
|
||||
);
|
||||
return googleLogin;
|
||||
}
|
||||
public static async Task<UserCredential> GetGoogleCredential(GoogleAuthSettings googleAuthSettings, IDataStore store, string googleUserLoginKey)
|
||||
public static async Task<UserCredential> GetGoogleCredential(GoogleAuthSettings googleAuthSettings, IDataStore store, string googleUserLoginKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(googleUserLoginKey))
|
||||
throw new InvalidOperationException("No Google login");
|
||||
@ -82,7 +82,7 @@ namespace Yavsc.Helpers
|
||||
var token = await store.GetAsync<TokenResponse>(googleUserLoginKey);
|
||||
// token != null
|
||||
var c = SystemClock.Default;
|
||||
if (token.IsStale) {
|
||||
if (token.IsExpired(c)) {
|
||||
token = await RefreshToken(googleAuthSettings, token);
|
||||
}
|
||||
return new UserCredential(flow, googleUserLoginKey, token);
|
||||
|
@ -1,6 +1,6 @@
|
||||
DESTDIR=/srv/www/yavsc
|
||||
CONFIGURATION=Release
|
||||
USER_AND_GROUP=www-data:www-data
|
||||
USER=www-data
|
||||
SERVICE_PROD=yavsc
|
||||
DOTNET_FRAMEWORK=net9.0
|
||||
|
||||
@ -22,17 +22,12 @@ install_service:
|
||||
pushInProd: publish
|
||||
sudo systemctl stop $(SERVICE_PROD)
|
||||
sudo cp -a bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish/* $(DESTDIR)
|
||||
sudo chown -R $(USER_AND_GROUP) $(DESTDIR)
|
||||
sudo chown -R $(USER) $(DESTDIR)
|
||||
sudo sync
|
||||
sudo systemctl start $(SERVICE_PROD)
|
||||
|
||||
%.css: %.scss
|
||||
scss $^ > $@
|
||||
|
||||
%.min.js: %.js
|
||||
jsmin < $^ > $@
|
||||
|
||||
%.min.css: %.css
|
||||
jsmin < $^ > $@
|
||||
|
||||
css: wwwroot/css/site.css
|
||||
|
@ -6,7 +6,7 @@ namespace Yavsc
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Yavsc
|
||||
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
var app = await builder.ConfigureWebAppServices().ConfigurePipeline();
|
||||
var app = builder.ConfigureWebAppServices().ConfigurePipeline();
|
||||
app.UseSession();
|
||||
app.Run();
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
using Yavsc.Settings;
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace Yavsc.ViewComponents
|
||||
{
|
||||
if (target!=null)
|
||||
{
|
||||
var oid = target.AuthorId;
|
||||
var oid = target.OwnerId;
|
||||
ViewBag.ACL = dbContext.Circle.Where(
|
||||
c=>c.OwnerId == oid)
|
||||
.Select(
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model BlogPostEditViewModel
|
||||
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Blog post edition";
|
||||
@ -47,7 +47,6 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mdcoding">
|
||||
<label asp-for="Content" class="col-md-2 control-label" ></label>
|
||||
<div class="col-md-10">
|
||||
@ -57,7 +56,6 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ACL" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
@ -65,13 +63,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="Publish" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input asp-for="Publish" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button class="btn btn-primary" >Save</button>
|
||||
|
@ -60,14 +60,10 @@ $('#commentValidation').html(
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
<div class="post">
|
||||
<div class="float-left">
|
||||
<img alt="" src="@Model.Photo" >
|
||||
</div>
|
||||
|
||||
<h1 ismarkdown>@Model.Title</h1>
|
||||
|
||||
<div class="container">
|
||||
<div class="blogpost">
|
||||
<h1 class="blogtitle" ismarkdown>@Model.Title</h1>
|
||||
<img class="blogphoto" alt="" src="@Model.Photo" >
|
||||
@Html.DisplayFor(m=>m.Author)
|
||||
<asciidoc>@Html.DisplayFor(m=>m.Content)</asciidoc>
|
||||
|
||||
@ -102,4 +98,4 @@ $('#commentValidation').html(
|
||||
<a asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-link">Edit</a>
|
||||
}
|
||||
<a asp-action="Index" class="btn btn-link">Back to List</a>
|
||||
|
||||
</div>
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
}
|
||||
|
||||
<h2 >Blog post</h2>
|
||||
<h2 > Blog post edition </h2>
|
||||
<label><input type="checkbox" id="vcbtn" />Editer le code source Markdown</label>
|
||||
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
@ -97,13 +97,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="Publish" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
<input type="checkbox" asp-for="Publish" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Save" class="btn btn-default" />
|
||||
@ -118,3 +111,5 @@
|
||||
<div>
|
||||
<a asp-action="Index">Back to List</a>
|
||||
</div>
|
||||
|
||||
using Yavsc.Migrations;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model IEnumerable<IBlogPost>
|
||||
@model IEnumerable<IGrouping<string,BlogPost>>
|
||||
@{
|
||||
ViewData["Title"] = "Blogs, l'index";
|
||||
}
|
||||
@ -43,51 +43,58 @@
|
||||
<a asp-action="Create">Create a new article</a>
|
||||
</p>
|
||||
}
|
||||
|
||||
<div class="blog">
|
||||
@{
|
||||
int maxTextLen = 75;
|
||||
foreach (var post in Model) {
|
||||
<div class="post">
|
||||
|
||||
|
||||
<div class="float-left" >
|
||||
<a asp-action="Details" asp-route-id="@post.Id" class="bloglink" style="display: float-left;">
|
||||
<img src="@post.Photo" >
|
||||
</a>
|
||||
</div>
|
||||
<h3>@post.Title</h3>
|
||||
<div>
|
||||
<a asp-action="Details" asp-route-id="@post.Id">
|
||||
<asciidoc summary="@maxTextLen">@post.Content</asciidoc></a>
|
||||
<span style="font-size:x-small;">@Html.DisplayFor(m => post.Author)</span>
|
||||
<span style="font-size:xx-small;">
|
||||
posté le @post.DateCreated.ToString("dddd d MMM yyyy à H:mm")
|
||||
@if ((post.DateModified - post.DateCreated).Minutes > 0){
|
||||
@:- Modifié le @post.DateModified.ToString("dddd d MMM yyyy à H:mm")
|
||||
})
|
||||
</span>
|
||||
</div>
|
||||
<div class="actiongroup">
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, post, new ReadPermission())).Succeeded)
|
||||
{
|
||||
<a asp-action="Details" asp-route-id="@post.Id" class="btn btn-light">Details</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-action="Details" asp-route-id="@post.Id" class="btn btn-light">Details</a>
|
||||
}
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, post, new EditPermission())).Succeeded)
|
||||
{
|
||||
<a asp-action="Edit" asp-route-id="@post.Id" class="btn btn-default">Edit</a>
|
||||
|
||||
<a asp-action="Delete" asp-route-id="@post.Id" class="btn btn-danger">Delete</a>
|
||||
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
<table class="table">
|
||||
@foreach (var group in Model) {
|
||||
var title = group.Key ?? "@";
|
||||
string secondclass="";
|
||||
var first = group.First();
|
||||
int maxTextLen = 256;
|
||||
|
||||
<tr><td colspan="3">
|
||||
<a asp-action="Title" asp-route-id="@group.Key" >@title</a></td></tr>
|
||||
@foreach (var item in group) {
|
||||
var trunked = item.Content?.Length > maxTextLen;
|
||||
<tr>
|
||||
<td><a asp-action="Details" asp-route-id="@item.Id" class="bloglink">
|
||||
<img src="@item.Photo" class="blogphoto"></a>
|
||||
</td>
|
||||
<td>
|
||||
<asciidoc summary="@maxTextLen">@item.Content</asciidoc>
|
||||
@if (trunked) { <a asp-action="Details" asp-route-id="@item.Id" class="bloglink">...</a> }
|
||||
<span style="font-size:x-small;">@Html.DisplayFor(m => item.Author)</span>
|
||||
<span style="font-size:xx-small;">
|
||||
posté le @item.DateCreated.ToString("dddd d MMM yyyy à H:mm")
|
||||
@if ((item.DateModified - item.DateCreated).Minutes > 0){
|
||||
@:- Modifié le @item.DateModified.ToString("dddd d MMM yyyy à H:mm")
|
||||
})
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<ul class="actiongroup">
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, item, new ReadPermission())).Succeeded) {
|
||||
<li>
|
||||
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
|
||||
</li>
|
||||
}
|
||||
else {
|
||||
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details DEBUG</a>
|
||||
}
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
|
||||
<li><a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-default">Edit</a>
|
||||
</li>
|
||||
<li><a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger">Delete</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</table>
|
||||
|
||||
@if(Model.Count()==0){<p>Néant</p>}
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -28,7 +28,7 @@
|
||||
<ul class="actiongroup">
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, item, new ReadPermission())).Succeeded) {
|
||||
<li>
|
||||
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-light">Details</a>
|
||||
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
|
||||
</li>
|
||||
}
|
||||
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
|
||||
|
@ -51,7 +51,7 @@
|
||||
@act.Description </p>
|
||||
|
||||
@if (act.Children.Count>0) {
|
||||
<a asp-route-id="@act.Code" class="btn btn-light">
|
||||
<a asp-route-id="@act.Code" class="btn btn-default">
|
||||
@foreach (Activity c in act.Children) {
|
||||
@Html.DisplayFor(subact=>c)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
<environment names="Development">
|
||||
<script>
|
||||
var CREATE_PAYMENT_URL = 'http://pschneider.fr:85/api/payment/create';
|
||||
var EXECUTE_PAYMENT_URL = 'http://pschneider.fr:85/api/payment/execute';
|
||||
var EXECUTE_PAYMENT_URL = 'http://dev.pschneider.fr:85/api/payment/execute';
|
||||
var PAYPAL_ENV = 'sandbox';
|
||||
</script>
|
||||
</environment>
|
||||
|
@ -20,9 +20,9 @@
|
||||
}
|
||||
</ul>
|
||||
<p>
|
||||
<input type="submit" class="btn btn-light btn-success" name="submit.Grant" value="Grant" />
|
||||
<input type="submit" class="btn btn-light btn-danger" name="submit.Deny" value="Deny" />
|
||||
<input type="submit" class="btn btn-light btn-success" name="submit.Login" value="Sign in as different user" />
|
||||
<input type="submit" class="btn btn-lg btn-success" name="submit.Grant" value="Grant" />
|
||||
<input type="submit" class="btn btn-lg btn-danger" name="submit.Deny" value="Deny" />
|
||||
<input type="submit" class="btn btn-lg btn-success" name="submit.Login" value="Sign in as different user" />
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
@ -1,10 +1,14 @@
|
||||
@using Yavsc.Abstract.Identity
|
||||
@model ApplicationUser
|
||||
@{
|
||||
var avuri = "/Avatars/" + Model.UserName + ".s.png";
|
||||
var avuri = "/Avatars/"+Model.UserName+".s.png";
|
||||
var userPosted = Model.Posts!=null && Model.Posts.Count()>=1;
|
||||
}
|
||||
<div class="userinfo">
|
||||
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
|
||||
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
|
||||
</a>
|
||||
@if (userPosted) { <a asp-controller="Blogspot" asp-action="Index"
|
||||
asp-route-id="@Model.UserName" class="btn btn-primary">
|
||||
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName"/>
|
||||
</a>
|
||||
} else {
|
||||
Html.DisplayFor(m=>m.UserName);
|
||||
}
|
||||
</div>
|
||||
|
@ -1,10 +0,0 @@
|
||||
@using Yavsc.Abstract.Identity
|
||||
@model IApplicationUser
|
||||
@{
|
||||
var avuri = "/Avatars/" + Model.UserName + ".s.png";
|
||||
}
|
||||
<div class="userinfo">
|
||||
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
|
||||
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
|
||||
</a>
|
||||
</div>
|
@ -14,6 +14,6 @@
|
||||
<input type="hidden" name="@parameter.Key" value="@parameter.Value" />
|
||||
}
|
||||
|
||||
<input class="btn btn-light btn-success" name="Authorize" type="submit" value="Yeah, sure" />
|
||||
<input class="btn btn-lg btn-success" name="Authorize" type="submit" value="Yeah, sure" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -37,7 +37,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<button type="submit" class="btn btn-light btn-success" name="submit.Signin">Login</button>
|
||||
<button type="submit" class="btn btn-lg btn-success" name="submit.Signin">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
|
@ -16,10 +16,7 @@
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
@await RenderSectionAsync("header", false)
|
||||
</head>
|
||||
<body style="background-image: url('@Config.SiteSetup.Banner');
|
||||
background-position: 0%;
|
||||
background-attachment: fixed;
|
||||
">
|
||||
<body>
|
||||
<partial name="_Nav" />
|
||||
@RenderSection("ctxmenu", required: false)
|
||||
@if (ViewData["Notify"] != null)
|
||||
|
@ -2,15 +2,23 @@
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
|
||||
@if (Context.User?.Identity?.IsAuthenticated ?? false)
|
||||
{
|
||||
string userName = User.GetUserName();
|
||||
@{
|
||||
#nullable enable
|
||||
string? name = null;
|
||||
if (Context.User!=null)
|
||||
{
|
||||
name = Context.User.GetUserName();
|
||||
}
|
||||
}
|
||||
|
||||
@if (name!=null)
|
||||
{
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Plateforme</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdown04">
|
||||
<li><a class="dropdown-item" asp-controller="Bug" asp-action="Index">Bugs</a></li>
|
||||
<li><a class="dropdown-item" asp-controller="HyperLink" asp-action="Index">HyperLink</a></li>
|
||||
<li><a class="dropdown-item" asp-controller="LiveFlow" asp-action="Index">LiveFlow</a></li>
|
||||
<li><a class="dropdown-item" asp-controller="Feature" asp-action="Index">Features</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@ -30,7 +38,7 @@
|
||||
</ul>
|
||||
</li>}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Hello @userName!</a>
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Hello @UserManager.GetUserName(User)!</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item" asp-controller="Manage" asp-action="Index" title="Manage">
|
||||
@ -54,4 +62,3 @@ else
|
||||
<a class="nav-link" asp-controller="Account" asp-action="Login" asp-route-ReturnUrl="~/" >Login</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,24 @@
|
||||
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-dark" aria-label="Yavsc">
|
||||
<a class="navbar-brand" href="#">@Config.SiteSetup.Title</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
|
||||
<a href="~/" class="navbar-brand"><img src="~/images/it/free-sofware.svg" class="icon-banner" alt="Lua"></a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbar" aria-controls="navbar"
|
||||
aria-expanded="true" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbar" style="background-image: @Config.SiteSetup.Banner;">
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbar">
|
||||
<ul class="navbar-nav me-auto" >
|
||||
<li class="nav-item"><a class="nav-link active" aria-current="page" href="/">Home</a></li>
|
||||
<li class="nav-item"><a asp-controller="Blogspot" asp-action="Index" class="nav-link">@SR["Blogs"]</a></li>
|
||||
<li class="nav-item"><a asp-controller="Home" asp-action="Chat" class="nav-link">@SR["Chat"]</a></li>
|
||||
<li class="nav-item"><a asp-controller="Home" asp-action="Contact" class="nav-link">@SR["Contact"]</a></li>
|
||||
<li class="nav-item"><a asp-controller="Home" asp-action="About" class="nav-link">@SR["About"]</a></li>
|
||||
|
||||
<partial name="_LoginPartial" />
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
@ -10,38 +10,36 @@
|
||||
<PackageReference Include="popper.js" Version="1.16.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="bootstrap" Version="5.3.7">
|
||||
<PackageReference Include="bootstrap" Version="5.3.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.5-preview-net9" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.4" />
|
||||
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.7">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.6">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.7" />
|
||||
<PackageReference Include="Google.Apis.Compute.v1" Version="1.70.0.3829" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.6" />
|
||||
<PackageReference Include="Google.Apis.Compute.v1" Version="1.54.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.7" />
|
||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
|
||||
<PackageReference Include="AsciiDocNet" Version="1.0.0-alpha6" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.7" />
|
||||
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
|
||||
|
@ -13,6 +13,7 @@
|
||||
.navbar-dark .navbar-toggler-icon {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); }
|
||||
|
||||
/* bootstrap.css | http://localhost:5000/lib/bootstrap/css/bootstrap.css */
|
||||
div.carousel-inner > div.item > div.carousel-caption-s {
|
||||
margin: .5em;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
@ -24,28 +25,13 @@ img.blogphoto {
|
||||
max-width: 100%;
|
||||
max-height: 100%; }
|
||||
|
||||
input[type='checkbox'] {
|
||||
appearance: auto;
|
||||
min-width: 1em;
|
||||
min-height: 1em; }
|
||||
|
||||
.container {
|
||||
background-color: #00000093;
|
||||
color: #fff;
|
||||
padding: .5em;
|
||||
margin: .5em; }
|
||||
|
||||
.post {
|
||||
background-color: #000000dd;
|
||||
color: #d1d1d1;
|
||||
padding: 2.3em;
|
||||
border-radius: 2em;
|
||||
border: solid #441515a4 2pt; }
|
||||
|
||||
.actiongroup {
|
||||
float: right;
|
||||
margin: .5em; }
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
margin: .5em; }
|
||||
.cmtdatetime {
|
||||
font-style: italic;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.blogcomment {
|
||||
display: inline-block;
|
||||
padding: .3em;
|
||||
border: solid black 1px;
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
.grants-page {
|
||||
.card {
|
||||
margin-top: 20px;
|
||||
@ -25,6 +23,10 @@
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
|
||||
/* bootstrap.css | http://localhost:5000/lib/bootstrap/css/bootstrap.css */
|
||||
|
||||
|
||||
div.carousel-inner > div.item > div.carousel-caption-s {
|
||||
margin: .5em;
|
||||
background-color: rgba(0,0,0,.6);
|
||||
@ -37,36 +39,3 @@ img.blogphoto {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
appearance: auto;
|
||||
min-width: 1em;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #00000093;
|
||||
color: #fff;
|
||||
padding: .5em;
|
||||
margin: .5em;
|
||||
}
|
||||
|
||||
.post {
|
||||
background-color: #000000dd;
|
||||
color:#d1d1d1;
|
||||
padding: 2.3em;
|
||||
border-radius: 2em;
|
||||
border: solid #441515a4 2pt;
|
||||
}
|
||||
|
||||
.actiongroup
|
||||
{
|
||||
float: right;
|
||||
margin:.5em;
|
||||
}
|
||||
|
||||
.float-left
|
||||
{
|
||||
float: left;
|
||||
margin:.5em;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
|
||||
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
|
||||
--#{$prefix}nav-link-color: #{$nav-link-color};
|
||||
--#{$prefix}nav-link-background-color: #{$dropdown-dark-bg};
|
||||
--#{$prefix}nav-link-hover-color: #{$nav-link-hover-color};
|
||||
--#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color};
|
||||
// scss-docs-end nav-css-vars
|
||||
@ -27,8 +28,9 @@
|
||||
@include font-size(var(--#{$prefix}nav-link-font-size));
|
||||
font-weight: var(--#{$prefix}nav-link-font-weight);
|
||||
color: var(--#{$prefix}nav-link-color);
|
||||
background-color: var(--#{$prefix}nav-link-background-color);
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
background: none;
|
||||
background-color: var(--#{$prefix}nav-tabs-link-active-bg);
|
||||
border: 0;
|
||||
@include transition($nav-link-transition);
|
||||
|
||||
|
@ -1607,7 +1607,6 @@ $list-group-action-active-color: var(--#{$prefix}body-color) !default;
|
||||
$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default;
|
||||
// scss-docs-end list-group-variables
|
||||
|
||||
|
||||
// Image thumbnails
|
||||
|
||||
// scss-docs-start thumbnail-variables
|
||||
@ -1619,7 +1618,6 @@ $thumbnail-border-radius: var(--#{$prefix}border-radius) !default;
|
||||
$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default;
|
||||
// scss-docs-end thumbnail-variables
|
||||
|
||||
|
||||
// Figures
|
||||
|
||||
// scss-docs-start figure-variables
|
||||
@ -1747,5 +1745,3 @@ $kbd-bg: var(--#{$prefix}body-color) !default;
|
||||
$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6
|
||||
|
||||
$pre-color: null !default;
|
||||
|
||||
@import "variables-dark"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3
|
||||
|
@ -11,6 +11,7 @@
|
||||
font-weight: $input-font-weight;
|
||||
line-height: $input-line-height;
|
||||
color: $input-color;
|
||||
appearance: none; // Fix appearance for date inputs in Safari
|
||||
background-color: $input-bg;
|
||||
background-clip: padding-box;
|
||||
border: $input-border-width solid $input-border-color;
|
||||
|
@ -1,6 +1,5 @@
|
||||
User-agent: *
|
||||
Disallow: /signin
|
||||
Disallow: /signin-google
|
||||
Disallow: /Account/Register
|
||||
Disallow: /External
|
||||
Disallow: /Command/Create
|
||||
|
||||
|
@ -13,7 +13,8 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
JwtSecurityTokenHandler.DefaultMapInboundClaims = true;
|
||||
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -27,7 +28,8 @@ builder.Services
|
||||
.AddCookie("Cookies")
|
||||
.AddOpenIdConnect("oidc", options =>
|
||||
{
|
||||
options.Authority = builder.Configuration.GetValue<String>("AuthIssuer");
|
||||
options.Authority = "https://localhost:5001";
|
||||
|
||||
options.ClientId = "mvc";
|
||||
options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0";
|
||||
options.ResponseType = "code";
|
||||
@ -36,14 +38,15 @@ builder.Services
|
||||
options.Scope.Add("profile");
|
||||
options.Scope.Add("scope2");
|
||||
options.MapInboundClaims = true;
|
||||
options.ClaimActions.MapUniqueJsonKey("preferred_username", "preferred_username");
|
||||
options.ClaimActions.MapUniqueJsonKey("preferred_username","preferred_username");
|
||||
options.ClaimActions.MapUniqueJsonKey("gender", "gender");
|
||||
|
||||
options.SaveTokens = true;
|
||||
});
|
||||
|
||||
|
||||
using (var app = builder.Build())
|
||||
{
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
app.UseDeveloperExceptionPage();
|
||||
else
|
||||
|
@ -19,26 +19,26 @@
|
||||
}
|
||||
|
||||
<form action="~/Home/GetUserInfo" method="post">
|
||||
<button class="btn btn-light btn-warning" type="submit">Get user info</button>
|
||||
<button class="btn btn-lg btn-warning" type="submit">Get user info</button>
|
||||
</form>
|
||||
|
||||
<form action="~/Home/GetApiCall" method="post">
|
||||
<button class="btn btn-light btn-warning" type="submit">Api Call</button>
|
||||
<button class="btn btn-lg btn-warning" type="submit">Api Call</button>
|
||||
</form>
|
||||
|
||||
<form action="~/Home/PostDeviceInfo" method="post">
|
||||
<button class="btn btn-light btn-warning" type="submit">Post device info</button>
|
||||
<button class="btn btn-lg btn-warning" type="submit">Post device info</button>
|
||||
</form>
|
||||
<form action="~/Home/PostFiles/?subdir=test" method="post" enctype="multipart/form-data">
|
||||
Envoyer vers le dossier "test" <input type="file" name="file" multiple/>
|
||||
<button class="btn btn-light btn-warning" type="submit">Post files</button>
|
||||
<button class="btn btn-lg btn-warning" type="submit">Post files</button>
|
||||
</form>
|
||||
|
||||
<a class="btn btn-light btn-danger" href="/signout">Sign out</a>
|
||||
<a class="btn btn-lg btn-danger" href="/signout">Sign out</a>
|
||||
}
|
||||
|
||||
else {
|
||||
<h1>Welcome, anonymous</h1>
|
||||
<a class="btn btn-light btn-success" href="/signin">Sign in</a>
|
||||
<a class="btn btn-lg btn-success" href="/signin">Sign in</a>
|
||||
}
|
||||
</div>
|
||||
|
@ -6,7 +6,6 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"AuthIssuer": "https://localhost:5001",
|
||||
"Kestrel": {
|
||||
"Endpoints":
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
|
||||
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
BIN
src/sampleWebAsWebApiClient/wwwroot/images/ASP-NET-Banners-01.png
Executable file
BIN
src/sampleWebAsWebApiClient/wwwroot/images/ASP-NET-Banners-01.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
@ -2120,6 +2120,9 @@ progress {
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: var(--bs-body-color);
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background-color: var(--bs-body-bg);
|
||||
background-clip: padding-box;
|
||||
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||
@ -12037,4 +12040,4 @@ textarea.form-control-lg {
|
||||
}
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap.css.map */
|
||||
/*# sourceMappingURL=bootstrap.css.map */
|
@ -11,6 +11,7 @@
|
||||
font-weight: $input-font-weight;
|
||||
line-height: $input-line-height;
|
||||
color: $input-color;
|
||||
appearance: none; // Fix appearance for date inputs in Safari
|
||||
background-color: $input-bg;
|
||||
background-clip: padding-box;
|
||||
border: $input-border-width solid $input-border-color;
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user