Server: Add admin reports, server pagination
This commit is contained in:
parent
c1ac9eeed4
commit
555aba8d36
221
src/admin/mod.rs
221
src/admin/mod.rs
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
error::{Error, OptionExt},
|
error::{Error, OptionExt},
|
||||||
extensions::{CommentExt, ProfileExt, SubmissionExt},
|
extensions::{CommentExt, ProfileExt, SubmissionExt},
|
||||||
nav::NavState,
|
nav::NavState,
|
||||||
pagination::{PageNum, SearchPage},
|
pagination::{Page, PageNum, PageSource, SearchPage},
|
||||||
views::{OwnedProfileView, OwnedSubmissionView},
|
views::{OwnedProfileView, OwnedSubmissionView},
|
||||||
ActixLoader, State,
|
ActixLoader, State,
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,8 @@ pub use hyaenidae_profiles::store::Report;
|
||||||
|
|
||||||
mod pagination;
|
mod pagination;
|
||||||
use pagination::{
|
use pagination::{
|
||||||
BlockedPager, FederatedPager, InboundPager, KnownPager, OutboundPager, ServerPager,
|
BlockedPager, ClosedPager, FederatedPager, InboundPager, KnownPager, OpenPager, OutboundPager,
|
||||||
|
ReportPager, ServerPager,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn scope() -> Scope {
|
pub(super) fn scope() -> Scope {
|
||||||
|
@ -123,20 +124,21 @@ async fn discover_server(
|
||||||
Ok(()) as Result<(), Error>
|
Ok(()) as Result<(), Error>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let query = query.into_inner();
|
||||||
if let Err(e) = (fallible)().await {
|
if let Err(e) = (fallible)().await {
|
||||||
let mut federation_view = FederationView::build(query.into_inner(), &state2).await?;
|
let mut federation_view = FederationView::build(query.clone(), &state2).await?;
|
||||||
federation_view
|
federation_view
|
||||||
.discover_error(e.to_string())
|
.discover_error(e.to_string())
|
||||||
.discover_value(url2);
|
.discover_value(url2);
|
||||||
|
|
||||||
let server_view = ServerView::build(&state2).await?;
|
let server_view = ServerView::build(&state2).await?;
|
||||||
let open_reports = ReportsView::new(state2).await?;
|
let reports_vew = ReportsView::new(query, state2).await?;
|
||||||
|
|
||||||
return crate::rendered(HttpResponse::Ok(), |cursor| {
|
return crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||||
crate::templates::admin::index(
|
crate::templates::admin::index(
|
||||||
cursor,
|
cursor,
|
||||||
&loader,
|
&loader,
|
||||||
&open_reports,
|
&reports_vew,
|
||||||
&server_view,
|
&server_view,
|
||||||
&federation_view,
|
&federation_view,
|
||||||
&nav_state,
|
&nav_state,
|
||||||
|
@ -878,6 +880,17 @@ impl FederationView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn page_source(query: &HashMap<String, String>, prefix: &str) -> Option<PageSource> {
|
||||||
|
query
|
||||||
|
.get(&format!("{}_min", prefix))
|
||||||
|
.and_then(|min_str| Some(PageSource::NewerThan(min_str.parse().ok()?)))
|
||||||
|
.or_else(|| {
|
||||||
|
query
|
||||||
|
.get(&format!("{}_max", prefix))
|
||||||
|
.and_then(|max_str| Some(PageSource::OlderThan(max_str.parse().ok()?)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn page_num(query: &HashMap<String, String>, name: &str) -> Option<PageNum> {
|
fn page_num(query: &HashMap<String, String>, name: &str) -> Option<PageNum> {
|
||||||
query.get(name).and_then(|page_str| {
|
query.get(name).and_then(|page_str| {
|
||||||
Some(PageNum {
|
Some(PageNum {
|
||||||
|
@ -923,7 +936,7 @@ async fn view_report(
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let report_id = report.into_inner();
|
let report_id = report.into_inner();
|
||||||
let report_store = state.profiles.store.reports.clone();
|
let report_store = state.profiles.store.reports.clone();
|
||||||
let report = web::block(move || Ok(report_store.by_id(report_id)?)).await?;
|
let report = web::block(move || report_store.by_id(report_id)?.req()).await?;
|
||||||
|
|
||||||
let report_view = ReportView::new(report, state).await?;
|
let report_view = ReportView::new(report, state).await?;
|
||||||
|
|
||||||
|
@ -966,7 +979,7 @@ async fn close_report(
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let report_id = report.into_inner();
|
let report_id = report.into_inner();
|
||||||
let report_store = state.profiles.store.reports.clone();
|
let report_store = state.profiles.store.reports.clone();
|
||||||
let report = web::block(move || Ok(report_store.by_id(report_id)?)).await?;
|
let report = web::block(move || report_store.by_id(report_id)?.req()).await?;
|
||||||
|
|
||||||
let form = form.into_inner();
|
let form = form.into_inner();
|
||||||
|
|
||||||
|
@ -1110,15 +1123,16 @@ async fn admin_page(
|
||||||
nav_state: NavState,
|
nav_state: NavState,
|
||||||
state: web::Data<State>,
|
state: web::Data<State>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let federation_view = FederationView::build(query.into_inner(), &state).await?;
|
let query = query.into_inner();
|
||||||
|
let federation_view = FederationView::build(query.clone(), &state).await?;
|
||||||
let server_view = ServerView::build(&state).await?;
|
let server_view = ServerView::build(&state).await?;
|
||||||
let open_reports = ReportsView::new(state).await?;
|
let reports_vew = ReportsView::new(query, state).await?;
|
||||||
|
|
||||||
crate::rendered(HttpResponse::Ok(), |cursor| {
|
crate::rendered(HttpResponse::Ok(), |cursor| {
|
||||||
crate::templates::admin::index(
|
crate::templates::admin::index(
|
||||||
cursor,
|
cursor,
|
||||||
&loader,
|
&loader,
|
||||||
&open_reports,
|
&reports_vew,
|
||||||
&server_view,
|
&server_view,
|
||||||
&federation_view,
|
&federation_view,
|
||||||
&nav_state,
|
&nav_state,
|
||||||
|
@ -1417,7 +1431,10 @@ impl ServerView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReportsView {
|
pub struct ReportsView {
|
||||||
reports: Vec<Report>,
|
query: HashMap<String, String>,
|
||||||
|
open_reports: Page,
|
||||||
|
closed_reports: Page,
|
||||||
|
reports: HashMap<Uuid, Report>,
|
||||||
profiles: HashMap<Uuid, Profile>,
|
profiles: HashMap<Uuid, Profile>,
|
||||||
submissions: HashMap<Uuid, Submission>,
|
submissions: HashMap<Uuid, Submission>,
|
||||||
comments: HashMap<Uuid, Comment>,
|
comments: HashMap<Uuid, Comment>,
|
||||||
|
@ -1511,8 +1528,94 @@ impl<'a> SubmissionView<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReportsView {
|
impl ReportsView {
|
||||||
pub(crate) fn reports(&self) -> &[Report] {
|
pub(crate) fn open_reports<'a>(&'a self) -> impl Iterator<Item = &'a Report> + 'a {
|
||||||
&self.reports
|
self.open_reports
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.filter_map(move |report_id| self.reports.get(report_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_open_reports_nav(&self) -> bool {
|
||||||
|
self.open_reports.prev.is_some() || self.open_reports.next.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn open_reports_nav(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||||
|
let mut btns = vec![];
|
||||||
|
|
||||||
|
if let Some(prev) = self.open_reports.prev {
|
||||||
|
let mut query = self.query.clone();
|
||||||
|
query.insert("open_min".to_owned(), prev.to_string());
|
||||||
|
query.remove("open_max");
|
||||||
|
|
||||||
|
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||||
|
format!("/admin?{}", query)
|
||||||
|
} else {
|
||||||
|
"/admin".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
btns.push(Button::secondary(&fl!(loader, "admin-reports-prev")).href(&href));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(next) = self.open_reports.next {
|
||||||
|
let mut query = self.query.clone();
|
||||||
|
query.insert("open_max".to_owned(), next.to_string());
|
||||||
|
query.remove("open_min");
|
||||||
|
|
||||||
|
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||||
|
format!("/admin?{}", query)
|
||||||
|
} else {
|
||||||
|
"/admin".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
btns.push(Button::secondary(&fl!(loader, "admin-reports-next")).href(&href));
|
||||||
|
}
|
||||||
|
|
||||||
|
btns
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn closed_reports<'a>(&'a self) -> impl Iterator<Item = &'a Report> + 'a {
|
||||||
|
self.closed_reports
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.filter_map(move |report_id| self.reports.get(report_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_closed_reports_nav(&self) -> bool {
|
||||||
|
self.closed_reports.prev.is_some() || self.closed_reports.next.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn closed_reports_nav(&self, loader: &ActixLoader) -> Vec<Button> {
|
||||||
|
let mut btns = vec![];
|
||||||
|
|
||||||
|
if let Some(prev) = self.closed_reports.prev {
|
||||||
|
let mut query = self.query.clone();
|
||||||
|
query.insert("closed_min".to_owned(), prev.to_string());
|
||||||
|
query.remove("closed_max");
|
||||||
|
|
||||||
|
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||||
|
format!("/admin?{}", query)
|
||||||
|
} else {
|
||||||
|
"/admin".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
btns.push(Button::secondary(&fl!(loader, "admin-reports-prev")).href(&href));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(next) = self.closed_reports.next {
|
||||||
|
let mut query = self.query.clone();
|
||||||
|
query.insert("closed_max".to_owned(), next.to_string());
|
||||||
|
query.remove("closed_min");
|
||||||
|
|
||||||
|
let href = if let Ok(query) = serde_urlencoded::to_string(query) {
|
||||||
|
format!("/admin?{}", query)
|
||||||
|
} else {
|
||||||
|
"/admin".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
btns.push(Button::secondary(&fl!(loader, "admin-reports-next")).href(&href));
|
||||||
|
}
|
||||||
|
|
||||||
|
btns
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn view_path(&self, report: &Report) -> String {
|
pub(crate) fn view_path(&self, report: &Report) -> String {
|
||||||
|
@ -1555,80 +1658,46 @@ impl ReportsView {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn new(state: web::Data<State>) -> Result<Self, Error> {
|
async fn new(query: HashMap<String, String>, state: web::Data<State>) -> Result<Self, Error> {
|
||||||
let store = state.profiles.clone();
|
let store = state.profiles.clone();
|
||||||
|
|
||||||
let view = web::block(move || {
|
let view = web::block(move || {
|
||||||
|
let mut reports = HashMap::new();
|
||||||
let mut profiles = HashMap::new();
|
let mut profiles = HashMap::new();
|
||||||
let mut submissions = HashMap::new();
|
let mut submissions = HashMap::new();
|
||||||
let mut comments = HashMap::new();
|
let mut comments = HashMap::new();
|
||||||
let mut files = HashMap::new();
|
let mut files = HashMap::new();
|
||||||
|
|
||||||
let reports = store
|
let open_reports = Page::from_pagination(
|
||||||
.store
|
OpenPager(ReportPager {
|
||||||
.reports
|
store: &store.store,
|
||||||
.all()
|
reports: &mut reports,
|
||||||
.filter_map(|id| {
|
profiles: &mut profiles,
|
||||||
let report = store.store.reports.by_id(id).ok()?;
|
submissions: &mut submissions,
|
||||||
|
comments: &mut comments,
|
||||||
|
files: &mut files,
|
||||||
|
}),
|
||||||
|
10,
|
||||||
|
page_source(&query, "open"),
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(id) = report.reporter_profile() {
|
let closed_reports = Page::from_pagination(
|
||||||
if !profiles.contains_key(&id) {
|
ClosedPager(ReportPager {
|
||||||
let profile = store.store.profiles.by_id(id).ok()??;
|
store: &store.store,
|
||||||
profiles.insert(profile.id(), profile);
|
reports: &mut reports,
|
||||||
}
|
profiles: &mut profiles,
|
||||||
}
|
submissions: &mut submissions,
|
||||||
|
comments: &mut comments,
|
||||||
match report.kind() {
|
files: &mut files,
|
||||||
ReportKind::Profile => {
|
}),
|
||||||
if !profiles.contains_key(&report.item()) {
|
10,
|
||||||
let profile = store.store.profiles.by_id(report.item()).ok()??;
|
page_source(&query, "closed"),
|
||||||
profiles.insert(profile.id(), profile);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
ReportKind::Submission => {
|
|
||||||
if !submissions.contains_key(&report.item()) {
|
|
||||||
let submission =
|
|
||||||
store.store.submissions.by_id(report.item()).ok()??;
|
|
||||||
|
|
||||||
if !profiles.contains_key(&submission.profile_id()) {
|
|
||||||
let profile = store
|
|
||||||
.store
|
|
||||||
.profiles
|
|
||||||
.by_id(submission.profile_id())
|
|
||||||
.ok()??;
|
|
||||||
profiles.insert(profile.id(), profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
for file_id in submission.files() {
|
|
||||||
if !files.contains_key(file_id) {
|
|
||||||
let file = store.store.files.by_id(*file_id).ok()??;
|
|
||||||
files.insert(file.id(), file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submissions.insert(submission.id(), submission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ReportKind::Comment => {
|
|
||||||
if !comments.contains_key(&report.item()) {
|
|
||||||
let comment = store.store.comments.by_id(report.item()).ok()??;
|
|
||||||
if !profiles.contains_key(&comment.profile_id()) {
|
|
||||||
let profile =
|
|
||||||
store.store.profiles.by_id(comment.profile_id()).ok()??;
|
|
||||||
profiles.insert(profile.id(), profile);
|
|
||||||
}
|
|
||||||
comments.insert(comment.id(), comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(report)
|
|
||||||
})
|
|
||||||
.rev()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(ReportsView {
|
Ok(ReportsView {
|
||||||
|
query,
|
||||||
|
open_reports,
|
||||||
|
closed_reports,
|
||||||
reports,
|
reports,
|
||||||
profiles,
|
profiles,
|
||||||
submissions,
|
submissions,
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
use crate::pagination::SearchPagination;
|
use crate::pagination::{Pagination, SearchPagination};
|
||||||
use hyaenidae_profiles::store::Server;
|
use hyaenidae_profiles::store::{Comment, File, Profile, Report, ReportKind, Server, Submission};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub(super) struct ReportPager<'b> {
|
||||||
|
pub(super) store: &'b hyaenidae_profiles::store::Store,
|
||||||
|
pub(super) reports: &'b mut HashMap<Uuid, Report>,
|
||||||
|
pub(super) profiles: &'b mut HashMap<Uuid, Profile>,
|
||||||
|
pub(super) submissions: &'b mut HashMap<Uuid, Submission>,
|
||||||
|
pub(super) comments: &'b mut HashMap<Uuid, Comment>,
|
||||||
|
pub(super) files: &'b mut HashMap<Uuid, File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct OpenPager<'b>(pub(super) ReportPager<'b>);
|
||||||
|
pub(super) struct ClosedPager<'b>(pub(super) ReportPager<'b>);
|
||||||
|
|
||||||
pub(super) struct ServerPager<'b> {
|
pub(super) struct ServerPager<'b> {
|
||||||
pub(super) self_id: Uuid,
|
pub(super) self_id: Uuid,
|
||||||
pub(super) store: &'b hyaenidae_profiles::store::Store,
|
pub(super) store: &'b hyaenidae_profiles::store::Store,
|
||||||
|
@ -15,6 +27,153 @@ pub(super) struct OutboundPager<'a>(pub(super) ServerPager<'a>);
|
||||||
pub(super) struct BlockedPager<'a>(pub(super) ServerPager<'a>);
|
pub(super) struct BlockedPager<'a>(pub(super) ServerPager<'a>);
|
||||||
pub(super) struct KnownPager<'a>(pub(super) ServerPager<'a>);
|
pub(super) struct KnownPager<'a>(pub(super) ServerPager<'a>);
|
||||||
|
|
||||||
|
impl<'b> Pagination for OpenPager<'b> {
|
||||||
|
fn from_max<'a>(&'a mut self, max: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.open_reports_older_than(max)
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_min<'a>(&'a mut self, min: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.open_reports_newer_than(min)
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_start<'a>(&'a mut self) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.open_reports()
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> Pagination for ClosedPager<'b> {
|
||||||
|
fn from_max<'a>(&'a mut self, max: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.closed_reports_older_than(max)
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_min<'a>(&'a mut self, min: Uuid) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.closed_reports_newer_than(min)
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_start<'a>(&'a mut self) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
|
Box::new(
|
||||||
|
self.0
|
||||||
|
.store
|
||||||
|
.reports
|
||||||
|
.closed_reports()
|
||||||
|
.filter_map(move |report_id| self.0.filter_report(report_id)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> ReportPager<'b> {
|
||||||
|
fn filter_report(&mut self, report_id: Uuid) -> Option<Uuid> {
|
||||||
|
if !self.reports.contains_key(&report_id) {
|
||||||
|
let report = self.store.reports.by_id(report_id).ok()??;
|
||||||
|
|
||||||
|
if let Some(id) = report.reporter_profile() {
|
||||||
|
self.cache_profile(id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match report.kind() {
|
||||||
|
ReportKind::Profile => {
|
||||||
|
self.cache_profile(report.item())?;
|
||||||
|
}
|
||||||
|
ReportKind::Submission => {
|
||||||
|
self.cache_submission(report.item())?;
|
||||||
|
}
|
||||||
|
ReportKind::Comment => {
|
||||||
|
self.cache_comment(report.item())?;
|
||||||
|
}
|
||||||
|
ReportKind::Post => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.reports.insert(report.id(), report);
|
||||||
|
|
||||||
|
Some(report_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_comment(&mut self, comment_id: Uuid) -> Option<()> {
|
||||||
|
if !self.comments.contains_key(&comment_id) {
|
||||||
|
let comment = self.store.comments.by_id(comment_id).ok()??;
|
||||||
|
|
||||||
|
self.cache_profile(comment.profile_id())?;
|
||||||
|
self.comments.insert(comment.id(), comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_submission(&mut self, submission_id: Uuid) -> Option<()> {
|
||||||
|
if !self.submissions.contains_key(&submission_id) {
|
||||||
|
let submission = self.store.submissions.by_id(submission_id).ok()??;
|
||||||
|
|
||||||
|
self.cache_profile(submission.profile_id())?;
|
||||||
|
|
||||||
|
for file_id in submission.files() {
|
||||||
|
self.cache_file(*file_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.submissions.insert(submission.id(), submission);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_profile(&mut self, profile_id: Uuid) -> Option<()> {
|
||||||
|
if !self.profiles.contains_key(&profile_id) {
|
||||||
|
let profile = self.store.profiles.by_id(profile_id).ok()??;
|
||||||
|
|
||||||
|
for file_id in profile.icon().into_iter().chain(profile.banner()) {
|
||||||
|
self.cache_file(file_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.profiles.insert(profile.id(), profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache_file(&mut self, file_id: Uuid) -> Option<()> {
|
||||||
|
if !self.files.contains_key(&file_id) {
|
||||||
|
let file = self.store.files.by_id(file_id).ok()??;
|
||||||
|
self.files.insert(file.id(), file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'b> SearchPagination for FederatedPager<'b> {
|
impl<'b> SearchPagination for FederatedPager<'b> {
|
||||||
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
fn from_term<'a>(&'a mut self, _: &'a str) -> Box<dyn DoubleEndedIterator<Item = Uuid> + 'a> {
|
||||||
Box::new(
|
Box::new(
|
||||||
|
|
|
@ -154,6 +154,10 @@ impl NavState {
|
||||||
"/notifications"
|
"/notifications"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_admin(&self) -> bool {
|
||||||
|
self.admin.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn admin_button(&self, loader: &ActixLoader) -> Button {
|
pub(crate) fn admin_button(&self, loader: &ActixLoader) -> Button {
|
||||||
Button::link(&fl!(loader, "nav-admin-button")).href("/admin")
|
Button::link(&fl!(loader, "nav-admin-button")).href("/admin")
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,53 +36,55 @@
|
||||||
@:card_title({
|
@:card_title({
|
||||||
@fl!(loader, "admin-reports-heading")
|
@fl!(loader, "admin-reports-heading")
|
||||||
})
|
})
|
||||||
@for report in reports_view.reports() {
|
@for report in reports_view.open_reports() {
|
||||||
@:card_body({
|
@:card_body({
|
||||||
<div class="report">
|
<div class="report">
|
||||||
<div class="report-head">
|
<div class="report-left">
|
||||||
@if let Some(profile) = reports_view.profile(report) {
|
<div class="report-head">
|
||||||
@:reporter(reports_view, report, {
|
@if let Some(profile) = reports_view.profile(report) {
|
||||||
@fl!(loader, "admin-reports-reported")
|
@:reporter(reports_view, report, {
|
||||||
|
@fl!(loader, "admin-reports-reported")
|
||||||
|
|
||||||
@:link(&Link::new_tab(&profile.view_path()).plain(true), {
|
@:link(&Link::new_tab(&profile.view_path()).plain(true), {
|
||||||
@Html(profile.name())
|
@Html(profile.name())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
@if let Some(submission) = reports_view.submission(report) {
|
||||||
@if let Some(submission) = reports_view.submission(report) {
|
@:reporter(reports_view, report, {
|
||||||
@:reporter(reports_view, report, {
|
@fl!(loader, "admin-reports-reported")
|
||||||
@fl!(loader, "admin-reports-reported")
|
|
||||||
|
|
||||||
@:link(&Link::new_tab(&submission.author_path()).plain(true), {
|
@:link(&Link::new_tab(&submission.author_path()).plain(true), {
|
||||||
@Html(fl!(loader, "author-owned", author = submission.author_name()))
|
@Html(fl!(loader, "author-owned", author = submission.author_name()))
|
||||||
})
|
})
|
||||||
@fl!(loader, "admin-reports-submission")
|
@fl!(loader, "admin-reports-submission")
|
||||||
|
|
||||||
@:link(&Link::new_tab(&submission.view_path()).plain(true), {
|
@:link(&Link::new_tab(&submission.view_path()).plain(true), {
|
||||||
@Html(submission.title())
|
@Html(submission.title())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
@if let Some(comment) = reports_view.comment(report) {
|
||||||
@if let Some(comment) = reports_view.comment(report) {
|
@:reporter(reports_view, report, {
|
||||||
@:reporter(reports_view, report, {
|
reported
|
||||||
reported
|
@:link(&Link::new_tab(&comment.author_path()).plain(true), {
|
||||||
@:link(&Link::new_tab(&comment.author_path()).plain(true), {
|
@Html(fl!(loader, "author-owned", author = comment.author_name()))
|
||||||
@Html(fl!(loader, "author-owned", author = comment.author_name()))
|
})
|
||||||
})
|
@fl!(loader, "admin-reports-comment")
|
||||||
@fl!(loader, "admin-reports-comment")
|
|
||||||
|
|
||||||
@:link(&Link::new_tab(&comment.view_path()).plain(true), {
|
@:link(&Link::new_tab(&comment.view_path()).plain(true), {
|
||||||
@Html(comment.body())
|
@Html(comment.body())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
</div>
|
||||||
|
@if let Some(note) = report.note() {
|
||||||
|
<div class="report-description text-section">
|
||||||
|
<h4>@fl!(loader, "admin-reports-note")</h4>
|
||||||
|
<p>@Html(note)</p>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@if let Some(note) = report.note() {
|
|
||||||
<div class="report-description text-section">
|
|
||||||
<h4>@fl!(loader, "admin-reports-note")</h4>
|
|
||||||
<p>@Html(note)</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="button-section report-actions">
|
<div class="button-section report-actions">
|
||||||
@:button_group(&[
|
@:button_group(&[
|
||||||
Button::secondary(&fl!(loader, "admin-reports-view-button")).href(&reports_view.view_path(report)),
|
Button::secondary(&fl!(loader, "admin-reports-view-button")).href(&reports_view.view_path(report)),
|
||||||
|
@ -91,6 +93,73 @@
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@if reports_view.has_open_reports_nav() {
|
||||||
|
@:card_body({
|
||||||
|
@:button_group(&reports_view.open_reports_nav(loader))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||||
|
@:card_title({
|
||||||
|
@fl!(loader, "admin-closed-reports-heading")
|
||||||
|
})
|
||||||
|
@for report in reports_view.closed_reports() {
|
||||||
|
@:card_body({
|
||||||
|
<div class="report">
|
||||||
|
<div class="report-left">
|
||||||
|
<div class="report-head">
|
||||||
|
@if let Some(profile) = reports_view.profile(report) {
|
||||||
|
@:reporter(reports_view, report, {
|
||||||
|
@fl!(loader, "admin-reports-reported")
|
||||||
|
|
||||||
|
@:link(&Link::new_tab(&profile.view_path()).plain(true), {
|
||||||
|
@Html(profile.name())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@if let Some(submission) = reports_view.submission(report) {
|
||||||
|
@:reporter(reports_view, report, {
|
||||||
|
@fl!(loader, "admin-reports-reported")
|
||||||
|
|
||||||
|
@:link(&Link::new_tab(&submission.author_path()).plain(true), {
|
||||||
|
@Html(fl!(loader, "author-owned", author = submission.author_name()))
|
||||||
|
})
|
||||||
|
@fl!(loader, "admin-reports-submission")
|
||||||
|
|
||||||
|
@:link(&Link::new_tab(&submission.view_path()).plain(true), {
|
||||||
|
@Html(submission.title())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@if let Some(comment) = reports_view.comment(report) {
|
||||||
|
@:reporter(reports_view, report, {
|
||||||
|
reported
|
||||||
|
@:link(&Link::new_tab(&comment.author_path()).plain(true), {
|
||||||
|
@Html(fl!(loader, "author-owned", author = comment.author_name()))
|
||||||
|
})
|
||||||
|
@fl!(loader, "admin-reports-comment")
|
||||||
|
|
||||||
|
@:link(&Link::new_tab(&comment.view_path()).plain(true), {
|
||||||
|
@Html(comment.body())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if let Some(note) = report.note() {
|
||||||
|
<div class="report-description text-section">
|
||||||
|
<h4>@fl!(loader, "admin-reports-note")</h4>
|
||||||
|
<p>@Html(note)</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@if reports_view.has_closed_reports_nav() {
|
||||||
|
@:card_body({
|
||||||
|
@:button_group(&reports_view.closed_reports_nav(loader))
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||||
<form method="POST" action="@federation_view.discover_path()">
|
<form method="POST" action="@federation_view.discover_path()">
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<div class="toolkit-button-group">
|
<div class="toolkit-button-group">
|
||||||
@:button(&nav_state.submission_button(loader))
|
@:button(&nav_state.submission_button(loader))
|
||||||
@:button(&nav_state.browse_button(loader))
|
@:button(&nav_state.browse_button(loader))
|
||||||
|
@if nav_state.is_admin() {
|
||||||
|
@:button(&nav_state.admin_button(loader))
|
||||||
|
}
|
||||||
@if nav_state.has_notifications() {
|
@if nav_state.has_notifications() {
|
||||||
@:icon_button("bell", &fl!(loader, "nav-notifications-button"), nav_state.notifications_path())
|
@:icon_button("bell", &fl!(loader, "nav-notifications-button"), nav_state.notifications_path())
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
})
|
})
|
||||||
@:card_body({
|
@:card_body({
|
||||||
<p>@fl!(loader, "report-description")</p>
|
<p>@fl!(loader, "report-description")</p>
|
||||||
@:text_input(&rview.input(loader))
|
@:text_input(&rview.input(loader).dark(nav_state.dark()))
|
||||||
})
|
})
|
||||||
@:card_body({
|
@:card_body({
|
||||||
@:button_group(&[
|
@:button_group(&[
|
||||||
|
|
|
@ -296,8 +296,11 @@ server-info-description-input = Description
|
||||||
server-info-description-placeholder = Describe your server
|
server-info-description-placeholder = Describe your server
|
||||||
server-info-submit-button = Save
|
server-info-submit-button = Save
|
||||||
|
|
||||||
admin-reports-heading = Reports
|
admin-closed-reports-heading = Closed Reports
|
||||||
|
admin-reports-heading = Open Reports
|
||||||
admin-reports-reported = reported
|
admin-reports-reported = reported
|
||||||
|
admin-reports-prev = Previous
|
||||||
|
admin-reports-next = Next
|
||||||
author-owned = {$author}'s
|
author-owned = {$author}'s
|
||||||
admin-reports-submission = submission:
|
admin-reports-submission = submission:
|
||||||
admin-reports-comment = comment:
|
admin-reports-comment = comment:
|
||||||
|
|
Loading…
Reference in a new issue