Skip to content

Commit

Permalink
Merge 305a413 into bd19de7
Browse files Browse the repository at this point in the history
  • Loading branch information
flosse committed Mar 9, 2019
2 parents bd19de7 + 305a413 commit 62b98ee
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 263 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
5 changes: 1 addition & 4 deletions src/infrastructure/flows/archive_comments.rs
Expand Up @@ -27,10 +27,7 @@ mod tests {
use super::super::tests::prelude::*;

fn archive_comments(fixture: &EnvFixture, ids: &[&str]) -> super::Result<()> {
super::archive_comments(
&fixture.db_connections,
ids,
)
super::archive_comments(&fixture.db_connections, ids)
}

#[test]
Expand Down
12 changes: 6 additions & 6 deletions src/ports/web/frontend/login.rs
Expand Up @@ -88,12 +88,12 @@ pub fn post_logout(mut cookies: Cookies) -> Flash<Redirect> {
}

#[cfg(test)]
mod tests {
pub mod tests {
use super::*;
use crate::ports::web::tests::prelude::*;
use crate::ports::web::{self, tests::prelude::*};

fn setup() -> (Client, Connections) {
let (client, db, _) = crate::ports::web::tests::setup(vec![("/", super::super::routes())]);
let (client, db, _) = web::tests::setup(vec![("/", super::super::routes())]);
(client, db)
}

Expand All @@ -107,7 +107,7 @@ mod tests {
cookie.map(|c| c.into_owned())
}

fn register_user(pool: Connections, email: &str, pw: &str, confirmed: bool) {
pub fn register_user(pool: &Connections, email: &str, pw: &str, confirmed: bool) {
let mut db = pool.exclusive().unwrap();
usecases::create_new_user(
&mut *db,
Expand Down Expand Up @@ -137,7 +137,7 @@ mod tests {
#[test]
fn post_login_fails() {
let (client, pool) = setup();
register_user(pool, "foo@bar.com", "baz", true);
register_user(&pool, "foo@bar.com", "baz", true);
let res = client
.post("/login")
.header(ContentType::Form)
Expand All @@ -156,7 +156,7 @@ mod tests {
#[test]
fn post_login_sucess() {
let (client, pool) = setup();
register_user(pool, "foo@bar.com", "baz", true);
register_user(&pool, "foo@bar.com", "baz", true);
let res = client
.post("/login")
.header(ContentType::Form)
Expand Down
215 changes: 196 additions & 19 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,49 @@ 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(
_admin: Admin,
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(
_admin: Admin,
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 +179,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 All @@ -132,21 +199,24 @@ pub fn routes() -> Vec<Route> {
#[cfg(test)]
mod tests {
use super::*;
use crate::infrastructure::db::tantivy;
use crate::ports::web::tests::prelude::*;
use chrono::*;

fn setup() -> (rocket::local::Client, sqlite::Connections) {
let (client, connections, _) =
crate::ports::web::tests::setup(vec![("/", super::routes())]);
(client, connections)
fn setup() -> (
rocket::local::Client,
sqlite::Connections,
tantivy::SearchEngine,
) {
crate::ports::web::tests::setup(vec![("/", super::routes())])
}

mod events {
use super::*;

#[test]
fn get_a_list_of_all_events() {
let (client, db) = setup();
let (client, db, _) = setup();
let events = vec![
Event {
id: "1234".into(),
Expand Down Expand Up @@ -221,7 +291,7 @@ mod tests {

#[test]
fn get_a_single_event() {
let (client, db) = setup();
let (client, db, _) = setup();
let events = vec![Event {
id: "1234".into(),
title: "A great event".into(),
Expand Down Expand Up @@ -258,7 +328,7 @@ mod tests {
use super::*;
#[test]
fn get_the_index_html() {
let (client, _db) = setup();
let (client, _db, _) = setup();
let mut index = client.get("/").dispatch();
assert_eq!(index.status(), Status::Ok);

Expand All @@ -274,4 +344,111 @@ mod tests {
}
}

mod entry {
use super::*;
use crate::core::usecases;
use crate::infrastructure::flows;

fn create_entry_with_rating(
db: &sqlite::Connections,
search: &mut tantivy::SearchEngine,
) -> (String, String, String) {
let e = usecases::NewEntry {
title: "entry".into(),
description: "desc".into(),
lat: 3.7,
lng: -50.0,
street: None,
zip: None,
city: None,
country: None,
email: None,
telephone: None,
homepage: None,
categories: vec![],
tags: vec![],
license: "CC0-1.0".into(),
image_url: None,
image_link_url: None,
};
let e_id = flows::prelude::create_entry(db, search, e).unwrap();
let r = usecases::RateEntry {
title: "A rating".into(),
comment: "Foo".into(),
context: RatingContext::Diversity,
source: None,
user: None,
value: 1.into(),
entry: e_id.clone(),
};
let (r_id, c_id) = flows::prelude::create_rating(db, search, r).unwrap();
(e_id, r_id, c_id)
}

#[test]
fn get_entry_details() {
let (client, db, mut search) = setup();
let (id, _, _) = create_entry_with_rating(&db, &mut search);
let mut res = client.get(format!("/entries/{}", id)).dispatch();
assert_eq!(res.status(), Status::Ok);
let body_str = res.body().and_then(|b| b.into_string()).unwrap();
assert_eq!(body_str.contains("<form"), false);
assert_eq!(
body_str.contains("action=\"/comments/actions/archive\""),
false
);
}

#[test]
fn get_entry_details_as_admin() {
let (client, db, mut search) = setup();
let (id, _, _) = create_entry_with_rating(&db, &mut search);
super::super::login::tests::register_user(&db, "foo@bar.com", "baz", true);
let mut user = db
.shared()
.unwrap()
.get_user_by_email("foo@bar.com")
.unwrap();
user.role = Role::Admin;
db.exclusive().unwrap().update_user(&user).unwrap();
let login_res = client
.post("/login")
.header(ContentType::Form)
.body("email=foo%40bar.com&password=baz")
.dispatch();
let mut res = client.get(format!("/entries/{}", id)).dispatch();
assert_eq!(res.status(), Status::Ok);
let body_str = res.body().and_then(|b| b.into_string()).unwrap();
assert_eq!(body_str.contains("<form"), true);
assert_eq!(
body_str.contains("action=\"/comments/actions/archive\""),
true
);
}

#[test]
fn archive_comment_as_guest() {
let (client, db, mut search) = setup();
let (e_id, r_id, c_id) = create_entry_with_rating(&db, &mut search);
let res = client
.post("/comments/actions/archive")
.header(ContentType::Form)
.body(format!("ids={}&entry_id={}", c_id, e_id))
.dispatch();
assert_eq!(res.status(), Status::NotFound);
}

#[test]
fn archive_rating_as_guest() {
let (client, db, mut search) = setup();
let (e_id, r_id, c_id) = create_entry_with_rating(&db, &mut search);
let res = client
.post("/ratings/actions/archive")
.header(ContentType::Form)
.body(format!("ids={}&entry_id={}", r_id, e_id))
.dispatch();
assert_eq!(res.status(), Status::NotFound);
}
}

}

0 comments on commit 62b98ee

Please sign in to comment.