bug fixes

This commit is contained in:
Paul Schneider
2024-11-10 23:12:02 +00:00
parent 86dc1b8a2b
commit f3a63c9e46
28 changed files with 261 additions and 234 deletions

View File

@ -10,29 +10,19 @@ using Yavsc.Attributes.Validation;
using Yavsc.Interfaces;
using Yavsc.Models.Access;
using Yavsc.Models.Relationship;
using Yavsc.ViewModels.Blog;
namespace Yavsc.Models.Blog
{
public class BlogPost : IBlogPost, ICircleAuthorized, ITaggable<long>, IIdentified<long>
public class BlogPost : BlogPostInputViewModel, IBlogPost, ICircleAuthorized, ITaggable<long>, IIdentified<long>
{
[Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name="Identifiant du post")]
public long Id { get; set; }
[Display(Name="Contenu")][YaStringLength(56224)]
public string Content { get; set; }
[Display(Name="Photo")][YaStringLength(1024)]
public string Photo { get; set; }
[YaStringLength(8)]
public string Lang { get; set; }
[Display(Name="Indice de qualité")]
public int Rate { get; set; }
[Display(Name="Titre")][YaStringLength(1024)]
public string Title { get; set; }
[Display(Name="Identifiant de l'auteur")]
[ForeignKey("Author")]
@ -41,8 +31,6 @@ namespace Yavsc.Models.Blog
[Display(Name="Auteur")]
public virtual ApplicationUser Author { set; get; }
[Display(Name="Visible")]
public bool Visible { get; set; }
[Display(Name="Date de création")]
public DateTime DateCreated
@ -68,10 +56,6 @@ namespace Yavsc.Models.Blog
get; set;
}
[InverseProperty("Target")]
[Display(Name="Liste de contrôle d'accès")]
public virtual List<CircleAuthorizationToBlogPost> ACL { get; set; }
public bool AuthorizeCircle(long circleId)
{
return ACL?.Any( i=>i.CircleId == circleId) ?? true;

View File

@ -1,26 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using Yavsc.Models;
namespace Yavsc.Server.Models.Blog
{
public class BlogTrad
{
[Required]
public long PostId { get; set; }
[Required]
public string Lang { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string TraducerId { get; set; }
[ForeignKey("TraducerId"),JsonIgnore]
public ApplicationUser Traducer { set; get; }
}
}

View File

@ -0,0 +1,26 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Yavsc.Models.Access;
namespace Yavsc.ViewModels.Blog
{
public class BlogPostInputViewModel
{
[StringLength(1024)]
public string? Photo { get; set; }
[StringLength(1024)]
public required string Title { get; set; }
[StringLength(56224)]
public required string Content { get; set; }
public bool Visible { get; set; }
[InverseProperty("Target")]
[Display(Name="Liste de contrôle d'accès")]
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
}
}

View File

@ -7,7 +7,8 @@ namespace Yavsc.ViewModels.Relationship
public CirclesViewModel(ICircleAuthorized resource)
{
Target = resource;
TargetTypeName = resource.GetType().Name;
if (resource!=null)
TargetTypeName = resource.GetType().Name;
}
public ICircleAuthorized Target { get; set; }
public string TargetTypeName { get; set; }

View File

@ -65,7 +65,7 @@ namespace Yavsc.ApiControllers
}
_logger.LogInformation($"Receiving files, saved in '{destDir}' (specified as '{subdir}').");
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
var uid = User.GetUserId();
var user = dbContext.Users.Single(
u => u.Id == uid
);

View File

@ -235,9 +235,16 @@ namespace Yavsc.Controllers
/// <summary>
/// Show logout page
/// </summary>
[HttpGet]
[HttpGet][Authorize]
public async Task<IActionResult> Logout(string logoutId)
{
if (string.IsNullOrWhiteSpace(logoutId))
{
if (User.Identity.IsAuthenticated)
{
logoutId = User.GetUserId();
}
}
// build a model so the logout page knows what to display
var vm = await BuildLogoutViewModelAsync(logoutId);
@ -265,9 +272,11 @@ namespace Yavsc.Controllers
{
// delete local authentication cookie
await HttpContext.SignOutAsync();
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
@ -282,6 +291,9 @@ namespace Yavsc.Controllers
return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
}
return View("LoggedOut", vm);
}

View File

@ -60,7 +60,7 @@ namespace Yavsc.Controllers
{
ViewBag.IsAdmin = User.IsInRole(Constants.AdminGroupName);
ViewBag.IsPerformer = User.IsInRole(Constants.PerformerGroupName);
ViewBag.AllowEdit = announce==null || announce.Id<=0 || !_authorizationService.AuthorizeAsync(User,announce,new EditRequirement()).IsFaulted;
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));
var rvalues = System.Enum.GetValues(typeof(Reason));

