permission handling

main
Paul Schneider 9 months ago
parent 04bcecad9e
commit 7ccb9cd1da
27 changed files with 243 additions and 288 deletions

@ -25,9 +25,10 @@ namespace Yavsc.Controllers
// GET: api/BlogApi // GET: api/BlogApi
[HttpGet] [HttpGet]
public IEnumerable<BlogPost> GetBlogspot() public IEnumerable<BlogPost> GetBlogspot(int start=0, int take=25)
{ {
return _context.BlogSpot.Where(b => b.Visible).OrderByDescending(b => b.UserModified); return _context.BlogSpot.OrderByDescending(b => b.UserModified)
.Skip(start).Take(take);
} }
// GET: api/BlogApi/5 // GET: api/BlogApi/5

@ -54,7 +54,7 @@ namespace Yavsc.ApiControllers
{ {
var bill = await billingService.GetBillAsync(billingCode, id); var bill = await billingService.GetBillAsync(billingCode, id);
if ( authorizationService.AuthorizeAsync(User, bill, new ViewRequirement()).IsFaulted) if ( authorizationService.AuthorizeAsync(User, bill, new ReadPermission()).IsFaulted)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }
@ -76,7 +76,7 @@ namespace Yavsc.ApiControllers
} }
logger.LogTrace(JsonConvert.SerializeObject(bill)); logger.LogTrace(JsonConvert.SerializeObject(bill));
if (!(await authorizationService.AuthorizeAsync(User, bill, new ViewRequirement())).Succeeded) if (!(await authorizationService.AuthorizeAsync(User, bill, new ReadPermission())).Succeeded)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }
@ -107,7 +107,7 @@ namespace Yavsc.ApiControllers
.FirstOrDefault(e=>e.Id == id); .FirstOrDefault(e=>e.Id == id);
if (estimate == null) if (estimate == null)
return new BadRequestResult(); return new BadRequestResult();
if (!(await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())).Succeeded) if (!(await authorizationService.AuthorizeAsync(User, estimate, new ReadPermission())).Succeeded)
{ {
@ -135,7 +135,7 @@ namespace Yavsc.ApiControllers
{ {
// For authorization purpose // For authorization purpose
var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id); var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id);
if (!(await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())).Succeeded) if (!(await authorizationService.AuthorizeAsync(User, estimate, new ReadPermission())).Succeeded)
{ {
return new ChallengeResult(); return new ChallengeResult();
@ -154,7 +154,7 @@ namespace Yavsc.ApiControllers
var estimate = dbContext.Estimates.Include( e=>e.Query var estimate = dbContext.Estimates.Include( e=>e.Query
).Include(e=>e.Owner).Include(e=>e.Owner.Performer).Include(e=>e.Client) ).Include(e=>e.Owner).Include(e=>e.Owner.Performer).Include(e=>e.Client)
.FirstOrDefault( e=> e.Id == id && e.Query.ClientId == uid ); .FirstOrDefault( e=> e.Id == id && e.Query.ClientId == uid );
if (!(await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())).Succeeded) if (!(await authorizationService.AuthorizeAsync(User, estimate, new ReadPermission())).Succeeded)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }
@ -171,7 +171,7 @@ namespace Yavsc.ApiControllers
{ {
// For authorization purpose // For authorization purpose
var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id); var estimate = dbContext.Estimates.FirstOrDefault(e=>e.Id == id);
if (!(await authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement())).Succeeded) if (!(await authorizationService.AuthorizeAsync(User, estimate, new ReadPermission())).Succeeded)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }

@ -3,11 +3,14 @@
namespace Yavsc namespace Yavsc
{ {
public interface IBlogPost : ITrackedEntity, IIdentified<long>, ITitle public interface IBlogPostPayLoad
{ {
string AuthorId { get; set; }
string Content { get; set; } string Content { get; set; }
string Photo { get; set; } string Photo { get; set; }
bool Visible { get; set; }
}
public interface IBlogPost :IBlogPostPayLoad, ITrackedEntity, IIdentified<long>, ITitle
{
string AuthorId { get; set; }
} }
} }

