Edit blogs, and add blog icons and banners (#460)

Also adds a parameter to `md_to_html` to only render inline elements (so that we don't have titles or images in blog descriptions). And moves the delete button for the blog on the edition page.

I still have to update the SQLite migration once others PRs with migrations will be merged.

Also, there will be a problem when you edit a blog while not owning its banner or icon: when validating they will be reset to their default values… I don't see a good solution to this until we have a better way to handle uploads with Rocket (the same is probably happening for articles btw).

And the icon/banner are not federated yet, I don't know if I should add it to this PR or if it can come after?

![image](https://user-images.githubusercontent.com/16254623/53894510-7d853300-4030-11e9-8a2c-f5c0b0c7f512.png)
![image](https://user-images.githubusercontent.com/16254623/53894539-8b3ab880-4030-11e9-8113-685a27be8d7c.png)

Fixes #453
Fixes #454
This commit is contained in:
Baptiste Gelez
2019-03-22 19:51:36 +01:00
committed by GitHub
parent 6cd9c8a01a
commit bdfad844d7
41 changed files with 1391 additions and 456 deletions
+49 -3
View File
@@ -46,8 +46,22 @@ enum State {
Ready,
}
fn to_inline(tag: Tag) -> Tag {
match tag {
Tag::Header(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell => {
Tag::Paragraph
}
Tag::Image(url, title) => Tag::Link(url, title),
t => t,
}
}
/// Returns (HTML, mentions, hashtags)
pub fn md_to_html(md: &str, base_url: &str) -> (String, HashSet<String>, HashSet<String>) {
pub fn md_to_html(
md: &str,
base_url: &str,
inline: bool,
) -> (String, HashSet<String>, HashSet<String>) {
let parser = Parser::new_ext(md, Options::all());
let (parser, mentions, hashtags): (Vec<Event>, Vec<String>, Vec<String>) = parser
@@ -69,6 +83,26 @@ pub fn md_to_html(md: &str, base_url: &str) -> (String, HashSet<String>, HashSet
Some(res)
})
.flat_map(|v| v.into_iter())
// Ignore headings, images, and tables if inline = true
.scan(vec![], |state: &mut Vec<Tag>, evt| {
if inline {
let new_evt = match evt {
Event::Start(t) => {
let tag = to_inline(t);
state.push(tag.clone());
Event::Start(tag)
}
Event::End(t) => match state.pop() {
Some(other) => Event::End(other),
None => Event::End(t),
},
e => e,
};
Some(new_evt)
} else {
Some(evt)
}
})
.map(|evt| match evt {
Event::Text(txt) => {
let (evts, _, _, _, new_mentions, new_hashtags) = txt.chars().fold(
@@ -239,7 +273,7 @@ mod tests {
for (md, mentions) in tests {
assert_eq!(
md_to_html(md, "").1,
md_to_html(md, "", false).1,
mentions
.into_iter()
.map(|s| s.to_string())
@@ -264,7 +298,7 @@ mod tests {
for (md, mentions) in tests {
assert_eq!(
md_to_html(md, "").2,
md_to_html(md, "", false).2,
mentions
.into_iter()
.map(|s| s.to_string())
@@ -272,4 +306,16 @@ mod tests {
);
}
}
#[test]
fn test_inline() {
assert_eq!(
md_to_html("# Hello", "", false).0,
String::from("<h1>Hello</h1>\n")
);
assert_eq!(
md_to_html("# Hello", "", true).0,
String::from("<p>Hello</p>\n")
);
}
}