Better test messages

This commit is contained in:
Philipp Heckel 2022-03-10 22:58:24 -05:00
parent 488aeb119b
commit 3f978bc45f
7 changed files with 60 additions and 12 deletions

View file

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

View file

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

View file

@ -26,14 +26,24 @@ class Api {
return messages; return messages;
} }
async publish(baseUrl, topic, message) { async publish(baseUrl, topic, message, title, priority, tags) {
const user = await userManager.get(baseUrl); const user = await userManager.get(baseUrl);
const url = topicUrl(baseUrl, topic); const url = topicUrl(baseUrl, topic);
console.log(`[Api] Publishing message to ${url}`); 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, { await fetch(url, {
method: 'PUT', method: 'PUT',
body: message, body: message,
headers: maybeWithBasicAuth({}, user) headers: maybeWithBasicAuth(headers, user)
}); });
} }

View file

@ -104,6 +104,17 @@ export const encodeBase64Url = (s) => {
return Base64.encodeURI(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/ // https://jameshfisher.com/2017/10/30/web-cryptography-api-hello-world/
export const sha256 = async (s) => { export const sha256 = async (s) => {
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode(s)); const buf = await crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode(s));

View file

@ -7,7 +7,7 @@ import Typography from "@mui/material/Typography";
import * as React from "react"; import * as React from "react";
import {useEffect, useRef, useState} from "react"; import {useEffect, useRef, useState} from "react";
import Box from "@mui/material/Box"; 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 {useLocation, useNavigate} from "react-router-dom";
import ClickAwayListener from '@mui/material/ClickAwayListener'; import ClickAwayListener from '@mui/material/ClickAwayListener';
import Grow from '@mui/material/Grow'; import Grow from '@mui/material/Grow';
@ -108,8 +108,31 @@ const SettingsIcons = (props) => {
const handleSendTestMessage = () => { const handleSendTestMessage = () => {
const baseUrl = props.subscription.baseUrl; const baseUrl = props.subscription.baseUrl;
const topic = props.subscription.topic; const topic = props.subscription.topic;
api.publish(baseUrl, topic, const tags = shuffle([
`This is a test notification sent by the ntfy Web UI at ${new Date().toString()}.`); // FIXME result ignored "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); setOpen(false);
} }

View file

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

View file

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