1 Commits

Author SHA1 Message Date
12cbc754cd App B context belongs to app
Some checks failed
Dotnet build and test / log-the-inputs (push) Failing after 1s
Dotnet build and test / build (push) Failing after 1s
2025-07-15 19:43:41 +01:00
492 changed files with 320453 additions and 8572 deletions

18
.vscode/launch.json vendored
View File

@ -4,18 +4,6 @@
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "cli .NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/cli/bin/Debug/net9.0/cli.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "internalConsole"
},
{
"name": "C#: sampleWebAsWebApiClient Debug",
"type": "dotnet",
@ -27,9 +15,9 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net9.0/Yavsc.dll",
"program": "${workspaceFolder}/bin/Debug/<target-framework>/<project-name.dll>",
"args": [],
"cwd": "${workspaceFolder}/src/Yavsc",
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"serverReadyAction": {
"action": "openExternally",
@ -132,7 +120,7 @@
"name": "web core",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net9.0/Yavsc.dll",
"program": "${workspaceFolder}/src/Yavsc/bin/Debug/net8.0/Yavsc.dll",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},

7
.vscode/tasks.json vendored
View File

@ -8,11 +8,14 @@
"type": "process",
"args": [
"build",
"/property:GenerateFullPaths=true"
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign",
],
"group": "build",
"isBuildCommand": true,
"isTestCommand": false
"isTestCommand": false,
"problemMatcher": "$msCompile"
},
{
"label": "build-web",

View File

@ -3,20 +3,15 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="IdentityModel.OidcClient" Version="6.0.0" />
<PackageVersion Include="AsciiDocNet" Version="1.0.0" />
<PackageVersion Include="bootstrap" Version="5.3.7" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3746" />
<PackageVersion Include="Google.Apis.Compute.v1" Version="1.70.0.3871" />
<PackageVersion Include="Google.Apis.Compute.v1" Version="1.70.0.3829" />
<PackageVersion Include="HigginsSoft.IdentityServer8" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.Storage" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.EntityFramework.Storage" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.EntityFramework" Version="8.0.5-preview-net9" />
<PackageVersion Include="HigginsSoft.IdentityServer8.Security" Version="8.0.5-preview-net9" />
<PackageVersion Include="IdentityModel.AspNetCore" Version="4.3.0" />
<PackageVersion Include="MailKit" Version="4.8.0" />
<PackageVersion Include="MailKit" Version="4.13.0" />
<PackageVersion Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
@ -27,29 +22,24 @@
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Razor" Version="2.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.StaticFiles" Version="2.3.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.7" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageVersion Include="Microsoft.Playwright" Version="1.53.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
<PackageVersion Include="MimeKit" Version="4.8.0" />
<PackageVersion Include="MimeKit" Version="4.13.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageVersion Include="PayPalMerchantSDK" Version="2.16.250" />
<PackageVersion Include="pazof.rules" Version="1.1.3" />
<PackageVersion Include="popper.js" Version="1.16.1" />
<PackageVersion Include="RazorEngine.NetCore" Version="3.1.0" />
<PackageVersion Include="Selenium.WebDriver" Version="4.34.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.10" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="9.0.3" />

View File

@ -3,9 +3,6 @@ CONFIG=Debug
FRAMEWORK=net8.0
DESTDIR=/tmp/yavsc
all:
@dotnet build --nologo 2>/dev/null |grep error
clean:
dotnet clean
@ -32,6 +29,7 @@ publish:
dotnet publish src/Yavsc/Yavsc.csproj -c Release -o $(DESTDIR)/srv/www/yavsc
install: publish
sudo chown -R www-data:www-data $(DESTDIR)/srv/www/yavsc
chown -R www-data $(DESTDIR)/srv/www/yavsc
chgrp -R www-data $(DESTDIR)/srv/www/yavsc
.PHONY:

View File

@ -8,7 +8,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Blog;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -6,7 +6,6 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Blog;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -10,7 +10,6 @@ namespace Yavsc.Controllers
using Models;
using Yavsc.Helpers;
using Yavsc.Models.Blog;
using Yavsc.Server.Helpers;
[Produces("application/json")]
[Route("~/api/PostTagsApi")]

View File

@ -8,7 +8,6 @@ namespace Yavsc.Controllers
using Microsoft.EntityFrameworkCore;
using Models.Relationship;
using Yavsc.Helpers;
using Yavsc.Server.Helpers;
[Produces("application/json")]
[Route("api/TagsApi")]

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc.Server.Helpers;
using Yavsc.Api.Helpers;
using Yavsc.Models;
using Yavsc.Models.Workflow;

View File

@ -33,7 +33,7 @@ namespace Yavsc.ApiControllers
public BillingController(
IAuthorizationService authorizationService,
ILoggerFactory loggerFactory,
IStringLocalizer<BillingController> SR,
IStringLocalizer<Yavsc.YavscLocalization> SR,
ApplicationDbContext context,
IOptions<GoogleAuthSettings> googleSettings,
IYavscMessageSender GCMSender,

View File

@ -15,10 +15,9 @@ namespace Yavsc.Controllers
using Yavsc.Abstract.Identity;
using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Server.Helpers;
[Produces("application/json")]
[Route("api/bookquery"), Authorize("Performer")]
[Route("api/bookquery"), Authorize(Roles = "Performer,Administrator")]
public class BookQueryApiController : Controller
{
private ApplicationDbContext _context;

View File

@ -10,7 +10,6 @@ using Newtonsoft.Json;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Billing;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Billing;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -28,7 +28,7 @@ namespace Yavsc.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[Authorize("Performer"),HttpGet("{id}")]
[Authorize(Roles="Performer"),HttpGet("{id}")]
public IActionResult Get(string id)
{
var pfr = dbContext.Performers.Include(

View File

@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Market;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Messaging;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Haircut;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -22,7 +22,6 @@ namespace Yavsc.ApiControllers
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Yavsc.Server.Helpers;
[Route("api/haircut")][Authorize]
public class HairCutController : Controller

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Musical;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Musical;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -8,7 +8,6 @@ using Microsoft.Extensions.Logging;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Identity;
using Yavsc.Server.Helpers;
[Authorize, Route("~/api/gcm")]
public class NativeConfidentialController : Controller

View File

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Access;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Access;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Chat;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
@ -46,7 +45,7 @@ namespace Yavsc.Controllers
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (uid != chatRoomAccess.UserId && uid != chatRoomAccess.Room.OwnerId
&& ! User.IsInMsRole(Constants.AdminGroupName))
&& ! User.IsInRole(Constants.AdminGroupName))
{
ModelState.AddModelError("UserId","get refused");
@ -72,7 +71,7 @@ namespace Yavsc.Controllers
}
var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName );
if (uid != room.OwnerId && ! User.IsInMsRole(Constants.AdminGroupName))
if (uid != room.OwnerId && ! User.IsInRole(Constants.AdminGroupName))
{
ModelState.AddModelError("ChannelName", "access put refused");
return BadRequest(ModelState);
@ -110,7 +109,7 @@ namespace Yavsc.Controllers
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName );
if (room == null || (uid != room.OwnerId && ! User.IsInMsRole(Constants.AdminGroupName)))
if (room == null || (uid != room.OwnerId && ! User.IsInRole(Constants.AdminGroupName)))
{
ModelState.AddModelError("ChannelName", "access post refused");
return BadRequest(ModelState);
@ -154,7 +153,7 @@ namespace Yavsc.Controllers
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName );
if (room == null || (uid != room.OwnerId && chatRoomAccess.UserId != uid && ! User.IsInMsRole(Constants.AdminGroupName)))
if (room == null || (uid != room.OwnerId && chatRoomAccess.UserId != uid && ! User.IsInRole(Constants.AdminGroupName)))
{
ModelState.AddModelError("UserId", "access drop refused");
return BadRequest(ModelState);

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Chat;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
@ -137,7 +136,7 @@ namespace Yavsc.Controllers
if (User.GetUserId() != chatRoom.OwnerId )
{
if (!User.IsInMsRole(Constants.AdminGroupName))
if (!User.IsInRole(Constants.AdminGroupName))
return BadRequest(new {error = "OwnerId"});
}

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Relationship;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Abstract.Identity;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Market;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{

View File

@ -8,11 +8,10 @@ using Microsoft.EntityFrameworkCore;
using Yavsc.Abstract.Identity;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
[Produces("application/json"),Authorize("AdministratorOnly")]
[Produces("application/json"),Authorize(Roles="Administrator")]
[Route("api/users")]
public class ApplicationUserApiController : Controller
{

View File

@ -6,7 +6,6 @@ using System.Linq;
using Yavsc.Models;
using Yavsc.Abstract.Identity;
using Yavsc.Helpers;
using Yavsc.Server.Helpers;
namespace Yavsc.ApiControllers.accounting
{
@ -34,7 +33,7 @@ namespace Yavsc.ApiControllers.accounting
public UserInfo[] GetUserHint(string name)
{
return _dbContext.Users.Where(u=>u.UserName.IndexOf(name)>0)
.Select(u=>new UserInfo(u.Id, u.UserName, u.Email, u.Avatar))
.Select(u=>new UserInfo(u.Id, u.UserName, u.Avatar))
.Take(10).ToArray();
}
}

View File

@ -0,0 +1,17 @@
using System.Security.Claims;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Blog;
namespace Yavsc.Api.Helpers
{
public static class UserHelpers
{
public static string? GetUserId(this ClaimsPrincipal user)
{
return user.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
}
}
}

View File

@ -13,7 +13,6 @@
using IdentityModel;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc;
using Yavsc.Helpers;
using Yavsc.Interface;
using Yavsc.Models;
@ -62,7 +61,7 @@ internal class Program
options.IncludeErrorDetails = true;
options.Authority = "https://localhost:5001";
options.TokenValidationParameters =
new() { ValidateAudience = false, RoleClaimType = Constants.RoleClaimType };
new() { ValidateAudience = false, RoleClaimType = JwtClaimTypes.Role };
options.MapInboundClaims = true;
});

View File

@ -0,0 +1,482 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Net;
using System.Text;
using GetUsernameAsyncFunc=System.Func<System.Collections.Generic.IDictionary<string,string>, System.Threading.Tasks.Task<string>>;
using System.IO;
using Newtonsoft.Json;
namespace Yavsc.Authentication
{
public class OAuthenticator
{
public OAuthenticator()
{
}
readonly string clientId;
readonly string clientSecret;
readonly string scope;
readonly Uri authorizeUrl;
readonly Uri accessTokenUrl;
readonly Uri redirectUrl;
readonly GetUsernameAsyncFunc getUsernameAsync;
readonly string requestState;
bool reportedForgery = false;
/// <summary>
/// Gets the client identifier.
/// </summary>
/// <value>The client identifier.</value>
public string ClientId
{
get { return this.clientId; }
}
/// <summary>
/// Gets the client secret.
/// </summary>
/// <value>The client secret.</value>
public string ClientSecret
{
get { return this.clientSecret; }
}
/// <summary>
/// Gets the authorization scope.
/// </summary>
/// <value>The authorization scope.</value>
public string Scope
{
get { return this.scope; }
}
/// <summary>
/// Gets the authorize URL.
/// </summary>
/// <value>The authorize URL.</value>
public Uri AuthorizeUrl
{
get { return this.authorizeUrl; }
}
/// <summary>
/// Gets the access token URL.
/// </summary>
/// <value>The URL used to request access tokens after an authorization code was received.</value>
public Uri AccessTokenUrl
{
get { return this.accessTokenUrl; }
}
/// <summary>
/// Redirect Url
/// </summary>
public Uri RedirectUrl
{
get { return this.redirectUrl; }
}
/// <summary>
/// Initializes a new <see cref="Yavsc.Authentication.YaOAuth2WebAuthenticator"/>
/// that authenticates using implicit granting (token).
/// </summary>
/// <param name='clientId'>
/// Client identifier.
/// </param>
/// <param name='scope'>
/// Authorization scope.
/// </param>
/// <param name='authorizeUrl'>
/// Authorize URL.
/// </param>
/// <param name='redirectUrl'>
/// Redirect URL.
/// </param>
/// <param name='getUsernameAsync'>
/// Method used to fetch the username of an account
/// after it has been successfully authenticated.
/// </param>
public OAuthenticator(string clientId, string scope, Uri authorizeUrl, Uri redirectUrl, GetUsernameAsyncFunc getUsernameAsync = null)
: this(redirectUrl)
{
if (string.IsNullOrEmpty(clientId))
{
throw new ArgumentException("clientId must be provided", "clientId");
}
if (authorizeUrl==null)
throw new ArgumentNullException("authorizeUrl");
this.clientId = clientId;
this.scope = scope ?? "";
this.authorizeUrl = authorizeUrl ;
this.getUsernameAsync = getUsernameAsync;
this.accessTokenUrl = null;
}
/// <summary>
/// Initializes a new instance <see cref="ZicMoove.Droid.OAuth.YaOAuth2WebAuthenticator"/>
/// that authenticates using authorization codes (code).
/// </summary>
/// <param name='clientId'>
/// Client identifier.
/// </param>
/// <param name='clientSecret'>
/// Client secret.
/// </param>
/// <param name='scope'>
/// Authorization scope.
/// </param>
/// <param name='authorizeUrl'>
/// Authorize URL.
/// </param>
/// <param name='redirectUrl'>
/// Redirect URL.
/// </param>
/// <param name='accessTokenUrl'>
/// URL used to request access tokens after an authorization code was received.
/// </param>
/// <param name='getUsernameAsync'>
/// Method used to fetch the username of an account
/// after it has been successfully authenticated.
/// </param>
public OAuthenticator(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null)
: this(redirectUrl, clientSecret, accessTokenUrl)
{
if (string.IsNullOrEmpty(clientId))
{
throw new ArgumentException("clientId must be provided", "clientId");
}
this.clientId = clientId;
if (string.IsNullOrEmpty(clientSecret))
{
throw new ArgumentException("clientSecret must be provided", "clientSecret");
}
this.clientSecret = clientSecret;
this.scope = scope ?? "";
if (authorizeUrl == null)
{
throw new ArgumentNullException("authorizeUrl");
}
this.authorizeUrl = authorizeUrl;
if (accessTokenUrl == null)
{
throw new ArgumentNullException("accessTokenUrl");
}
this.accessTokenUrl = accessTokenUrl;
if (redirectUrl == null)
throw new Exception("redirectUrl is null");
this.redirectUrl = redirectUrl;
this.getUsernameAsync = getUsernameAsync;
}
OAuthenticator(Uri redirectUrl, string clientSecret = null, Uri accessTokenUrl = null)
{
this.redirectUrl = redirectUrl;
this.clientSecret = clientSecret;
this.accessTokenUrl = accessTokenUrl;
//
// Generate a unique state string to check for forgeries
//
var chars = new char[16];
var rand = new Random();
for (var i = 0; i < chars.Length; i++)
{
chars[i] = (char)rand.Next((int)'a', (int)'z' + 1);
}
this.requestState = new string(chars);
}
bool IsImplicit { get { return accessTokenUrl == null; } }
/// <summary>
/// Method that returns the initial URL to be displayed in the web browser.
/// </summary>
/// <returns>
/// A task that will return the initial URL.
/// </returns>
public Task<Uri> GetInitialUrlAsync()
{
var url = new Uri(string.Format(
"{0}?client_id={1}&redirect_uri={2}&response_type={3}&scope={4}&state={5}",
authorizeUrl.AbsoluteUri,
Uri.EscapeDataString(clientId),
Uri.EscapeDataString(RedirectUrl.AbsoluteUri),
IsImplicit ? "token" : "code",
Uri.EscapeDataString(scope),
Uri.EscapeDataString(requestState)));
var tcs = new TaskCompletionSource<Uri>();
tcs.SetResult(url);
return tcs.Task;
}
/// <summary>
/// Raised when a new page has been loaded.
/// </summary>
/// <param name='url'>
/// URL of the page.
/// </param>
/// <param name='query'>
/// The parsed query of the URL.
/// </param>
/// <param name='fragment'>
/// The parsed fragment of the URL.
/// </param>
protected void OnPageEncountered(Uri url, IDictionary<string, string> query, IDictionary<string, string> fragment)
{
if (url.AbsoluteUri.StartsWith(this.redirectUrl.AbsoluteUri))
{
if (!this.redirectUrl.Equals(url)) {
// this is not our redirect page,
// but perhaps one one the third party identity providers
// One don't check for a state here.
//
if (fragment.ContainsKey("continue")) {
var cont = fragment["continue"];
// TODO continue browsing this address
var tcs = new TaskCompletionSource<Uri>();
tcs.SetResult(new Uri(cont));
tcs.Task.RunSynchronously();
}
return;
}
var all = new Dictionary<string, string>(query);
foreach (var kv in fragment)
all[kv.Key] = kv.Value;
//
// Check for forgeries
//
if (all.ContainsKey("state"))
{
if (all["state"] != requestState && !reportedForgery)
{
reportedForgery = true;
OnError("Invalid state from server. Possible forgery!");
return;
}
}
}
}
private void OnError(string v)
{
throw new NotImplementedException();
}
private void OnError(AggregateException ex)
{
throw new NotImplementedException();
}
/// <summary>
/// Raised when a new page has been loaded.
/// </summary>
/// <param name='url'>
/// URL of the page.
/// </param>
/// <param name='query'>
/// The parsed query string of the URL.
/// </param>
/// <param name='fragment'>
/// The parsed fragment of the URL.
/// </param>
protected void OnRedirectPageLoaded(Uri url, IDictionary<string, string> query, IDictionary<string, string> fragment)
{
//
// Look for the access_token
//
if (fragment.ContainsKey("access_token"))
{
//
// We found an access_token
//
OnRetrievedAccountProperties(fragment);
}
else if (!IsImplicit)
{
//
// Look for the code
//
if (query.ContainsKey("code"))
{
var code = query["code"];
RequestAccessTokenAsync(code).ContinueWith(task =>
{
if (task.IsFaulted)
{
OnError(task.Exception);
}
else
{
OnRetrievedAccountProperties(task.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
OnError("Expected code in response, but did not receive one.");
return;
}
}
else
{
OnError("Expected access_token in response, but did not receive one.");
return;
}
}
/// <summary>
/// Asynchronously requests an access token with an authorization <paramref name="code"/>.
/// </summary>
/// <returns>
/// A dictionary of data returned from the authorization request.
/// </returns>
/// <param name='code'>The authorization code.</param>
/// <remarks>Implements: http://tools.ietf.org/html/rfc6749#section-4.1</remarks>
Task<IDictionary<string, string>> RequestAccessTokenAsync(string code)
{
var queryValues = new Dictionary<string, string> {
{ "grant_type", "authorization_code" },
{ "code", code },
{ "redirect_uri", RedirectUrl.AbsoluteUri },
{ "client_id", clientId }
};
if (!string.IsNullOrEmpty(clientSecret))
{
queryValues["client_secret"] = clientSecret;
}
return RequestAccessTokenAsync(queryValues);
}
/// <summary>
/// Asynchronously makes a request to the access token URL with the given parameters.
/// </summary>
/// <param name="queryValues">The parameters to make the request with.</param>
/// <returns>The data provided in the response to the access token request.</returns>
public async Task<IDictionary<string, string>> RequestAccessTokenAsync(IDictionary<string, string> queryValues)
{
StringBuilder postData = new StringBuilder();
if (!queryValues.ContainsKey("client_id"))
{
postData.Append("client_id="+Uri.EscapeDataString($"{this.clientId}")+"&");
}
if (!queryValues.ContainsKey("client_secret"))
{
postData.Append("client_secret="+Uri.EscapeDataString($"{this.clientSecret}")+"&");
}
if (!queryValues.ContainsKey("scope"))
{
postData.Append("scope="+Uri.EscapeDataString($"{this.scope}")+"&");
}
foreach (string key in queryValues.Keys)
{
postData.Append($"{key}="+Uri.EscapeDataString($"{queryValues[key]}")+"&");
}
var req = WebRequest.Create(accessTokenUrl);
(req as HttpWebRequest).Accept = "application/json";
req.Method = "POST";
var body = Encoding.UTF8.GetBytes(postData.ToString());
req.ContentLength = body.Length;
req.ContentType = "application/x-www-form-urlencoded";
var s = req.GetRequestStream();
s.Write(body, 0, body.Length);
var auth = await req.GetResponseAsync();
var repstream = auth.GetResponseStream();
var respReader = new StreamReader(repstream);
var text = await respReader.ReadToEndAsync();
req.Abort();
// Parse the response
var data = text.Contains("{") ? JsonDecode(text) : FormDecode(text);
if (data.ContainsKey("error"))
{
OnError("Error authenticating: " + data["error"]);
}
else if (data.ContainsKey("access_token"))
{
return data;
}
else
{
OnError("Expected access_token in access token response, but did not receive one.");
}
return data;
}
private IDictionary<string,string> FormDecode(string text)
{
throw new NotImplementedException();
}
private IDictionary<string,string> JsonDecode(string text)
{
return JsonConvert.DeserializeObject<Dictionary<string,string>>(text);
}
/// <summary>
/// Event handler that is fired when an access token has been retreived.
/// </summary>
/// <param name='accountProperties'>
/// The retrieved account properties
/// </param>
protected virtual void OnRetrievedAccountProperties(IDictionary<string, string> accountProperties)
{
//
// Now we just need a username for the account
//
if (getUsernameAsync != null)
{
getUsernameAsync(accountProperties).ContinueWith(task =>
{
if (task.IsFaulted)
{
OnError(task.Exception);
}
else
{
OnSucceeded(task.Result, accountProperties);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
OnSucceeded("", accountProperties);
}
}
private void OnSucceeded(string v, IDictionary<string, string> accountProperties)
{
throw new NotImplementedException();
}
}
}

View File

@ -54,7 +54,5 @@ namespace Yavsc
public const string LivePath = "/live/cast";
public const string StreamingPath = "/api/stream/put";
public static string RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
}
}

View File

@ -12,7 +12,7 @@ namespace Yavsc.Abstract.Helpers
public bool Done { get; set; } = false;
public ErrorCode ErrorCode { get; set; }
public string? ErrorMessage { get; set; }
public string ErrorMessage { get; set; }
}
}

View File

@ -7,17 +7,15 @@ namespace Yavsc.Abstract.Identity
}
public UserInfo(string userId, string userName, string email, string avatar)
public UserInfo(string userId, string userName, string avatar)
{
UserId = userId;
UserName = userName;
Email = email;
Avatar = avatar;
}
public string UserId { get; set; }
public string UserName { get; set; }
public string Email { get; }
public string UserName { get; set; }
public string Avatar { get; set; }
}
}

View File

@ -43,13 +43,13 @@ public static class Config
new IdentityResources.Email()
];
public static IEnumerable<ApiScope> ApiScopes =>
public static IEnumerable<ApiScope> TestingApiScopes =>
[
new ApiScope("scope1",new string[] {"scope1"}),
new ApiScope("scope2",new string[] {"scope2"}),
];
public static IEnumerable<Client> Clients =>
public static IEnumerable<Client> TestingClients =>
[
// m2m client credentials flow client
new Client
@ -58,7 +58,7 @@ public static class Config
ClientName = "Client Credentials Client",
ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowedScopes = { "scope1" }
},

View File

@ -1,18 +0,0 @@
namespace Yavsc.Services
{
[Serializable]
internal class YavscInfrastructureException : Exception
{
public YavscInfrastructureException()
{
}
public YavscInfrastructureException(string? message) : base(message)
{
}
public YavscInfrastructureException(string? message, Exception? innerException) : base(message, innerException)
{
}
}
}

View File

@ -19,10 +19,5 @@ namespace Yavsc.Server.Helpers
return user.Identity.IsAuthenticated;
}
public static bool IsInMsRole(this ClaimsPrincipal user, string roleName)
{
return user.HasClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", roleName);
}
}
}

