write zip file, pack blobs into it

and copy some styles over from desktop
This commit is contained in:
Simon Laux
2020-04-15 22:45:20 +02:00
parent c99131f551
commit 8665a3f8ad
5 changed files with 921 additions and 46 deletions

View File

@@ -6,6 +6,10 @@ use crate::context::Context;
use crate::error::Error;
use crate::message::*;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use zip::write::FileOptions;
#[derive(Debug)]
pub struct ExportChatResult {
@@ -20,7 +24,41 @@ struct ContactInfo {
profile_img: Option<String>,
}
// pub fn packExportedChat(artifact:ExportChatResult) -> ? {}
pub fn pack_exported_chat(
context: &Context,
artifact: ExportChatResult,
filename: &str,
) -> zip::result::ZipResult<()> {
let path = std::path::Path::new(filename);
let file = std::fs::File::create(&path).unwrap();
let mut zip = zip::ZipWriter::new(file);
zip.start_file("index.html", Default::default())?;
zip.write_all(artifact.html.as_bytes())?;
zip.start_file("styles.css", Default::default())?;
zip.write_all(include_bytes!("../assets/exported-chat.css"))?;
zip.add_directory("blobs/", Default::default())?;
let options = FileOptions::default();
for blob_name in artifact.referenced_blobs {
let path = context.get_blobdir().join(&blob_name);
// println!("adding file {:?} as {:?} ...", path, &blob_name);
zip.start_file_from_path(Path::new(&format!("blobs/{}", &blob_name)), options)?;
let mut f = File::open(path)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
zip.write_all(&*buffer)?;
buffer.clear();
}
zip.finish()?;
Ok(())
}
pub fn export_chat(context: &Context, chat_id: ChatId) -> ExportChatResult {
let mut blobs = Vec::new();
@@ -46,20 +84,28 @@ pub fn export_chat(context: &Context, chat_id: ChatId) -> ExportChatResult {
chat_author_ids.dedup();
// chache information about the authors
let mut chat_authors: HashMap<u32, ContactInfo> = HashMap::new();
chat_authors.insert(0, ContactInfo {
name: "Err: Contact not found".to_owned(),
initial: "#".to_owned(),
profile_img: None,
color: "grey".to_owned(),
});
chat_authors.insert(
0,
ContactInfo {
name: "Err: Contact not found".to_owned(),
initial: "#".to_owned(),
profile_img: None,
color: "grey".to_owned(),
},
);
for author_id in chat_author_ids {
let contact = Contact::get_by_id(context, author_id);
if let Ok(c) = contact {
let profile_img_path: String;
if let Some(path) = c.get_profile_image(context) {
profile_img_path = path.file_name().unwrap_or_else(|| std::ffi::OsStr::new("")).to_str().unwrap().to_owned();
// push referenced blobs (avatars)
blobs.push(profile_img_path.clone());
profile_img_path = path
.file_name()
.unwrap_or_else(|| std::ffi::OsStr::new(""))
.to_str()
.unwrap()
.to_owned();
// push referenced blobs (avatars)
blobs.push(profile_img_path.clone());
} else {
profile_img_path = "".to_owned();
}
@@ -79,14 +125,13 @@ pub fn export_chat(context: &Context, chat_id: ChatId) -> ExportChatResult {
}
// run message_to_html for each message and generate the html that way
let mut html_messages:Vec<String> = Vec::new();
let mut html_messages: Vec<String> = Vec::new();
for message in messages {
if let Ok(msg) = message {
html_messages.push(message_to_html(&chat_authors, msg));
} else {
html_messages.push(
format!(
r#"<li>
html_messages.push(format!(
r#"<li>
<div class='message error'>
<div class="msg-container">
<div class="msg-body">
@@ -95,13 +140,13 @@ pub fn export_chat(context: &Context, chat_id: ChatId) -> ExportChatResult {
</div>
</div>
</li>"#,
message.unwrap_err()
)
);
message.unwrap_err()
));
}
}
// todo chat image, chat name and so on..
let chat = Chat::load_from_db(context, chat_id).unwrap();
// todo option to export locations as kml?
@@ -109,7 +154,23 @@ pub fn export_chat(context: &Context, chat_id: ChatId) -> ExportChatResult {
// (those can be linked from the messages, they are stored in msg_info/[msg-id].txt)
ExportChatResult {
html: format!(r#"<ul>{}</ul>"#, html_messages.join("")),
html: format!(
"<html>\
<head>\
<title>{}</title>\
<link rel=\"stylesheet\" href=\"styles.css\" type=\"text/css\">\
</head>\
<body>\
<div class=\"message-list-and-composer__message-list\">\
<div id=\"message-list\">\
<ul>{}</ul>\
</div>\
</div>\
</body>\
</html>",
chat.get_name(),
html_messages.join("")
),
referenced_blobs: blobs,
}
}
@@ -127,21 +188,21 @@ fn message_to_html(author_cache: &HashMap<u32, ContactInfo>, message: Message) -
if let Some(profile_img) = &author.profile_img {
format!(
"<div class=\"author-avatar\">\
<img\
alt=\"{author_name}\"\
src=\"blobs/{author_avatar_src}\"\
/>\
</div>",
<img\
alt=\"{author_name}\"\
src=\"blobs/{author_avatar_src}\"\
/>\
</div>",
author_name = author.name,
author_avatar_src = profile_img
)
} else {
format!(
"<div class=\"author-avatar default\" alt=\"{name}\">\
<div class=\"label\" style=\"background-color: {color}\">\
{initial}\
</div>\
</div>",
<div class=\"label\" style=\"background-color: {color}\">\
{initial}\
</div>\
</div>",
name = author.name,
initial = author.initial,
color = author.color
@@ -155,26 +216,26 @@ fn message_to_html(author_cache: &HashMap<u32, ContactInfo>, message: Message) -
format!(
"<li>\
<div class=\"message {direction}\">\
{avatar}\
<div class=\"msg-container\">\
<span class=\"author\" style=\"color: {author_color};\">{author_name}</span>\
<div class=\"msg-body\">\
<div dir=\"auto\" class=\"text\">\
{content}\
</div>\
<div class=\"metadata\">\
{encryption}\
<span class=\"date date--{direction}\" title=\"{full_time}\">{relative_time}</span>\
<span class=\"spacer\"></span>\
</div>\
</div>\
</div>\
<div>\
</li>",
<div class=\"message {direction}\">\
{avatar}\
<div class=\"msg-container\">\
<span class=\"author\" style=\"color: {author_color};\">{author_name}</span>\
<div class=\"msg-body\">\
<div dir=\"auto\" class=\"text\">\
{content}\
</div>\
<div class=\"metadata\">\
{encryption}\
<span class=\"date date--{direction}\" title=\"{full_time}\">{relative_time}</span>\
<span class=\"spacer\"></span>\
</div>\
</div>\
</div>\
<div>\
</li>",
direction = match message.from_id == DC_CONTACT_ID_SELF {
true => "outgoing",
false => "incomming",
false => "incoming",
},
avatar = avatar,
author_name = author.name,