@ -30,7 +30,7 @@ namespace Yavsc.Helpers
{ {
var userPosts = dbContext.BlogSpot.Include( var userPosts = dbContext.BlogSpot.Include(
b => b.Author b => b.Author
).Where(x => ((x.AuthorId == posterId) && (x.Visible))).ToArray(); ).Where(x => ((x.AuthorId == posterId))).ToArray();
return userPosts; return userPosts;
} }
else else
@ -42,8 +42,7 @@ namespace Yavsc.Helpers
return dbContext.BlogSpot.Include( return dbContext.BlogSpot.Include(
b => b.Author b => b.Author
).Include(p => p.ACL).Where(x => x.Author.Id == posterId && ).Include(p => p.ACL).Where(x => x.Author.Id == posterId &&
(x.Visible && (x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId))));
(x.ACL.Count == 0 || x.ACL.Any(a => readerCirclesMemberships.Contains(a.CircleId)))));
} }

@ -68,7 +68,7 @@ namespace Yavsc.Models.Blog
if (existent==null) Tags.Add(new BlogTag { PostId = Id, Tag = tag } ); if (existent==null) Tags.Add(new BlogTag { PostId = Id, Tag = tag } );
} }
public void Detag(Tag tag) public void DeTag(Tag tag)
{ {
var existent = Tags.SingleOrDefault(t => (( t.TagId == tag.Id) && t.PostId == Id)); var existent = Tags.SingleOrDefault(t => (( t.TagId == tag.Id) && t.PostId == Id));
if (existent!=null) Tags.Remove(existent); if (existent!=null) Tags.Remove(existent);

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Authorization;
namespace Yavsc.ViewModels.Auth
{
public class DeletePermission: IAuthorizationRequirement
{
public DeletePermission()
{
}
}
}

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Authorization;
namespace Yavsc.ViewModels.Auth
{
public class EditPermission : IAuthorizationRequirement
{
public EditPermission()
{
}
}
}

@ -1,26 +0,0 @@
using Microsoft.AspNetCore.Authorization;
namespace Yavsc.ViewModels.Auth
{
public class EditPermission : IAuthorizationRequirement
{
public EditPermission()
{
}
}
public class ReadPermission: IAuthorizationRequirement
{
public ReadPermission()
{
}
}
public class DeletePermission: IAuthorizationRequirement
{
public DeletePermission()
{
}
}
}

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

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace Yavsc.ViewModels.Blog;
public class BlogPostEditViewModel : BlogPostInputViewModel
{
[Required]
public required long Id { get; set; }
}

@ -11,16 +11,15 @@ namespace Yavsc.ViewModels.Blog
public string? Photo { get; set; } public string? Photo { get; set; }
[StringLength(1024)] [StringLength(1024)]
public required string Title { get; set; } public string Title { get; set; }
[StringLength(56224)] [StringLength(56224)]
public required string Content { get; set; } public string Content { get; set; }
public bool Visible { get; set; }
[InverseProperty("Target")] [InverseProperty("Target")]
[Display(Name="Liste de contrôle d'accès")] [Display(Name="Liste de contrôle d'accès")]
public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; } public virtual List<CircleAuthorizationToBlogPost>? ACL { get; set; }
} }
} }

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Yavsc.ViewModels.BlogSpot
{
public class NewPost
{
[Required]
public string Title{ get; set; }
[Required]
public string Content { get; set; }
}
}

