16 Commits

Author SHA1 Message Date
d0d1c652fe make css
Some checks failed
Dotnet build and test / log-the-inputs (push) Successful in 9s
Dotnet build and test / build (push) Failing after 1m50s
2025-07-09 13:25:21 +01:00
0a1bef37fe Blog post create 2025-07-09 13:16:01 +01:00
2a825da32e MEF 2025-07-09 11:17:16 +01:00
e6f8947c08 misc
Some checks failed
Dotnet build and test / log-the-inputs (push) Successful in 9s
Dotnet build and test / build (push) Failing after 1m33s
2025-07-07 07:49:18 +01:00
15d35e5508 WIP allow blog comment 2025-07-05 13:21:50 +01:00
3f1bfc1c3c fixies the refact of blog spot index
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 5s
Dotnet build and test / build (push) Successful in 1m58s
2025-06-29 19:53:56 +01:00
fdf75934e5 fixes backend accept 2025-06-29 19:53:19 +01:00
f603d87b33 db update 2025-06-29 18:55:52 +01:00
bebca989d0 refact
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 4s
Dotnet build and test / build (push) Successful in 2m30s
2025-06-29 18:44:35 +01:00
531797d348 refact
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 4s
Dotnet build and test / build (push) Successful in 1m50s
2025-06-29 16:20:37 +01:00
2002b8b232 refactoring
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 7s
Dotnet build and test / build (push) Successful in 1m48s
2025-06-29 16:12:16 +01:00
0e0a79c6cd a web resource authorisation 2025-06-29 11:53:25 +01:00
0f52a875de Migrate the db at startup 2025-06-29 11:52:57 +01:00
70771e5ab5 Implémentation de la publication d'un billet
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 10s
Dotnet build and test / build (push) Successful in 2m0s
2025-06-28 16:14:52 +01:00
447d926ca6 Brusher Profile and Blog delete permisssion 2025-06-28 14:54:44 +01:00
b4870a1814 migration net9.0
All checks were successful
Dotnet build and test / log-the-inputs (push) Successful in 6s
Dotnet build and test / build (push) Successful in 1m47s
2025-06-16 02:30:32 +01:00
1438 changed files with 241090 additions and 33662 deletions

View File

@ -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

View File

@ -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
View File

@ -7,6 +7,7 @@
.paket/
.vs/
.sass-cache/
.private/
/out
bin

28
.vscode/launch.json vendored
View File

@ -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,

6
.vscode/tasks.json vendored
View File

@ -9,8 +9,12 @@
"args": [
"build",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
"/consoleloggerparameters:NoSummary;ForceNoAlign",
],
"group": "build",
"isBuildCommand": true,
"isTestCommand": false,
"problemMatcher": "$msCompile"
},
{

View File

@ -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
View 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

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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; }
}
}

View 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; }
}
}

View File

@ -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") ;

View File

@ -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();
}
}
}

View File

@ -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");

View File

@ -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() });
}

View File

@ -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

View File

@ -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");
}

View File

@ -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();
}
;
}
}

View File

@ -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; }
}
}

View File

@ -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";
}
}

View File

@ -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

View File

@ -54,7 +54,7 @@ namespace Yavsc.Models.Google.Messaging
/// <summary>
/// The error.
/// </summary>
public string error;
public string? error;
}
/// <summary>

View File

@ -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; }
}
}

View File

@ -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();

View File

@ -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; }
}
}

View File

@ -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()
{

View File

@ -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.

View File

@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "9.0.6",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}

View File

@ -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" },
},
};

View 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)
{
}
}

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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)
{
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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");
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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)
{
}
}
}

File diff suppressed because it is too large Load Diff

View 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");
}
}
}

View File

@ -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)");
@ -725,22 +776,20 @@ namespace Yavsc.Migrations
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<bool>("Publish")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(1024)
.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 +862,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 +1138,6 @@ namespace Yavsc.Migrations
.HasColumnType("numeric");
b.Property<string>("ScheduleOwnerId")
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("ShampooPrice")
@ -1602,61 +1660,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 +2095,6 @@ namespace Yavsc.Migrations
.HasColumnType("boolean");
b.Property<string>("ModeratorGroupName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
@ -2103,22 +2105,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 +2778,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 +2860,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 +3064,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 +3395,7 @@ namespace Yavsc.Migrations
modelBuilder.Entity("Yavsc.Models.ApplicationUser", b =>
{
b.Navigation("AccountBalance")
.IsRequired();
b.Navigation("AccountBalance");
b.Navigation("BankInfo");

View File

@ -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; }
}
}

View File

