Browse Source

allow a test notification from the notification help screen

kb/add-usage-guide
Trent Larson 11 months ago
parent
commit
05c6ddda02
  1. 4
      README.md
  2. 14
      project.task.yaml
  3. 14
      src/App.vue
  4. 12
      src/constants/app.ts
  5. 4
      src/db/index.ts
  6. 18
      src/views/AccountViewView.vue
  7. 125
      src/views/HelpNotificationsView.vue
  8. 9
      src/views/HelpView.vue
  9. 24
      sw_scripts/additional-scripts.js
  10. 4
      sw_scripts/safari-notifications.js

4
README.md

@ -26,13 +26,13 @@ If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js,
* Tag wth the new version: `git tag 0.1.0`. * Tag wth the new version: `git tag 0.1.0`.
* If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD and package.json to not be _Test. * If production, change src/constants/app.ts DEFAULT_*_SERVER to be "PROD" and package.json to remove "_Test".
* `npm run build` * `npm run build`
* `npx prettier --write ./sw_scripts/` * `npx prettier --write ./sw_scripts/`
...to make sure the service worker scripts are in proper form ...to make sure the service worker scripts are in proper form. It's only important if you changed something in that directory.
* `cp sw_scripts/[ns]* dist/` * `cp sw_scripts/[ns]* dist/`

14
project.task.yaml

@ -2,18 +2,23 @@
tasks: tasks:
- 08 notifications : - 08 notifications :
- get the rest of our Android devices to work... and insert tooling (exportable logs?) so that we can see problems and troubleshoot as we onboard - get the rest of our Android devices to work
- insert tooling (exportable logs?) so that we can see problems and troubleshoot as we onboard
- get an error registering notifications on Firefox and subscription info is null - get an error registering notifications on Firefox and subscription info is null
- if navigator.serviceWorker is null, then tell the user to wait - if navigator.serviceWorker is null, then tell the user to wait
- Android DuckDuckGo asked for my permissions, got error, won't download DB - Android DuckDuckGo asked for my permissions, got error, won't download DB
- Android Chrome won't ask permission, will download log but always empty - Android Chrome won't ask permission, will download log but always empty
- - Firefox works
- Chrome will get notification permissions but still complain when I reload (maybe I reload too soon?) - Local install works after cleared out cache in Chrome
- create troubleshooting notification:
- server gets signal to send a normal notification back immediately
- add windows & mac help at OS & browser level, in HelpNotificationsView.vue (linked from account page)
maybe tell them to pause, after first turn-on and after test
maybe Google Play permissions
- prompt user to install on their home screen https://benborgers.com/posts/pwa-detect-installed - prompt user to install on their home screen https://benborgers.com/posts/pwa-detect-installed
- warn if they're using the web (android only?) - warn if they're using the web (android only?)
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps
https://web.dev/articles/get-installed-related-apps https://web.dev/articles/get-installed-related-apps
- add windows & mac help at OS & browser level, in HelpNotificationsView.vue (linked from account page)
- .2 fix the projects on /discover to show the issuer (currently all "Someone Anonymous") - .2 fix the projects on /discover to show the issuer (currently all "Someone Anonymous")
@ -83,6 +88,7 @@ tasks:
- 24 Move to Vite - 24 Move to Vite
- 32 accept images for projects - 32 accept images for projects
- 32 accept images for contacts - 32 accept images for contacts
- import project interactions from GitHub/GitLab and manage signing
- linking between projects or plans : - linking between projects or plans :
- show total time given to & from a project - show total time given to & from a project

14
src/App.vue