View File

@ -14,6 +14,8 @@ using Yavsc.Helpers;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using Yavsc.ViewModels.Blog;
// For more information on enabling Web API for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
@ -111,30 +113,35 @@ namespace Yavsc.Controllers
[Authorize()]
public IActionResult Create(string title)
{
var result = new BlogPost{Title=title};
var result = new BlogPostInputViewModel{Title=title,Content=""};
ViewData["PostTarget"]="Create";
SetLangItems();
return View("Edit",result);
return View(result);
}
// POST: Blog/Create
[HttpPost, Authorize, ValidateAntiForgeryToken]
public IActionResult Create(Models.Blog.BlogPost blog)
public IActionResult Create(BlogPostInputViewModel blogInput)
{
blog.Rate = 0;
blog.AuthorId = User.GetUserId();
blog.Id=0;
if (ModelState.IsValid)
{
_context.Blogspot.Add(blog);
BlogPost post = new BlogPost
{
Title = blogInput.Title,
Content = blogInput.Content,
Photo = blogInput.Photo,
Rate = 0,
AuthorId = User.GetUserId()
};
_context.Blogspot.Add(post);
_context.SaveChanges(User.GetUserId());
return RedirectToAction("Index");
}
ModelState.AddModelError("Unknown","Invalid Blog posted ...");
ViewData["PostTarget"]="Create";
return View("Edit",blog);
return View("Edit",blogInput);
}
[Authorize()]
// GET: Blog/Edit/5
public async Task<IActionResult> Edit(long? id)
@ -147,12 +154,11 @@ namespace Yavsc.Controllers
ViewData["PostTarget"]="Edit";
BlogPost blog = _context.Blogspot.Include(x => x.Author).Include(x => x.ACL).Single(m => m.Id == id);
if (blog == null)
{
return NotFound();
}
if (!_authorizationService.AuthorizeAsync(User, blog, new EditRequirement()).IsFaulted)
if (!_authorizationService.AuthorizeAsync(User, blog, new EditPermission()).IsFaulted)
{
ViewBag.ACL = _context.Circle.Where(
c=>c.OwnerId == blog.AuthorId)
@ -180,7 +186,7 @@ namespace Yavsc.Controllers
{
if (ModelState.IsValid)
{
var auth = _authorizationService.AuthorizeAsync(User, blog, new EditRequirement());
var auth = _authorizationService.AuthorizeAsync(User, blog, new EditPermission());
if (!auth.IsFaulted)
{
// saves the change

View File

@ -29,6 +29,7 @@ using Yavsc.Models.Market;
using Yavsc.Models.Workflow;
using Yavsc.Services;
using Yavsc.Settings;
using Yavsc.ViewModels.Auth;
namespace Yavsc.Extensions;
@ -308,7 +309,12 @@ internal static class HostingExtensions
// options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456"));
// options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement()));
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
options.AddPolicy("IsTheAuthor", policy =>
policy.Requirements.Add(new EditPermission()));
});
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
_ = services.AddControllersWithViews()
.AddNewtonsoftJson();
LoadGoogleConfig(builder.Configuration);

View File

@ -0,0 +1,46 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Yavsc.ViewModels.Auth;
namespace Yavsc.Extensions;
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadPermission)
{
if (IsOwner(context.User, context.Resource)
|| IsSponsor(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditPermission || requirement is DeletePermission)
{
if (IsOwner(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
return Task.CompletedTask;
}
private static bool IsOwner(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
private static bool IsSponsor(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
}

View File

@ -117,7 +117,18 @@ namespace Yavsc.Helpers
InternalAnchor a = (InternalAnchor) elt;
sb.AppendFormat("<a name=\"{0}\">{1}</a> ", a.Id, a.XRefLabel);
break;
case "AsciiDocNet.Subscript":
sb.AppendHtml("<sup>");
Subscript sub = (Subscript)elt;
sub.ToHtml(sb);
sb.AppendHtml("</sup>");
break;
case "AsciiDocNet.Superscript":
sb.AppendHtml("<sup>");
Superscript sup = (Superscript)elt;
sup.ToHtml(sb);
sb.AppendHtml("</sup>");
break;
default:
string unsupportedType = elt.GetType().FullName;
throw new InvalidProgramException(unsupportedType);

View File

@ -35,7 +35,6 @@ namespace Yavsc.Models
using Calendar;
using Blog;
using Yavsc.Abstract.Identity;
using Yavsc.Server.Models.Blog;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Yavsc.Server.Models.Calendar;
@ -79,7 +78,6 @@ namespace Yavsc.Models
builder.Entity<Models.Cratie.Option>().HasKey(o => new { o.Code, o.CodeScrutin });
builder.Entity<Notification>().Property(n => n.icon).HasDefaultValue("exclam");
builder.Entity<ChatRoomAccess>().HasKey(p => new { room = p.ChannelName, user = p.UserId });
builder.Entity<BlogTrad>().HasKey(tr => new { post = tr.PostId, lang = tr.Lang });
builder.Entity<InstrumentRating>().HasAlternateKey(i => new { Instrument= i.InstrumentId, owner = i.OwnerId });
foreach (var et in builder.Model.GetEntityTypes())
@ -291,8 +289,6 @@ namespace Yavsc.Models
public DbSet<Project> Project { get; set; }
public DbSet<BlogTrad> BlogTrad { get; set; }
[Obsolete("use signaled flows")]
public DbSet<LiveFlow> LiveFlow { get; set; }

View File

@ -20,6 +20,8 @@ namespace Yavsc.ViewComponents
public IViewComponentResult Invoke (ICircleAuthorized target)
{
if (target!=null)
{
var oid = target.GetOwnerId();
ViewBag.ACL = dbContext.Circle.Where(
c=>c.OwnerId == oid)
@ -41,6 +43,8 @@ namespace Yavsc.ViewComponents
Checked = target.AuthorizeCircle(c.Id),
Value = c.Id.ToString()
});
}
return View(new CirclesViewModel(target));
}
}

View File

@ -2,10 +2,25 @@ using Microsoft.AspNetCore.Authorization;
namespace Yavsc.ViewModels.Auth
{
public class EditRequirement : IAuthorizationRequirement
public class EditPermission : IAuthorizationRequirement
{
public EditRequirement()
public EditPermission()
{
}
}
public class ReadPermission: IAuthorizationRequirement
{
public ReadPermission()
{
}
}
public class DeletePermission: IAuthorizationRequirement
{
public DeletePermission()
{
}
}
}

View File

@ -0,0 +1,85 @@
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel
@{
ViewData["Title"] = "Blog post edition";
}
@section header {
<link href="~/css/main/dropzone.css" rel="stylesheet">
<script src="~/js/dropzone.js"></script>
@{ await Html.RenderPartialAsync("_FSScriptsPartial"); }
}
<h2>Blog post</h2>
<label><input type="checkbox" id="vcbtn" />Editer le code source Markdown</label>
<div asp-validation-summary="All" class="text-danger"></div>
<img class="blogphoto" alt="" src="@Model.Photo" title="Photo associée au post">
<h2 title="Titre du post" class="blogtitle" id="titleview" >@Model.Title</h2>
<div title="Contenu du post" id="contentview">@Model.Content</div>
<hr>
<form asp-controller="Blogspot" asp-action="Create">
<div class="form-horizontal">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group mdcoding">
<label asp-for="Title" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Title" class="form-control" data-from="titleview"/>
<span asp-validation-for="Title" class="text-danger" >
</span>
</div>
</div>
<div class="form-group">
<label asp-for="Photo" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Photo" class="form-control" />
<span asp-validation-for="Photo" class="text-danger" >
</span>
</div>
</div>
<div class="form-group mdcoding">
<label asp-for="Content" class="col-md-2 control-label" ></label>
<div class="col-md-10">
<textarea asp-for="Content" class="form-control" id="Content" data-from="contentview">
</textarea>
<span asp-validation-for="Content" class="text-danger" >
</span>
</div>
</div>
<div class="form-group">
<label asp-for="Visible" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Visible" class="form-control"/>
</div>
</div>
<div class="form-group">
<label asp-for="ACL" class="col-md-2 control-label"></label>
<div class="col-md-10">
@await Component.InvokeAsync("CirclesControl", Model)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button class="btn btn-primary" >Save</button>
</div>
</div>
</div>
</form>
@await Component.InvokeAsync("Directory","")
<div >
@{ await Html.RenderPartialAsync("_PostFilesPartial"); }
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>

View File

@ -112,7 +112,7 @@ $('span.field-validation-valid[data-valmsg-for="Content"]').html(
}
</div>
@if ((await AuthorizationService.AuthorizeAsync(User, Model, new EditRequirement())).Succeeded) {
@if ((await AuthorizationService.AuthorizeAsync(User, Model, new EditPermission())).Succeeded) {
<a asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-link">Edit</a>
}
<a asp-action="Index" class="btn btn-link">Back to List</a>

View File

@ -1,4 +1,4 @@
@model BlogPost
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel
@{
ViewData["Title"] = "Blog post edition";
@ -6,7 +6,6 @@
@section header {
<link href="~/css/main/quill.snow.css" rel="stylesheet">
<link href="~/css/main/dropzone.css" rel="stylesheet">
<style>
@ -34,90 +33,12 @@
</style>
<script src="~/js/dropzone.js"></script>
<script src="~/js/quill.js"></script>
<script src="~/js/to-markdown.js"></script>
@{ await Html.RenderPartialAsync("_FSScriptsPartial"); }
@{ await Html.RenderPartialAsync("_FSScriptsPartial"); }
}
@section scripts {
<script src="~/js/showdown.js" asp-append-version="true"></script>
<script src="~/js/md-helpers.js" asp-append-version="true"></script>
<script>
$(document).ready(function() {
if (typeof(allowCircleToBlog) !== 'undefined') {
$('input.Blogcirle[type=checkbox]').on('change', allowCircleToBlog);
}
$(".mdcoding").addClass('hidden');
$("#contentview").on('drop', function(){drop(event);});
$("#contentview").on('dragover', function(){allowDrop(event);});
var onchange = function(){
var nv = $(this).val();
var tid = $(this).data('from');
$('#'+tid).html(htmlize(nv));
};
$("#Content").change(onchange);
$("#Title").change(onchange);
$('#vcbtn').change(function(){
var vc = $(this).prop('checked');
if (vc) {
$("#contentview").addClass('hidden');
$("#titleview").addClass('hidden');
$(".mdcoding").removeClass('hidden');
} else {
$("#contentview").removeClass('hidden');
$("#titleview").removeClass('hidden');
$(".mdcoding").addClass('hidden');
}
});
var initQuill = function() {
var editortitre = new Quill('#titleview', {
modules: { toolbar: '#Titletoolbar' },
theme: 'snow'
});
var editorcontenu = new Quill('#contentview', {
modules: { toolbar: '#contentbar' },
theme: 'snow'
});
editortitre.on('selection-change', function(range) {
if (range) {
$('#contentbar').addClass('hidden');
$('#Titletoolbar').removeClass('hidden');
}
});
editortitre.on('text-change',function(delta,source){
if (source=='user')
{
updateMD('Title',$('#ql-editor-1').html())
}
});
editorcontenu.on('selection-change', function(range) {
if (range) {
$('#contentbar').removeClass('hidden');
$('#Titletoolbar').addClass('hidden');
}
});
editorcontenu.on('text-change',function(delta,source){
if (source=='user')
{
updateMD('Content',$('#ql-editor-2').html())
}
});
};
initQuill();
});
</script>
@Html.Partial("_ValidationScriptsPartial")
}
<h2 > Blog post edition </h2>
<label><input type="checkbox" id="vcbtn" />Editer le code source Markdown</label>
@ -131,47 +52,17 @@
</div>
<img class="blogphoto" alt="" src="@Model.Photo" title="Photo associée au post">
<h2 title="Titre du post" class="blogtitle" id="titleview" ismarkdown>@Model.Title</h2>
<h2 title="Titre du post" class="blogtitle" id="titleview" >@Model.Title</h2>
<div id="contentbar" class="hidden ql-snow ql-toolbar">
<span class="ql-format-group">
<button class="ql-format-button ql-bold"></button>
<button class="ql-format-button ql-italic"></button>
<button class="ql-format-button ql-underline"></button>
<button class="ql-format-button ql-strike"></button>
<environment names="Development">
<button class="ql-format-button ql-link"></button>
<button class="ql-format-button ql-image"></button>
<button class="ql-format-button ql-video"></button>
<button class="ql-format-button ql-file"></button>
</environment>
</span>
<span class="ql-format-group">
<span title="List" class="ql-format-button ql-list"></span>
<span class="ql-format-separator"></span>
<span title="Bullet" class="ql-format-button ql-bullet"></span>
<span class="ql-format-separator"></span>
<select title="Text Alignment" class="ql-align">
<option value="left" label="Left" selected=""></option>
<option value="center" label="Center"></option>
<option value="right" label="Right"></option>
<option value="justify" label="Justify"></option>
</select>
</span>
</div>
<div title="Contenu du post" id="contentview" markdown="@Model.Content"></div>
<div title="Contenu du post" id="contentview">@Model.Content</div>
<hr>
<form asp-action="@ViewData["PostTarget"]">
<form>
<div class="form-horizontal">
<hr />
<p class="text-success">@ViewData["StatusMessage"]</p>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<input type="hidden" asp-for="AuthorId" />
<div class="form-group mdcoding">
<label asp-for="Title" class="col-md-2 control-label"></label>
@ -182,17 +73,6 @@
</div>
</div>
<div class="form-group">
<label asp-for="Lang" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="Lang" class="form-control" asp-items="@ViewBag.LangItems" >
</select>
<span asp-validation-for="Lang" class="text-danger" >
</span>
</div>
</div>
<div class="form-group">
<label asp-for="Photo" class="col-md-2 control-label"></label>
<div class="col-md-10">
@ -230,9 +110,6 @@
</div>
</div>
</form>
<div>
</div>
@await Component.InvokeAsync("Directory","")
<div >
@{ await Html.RenderPartialAsync("_PostFilesPartial"); }

View File

@ -46,7 +46,7 @@
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
</li>
}
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditRequirement())).Succeeded) {
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
<li><a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-default">Edit</a>
</li>
<li><a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger">Delete</a>

View File

@ -49,7 +49,7 @@
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
</li>
}
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditRequirement())).Succeeded) {
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
<li><a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-default">Edit</a>
</li>
<li><a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger">Delete</a>

View File

@ -1,6 +1,6 @@
@model CirclesViewModel
@foreach (var cb in ViewBag.Access) { 
@if (ViewBag.Access!=null)
foreach (var cb in ViewBag.Access) {
<label><input type="checkbox" class="@(Model.TargetTypeName)cirle" checked="@cb.Checked" value="@cb.Text"
data-target-id="@Model.Target.Id" data-circle-id="@cb.Value" data-targe-type="">
@cb.Text </label>

View File

@ -6,7 +6,7 @@
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
@if (Model!=null) if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>

View File

@ -10,8 +10,7 @@
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-append-version="true"/>
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
<!-- #region jQuery Slim
<script src="~/lib/jquery/dist/jquery.slim.min.js"></script>
-->
<script src="~/lib/jquery/dist/jquery.slim.min.js"></script> -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
@await RenderSectionAsync("header", false)
</head>

View File

@ -46,7 +46,9 @@
Manage your account
</a>
</li>
<li><a class="dropdown-item" asp-controller="Grants" asp-action="Index">Your Grants</a></li>
<li><a class="dropdown-item" asp-controller="Grants" asp-action="Index">Grants</a></li>
<li><a class="dropdown-item" asp-controller="Device" asp-action="Index">Device</a></li>
<li><a class="dropdown-item" asp-controller="Diagnostics" asp-action="Index">Diagnostics</a></li>
<li><a class="dropdown-item" asp-controller="Account" asp-action="Logout">Logout</a></li>
</ul>
</li>

View File

@ -5,7 +5,7 @@
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbar" aria-controls="navbar"
aria-expanded="false" aria-label="Toggle navigation">
aria-expanded="true" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>

View File

@ -14,21 +14,13 @@
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); }
/* bootstrap.css | http://localhost:5000/lib/bootstrap/css/bootstrap.css */
.nav-link {
/* background-color: var(--bs-nav-tabs-link-active-bg); */
background-color: black; }
.dropdown-item {
/* background-color: transparent; */
background-color: black; }
.dropdown-menu {
/* background-color: var(--bs-dropdown-bg); */
background-color: black; }
div.carousel-inner > div.item > div.carousel-caption-s {
margin: .5em;
background-color: rgba(0, 0, 0, 0.6);
color: #ffffc8;
font-weight: bold;
padding: .5em; }
img.blogphoto {
max-width: 100%;
max-height: 100%; }

View File

@ -26,20 +26,6 @@
/* bootstrap.css | http://localhost:5000/lib/bootstrap/css/bootstrap.css */
.nav-link {
/* background-color: var(--bs-nav-tabs-link-active-bg); */
background-color: black;
}
.dropdown-item {
/* background-color: transparent; */
background-color: black;
}
.dropdown-menu {
/* background-color: var(--bs-dropdown-bg); */
background-color: black;
}
div.carousel-inner > div.item > div.carousel-caption-s {
margin: .5em;
@ -48,3 +34,8 @@ div.carousel-inner > div.item > div.carousel-caption-s {
font-weight: bold;
padding: .5em;
}
img.blogphoto {
max-width: 100%;
max-height: 100%;
}

View File

@ -615,14 +615,14 @@ namespace yavscTests
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "google-secret.json");
/* TODO
ConfigureFileServerApp(app, SiteSetup, env, authorizationService);
app.UseRequestLocalization(localizationOptions.Value, (RequestCulture)new RequestCulture((string)"en-US"));
ConfigureWorkflow();
*/
app.UseMvc(routes =>
{