@ -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,8 @@ namespace Yavsc.Models
using Yavsc.Server.Models.Calendar;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Yavsc.Abstract.Models.Messaging;
using Org.BouncyCastle.Asn1.Crmf;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
@ -50,7 +46,7 @@ namespace Yavsc.Models
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
@ -60,7 +56,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 +76,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 +84,23 @@ namespace Yavsc.Models
et.FindProperty("DateCreated").SetAfterSaveBehavior(Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore);
}
builder.Entity<Activity>().Property(a=>a.ParentCode).IsRequired(false);
builder.Entity<Activity>().Property(a => a.ParentCode).IsRequired(false);
//builder.Entity<BlogPost>().HasOne(p => p.Author).WithMany(a => a.Posts);
}
// this is not a failback procedure.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var appSetup = (string) AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
if (!string.IsNullOrWhiteSpace(appSetup))
var appSetup = (string)AppDomain.CurrentDomain.GetData(Constants.YavscConnectionStringEnvName);
if (!string.IsNullOrWhiteSpace(appSetup))
{
optionsBuilder.UseNpgsql(appSetup);
return;
}
var envSetup = Environment.GetEnvironmentVariable(Constants.YavscConnectionStringEnvName);
if (envSetup!=null)
if (envSetup != null)
optionsBuilder.UseNpgsql(envSetup);
else optionsBuilder.UseNpgsql();
}
@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View 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; }
}
}

View File

@ -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}")]

View File

@ -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

View File

@ -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;
}

View File

@ -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; }
}

View 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();
}
}

View 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<IGrouping<string, IBlogPost>>> IndexByTitle(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.DateCreated);
var grouped = data.GroupBy(p => p.Title).Skip(skip).Take(take);
return grouped;
}
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? ByTitle(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);
}
}

View File

@ -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))

View File

@ -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;

View File

@ -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);
}

View File

@ -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";

View File

@ -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; }
}

View File

@ -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
};
}
}

View File

@ -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
View 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"

View File

@ -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<IGrouping<string,IBlogPost>> byTitle = await this.blogSpotService.IndexByTitle(User, id, skip, take);
return View(byTitle);
}
[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.ByTitle(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");
}
}

View File

@ -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;

View File

@ -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
{

View File

@ -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)

View File

@ -32,13 +32,17 @@ 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;
namespace Yavsc.Extensions;
public static class HostingExtensions
{
#region files config
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
bool enableDirectoryBrowsing = false)
{
@ -90,16 +94,10 @@ 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>()
@ -147,7 +145,8 @@ public static class HostingExtensions
.AddTransient<IYavscMessageSender, YavscMessageSender>()
.AddTransient<IBillingService, BillingService>()
.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false))
.AddTransient<ICalendarManager, CalendarManager>();
.AddTransient<ICalendarManager, CalendarManager>()
.AddTransient<BlogSpotService>();
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
@ -196,11 +195,13 @@ public static class HostingExtensions
{
policy
.RequireAuthenticatedUser()
.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Performer");
.RequireClaim(JwtClaimTypes.Role, "Performer");
});
options.AddPolicy("AdministratorOnly", policy =>
{
_ = policy.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Constants.AdminGroupName);
_ = policy
.RequireAuthenticatedUser()
.RequireClaim(JwtClaimTypes.Role, Constants.AdminGroupName);
});
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
@ -208,7 +209,7 @@ public static class HostingExtensions
// 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()));
options.AddPolicy("TheAuthor", policy => policy.Requirements.Add(new EditPermission()));
})
.AddCors(options =>
{
@ -289,12 +290,13 @@ public static class HostingExtensions
// 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>()
.AddAspNetIdentity<ApplicationUser>()
;
if (builder.Environment.IsDevelopment())
{
@ -304,15 +306,16 @@ public static class HostingExtensions
{
var path = builder.Configuration["SigningCert:Path"];
var pass = builder.Configuration["SigningCert:Password"];
Debug.Assert(path != null);
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 }
};
{
CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
};
identityServerBuilder.AddSigningCredential(signingCredentials);
}
return identityServerBuilder;
@ -353,7 +356,7 @@ public static class HostingExtensions
}
internal static WebApplication ConfigurePipeline(this WebApplication app)
internal async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
{
if (app.Environment.IsDevelopment())
@ -363,6 +366,11 @@ public static class HostingExtensions
else
{
app.UseExceptionHandler("/Home/Error");
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
}
app.UseStaticFiles();
@ -371,7 +379,7 @@ public static class HostingExtensions
app.UseAuthorization();
app.UseCors("default");
app.MapDefaultControllerRoute();
//pp.MapRazorPages();
//app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
WorkflowHelpers.ConfigureBillingService();
@ -407,3 +415,86 @@ public static class HostingExtensions
}
}
}
public class MyIdentityStore : IUserClaimStore<IdentityUser>
{
public Task AddClaimsAsync(IdentityUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> CreateAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> DeleteAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public void Dispose()
{
throw new NotImplementedException();
}
public Task<IdentityUser?> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityUser?> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IList<Claim>> GetClaimsAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string?> GetNormalizedUserNameAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetUserIdAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string?> GetUserNameAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IList<IdentityUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task RemoveClaimsAsync(IdentityUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task ReplaceClaimAsync(IdentityUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetNormalizedUserNameAsync(IdentityUser user, string? normalizedName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetUserNameAsync(IdentityUser user, string? userName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> UpdateAsync(IdentityUser user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

View File

@ -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;

View File

@ -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();
} */
}
}

View File

@ -6,9 +6,9 @@ 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"))
if (context.AllAttributes.ContainsName("summary"))
{
var summaryLength = context.AllAttributes["summary"].Value;
}
@ -16,12 +16,23 @@ namespace Yavsc.Helpers
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
{
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");
}
}
}
}

View File

@ -1,6 +1,6 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Yavsc.Models.Messaging;
using Yavsc.Abstract.Models.Messaging;
namespace Yavsc.Helpers
{

View File

@ -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)
sudo sync
sudo service $(SERVICE_PRE) start
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 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

View File

@ -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();
}

