瀏覽代碼

Better test messages

Philipp Heckel 3 年之前
父節點
當前提交
3f978bc45f

+ 3 - 3
docs/static/css/extra.css

@@ -1,7 +1,7 @@
 :root {
-    --md-primary-fg-color:        #3a9784;
-    --md-primary-fg-color--light: #3a9784;
-    --md-primary-fg-color--dark:  #3a9784;
+    --md-primary-fg-color:        #338574;
+    --md-primary-fg-color--light: #338574;
+    --md-primary-fg-color--dark:  #338574;
 }
 
 .md-header__button.md-logo :is(img, svg) {

+ 2 - 2
server/server.go

@@ -881,8 +881,8 @@ func parseSince(r *http.Request, poll bool) (sinceMarker, error) {
 
 func (s *Server) handleOptions(w http.ResponseWriter, _ *http.Request) error {
 	w.Header().Set("Access-Control-Allow-Methods", "GET, PUT, POST")
-	w.Header().Set("Access-Control-Allow-Origin", "*")              // CORS, allow cross-origin requests
-	w.Header().Set("Access-Control-Allow-Headers", "Authorization") // CORS, allow auth via JS
+	w.Header().Set("Access-Control-Allow-Origin", "*")  // CORS, allow cross-origin requests
+	w.Header().Set("Access-Control-Allow-Headers", "*") // CORS, allow auth via JS // FIXME is this terrible?
 	return nil
 }
 

+ 12 - 2
web/src/app/Api.js

@@ -26,14 +26,24 @@ class Api {
         return messages;
     }
 
-    async publish(baseUrl, topic, message) {
+    async publish(baseUrl, topic, message, title, priority, tags) {
         const user = await userManager.get(baseUrl);
         const url = topicUrl(baseUrl, topic);
         console.log(`[Api] Publishing message to ${url}`);
+        const headers = {};
+        if (title) {
+            headers["X-Title"] = title;
+        }
+        if (priority !== 3) {
+            headers["X-Priority"] = `${priority}`;
+        }
+        if (tags.length > 0) {
+            headers["X-Tags"] = tags.join(",");
+        }
         await fetch(url, {
             method: 'PUT',
             body: message,
-            headers: maybeWithBasicAuth({}, user)
+            headers: maybeWithBasicAuth(headers, user)
         });
     }
 

+ 11 - 0
web/src/app/utils.js

@@ -104,6 +104,17 @@ export const encodeBase64Url = (s) => {
     return Base64.encodeURI(s);
 }
 
+export const shuffle = (arr) => {
+    let j, x;
+    for (let index = arr.length - 1; index > 0; index--) {
+        j = Math.floor(Math.random() * (index + 1));
+        x = arr[index];
+        arr[index] = arr[j];
+        arr[j] = x;
+    }
+    return arr;
+}
+
 // https://jameshfisher.com/2017/10/30/web-cryptography-api-hello-world/
 export const sha256 = async (s) => {
     const buf = await crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode(s));

+ 26 - 3
web/src/components/ActionBar.js

@@ -7,7 +7,7 @@ import Typography from "@mui/material/Typography";
 import * as React from "react";
 import {useEffect, useRef, useState} from "react";
 import Box from "@mui/material/Box";
-import {topicShortUrl} from "../app/utils";
+import {formatShortDateTime, shuffle, topicShortUrl} from "../app/utils";
 import {useLocation, useNavigate} from "react-router-dom";
 import ClickAwayListener from '@mui/material/ClickAwayListener';
 import Grow from '@mui/material/Grow';
@@ -108,8 +108,31 @@ const SettingsIcons = (props) => {
     const handleSendTestMessage = () => {
         const baseUrl = props.subscription.baseUrl;
         const topic = props.subscription.topic;
-        api.publish(baseUrl, topic,
-            `This is a test notification sent by the ntfy Web UI at ${new Date().toString()}.`); // FIXME result ignored
+        const tags = shuffle([
+            "grinning", "octopus", "upside_down_face", "palm_tree", "maple_leaf", "apple", "skull", "warning", "jack_o_lantern",
+            "de-server-1", "backups", "cron-script", "script-error", "phils-automation", "mouse", "go-rocks", "hi-ben"])
+                .slice(0, Math.round(Math.random() * 4));
+        const priority = shuffle([1, 2, 3, 4, 5])[0];
+        const title = shuffle([
+            "",
+            "",
+            "", // Higher chance of no title
+            "Oh my, another test message?",
+            "Titles are optional, did you know that?",
+            "ntfy is open source, and will always be free. Cool, right?",
+            "I don't really like apples",
+            "My favorite TV show is The Wire. You should watch it!"
+        ])[0];
+        const message = shuffle([
+            `Hello friend, this is a test notification from ntfy web. It's ${formatShortDateTime(Date.now())} right now. Is that early or late?`,
+            `So I heard you like ntfy? If that's true, go to GitHub and star it, or to the Play store and rate it. Thanks! Oh yeah, this is a test notification.`,
+            `It's almost like you want to hear what I have to say. I'm not even a machine. I'm just a sentence that Phil typed on a random Thursday.`,
+            `Alright then, it's ${formatShortDateTime(Date.now())} already. Boy oh boy, where did the time go? I hope you're alright, friend.`,
+            `There are nine million bicycles in Beijing That's a fact; It's a thing we can't deny. I wonder if that's true ...`,
+            `I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/annoucements.`,
+            `It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?`
+        ])[0];
+        api.publish(baseUrl, topic, message, title, priority, tags);
         setOpen(false);
     }
 

+ 0 - 1
web/src/components/App.js

@@ -20,7 +20,6 @@ import ErrorBoundary from "./ErrorBoundary";
 import routes from "./routes";
 import {useAutoSubscribe, useConnectionListeners} from "./hooks";
 
-// TODO better "send test message" (a la android app)
 // TODO docs
 // TODO screenshot on homepage
 // TODO "copy url" toast

+ 6 - 1
web/src/components/Navigation.js

@@ -14,7 +14,7 @@ import SubscribeDialog from "./SubscribeDialog";
 import {Alert, AlertTitle, Badge, CircularProgress, ListSubheader} from "@mui/material";
 import Button from "@mui/material/Button";
 import Typography from "@mui/material/Typography";
-import {topicShortUrl, topicUrl} from "../app/utils";
+import {openUrl, topicShortUrl, topicUrl} from "../app/utils";
 import routes from "./routes";
 import {ConnectionState} from "../app/Connection";
 import {useLocation, useNavigate} from "react-router-dom";
@@ -23,6 +23,7 @@ import {ChatBubble, NotificationsOffOutlined} from "@mui/icons-material";
 import Box from "@mui/material/Box";
 import notifier from "../app/Notifier";
 import config from "../app/config";
+import ArticleIcon from '@mui/icons-material/Article';
 
 const navWidth = 280;
 
@@ -113,6 +114,10 @@ const NavList = (props) => {
                     <ListItemIcon><SettingsIcon/></ListItemIcon>
                     <ListItemText primary="Settings"/>
                 </ListItemButton>
+                <ListItemButton onClick={() => openUrl("/docs")}>
+                    <ListItemIcon><ArticleIcon/></ListItemIcon>
+                    <ListItemText primary="Documentation"/>
+                </ListItemButton>
                 <ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
                     <ListItemIcon><AddIcon/></ListItemIcon>
                     <ListItemText primary="Add subscription"/>