From b7679c7826b45643a15c62103aead00df36d4af8 Mon Sep 17 00:00:00 2001
From: binwiederhier <philipp.heckel@gmail.com>
Date: Sat, 8 Jul 2023 15:14:35 -0400
Subject: [PATCH] Remove setting, add persistence

---
 server/message_cache.go              | 80 ++++++++++++++++++----------
 server/server_firebase_test.go       |  2 +
 web/public/static/langs/en.json      |  3 --
 web/src/app/Prefs.js                 |  9 ----
 web/src/components/Notifications.jsx | 12 ++---
 web/src/components/Preferences.jsx   | 21 --------
 6 files changed, 60 insertions(+), 67 deletions(-)

diff --git a/server/message_cache.go b/server/message_cache.go
index 140271fe..8a613ff1 100644
--- a/server/message_cache.go
+++ b/server/message_cache.go
@@ -45,6 +45,7 @@ const (
 			attachment_deleted INT NOT NULL,
 			sender TEXT NOT NULL,
 			user TEXT NOT NULL,
+			content_type TEXT NOT NULL,
 			encoding TEXT NOT NULL,
 			published INT NOT NULL
 		);
@@ -63,43 +64,43 @@ const (
 		COMMIT;
 	`
 	insertMessageQuery = `
-		INSERT INTO messages (mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_deleted, sender, user, encoding, published)
-		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+		INSERT INTO messages (mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, attachment_deleted, sender, user, content_type, encoding, published)
+		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
 	`
 	deleteMessageQuery                = `DELETE FROM messages WHERE mid = ?`
 	updateMessagesForTopicExpiryQuery = `UPDATE messages SET expires = ? WHERE topic = ?`
 	selectRowIDFromMessageID          = `SELECT id FROM messages WHERE mid = ?` // Do not include topic, see #336 and TestServer_PollSinceID_MultipleTopics
 	selectMessagesByIDQuery           = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE mid = ?
 	`
 	selectMessagesSinceTimeQuery = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE topic = ? AND time >= ? AND published = 1
 		ORDER BY time, id
 	`
 	selectMessagesSinceTimeIncludeScheduledQuery = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE topic = ? AND time >= ?
 		ORDER BY time, id
 	`
 	selectMessagesSinceIDQuery = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE topic = ? AND id > ? AND published = 1 
 		ORDER BY time, id
 	`
 	selectMessagesSinceIDIncludeScheduledQuery = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE topic = ? AND (id > ? OR published = 0)
 		ORDER BY time, id
 	`
 	selectMessagesDueQuery = `
-		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, encoding
+		SELECT mid, time, expires, topic, message, title, priority, tags, click, icon, actions, attachment_name, attachment_type, attachment_size, attachment_expires, attachment_url, sender, user, content_type, encoding
 		FROM messages 
 		WHERE time <= ? AND published = 0
 		ORDER BY time, id
@@ -121,7 +122,7 @@ const (
 
 // Schema management queries
 const (
-	currentSchemaVersion          = 11
+	currentSchemaVersion          = 12
 	createSchemaVersionTableQuery = `
 		CREATE TABLE IF NOT EXISTS schemaVersion (
 			id INT PRIMARY KEY,
@@ -240,6 +241,11 @@ const (
 		);
 		INSERT INTO stats (key, value) VALUES ('messages', 0);
 	`
+
+	// 11 -> 12
+	migrate11To12AlterMessagesTableQuery = `
+		ALTER TABLE messages ADD COLUMN content_type TEXT NOT NULL DEFAULT('');
+	`
 )
 
 var (
@@ -255,6 +261,7 @@ var (
 		8:  migrateFrom8,
 		9:  migrateFrom9,
 		10: migrateFrom10,
+		11: migrateFrom11,
 	}
 )
 
@@ -384,6 +391,7 @@ func (c *messageCache) addMessages(ms []*message) error {
 			attachmentDeleted, // Always zero
 			sender,
 			m.User,
+			m.ContentType,
 			m.Encoding,
 			published,
 		)
@@ -656,7 +664,7 @@ func readMessages(rows *sql.Rows) ([]*message, error) {
 func readMessage(rows *sql.Rows) (*message, error) {
 	var timestamp, expires, attachmentSize, attachmentExpires int64
 	var priority int
-	var id, topic, msg, title, tagsStr, click, icon, actionsStr, attachmentName, attachmentType, attachmentURL, sender, user, encoding string
+	var id, topic, msg, title, tagsStr, click, icon, actionsStr, attachmentName, attachmentType, attachmentURL, sender, user, contentType, encoding string
 	err := rows.Scan(
 		&id,
 		&timestamp,
@@ -676,6 +684,7 @@ func readMessage(rows *sql.Rows) (*message, error) {
 		&attachmentURL,
 		&sender,
 		&user,
+		&contentType,
 		&encoding,
 	)
 	if err != nil {
@@ -706,22 +715,23 @@ func readMessage(rows *sql.Rows) (*message, error) {
 		}
 	}
 	return &message{
-		ID:         id,
-		Time:       timestamp,
-		Expires:    expires,
-		Event:      messageEvent,
-		Topic:      topic,
-		Message:    msg,
-		Title:      title,
-		Priority:   priority,
-		Tags:       tags,
-		Click:      click,
-		Icon:       icon,
-		Actions:    actions,
-		Attachment: att,
-		Sender:     senderIP, // Must parse assuming database must be correct
-		User:       user,
-		Encoding:   encoding,
+		ID:          id,
+		Time:        timestamp,
+		Expires:     expires,
+		Event:       messageEvent,
+		Topic:       topic,
+		Message:     msg,
+		Title:       title,
+		Priority:    priority,
+		Tags:        tags,
+		Click:       click,
+		Icon:        icon,
+		Actions:     actions,
+		Attachment:  att,
+		Sender:      senderIP, // Must parse assuming database must be correct
+		User:        user,
+		ContentType: contentType,
+		Encoding:    encoding,
 	}, nil
 }
 
@@ -929,7 +939,7 @@ func migrateFrom9(db *sql.DB, cacheDuration time.Duration) error {
 	return tx.Commit()
 }
 
-func migrateFrom10(db *sql.DB, cacheDuration time.Duration) error {
+func migrateFrom10(db *sql.DB, _ time.Duration) error {
 	log.Tag(tagMessageCache).Info("Migrating cache database schema: from 10 to 11")
 	tx, err := db.Begin()
 	if err != nil {
@@ -944,3 +954,19 @@ func migrateFrom10(db *sql.DB, cacheDuration time.Duration) error {
 	}
 	return tx.Commit()
 }
+
+func migrateFrom11(db *sql.DB, _ time.Duration) error {
+	log.Tag(tagMessageCache).Info("Migrating cache database schema: from 11 to 12")
+	tx, err := db.Begin()
+	if err != nil {
+		return err
+	}
+	defer tx.Rollback()
+	if _, err := tx.Exec(migrate11To12AlterMessagesTableQuery); err != nil {
+		return err
+	}
+	if _, err := tx.Exec(updateSchemaVersion, 12); err != nil {
+		return err
+	}
+	return tx.Commit()
+}
diff --git a/server/server_firebase_test.go b/server/server_firebase_test.go
index f18abe13..fb27ea05 100644
--- a/server/server_firebase_test.go
+++ b/server/server_firebase_test.go
@@ -182,6 +182,7 @@ func TestToFirebaseMessage_Message_Normal_Allowed(t *testing.T) {
 				"title":              "some title",
 				"message":            "this is a message",
 				"actions":            `[{"id":"123","action":"view","label":"Open page","clear":true,"url":"https://ntfy.sh"},{"id":"456","action":"http","label":"Close door","clear":false,"url":"https://door.com/close","method":"PUT","headers":{"really":"yes"}}]`,
+				"content_type":       "",
 				"encoding":           "",
 				"attachment_name":    "some file.jpg",
 				"attachment_type":    "image/jpeg",
@@ -203,6 +204,7 @@ func TestToFirebaseMessage_Message_Normal_Allowed(t *testing.T) {
 		"title":              "some title",
 		"message":            "this is a message",
 		"actions":            `[{"id":"123","action":"view","label":"Open page","clear":true,"url":"https://ntfy.sh"},{"id":"456","action":"http","label":"Close door","clear":false,"url":"https://door.com/close","method":"PUT","headers":{"really":"yes"}}]`,
+		"content_type":       "",
 		"encoding":           "",
 		"attachment_name":    "some file.jpg",
 		"attachment_type":    "image/jpeg",
diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json
index 3d85b757..3f2947e4 100644
--- a/web/public/static/langs/en.json
+++ b/web/public/static/langs/en.json
@@ -359,9 +359,6 @@
   "prefs_appearance_theme_system": "System (default)",
   "prefs_appearance_theme_dark": "Dark mode",
   "prefs_appearance_theme_light": "Light mode",
-  "prefs_appearance_markdown_always_enabled_title": "Format all messages as Markdown",
-  "prefs_appearance_markdown_always_enabled_on": "Enabled",
-  "prefs_appearance_markdown_always_enabled_off": "Disabled",
   "prefs_reservations_title": "Reserved topics",
   "prefs_reservations_description": "You can reserve topic names for personal use here. Reserving a topic gives you ownership over the topic, and allows you to define access permissions for other users over the topic.",
   "prefs_reservations_limit_reached": "You reached your reserved topics limit.",
diff --git a/web/src/app/Prefs.js b/web/src/app/Prefs.js
index 9d9ed0d5..4f28f87e 100644
--- a/web/src/app/Prefs.js
+++ b/web/src/app/Prefs.js
@@ -55,15 +55,6 @@ class Prefs {
   async setTheme(mode) {
     await this.db.prefs.put({ key: "theme", value: mode });
   }
-
-  async markdownAlwaysEnabled() {
-    const record = await this.db.prefs.get("markdownAlwaysEnabled");
-    return record?.value ?? false;
-  }
-
-  async setMarkdownAlwaysEnabled(enabled) {
-    await this.db.prefs.put({ key: "markdownAlwaysEnabled", value: enabled });
-  }
 }
 
 const prefs = new Prefs(db());
diff --git a/web/src/components/Notifications.jsx b/web/src/components/Notifications.jsx
index 610d5256..ccd2deb9 100644
--- a/web/src/components/Notifications.jsx
+++ b/web/src/components/Notifications.jsx
@@ -192,6 +192,10 @@ const MarkdownContainer = styled("div")`
   ol {
     padding-inline: 1rem;
   }
+  
+  img {
+    max-width: 100%;
+  }
 `;
 
 const MarkdownContent = ({ content }) => {
@@ -205,17 +209,11 @@ const MarkdownContent = ({ content }) => {
 };
 
 const NotificationBody = ({ notification }) => {
-  const markdownAlwaysEnabled = useLiveQuery(async () => prefs.markdownAlwaysEnabled());
-
-  // TODO: check notification content-type when implemented on the server
-  const displayAsMarkdown = markdownAlwaysEnabled;
-
+  const displayAsMarkdown = notification.content_type === "text/markdown";
   const formatted = formatMessage(notification);
-
   if (displayAsMarkdown) {
     return <MarkdownContent content={formatted} />;
   }
-
   return autolink(formatted);
 };
 
diff --git a/web/src/components/Preferences.jsx b/web/src/components/Preferences.jsx
index f28c3da3..a93032ce 100644
--- a/web/src/components/Preferences.jsx
+++ b/web/src/components/Preferences.jsx
@@ -259,26 +259,6 @@ const Theme = () => {
   );
 };
 
-const MarkdownAlwaysEnabled = () => {
-  const { t } = useTranslation();
-  const labelId = "prefMarkdown";
-  const enabled = useLiveQuery(async () => prefs.markdownAlwaysEnabled());
-  const handleChange = async (ev) => {
-    await prefs.setMarkdownAlwaysEnabled(ev.target.value);
-  };
-
-  return (
-    <Pref labelId={labelId} title={t("prefs_appearance_markdown_always_enabled_title")}>
-      <FormControl fullWidth variant="standard" sx={{ m: 1 }}>
-        <Select value={enabled ?? false} onChange={handleChange} aria-labelledby={labelId}>
-          <MenuItem value>{t("prefs_appearance_markdown_always_enabled_on")}</MenuItem>
-          <MenuItem value={false}>{t("prefs_appearance_markdown_always_enabled_off")}</MenuItem>
-        </Select>
-      </FormControl>
-    </Pref>
-  );
-};
-
 const WebPushEnabled = () => {
   const { t } = useTranslation();
   const labelId = "prefWebPushEnabled";
@@ -533,7 +513,6 @@ const Appearance = () => {
       <PrefGroup>
         <Theme />
         <Language />
-        <MarkdownAlwaysEnabled />
       </PrefGroup>
     </Card>
   );