View File

@ -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;

View File

@ -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(

View File

@ -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>

View File

@ -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;

View File

@ -1,4 +1,4 @@
@model IEnumerable<IGrouping<string,BlogPost>>
@model IEnumerable<IGrouping<string,IBlogPost>>
@{
ViewData["Title"] = "Blogs, l'index";
}
@ -47,6 +47,7 @@
<div class="container">
<table class="table">
@foreach (var group in Model) {
var title = group.Key ?? "@";
string secondclass="";
@ -95,6 +96,6 @@
}
</table>
@if(Model.Count()==0){<p>Néant</p>}
</div>

View File

@ -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>

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Create";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Delete";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Details";

View File

@ -1,4 +1,4 @@
@model Yavsc.Models.Messaging.Notification
@model Notification
@{
ViewData["Title"] = "Edit";

View File

@ -1,4 +1,4 @@
@model IEnumerable<Yavsc.Models.Messaging.Notification>
@model IEnumerable<Notification>
@{
ViewData["Title"] = "Index";

View File

@ -1,14 +1,10 @@
@using Yavsc.Abstract.Identity
@model ApplicationUser
@{
var avuri = "/Avatars/"+Model.UserName+".s.png";
var userPosted = Model.Posts!=null && Model.Posts.Count()>=1;
var avuri = "/Avatars/" + Model.UserName + ".s.png";
}
<div class="userinfo">
@if (userPosted) { <a asp-controller="Blogspot" asp-action="Index"
asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName"/>
</a>
} else {
Html.DisplayFor(m=>m.UserName);
}
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
</a>
</div>

View File

@ -0,0 +1,10 @@
@using Yavsc.Abstract.Identity
@model IApplicationUser
@{
var avuri = "/Avatars/" + Model.UserName + ".s.png";
}
<div class="userinfo">
<a title="Posts" asp-controller="Blogspot" asp-action="Index" asp-route-id="@Model.UserName" class="btn btn-primary">
<img src="@avuri" asp-append-version="true" class="smalltofhol" alt="@Model.UserName" title="@Model.UserName" />
</a>
</div>

View File

@ -16,7 +16,10 @@
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("header", false)
</head>
<body>
<body style="background-image: url('@Config.SiteSetup.Banner');
background-position: 0%;
background-attachment: fixed;
">
<partial name="_Nav" />
@RenderSection("ctxmenu", required: false)
@if (ViewData["Notify"] != null)

View File

@ -18,7 +18,6 @@
<ul class="dropdown-menu" aria-labelledby="dropdown04">
<li><a class="dropdown-item" asp-controller="Bug" asp-action="Index">Bugs</a></li>
<li><a class="dropdown-item" asp-controller="HyperLink" asp-action="Index">HyperLink</a></li>
<li><a class="dropdown-item" asp-controller="LiveFlow" asp-action="Index">LiveFlow</a></li>
<li><a class="dropdown-item" asp-controller="Feature" asp-action="Index">Features</a></li>
</ul>
</li>

Some files were not shown because too many files have changed in this diff Show More