Compare commits
21 Commits
dependabot
...
984b76b170
Author | SHA1 | Date | |
---|---|---|---|
984b76b170 | |||
19a3ba6f87 | |||
a39f39c692 | |||
e870271fe4 | |||
080578c101 | |||
d0d1c652fe | |||
0a1bef37fe | |||
2a825da32e | |||
e6f8947c08 | |||
15d35e5508 | |||
3f1bfc1c3c | |||
fdf75934e5 | |||
f603d87b33 | |||
bebca989d0 | |||
531797d348 | |||
2002b8b232 | |||
0e0a79c6cd | |||
0f52a875de | |||
70771e5ab5 | |||
447d926ca6 | |||
b4870a1814 |
@ -44,7 +44,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
@ -1,7 +0,0 @@
|
||||
on: workflow_call
|
||||
jobs:
|
||||
my_first_job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run my action
|
||||
uses: ./.github/worklflows/dotnet
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@
|
||||
.paket/
|
||||
.vs/
|
||||
.sass-cache/
|
||||
.private/
|
||||
|
||||
/out
|
||||
bin
|
||||
|
33
.vscode/launch.json
vendored
33
.vscode/launch.json
vendored
@ -4,6 +4,32 @@
|
||||
// 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"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/* {
|
||||
@ -43,7 +69,7 @@
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net8.0/Yavsc.dll",
|
||||
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net9.0/Yavsc.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/src/Yavsc",
|
||||
"stopAtEntry": false,
|
||||
@ -83,6 +109,11 @@
|
||||
"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,8 +9,12 @@
|
||||
"args": [
|
||||
"build",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign",
|
||||
|
||||
],
|
||||
"group": "build",
|
||||
"isBuildCommand": true,
|
||||
"isTestCommand": false,
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
|
15
README.md
15
README.md
@ -17,15 +17,15 @@ C'est une application mettant en oeuvre une prise de contact entre un demandeur
|
||||
|
||||
et, pour execution en environement de développement
|
||||
|
||||
```
|
||||
~/workspace/yavsc/Yavsc @ ASPNETCORE_ENV=Development dotnet run
|
||||
```bash
|
||||
~/workspace/yavsc/Yavsc @ ASPNETCORE_ENV=Development dotnet run
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Utilisez GNU/Makefile (et visitez le code, dans le dossier `test` ):
|
||||
|
||||
[TOREDO] Depuis le répertoire racine:
|
||||
[TODO] Depuis le répertoire racine:
|
||||
|
||||
```bash
|
||||
make test
|
||||
@ -33,13 +33,14 @@ make test
|
||||
|
||||
## Installation / Déploiment / Développement
|
||||
|
||||
### les services kestrel et kestrel-pre
|
||||
|
||||
[TODO]
|
||||
### les services et l'API
|
||||
|
||||
### La Prod
|
||||
|
||||
Une fois sûr de vous, et une fois que Git dit propre votre copie de travail, depuis le répertoire `Yavsc`, lancez `make pushInProd`.
|
||||
`cd srv/Yavsc` : `make pushInProd CONFIGURATION=Release`.
|
||||
|
||||
puis, pour une première installation
|
||||
`make install_service`.
|
||||
|
||||
## Fonctionalités (encore en cours de développement)
|
||||
|
||||
|
27
contrib/yavsc.service
Normal file
27
contrib/yavsc.service
Normal file
@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=Yavsc
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
Wants=postgresql.service
|
||||
After=postgresql.service
|
||||
|
||||
[Service]
|
||||
RestartSec=5s
|
||||
Type=simple
|
||||
User=www-data
|
||||
Group=www-data
|
||||
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"
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=yavsc
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>1c73094f-959f-4211-b1a1-6a69b236c283</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -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,23 +1,16 @@
|
||||
using Yavsc.Attributes.Validation;
|
||||
namespace Yavsc.Models.FileSystem
|
||||
{
|
||||
public class RenameFileQuery {
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public 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; }
|
||||
public class MoveFileQuery
|
||||
{
|
||||
[ValidRemoteUserFilePath]
|
||||
[YaStringLength(1, 512)]
|
||||
public required string Id { get; set; }
|
||||
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public string to { get; set; }
|
||||
}
|
||||
[YaStringLength(0, 512)]
|
||||
[ValidRemoteUserFilePath]
|
||||
public required string To { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
15
src/Api/Controllers/Blogspot/RenameFileQuery.cs
Normal file
15
src/Api/Controllers/Blogspot/RenameFileQuery.cs
Normal file
@ -0,0 +1,15 @@
|
||||
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/reject")]
|
||||
[HttpPost("query/accept")]
|
||||
public IActionResult AcceptQuery(string billingCode, long queryId)
|
||||
{
|
||||
if (billingCode == null) return BadRequest("billingCode");
|
||||
@ -51,7 +51,6 @@ namespace Yavsc.ApiControllers
|
||||
billing.Decided = true;
|
||||
dbContext.SaveChanges();
|
||||
return Ok();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ 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,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Api.Helpers;
|
||||
using Yavsc.Server.Helpers;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Yavsc.WebApi.Controllers
|
||||
{
|
||||
@ -30,9 +31,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);
|
||||
@ -57,7 +58,7 @@ namespace Yavsc.WebApi.Controllers
|
||||
[HttpGet("myhost")]
|
||||
public IActionResult MyHost ()
|
||||
{
|
||||
return Ok(new { host = Request.ForHost() });
|
||||
return Ok(new { host = Request.ForwardedFor() });
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,8 +13,8 @@ namespace Yavsc.Api.Helpers
|
||||
public static class RequestHelpers
|
||||
{
|
||||
// Check for some apache proxy header, if any
|
||||
public static string ForHost(this HttpRequest request) {
|
||||
string host = request.Headers["X-Forwarded-For"];
|
||||
public static string? ForwardedFor(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,8 +11,6 @@
|
||||
*/
|
||||
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Helpers;
|
||||
@ -63,7 +61,8 @@ internal class Program
|
||||
options.IncludeErrorDetails = true;
|
||||
options.Authority = "https://localhost:5001";
|
||||
options.TokenValidationParameters =
|
||||
new() { ValidateAudience = false };
|
||||
new() { ValidateAudience = false, RoleClaimType = JwtClaimTypes.Role };
|
||||
options.MapInboundClaims = true;
|
||||
});
|
||||
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
@ -74,9 +73,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();
|
||||
@ -101,15 +100,10 @@ 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,16 +1,19 @@
|
||||
|
||||
|
||||
|
||||
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,9 +52,7 @@ 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";
|
||||
public const string StreamingPath = "/api/stream/put";
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Yavsc.Models.Messaging;
|
||||
|
||||
namespace Yavsc.Models.Google.Messaging
|
||||
|
@ -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; set; }
|
||||
string DedicatedGoogleCalendar { get; set; }
|
||||
ILocation PostalAddress { get; set; }
|
||||
string? UserName { get; set; }
|
||||
string? Avatar { get ; set; }
|
||||
IAccountBalance? AccountBalance { get; }
|
||||
string? DedicatedGoogleCalendar { get; }
|
||||
ILocation? PostalAddress { get; }
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ namespace Yavsc.Abstract.Identity.Security
|
||||
public interface ICircleAuthorized
|
||||
{
|
||||
long Id { get; set; }
|
||||
string OwnerId { get; }
|
||||
string AuthorId { get; }
|
||||
bool AuthorizeCircle(long circleId);
|
||||
ICircleAuthorization [] GetACL();
|
||||
|
||||
|
@ -5,8 +5,8 @@ namespace Yavsc
|
||||
public interface ITrackedEntity
|
||||
{
|
||||
DateTime DateCreated { get; set; }
|
||||
string UserCreated { get; set; }
|
||||
string? UserCreated { get; set; }
|
||||
DateTime DateModified { get; set; }
|
||||
string UserModified { get; set; }
|
||||
string? UserModified { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Yavsc.Models.Messaging
|
||||
namespace Yavsc.Abstract.Models.Messaging
|
||||
{
|
||||
/// <summary>
|
||||
/// A Notification, that mocks the one sent to Google,
|
||||
@ -29,25 +29,25 @@ namespace Yavsc.Models.Messaging
|
||||
/// </summary>
|
||||
[StringLength(512)]
|
||||
[Display(Name = "Icône")]
|
||||
public string icon { get; set; }
|
||||
public string? icon { get; set; }
|
||||
/// <summary>
|
||||
/// The sound.
|
||||
/// </summary>
|
||||
[StringLength(512)]
|
||||
[Display(Name = "Son")]
|
||||
public string sound { get; set; }
|
||||
public string? sound { get; set; }
|
||||
/// <summary>
|
||||
/// The tag.
|
||||
/// </summary>
|
||||
[StringLength(512)]
|
||||
[Display(Name = "Tag")]
|
||||
public string tag { get; set; }
|
||||
public string? tag { get; set; }
|
||||
/// <summary>
|
||||
/// The color.
|
||||
/// </summary>
|
||||
[StringLength(512)]
|
||||
[Display(Name = "Couleur")]
|
||||
public string color { get; set; }
|
||||
public string? color { get; set; }
|
||||
/// <summary>
|
||||
/// The click action.
|
||||
/// </summary>
|
||||
@ -63,7 +63,7 @@ namespace Yavsc.Models.Messaging
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[StringLength(512)]
|
||||
public string Target { get; set; }
|
||||
public string? Target { get; set; }
|
||||
|
||||
public Notification()
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0</TargetFrameworks>
|
||||
<TargetFrameworks>net9.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description> A shared model for a little client/server app, dealing about establishing some contract, between some human client and provider.
|
||||
|
13
src/Yavsc.Server/.config/dotnet-tools.json
Normal file
13
src/Yavsc.Server/.config/dotnet-tools.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"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" },
|
||||
},
|
||||
};
|
||||
|
||||
|
17
src/Yavsc.Server/Exceptions/AuthorizationFailureException.cs
Normal file
17
src/Yavsc.Server/Exceptions/AuthorizationFailureException.cs
Normal file
@ -0,0 +1,17 @@
|
||||
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(ClaimTypes.Name);
|
||||
return user.FindFirstValue("name");
|
||||
}
|
||||
|
||||
public static bool IsSignedIn(this ClaimsPrincipal user)
|
||||
@ -24,13 +24,14 @@ 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.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Where(x => ((x.AuthorId == posterId))).ToArray();
|
||||
var userPosts = dbContext.blogSpotPublications.Include(
|
||||
b => b.BlogPost
|
||||
).Where(x => x.BlogPost.AuthorId == posterId)
|
||||
.Select(x=>x.BlogPost).ToArray();
|
||||
return userPosts;
|
||||
}
|
||||
else
|
||||
|
@ -29,11 +29,13 @@ 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
|
||||
{
|
||||
@ -192,10 +194,11 @@ namespace Yavsc
|
||||
NotifyUserInRoom(NotificationTypes.Error, room, "already registered.");
|
||||
return;
|
||||
}
|
||||
string userName = Context.User.Identity.Name;
|
||||
Debug.Assert(Context.User != null);
|
||||
string userName = Context.User.GetUserName();
|
||||
var user = _dbContext.Users.FirstOrDefault(u => u.UserName == userName);
|
||||
|
||||
var newroom = new ChatRoom { Name = room, OwnerId = user.Id };
|
||||
var newroom = new ChatRoom { Name = room, OwnerId = Context.User.GetUserId() };
|
||||
ChatRoomInfo chanInfo;
|
||||
if (_cxManager.TryGetChanInfo(room, out chanInfo))
|
||||
{
|
||||
@ -319,7 +322,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);
|
||||
}
|
||||
|
||||
@ -331,6 +334,8 @@ 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))
|
||||
@ -344,19 +349,21 @@ namespace Yavsc
|
||||
return ;
|
||||
}
|
||||
_logger.LogInformation($"Message form is validated.");
|
||||
var identityUserName = Context.User.GetUserName();
|
||||
|
||||
if (userName[0] != '?')
|
||||
if (userName[0] != '?' && Context.User!=null)
|
||||
if (!Context.User.IsInRole(Constants.AdminGroupName))
|
||||
{
|
||||
|
||||
var bl = _dbContext.BlackListed
|
||||
.Include(r => r.User)
|
||||
.Include(r => r.Owner)
|
||||
.Where(r => r.User.UserName == Context.User.Identity.Name && r.Owner.UserName == userName)
|
||||
.Where(r => r.User.UserName == identityUserName && r.Owner.UserName == userName)
|
||||
.Select(r => r.OwnerId);
|
||||
|
||||
if (bl.Count() > 0)
|
||||
{
|
||||
_logger.LogError($"Black listed : {Context.User.Identity.Name}");
|
||||
_logger.LogError($"Black listed : {identityUserName}");
|
||||
await NotifyUser(NotificationTypes.PrivateMessageDenied, userName, "you are black listed.");
|
||||
return;
|
||||
}
|
||||
@ -372,7 +379,7 @@ namespace Yavsc
|
||||
_logger.LogInformation($"cx: {connectionId}");
|
||||
var cli = Clients.Client(connectionId);
|
||||
_logger.LogInformation($"cli: {cli.ToString()}");
|
||||
await cli.SendAsync("addPV", Context.User.Identity.Name, message);
|
||||
await cli.SendAsync("addPV", identityUserName, message);
|
||||
_logger.LogInformation($"Sent pv to cx {connectionId}");
|
||||
}
|
||||
}
|
||||
@ -380,6 +387,9 @@ 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);
|
||||
|
3509
src/Yavsc.Server/Migrations/20250613122253_notificationTarget.Designer.cs
generated
Normal file
3509
src/Yavsc.Server/Migrations/20250613122253_notificationTarget.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class notificationTarget : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Visible",
|
||||
table: "BlogSpot");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Target",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Target",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "Visible",
|
||||
table: "BlogSpot",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
}
|
||||
}
|
3505
src/Yavsc.Server/Migrations/20250613123306_notificationNulls.Designer.cs
generated
Normal file
3505
src/Yavsc.Server/Migrations/20250613123306_notificationNulls.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
109
src/Yavsc.Server/Migrations/20250613123306_notificationNulls.cs
Normal file
109
src/Yavsc.Server/Migrations/20250613123306_notificationNulls.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class notificationNulls : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "tag",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "sound",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "icon",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
defaultValue: "exclam",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldDefaultValue: "exclam");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "color",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "tag",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "sound",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "icon",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "exclam",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true,
|
||||
oldDefaultValue: "exclam");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "color",
|
||||
table: "Notification",
|
||||
type: "character varying(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(512)",
|
||||
oldMaxLength: 512,
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
3505
src/Yavsc.Server/Migrations/20250613131533_trackedNulls.Designer.cs
generated
Normal file
3505
src/Yavsc.Server/Migrations/20250613131533_trackedNulls.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
src/Yavsc.Server/Migrations/20250613131533_trackedNulls.cs
Normal file
22
src/Yavsc.Server/Migrations/20250613131533_trackedNulls.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class trackedNulls : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
3503
src/Yavsc.Server/Migrations/20250613131836_blogNulls.Designer.cs
generated
Normal file
3503
src/Yavsc.Server/Migrations/20250613131836_blogNulls.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
54
src/Yavsc.Server/Migrations/20250613131836_blogNulls.cs
Normal file
54
src/Yavsc.Server/Migrations/20250613131836_blogNulls.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class blogNulls : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserModified",
|
||||
table: "BlogSpot",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserCreated",
|
||||
table: "BlogSpot",
|
||||
type: "text",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserModified",
|
||||
table: "BlogSpot",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "UserCreated",
|
||||
table: "BlogSpot",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
3502
src/Yavsc.Server/Migrations/20250613132139_BlogPostInputViewModelNulls.Designer.cs
generated
Normal file
3502
src/Yavsc.Server/Migrations/20250613132139_BlogPostInputViewModelNulls.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Yavsc.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class BlogPostInputViewModelNulls : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Content",
|
||||
table: "BlogSpot",
|
||||
type: "character varying(56224)",
|
||||
maxLength: 56224,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(56224)",
|
||||
oldMaxLength: 56224);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Content",
|
||||
table: "BlogSpot",
|
||||
type: "character varying(56224)",
|
||||
maxLength: 56224,
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(56224)",
|
||||
oldMaxLength: 56224,
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
3497
src/Yavsc.Server/Migrations/20250613181510_ActivityNulls.Designer.cs
generated
Normal file
3497
src/Yavsc.Server/Migrations/20250613181510_ActivityNulls.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
108
src/Yavsc.Server/Migrations/20250613181510_ActivityNulls.cs
Normal file
108
src/Yavsc.Server/Migrations/20250613181510_ActivityNulls.cs
Normal file
@ -0,0 +1,108 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
3494
src/Yavsc.Server/Migrations/20250620185047_BrusherProfileSchedulerId.Designer.cs
generated
Normal file
3494
src/Yavsc.Server/Migrations/20250620185047_BrusherProfileSchedulerId.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,59 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
3515
src/Yavsc.Server/Migrations/20250628150549_blogPostPub.Designer.cs
generated
Normal file
3515
src/Yavsc.Server/Migrations/20250628150549_blogPostPub.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
src/Yavsc.Server/Migrations/20250628150549_blogPostPub.cs
Normal file
38
src/Yavsc.Server/Migrations/20250628150549_blogPostPub.cs
Normal file
@ -0,0 +1,38 @@
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
3518
src/Yavsc.Server/Migrations/20250629174955_blogPusb2.Designer.cs
generated
Normal file
3518
src/Yavsc.Server/Migrations/20250629174955_blogPusb2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
79
src/Yavsc.Server/Migrations/20250629174955_blogPusb2.cs
Normal file
79
src/Yavsc.Server/Migrations/20250629174955_blogPusb2.cs
Normal file
@ -0,0 +1,79 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
3518
src/Yavsc.Server/Migrations/20250629175034_blogPub2.Designer.cs
generated
Normal file
3518
src/Yavsc.Server/Migrations/20250629175034_blogPub2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
src/Yavsc.Server/Migrations/20250629175034_blogPub2.cs
Normal file
22
src/Yavsc.Server/Migrations/20250629175034_blogPub2.cs
Normal file
@ -0,0 +1,22 @@
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
3519
src/Yavsc.Server/Migrations/20250705112955_commentAllowed.Designer.cs
generated
Normal file
3519
src/Yavsc.Server/Migrations/20250705112955_commentAllowed.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
54
src/Yavsc.Server/Migrations/20250705112955_commentAllowed.cs
Normal file
54
src/Yavsc.Server/Migrations/20250705112955_commentAllowed.cs
Normal file
@ -0,0 +1,54 @@
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
3516
src/Yavsc.Server/Migrations/20250709123810_noPublishColumn.Designer.cs
generated
Normal file
3516
src/Yavsc.Server/Migrations/20250709123810_noPublishColumn.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ namespace Yavsc.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.2")
|
||||
.HasAnnotation("ProductVersion", "9.0.6")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
@ -183,6 +183,56 @@ namespace Yavsc.Migrations
|
||||
b.ToTable("ClientProviderInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Abstract.Models.Messaging.Notification", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Target")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("body")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("click_action")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("color")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("icon")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasDefaultValue("exclam");
|
||||
|
||||
b.Property<string>("sound")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("tag")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Notification");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Access.Ban", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -253,6 +303,9 @@ namespace Yavsc.Migrations
|
||||
b.Property<long>("BlogPostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Comment")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("CircleId", "BlogPostId");
|
||||
|
||||
b.HasIndex("BlogPostId");
|
||||
@ -288,7 +341,6 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
@ -711,7 +763,6 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasMaxLength(56224)
|
||||
.HasColumnType("character varying(56224)");
|
||||
|
||||
@ -731,16 +782,11 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("character varying(1024)");
|
||||
|
||||
b.Property<string>("UserCreated")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("UserModified")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("Visible")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AuthorId");
|
||||
@ -813,6 +859,16 @@ 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")
|
||||
@ -1079,7 +1135,6 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<string>("ScheduleOwnerId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("ShampooPrice")
|
||||
@ -1602,61 +1657,6 @@ namespace Yavsc.Migrations
|
||||
b.ToTable("DismissClicked");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Messaging.Notification", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Target")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("body")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("click_action")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("color")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("icon")
|
||||
.IsRequired()
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasDefaultValue("exclam");
|
||||
|
||||
b.Property<string>("sound")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("tag")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Notification");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Musical.Instrument", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
@ -2092,7 +2092,6 @@ namespace Yavsc.Migrations
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("ModeratorGroupName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Name")
|
||||
@ -2103,22 +2102,18 @@ 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");
|
||||
@ -2780,6 +2775,17 @@ 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")
|
||||
@ -2851,9 +2857,7 @@ namespace Yavsc.Migrations
|
||||
{
|
||||
b.HasOne("Yavsc.Models.Calendar.Schedule", "Schedule")
|
||||
.WithMany()
|
||||
.HasForeignKey("ScheduleOwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
.HasForeignKey("ScheduleOwnerId");
|
||||
|
||||
b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "BaseProfile")
|
||||
.WithMany()
|
||||
@ -3057,7 +3061,7 @@ namespace Yavsc.Migrations
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.Messaging.DismissClicked", b =>
|
||||
{
|
||||
b.HasOne("Yavsc.Models.Messaging.Notification", "Notified")
|
||||
b.HasOne("Yavsc.Abstract.Models.Messaging.Notification", "Notified")
|
||||
.WithMany()
|
||||
.HasForeignKey("NotificationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
@ -3388,8 +3392,7 @@ namespace Yavsc.Migrations
|
||||
|
||||
modelBuilder.Entity("Yavsc.Models.ApplicationUser", b =>
|
||||
{
|
||||
b.Navigation("AccountBalance")
|
||||
.IsRequired();
|
||||
b.Navigation("AccountBalance");
|
||||
|
||||
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,7 +17,10 @@ namespace Yavsc.Models.Access
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey("CircleId")]
|
||||
public virtual Circle Allowed { get; set; }
|
||||
public virtual Circle Allowed { get; set; }
|
||||
|
||||
public bool Comment { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
|
||||
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;
|
||||
@ -10,7 +6,6 @@ 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
|
||||
{
|
||||
@ -32,7 +27,6 @@ namespace Yavsc.Models
|
||||
using Attributes;
|
||||
using Bank;
|
||||
using Payment;
|
||||
using Calendar;
|
||||
using Blog;
|
||||
using Yavsc.Abstract.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -40,6 +34,9 @@ namespace Yavsc.Models
|
||||
using Yavsc.Server.Models.Calendar;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Org.BouncyCastle.Asn1.Crmf;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||
{
|
||||
@ -50,7 +47,7 @@ namespace Yavsc.Models
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
@ -60,7 +57,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);
|
||||
@ -80,7 +77,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())
|
||||
{
|
||||
@ -88,23 +85,22 @@ namespace Yavsc.Models
|
||||
et.FindProperty("DateCreated").SetAfterSaveBehavior(Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore);
|
||||
}
|
||||
|
||||
builder.Entity<Activity>().Property(a=>a.ParentCode).IsRequired(false);
|
||||
//builder.Entity<BlogPost>().HasOne(p => p.Author).WithMany(a => a.Posts);
|
||||
|
||||
builder.Entity<Activity>().Property(a => a.ParentCode).IsRequired(false);
|
||||
builder.Entity<IdentityUserLogin<String>>().HasKey(i=> new { i.LoginProvider, i.UserId, i.ProviderKey });
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
@ -124,7 +120,7 @@ namespace Yavsc.Models
|
||||
/// Users posts
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DbSet<Blog.BlogPost> BlogSpot { get; set; }
|
||||
public DbSet<BlogPost> BlogSpot { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Skills powered by this site
|
||||
@ -225,14 +221,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))
|
||||
{
|
||||
@ -281,7 +277,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
|
||||
@ -294,7 +290,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; }
|
||||
|
||||
@ -303,6 +299,8 @@ 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,10 +7,12 @@ 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
|
||||
public class ApplicationUser : IdentityUser, IApplicationUser
|
||||
{
|
||||
/// <summary>
|
||||
/// Another me, as a byte array.TG7@Eu%80rufzkhbb
|
||||
@ -22,10 +24,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>
|
||||
@ -33,32 +35,31 @@ 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
|
||||
@ -66,7 +67,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
|
||||
@ -81,14 +82,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;
|
||||
@ -97,21 +98,24 @@ 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,6 +5,8 @@ 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;
|
||||
@ -14,7 +16,8 @@ using Yavsc.ViewModels.Blog;
|
||||
|
||||
namespace Yavsc.Models.Blog
|
||||
{
|
||||
public class BlogPost : BlogPostInputViewModel, IBlogPost, ICircleAuthorized, ITaggable<long>, IIdentified<long>
|
||||
public class BlogPost : BlogPostBase,
|
||||
IBlogPost, ICircleAuthorized, ITaggable<long>
|
||||
{
|
||||
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Display(Name="Identifiant du post")]
|
||||
@ -35,7 +38,7 @@ namespace Yavsc.Models.Blog
|
||||
}
|
||||
|
||||
[Display(Name="Créateur")]
|
||||
public string UserCreated
|
||||
public string? UserCreated
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@ -47,7 +50,7 @@ namespace Yavsc.Models.Blog
|
||||
}
|
||||
|
||||
[Display(Name="Utilisateur ayant modifé le dernier")]
|
||||
public string UserModified
|
||||
public string? UserModified
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@ -85,7 +88,6 @@ namespace Yavsc.Models.Blog
|
||||
[InverseProperty("Post")]
|
||||
public virtual List<Comment> Comments { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string OwnerId => AuthorId;
|
||||
IApplicationUser IBlogPost.Author { get => this.Author; }
|
||||
}
|
||||
}
|
||||
|
15
src/Yavsc.Server/Models/Blog/BlogspotPublication.cs
Normal file
15
src/Yavsc.Server/Models/Blog/BlogspotPublication.cs
Normal file
@ -0,0 +1,15 @@
|
||||
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}")]
|
||||
|
||||
|
33
src/Yavsc.Server/Models/IdentityUserLogin.cs
Normal file
33
src/Yavsc.Server/Models/IdentityUserLogin.cs
Normal file
@ -0,0 +1,33 @@
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Yavsc.Attributes.Validation;
|
||||
|
||||
namespace Yavsc.Models.Messaging
|
||||
|
@ -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; }
|
||||
|
||||
}
|
||||
|
||||
|
13
src/Yavsc.Server/Services/BlogPostEdition.cs
Normal file
13
src/Yavsc.Server/Services/BlogPostEdition.cs
Normal file
@ -0,0 +1,13 @@
|
||||
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();
|
||||
}
|
||||
}
|
193
src/Yavsc.Server/Services/BlogSpotService.cs
Normal file
193
src/Yavsc.Server/Services/BlogSpotService.cs
Normal file
@ -0,0 +1,193 @@
|
||||
|
||||
|
||||
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,7 +130,6 @@ 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,13 +1,9 @@
|
||||
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;
|
||||
@ -27,8 +23,7 @@ namespace Yavsc.Services
|
||||
public MailSender(
|
||||
IOptions<SiteSettings> sitesOptions,
|
||||
IOptions<SmtpSettings> smtpOptions,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStringLocalizer<Yavsc.YavscLocalization> localizer
|
||||
ILoggerFactory loggerFactory
|
||||
)
|
||||
{
|
||||
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(Constants.RoleClaimName, r)));
|
||||
claims.AddRange(roles.Select(r => new Claim(JwtClaimTypes.Role, 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,7 +6,9 @@ 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";
|
||||
|
@ -5,20 +5,21 @@ using Yavsc.Models.Access;
|
||||
|
||||
namespace Yavsc.ViewModels.Blog
|
||||
{
|
||||
public class BlogPostInputViewModel
|
||||
{
|
||||
public class BlogPostBase
|
||||
{
|
||||
[StringLength(1024)]
|
||||
public string? Photo { get; set; }
|
||||
|
||||
[StringLength(1024)]
|
||||
[Required]
|
||||
public string Title { get; set; }
|
||||
|
||||
[StringLength(56224)]
|
||||
public string Content { get; set; }
|
||||
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; }
|
||||
|
||||
|
||||
}
|
@ -1,11 +1,50 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Yavsc.Models.Blog;
|
||||
|
||||
namespace Yavsc.ViewModels.Blog;
|
||||
|
||||
public class BlogPostEditViewModel : BlogPostInputViewModel
|
||||
|
||||
public class BlogPostCreateViewModel : BlogPostBase
|
||||
{
|
||||
public bool Publish { get; set; }
|
||||
}
|
||||
|
||||
public class BlogPostEditViewModel : BlogPostCreateViewModel
|
||||
{
|
||||
|
||||
[Required]
|
||||
|
||||
public required long Id { get; set; }
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UserSecretsId>53bd70e8-ff81-497a-847f-a15fd8ea7a09</UserSecretsId>
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
|
||||
<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" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
|
||||
<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.StaticFiles" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.1" />
|
||||
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.60.0.2993" />
|
||||
<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="PayPalMerchantSDK" Version="2.16.250" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />
|
||||
<PackageReference Include="MailKit" Version="4.3.0" />
|
||||
<PackageReference Include="MimeKit" Version="4.7.1" />
|
||||
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||
<PackageReference Include="MimeKit" Version="4.13.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>
|
||||
|
169
src/Yavsc/"BlogSpot"
Normal file
169
src/Yavsc/"BlogSpot"
Normal file
@ -0,0 +1,169 @@
|
||||
\dt
|
||||
select user,password from users;
|
||||
select user,passwd from users;
|
||||
select user from users;
|
||||
select username,pwd from users;
|
||||
select username,passwd from users;
|
||||
select username,password from users;
|
||||
\dT users
|
||||
\d users
|
||||
select username,passwd from users;
|
||||
select username,passd from users;
|
||||
\d users
|
||||
select username,passw from users;
|
||||
\d profiledata
|
||||
select gregid from profiledata;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,username from profile;
|
||||
select uniqueid,username from profiles;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,username from profiles;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,gregid from profiledata;
|
||||
select uniqueid,gregid from profiledata;
|
||||
drop table GitRepositoryReference;
|
||||
\use YavscDev
|
||||
\use
|
||||
\?
|
||||
\use \?
|
||||
\dt
|
||||
drop table "GitRepositoryReference";
|
||||
drop table "GitRepositoryReference" CASCADE;
|
||||
exit;
|
||||
\q
|
||||
delete from "Project"
|
||||
;
|
||||
\q
|
||||
create database dotnetmvc
|
||||
;
|
||||
create user dotnetmvc ;
|
||||
grant CREATE on paul;
|
||||
grant admins TO paul;
|
||||
grant CREATE TO paul;
|
||||
grant postgres TO paul;
|
||||
grant paul TO postgres;
|
||||
commit;
|
||||
CREATE ROLE baget nocreatedb nocreaterole noreplication;
|
||||
CREATE ROLE baget nocreatedb nocreaterole noreplication;
|
||||
CREATE ROLE baget nocreatedb nocreaterole noreplication;
|
||||
DROP ROLE baget;
|
||||
commit;
|
||||
alter role baget with superuser
|
||||
;
|
||||
commit;
|
||||
\dT Project
|
||||
\dt Project
|
||||
\dt "Project"
|
||||
desc "Project"
|
||||
\?
|
||||
\d "Project"
|
||||
\d BlogSpot
|
||||
\d Blogspot
|
||||
\d "Blogspot"
|
||||
\d "BlogSpot"
|
||||
\d "BlogPost"
|
||||
\d "BlogPost"
|
||||
\d "BlogPost"
|
||||
\d "BlogPost"
|
||||
\d "BlogPost"
|
||||
\d AspNetUsers
|
||||
\d "AspNetUsers"
|
||||
\dT "AspNetUsers"
|
||||
update "AspNetUsers" set "LockoutEnable" = false;
|
||||
\d "AspNetUsers"
|
||||
\d "AspNetUsers"
|
||||
update "AspNetUsers" set "LockoutEnabled" = false;
|
||||
commit ;
|
||||
\quit
|
||||
update "AspNetUsers" set "LockoutEnabled" = true;
|
||||
\s
|
||||
\d
|
||||
\dT
|
||||
\?
|
||||
\dn
|
||||
\?
|
||||
\?
|
||||
\conninfo
|
||||
\h create database
|
||||
\h create user
|
||||
create user forgejo with login 'ogVZ)f#m85zx';
|
||||
create user forgejo with login;
|
||||
\h alter user
|
||||
alter user forgejo with PASSWORD 'ogVZ)f#m85zx';
|
||||
commit:
|
||||
commit;
|
||||
commit;
|
||||
\h create databse
|
||||
\h create databse
|
||||
create database forgejo with owner forgejo;
|
||||
create user woodpecker with password 'aormb%$98zv<U&@' ;'
|
||||
\sd
|
||||
\?d
|
||||
\dd
|
||||
\dT
|
||||
\dt
|
||||
\d
|
||||
\dd
|
||||
\?
|
||||
\dS
|
||||
\?
|
||||
\dD
|
||||
\?
|
||||
\dg
|
||||
\?
|
||||
\dn
|
||||
\?
|
||||
\l
|
||||
\dl
|
||||
\l
|
||||
\dg
|
||||
create database woodpecker with OWNER 'woodpecker';
|
||||
select count(*) from "Users"
|
||||
;
|
||||
select count(*) from "AspNetUsers";
|
||||
desc "AspNetUsers";
|
||||
\dT "AspNetUsers"
|
||||
\d "AspNetUsers"
|
||||
update "AspNetUsers" set "EmailConfirmed" = true;
|
||||
commit
|
||||
;
|
||||
select "UserName" from "AspNetUsers" ;
|
||||
desc "AspNetUsers"
|
||||
\d "AspNetUsers"
|
||||
select "UserName", "Email" from "AspNetUsers" ;
|
||||
select "UserName", "Email" from "AspNetUsers" ;
|
||||
\d "AspNetUsers"
|
||||
select "Id", "UserName", "Email" from "AspNetUsers" ;
|
||||
\d "AspNetUsers"
|
||||
select "Id", "UserName", "Email", "ConfirmedEmail" from "AspNetUsers" ;
|
||||
\d "AspNetUsers"
|
||||
select "Id", "UserName", "Email", "EmailConfirmed" from "AspNetUsers" ;
|
||||
select * from "AspNetUsers" ;
|
||||
\d "AspNetUsers"
|
||||
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabe" from "AspNetUsers" ;
|
||||
\d "AspNetUsers"
|
||||
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
|
||||
upate AspNetUsers set LockoutEnabled = false;
|
||||
update AspNetUsers set LockoutEnabled = false;
|
||||
update "AspNetUsers" set "LockoutEnabled" = false;
|
||||
commit;
|
||||
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
|
||||
SELECT a."Id", a."AccessFailedCount", a."AllowMonthlyEmail", a."Avatar", a."BankInfoId", a."ConcurrencyStamp", a."DedicatedGoogleCalendar", a."DiskQuota", a."DiskUsage", a."Email", a."EmailConfirmed", a."FullName", a."LockoutEnabled", a."LockoutEnd", a."MaxFileSize", a."NormalizedEmail", a."NormalizedUserName", a."PasswordHash", a."PhoneNumber", a."PhoneNumberConfirmed", a."PostalAddressId", a."SecurityStamp", a."TwoFactorEnabled", a."UserName"
|
||||
FROM "AspNetUsers" AS a
|
||||
WHERE a."Email" = 'paul@pschneider.fr';
|
||||
update "AspNetUsers" set "UserName" = 'Paul' where "Email" = 'paul@pschneider.fr';
|
||||
update "AspNetUsers" set "UserName" = 'PaulS' where "Email" = 'contact@pschneider.fr';
|
||||
update "AspNetUsers" set "UserName" = 'PaulSc' where "Email" = 'redienhcs.luap@gmail.com';
|
||||
delete from Users where "userName" = 'pa'
|
||||
;
|
||||
delete from "Users" where "UserName" = 'pa';
|
||||
delete from "AspNetUsers" where "UserName" = 'pa';
|
||||
select "Id", "UserName", "Email", "EmailConfirmed", "LockoutEnabled" from "AspNetUsers" ;
|
||||
\dT
|
||||
\d
|
||||
alter table "Activity" rename to "Activities";
|
||||
\d
|
||||
alter table "BlogPost" rename to "BlogSpot";
|
||||
\s "BlogSpot"
|
228
src/Yavsc/Controllers/Accounting/ExternalController.cs
Normal file
228
src/Yavsc/Controllers/Accounting/ExternalController.cs
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
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 } });
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
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,22 +1,15 @@
|
||||
|
||||
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 System.Collections;
|
||||
using Yavsc.Server.Exceptions;
|
||||
|
||||
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
@ -29,111 +22,70 @@ namespace Yavsc.Controllers
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
readonly RequestLocalizationOptions _localisationOptions;
|
||||
|
||||
readonly BlogSpotService blogSpotService;
|
||||
public BlogspotController(
|
||||
ApplicationDbContext context,
|
||||
ILoggerFactory loggerFactory,
|
||||
IAuthorizationService authorizationService,
|
||||
IOptions<RequestLocalizationOptions> localisationOptions)
|
||||
IOptions<RequestLocalizationOptions> localisationOptions,
|
||||
BlogSpotService blogSpotService)
|
||||
{
|
||||
_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 UserPosts(id));
|
||||
}
|
||||
IEnumerable<BlogPost> posts;
|
||||
|
||||
if (User.Identity.IsAuthenticated)
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
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)))
|
||||
);
|
||||
return View("UserPosts",
|
||||
await blogSpotService.UserPosts(id, User.GetUserId(),
|
||||
skip, take));
|
||||
}
|
||||
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);
|
||||
IEnumerable<IBlogPost> index = await this.blogSpotService.Index(User, id, skip, take);
|
||||
return View(index);
|
||||
}
|
||||
|
||||
[Route("~/Title/{id?}")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Title(string id)
|
||||
{
|
||||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
ViewData["Title"] = id;
|
||||
return View("Title", _context.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Where(x => x.Title == id && (x.AuthorId == uid )).OrderByDescending(
|
||||
x => x.DateCreated
|
||||
).ToList());
|
||||
return View("Title", blogSpotService.GetTitle(id));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
string posterId = (await _context.Users.SingleOrDefaultAsync(u=>u.UserName == userName))?.Id ?? null ;
|
||||
return _context.UserPosts(posterId, User.Identity.Name);
|
||||
return await blogSpotService.UserPosts(userName, User.GetUserId(), pageLen, pageNum);
|
||||
|
||||
}
|
||||
// GET: Blog/Details/5
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Details(long? id)
|
||||
{
|
||||
if (id == null)
|
||||
if (id == null) return this.NotFound();
|
||||
try
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
var blog = await blogSpotService.Details(User, id.Value);
|
||||
ViewData["apicmtctlr"] = "/api/blogcomments";
|
||||
ViewData["moderatoFlag"] = User.IsInRole(Constants.BlogModeratorGroupName);
|
||||
|
||||
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 View(blog);
|
||||
|
||||
}
|
||||
catch (AuthorizationFailureException ex)
|
||||
{
|
||||
return NotFound();
|
||||
return Challenge();
|
||||
}
|
||||
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 }
|
||||
);
|
||||
@ -143,33 +95,25 @@ namespace Yavsc.Controllers
|
||||
[Authorize()]
|
||||
public IActionResult Create(string title)
|
||||
{
|
||||
var result = new BlogPostInputViewModel{Title=title
|
||||
var result = new BlogPostCreateViewModel
|
||||
{
|
||||
Title = title
|
||||
};
|
||||
ViewData["PostTarget"]="Create";
|
||||
SetLangItems();
|
||||
return View(result);
|
||||
}
|
||||
|
||||
// POST: Blog/Create
|
||||
[HttpPost, Authorize, ValidateAntiForgeryToken]
|
||||
public IActionResult Create(BlogPostInputViewModel blogInput)
|
||||
public IActionResult Create(BlogPostEditViewModel blogInput)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
BlogPost post = new BlogPost
|
||||
{
|
||||
Title = blogInput.Title,
|
||||
Content = blogInput.Content,
|
||||
Photo = blogInput.Photo,
|
||||
AuthorId = User.GetUserId()
|
||||
};
|
||||
_context.BlogSpot.Add(post);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
BlogPost post = blogSpotService.Create(User.GetUserId(),
|
||||
BlogPostEditViewModel.FromViewModel(blogInput));
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
ModelState.AddModelError("Unknown","Invalid Blog posted ...");
|
||||
ViewData["PostTarget"]="Create";
|
||||
return View("Edit",blogInput);
|
||||
return View("Edit", blogInput);
|
||||
}
|
||||
|
||||
[Authorize()]
|
||||
@ -180,37 +124,18 @@ namespace Yavsc.Controllers
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
ViewData["PostTarget"]="Edit";
|
||||
BlogPost blog = _context.BlogSpot.Include(x => x.Author).Include(x => x.ACL).Single(m => m.Id == id);
|
||||
|
||||
if (blog == null)
|
||||
try
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
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
|
||||
var blog = await blogSpotService.GetPostForEdition(User, id.Value);
|
||||
if (blog == null)
|
||||
{
|
||||
Id = blog.Id,
|
||||
Title = blog.Title,
|
||||
Content = blog.Content,
|
||||
ACL = blog.ACL,
|
||||
Photo = blog.Photo
|
||||
});
|
||||
return NotFound();
|
||||
}
|
||||
SetLangItems();
|
||||
return View(blog);
|
||||
|
||||
}
|
||||
else
|
||||
catch (AuthorizationFailureException)
|
||||
{
|
||||
return new ChallengeResult();
|
||||
}
|
||||
@ -218,65 +143,41 @@ namespace Yavsc.Controllers
|
||||
|
||||
// POST: Blog/Edit/5
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken,Authorize()]
|
||||
[ValidateAntiForgeryToken, Authorize()]
|
||||
public async Task<IActionResult> Edit(BlogPostEditViewModel blogEdit)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
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());
|
||||
await blogSpotService.Modify(User, blogEdit);
|
||||
ViewData["StatusMessage"] = "Post modified";
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
ViewData["PostTarget"]="Edit";
|
||||
return View(blogEdit);
|
||||
}
|
||||
|
||||
// GET: Blog/Delete/5
|
||||
[ActionName("Delete"),Authorize()]
|
||||
public IActionResult Delete(long? id)
|
||||
[ActionName("Delete"), Authorize()]
|
||||
public async Task<IActionResult> Delete(long? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
BlogPost blog = _context.BlogSpot.Include(
|
||||
b => b.Author
|
||||
).Single(m => m.Id == id);
|
||||
var blog = await blogSpotService.GetBlogPostAsync(id.Value);
|
||||
if (blog == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(blog);
|
||||
}
|
||||
|
||||
// POST: Blog/Delete/5
|
||||
[HttpPost, ActionName("Delete"), Authorize("IsTheAuthor")]
|
||||
[HttpPost, ActionName("Delete"), Authorize("TheAuthor")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public IActionResult DeleteConfirmed(long id)
|
||||
public async Task<IActionResult> DeleteConfirmed(long id)
|
||||
{
|
||||
var uid = User.GetUserId();
|
||||
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
|
||||
|
||||
_context.BlogSpot.Remove(blog);
|
||||
_context.SaveChanges(User.GetUserId());
|
||||
|
||||
await blogSpotService.Delete(User, id);
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Yavsc.Helpers;
|
||||
using Yavsc.Models;
|
||||
using Yavsc.Models.Messaging;
|
||||
|
@ -25,6 +25,7 @@ namespace Yavsc.Controllers
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Yavsc.Interface;
|
||||
using Yavsc.Settings;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
|
||||
public class HairCutCommandController : CommandController
|
||||
{
|
||||
|
@ -48,9 +48,6 @@ namespace Yavsc.Controllers
|
||||
);
|
||||
if (notes.Any()) this.Notify(notes);
|
||||
|
||||
ViewData["HaircutCommandCount"] = _dbContext.HairCutQueries.Where(
|
||||
q => q.ClientId == uid && q.Status < QueryStatus.Failed
|
||||
).Count();
|
||||
var toShow = _dbContext.Activities
|
||||
.Include(a => a.Forms)
|
||||
.Include(a => a.Parent)
|
||||
|
@ -32,13 +32,331 @@ using Yavsc.ViewModels.Auth;
|
||||
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
|
||||
{
|
||||
#region files config
|
||||
|
||||
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)
|
||||
{
|
||||
//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)
|
||||
// .AddProfileService<ProfileService>()
|
||||
.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.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());
|
||||
}
|
||||
}
|
||||
|
||||
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
|
||||
bool enableDirectoryBrowsing = false)
|
||||
{
|
||||
@ -90,320 +408,5 @@ 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"];
|
||||
Debug.Assert(path != null);
|
||||
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,7 +1,9 @@
|
||||
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;
|
||||
@ -32,6 +34,10 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else if (context.User.IsInRole("Administrator"))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
else if (requirement is EditPermission || requirement is DeletePermission)
|
||||
{
|
||||
@ -49,18 +55,33 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
if (resource is BlogPost blogPost)
|
||||
{
|
||||
if (blogPost.ACL.Count==0)
|
||||
return true;
|
||||
return
|
||||
applicationDbContext.blogSpotPublications
|
||||
.Any(p=>p.BlogpostId == blogPost.Id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsOwner(ClaimsPrincipal user, object? resource)
|
||||
private 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;
|
||||
}
|
||||
|
||||
@ -70,7 +91,7 @@ public class PermissionHandler : IAuthorizationHandler
|
||||
{
|
||||
return applicationDbContext.CircleMembers
|
||||
.Include(c => c.Circle)
|
||||
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.OwnerId)
|
||||
.Where(m=>m.MemberId==user.GetUserId() && m.Circle.OwnerId == blogPost.AuthorId)
|
||||
.Any();
|
||||
}
|
||||
return true;
|
||||
|
@ -70,6 +70,11 @@ namespace Yavsc.Helpers
|
||||
{
|
||||
switch (elt.GetType().FullName)
|
||||
{
|
||||
case "AsciiDocNet.Monospace":
|
||||
sb.AppendHtml("<code>");
|
||||
Monospace mono = (Monospace)elt;
|
||||
AllItemsToHtml(sb, mono);
|
||||
break;
|
||||
case "AsciiDocNet.Link":
|
||||
Link link = (Link)elt;
|
||||
Uri uri;
|
||||
@ -98,11 +103,8 @@ namespace Yavsc.Helpers
|
||||
|
||||
case "AsciiDocNet.Strong":
|
||||
sb.AppendHtml("<b>");
|
||||
AsciiDocNet.Strong str = (Strong)elt;
|
||||
foreach (var stritem in str)
|
||||
{
|
||||
stritem.ToHtml(sb);
|
||||
}
|
||||
Strong str = (Strong)elt;
|
||||
AllItemsToHtml(sb, str);
|
||||
sb.AppendHtml("</b>");
|
||||
break;
|
||||
case "AsciiDocNet.InternalAnchor":
|
||||
@ -138,10 +140,35 @@ namespace Yavsc.Helpers
|
||||
|
||||
default:
|
||||
string unsupportedType = elt.GetType().FullName;
|
||||
throw new InvalidProgramException(unsupportedType);
|
||||
if (elt is InlineContainer inlineContainer)
|
||||
{
|
||||
sb.AppendHtml($"<span title=\"E NOT SUPPORTED : {unsupportedType}\">");
|
||||
AllItemsToHtml(sb, inlineContainer);
|
||||
sb.AppendHtml("</span>");
|
||||
}
|
||||
else if (elt is IInlineElement inlineElement)
|
||||
{
|
||||
sb.AppendHtml($"<span title=\"E NOT SUPPORTED : {unsupportedType}\">");
|
||||
RenderLitteral(inlineElement, sb);
|
||||
sb.AppendHtml("</span>");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidProgramException(unsupportedType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AllItemsToHtml(IHtmlContentBuilder sb, InlineContainer mono)
|
||||
{
|
||||
foreach (var item in mono)
|
||||
{
|
||||
item.ToHtml(sb);
|
||||
}
|
||||
sb.AppendHtml("</code>");
|
||||
}
|
||||
|
||||
private static void RenderLitteral(IInlineElement elt, IHtmlContentBuilder sb)
|
||||
{
|
||||
var tl = elt as TextLiteral;
|
||||
@ -173,39 +200,39 @@ namespace Yavsc.Helpers
|
||||
return contentbuilder;
|
||||
}
|
||||
|
||||
/*
|
||||
public static IHtmlContent AsciiDocFor<TModel>(this IHtmlHelper<TModel> html,
|
||||
Expression<Func<TModel, string>> expression)
|
||||
{
|
||||
string ascii = html.ValueFor<string>(expression, "{0}");
|
||||
if (string.IsNullOrWhiteSpace(ascii))
|
||||
return new HtmlString(string.Empty);
|
||||
Document document = Document.Parse(ascii);
|
||||
var htmlDoc = document.ToHtml();
|
||||
var span = new TagBuilder("p") { TagRenderMode = TagRenderMode.SelfClosing };
|
||||
span.InnerHtml.AppendHtml(htmlDoc);
|
||||
return span.RenderBody();
|
||||
}
|
||||
/*
|
||||
public static IHtmlContent AsciiDocFor<TModel>(this IHtmlHelper<TModel> html,
|
||||
Expression<Func<TModel, string>> expression)
|
||||
{
|
||||
string ascii = html.ValueFor<string>(expression, "{0}");
|
||||
if (string.IsNullOrWhiteSpace(ascii))
|
||||
return new HtmlString(string.Empty);
|
||||
Document document = Document.Parse(ascii);
|
||||
var htmlDoc = document.ToHtml();
|
||||
var span = new TagBuilder("p") { TagRenderMode = TagRenderMode.SelfClosing };
|
||||
span.InnerHtml.AppendHtml(htmlDoc);
|
||||
return span.RenderBody();
|
||||
}
|
||||
|
||||
public static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text)
|
||||
{
|
||||
return AsciiDoc(htmlHelper, text, null);
|
||||
}
|
||||
public static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text)
|
||||
{
|
||||
return AsciiDoc(htmlHelper, text, null);
|
||||
}
|
||||
|
||||
private static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text, object htmlAttributes)
|
||||
{
|
||||
// Create tag builder
|
||||
var builder = new TagBuilder("div");
|
||||
var document = Document.Parse(text);
|
||||
private static string AsciiDoc(IHtmlHelper<BlogPost> htmlHelper, string text, object htmlAttributes)
|
||||
{
|
||||
// Create tag builder
|
||||
var builder = new TagBuilder("div");
|
||||
var document = Document.Parse(text);
|
||||
|
||||
// builder.InnerHtml = .
|
||||
// builder.InnerHtml = .
|
||||
|
||||
// Add attributes
|
||||
builder.MergeAttribute("class", "ascii");
|
||||
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
|
||||
// Add attributes
|
||||
builder.MergeAttribute("class", "ascii");
|
||||
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
|
||||
|
||||
// Render tag
|
||||
return builder.ToString();
|
||||
} */
|
||||
// Render tag
|
||||
return builder.ToString();
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,50 @@
|
||||
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;
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Yavsc.Models.Messaging;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
|
||||
namespace Yavsc.Helpers
|
||||
{
|
||||
|
@ -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.IsExpired(c)) {
|
||||
if (token.IsStale) {
|
||||
token = await RefreshToken(googleAuthSettings, token);
|
||||
}
|
||||
return new UserCredential(flow, googleUserLoginKey, token);
|
||||
|
@ -1,30 +1,33 @@
|
||||
DESTDIR=/srv/www/yavsc
|
||||
HOSTING=localhost
|
||||
ASPNET_LOG_LEVEL=debug
|
||||
SOURCE_DIR=../..
|
||||
USER=www-data
|
||||
HOSTING_PRE=yavsv.pschneider.fr
|
||||
CONFIGURATION=Debug
|
||||
SERVICE_PRE=Yavsc
|
||||
CONFIGURATION=Release
|
||||
USER_AND_GROUP=www-data:www-data
|
||||
SERVICE_PROD=yavsc
|
||||
DOTNET_FRAMEWORK=net9.0
|
||||
|
||||
all:
|
||||
dotnet build
|
||||
|
||||
showConfig:
|
||||
@echo HOSTING_PRE: $(USER)@$(HOSTING_PRE)
|
||||
@echo CONFIGURATION: $(CONFIGURATION)
|
||||
@echo DESTDIR: $(DESTDIR)
|
||||
@echo SERVICE_PRE: $(SERVICE_PRE)
|
||||
@echo SERVICE_PROD: $(SERVICE_PROD)
|
||||
|
||||
publish:
|
||||
ASPNETCORE_ENV=$(CONFIGURATION) dotnet publish
|
||||
|
||||
pushInPre: publish
|
||||
sudo service $(SERVICE_PRE) stop
|
||||
sudo cp -a bin/Debug/net7.0/publish/* $(DESTDIR)
|
||||
sudo chown -R $(USER) $(DESTDIR)
|
||||
install_service:
|
||||
sudo cp ../../contrib/yavsc.service /etc/systemd/system
|
||||
sudo systemctl enable yavsc
|
||||
|
||||
pushInProd: publish
|
||||
sudo systemctl stop $(SERVICE_PROD)
|
||||
sudo cp -a bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish/* $(DESTDIR)
|
||||
sudo chown -R $(USER_AND_GROUP) $(DESTDIR)
|
||||
sudo sync
|
||||
sudo service $(SERVICE_PRE) start
|
||||
sudo systemctl start $(SERVICE_PROD)
|
||||
|
||||
%.css: %.scss
|
||||
scss $^ > $@
|
||||
|
||||
%.min.js: %.js
|
||||
jsmin < $^ > $@
|
||||
@ -32,5 +35,4 @@ pushInPre: publish
|
||||
%.min.css: %.css
|
||||
jsmin < $^ > $@
|
||||
|
||||
%.Designer.cs: %.resx
|
||||
strongresbuildercli -l -p -t -r "Yavsc.Resources." $^
|
||||
css: wwwroot/css/site.css
|
||||
|
@ -6,7 +6,7 @@ namespace Yavsc
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
public static async Task 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 = builder.ConfigureWebAppServices().ConfigurePipeline();
|
||||
var app = await builder.ConfigureWebAppServices().ConfigurePipeline();
|
||||
app.UseSession();
|
||||
app.Run();
|
||||
}
|
||||
|
28
src/Yavsc/Services/ExternalIdentityManager.cs
Normal file
28
src/Yavsc/Services/ExternalIdentityManager.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Models;
|
||||
|
||||
public class ExternalIdentityManager : IExternalIdentityManager
|
||||
{
|
||||
private ApplicationDbContext _applicationDbContext;
|
||||
|
||||
public ExternalIdentityManager(ApplicationDbContext applicationDbContext)
|
||||
{
|
||||
_applicationDbContext = applicationDbContext;
|
||||
}
|
||||
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.AspNetUserLogins
|
||||
.FirstOrDefaultAsync(
|
||||
i => (i.LoginProvider == provider) && (i.ProviderKey == providerUserId)
|
||||
);
|
||||
if (user == null) return null;
|
||||
return await _applicationDbContext.Users.FirstOrDefaultAsync(u=>u.Id == user.UserId);
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
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.OwnerId;
|
||||
var oid = target.AuthorId;
|
||||
ViewBag.ACL = dbContext.Circle.Where(
|
||||
c=>c.OwnerId == oid)
|
||||
.Select(
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel
|
||||
@model BlogPostEditViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Blog post edition";
|
||||
@ -47,6 +47,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mdcoding">
|
||||
<label asp-for="Content" class="col-md-2 control-label" ></label>
|
||||
<div class="col-md-10">
|
||||
@ -56,6 +57,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ACL" class="col-md-2 control-label"></label>
|
||||
<div class="col-md-10">
|
||||
@ -63,6 +65,13 @@
|
||||
</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,10 +60,14 @@ $('#commentValidation').html(
|
||||
}
|
||||
</style>
|
||||
}
|
||||
<div class="container">
|
||||
<div class="blogpost">
|
||||
<h1 class="blogtitle" ismarkdown>@Model.Title</h1>
|
||||
<img class="blogphoto" alt="" src="@Model.Photo" >
|
||||
|
||||
<div class="post">
|
||||
<div class="float-left">
|
||||
<img alt="" src="@Model.Photo" >
|
||||
</div>
|
||||
|
||||
<h1 ismarkdown>@Model.Title</h1>
|
||||
|
||||
@Html.DisplayFor(m=>m.Author)
|
||||
<asciidoc>@Html.DisplayFor(m=>m.Content)</asciidoc>
|
||||
|
||||
@ -98,4 +102,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 edition </h2>
|
||||
<h2 >Blog post</h2>
|
||||
<label><input type="checkbox" id="vcbtn" />Editer le code source Markdown</label>
|
||||
|
||||
<div asp-validation-summary="All" class="text-danger"></div>
|
||||
@ -97,6 +97,13 @@
|
||||
</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" />
|
||||
@ -111,5 +118,3 @@
|
||||
<div>
|
||||
<a asp-action="Index">Back to List</a>
|
||||
</div>
|
||||
|
||||
using Yavsc.Migrations;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@model IEnumerable<IGrouping<string,BlogPost>>
|
||||
@model IEnumerable<IBlogPost>
|
||||
@{
|
||||
ViewData["Title"] = "Blogs, l'index";
|
||||
}
|
||||
@ -43,58 +43,51 @@
|
||||
<a asp-action="Create">Create a new article</a>
|
||||
</p>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
|
||||
<table class="table">
|
||||
@foreach (var group in Model) {
|
||||
var title = group.Key ?? "@";
|
||||
string secondclass="";
|
||||
var first = group.First();
|
||||
int maxTextLen = 256;
|
||||
<div class="blog">
|
||||
@{
|
||||
int maxTextLen = 75;
|
||||
foreach (var post in Model) {
|
||||
<div class="post">
|
||||
|
||||
|
||||
<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 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>
|
||||
}
|
||||
}
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@if(Model.Count()==0){<p>Néant</p>}
|
||||
|
@ -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-lg">Details</a>
|
||||
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-light">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-default">
|
||||
<a asp-route-id="@act.Code" class="btn btn-light">
|
||||
@foreach (Activity c in act.Children) {
|
||||
@Html.DisplayFor(subact=>c)
|
||||
}
|
||||
@ -80,11 +80,6 @@
|
||||
<li><a asp-controller="Announces" class="badge" >
|
||||
<img src="@SiteSettings.Value.Logo" alt="announces" title="Annonces @SiteSettings.Value.Title" /></a></li>
|
||||
}
|
||||
@if ((int)ViewData["HaircutCommandCount"]>0) {
|
||||
<li><a asp-controller="HairCutCommand" class="badge" >
|
||||
<img src="~/images/shoppingcart.svg" alt="basket" title="Vos bons de commande" />(@ViewData["HaircutCommandCount"])</a></li>
|
||||
}
|
||||
|
||||
}
|
||||
@section header {
|
||||
<script src="~/lib/bootstrap/js/carousel.js" asp-append-version="true"></script>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user