@ -281,7 +281,7 @@ interface VapidResponse {
}; };
} }
import { AppString } from "@/constants/app"; import { DEFAULT_PUSH_SERVER } from "@/constants/app";
import { db } from "@/db/index"; import { db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
@ -302,7 +302,7 @@ export default class App extends Vue {
try { try {
await db.open(); await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY); const settings = await db.settings.get(MASTER_SETTINGS_KEY);
let pushUrl: string = AppString.DEFAULT_PUSH_SERVER; let pushUrl = DEFAULT_PUSH_SERVER;
if (settings?.webPushServer) { if (settings?.webPushServer) {
pushUrl = settings.webPushServer; pushUrl = settings.webPushServer;
} }
@ -446,7 +446,9 @@ export default class App extends Vue {
} }
}) })
.then(() => { .then(() => {
console.log("Subscription data sent to server."); console.log(
"Subscription data sent to server and all finished successfully.",
);
}) })
.catch((error) => { .catch((error) => {
console.error( console.error(
@ -510,11 +512,7 @@ export default class App extends Vue {
resolve(); resolve();
}) })
.catch((error) => { .catch((error) => {
console.error( console.error("Push subscription failed:", error, options);
"Subscription or server communication failed:",
error,
options,
);
// Inform the user about the issue // Inform the user about the issue
alert( alert(

12
src/constants/app.ts

@ -4,22 +4,20 @@
* See also ../libs/veramo/setup.ts * See also ../libs/veramo/setup.ts
*/ */
export enum AppString { export enum AppString {
APP_NAME = "Time Safari",
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch", PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch", TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch",
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000", LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
DEFAULT_ENDORSER_API_SERVER = TEST_ENDORSER_API_SERVER,
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
PROD_PUSH_SERVER = "https://timesafari.app", PROD_PUSH_SERVER = "https://timesafari.app",
TEST1_PUSH_SERVER = "https://test.timesafari.app", TEST1_PUSH_SERVER = "https://test.timesafari.app",
TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com", TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com",
DEFAULT_PUSH_SERVER = TEST1_PUSH_SERVER,
} }
export const DEFAULT_ENDORSER_API_SERVER = AppString.TEST_ENDORSER_API_SERVER;
export const DEFAULT_PUSH_SERVER =
window.location.protocol + "//" + window.location.host;
/** /**
* The possible values for "group" and "type" are in App.vue. * The possible values for "group" and "type" are in App.vue.
* From the notiwind package * From the notiwind package

4
src/db/index.ts

@ -8,7 +8,7 @@ import {
Settings, Settings,
SettingsSchema, SettingsSchema,
} from "./tables/settings"; } from "./tables/settings";
import { AppString } from "@/constants/app"; import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
// Define types for tables that hold sensitive and non-sensitive data // Define types for tables that hold sensitive and non-sensitive data
type SensitiveTables = { accounts: Table<Account> }; type SensitiveTables = { accounts: Table<Account> };
@ -52,6 +52,6 @@ db.version(2).stores(NonsensitiveSchemas);
db.on("populate", () => { db.on("populate", () => {
db.settings.add({ db.settings.add({
id: MASTER_SETTINGS_KEY, id: MASTER_SETTINGS_KEY,
apiServer: AppString.DEFAULT_ENDORSER_API_SERVER, apiServer: DEFAULT_ENDORSER_API_SERVER,
}); });
}); });

18
src/views/AccountViewView.vue

@ -133,6 +133,9 @@
Notification status may have changed. Revisit this page to see the Notification status may have changed. Revisit this page to see the
latest setting. latest setting.
</div> </div>
<router-link class="px-4 text-sm text-blue-500" to="/help-notifications">
Troubleshoot notifications here.
</router-link>
</div> </div>
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3> <h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
@ -306,13 +309,6 @@
Switch Identity Switch Identity
</router-link> </router-link>
<button
@click="alertWebPushSubscription()"
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
>
Show Subscription from Web Push Server
</button>
<div class="flex py-4"> <div class="flex py-4">
<h2 class="text-slate-500 text-sm font-bold mb-2">Claim Server</h2> <h2 class="text-slate-500 text-sm font-bold mb-2">Claim Server</h2>
<input <input
@ -1048,13 +1044,5 @@ export default class AccountViewView extends Vue {
-1, -1,
); );
} }
alertWebPushSubscription() {
console.log(
"Web push subscription:",
JSON.parse(JSON.stringify(this.subscription)), // gives more info than plain console logging
);
alert(JSON.stringify(this.subscription));
}
} }
</script> </script>

125
src/views/HelpNotificationsView.vue

@ -69,12 +69,34 @@
<h2 class="text-xl font-semibold">Auto-detection</h2> <h2 class="text-xl font-semibold">Auto-detection</h2>
<p>Show results of auto-detection whether they're turned on</p> <p>Show results of auto-detection whether they're turned on</p>
<button
@click="alertWebPushSubscription()"
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
>
Show Subscription from Web Push Server
</button>
<button
@click="sendTestWebPushMessage()"
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
>
Send Myself a Test Web Push Message
</button>
</div> </div>
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import axios from "axios";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import { db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { DEFAULT_PUSH_SERVER } from "@/constants/app";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer;
interface Notification { interface Notification {
group: string; group: string;
@ -86,5 +108,108 @@ interface Notification {
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav } })
export default class HelpNotificationsView extends Vue { export default class HelpNotificationsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
subscription: PushSubscription | null = null;
async mounted() {
try {
const registration = await navigator.serviceWorker.ready;
this.subscription = await registration.pushManager.getSubscription();
} catch (error) {
console.error("Mount error:", error);
}
}
alertWebPushSubscription() {
console.log(
"Web push subscription:",
JSON.parse(JSON.stringify(this.subscription)), // gives more info than plain console logging
);
alert(JSON.stringify(this.subscription));
}
async sendTestWebPushMessage() {
if (!this.subscription) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Not Subscribed",
text: "You must enable notifications before testing the web push.",
},
-1,
);
return;
}
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
let pushUrl: string = DEFAULT_PUSH_SERVER as string;
if (settings?.webPushServer) {
pushUrl = settings.webPushServer;
}
// This should be a constant shared with the service worker. See TEST_PUSH_TITLE in additional-scripts.js
// Use something other than "Daily Update" https://gitea.anomalistdesign.com/trent_larson/py-push-server/src/commit/3c0e196c11bc98060ec5934e99e7dbd591b5da4d/app.py#L213
const DIRECT_PUSH_TITLE = "DIRECT_NOTIFICATION";
const auth = Buffer.from(this.subscription.getKey("auth"));
const authB64 = auth
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const p256dh = Buffer.from(this.subscription.getKey("p256dh"));
const p256dhB64 = p256dh
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const newPayload = {
endpoint: this.subscription.endpoint,
keys: {
auth: authB64,
p256dh: p256dhB64,
},
message: "This is a test message, hopefully triggered by you.",
title: DIRECT_PUSH_TITLE,
};
console.log("Sending a test web push message:", newPayload);
const payloadStr = JSON.stringify(newPayload);
const response = await axios.post(
pushUrl + "/web-push/send-test",
payloadStr,
{
headers: {
"Content-Type": "application/json",
},
},
);
console.log("Got response from web push server:", response);
this.$notify(
{
group: "alert",
type: "success",
title: "Test Web Push Sent",
text: "Check your device for the test web push message.",
},
-1,
);
} catch (error) {
console.error("Got an error sending test notification:", error);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Sending Test",
text: "Got an error sending the test web push notification.",
},
-1,
);
}
}
} }
</script> </script>

9
src/views/HelpView.vue

@ -182,6 +182,15 @@
different page. different page.
</p> </p>
<h2 class="text-xl font-semibold">
Where do I get help with notifications?
</h2>
<p>
<router-link class="text-blue-500" to="/help-notifications"
>Here.</router-link
>
</p>
<h2 class="text-xl font-semibold"> <h2 class="text-xl font-semibold">
How do I access even more functionality? How do I access even more functionality?
</h2> </h2>

24
sw_scripts/additional-scripts.js

@ -38,11 +38,29 @@ self.addEventListener("push", function (event) {
try { try {
let payload; let payload;
if (text) { if (text) {
payload = JSON.parse(text); try {
payload = JSON.parse(text);
} catch (e) {
// don't use payload since it is not JSON
}
}
// This should be a constant shared with the notification-test code. See TEST_PUSH_TITLE in HelpNotificationsView.vue
// Use something other than "Daily Update" https://gitea.anomalistdesign.com/trent_larson/py-push-server/src/commit/3c0e196c11bc98060ec5934e99e7dbd591b5da4d/app.py#L213
const DIRECT_PUSH_TITLE = "DIRECT_NOTIFICATION";
let title = "Generic Notification";
let message = "Got some empty message.";
if (payload && payload.title == DIRECT_PUSH_TITLE) {
// skip any search logic and show the message directly
title = "Direct Message";
message = payload.message || "No details were provided.";
} else {
title =
payload && payload.title ? payload.title : "Unknown Notification";
message = await self.getNotificationCount();
} }
const message = await self.getNotificationCount();
if (message) { if (message) {
const title = payload && payload.title ? payload.title : "Message";
const options = { const options = {
body: message, body: message,
icon: payload ? payload.icon : "icon.png", icon: payload ? payload.icon : "icon.png",

4
sw_scripts/safari-notifications.js

@ -503,7 +503,6 @@ async function getNotificationCount() {
lastNotifiedClaimId = settings["lastNotifiedClaimId"]; lastNotifiedClaimId = settings["lastNotifiedClaimId"];
} }
const activeDid = settings["activeDid"]; const activeDid = settings["activeDid"];
console.log("safari-not getNotificationsCount last", lastNotifiedClaimId);
accounts = await fetchAllAccounts(); accounts = await fetchAllAccounts();
let activeAccount = null; let activeAccount = null;
for (let i = 0; i < accounts.length; i++) { for (let i = 0; i < accounts.length; i++) {
@ -532,7 +531,6 @@ async function getNotificationCount() {
headers["Authorization"] = "Bearer " + (await accessToken(identifier)); headers["Authorization"] = "Bearer " + (await accessToken(identifier));
} }
console.log("safari-not getNotificationsCount fetch", headers);
const response = await fetch( const response = await fetch(
settings["apiServer"] + "/api/v2/report/claims", settings["apiServer"] + "/api/v2/report/claims",
{ {
@ -540,10 +538,8 @@ async function getNotificationCount() {
headers: headers, headers: headers,
}, },
); );
console.log("safari-not getNotificationsCount json", response);
if (response.status == 200) { if (response.status == 200) {
const json = await response.json(); const json = await response.json();
console.log("safari-not getNotificationsCount json", json);
const claims = json["data"]; const claims = json["data"];
let newClaims = 0; let newClaims = 0;
for (let i = 0; i < claims.length; i++) { for (let i = 0; i < claims.length; i++) {

Loading…
Cancel
Save