fdfeeed6d9
Add some support for comment visibility, fix #217 This add a new column to comment, denoting if they are public or not, and a new table linking private comments to those allowed to read them. There is currently no way to write a private comment from Plume. Git is having a hard time what happened in Comment::from_activity, but most of it is just re-indentation because a new block was needed to please the borrow checker. I've marked with comments where things actually changed. At this point only mentioned users can see private comments, even when posted as "follower only" or equivalent. What should we do when someone isn't allowed to see a comment? Hide the whole thread, or just the comment? If hiding just the comment, should we mark there is a comment one can't see, but answers they can, or put other comments like if they answered to the same comment the hidden one do?
159 lines
7.8 KiB
HTML
159 lines
7.8 KiB
HTML
@use templates::{base, partials::comment};
|
|
@use template_utils::*;
|
|
@use plume_models::blogs::Blog;
|
|
@use plume_models::comments::{Comment, CommentTree};
|
|
@use plume_models::posts::Post;
|
|
@use plume_models::tags::Tag;
|
|
@use plume_models::users::User;
|
|
@use validator::ValidationErrors;
|
|
@use routes::comments::NewCommentForm;
|
|
@use routes::*;
|
|
|
|
@(ctx: BaseContext, article: Post, blog: Blog, comment_form: &NewCommentForm, comment_errors: ValidationErrors, tags: Vec<Tag>, comments: Vec<CommentTree>, previous_comment: Option<Comment>, n_likes: i64, n_reshares: i64, has_liked: bool, has_reshared: bool, is_following: bool, author: User)
|
|
|
|
@:base(ctx, &article.title.clone(), {
|
|
<meta property="og:title" content="@article.title"/>
|
|
<meta property="og:type" content="article"/>
|
|
@if article.cover_id.is_some() {
|
|
<meta property="og:image" content="@Html(article.cover_url(ctx.0).unwrap_or_default())"/>
|
|
}
|
|
<meta property="og:url" content="@uri!(posts::details: blog = blog.get_fqn(ctx.0), slug = &article.slug, responding_to = _)"/>
|
|
<meta property="og:description" content="@article.subtitle"/>
|
|
}, {
|
|
<a href="@uri!(blogs::details: name = blog.get_fqn(ctx.0), page = _)">@blog.title</a>
|
|
}, {
|
|
<div class="h-entry">
|
|
<h1 class="article p-name">@&article.title</h1>
|
|
<h2 class="article p-summary">@&article.subtitle</h2>
|
|
<div class="article-info">
|
|
<span class="author">
|
|
@Html(i18n!(ctx.1, "Written by {0}"; format!("<a href=\"{}\">{}</a>",
|
|
uri!(user::details: name = &author.get_fqn(ctx.0)),
|
|
escape(&author.name(ctx.0)))))
|
|
</span>
|
|
—
|
|
<span class="date dt-published" datetime="@article.creation_date.format("%F %T")">@article.creation_date.format("%B %e, %Y")</span><a class="u-url" href="@article.ap_url"></a>
|
|
@if ctx.2.clone().map(|u| u.id == author.id).unwrap_or(false) {
|
|
—
|
|
<a href="@uri!(posts::edit: blog = blog.get_fqn(ctx.0), slug = &article.slug)">@i18n!(ctx.1, "Edit")</a>
|
|
—
|
|
<form class="inline" method="post" action="@uri!(posts::delete: blog_name = blog.get_fqn(ctx.0), slug = &article.slug)">
|
|
<input onclick="return confirm('Are you sure you?')" type="submit" value="@i18n!(ctx.1, "Delete this article")">
|
|
</form>
|
|
}
|
|
@if !article.published {
|
|
<span class="badge">@i18n!(ctx.1, "Draft")</span>
|
|
}
|
|
</div>
|
|
@if article.cover_id.is_some() {
|
|
<div class="cover" style="background-image: url('@Html(article.cover_url(ctx.0).unwrap_or_default())')"></div>
|
|
<img class="hidden u-photo" src="@article.cover_url(ctx.0).unwrap_or_default()" />
|
|
}
|
|
<article class="e-content">
|
|
@Html(&article.content)
|
|
</article>
|
|
<div class="article-meta">
|
|
<p>
|
|
@if article.license.is_empty() {
|
|
@i18n!(ctx.1, "All rights reserved."; &article.license)
|
|
} else {
|
|
@i18n!(ctx.1, "This article is under the {0} license."; &article.license)
|
|
}
|
|
</p>
|
|
<ul class="tags">
|
|
@for tag in tags {
|
|
@if !tag.is_hashtag {
|
|
<li><a class="p-category" href="@uri!(tags::tag: name = &tag.tag, page = _)">@tag.tag</a></li>
|
|
} else {
|
|
<span class="hidden p-category">@tag.tag</span>
|
|
}
|
|
}
|
|
</ul>
|
|
<div class="flex p-author h-card">
|
|
@avatar(ctx.0, &author, Size::Medium, true, ctx.1)
|
|
<div class="grow">
|
|
<h2 class="p-name">
|
|
<a href="@uri!(user::details: name = author.get_fqn(ctx.0))">@author.name(ctx.0)</a>
|
|
<a rel="author" class="u-url" href="@author.ap_url"></a>
|
|
</h2>
|
|
<p>@Html(&author.summary)</h2>
|
|
</div>
|
|
@if !ctx.2.as_ref().map(|u| u.id == author.id).unwrap_or(false) {
|
|
<form action="@uri!(user::follow: name = author.get_fqn(ctx.0))" method="POST">
|
|
<input type="submit" class="button" value="@if is_following {@i18n!(ctx.1, "Unfollow")} else {@i18n!(ctx.1, "Follow")}">
|
|
</form>
|
|
}
|
|
</div>
|
|
@if ctx.2.is_some() {
|
|
<div class="actions">
|
|
<form class="likes" action="@uri!(likes::create: blog = blog.get_fqn(ctx.0), slug = &article.slug)" method="POST">
|
|
<p aria-label="@i18n!(ctx.1, "One like", "{0} likes", &n_likes)" title="@i18n!(ctx.1, "One like", "{0} likes", n_likes)">
|
|
@n_likes
|
|
</p>
|
|
|
|
@if has_liked {
|
|
<button type="submit" class="action liked">@icon!("heart") @i18n!(ctx.1, "I don't like this anymore")</button>
|
|
} else {
|
|
<button type="submit" class="action">@icon!("heart") @i18n!(ctx.1, "Add yours")</button>
|
|
}
|
|
</form>
|
|
<form class="reshares" action="@uri!(reshares::create: blog = blog.get_fqn(ctx.0), slug = &article.slug)" method="POST">
|
|
<p aria-label="@i18n!(ctx.1, "One boost", "{0} boost", &n_reshares)" title="@i18n!(ctx.1, "One boost", "{0} boosts", n_reshares)">
|
|
@n_reshares
|
|
</p>
|
|
|
|
@if has_reshared {
|
|
<button type="submit" class="action reshared">@icon!("repeat") @i18n!(ctx.1, "I don't want to boost this anymore")</button>
|
|
} else {
|
|
<button type="submit" class="action">@icon!("repeat") @i18n!(ctx.1, "Boost")</button>
|
|
}
|
|
</form>
|
|
</div>
|
|
} else {
|
|
<p class="center">@i18n!(ctx.1, "Login or use your Fediverse account to interact with this article")</p>
|
|
<div class="actions">
|
|
<div class="likes">
|
|
<p aria-label="@i18n!(ctx.1, "One like", "{0} likes", &n_likes)" title="@i18n!(ctx.1, "One like", "{0} likes", n_likes)">
|
|
@n_likes
|
|
</p>
|
|
<a href="@uri!(session::new: m = i18n!(ctx.1, "Login to like"))" class="action">@icon!("heart") @i18n!(ctx.1, "Add yours")</a>
|
|
</div>
|
|
|
|
<div class="reshares">
|
|
<p aria-label="@i18n!(ctx.1, "One boost", "{0} boost", &n_reshares)" title="@i18n!(ctx.1, "One boost", "{0} boosts", n_reshares)">
|
|
@n_reshares
|
|
</p>
|
|
<a href="@uri!(session::new: m = i18n!(ctx.1, "Login to boost"))" class="action">@icon!("repeat") @i18n!(ctx.1, "Boost")</a>
|
|
</div>
|
|
</div>
|
|
}
|
|
<div class="comments">
|
|
<h2>@i18n!(ctx.1, "Comments")</h2>
|
|
|
|
@if ctx.2.is_some() {
|
|
<form method="post" action="@uri!(comments::create: blog_name = blog.get_fqn(ctx.0), slug = &article.slug)">
|
|
@input!(ctx.1, warning (optional text), "Content warning", comment_form, comment_errors, "")
|
|
|
|
<label for="plume-editor">@i18n!(ctx.1, "Your comment")</label>
|
|
@if let Some(ref prev) = previous_comment {
|
|
<input type="hidden" name="responding_to" value="@prev.id"/>
|
|
}
|
|
<textarea id="plume-editor" name="content">@comment_form.content</textarea>
|
|
<input type="submit" value="@i18n!(ctx.1, "Submit comment")" />
|
|
</form>
|
|
}
|
|
|
|
@if !comments.is_empty() {
|
|
<div class="list">
|
|
@for comm in comments {
|
|
@:comment(ctx, &comm, Some(&article.ap_url), &blog.get_fqn(ctx.0), &article.slug)
|
|
}
|
|
</div>
|
|
} else {
|
|
<p class="center">@i18n!(ctx.1, "No comments yet. Be the first to react!")</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
})
|