diff --git a/migrations/.gitkeep b/migrations/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/migrations/2020-01-15-052544_add_highlight/down.sql b/migrations/2020-01-15-052544_add_highlight/down.sql
new file mode 100644
index 0000000..240553b
--- /dev/null
+++ b/migrations/2020-01-15-052544_add_highlight/down.sql
@@ -0,0 +1,2 @@
+ALTER TABLE texts
+DROP COLUMN highlight;
diff --git a/migrations/2020-01-15-052544_add_highlight/up.sql b/migrations/2020-01-15-052544_add_highlight/up.sql
new file mode 100644
index 0000000..bbfb5a2
--- /dev/null
+++ b/migrations/2020-01-15-052544_add_highlight/up.sql
@@ -0,0 +1,2 @@
+ALTER TABLE texts
+ADD highlight BOOLEAN NOT NULL DEFAULT false;
diff --git a/resources/highlight.html b/resources/highlight.html
new file mode 100644
index 0000000..ca30fab
--- /dev/null
+++ b/resources/highlight.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ {{ title }}
+
+
+
+
+ {{ contents }}
+
+ {{ languages }}
+
+
+
diff --git a/resources/script.js b/resources/script.js
index 664a9ab..c6c5907 100644
--- a/resources/script.js
+++ b/resources/script.js
@@ -231,7 +231,7 @@ for (const group in inputs) {
fetch(url, {
method: "PUT",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ contents }),
+ body: JSON.stringify({ contents, highlight: true }),
})
.then((response) => {
status = response.status;
diff --git a/src/models.rs b/src/models.rs
index 4b41386..19afe6d 100644
--- a/src/models.rs
+++ b/src/models.rs
@@ -65,6 +65,8 @@ pub mod texts {
pub contents: String,
/// Creation date and time as a UNIX timestamp
pub created: i32,
+ /// Whether to enable code highlighting or not for that text
+ pub highlight: bool,
}
/// A new entry to the `texts` table
@@ -75,5 +77,7 @@ pub mod texts {
pub id: i32,
/// Text contents
pub contents: &'a str,
+ /// Whether to enable code highlighting or not for that text
+ pub highlight: bool,
}
}
diff --git a/src/queries.rs b/src/queries.rs
index bd05257..e56c9e5 100644
--- a/src/queries.rs
+++ b/src/queries.rs
@@ -175,11 +175,17 @@ pub mod texts {
find!(texts, Text);
/// REPLACE a text entry
- pub fn replace(r_id: i32, r_contents: &str, pool: Data) -> QueryResult {
+ pub fn replace(
+ r_id: i32,
+ r_contents: &str,
+ r_highlight: bool,
+ pool: Data,
+ ) -> QueryResult {
let conn: &SqliteConnection = &pool.get().unwrap();
let new_text = NewText {
id: r_id,
contents: r_contents,
+ highlight: r_highlight,
};
diesel::replace_into(table)
.values(&new_text)
diff --git a/src/routes.rs b/src/routes.rs
index 362bd21..2578990 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -116,6 +116,13 @@ fn timestamp_to_last_modified(timestamp: i32) -> String {
datetime.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
}
+/// Escapes text to be inserted in a HTML element
+fn escape_html(text: &str) -> String {
+ text.replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+}
+
/// GET multiple entries
macro_rules! select {
($m:ident) => {
@@ -196,6 +203,9 @@ lazy_static! {
};
}
+static HIGHLIGHT_CONTENTS: &str = include_str!("../resources/highlight.html");
+const HIGHLIGHT_LANGUAGE: &str = r#""#;
+
/// Index page letting users upload via a UI
pub async fn index(
request: HttpRequest,
@@ -406,6 +416,7 @@ pub mod links {
}
pub mod texts {
+ use crate::routes::escape_html;
use crate::{
queries::{self, SelectQuery},
routes::{
@@ -413,6 +424,10 @@ pub mod texts {
},
Pool,
};
+ use crate::{
+ routes::{HIGHLIGHT_CONTENTS, HIGHLIGHT_LANGUAGE},
+ setup::Config,
+ };
use actix_identity::Identity;
use actix_web::{web, Error, HttpRequest, HttpResponse};
@@ -420,14 +435,38 @@ pub mod texts {
/// GET a text entry and display it
pub async fn get(
+ config: web::Data,
path: web::Path,
pool: web::Data,
) -> Result {
let id = parse_id(&path)?;
match web::block(move || queries::texts::find(id, pool)).await {
- Ok(text) => Ok(HttpResponse::Ok()
- .header("Last-Modified", timestamp_to_last_modified(text.created))
- .body(text.contents)),
+ Ok(text) => {
+ let last_modified = timestamp_to_last_modified(text.created);
+ if text.highlight {
+ let languages: Vec = config
+ .highlight
+ .languages
+ .iter()
+ .map(|l| HIGHLIGHT_LANGUAGE.replace("{{ language }}", l))
+ .collect();
+ let languages = languages.join("\n");
+ let contents = HIGHLIGHT_CONTENTS
+ .replace("{{ title }}", &path)
+ .replace("{{ theme }}", &config.highlight.theme)
+ .replace("{{ contents }}", &escape_html(&text.contents))
+ .replace("{{ languages }}", &languages);
+
+ Ok(HttpResponse::Ok()
+ .header("Last-Modified", last_modified)
+ .header("Content-Type", "text/html")
+ .body(contents))
+ } else {
+ Ok(HttpResponse::Ok()
+ .header("Last-Modified", last_modified)
+ .body(text.contents))
+ }
+ }
Err(e) => match_find_error(e),
}
}
@@ -436,6 +475,7 @@ pub mod texts {
#[derive(Deserialize)]
pub struct PutText {
pub contents: String,
+ pub highlight: bool,
}
/// PUT a new text entry
@@ -451,7 +491,8 @@ pub mod texts {
let id = parse_id(&path)?;
match_replace_result(
- web::block(move || queries::texts::replace(id, &body.contents, pool)).await,
+ web::block(move || queries::texts::replace(id, &body.contents, body.highlight, pool))
+ .await,
)
}
diff --git a/src/schema.rs b/src/schema.rs
index 43cb46e..63ccef8 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -19,6 +19,7 @@ table! {
id -> Integer,
contents -> Text,
created -> Integer,
+ highlight -> Bool,
}
}
diff --git a/src/setup.rs b/src/setup.rs
index f3ab217..95fe2c6 100644
--- a/src/setup.rs
+++ b/src/setup.rs
@@ -88,6 +88,17 @@ pub struct Config {
pub files_dir: PathBuf,
/// Maximum allowed file size
pub max_filesize: usize,
+ /// Highlight.js configuration
+ pub highlight: HighlightConfig,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+#[cfg_attr(not(feature = "dev"), serde(default))]
+pub struct HighlightConfig {
+ /// Theme to use
+ pub theme: String,
+ /// Additional languages to include
+ pub languages: Vec,
}
#[cfg(not(feature = "dev"))]
@@ -104,12 +115,22 @@ impl Default for Config {
let files_dir = get_data_dir().join("files");
let max_filesize = 10_000_000;
- Config {
+ Self {
port,
database_url,
pool_size,
files_dir,
max_filesize,
+ highlight: HighlightConfig::default(),
+ }
+ }
+}
+
+impl Default for HighlightConfig {
+ fn default() -> Self {
+ Self {
+ theme: "github".to_owned(),
+ languages: vec!["rust".to_owned()],
}
}
}
@@ -192,12 +213,13 @@ impl Config {
};
let max_filesize = parse_env!("MAX_FILESIZE");
- Config {
+ Self {
port,
database_url,
pool_size,
files_dir,
max_filesize,
+ highlight: HighlightConfig::default(),
}
}
}