Added ability for authors to choose their reviewer if there are multiple
This commit is contained in:
parent
3b64009ada
commit
afe9627438
|
@ -81,12 +81,12 @@
|
|||
</section>
|
||||
}
|
||||
|
||||
<div class="flex gap-2 flex-wrap">
|
||||
<div class="flex gap-2 flex-wrap w-full">
|
||||
@if (string.IsNullOrWhiteSpace(Article.Author.AboutTheAuthor)) {
|
||||
<ProfilePill Profile="Article.Author" RoleTag="@Localizer["Author"]"/>
|
||||
}
|
||||
@if (Article.Reviewer is not null && Article.Reviewer.Id != Article.Author.Id) {
|
||||
<ProfilePill Profile="Article.Reviewer" RoleTag="@Localizer["Reviewer"]"/>
|
||||
<ProfilePill Profile="Article.Reviewer" RoleTag="@Localizer["Reviewer"]" DisableProfileLink="true" />
|
||||
}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -60,10 +60,37 @@
|
|||
<a class="btn btn-info w-full sm:btn-wide" href="article/@Article!.Id/edit"
|
||||
data-enhance-nav="false">@Localizer["Edit"]</a>
|
||||
}
|
||||
@if (article.AllowedToDelete(HttpContext.User)) {
|
||||
<a class="btn btn-error w-full sm:btn-wide" href="/article/@article.Id/delete">
|
||||
@Localizer["Delete_Submit"]
|
||||
</a>
|
||||
}
|
||||
@if (article.AllowedToSubmitForReview(HttpContext.User)) {
|
||||
<form @formname="submit-for-review" method="post" @onsubmit="SubmitForReview" class="max-sm:w-full">
|
||||
<AntiforgeryToken/>
|
||||
<button type="submit" class="btn btn-primary w-full sm:btn-wide">@Localizer["Review_Submit"]</button>
|
||||
|
||||
@if (Reviewers.Count > 1) {
|
||||
<div class="join join-vertical md:join-horizontal w-full">
|
||||
<button type="submit" class="btn btn-primary flex-1 sm:btn-wide join-item">
|
||||
@Localizer["Review_Submit"]
|
||||
</button>
|
||||
<InputSelect @bind-Value="ReviewerId" class="select select-bordered select-primary join-item">
|
||||
<option value="" selected>@Localizer["Review_Reviewer_Any"]</option>
|
||||
@foreach (var reviewer in Reviewers) {
|
||||
if (reviewer.FullName is null) continue;
|
||||
|
||||
<option value="@reviewer.Id">
|
||||
@reviewer.Name
|
||||
</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</div>
|
||||
} else {
|
||||
<button type="submit" class="btn btn-primary w-full sm:btn-wide">
|
||||
@Localizer["Review_Submit"]
|
||||
</button>
|
||||
}
|
||||
|
||||
</form>
|
||||
}
|
||||
@if (article.AllowedToPublish(HttpContext.User)) {
|
||||
|
@ -80,11 +107,6 @@
|
|||
}
|
||||
</form>
|
||||
}
|
||||
@if (article.AllowedToDelete(HttpContext.User)) {
|
||||
<a class="btn btn-error w-full sm:btn-wide" href="/article/@article.Id/delete">
|
||||
@Localizer["Delete_Submit"]
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</ChildContent>
|
||||
|
@ -127,9 +149,14 @@
|
|||
[Parameter, SupplyParameterFromForm(FormName = "submit-for-publish")]
|
||||
public bool PublishSilently { get; set; }
|
||||
|
||||
[Parameter, SupplyParameterFromForm(FormName = "submit-for-review")]
|
||||
public string ReviewerId { get; set; } = string.Empty;
|
||||
|
||||
[CascadingParameter]
|
||||
public HttpContext HttpContext { get; set; } = default!;
|
||||
|
||||
|
||||
private List<ApplicationUser> Reviewers { get; } = [];
|
||||
|
||||
private Article GetArticle(ClaimsPrincipal principal) {
|
||||
if (Article.AllowedToRead(principal)) return Article!;
|
||||
|
||||
|
@ -159,35 +186,57 @@
|
|||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
Reviewers.AddRange([
|
||||
.. await UserManager.GetUsersInRoleAsync("Reviewer"),
|
||||
.. await UserManager.GetUsersInRoleAsync("Admin")
|
||||
]);
|
||||
}
|
||||
|
||||
private async Task SubmitForReview() {
|
||||
if (Article.AllowedToSubmitForReview(HttpContext.User) is false) return;
|
||||
|
||||
await using var context = await ContextFactory.CreateDbContextAsync();
|
||||
Article!.Status = ArticleStatus.InReview;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ReviewerId)) {
|
||||
Article.Reviewer = Reviewers.First(r => r.Id == ReviewerId);
|
||||
}
|
||||
|
||||
context.Update(Article);
|
||||
await context.SaveChangesAsync();
|
||||
Message.ShowSuccess(Localizer["Submit_Review_Success"]);
|
||||
|
||||
try {
|
||||
List<ApplicationUser> reviewers = [
|
||||
.. await UserManager.GetUsersInRoleAsync("Reviewer"),
|
||||
.. await UserManager.GetUsersInRoleAsync("Admin")
|
||||
];
|
||||
if (reviewers.Count > 0) {
|
||||
if (Reviewers.Count > 0) {
|
||||
await EmailService.ConnectAsync(CancellationToken.None);
|
||||
|
||||
foreach (var reviewer in reviewers) {
|
||||
if (reviewer.Id == HttpContext.User.FindFirst("Id")!.Value) continue;
|
||||
if (!string.IsNullOrWhiteSpace(ReviewerId) && Article.Reviewer is not null) {
|
||||
if (Article.Reviewer.Id != HttpContext.User.FindFirst("Id")!.Value) {
|
||||
var email = await Email.CreateDefaultEmail(
|
||||
Article.Reviewer.Email!,
|
||||
Article.Reviewer.Name,
|
||||
"Article submitted for Review",
|
||||
"Article submitted for Review",
|
||||
$"<p>The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.</p>",
|
||||
$"The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.");
|
||||
// TODO check if they enabled email notifications (property currently not implemented)
|
||||
await EmailService.SendEmailAsync(email);
|
||||
}
|
||||
} else {
|
||||
foreach (var reviewer in Reviewers) {
|
||||
if (reviewer.Id == HttpContext.User.FindFirst("Id")!.Value) continue;
|
||||
|
||||
var email = await Email.CreateDefaultEmail(
|
||||
reviewer.Email!,
|
||||
reviewer.Name,
|
||||
"Article submitted for Review",
|
||||
"Article submitted for Review",
|
||||
$"<p>The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.</p>",
|
||||
$"The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.");
|
||||
// TODO check if they enabled email notifications (property currently not implemented)
|
||||
await EmailService.SendEmailAsync(email);
|
||||
var email = await Email.CreateDefaultEmail(
|
||||
reviewer.Email!,
|
||||
reviewer.Name,
|
||||
"Article submitted for Review",
|
||||
"Article submitted for Review",
|
||||
$"<p>The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.</p>",
|
||||
$"The Article '{Article.Title}' by {Article.Author.Name} has been submitted for review.");
|
||||
// TODO check if they enabled email notifications (property currently not implemented)
|
||||
await EmailService.SendEmailAsync(email);
|
||||
}
|
||||
}
|
||||
|
||||
await EmailService.DisconnectAsync(CancellationToken.None);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@using Wave.Data
|
||||
|
||||
@if (!DisableProfileLink) {
|
||||
<a href="/profile/@Profile.Id">
|
||||
<a href="/profile/@Profile.Id" class="w-full sm:w-56">
|
||||
<div class="rounded bg-base-200 text-base-content flex content-center w-full sm:w-56">
|
||||
<div class="w-16 h-16"><ProfilePictureComponent Size="200" ProfileId="@Profile.Id" /></div>
|
||||
<div class="flex flex-col p-2">
|
||||
|
|
|
@ -149,4 +149,7 @@
|
|||
<data name="Delete_Warning" xml:space="preserve">
|
||||
<value>Ihr Artikel wird runtergenommen. Bitte beachten Sie das Suchmaschinen eventuell noch links zu diesem Artikel haben, welche dann eine Fehlernachricht produzieren. Der Artikel ist womöglich noch in manchen Caches für die nächsten paar Stunden auffindbar. </value>
|
||||
</data>
|
||||
<data name="Review_Reviewer_Any" xml:space="preserve">
|
||||
<value>Jeder</value>
|
||||
</data>
|
||||
</root>
|
|
@ -149,4 +149,7 @@
|
|||
<data name="Delete_Warning" xml:space="preserve">
|
||||
<value>This will take down your Article. Please keep in mind that search engines may still have links to this article, which will produce error messages. The Article may still be accessable in some caches the next couple of hours.</value>
|
||||
</data>
|
||||
<data name="Review_Reviewer_Any" xml:space="preserve">
|
||||
<value>Anyone</value>
|
||||
</data>
|
||||
</root>
|
|
@ -48,7 +48,15 @@ public static class Permissions {
|
|||
|
||||
// Reviewers can edit in-review articles
|
||||
if (article.Status is ArticleStatus.InReview && principal.IsInRole("Reviewer")) {
|
||||
return true;
|
||||
// Nobody is reviewing this article yet
|
||||
if (article.Reviewer is null || article.Reviewer.Id == article.Author.Id) {
|
||||
return true;
|
||||
}
|
||||
// This reviewer is the Reviewer of the article
|
||||
if (article.Reviewer?.Id == principal.FindFirst("Id")!.Value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Moderators can edit published/-ing articles
|
||||
|
@ -107,7 +115,15 @@ public static class Permissions {
|
|||
|
||||
// Reviewers can reject/delete in-review articles
|
||||
if (article.Status is ArticleStatus.InReview && principal.IsInRole("Reviewer")) {
|
||||
return true;
|
||||
// Nobody is reviewing this article yet
|
||||
if (article.Reviewer is null || article.Reviewer.Id == article.Author.Id) {
|
||||
return true;
|
||||
}
|
||||
// This reviewer is the Reviewer of the article
|
||||
if (article.Reviewer?.Id == principal.FindFirst("Id")!.Value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Moderators can take down articles
|
||||
|
|
2
Wave/wwwroot/css/main.min.css
vendored
2
Wave/wwwroot/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue