Skip to content

Commit

Permalink
first approach to archives ratings & comments
Browse files Browse the repository at this point in the history
  • Loading branch information
flosse committed Mar 8, 2019
1 parent bd19de7 commit 34f23b5
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 246 deletions.
3 changes: 3 additions & 0 deletions src/infrastructure/error.rs
Expand Up @@ -57,6 +57,9 @@ quick_error! {
String(err: ::std::string::FromUtf8Error){
from()
}
Str(err: ::std::str::Utf8Error){
from()
}
Csv(err: ::csv::Error){
from()
}
Expand Down
89 changes: 77 additions & 12 deletions src/ports/web/frontend/mod.rs
@@ -1,13 +1,17 @@
use crate::{
core::{prelude::*, usecases},
infrastructure::db::sqlite,
infrastructure::{db::sqlite, error::*, flows::prelude::*},
ports::web::{guards::*, tantivy::SearchEngine},
};
use maud::Markup;
use rocket::{
self,
http::RawStr,
response::content::{Css, JavaScript},
request::Form,
response::{
content::{Css, JavaScript},
Flash, Redirect,
},
Route,
};

Expand All @@ -18,6 +22,8 @@ mod view;
const MAP_JS: &str = include_str!("map.js");
const MAIN_CSS: &str = include_str!("main.css");

type Result<T> = std::result::Result<T, AppError>;

#[get("/")]
pub fn get_index_user(account: Account) -> Markup {
view::index(Some(&account.email()))
Expand All @@ -35,8 +41,9 @@ pub fn get_index_html() -> Markup {

#[get("/search?<q>&<limit>")]
pub fn get_search(search_engine: SearchEngine, q: &RawStr, limit: Option<usize>) -> Result<Markup> {
let entries = usecases::global_search(&search_engine, q.as_str(), limit.unwrap_or(10))?;
Ok(view::search_results(q.as_str(), &entries))
let q = q.url_decode()?;
let entries = usecases::global_search(&search_engine, &q, limit.unwrap_or(10))?;
Ok(view::search_results(None, &q, &entries))
}

#[get("/map.js")]
Expand All @@ -51,24 +58,40 @@ pub fn get_main_css() -> Css<&'static str> {

#[get("/events/<id>")]
pub fn get_event(db: sqlite::Connections, id: &RawStr) -> Result<Markup> {
let mut ev = usecases::get_event(&*db.shared().map_err(RepoError::from)?, &id)?;
let mut ev = usecases::get_event(&*db.shared()?, &id)?;
// TODO:
// Make sure within usecase that the creator email
// is not shown to unregistered users
ev.created_by = None;
Ok(view::event(ev))
Ok(view::event(None, ev))
}

#[get("/entries/<id>")]
pub fn get_entry_admin(pool: sqlite::Connections, id: &RawStr, admin: Admin) -> Result<Markup> {
//TODO: dry out
let (e, ratings) = {
let db = pool.shared()?;
let e = db.get_entry(id.as_str())?;
let ratings = db.load_ratings_of_entry(&e.id)?;
let ratings_with_comments = db.zip_ratings_with_comments(ratings)?;
(e, ratings_with_comments)
};
Ok(view::entry(
Some(&admin.0),
(e, ratings, Role::Admin).into(),
))
}

#[get("/entries/<id>", rank = 2)]
pub fn get_entry(pool: sqlite::Connections, id: &RawStr) -> Result<Markup> {
let (e, ratings) = {
let db = pool.shared().map_err(RepoError::from)?;
let db = pool.shared()?;
let e = db.get_entry(id.as_str())?;
let ratings = db.load_ratings_of_entry(&e.id)?;
let ratings_with_comments = db.zip_ratings_with_comments(ratings)?;
(e, ratings_with_comments)
};
Ok(view::entry((e, ratings).into()))
Ok(view::entry(None, (e, ratings).into()))
}

#[get("/events")]
Expand All @@ -78,8 +101,7 @@ pub fn get_events(db: sqlite::Connections) -> Result<Markup> {
.unwrap()
.naive_utc();
let mut events: Vec<_> = db
.shared()
.map_err(RepoError::from)?
.shared()?
.all_events()?
.into_iter()
.filter(|e| e.start > yesterday)
Expand All @@ -91,7 +113,7 @@ pub fn get_events(db: sqlite::Connections) -> Result<Markup> {
#[get("/dashboard")]
pub fn get_dashboard(db: sqlite::Connections, admin: Admin) -> Result<Markup> {
let data = {
let db = db.shared().map_err(RepoError::from)?;
let db = db.shared()?;
let tag_count = db.count_tags()?;
let entry_count = db.count_entries()?;
let user_count = db.count_users()?;
Expand All @@ -104,7 +126,47 @@ pub fn get_dashboard(db: sqlite::Connections, admin: Admin) -> Result<Markup> {
user_count,
}
};
Ok(view::dashboard(data))
Ok(view::dashboard(Some(&admin.0), data))
}

#[derive(FromForm)]
pub struct ArchiveAction {
ids: String,
entry_id: String,
}

#[post("/comments/actions/archive", data = "<data>")]
pub fn post_comments_archive(
db: sqlite::Connections,
data: Form<ArchiveAction>,
) -> std::result::Result<Redirect, Flash<Redirect>> {
//TODO: dry out
let d = data.into_inner();
let ids: Vec<_> = d.ids.split(',').filter(|id| !id.is_empty()).collect();
match archive_comments(&db, &ids) {
Err(_) => Err(Flash::error(
Redirect::to(uri!(get_entry:d.entry_id)),
"Failed to achive the comment.",
)),
Ok(_) => Ok(Redirect::to(uri!(get_entry:d.entry_id))),
}
}

#[post("/ratings/actions/archive", data = "<data>")]
pub fn post_ratings_archive(
db: sqlite::Connections,
mut search_engine: SearchEngine,
data: Form<ArchiveAction>,
) -> std::result::Result<Redirect, Flash<Redirect>> {
let d = data.into_inner();
let ids: Vec<_> = d.ids.split(',').filter(|id| !id.is_empty()).collect();
match archive_ratings(&db, &mut search_engine, &ids) {
Err(_) => Err(Flash::error(
Redirect::to(uri!(get_entry:d.entry_id)),
"Failed to archive the rating.",
)),
Ok(_) => Ok(Redirect::to(uri!(get_entry:d.entry_id))),
}
}

pub fn routes() -> Vec<Route> {
Expand All @@ -115,10 +177,13 @@ pub fn routes() -> Vec<Route> {
get_dashboard,
get_search,
get_entry,
get_entry_admin,
get_events,
get_event,
get_main_css,
get_map_js,
post_comments_archive,
post_ratings_archive,
login::get_login,
login::get_login_user,
login::post_login,
Expand Down
42 changes: 42 additions & 0 deletions src/ports/web/frontend/view/dashboard.rs
@@ -0,0 +1,42 @@
use super::page;
use maud::{html, Markup};

pub struct DashBoardPresenter<'a> {
pub email: &'a str,
pub entry_count: usize,
pub event_count: usize,
pub tag_count: usize,
pub user_count: usize,
}

pub fn dashboard(email: Option<&str>, data: DashBoardPresenter) -> Markup {
page(
"Admin Dashboard",
email,
None,
None,
html! {
main {
h3 { "Database Statistics" }
table {
tr {
td {"Number of Entries"}
td {(data.entry_count)}
}
tr {
td {"Number of Events"}
td {(data.event_count)}
}
tr {
td {"Number of Users"}
td {(data.user_count)}
}
tr {
td {"Number of Tags"}
td {(data.tag_count)}
}
}
}
},
)
}
143 changes: 143 additions & 0 deletions src/ports/web/frontend/view/entry.rs
@@ -0,0 +1,143 @@
use super::{address_to_html, leaflet_css_link, map_scripts, page};
use crate::core::prelude::*;
use maud::{html, Markup};
use std::collections::HashMap;

type Ratings = Vec<(Rating, Vec<Comment>)>;

pub struct EntryPresenter {
pub entry: Entry,
pub ratings: HashMap<RatingContext, Ratings>,
pub allow_archiving: bool,
}

impl From<(Entry, Vec<(Rating, Vec<Comment>)>, Role)> for EntryPresenter {
fn from((entry, rtngs, role): (Entry, Vec<(Rating, Vec<Comment>)>, Role)) -> EntryPresenter {
let mut p: EntryPresenter = (entry, rtngs).into();
p.allow_archiving = match role {
Role::Admin => true,
_ => false,
};
p
}
}

impl From<(Entry, Vec<(Rating, Vec<Comment>)>)> for EntryPresenter {
fn from((entry, rtngs): (Entry, Vec<(Rating, Vec<Comment>)>)) -> EntryPresenter {
let mut ratings: HashMap<RatingContext, Ratings> = HashMap::new();

for (r, comments) in rtngs {
if let Some(x) = ratings.get_mut(&r.context) {
x.push((r, comments));
} else {
ratings.insert(r.context, vec![(r, comments)]);
}
}
let allow_archiving = false;
EntryPresenter {
entry,
ratings,
allow_archiving,
}
}
}

pub fn entry(email: Option<&str>, e: EntryPresenter) -> Markup {
page(
&format!("{} | OpenFairDB", e.entry.title),
email,
None,
Some(leaflet_css_link()),
entry_detail(e),
)
}

fn entry_detail(e: EntryPresenter) -> Markup {
html! {
h3 { (e.entry.title) }
p {(e.entry.description)}
p {
table {
@if let Some(ref h) = e.entry.homepage {
tr {
td { "Homepage" }
td { a href=(h) { (h) } }
}
}
@if let Some(ref c) = e.entry.contact {
@if let Some(ref m) = c.email {
tr {
td { "eMail" }
td { a href=(format!("mailto:{}",m)) { (m) } }
}
}
@if let Some(ref t) = c.telephone {
tr {
td { "Telephone" }
td { a href=(format!("tel:{}",t)) { (t) } }
}
}
}
@if let Some(ref a) = e.entry.location.address {
@if !a.is_empty() {
tr {
td { "Address" }
td { (address_to_html(&a)) }
}
}
}
}
}
p {
ul {
@for t in &e.entry.tags{
li{ (format!("#{}", t)) }
}
}
}
h3 { "Ratings" }

@for (ctx, ratings) in e.ratings {
h4 { (format!("{:?}",ctx)) }
ul {
@for (r,comments) in ratings {
li {
(rating(&e.entry.id, e.allow_archiving, &r, &comments))
}
}
}
}
div id="map" style="height:300px;" { }
(map_scripts(&[e.entry.into()]))
}
}

fn rating(entry_id: &str, archive: bool, r: &Rating, comments: &[Comment]) -> Markup {
html! {
h5 { (r.title) " " span { (format!("({})",i8::from(r.value))) } }
@if archive {
form action = "/ratings/actions/archive" method = "POST" {
input type="hidden" name="ids" value=(r.id);
input type="hidden" name="entry_id" value=(entry_id);
input type="submit" value="archive rating";
}
}
@if let Some(ref src) = r.source {
p { (format!("source: {}",src)) }
}
ul {
@for c in comments {
li {
p { (c.text) }
@if archive {
form action = "/comments/actions/archive" method = "POST" {
input type="hidden" name="ids" value=(c.id);
input type="hidden" name="entry_id" value=(entry_id);
input type="submit" value="archive comment";
}
}
}
}
}
}
}

0 comments on commit 34f23b5

Please sign in to comment.