View File

@ -1,2 +1,5 @@
listConnections:
dotnet ef migrations list --connection "$(YAVSC_CONNECTION_STRING)"
SOURCE_DIR=..
SOLUTION_DIR=../..

View File

@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Yavsc.Models.Auth
{
public class Client
{
[Key][Required][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[Required]
[MaxLength(128)]
public string DisplayName { get; set; }
[MaxLength(512)]
public string? RedirectUri { get; set; }
[MaxLength(512)]
public string LogoutRedirectUri { get; set; }
[MaxLength(512)]
public string Secret { get; set; }
public ApplicationTypes Type { get; set; }
public bool Active { get; set; }
public int RefreshTokenLifeTime { get; set; }
public int AccessTokenLifetime { get; set; }
}
}

View File

@ -13,7 +13,7 @@ namespace Yavsc.Models.Billing
using Yavsc.Abstract.Workflow;
using Yavsc.Services;
public abstract class NominativeServiceCommand : IDecidableQuery, IIdentified<long>, IBillable
public abstract class NominativeServiceCommand : IDecidableQuery, IIdentified<long>
{
public string GetInvoiceId() { return GetType().Name + "/" + Id; }

View File

@ -25,10 +25,10 @@ namespace Yavsc.Models.Blog
[Display(Name="Identifiant de l'auteur")]
[ForeignKey("Author")]
public string? AuthorId { get; set; }
public string AuthorId { get; set; }
[Display(Name="Auteur")]
public virtual ApplicationUser? Author { set; get; }
public virtual ApplicationUser Author { set; get; }
[Display(Name="Date de création")]

View File

@ -24,7 +24,16 @@ namespace Yavsc.Models.Haircut
string _description = null;
public override string Description
{
get; set;
get
{
string type = ResourcesHelpers.GlobalLocalizer[this.GetType().Name];
string gender = ResourcesHelpers.GlobalLocalizer[this.Prestation.Gender.ToString()];
return $"{_description} {type} ({gender})";
}
set
{
_description = value;
}
}

View File

@ -30,7 +30,7 @@ namespace Yavsc.Models.Haircut.Views
public class HaircutQueryProviderInfo : HaircutQueryComonInfo {
public HaircutQueryProviderInfo(HairCutQuery query) : base (query)
{
ClientInfo = new UserInfo(query.Client.Id, query.Client.UserName, query.Client.Email, query.Client.Avatar);
ClientInfo = new UserInfo(query.Client.Id, query.Client.UserName, query.Client.Avatar);
}
public UserInfo ClientInfo { get; set; }
@ -39,7 +39,7 @@ namespace Yavsc.Models.Haircut.Views
public HaircutQueryClientInfo(HairCutQuery query) : base (query)
{
var user = query.PerformerProfile.Performer;
ProviderInfo = new UserInfo(user.Id, user.UserName, user.Email, user.Avatar);
ProviderInfo = new UserInfo(user.Id, user.UserName, user.Avatar);
}
public UserInfo ProviderInfo { get; set; }

View File

@ -70,4 +70,4 @@
<data name="Buying"><value>Offre d'achat</value></data>
<data name="ServiceProposal">Offre de service<value></value></data>
<data name="For"><value>Pour</value></data>
</root>
</root>

View File

@ -453,6 +453,7 @@
<data name="PasswordConfirm"><value>Confirmation du mot de passe</value></data>
<data name="ErrorSendingEmailForConfirm"><value>L'envoi de de courrier pour confirmation de l'adresse e-mail a échoué.</value></data>
<data name="EmailSentForConfirm"><value>Un courrier a été envoyé pour confirmation de l'adresse e-mail .</value></data>
<data name="ConfirmYourAccountTitle"><value>S'il vous plait, confirmez votre addresse e-mail</value></data>
<data name="ConfirmYourAccountBody"><value>Vous avez créé avec succès votre compte {0},
mais votre adresse e-mail reste à confirmer.
Pour ce faire, suivez le lien suivant : &lt;{1}&gt;.

View File

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader><resheader name="version">2.0</resheader><resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader><resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader><data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data><data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data><data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"><value>[base64 mime encoded serialized .NET Framework object]</value></data><data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"><value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value><comment>This is a comment</comment></data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root"
xmlns=""
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="HairCutQueryValidation"><value>Une demande (de {0}) en coiffure à domicile vient d'être validée</value></data>
</root>

File diff suppressed because it is too large Load Diff

View File

@ -1,788 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader><resheader name="version">2.0</resheader><resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader><resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader><data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data><data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data><data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"><value>[base64 mime encoded serialized .NET Framework object]</value></data><data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"><value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value><comment>This is a comment</comment></data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root"
xmlns=""
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About">
<value>About</value>
</data>
<data name="About_BookAStar">
<value>About BookAStar</value>
</data>
<data name="About_Message">
<value>Welcome by your stars.</value>
</data>
<data name="access_denied">
<value>Access denied</value>
</data>
<data name="AccountBalance">
<value>Account Balance</value>
</data>
<data name="Activity">
<value>Activity</value>
</data>
<data name="Activities">
<value>Activities</value>
</data>
<data name="additionally">
<value>additionally</value>
</data>
<data name="Allow my geolocatisation, nearby my clients">
<value>Allow my geolocatisation, nearby my clients</value>
</data>
<data name="AnIMessageHasbeenSent">
<value>An instant message has been sent to {0}, showing to him your query. You should be contacted very soon.</value>
</data>
<data name="aprestation">
<value>a prestation</value>
</data>
<data name="AskForAnEstimate">
<value>Ask for an estimate</value>
</data>
<data name="AttachedFiles">
<value>Attached files</value>
</data>
<data name="AuthenticatedOnly">
<value>You must be authenticated in order to access this information</value>
</data>
<data name="Author">
<value>Author</value>
</data>
<data name="available">
<value>available</value>
</data>
<data name="Basket">
<value>Basket</value>
</data>
<data name="Bill_edition">
<value>Bill edition</value>
</data>
<data name="Bill_removal">
<value>Bill removal</value>
</data>
<data name="BillAccessControl">
<value>Bill access control</value>
</data>
<data name="BillCreated">
<value>Bill created</value>
</data>
<data name="BillSourceCode">
<value>Bill source code</value>
</data>
<data name="BillUpdated">
<value>Bill updated</value>
</data>
<data name="body">
<value>body</value>
</data>
<data name="Book A Star">
<value>Book an artist</value>
</data>
<data name="Book IT">
<value>Book a performer in information technology</value>
</data>
<data name="BookingTitleArtiste">
<value>Book an artiste</value>
</data>
<data name="BookingTitle6829C">
<value>Book a software editor</value>
</data>
<data name="Catalog">
<value>Catalog</value>
</data>
<data name="Change user name form">
<value>Change user name form</value>
</data>
<data name="Change your account settings">
<value>Change your account settings</value>
</data>
<data name="ChooseADescription">
<value>Please, choose a description</value>
</data>
<data name="ChooseATitle">
<value>Please, choose a title</value>
</data>
<data name="ChooseADateInTheFutur">
<value>Please, Choose A Date In The Futur</value>
</data>
<data name="ChooseAnEventDate">
<value>Please, choose a date for this event </value>
</data>
<data name="Ciffer">
<value>Ciffer</value>
</data>
<data name="Circles">
<value>Circles</value>
</data>
<data name="Click action">
<value>Click action</value>
</data>
<data name="Color">
<value>Color</value>
</data>
<data name="Comment">
<value>Comment</value>
</data>
<data name="Consultant">
<value>Consultant</value>
</data>
<data name="ContactAPerformer">
<value>Contact a performer</value>
</data>
<data name="CouldNotConvertVToDouble">
<value>Could not convert '{0}' to double.</value>
</data>
<data name="Count">
<value>Count</value>
</data>
<data name="Create">
<value>Créer</value>
</data>
<data name="Credits">
<value>Credits</value>
</data>
<data name="Date_search">
<value>Date search</value>
</data>
<data name="DB">
<value>Data base</value>
</data>
<data name="Description">
<value>Description</value>
</data>
<data name="Disable">
<value>Disable</value>
</data>
<data name="DisplayName">
<value>Display Name</value>
</data>
<data name="DoAnEstimate">
<value>Do an estimate</value>
</data>
<data name="DoComment">
<value>Commenter</value>
</data>
<data name="DocTemplateException">
<value>Une erreur est survenue à la génération de votre document</value>
</data>
<data name="DoNotPublishMyActivity">
<value>Ne pas publier mon activité</value>
</data>
<data name="DoPost">
<value>Do post</value>
</data>
<data name="DoSpecifyCircles">
<value>S'il vous plait, spécifiez ceux de vos cercles à qui est destiné ce contenu</value>
</data>
<data name="DoTag">
<value>Tagger</value>
</data>
<data name="DuplicateEmail">
<value>This email adress is already used ({0}).</value>
</data>
<data name="DuplicateUserName">
<value>This user name is already used ({0}).</value>
</data>
<data name="Edit">
<value>Edit</value>
</data>
<data name="Edited">
<value>Edited</value>
</data>
<data name="EditRelatedSkills">
<value>Edit related skills</value>
</data>
<data name="EndDate">
<value>Date de fin</value>
</data>
<data name="EndHour">
<value>Heure de fin</value>
</data>
<data name="email">
<value>e-mail</value>
</data>
<data name="EMailToPerformerFooter">
<value> Generated e-mail from {0}, because of your perfomer profile publication, and your email usage agreement. Visit {1} to modify your profile, unsubscribe or unregister.</value>
</data>
<data name="entries">
<value>entries</value>
</data>
<data name="Estimate not found">
<value>Estimate not found</value>
</data>
<data name="EstimateWanted">
<value>Estimate wanted</value>
</data>
<data name="EventWebPage">
<value>Event Web page</value>
</data>
<data name="ExistantDB">
<value>Existant data base</value>
</data>
<data name="External Logins">
<value>External Logins</value>
</data>
<data name="FillInAFutureDate">
<value>Please, use a date in the future as starting date.</value>
</data>
<data name="Forbidden">
<value>Restricted area</value>
</data>
<data name="from">
<value>from</value>
</data>
<data name="GiveAnExplicitReason">
<value>Tell more, below, about your query</value>
</data>
<data name="GoogleDidntGeoLocalized">
<value>Google could'nt identify this place</value>
</data>
<data name="Google calendar">
<value>Google calendar</value>
</data>
<data name="Google error">
<value>Google error : {0}</value>
</data>
<data name="Google registration id">
<value>Google registration id</value>
</data>
<data name="Home">
<value>Home</value>
</data>
<data name="Hide">
<value>Hide</value>
</data>
<data name="hidden">
<value>hidden</value>
</data>
<data name="Hide source">
<value>Hide the bill source text</value>
</data>
<data name="I understood">
<value>I understood</value>
</data>
<data name="Icons made by">
<value>Icons made by</value>
</data>
<data name="ImgLocator">
<value>Image URI</value>
</data>
<data name="ImportException">
<value>Exception at importing</value>
</data>
<data name="InternalServerError">
<value>Internal Server Error</value>
</data>
<data name="is licensed by">
<value>is licensed by</value>
</data>
<data name="Item added to basket">
<value>Item added to basket</value>
</data>
<data name="Location">
<value>Location</value>
</data>
<data name="Login">
<value>Login</value>
</data>
<data name="Logout">
<value>Logout</value>
</data>
<data name="MainActivity">
<value>Main activity</value>
</data>
<data name="Manage">
<value>Manage</value>
</data>
<data name="ManagedSiteSkills">
<value>Site skills</value>
</data>
<data name="MaxDate">
<value>Maximal date for the rendez-vous</value>
</data>
<data name="MEACode">
<value>Mainly Exerted Activity code</value>
</data>
<data name="Manage your account">
<value>Manage your account</value>
</data>
<data name="Members">
<value>Members</value>
</data>
<data name="Message sent">
<value>Your message has been sent.</value>
</data>
<data name="MinDate">
<value>Minimal date for the rendez-vous</value>
</data>
<data name="Modify">
<value>Modify</value>
</data>
<data name="My Estimates">
<value>My estimates</value>
</data>
<data name="Name">
<value>Name</value>
</data>
<data name="Needs">
<value>Needs</value>
</data>
<data name="Need">
<value>Need</value>
</data>
<data name="nouvel instrument">
<value>new instrument</value>
</data>
<data name="UserName">
<value>Display name</value>
</data>
<data name="New user name">
<value>New display name</value>
</data>
<data name="New Tag">
<value>New Tag</value>
</data>
<data name="NewPasswordMessageSent">
<value>A message had been sent, containing a link to follow in order to update your password.</value>
</data>
<data name="no content">
<value>no content</value>
</data>
<data name="NoSkillforthisactivity">
<value>No skill was informed by any performer for this activity</value>
</data>
<data name="none">
<value>none</value>
</data>
<data name="Non existent user">
<value>Non existent user</value>
</data>
<data name="Not Approuved">
<value>Not Approuved</value>
</data>
<data name="No calendar for this user">
<value>No calendar was associated to this user.</value>
</data>
<data name="Offline">
<value>Offline</value>
</data>
<data name="Online">
<value>Online</value>
</data>
<data name="OnlyAuthorizedMayContact">
<value>Only authorized users may contact a performer by mail.</value>
</data>
<data name="Pdf version">
<value>Pdf version</value>
</data>
<data name="PerformanceDate">
<value>Performance date</value>
</data>
<data name="PerformancePlace">
<value>Performance place</value>
</data>
<data name="Performers">
<value>Performers</value>
</data>
<data name="Performer">
<value>Performer</value>
</data>
<data name="Person">
<value>Person</value>
</data>
<data name="Photo">
<value>Photo</value>
</data>
<data name="PhotoUpdated">
<value>Photo updated</value>
</data>
<data name="PleaseCheckYourEmail">
<value>Please check your email to reset your password.</value>
</data>
<data name="PleaseConfirmYourNewPassword">
<value>Please confirm your new password</value>
</data>
<data name="PleaseFillInABody">
<value>Please fill in a body</value>
</data>
<data name="PleaseFillInAReason">
<value>Please, fill in a reason</value>
</data>
<data name="Posted">
<value>Posted</value>
</data>
<data name="PreferedDate">
<value>Prefered date</value>
</data>
<data name="prestation">
<value>prestation</value>
</data>
<data name="PresationLocation">
<value>Presation location:{0}.\n</value>
</data>
<data name="Preview">
<value>Preview</value>
<comment>comment on preview</comment>
</data>
<data name="Profile edition">
<value>Profile edition</value>
</data>
<data name="Private circle">
<value>Private circle</value>
</data>
<data name="ProviderId">
<value>Provider identifier</value>
</data>
<data name="ProviderName">
<value>Provider name</value>
</data>
<data name="Product reference">
<value>Product_reference</value>
</data>
<data name="ReadMore">
<value>Read more ...</value>
</data>
<data name="reason">
<value>reason</value>
</data>
<data name="Register">
<value>Register</value>
</data>
<data name="RegistrationUnexpectedError">
<value>Registration: unexpected error occured: "{0}". Please forgive for troubles</value>
</data>
<data name="Remember me">
<value>Remember me</value>
</data>
<data name="Remove">
<value>Remove</value>
</data>
<data name="ResetPassword">
<value>Reset your password</value>
</data>
<data name="Role">
<value>Role</value>
</data>
<data name="role created">
<value>role created</value>
</data>
<data name="RoleName">
<value>Role name</value>
</data>
<data name="Save these settings">
<value>Save these settings</value>
</data>
<data name="Search">
<value>Search</value>
</data>
<data name="SiteSkills">
<value>Talents/Compétences/Spécialités gérés sur ce site</value>
</data>
<data name="Skill">
<value>Skill</value>
</data>
<data name="Skills">
<value>Skills</value>
</data>
<data name="Specifyavalidlatitude">
<value>Please, specify a valid latitude</value>
</data>
<data name="Specifyavalidlongitude">
<value>Please, specify a valid longitude</value>
</data>
<data name="SpecifyLatitude">
<value>Specify a latitude</value>
</data>
<data name="SpecifyLongitude">
<value>Specify a longitude</value>
</data>
<data name="SpecifyPlace">
<value>Please, specify a place</value>
</data>
<data name="SomeoneAskingYouForAnEstimate">
<value>{0} would want you to establish an estimate concerning {1}</value>
</data>
<data name="Sound">
<value>Sound</value>
</data>
<data name="StartDate">
<value>Start date</value>
</data>
<data name="StartDateAfterEndDate">
<value>The ending date must be later than the starting one.</value>
</data>
<data name="StartHour">
<value>Start hour</value>
</data>
<data name="Submit">
<value>Submit</value>
</data>
<data name="SubmitChanges">
<value>Submit changes</value>
</data>
<data name="Tag">
<value>Tag</value>
</data>
<data name="Tag name">
<value>Tag name</value>
</data>
<data name="Tex version">
<value>LaTeX version</value>
</data>
<data name="ThisSiteUsesCookies">
<value>This site uses cookies</value>
</data>
<data name="ThisPerformerGivesAccessToHisCalendarAndSeemsToBeAvailableThis">
<value>ThisPerformer Gives access to his calendar and seems to be available this</value>
</data>
<data name="ThisPerformerGivesAccessToHisCalendarAndItAppearsHeShouldNotBeAvailableThis">
<value>This performer gives access to his calendar and it appears he should not be available this</value>
</data>
<data name="ThisPerformerDoesntGiveAccessToHisCalendar">
<value>ThisPerformerDoesntGiveAccessToHisCalendar</value>
</data>
<data name="Title">
<value>Title</value>
</data>
<data name="to">
<value>to</value>
</data>
<data name="TwoFactorAuthentication">
<value>Two-Factor authentication</value>
</data>
<data name="Unitary_cost">
<value>Unitary_cost</value>
</data>
<data name="Unregister">
<value>Unregister</value>
</data>
<data name="User List">
<value>User List</value>
</data>
<data name="User name">
<value>User name</value>
</data>
<data name="UsersInRole">
<value>List of users assuming the role "{0}"</value>
</data>
<data name="UserNotInThisRole">
<value>This user is not in this role</value>
</data>
<data name="UserSkills">
<value>User skills</value>
</data>
<data name="View source">
<value>View source</value>
</data>
<data name="was added to_the_role">
<value>was added to the role</value>
</data>
<data name="was_added_to_the_empty_role">
<value>There was no user in the "{1}" role. You ({0}) was just added as firt user in the "{1}" role.</value>
</data>
<data name="Welcome">
<value>Welcome</value>
<comment></comment>
</data>
<data name="XHasBeenNotified">
<value>{0} has been notified of your query, you should be fast contacted</value>
</data>
<data name="Xshouldbeavailable">
<value>regarding his calendar, {0} should be available for this booking</value>
</data>
<data name="Yavsc.Models.Musical.Profiles.Instrumentation">
<value>Paramètres musicien (l'instrument)</value>
</data>
<data name="Yavsc.Models.Musical.Profiles.DjSettings">
<value>Paramètres Dj (le compte SoundCloud.com)</value>
</data>
<data name="Yavsc.Models.Musical.Profiles.FormationSettings">
<value>Paramètres formation (les partenaires)</value>
</data>
<data name="Yavsc.Models.Musical.Profiles.GeneralSettings">
<value>Paramètres généraux: une couleur musicale</value>
</data>
<data name="YouNeedToBeAuthenticatedIOToContact">
<value>You need to be authenticated in order to contact a performer</value>
</data>
<data name="younotadmin">
<value>You're not administrator</value>
</data>
<data name="YourEstimates">
<value>Your estimates</value>
</data>
<data name="YourMEACode">
<value>Your activity</value>
</data>
<data name="YourNeed">
<value>Your need</value>
</data>
<data name="yourquerytransmitted">
<value>your query has been transmitted</value>
</data>
<data name="YourSkills">
<value>Your skills, your special fields, the scope of your activities</value>
</data>
<data name="YourPosts">
<value>You posts</value>
</data>
<data name="YourProfile">
<value>Your profile</value>
</data>
<data name="YourMessageHasBeenSent">
<value>Your message has been sent</value>
</data>
<data name="Longueur de cheveux">
<value>Hair Length</value>
</data>
<data name="Français">
<value>French</value>
</data>
<data name="Anglais">
<value>English</value>
</data>
<data name="Portugais"><value>Portugese</value></data>
<data name="RequiredField">
<value>This field is required.</value>
</data>
<data name="PasswordTooShort">
<value>Passwords must be at least {0} characters.</value>
</data>
<data name="PasswordRequiresNonLetterAndDigit">
<value>Passwords must have at least one non letter and non digit character.</value>
</data>
<data name="PasswordRequiresDigit">
<value>Passwords must have at least one digit ('0'-'9').</value>
</data>
<data name="PasswordRequiresUpper">
<value>Passwords must have at least one uppercase ('A'-'Z').</value>
</data>
<data name="PassAndConfirmDontMach">
<value>Passwords and confirmation are not the same.</value>
</data>
<data name="PasswordConfirm">
<value>Password confirmation</value>
</data>
<data name="InvalidUserName">
<value>Invalid user name.
Valid caracters are: underscore '_', '-', 'a' - 'z', 'A' - 'Z', '0' - '9', the single quote ('), the space and the dot.</value>
</data>
<data name="EmailSentForConfirm">
<value>An email has been sent to confirm your addresse.</value>
</data>
<data name="ConfirmYourAccountBody"><value>You successfully created your {0} account,
but your e-mail address is not yet confirmed.
Please, in order to validate it, follow this link &lt;{1}&gt;.
Thanks.
--
{0} - {2} &lt;https://{3}&gt;</value>
</data>
<data name="Instrumentation"><value>Instrumentation</value></data>
<data name="Partenariat"><value>Co-working</value></data>
</root>

View File

@ -1,282 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Reset Password"><value>Ré-initialiser votre mot de passe</value></data>
<data name="role created"><value>Rôle créé</value></data>
<data name="RoleName"><value>Nom du rôle </value></data>
<data name="Save these settings"><value>Enregistrer ces paramètres</value></data>
<data name="Search"><value>Chercher</value></data>
<data name="Select a Google calendar"><value>Selectioner un calendrier Google</value></data>
<data name="Send"><value>Envoyer</value></data>
<data name="Send a private message"><value>Envoyer un message privé</value></data>
<data name="Send a public message"><value>Envoyer un message publique</value></data>
<data name="Set"><value>Positioner</value></data>
<data name="SettingsClass"><value>Classe du paramétrage</value></data>
<data name="Short"><value>court</value></data>
<data name="Son blog"><value>Son blog</value></data>
<data name="Your performer profile"><value>Votre profil professionel</value></data>
<data name="Setup below your activity parameters"><value>Positionnez ci-après vos les paramêtre de votre activité</value></data>
<data name="SiteSkills"><value>Talents/Compétences/Spécialités gérés sur ce site</value></data>
<data name="Skill"><value>Compétence</value></data>
<data name="Skills"><value>Talents/Compétences/Spécialités</value></data>
<data name="SomeoneAskingYouForAnEstimate"><value>{0} désirerait un devis concernant {1}</value></data>
<data name="Sound"><value>Son</value></data>
<data name="SpecifyLatitude"><value>Specify a latitude</value></data>
<data name="SpecifyLongitude"><value>Specify a longitude</value></data>
<data name="SpecifyPlace"><value>L'endroit ainsi renseigné ne semble pas convenir ...</value></data>
<data name="Specifyavalidlatitude"><value>Please, specify a valid latitude.</value></data>
<data name="StartDate"><value>Date de début</value></data>
<data name="StartDateAfterEndDate"><value>La date de fin doit être postérieure à la date de début.</value></data>
<data name="StartHour"><value>Heure de début</value></data>
<data name="Submit"><value>Soumettre</value></data>
<data name="SubmitChanges"><value>Envoyer les modifications</value></data>
<data name="Tag"><value>Tag</value></data>
<data name="Tag name"><value>Nom du tag</value></data>
<data name="Tex version"><value>Version LaTeX</value></data>
<data name="ThisSiteUsesCookies"><value>Ce site utilise les cookies</value></data>
<data name="ThisPerformerGivesAccessToHisCalendarAndSeemsToBeAvailableThis"><value>Selon son calendier Google, ce perstataire est disponbile ce</value></data>
<data name="ThisPerformerGivesAccessToHisCalendarAndItAppearsHeShouldNotBeAvailableThis"><value>Selon son calendier Google, ce perstataire pourrait ne pas être disponible ce</value></data>
<data name="ThisPerformerDoesntGiveAccessToHisCalendar"><value>Ce prestataire n'a pas mis de calendrier à disposition.</value></data>
<data name="Title"><value>Titre</value></data>
<data name="Feature"><value>Fonctionalité</value></data>
<data name="FeatureId"><value>Identifiant de fonctionalité</value></data>
<data name="to"><value>à</value></data>
<data name="TwoFactorAuthentication"><value>Double identification</value></data>
<data name="Unitary_cost"><value>Coût unitaire</value></data>
<data name="Unregister"><value>Se désinscrire</value></data>
<data name="Use a local account to log in"><value>Utiliser un compte local pour se connecter</value></data>
<data name="Use another service to log in"><value>Utiliser un autre service pour se connecter</value></data>
<data name="UseGeoLocalizationToReduceDistanceWithClients"><value>Utiliser ma position pour avoir des clients plus proches</value></data>
<data name="User"><value>Utilisateur</value><comment></comment></data>
<data name="User List"><value>Liste des utilisateurs</value><comment></comment></data>
<data name="UserName"><value>Nom d'utilisateur</value></data>
<data name="UsersInRole"><value>Liste des utilisateurs assumant le rôle "{0}"</value></data>
<data name="UserSkills"><value>Talents/compétences/spécialités utilisateur</value></data>
<data name="UserNotInThisRole"><value>Le rôle demandé n'est pas assumé par ce préstataire</value></data>
<data name="ValidationDate"><value>Date de validation</value></data>
<data name="View_source"><value>Voir le texte source de l'article</value></data>
<data name="was_added_to_the_role"><value>a été ajouté au rôle</value></data>
<data name="was_added_to_the_empty_role"><value>Il n'y avait pas d'utilisateur dans le rôle "{1}". Vous ({0}) avez été ajouté au rôle "{1}".</value></data>
<data name="WebSite"><value>Site Web</value><comment></comment></data>
<data name="Welcome"><value>Bienvenue</value><comment></comment></data>
<data name="Women"><value>Femme</value><comment></comment></data>
<data name="XHasBeenNotified"><value>{0} à été notifié de votre demande, vous devriez être contacté rapidement</value></data>
<data name="Xshouldbeavailable"><value>Au vu de son calendrier,
{0} devrait être disponible pour ce rendez-vous</value></data>
<data name="Yavsc.Models.Musical.Profiles.Instrumentation"><value>Paramètres musicien (l'instrument)</value></data>
<data name="Yavsc.Models.Musical.Profiles.DjSettings"><value>Paramètres Dj (le compte SoundCloud.com)</value></data>
<data name="Yavsc.Models.Workflow.Profiles.FormationSettings"><value>Paramètres formation (les partenaires)</value></data>
<data name="Yavsc.Models.Musical.Profiles.GeneralSettings"><value>Paramètres généraux (visibilité et présentation)</value></data>
<data name="Yavsc.Models.Haircut.BrusherProfile"><value>Paramètres coiffeur: tarifs, disponibilité</value></data>
<data name="Yes"><value>Oui</value></data>
<data name="YouNeedToBeAuthenticatedIOToContact"><value>Vous devez vous authentifier pour pouvoir demander un devis
à un préstataire.</value></data>
<data name="younotadmin"><value>Vous n'êtes pas administrateur</value></data>
<data name="Your account settings"><value>Les paramètres de votre compte</value></data>
<data name="Your book query"><value>Votre demande de rendez-vous</value></data>
<data name="Your password has been reset."><value>Votre mote de passe a été mis à jour.</value></data>
<data name="YourEstimates"><value>Vos Devis</value></data>
<data name="YourMEACode"><value>Votre activité</value></data>
<data name="YourNeed"><value>Votre besoin</value></data>
<data name="yourquerytransmitted"><value>Votre demande a été transmise</value></data>
<data name="YourSkills"><value>Vos talents, vos spécialités, le domaine de vos activités</value></data>
<data name="Your posts"><value>Vos publications</value></data>
<data name="Your profile"><value>Votre profil</value></data>
<data name="YourMessageHasBeenSent"><value>Votre messge a été envoyé</value></data>
<data name="Tell more, below, about your query"><value>Dites en plus, ci àprès, à propos de cet évennement</value></data>
<data name="UnsetActivity"><value>Supprimer mon profil professionel</value></data>
<data name="Français"><value>Français</value></data>
<data name="Anglais"><value>Anglais</value></data>
<data name="Portugais"><value>Portugais</value></data>
<data name="InvalidUserName"><value>Nom d'utilisateur invalide.
Les caratères valides sont: le souligné (_), le petit titret (-), l'apostrohe ('), les minuscules et majuscules de a à z, les chiffres de 0 à 9, l'espace et le point.</value></data>
<data name="RequiredField"><value>Ce champ est obligatoire.</value></data>
<data name="validationError"><value>Champ invalide ...</value></data>
<data name="PasswordTooShort"><value>Le Mot de passe doit contenir au moins 6 caractères.</value></data>
<data name="PasswordRequiresNonLetterAndDigit"><value>Mot de passe doit contenir au moins un caractère spécial (ni un chiffre, ni une lettre).</value></data>
<data name="PasswordRequiresDigit"><value>Les mots de passe doivent contenir au moins un chiffre ('0' à '9').</value></data>
<data name="PasswordRequiresUpper"><value>Les mots de passe doivent contenir au moins une lettre majuscule ('A' à 'Z').</value></data>
<data name="PassAndConfirmDontMach"><value>Le mot de passe et sa confirmation ne sont pas les mêmes.</value></data>
<data name="PasswordConfirm"><value>Confirmation du mot de passe</value></data>
<data name="ConfirmPassword"><value>Confirmation du mot de passe</value></data>
<data name="ErrorSendingEmailForConfirm"><value>L'envoi de de courrier pour confirmation de l'adresse e-mail a échoué.</value></data>
<data name="EmailSentForConfirm"><value>Un courrier a été envoyé pour confirmation de l'adresse e-mail .</value></data>
<data name="AccountEmailFactorTitle"><value>Le second facteur de votre identification</value></data>
<data name="AccountEmailFactorBody"><value>Votre compte est endurci d'une requisition d'un second facteur d'identification.
Une nouvelle connection depuis un navigateur web nécéssite votre authorisation.
Vous pouvez l'accorder en suivant le lien suivant : &lt;{1}&gt;.
Votre code dáctivation est : {4}
Vour pourrez cochez la case "Se souvenir de ce navigateur" pour conserver cette authorisation pour ce navigateur.
{0} - {2} &lt;{3}&gt;</value></data>
<data name="ConfirmYourAccountBody"><value>Vous avez créé avec succès votre compte {0},
mais votre adresse e-mail reste à confirmer.
Pour ce faire, veuillez, s'il vous plait, suivre le lien suivant
dans votre navigateur favori : &lt;{1}&gt;.
--
{0} - {2} &lt;{3}&gt;</value></data>
<data name="BadStringLength"><value>Taille maximale: {0} caractère.</value></data>
<data name="DetailledMinMaxStringLength"><value>Ce champ est
d'au moins {0} et d'au plus {1} caractère(s) (manquent {2}) ou ({3} en trop).</value></data>
<data name="DetailledMaxStringLength"><value>Ce champ est
d'au plus {0} caractère(s) ({1} en excès). </value></data>
<data name="EmailSentToPerformer"><value>Un message éléctronique a été envoyé à {0}.</value></data>
<data name="QueryValidatedNonReg"><value>Un client vient de valider une demande de prestation à votre encontre:
Prestation: {0}
Client : {1}
Date: {2},
Adresse: {3}
-----
{4}
Facture prévue (non réglée): {5}</value></data>
<data name="QueryValidatedRegular"><value>Un client vient de valider une demande de prestation à votre encontre:
Prestation: {0}
Client : {1}
Date: {2},
Adresse: {3}
-----
{4}
Facture réglée: {5}</value></data>
<data name="AllowMonthlyEmail"><value>Recevoir la lettre mensuelle d'information</value></data>
<data name="Join"><value>joindre</value></data>
<data name="Enroll"><value>Enrôler</value></data>
<data name="Fire"><value>Licencier</value></data>
<data name="LiveFlow"><value>Flux live</value></data>
<data name="Instrumentation"><value>Instrumentation</value></data>
<data name="Partenariat"><value>Partenariat</value></data>
<data name="IconWebUploadSpecification"><value>
Le format png pourrait être supporté ici,
le format Gif, peut-être aussi, et même, mais là, moins souvent, le surnommé Jpg.
</value></data>
</root>

View File

@ -772,7 +772,18 @@
<value>Invalid user name.
Valid caracters are: underscore '_', '-', 'a' - 'z', 'A' - 'Z', '0' - '9', the single quote ('), the space and the dot.</value>
</data>
<data name="EmailSentForConfirm">
<value>An email has been sent to confirm your addresse.</value>
</data>
<data name="ConfirmYourAccountTitle"><value>Please, confirm your e-mail</value></data>
<data name="ConfirmYourAccountBody"><value>You successfully created your {0} account,
but your e-mail address is not yet confirmed.
Please, in order to validate it, follow this link &lt;{1}&gt;.
Thanks.
--
{0} - {2} &lt;https://{3}&gt;</value>
</data>
<data name="Instrumentation"><value>Instrumentation</value></data>
<data name="Partenariat"><value>Co-working</value></data>
</root>

View File

@ -437,6 +437,7 @@
<data name="ConfirmPassword"><value>Confirme sua senha</value></data>
<data name="ErrorSendingEmailForConfirm"><value>O envio de e-mail para confirmação do endereço de e-mail falhou.</value></data>
<data name="EmailSentForConfirm"><value>Um e-mail foi enviado para confirmação do endereço de e-mail.</value></data>
<data name="ConfirmYourAccountTitle"><value>Por favor, confirme seu endereço de e-mail</value></data>
<data name="ConfirmYourAccountBody"><value>Você criou sua conta {0} com sucesso,
mas o seu endereço de e-mail tem que ser confirmado.
Para fazer isso, siga o seguinte link : &lt;{1}&gt;.

View File

@ -251,6 +251,7 @@
<data name="HalfLong"><value>mi-long</value></data>
<data name="MobileHairCut"><value>Coiffure à domicile</value></data>
<data name="HairCutQuery"><value>Préstation en coiffure à domicile</value></data>
<data name="HairCutQueryValidation"><value>Une demande (de {0}) en coiffure à domicile vient d'être validée</value></data>
<data name="Hide source"><value>Cacher le texte source de l'article</value></data>
<data name="Home"><value>Accueil</value></data>
<data name="Hide"><value>Cacher</value></data>
@ -461,6 +462,7 @@
<data name="PasswordConfirm"><value>Confirmation du mot de passe</value></data>
<data name="ConfirmPassword"><value>Confirmation du mot de passe</value></data>
<data name="ErrorSendingEmailForConfirm"><value>L'envoi de de courrier pour confirmation de l'adresse e-mail a échoué.</value></data>
<data name="EmailSentForConfirm"><value>Un courrier a été envoyé pour confirmation de l'adresse e-mail .</value></data>
<data name="AccountEmailFactorTitle"><value>Le second facteur de votre identification</value></data>
<data name="AccountEmailFactorBody"><value>Votre compte est endurci d'une requisition d'un second facteur d'identification.
@ -471,7 +473,15 @@ Votre code dáctivation est : {4}
Vour pourrez cochez la case "Se souvenir de ce navigateur" pour conserver cette authorisation pour ce navigateur.
{0} - {2} &lt;{3}&gt;</value></data>
<data name="ConfirmYourAccountTitle"><value>S'il vous plait, confirmez votre addresse e-mail</value></data>
<data name="ConfirmYourAccountBody"><value>Vous avez créé avec succès votre compte {0},
mais votre adresse e-mail reste à confirmer.
Pour ce faire, veuillez, s'il vous plait, suivre le lien suivant
dans votre navigateur favori : &lt;{1}&gt;.
--
{0} - {2} &lt;{3}&gt;</value></data>
<data name="BadStringLength"><value>Taille maximale: {0} caractère.</value></data>
<data name="DetailledMinMaxStringLength"><value>Ce champ est
d'au moins {0} et d'au plus {1} caractère(s) (manquent {2}) ou ({3} en trop).</value></data>

View File

@ -14,17 +14,16 @@ using System.Web;
namespace Yavsc.Services
{
public class MailSender : IEmailSender<ApplicationUser>, IEmailSender, ITrueEmailSender
public class MailSender : IEmailSender<ApplicationUser>, IEmailSender, ITrueEmailSender
{
private readonly IStringLocalizer<MailSender> localizer;
private readonly IStringLocalizer<YavscLocalization> localizer;
readonly SiteSettings siteSettings;
readonly SmtpSettings smtpSettings;
private readonly ILogger logger;
public MailSender(
IOptions<SiteSettings> sitesOptions,
IOptions<SiteSettings> sitesOptions,
IOptions<SmtpSettings> smtpOptions,
ILoggerFactory loggerFactory,
IStringLocalizer<MailSender> localizer
ILoggerFactory loggerFactory
)
{
this.localizer = localizer;
@ -47,15 +46,17 @@ namespace Yavsc.Services
/// <returns>a MessageWithPayloadResponse,
/// <c>bool somethingsent = (response.failure == 0 &amp;&amp; response.success > 0)</c>
/// </returns>
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
await SendEmailAsync("", email, subject, htmlMessage);
await SendEmailAsync("", email, subject, htmlMessage);
}
public async Task<string> SendEmailAsync(string name, string email, string subject, string htmlMessage)
{
logger.LogInformation($"SendEmail for {email} : {subject}");
MimeMessage msg = new();
logger.LogInformation($"SendEmail for {email} : {subject}");
MimeMessage msg = new ();
msg.From.Add(new MailboxAddress(siteSettings.Owner.Name,
siteSettings.Owner.EMail));
msg.To.Add(new MailboxAddress(name, email));
@ -67,37 +68,30 @@ namespace Yavsc.Services
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
siteSettings.Authority
);
using (SmtpClient sc = new())
using (SmtpClient sc = new ())
{
sc.Connect(
smtpSettings.Server,
smtpSettings.Port,
SecureSocketOptions.Auto
);
if (smtpSettings.UserName != null)
{
sc.Authenticate(smtpSettings.UserName, smtpSettings.Password);
SecureSocketOptions.Auto);
if (smtpSettings.UserName!=null) {
NetworkCredential creds = new (
smtpSettings.UserName, smtpSettings.Password);
await sc.AuthenticateAsync(System.Text.Encoding.UTF8, creds, System.Threading.CancellationToken.None);
}
await sc.SendAsync(msg);
logger.LogInformation($"Sent : {msg.MessageId}");
sc.Disconnect(true);
}
return msg.MessageId;
}
public void SendEmailFromCriteria(string Criteria)
{
throw new NotImplementedException();
}
public async Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode)
{
var callbackUrl = siteSettings.Audience + "/Account/ResetPassword/" +
var callbackUrl = siteSettings.Audience + "/Account/ResetPassword/" +
HttpUtility.UrlEncode(user.Id) + "/" + HttpUtility.UrlEncode(resetCode);
await SendEmailAsync(user.UserName, user.Email,
await SendEmailAsync(user.UserName, user.Email,
localizer["Reset Password"],
localizer["Please reset your password by "] + " <a href=\"" +
callbackUrl + "\" >following this link</a>");
@ -106,10 +100,10 @@ namespace Yavsc.Services
public async Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink)
{
await SendEmailAsync(user.UserName, user.Email,
localizer["Reset Password"],
localizer["Please reset your password by "] + " <a href=\"" +
resetLink + "\" >following this link</a>");
await SendEmailAsync(user.UserName, user.Email,
localizer["Reset Password"],
localizer["Please reset your password by "] + " <a href=\"" +
resetLink + "\" >following this link</a>");
}
}
}

View File

@ -43,7 +43,7 @@ namespace Yavsc.Services
claimAdds.Remove("profile");
claimAdds.Add(JwtClaimTypes.Name);
claimAdds.Add(JwtClaimTypes.Email);
claimAdds.Add(Constants.RoleClaimType);
claimAdds.Add(JwtClaimTypes.Role);
}
if (claimAdds.Contains(JwtClaimTypes.Name))
@ -52,12 +52,12 @@ namespace Yavsc.Services
if (claimAdds.Contains(JwtClaimTypes.Email))
claims.Add(new Claim(JwtClaimTypes.Email, user.Email));
if (claimAdds.Contains(Constants.RoleClaimType))
if (claimAdds.Contains(JwtClaimTypes.Role))
{
var roles = await this._userManager.GetRolesAsync(user);
if (roles.Count()>0)
{
claims.AddRange(roles.Select(r => new Claim(Constants.RoleClaimType, r)));
claims.AddRange(roles.Select(r => new Claim(JwtClaimTypes.Role, r)));
}
}
return claims;

View File

@ -14,17 +14,14 @@ namespace Yavsc
public string FavIcon { get; set; } = "favicon.ico";
public string Logo { get; set; } = "logo.png";
/// <summary>
/// Conceptually,
/// This authorisation server only has this present site as unique audience.
/// </summary>
/// <returns></returns>
public string Audience { get; set; } = "lua.pschneider.fr";
/// <summary>
/// External Url
/// </summary>
/// <value></value>
public string ExternalUrl { get; set; } = "http://lua.pschneider.fr";
/// <summary>
/// Must be a fqdn.
/// it's a very small company, with one domaine name only,
/// so let it be the same as in the Audience field.
/// </summary>
/// <returns></returns>
public string Authority { get; set; } = "lua.pschneider.fr";

View File

@ -5,10 +5,10 @@ namespace Yavsc.ViewModels.Account
{
public class UnregisterViewModel
{
[Required]
[YaRequired]
public string UserId { get; set; }
public string? ReturnUrl { get; set; }
public string ReturnUrl { get; set; }
}
}

View File

@ -29,4 +29,4 @@
<ItemGroup>
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
</ItemGroup>
</Project>
</Project>

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

@ -28,7 +28,6 @@ using System.Security.Cryptography;
using System.Text.Unicode;
using System.Text;
using Yavsc.Server.Helpers;
using System.Reflection;
namespace Yavsc.Controllers
{
@ -67,7 +66,7 @@ namespace Yavsc.Controllers
ITrueEmailSender emailSender,
IOptions<SiteSettings> siteSettings,
ILoggerFactory loggerFactory, IOptions<TwilioSettings> twilioSettings,
IStringLocalizerFactory localizerFactory,
IStringLocalizer<Yavsc.YavscLocalization> localizer,
ApplicationDbContext dbContext)
{
_interaction = interaction;
@ -82,9 +81,8 @@ namespace Yavsc.Controllers
_siteSettings = siteSettings.Value;
_twilioSettings = twilioSettings.Value;
_logger = loggerFactory.CreateLogger<AccountController>();
_localizer = localizer;
_dbContext = dbContext;
_localizer = localizerFactory.Create(typeof(AccountController));
}
@ -405,7 +403,7 @@ namespace Yavsc.Controllers
}
[Authorize("AdministratorOnly")]
[Authorize(Roles = Constants.AdminGroupName)]
public IActionResult Index()
{
IViewComponentHelper h;
@ -413,9 +411,9 @@ namespace Yavsc.Controllers
return View();
}
[Authorize("AdministratorOnly")]
[Route("Account/UserList/{pageNum?}/{len?}")]
public async Task<IActionResult> UserList(int pageNum=0, int pageLen = defaultLen)
[Authorize(Roles = Constants.AdminGroupName)]
[Route("Account/UserList/{pageNum}/{len?}")]
public async Task<IActionResult> UserList(int pageNum, int pageLen = defaultLen)
{
var users = _dbContext.Users.OrderBy(u=>u.UserName);
var shown = pageNum * pageLen;
@ -425,6 +423,8 @@ namespace Yavsc.Controllers
ViewBag.hasNext = users.Count() > (toShow.Count() + shown);
ViewBag.nextpage = pageNum+1;
ViewBag.pageLen = pageLen;
// ApplicationUser user;
// user.EmailConfirmed
return View(toShow.ToArray());
}
@ -863,13 +863,11 @@ namespace Yavsc.Controllers
{
ApplicationUser user;
// Username should not contain any '@'
if (model.LoginOrEmail.Contains('@'))
{
if (model.LoginOrEmail.Contains('@')) {
user = await _userManager.FindByEmailAsync(model.LoginOrEmail);
}
else
{
user = await _dbContext.Users.FirstOrDefaultAsync(u => u.UserName == model.LoginOrEmail);
else {
user = await _dbContext.Users.FirstOrDefaultAsync( u => u.UserName == model.LoginOrEmail);
}
// Don't reveal that the user does not exist or is not confirmed
@ -892,16 +890,13 @@ namespace Yavsc.Controllers
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// Send an email with this link
var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var f = this.HttpContext.Features;
var callbackUrl = _siteSettings.ExternalUrl + "/Account/ResetPassword/" +
HttpUtility.UrlEncode(user.Id) + "/" + HttpUtility.UrlEncode(code);
var callbackUrl = _siteSettings.Audience + "/Account/ResetPassword/" +
HttpUtility.UrlEncode(user.Id) + "/" + HttpUtility.UrlEncode(code);
var sent = await _emailSender.SendEmailAsync(user.UserName, user.Email, _localizer["Reset Password"],
_localizer["Please reset your password by "] + " <a href=\"" +
callbackUrl + "\" >following this link</a>");
return View("ForgotPasswordConfirmation", sent);
}
// If we got this far, something failed, redisplay form
@ -925,15 +920,8 @@ namespace Yavsc.Controllers
var user = await _userManager.FindByIdAsync(id);
if (user==null) return new BadRequestResult();
if (!await _userManager.VerifyUserTokenAsync(user,
_userManager.Options.Tokens.PasswordResetTokenProvider,
"ResetPassword", code.Replace("%2f","/")))
{
return BadRequest("code");
}
// We just serve the form to reset here.
return View(new ResetPasswordViewModel
{
return View(new ResetPasswordViewModel {
Id = id,
Code = code,
Email = user.Email
@ -958,11 +946,9 @@ namespace Yavsc.Controllers
// Don't reveal that the user does not exist
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
}
if (user.Id != id) return BadRequest("userid");
// code : "CfDJ8DmPlC3R8%2fNMqGlHZHZMwbjaXxgD3GW3H75Ubt+4Sbw%2fn%2fdg9X8Bll+CLIh%2fquI+Z96XEkx7bfrZiB+wpPb+b5%2ffgzgy+cQnKfX9J7%2fLNro+F3uE5JkXSlUc1WqVW2mVQrpWHjx1Dbn2n77TTGym3ttQoECsTR%2foo27dW9U11pmRJuTiwPBJZBOt0ffIRmgDDHh2f0VySTQEwjfRiLdCwctL%2fmh21ympJMKJl5PZnTVs"
var result = await _userManager.ResetPasswordAsync(user,
code.Replace("%2f","/"), model.Password);
HttpUtility.UrlDecode(code), model.Password);
if (result.Succeeded)
{
@ -1100,23 +1086,11 @@ namespace Yavsc.Controllers
}
[HttpGet, Authorize("AdministratorOnly")]
public IActionResult AdminDelete(string id, string? returnUrl=null)
public IActionResult AdminDelete(string id)
{
return View(new UnregisterViewModel { UserId = id, ReturnUrl = returnUrl });
return View(new UnregisterViewModel { UserId = id });
}
[HttpPost, Authorize("AdministratorOnly")]
public async Task<IActionResult> AdminDelete(UnregisterViewModel model)
{
var result = await DeleteUser(model.UserId);
if (!result.Succeeded)
{
AddErrors(result);
return new BadRequestObjectResult(ModelState);
}
return View();
}
[HttpPost, Authorize]
public async Task<IActionResult> Delete(UnregisterViewModel model)
{
@ -1144,6 +1118,21 @@ namespace Yavsc.Controllers
return await _userManager.DeleteAsync(user);
}
[HttpPost, Authorize("AdministratorOnly")]
public async Task<IActionResult> AdminDelete(UnregisterViewModel model)
{
var result = await DeleteUser(model.UserId);
if (!result.Succeeded)
{
AddErrors(result);
return new BadRequestObjectResult(ModelState);
}
return View();
}
#region Helpers
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
@ -1152,5 +1141,15 @@ namespace Yavsc.Controllers
}
}
private async Task<ApplicationUser> GetCurrentUserAsync()
{
return await GetCurrentUserAsync(HttpContext.User.GetUserId());
}
private async Task<ApplicationUser> GetCurrentUserAsync(string id)
{
return await _userManager.FindByIdAsync(id);
}
#endregion
}
}

View File

@ -51,7 +51,7 @@ namespace Yavsc.Controllers
IOptions<GoogleAuthSettings> googleSettings,
IOptions<PayPalSettings> paypalSettings,
IOptions<CompanyInfoSettings> cinfoSettings,
IStringLocalizer<ManageController> SR,
IStringLocalizer<Yavsc.YavscLocalization> SR,
ICalendarManager calendarManager,
ILoggerFactory loggerFactory)
{
@ -625,7 +625,7 @@ namespace Yavsc.Controllers
else _dbContext.Performers.Add(model);
_dbContext.SaveChanges(User.GetUserId());
// Give this user the Performer role
if (!User.IsInMsRole("Performer"))
if (!User.IsInRole("Performer"))
await _userManager.AddToRoleAsync(user, "Performer");
var message = ManageMessageId.SetActivitySuccess;

View File

@ -30,26 +30,11 @@ namespace Yavsc.Controllers
this._dbContext = context;
}
public async Task<IActionResult> Role(string id)
{
var role = await _roleManager.FindByIdAsync(id);
if (role == null) return NotFound();
RoleUserCollection roleUserCollection = new RoleUserCollection
{
Id = id,
Name = role.Name,
Users = (await this._userManager.GetUsersInRoleAsync(role.Name))
.Select(u => new UserInfo (id, u.UserName, u.Email, u.Avatar)).ToArray()
};
return View(roleUserCollection);
}
private async Task<bool> EnsureRoleList()
{
private async Task<bool> EnsureRoleList () {
// ensure all roles existence
foreach (string roleName in new string[] {
Constants.AdminGroupName,
Constants.StarGroupName,
Constants.StarGroupName,
Constants.PerformerGroupName,
Constants.FrontOfficeGroupName,
Constants.StarHunterGroupName,
@ -65,8 +50,8 @@ namespace Yavsc.Controllers
return false;
}
}
return true;
return true;
}
/// <summary>
/// Gives the (new if was not existing) administrator role
@ -80,21 +65,20 @@ namespace Yavsc.Controllers
{
// If some amdin already exists, make this method disapear
var admins = await _userManager.GetUsersInRoleAsync(Constants.AdminGroupName);
if (admins != null && admins.Count > 0)
if (admins != null && admins.Count > 0)
{
// All is ok, nothing to do here.
if (User.IsInMsRole(Constants.AdminGroupName))
if (User.IsInRole(Constants.AdminGroupName))
{
return Ok(new { message = "you already got it." });
}
return NotFound();
}
var user = await _userManager.FindByIdAsync(User.GetUserId());
// check all user groups exist
if (!await EnsureRoleList())
{
if (!await EnsureRoleList()) {
ModelState.AddModelError(null, "Could not ensure role list existence. aborting.");
return new BadRequestObjectResult(ModelState);
}
@ -109,7 +93,7 @@ namespace Yavsc.Controllers
return Ok(new { message = "you owned it." });
}
[Authorize("AdministratorOnly")]
[Authorize(Roles = Constants.AdminGroupName)]
[Produces("application/json")]
public async Task<IActionResult> Index()
{
@ -119,12 +103,11 @@ namespace Yavsc.Controllers
var youAreAdmin = await _userManager.IsInRoleAsync(
await _userManager.FindByIdAsync(User.GetUserId()),
Constants.AdminGroupName);
var roles = await _roleManager.Roles.Select(x => new RoleInfo
{
var roles = await _roleManager.Roles.Select(x => new RoleInfo {
Id = x.Id,
Name = x.Name
}).ToArrayAsync();
Name = x.Name
}).ToArrayAsync();
foreach (var role in roles)
{
var uinrole = await _userManager.GetUsersInRoleAsync(role.Name);
@ -132,9 +115,9 @@ namespace Yavsc.Controllers
role.UserCount = uinrole.Count();
}
var assembly = GetType().Assembly;
ViewBag.ThisAssembly = assembly.FullName;
ViewBag.RunTimeVersion = assembly.ImageRuntimeVersion;
var rolesArray = roles.ToArray();
ViewBag.ThisAssembly = assembly.FullName;
ViewBag.RunTimeVersion = assembly.ImageRuntimeVersion;
var rolesArray = roles.ToArray();
return View(new AdminViewModel
{
Roles = rolesArray,
@ -148,7 +131,7 @@ namespace Yavsc.Controllers
public IActionResult Enroll(string roleName)
{
ViewBag.UserId = new SelectList(_dbContext.Users, "Id", "UserName");
return View(new EnrolerViewModel { RoleName = roleName });
return View(new EnrolerViewModel{ RoleName = roleName });
}
[Authorize("AdministratorOnly")]
@ -157,8 +140,8 @@ namespace Yavsc.Controllers
{
if (ModelState.IsValid)
{
var newAdmin = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == model.EnroledUserId);
if (newAdmin == null) return NotFound();
var newAdmin = await _dbContext.Users.FirstOrDefaultAsync(u=>u.Id==model.EnroledUserId);
if (newAdmin==null) return NotFound();
var addToRoleResult = await _userManager.AddToRoleAsync(newAdmin, model.RoleName);
if (addToRoleResult.Succeeded)
{
@ -173,10 +156,10 @@ namespace Yavsc.Controllers
[Authorize("AdministratorOnly")]
public async Task<IActionResult> Fire(string roleName, string userId)
{
var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
var user = await _dbContext.Users.FirstOrDefaultAsync(u=>u.Id==userId);
if (user == null) return NotFound();
return View(new FireViewModel { RoleName = roleName, EnroledUserId = userId, EnroledUserName = user.UserName });
return View(new FireViewModel{ RoleName = roleName, EnroledUserId = userId, EnroledUserName = user.UserName });
}
[Authorize("AdministratorOnly")]
@ -185,8 +168,8 @@ namespace Yavsc.Controllers
{
if (ModelState.IsValid)
{
var oldEnroled = await _dbContext.Users.FirstOrDefaultAsync(u => u.Id == model.EnroledUserId);
if (oldEnroled == null) return NotFound();
var oldEnroled = await _dbContext.Users.FirstOrDefaultAsync(u=>u.Id==model.EnroledUserId);
if (oldEnroled==null) return NotFound();
var removeFromRole = await _userManager.RemoveFromRoleAsync(oldEnroled, model.RoleName);
if (removeFromRole.Succeeded)
{

View File

@ -1,72 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Yavsc.Models;
namespace Yavsc.Controllers
{
[Authorize()]
public class DatabaseController : Controller
{
private readonly ILogger<DatabaseController> logger;
private readonly ApplicationDbContext applicationDbContext;
public DatabaseController(ApplicationDbContext applicationDbContext,
ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger<DatabaseController>();
this.applicationDbContext = applicationDbContext;
}
public IActionResult GetBlog()
{
return ReturnDbSet(applicationDbContext.BlogSpot);
}
public IActionResult GetUsers()
{
return ReturnDbSet(applicationDbContext.Users);
}
public IActionResult GeActivities()
{
return ReturnDbSet(applicationDbContext.Activities);
}
public IActionResult ImportUsers(String usersJson)
{
return DBSetImportFromJson(applicationDbContext.Users, usersJson);
}
public IActionResult ImportBlog(String blogJson)
{
return DBSetImportFromJson(applicationDbContext.BlogSpot, blogJson);
}
IActionResult ReturnDbSet<T>(DbSet<T> dbSet) where T : class
{
var data = dbSet.ToArray();
return Ok(data);
}
private IActionResult DBSetImportFromJson<T>(DbSet<T> dbSet, string usersJson) where T : class
{
int failures = 0;
var input = JsonConvert.DeserializeObject<T[]>(usersJson);
foreach (var user in input)
{
try
{
dbSet.Add(user);
}
catch (Exception ex)
{
failures++;
}
}
return Ok(failures);
}
}
}

View File

@ -8,7 +8,6 @@ using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
@ -59,8 +58,8 @@ namespace Yavsc.Controllers
}
private async Task SetupView(Announce announce)
{
ViewBag.IsAdmin = User.IsInMsRole(Constants.AdminGroupName);
ViewBag.IsPerformer = User.IsInMsRole(Constants.PerformerGroupName);
ViewBag.IsAdmin = User.IsInRole(Constants.AdminGroupName);
ViewBag.IsPerformer = User.IsInRole(Constants.PerformerGroupName);
ViewBag.AllowEdit = announce==null || announce.Id<=0 || !_authorizationService.AuthorizeAsync(User,announce,new EditPermission()).IsFaulted;
List<SelectListItem> dl = new List<SelectListItem>();
var rnames = System.Enum.GetNames(typeof(Reason));
@ -79,17 +78,18 @@ namespace Yavsc.Controllers
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Announce announce)
{
await SetupView(announce);
if (ModelState.IsValid)
{
// Only allow admin to create corporate annonces
if (announce.For == Reason.Corporate && ! User.IsInMsRole(Constants.AdminGroupName))
if (announce.For == Reason.Corporate && ! ViewBag.IsAdmin)
{
ModelState.AddModelError("For", _localizer["YourNotAdmin"]);
return View(announce);
}
// Only allow performers to create ServiceProposal
if (announce.For == Reason.ServiceProposal && ! User.IsInMsRole(Constants.PerformerGroupName))
if (announce.For == Reason.ServiceProposal && ! ViewBag.IsAdmin)
{
ModelState.AddModelError("For", _localizer["YourNotAPerformer"]);
return View(announce);
@ -99,7 +99,6 @@ namespace Yavsc.Controllers
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
await SetupView(announce);
return View(announce);
}

View File

@ -74,7 +74,7 @@ namespace Yavsc.Controllers
{
var blog = await blogSpotService.Details(User, id.Value);
ViewData["apicmtctlr"] = "/api/blogcomments";
ViewData["moderatoFlag"] = User.IsInMsRole(Constants.BlogModeratorGroupName);
ViewData["moderatoFlag"] = User.IsInRole(Constants.BlogModeratorGroupName);
return View(blog);

View File

@ -15,11 +15,11 @@ namespace Yavsc.Controllers
public class ActivityController : Controller
{
private readonly ApplicationDbContext _context;
readonly IStringLocalizer<ActivityController> SR;
readonly IStringLocalizer<Yavsc.YavscLocalization> SR;
readonly ILogger logger;
public ActivityController(ApplicationDbContext context,
IStringLocalizer<ActivityController> SR,
IStringLocalizer<Yavsc.YavscLocalization> SR,
ILoggerFactory loggerFactory)
{
_context = context;
@ -50,8 +50,9 @@ namespace Yavsc.Controllers
private List<SelectListItem> GetEligibleParent(string code)
{
// eligibles are those
// who are not in descendence
// who are not in descendants
//
var acts = _context.Activities.Where(
a => a.Code != code
).Select(a => new SelectListItem
@ -67,13 +68,13 @@ namespace Yavsc.Controllers
var pi = acts.FirstOrDefault(i => i.Value == existing.ParentCode);
if (pi!=null) pi.Selected = true;
else nullItem.Selected = true;
RecursivelyFilterChild(acts, existing);
RecFilterChild(acts, existing);
return acts;
}
/// <summary>
/// Filters a activity selection list
/// in order to exclude any descendant
/// in order to exculde any descendant
/// from the eligible list at the <c>Parent</c> property.
/// WARN! results in a infinite loop when
/// data is corrupted and there is a circularity
@ -81,19 +82,22 @@ namespace Yavsc.Controllers
/// </summary>
/// <param name="list"></param>
/// <param name="activity"></param>
private static void RecursivelyFilterChild(List<SelectListItem> list, Activity activity)
private static void RecFilterChild(List<SelectListItem> list, Activity activity)
{
if (activity == null) return;
if (activity.Children == null) return;
if (list.Count == 0) return;
foreach (var child in activity.Children)
{
RecursivelyFilterChild(list, child);
RecFilterChild(list, child);
var rem = list.FirstOrDefault(i => i.Value == child.Code);
if (rem != null) list.Remove(rem);
}
}
// GET: Activity/Details/5
public IActionResult Details(string id)
{

View File

@ -1,6 +1,3 @@
using IdentityServer8.EntityFramework.DbContexts;
using IdentityServer8.EntityFramework.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
@ -11,21 +8,19 @@ using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
[Authorize("AdministratorOnly")]
public class ClientController : Controller
{
private readonly ConfigurationDbContext _context;
private readonly ApplicationDbContext _context;
public ClientController(ConfigurationDbContext context)
public ClientController(ApplicationDbContext context)
{
_context = context;
_context = context;
}
// GET: Client
public async Task<IActionResult> Index()
{
return View(await _context.Clients.Include(c=>c.AllowedGrantTypes)
.Include(c=>c.RedirectUris).ToListAsync());
return View(await _context.Applications.ToListAsync());
}
// GET: Client/Details/5
@ -36,11 +31,7 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Clients.Include(
c => c.ClientSecrets
).Include(c=>c.AllowedGrantTypes)
.Include(c=>c.RedirectUris)
.SingleAsync(m => m.ClientId == id);
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
if (client == null)
{
return NotFound();
@ -62,10 +53,9 @@ namespace Yavsc.Controllers
{
if (ModelState.IsValid)
{
if (string.IsNullOrWhiteSpace(client.ClientId))
client.ClientId = Guid.NewGuid().ToString();
_context.Clients.Add(client);
await _context.SaveChangesAsync();
client.Id = Guid.NewGuid().ToString();
_context.Applications.Add(client);
await _context.SaveChangesAsync(User.GetUserId());
return RedirectToAction("Index");
}
SetAppTypesInputValues();
@ -73,16 +63,16 @@ namespace Yavsc.Controllers
}
private void SetAppTypesInputValues()
{
IEnumerable<SelectListItem> types = new SelectListItem[] {
IEnumerable<SelectListItem> types = new SelectListItem[] {
new SelectListItem {
Text = ApplicationTypes.JavaScript.ToString(),
Value = ((int) ApplicationTypes.JavaScript).ToString() },
new SelectListItem {
Text = ApplicationTypes.NativeConfidential.ToString(),
Value = ((int) ApplicationTypes.NativeConfidential).ToString()
Value = ((int) ApplicationTypes.NativeConfidential).ToString()
}
};
ViewData["AccessTokenType"] = types;
ViewData["Type"] = types;
}
// GET: Client/Edit/5
public async Task<IActionResult> Edit(string id)
@ -92,7 +82,7 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
if (client == null)
{
return NotFound();
@ -109,7 +99,7 @@ namespace Yavsc.Controllers
if (ModelState.IsValid)
{
_context.Update(client);
await _context.SaveChangesAsync();
await _context.SaveChangesAsync(User.GetUserId());
return RedirectToAction("Index");
}
return View(client);
@ -124,7 +114,7 @@ namespace Yavsc.Controllers
return NotFound();
}
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
if (client == null)
{
return NotFound();
@ -138,9 +128,9 @@ namespace Yavsc.Controllers
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string id)
{
Client client = await _context.Clients.SingleAsync(m => m.ClientId == id);
_context.Clients.Remove(client);
await _context.SaveChangesAsync();
Client client = await _context.Applications.SingleAsync(m => m.Id == id);
_context.Applications.Remove(client);
await _context.SaveChangesAsync(User.GetUserId());
return RedirectToAction("Index");
}
}

View File

@ -16,8 +16,6 @@ namespace Yavsc.Controllers
using Models.Workflow;
using Services;
using Yavsc.Interface;
using Yavsc.Models.Billing;
using Yavsc.Models.Haircut;
using Yavsc.Server.Helpers;
using Yavsc.Settings;
@ -28,7 +26,7 @@ namespace Yavsc.Controllers
protected GoogleAuthSettings _googleSettings;
protected IYavscMessageSender _MessageSender;
protected ITrueEmailSender _emailSender;
protected IStringLocalizer<CommandController> _localizer;
protected IStringLocalizer _localizer;
protected SiteSettings _siteSettings;
protected SmtpSettings _smtpSettings;
protected ICalendarManager _calendarManager;
@ -38,7 +36,7 @@ namespace Yavsc.Controllers
IYavscMessageSender messageSender,
UserManager<ApplicationUser> userManager,
ICalendarManager calendarManager,
IStringLocalizer<CommandController> localizer,
IStringLocalizer<YavscLocalization> localizer,
ITrueEmailSender emailSender,
IOptions<SmtpSettings> smtpSettings,
IOptions<SiteSettings> siteSettings,

View File

@ -90,7 +90,7 @@ namespace Yavsc.Controllers
public IActionResult Create(UserActivity userActivity)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (!User.IsInMsRole("Administrator"))
if (!User.IsInRole("Administrator"))
if (uid != userActivity.UserId)
ModelState.AddModelError("User","You're not admin.");
if (userActivity.UserId == null) userActivity.UserId = uid;
@ -133,7 +133,7 @@ namespace Yavsc.Controllers
[ValidateAntiForgeryToken]
public IActionResult Edit(UserActivity userActivity)
{
if (!User.IsInMsRole("Administrator"))
if (!User.IsInRole("Administrator"))
if (User.GetUserId() != userActivity.UserId)
ModelState.AddModelError("User","You're not admin.");
if (ModelState.IsValid)
@ -162,7 +162,7 @@ namespace Yavsc.Controllers
{
return NotFound();
}
if (!User.IsInMsRole("Administrator"))
if (!User.IsInRole("Administrator"))
if (User.GetUserId() != userActivity.UserId)
ModelState.AddModelError("User","You're not admin.");
return View(userActivity);
@ -175,7 +175,7 @@ namespace Yavsc.Controllers
{
if (!ModelState.IsValid)
return new BadRequestObjectResult(ModelState);
if (!User.IsInMsRole("Administrator"))
if (!User.IsInRole("Administrator"))
if (User.GetUserId() != userActivity.UserId) {
ModelState.AddModelError("User","You're not admin.");
return RedirectToAction("Index");

View File

@ -25,7 +25,7 @@ namespace Yavsc.Controllers
UserManager<ApplicationUser> userManager,
IBillingService billing,
ILoggerFactory loggerFactory,
IStringLocalizer<FrontOfficeController> SR)
IStringLocalizer<Yavsc.YavscLocalization> SR)
{
_context = context;
_userManager = userManager;

View File

@ -7,7 +7,7 @@ using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
[Authorize("AdministratorOnly")]
[Authorize(Roles="Administrator")]
public class SIRENExceptionsController : Controller
{
private readonly ApplicationDbContext _context;

View File

@ -1,175 +0,0 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc.Helpers;
using Yavsc.Models;
using Yavsc.Models.Messaging;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
[Produces("application/json")]
[Route("api/dimiss")]
public class DimissClicksApiController : Controller
{
private readonly ApplicationDbContext _context;
public DimissClicksApiController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/DimissClicksApi
[HttpGet]
public IEnumerable<DismissClicked> GetDismissClicked()
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
return _context.DismissClicked.Where(d=>d.UserId == uid);
}
[HttpGet("click/{noteid}"),AllowAnonymous]
public async Task<IActionResult> Click(long noteid )
{
if (User.IsSignedIn())
return await PostDismissClicked(new DismissClicked { NotificationId= noteid, UserId = User.GetUserId()});
await HttpContext.Session.LoadAsync();
var clicked = HttpContext.Session.GetString("clicked");
if (clicked == null) {
HttpContext.Session.SetString("clicked",noteid.ToString());
} else HttpContext.Session.SetString("clicked",$"{clicked}:{noteid}");
await HttpContext.Session.CommitAsync();
return Ok();
}
// GET: api/DimissClicksApi/5
[HttpGet("{id}", Name = "GetDismissClicked")]
public async Task<IActionResult> GetDismissClicked([FromRoute] string id)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (uid != id) return new ChallengeResult();
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
DismissClicked DismissClicked = await _context.DismissClicked.SingleAsync(m => m.UserId == id);
if (DismissClicked == null)
{
return NotFound();
}
return Ok(DismissClicked);
}
// PUT: api/DimissClicksApi/5
[HttpPut("{id}")]
public async Task<IActionResult> PutDismissClicked([FromRoute] string id, [FromBody] DismissClicked DismissClicked)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (uid != id || uid != DismissClicked.UserId) return new ChallengeResult();
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != DismissClicked.UserId)
{
return BadRequest();
}
_context.Entry(DismissClicked).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync(User.GetUserId());
}
catch (DbUpdateConcurrencyException)
{
if (!DismissClickedExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return new StatusCodeResult(StatusCodes.Status204NoContent);
}
// POST: api/DimissClicksApi
[HttpPost]
public async Task<IActionResult> PostDismissClicked([FromBody] DismissClicked DismissClicked)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (uid != DismissClicked.UserId) return new ChallengeResult();
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.DismissClicked.Add(DismissClicked);
try
{
await _context.SaveChangesAsync(User.GetUserId());
}
catch (DbUpdateException)
{
if (DismissClickedExists(DismissClicked.UserId))
{
return new StatusCodeResult(StatusCodes.Status409Conflict);
}
else
{
throw;
}
}
return CreatedAtRoute("GetDismissClicked", new { id = DismissClicked.UserId }, DismissClicked);
}
// DELETE: api/DimissClicksApi/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteDismissClicked([FromRoute] string id)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (!User.IsInRole("Administrator"))
if (uid != id) return new ChallengeResult();
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
DismissClicked DismissClicked = await _context.DismissClicked.SingleAsync(m => m.UserId == id);
if (DismissClicked == null)
{
return NotFound();
}
_context.DismissClicked.Remove(DismissClicked);
await _context.SaveChangesAsync(User.GetUserId());
return Ok(DismissClicked);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
base.Dispose(disposing);
}
private bool DismissClickedExists(string id)
{
return _context.DismissClicked.Count(e => e.UserId == id) > 0;
}
}
}

View File

@ -5,7 +5,7 @@ using Yavsc.Controllers.Generic;
namespace Yavsc.Controllers
{
[Authorize("Performer")]
[Authorize(Roles="Performer")]
public class BrusherProfileController : SettingsController<BrusherProfile>
{
public BrusherProfileController(ApplicationDbContext context) : base(context)

View File

@ -18,9 +18,11 @@ namespace Yavsc.Controllers
using System.Globalization;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
using Yavsc.Models.Messaging;
using PayPal.PayPalAPIInterfaceService.Model;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.UI.Services;
using Yavsc.Interface;
using Yavsc.Settings;
using Yavsc.Abstract.Models.Messaging;
@ -29,15 +31,12 @@ namespace Yavsc.Controllers
public class HairCutCommandController : CommandController
{
readonly PayPalSettings payPalSettings;
private readonly IStringLocalizer<HairCutQuery> haircutLocalizer;
public HairCutCommandController(ApplicationDbContext context,
IOptions<PayPalSettings> payPalSettings,
IOptions<GoogleAuthSettings> googleSettings,
IYavscMessageSender GCMSender,
UserManager<ApplicationUser> userManager,
IStringLocalizer<HairCutQuery> haircutLocalizer,
IStringLocalizer<CommandController> localizer,
IStringLocalizer<Yavsc.YavscLocalization> localizer,
ITrueEmailSender emailSender,
IOptions<SmtpSettings> smtpSettings,
IOptions<SiteSettings> siteSettings,
@ -46,7 +45,6 @@ namespace Yavsc.Controllers
calManager, localizer, emailSender, smtpSettings, siteSettings, loggerFactory)
{
this.payPalSettings = payPalSettings.Value;
this.haircutLocalizer = haircutLocalizer;
}
@ -265,7 +263,7 @@ namespace Yavsc.Controllers
model.SelectedProfile = brusherProfile;
model.Client = await _userManager.FindByIdAsync(uid);
_logger.LogInformation(JsonConvert.SerializeObject(model));
var yaev = model.CreateNewHairCutQueryEvent(this.haircutLocalizer);
var yaev = model.CreateNewHairCutQueryEvent(_localizer);
if (pro.AcceptPublicContact)
{

View File

@ -16,11 +16,11 @@ namespace Yavsc.Controllers
public class ProjectController : Controller
{
private readonly ApplicationDbContext _context;
readonly IStringLocalizer<ProjectController> _localizer;
readonly IStringLocalizer<Yavsc.YavscLocalization> _localizer;
readonly IStringLocalizer<BugController> _bugLocalizer;
public ProjectController(ApplicationDbContext context,
IStringLocalizer<ProjectController> localizer,
IStringLocalizer<Yavsc.YavscLocalization> localizer,
IStringLocalizer<BugController> bugLocalizer
)
{

View File

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Musical;
using Yavsc.Server.Helpers;
namespace Yavsc.Controllers
{
@ -61,7 +60,7 @@ namespace Yavsc.Controllers
ViewBag.YetAvailableInstruments = _context.Instrument.Select(k=>new SelectListItem
{ Text = k.Name, Value = k.Id.ToString(), Disabled = actual.Contains(k.Id) });
if (User.IsInMsRole("Administrator"))
if (User.IsInRole("Administrator"))
ViewBag.OwnerIds = new SelectList(_context.Performers, "PerformerId", "Profile");
return View();
}

View File

@ -64,7 +64,7 @@ namespace Yavsc.Controllers
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (ModelState.IsValid)
{
if (model.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName))
if (model.UserId != uid) if (!User.IsInRole(Constants.AdminGroupName))
return new ChallengeResult();
_context.Instrumentation.Add(model);
@ -82,7 +82,7 @@ namespace Yavsc.Controllers
{
return NotFound();
}
if (id != uid) if (!User.IsInMsRole(Constants.AdminGroupName))
if (id != uid) if (!User.IsInRole(Constants.AdminGroupName))
return new ChallengeResult();
Instrumentation musicianSettings = await _context.Instrumentation.SingleAsync(m => m.UserId == id);
if (musicianSettings == null)
@ -98,7 +98,7 @@ namespace Yavsc.Controllers
public async Task<IActionResult> Edit(Instrumentation musicianSettings)
{
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName))
if (musicianSettings.UserId != uid) if (!User.IsInRole(Constants.AdminGroupName))
return new ChallengeResult();
if (ModelState.IsValid)
{
@ -124,7 +124,7 @@ namespace Yavsc.Controllers
return NotFound();
}
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName))
if (musicianSettings.UserId != uid) if (!User.IsInRole(Constants.AdminGroupName))
return new ChallengeResult();
return View(musicianSettings);
}
@ -137,7 +137,7 @@ namespace Yavsc.Controllers
Instrumentation musicianSettings = await _context.Instrumentation.SingleAsync(m => m.UserId == id);
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName))
if (musicianSettings.UserId != uid) if (!User.IsInRole(Constants.AdminGroupName))
return new ChallengeResult();

View File

@ -2,11 +2,6 @@ using System.Diagnostics;
using System.Globalization;
using Google.Apis.Util.Store;
using IdentityServer8;
using Microsoft.Extensions.DependencyInjection;
using IdentityServer8.Stores;
using IdentityServer8.EntityFramework;
using IdentityServer8.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
@ -32,18 +27,13 @@ using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.Configuration;
using IdentityModel;
using Yavsc.Interfaces;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Npgsql;
using System.Reflection;
using IdentityServer8.EntityFramework.DbContexts;
using IdentityServer8.EntityFramework.Mappers;
namespace Yavsc.Extensions;
public static class HostingExtensions
{
public static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
{
IServiceCollection services = LoadConfiguration(builder);
@ -58,16 +48,15 @@ public static class HostingExtensions
_ = services.AddSingleton<IConnexionManager, HubConnectionManager>();
_ = services.AddSingleton<ILiveProcessor, LiveProcessor>();
_ = services.AddTransient<IFileSystemAuthManager, FileSystemAuthManager>();
AddIdentityDBAndStores(builder)
.AddDefaultTokenProviders();
AddIdentityDBAndStores(builder).AddDefaultTokenProviders();
AddIdentityServer(builder);
services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
});
services.AddMvc(config =>
{
/* var policy = new AuthorizationPolicyBuilder()
@ -118,9 +107,7 @@ public static class HostingExtensions
AddAuthentication(builder);
services.AddTransient<RoleManager<IdentityRole>>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore<IdentityRole, ApplicationDbContext>>();
// accepts any access token issued by identity server
return builder.Build();
}
@ -129,22 +116,16 @@ public static class HostingExtensions
{
IServiceCollection services = builder.Services;
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"),
options => options.MigrationsAssembly("Yavsc")
);
}
);
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
return services.AddIdentity<ApplicationUser, IdentityRole>(
options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.PreferredUserName;
options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType;
}
)
.AddEntityFrameworkStores<ApplicationDbContext>();
.AddEntityFrameworkStores<ApplicationDbContext>();
}
private static void AddYavscPolicies(IServiceCollection services)
@ -156,20 +137,17 @@ public static class HostingExtensions
policy.RequireAuthenticatedUser()
.RequireClaim("scope", "scope2");
});
options.AddPolicy("Performer", policy =>
{
policy
.RequireAuthenticatedUser()
.RequireClaim(Constants.RoleClaimType,
new string[] { Constants.PerformerGroupName, Constants.AdminGroupName })
;
.RequireClaim(JwtClaimTypes.Role, "Performer");
});
options.AddPolicy("AdministratorOnly", policy =>
{
_ = policy
.RequireAuthenticatedUser()
.RequireClaim(Constants.RoleClaimType, Constants.AdminGroupName);
.RequireClaim(JwtClaimTypes.Role, Constants.AdminGroupName);
});
options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName));
@ -201,11 +179,11 @@ public static class HostingExtensions
//LoadGoogleConfig(builder.Configuration);
var services = builder.Services;
_ = services.AddControllersWithViews()
.AddNewtonsoftJson();
services.Configure<SiteSettings>(siteSection);
services.Configure<SmtpSettings>(smtpSection);
services.Configure<PayPalSettings>(paypalSection);
@ -217,31 +195,28 @@ public static class HostingExtensions
private static void AddAuthentication(WebApplicationBuilder builder)
{
IServiceCollection services = builder.Services;
IConfigurationRoot configurationRoot = builder.Configuration;
IServiceCollection services=builder.Services;
IConfigurationRoot configurationRoot=builder.Configuration;
string? googleClientId = configurationRoot["Authentication:Google:ClientId"];
string? googleClientSecret = configurationRoot["Authentication:Google:ClientSecret"];
var authenticationBuilder = services.AddAuthentication();
if (googleClientId != null && googleClientSecret != null)
authenticationBuilder.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
if (googleClientId!=null && googleClientSecret!=null)
authenticationBuilder.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
// register your IdentityServer with Google at https://console.developers.google.com
// enable the Google+ API
// set the redirect URI to https://localhost:5001/signin-google
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
// register your IdentityServer with Google at https://console.developers.google.com
// enable the Google+ API
// set the redirect URI to https://localhost:5001/signin-google
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
}
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
{
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
@ -251,30 +226,13 @@ public static class HostingExtensions
// see https://IdentityServer8.readthedocs.io/en/latest/topics/resources.html
options.EmitStaticAudienceClaim = true;
})
//.AddInMemoryIdentityResources(Config.IdentityResources)
//.AddInMemoryClients(Config.TestingClients)
//.AddInMemoryApiScopes(Config.TestingApiScopes)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddAspNetIdentity<ApplicationUser>();
builder.Services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject;
options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.Name;
options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType;
});
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryClients(Config.TestingClients)
.AddClientStore<ClientStore>()
.AddInMemoryApiScopes(Config.TestingApiScopes)
.AddAspNetIdentity<ApplicationUser>()
;
if (builder.Environment.IsDevelopment())
{
identityServerBuilder.AddDeveloperSigningCredential();
@ -335,8 +293,6 @@ public static class HostingExtensions
public async static Task<WebApplication> ConfigurePipeline(this WebApplication app)
{
ILoggerFactory loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<Program>();
if (app.Environment.IsDevelopment())
{
@ -345,34 +301,22 @@ public static class HostingExtensions
else
{
app.UseExceptionHandler("/Home/Error");
try
using (var scope = app.Services.CreateScope())
{
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
}
catch (Exception ex)
{
logger.LogError("Error migrating the database : {0}", ex);
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
}
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/robots.txt"))
{
app.Use(async (context, next) => {
if (context.Request.Path.StartsWithSegments("/robots.txt")) {
var robotsTxtPath = System.IO.Path.Combine(app.Environment.WebRootPath, $"robots.txt");
string output = "User-agent: * \nDisallow: /";
if (File.Exists(robotsTxtPath))
{
if (File.Exists(robotsTxtPath)) {
output = await File.ReadAllTextAsync(robotsTxtPath);
}
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync(output);
}
else await next();
} else await next();
});
app.UseStaticFiles();
app.UseRouting();
@ -382,69 +326,23 @@ public static class HostingExtensions
app.MapDefaultControllerRoute();
//app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
WorkflowHelpers.ConfigureBillingService();
var services = app.Services;
ILoggerFactory loggerFactory = services.GetRequiredService<ILoggerFactory>();
var siteSettings = services.GetRequiredService<IOptions<SiteSettings>>();
var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>();
var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>();
var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>();
var localization = services.GetRequiredService<IStringLocalizer<Startup>>();
var localization = services.GetRequiredService<IStringLocalizer<YavscLocalization>>();
Startup.Configure(app, siteSettings, smtpSettings,
payPalSettings, googleAuthSettings, localization, loggerFactory,
app.Environment.EnvironmentName);
app.ConfigureFileServerApp();
app.InitializeDatabase();
return app;
}
private static void InitializeDatabase(this IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
try
{
context.Database.Migrate();
if (!context.Clients.Any())
{
foreach (var client in Config.Clients)
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.IdentityResources)
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiScopes.Any())
{
foreach (var resource in Config.ApiScopes)
{
context.ApiScopes.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
catch (InvalidOperationException ex)
{
app.Properties["DegradedDBContext"] = ex.Message;
}
}
}
static void LoadGoogleConfig(IConfigurationRoot configuration)
{
@ -461,7 +359,7 @@ public static class HostingExtensions
Config.GServiceAccount = JsonConvert.DeserializeObject<GoogleServiceAccount>(safile.OpenText().ReadToEnd());
}
}
public static IApplicationBuilder ConfigureFileServerApp(this IApplicationBuilder app,
bool enableDirectoryBrowsing = false)
{

View File

@ -1,6 +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.Server.Helpers;
@ -32,7 +35,7 @@ public class PermissionHandler : IAuthorizationHandler
{
context.Succeed(requirement);
}
else if (context.User.IsInMsRole("Administrator"))
else if (context.User.IsInRole("Administrator"))
{
context.Succeed(requirement);
}

View File

@ -34,7 +34,7 @@ namespace Yavsc.Helpers
public static HairCutQueryEvent CreateNewHairCutQueryEvent(this HairCutQuery query,
IStringLocalizer<HairCutQuery> SR)
IStringLocalizer SR)
{
string evdate = query.EventDate?.ToString("dddd dd/MM/yyyy à hh:mm")??"[pas de date spécifiée]";
string address = query.Location?.Address??"[pas de lieu spécifié]";
@ -42,7 +42,7 @@ namespace Yavsc.Helpers
string strprestation = query.Description;
var yaev = query.CreateEvent("NewHairCutQuery",
string.Format(SR["HairCutQueryValidation"],query.Client.UserName),
string.Format(ResourcesHelpers.GlobalLocalizer["HairCutQueryValidation"],query.Client.UserName),
$"{query.Client.Id}");

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