mirror of
https://github.com/chatmail/core.git
synced 2026-05-04 13:56:30 +03:00
write zip file, pack blobs into it
and copy some styles over from desktop
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user