@ -43,12 +43,44 @@ namespace Yavsc.Controllers
// GET: Blog // GET: Blog
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> Index(string id) public async Task<IActionResult> Index(string id, int skip=0, int take=25)
{ {
if (!string.IsNullOrEmpty(id)) { if (!string.IsNullOrEmpty(id)) {
return View("UserPosts", await UserPosts(id)); return View("UserPosts", await UserPosts(id));
} }
return View(); IEnumerable<BlogPost> posts;
if (User.Identity.IsAuthenticated)
{
string viewerId = User.GetUserId();
long[] usercircles = await _context.Circle.Include(c=>c.Members).
Where(c=>c.Members.Any(m=>m.MemberId == viewerId))
.Select(c=>c.Id).ToArrayAsync();
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p =>(p.ACL.Count == 0)
|| (p.AuthorId == viewerId)
|| (usercircles != null && p.ACL.Any(a => usercircles.Contains(a.CircleId)))
);
}
else
{
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p => p.ACL.Count == 0 ).ToArray();
}
var data = posts.OrderByDescending( p=> p.DateCreated);
var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(take);
return View(grouped);
} }
[Route("~/Title/{id?}")] [Route("~/Title/{id?}")]
@ -59,7 +91,7 @@ namespace Yavsc.Controllers
ViewData["Title"] = id; ViewData["Title"] = id;
return View("Title", _context.BlogSpot.Include( return View("Title", _context.BlogSpot.Include(
b => b.Author b => b.Author
).Where(x => x.Title == id && (x.Visible || x.AuthorId == uid )).OrderByDescending( ).Where(x => x.Title == id && (x.AuthorId == uid )).OrderByDescending(
x => x.DateCreated x => x.DateCreated
).ToList()); ).ToList());
} }
@ -88,7 +120,7 @@ namespace Yavsc.Controllers
{ {
return NotFound(); return NotFound();
} }
if ( _authorizationService.AuthorizeAsync(User, blog, new ViewRequirement()).IsFaulted) if ( _authorizationService.AuthorizeAsync(User, blog, new ReadPermission()).IsFaulted)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }
@ -111,7 +143,8 @@ namespace Yavsc.Controllers
[Authorize()] [Authorize()]
public IActionResult Create(string title) public IActionResult Create(string title)
{ {
var result = new BlogPostInputViewModel{Title=title,Content=""}; var result = new BlogPostInputViewModel{Title=title
};
ViewData["PostTarget"]="Create"; ViewData["PostTarget"]="Create";
SetLangItems(); SetLangItems();
return View(result); return View(result);
@ -168,7 +201,14 @@ namespace Yavsc.Controllers
}  } 
); );
SetLangItems(); SetLangItems();
return View(blog); return View(new BlogPostEditViewModel
{
Id = blog.Id,
Title = blog.Title,
Content = blog.Content,
ACL = blog.ACL,
Photo = blog.Photo
});
} }
else else
{ {
@ -179,27 +219,31 @@ namespace Yavsc.Controllers
// POST: Blog/Edit/5 // POST: Blog/Edit/5
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken,Authorize()] [ValidateAntiForgeryToken,Authorize()]
public IActionResult Edit(BlogPost blog) public async Task<IActionResult> Edit(BlogPostEditViewModel blogEdit)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var auth = _authorizationService.AuthorizeAsync(User, blog, new EditPermission()); var blog = _context.BlogSpot.SingleOrDefault(b=>b.Id == blogEdit.Id);
if (!auth.IsFaulted) if (blog == null) {
{ ModelState.AddModelError("Id", "not found");
return View();
}
if (!(await _authorizationService.AuthorizeAsync(User, blog, new EditPermission())).Succeeded) {
ViewData["StatusMessage"] = "Accès restreint";
return new ChallengeResult();
}
blog.Content=blogEdit.Content;
blog.Title = blogEdit.Title;
blog.Photo = blogEdit.Photo;
blog.ACL = blogEdit.ACL;
// saves the change // saves the change
_context.Update(blog); _context.Update(blog);
_context.SaveChanges(User.GetUserId()); _context.SaveChanges(User.GetUserId());
ViewData["StatusMessage"] = "Post modified"; ViewData["StatusMessage"] = "Post modified";
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
else
{
ViewData["StatusMessage"] = "Accès restreint";
return new ChallengeResult();
}
}
ViewData["PostTarget"]="Edit"; ViewData["PostTarget"]="Edit";
return View(blog); return View(blogEdit);
} }
// GET: Blog/Delete/5 // GET: Blog/Delete/5
@ -223,12 +267,12 @@ namespace Yavsc.Controllers
} }
// POST: Blog/Delete/5 // POST: Blog/Delete/5
[HttpPost, ActionName("Delete"), Authorize()] [HttpPost, ActionName("Delete"), Authorize("IsTheAuthor")]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(long id) public IActionResult DeleteConfirmed(long id)
{ {
var uid = User.GetUserId(); var uid = User.GetUserId();
BlogPost blog = _context.BlogSpot.Single(m => m.Id == id && m.AuthorId == uid ); BlogPost blog = _context.BlogSpot.Single(m => m.Id == id);
_context.BlogSpot.Remove(blog); _context.BlogSpot.Remove(blog);
_context.SaveChanges(User.GetUserId()); _context.SaveChanges(User.GetUserId());

@ -64,7 +64,7 @@ namespace Yavsc.Controllers
{ {
return NotFound(); return NotFound();
} }
if (authorizationService.AuthorizeAsync(User, estimate, new ViewRequirement()).IsFaulted) if (authorizationService.AuthorizeAsync(User, estimate, new ReadPermission()).IsFaulted)
{ {
return new ChallengeResult(); return new ChallengeResult();
} }

@ -206,7 +206,7 @@ public static class HostingExtensions
services.AddDataProtection().PersistKeysToFileSystem(dataDir); services.AddDataProtection().PersistKeysToFileSystem(dataDir);
AddYavscPolicies(services); AddYavscPolicies(services);
services.AddSingleton<IAuthorizationHandler, PermissionHandler>(); services.AddScoped<IAuthorizationHandler, PermissionHandler>();
AddAuthentication(builder); AddAuthentication(builder);
@ -417,9 +417,8 @@ public static class HostingExtensions
var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>(); var smtpSettings = services.GetRequiredService<IOptions<SmtpSettings>>();
var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>(); var payPalSettings = services.GetRequiredService<IOptions<PayPalSettings>>();
var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>(); var googleAuthSettings = services.GetRequiredService<IOptions<GoogleAuthSettings>>();
var authorizationService = services.GetRequiredService<IAuthorizationService>();
var localization = services.GetRequiredService<IStringLocalizer<YavscLocalization>>(); var localization = services.GetRequiredService<IStringLocalizer<YavscLocalization>>();
Startup.Configure(app, siteSettings, smtpSettings, authorizationService, Startup.Configure(app, siteSettings, smtpSettings,
payPalSettings, googleAuthSettings, localization, loggerFactory, payPalSettings, googleAuthSettings, localization, loggerFactory,
app.Environment.EnvironmentName); app.Environment.EnvironmentName);
app.ConfigureFileServerApp(); app.ConfigureFileServerApp();

@ -23,7 +23,11 @@ public class PermissionHandler : IAuthorizationHandler
{ {
if (requirement is ReadPermission) if (requirement is ReadPermission)
{ {
if (IsOwner(context.User, context.Resource) if (IsPublic(context.Resource))
{
context.Succeed(requirement);
}
else if (IsOwner(context.User, context.Resource)
|| IsSponsor(context.User, context.Resource)) || IsSponsor(context.User, context.Resource))
{ {
context.Succeed(requirement); context.Succeed(requirement);
@ -41,6 +45,16 @@ public class PermissionHandler : IAuthorizationHandler
return Task.CompletedTask; return Task.CompletedTask;
} }
private bool IsPublic(object? resource)
{
if (resource is BlogPost blogPost)
{
if (blogPost.ACL.Count==0)
return true;
}
return false;
}
private static bool IsOwner(ClaimsPrincipal user, object? resource) private static bool IsOwner(ClaimsPrincipal user, object? resource)
{ {
if (resource is BlogPost blogPost) if (resource is BlogPost blogPost)

@ -89,12 +89,7 @@ namespace Yavsc.Helpers
break; break;
case "AsciiDocNet.TextLiteral": case "AsciiDocNet.TextLiteral":
var tl = elt as TextLiteral; RenderLitteral(elt, sb);
if (tl?.Attributes.Anchor!=null)
{
sb.AppendFormat("<a name=\"{0}\">{1}</a> ", tl.Attributes.Anchor.Id, tl.Attributes.Anchor.XRefLabel);
}
if (tl!=null) sb.Append(tl.Text);
break; break;
case "AsciiDocNet.Emphasis": case "AsciiDocNet.Emphasis":
@ -114,27 +109,52 @@ namespace Yavsc.Helpers
sb.AppendHtml("</b>"); sb.AppendHtml("</b>");
break; break;
case "AsciiDocNet.InternalAnchor": case "AsciiDocNet.InternalAnchor":
InternalAnchor a = (InternalAnchor) elt; InternalAnchor a = (InternalAnchor)elt;
sb.AppendFormat("<a name=\"{0}\">{1}</a> ", a.Id, a.XRefLabel); sb.AppendFormat("<a name=\"{0}\">{1}</a> ", a.Id, a.XRefLabel);
break; break;
case "AsciiDocNet.Subscript": case "AsciiDocNet.Subscript":
sb.AppendHtml("<sup>"); sb.AppendHtml("<sup>");
Subscript sub = (Subscript)elt; Subscript sub = (Subscript)elt;
sub.ToHtml(sb); RenderLitteral(sub, sb);
sb.AppendHtml("</sup>"); sb.AppendHtml("</sup>");
break; break;
case "AsciiDocNet.Superscript": case "AsciiDocNet.Superscript":
sb.AppendHtml("<sup>"); sb.AppendHtml("<sup>");
Superscript sup = (Superscript)elt; Superscript sup = (Superscript)elt;
sup.ToHtml(sb); RenderLitteral(sup, sb);
sb.AppendHtml("</sup>"); sb.AppendHtml("</sup>");
break; break;
case "AsciiDocNet.Mark":
sb.AppendHtml("<em>");
Mark mark = (Mark)elt;
if (mark.DoubleDelimited)
{
sb.AppendHtml("<b>");
RenderLitteral(mark, sb);
sb.AppendHtml("</b>");
}
else
RenderLitteral(mark, sb);
sb.AppendHtml("</em>");
break;
default: default:
string unsupportedType = elt.GetType().FullName; string unsupportedType = elt.GetType().FullName;
throw new InvalidProgramException(unsupportedType); throw new InvalidProgramException(unsupportedType);
} }
} }
private static void RenderLitteral(IInlineElement elt, IHtmlContentBuilder sb)
{
var tl = elt as TextLiteral;
if (tl?.Attributes.Anchor != null)
{
sb.AppendFormat("<a name=\"{0}\">{1}</a> ", tl.Attributes.Anchor.Id, tl.Attributes.Anchor.XRefLabel);
}
if (tl != null) sb.Append(tl.Text);
}
public static IHtmlContent ToHtml(this Document doc, int doclevel = 4) public static IHtmlContent ToHtml(this Document doc, int doclevel = 4)
{ {
var contentbuilder = new HtmlContentBuilder(); var contentbuilder = new HtmlContentBuilder();

@ -13,7 +13,6 @@ public class Startup
IApplicationBuilder app, IApplicationBuilder app,
IOptions<SiteSettings> siteSettings, IOptions<SiteSettings> siteSettings,
IOptions<SmtpSettings> smtpSettings, IOptions<SmtpSettings> smtpSettings,
IAuthorizationService authorizationService,
IOptions<PayPalSettings> payPalSettings, IOptions<PayPalSettings> payPalSettings,
IOptions<GoogleAuthSettings> googleSettings, IOptions<GoogleAuthSettings> googleSettings,
IStringLocalizer<YavscLocalization> localizer, IStringLocalizer<YavscLocalization> localizer,

@ -1,63 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yavsc.Models;
using Yavsc.Models.Blog;
using Yavsc.Helpers;
using System.Security.Claims;
using IdentityServer8.Extensions;
namespace Yavsc.ViewComponents
{
public class BlogIndexViewComponent: ViewComponent
{
private readonly ApplicationDbContext _context;
public BlogIndexViewComponent(
ApplicationDbContext context)
{
_context = context;
}
// Renders blog index ofr the specified user by name,
// grouped by title
public async Task<IViewComponentResult> InvokeAsync(int skip=0, int maxLen=25)
{
IEnumerable<BlogPost> posts;
if (User.IsAuthenticated())
{
string viewerId = UserClaimsPrincipal.GetUserId();
long[] usercircles = await _context.Circle.Include(c=>c.Members).
Where(c=>c.Members.Any(m=>m.MemberId == viewerId))
.Select(c=>c.Id).ToArrayAsync();
IQueryable<BlogPost> allposts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p => p.AuthorId == viewerId || p.Visible);
posts = (usercircles != null) ?
allposts.Where(p=> p.ACL.Count==0 || p.ACL.Any(a => usercircles.Contains(a.CircleId)))
: allposts.Where(p => p.ACL.Count == 0);
}
else
{
posts = _context.BlogSpot
.Include(b => b.Author)
.Include(p=>p.ACL)
.Include(p=>p.Tags)
.Include(p=>p.Comments)
.Where(p => p.Visible && p.ACL.Count == 0 ).ToArray();
}
var data = posts.OrderByDescending( p=> p.DateCreated);
var grouped = data.GroupBy(p=> p.Title).Skip(skip).Take(maxLen);
return View("Default", grouped);
}
}
}

@ -56,12 +56,6 @@
</span> </span>
</div> </div>
</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"> <div class="form-group">
<label asp-for="ACL" class="col-md-2 control-label"></label> <label asp-for="ACL" class="col-md-2 control-label"></label>
<div class="col-md-10"> <div class="col-md-10">

@ -12,7 +12,7 @@
<hr /> <hr />
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt> <dt>
Author"] Author
</dt> </dt>
<dd> <dd>
@Model.Author @Model.Author
@ -47,12 +47,6 @@
<dd> <dd>
@Html.DisplayFor(model => model.Title) @Html.DisplayFor(model => model.Title)
</dd> </dd>
<dt>
@Html.DisplayNameFor(model => model.Visible)
</dt>
<dd>
@Html.DisplayFor(model => model.Visible)
</dd>
</dl> </dl>
<form asp-action="Delete"> <form asp-action="Delete">

@ -1,4 +1,4 @@
@model Yavsc.ViewModels.Blog.BlogPostInputViewModel @model BlogPostEditViewModel
@{ @{
ViewData["Title"] = "Blog post edition"; ViewData["Title"] = "Blog post edition";
@ -58,11 +58,11 @@
<div title="Contenu du post" id="contentview">@Model.Content</div> <div title="Contenu du post" id="contentview">@Model.Content</div>
<hr> <hr>
<form> <form asp-action="Edit">
<div class="form-horizontal"> <div class="form-horizontal">
<div asp-validation-summary="ModelOnly" class="text-danger"></div> <div asp-validation-summary="ModelOnly" class="text-danger"></div>
@Html.HiddenFor(m=>m.Id)
<div class="form-group mdcoding"> <div class="form-group mdcoding">
<label asp-for="Title" class="col-md-2 control-label"></label> <label asp-for="Title" class="col-md-2 control-label"></label>
@ -90,12 +90,6 @@
</span> </span>
</div> </div>
</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"> <div class="form-group">
<label asp-for="ACL" class="col-md-2 control-label"></label> <label asp-for="ACL" class="col-md-2 control-label"></label>
<div class="col-md-10"> <div class="col-md-10">
@ -118,3 +112,4 @@
<a asp-action="Index">Back to List</a> <a asp-action="Index">Back to List</a>
</div> </div>
using Yavsc.Migrations;

@ -45,5 +45,55 @@
} }
<div class="container"> <div class="container">
@await Component.InvokeAsync("BlogIndex")
<table class="table">
@foreach (var group in Model) {
var title = group.Key ?? "@";
string secondclass="";
var first = group.First();
<tr><td colspan="3">
<a asp-action="Title" asp-route-id="@group.Key" >@title</a></td></tr>
@foreach (var item in group) {
var trunked = item.Content?.Length > 256;
<tr>
<td><a asp-action="Details" asp-route-id="@item.Id" class="bloglink">
<img src="@item.Photo" class="blogphoto"></a>
</td>
<td>
<asciidoc summary="256">@item.Content</asciidoc>
@if (trunked) { <a asp-action="Details" asp-route-id="@item.Id" class="bloglink">...</a> }
<span style="font-size:x-small;">@Html.DisplayFor(m => item.Author)</span>
<span style="font-size:xx-small;">
posté le @item.DateCreated.ToString("dddd d MMM yyyy à H:mm")
@if ((item.DateModified - item.DateCreated).Minutes > 0){ 
@:- Modifié le @item.DateModified.ToString("dddd d MMM yyyy à H:mm")
})
</span>
</td>
<td>
<ul class="actiongroup">
@if ((await AuthorizationService.AuthorizeAsync(User, item, new ReadPermission())).Succeeded) {
<li>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
</li>
}
else {
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details DEBUG</a>
}
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
<li><a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-default">Edit</a>
</li>
<li><a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger">Delete</a>
</li>
}
</ul>
</td>
</tr>
}
}
</table>
</div> </div>

@ -2,30 +2,15 @@
<h2 markdown="@ViewData["Title"]"></h2> <h2 markdown="@ViewData["Title"]"></h2>
<p class="text-success">@ViewData["StatusMessage"]</p> <p class="text-success">@ViewData["StatusMessage"]</p>
@if (User.IsSignedIn()) {
<label>
<input type="checkbox" id="cbv" checked/>Invisibles, posts privés</label>
<script>
$("#cbv").change(function() {
if (this.checked) {
$("tr.hiddenpost").removeClass("hidden");
} else {
$("tr.hiddenpost").addClass("hidden");
}
});
</script>
}
<p> <p>
<a asp-action="Create" asp-route-title="@ViewData["Title"]">Poster au même titre"]</a> <a asp-action="Create" asp-route-title="@ViewData["Title"]">Poster au même titre</a>
</p> </p>
<table class="table"> <table class="table">
@foreach (var item in Model) { @foreach (var item in Model) {
var trclass = (item.Visible)?"visiblepost":"hiddenpost"; <tr>
<tr class="@trclass">
<td><a asp-action="Details" asp-route-id="@item.Id" class="bloglink"> <td><a asp-action="Details" asp-route-id="@item.Id" class="bloglink">
<img src="@item.Photo" class="blogphoto"></a> <img src="@item.Photo" class="blogphoto"></a>
</td> </td>
@ -41,7 +26,7 @@
</td> </td>
<td> <td>
<ul class="actiongroup"> <ul class="actiongroup">
@if ((await AuthorizationService.AuthorizeAsync(User, item, new ViewRequirement())).Succeeded) { @if ((await AuthorizationService.AuthorizeAsync(User, item, new ReadPermission())).Succeeded) {
<li> <li>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a> <a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
</li> </li>

@ -11,7 +11,7 @@
<table class="table"> <table class="table">
<tr> <tr>
<th> <th>
Author"] Author
</th> </th>
<th> <th>
@Html.DisplayNameFor(model => model.Content) @Html.DisplayNameFor(model => model.Content)
@ -28,9 +28,6 @@
<th> <th>
@Html.DisplayNameFor(model => model.Title) @Html.DisplayNameFor(model => model.Title)
</th> </th>
<th>
@Html.DisplayNameFor(model => model.Visible)
</th>
<th></th> <th></th>
</tr> </tr>
@ -56,9 +53,6 @@
</td> </td>
<td> <td>
@Html.DisplayFor(modelItem => item.Title) @Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Visible)
</td> </td>
</tr> </tr>
</table> </table>

@ -1,66 +0,0 @@
@model IEnumerable<IGrouping<string,BlogPost>>
@if (User.IsSignedIn()) {
<label>
<input type="checkbox" id="_cbv" checked/>Invisibles, posts privés</label>
<script type="text/javascript">
$('#_cbv').change(function()
{
if (this.checked) {
$('tr.hiddenpost').removeClass("hidden");
} else {
$('tr.hiddenpost').addClass("hidden");
}
});
</script>
}
<table class="table">
@foreach (var group in Model) {
var title = group.Key ?? "@";
string secondclass="";
var first = group.First();
string ftrclass = (first.Visible) ? "visiblepost" : "hiddenpost";
<tr><td colspan="3">
<a asp-action="Title" asp-route-id="@group.Key" >@title</a></td></tr>
@foreach (var item in group) {
var trclass = (item.Visible)?"visiblepost":"hiddenpost";
var trunked = item.Content?.Length > 256;
<tr class="@trclass">
<td><a asp-action="Details" asp-route-id="@item.Id" class="bloglink">
<img src="@item.Photo" class="blogphoto"></a>
</td>
<td>
<asciidoc summary="256">@item.Content</asciidoc>
@if (trunked) { <a asp-action="Details" asp-route-id="@item.Id" class="bloglink">...</a> }
<span style="font-size:x-small;">@Html.DisplayFor(m => item.Author)</span>
<span style="font-size:xx-small;">
posté le @item.DateCreated.ToString("dddd d MMM yyyy à H:mm")
@if ((item.DateModified - item.DateCreated).Minutes > 0){ 
@:- Modifié le @item.DateModified.ToString("dddd d MMM yyyy à H:mm")
})
</span>
</td>
<td>
<ul class="actiongroup">
@if ((await AuthorizationService.AuthorizeAsync(User, item, new ViewRequirement())).Succeeded) {
<li>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-lg">Details</a>
</li>
}
@if ((await AuthorizationService.AuthorizeAsync(User, item, new EditPermission())).Succeeded) {
<li><a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-default">Edit</a>
</li>
<li><a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-danger">Delete</a>
</li>
}
</ul>
</td>
</tr>
}
}
</table>

@ -13,6 +13,7 @@
@using Yavsc.Models.Access; @using Yavsc.Models.Access;
@using Yavsc.Billing; @using Yavsc.Billing;
@using Yavsc.Server.Models.Calendar; @using Yavsc.Server.Models.Calendar;
@using Yavsc.ViewModels.Blog;
@using Yavsc.ViewModels.Haircut; @using Yavsc.ViewModels.Haircut;
@using Yavsc.ViewModels.Administration; @using Yavsc.ViewModels.Administration;
@using Yavsc.ViewModels.Account; @using Yavsc.ViewModels.Account;

Loading…