From f8002c4550ed7d368e87f566ecce8161f3196367 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Wed, 20 Dec 2023 20:40:00 -0700 Subject: [PATCH 1/9] add DB logging for service-worker events --- sw_scripts/additional-scripts.js | 37 +++++++++++++++++++++--------- sw_scripts/safari-notifications.js | 25 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index fe16c18..5ecb1ed 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -4,8 +4,22 @@ importScripts( "https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js", ); +function logDbOrConsole(self, message, arg1, arg2) { + let fullMessage = `${new Date().toISOString()} ${message}`; + if (arg1) { + fullMessage += `: ${JSON.stringify(arg1)}`; + } + if (arg2) { + fullMessage += ` -- ${JSON.stringify(arg2)}`; + } + const logged = self.logMessage(fullMessage); + if (!logged) { + console.log(`$new Date().toISOString()} ${message}`, arg1, arg2); + } +} + self.addEventListener("install", (event) => { - console.log(new Date().toISOString(), "Installing service worker:", event); + logDbOrConsole(self, "Installing service worker:", event); importScripts( "safari-notifications.js", "nacl.js", @@ -15,7 +29,7 @@ self.addEventListener("install", (event) => { }); self.addEventListener("push", function (event) { - console.log(new Date().toISOString(), "Received push event:", event); + logDbOrConsole(self, "Received push event:", event); event.waitUntil( (async () => { try { @@ -32,40 +46,41 @@ self.addEventListener("push", function (event) { badge: payload ? payload.badge : "badge.png", }; await self.registration.showNotification(title, options); - console.log(new Date().toISOString(), "Notified user:", options); + logDbOrConsole(self, "Notified user:", options); } else { - console.log(new Date().toISOString(), "No notification message."); + logDbOrConsole(self, "No notification message."); } } catch (error) { - console.error(new Date().toISOString(), "Error with push event", event, " - ", error); + logDbOrConsole(self, "Error with push event", event, error); } })(), ); }); self.addEventListener("message", (event) => { - console.log(new Date().toISOString(), "Service worker message:", event); + logDbOrConsole(self, "Service worker message:", event); if (event.data && event.data.type === "SEND_LOCAL_DATA") { self.secret = event.data.data; event.ports[0].postMessage({ success: true }); } - console.log(new Date().toISOString(), "Service worker posted message."); + logDbOrConsole(self, "Service worker posted message."); }); self.addEventListener("activate", (event) => { - console.log(new Date().toISOString(), "Service worker activating...", event); + logDbOrConsole(self, "Service worker activating...", event); // see https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim // and https://web.dev/articles/service-worker-lifecycle#clientsclaim event.waitUntil(clients.claim()); - console.log(new Date().toISOString(), "Service worker activated."); + logDbOrConsole(self, "Service worker activated."); }); self.addEventListener("fetch", (event) => { - console.log(new Date().toISOString(), "Got fetch event:", event); + logDbOrConsole(self, "Got fetch event:", event); }); self.addEventListener("error", (event) => { - console.error(new Date().toISOString(), "Error in Service Worker:", event); + logDbOrConsole(self, "Error in Service Worker:", event); + console.error("Full Error:", event); console.error("Message:", event.message); console.error("File:", event.filename); console.error("Line:", event.lineno); diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index 32c12e0..16969ad 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -404,6 +404,27 @@ async function setMostRecentNotified(id) { } } +async function logMessage(message) { + try { + const db = await openIndexedDB("TimeSafari"); + const transaction = db.transaction("worker_log", "readwrite"); + const store = transaction.objectStore("worker_log"); + // will only keep one day's worth of logs + let data = await getRecord(store, new Date().toDateString()); + if (!data) { + await store.clear(); // clear out anything older than today + } + data = data || ""; + data += `\n${message}`; + await updateRecord(store, data); + transaction.oncomplete = () => db.close(); + return true; + } catch (error) { + console.error("IndexedDB logMessage error:", error); + return false; + } +} + function openIndexedDB(dbName) { return new Promise((resolve, reject) => { const request = indexedDB.open(dbName); @@ -420,6 +441,7 @@ function getRecord(store, key) { }); } +// Note that this assumes there is only one record in the store. function updateRecord(store, data) { return new Promise((resolve, reject) => { const request = store.put(data); @@ -437,6 +459,9 @@ async function fetchAllAccounts() { if (!db.objectStoreNames.contains("accounts")) { db.createObjectStore("accounts", { keyPath: "id" }); } + if (!db.objectStoreNames.contains("worker_log")) { + db.createObjectStore("worker_log"); + } }; openRequest.onsuccess = function (event) { From d7f4acb70253bd7d957d734a5d661c638d1ffad4 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Thu, 21 Dec 2023 20:50:35 -0700 Subject: [PATCH 2/9] make more adjustments to try and get logging to work --- README.md | 4 +-- package.json | 2 +- src/App.vue | 4 +-- src/components/TopMessage.vue | 2 +- src/db/index.ts | 14 ++++++++-- src/db/tables/contacts.ts | 2 +- src/db/tables/logs.ts | 7 +++++ sw_scripts/additional-scripts.js | 45 ++++++++++++++++-------------- sw_scripts/safari-notifications.js | 13 +++++---- 9 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 src/db/tables/logs.ts diff --git a/README.md b/README.md index 861a86d..34a169a 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ 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`. -* If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD. +* If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD and package.json to not be _Test. * `npm run build` @@ -40,7 +40,7 @@ If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, * `rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntu@endorser.ch:time-safari` -* Revert src/constants/app.ts, increment version, add "-beta", `npm install`, and commit. +* Revert src/constants/app.ts and/or package.json, edit package.json to increment version & add "-beta", `npm install`, and commit. diff --git a/package.json b/package.json index a24cb46..1d35ad2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "TimeSafari", + "name": "TimeSafari_Test", "version": "0.1.8-beta", "private": true, "scripts": { diff --git a/src/App.vue b/src/App.vue index 05bbe0a..b69bbd0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -462,9 +462,7 @@ export default class App extends Vue { "An error occurred setting notification permissions:", error, ); - alert( - "Some error occurred setting notification permissions. See logs.", - ); + alert("Some error occurred setting notification permissions."); }); } diff --git a/src/components/TopMessage.vue b/src/components/TopMessage.vue index 8433741..bccc2fe 100644 --- a/src/components/TopMessage.vue +++ b/src/components/TopMessage.vue @@ -50,7 +50,7 @@ export default class TopMessage extends Vue { title: "Error Detecting Server", text: JSON.stringify(err), }, - 10000, + -1, ); } } diff --git a/src/db/index.ts b/src/db/index.ts index 37d6cf5..644f813 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,7 +1,8 @@ import BaseDexie, { Table } from "dexie"; import { encrypted, Encryption } from "@pvermeer/dexie-encrypted-addon"; import { Account, AccountsSchema } from "./tables/accounts"; -import { Contact, ContactsSchema } from "./tables/contacts"; +import { Contact, ContactSchema } from "./tables/contacts"; +import { Log, LogSchema } from "@/db/tables/logs"; import { MASTER_SETTINGS_KEY, Settings, @@ -13,6 +14,7 @@ import { AppString } from "@/constants/app"; type SensitiveTables = { accounts: Table }; type NonsensitiveTables = { contacts: Table; + logs: Table; settings: Table; }; @@ -26,7 +28,11 @@ export const accountsDB = new BaseDexie("TimeSafariAccounts") as SensitiveDexie; const SensitiveSchemas = { ...AccountsSchema }; export const db = new BaseDexie("TimeSafari") as NonsensitiveDexie; -const NonsensitiveSchemas = { ...ContactsSchema, ...SettingsSchema }; +const NonsensitiveSchemas = { + ...ContactSchema, + ...LogSchema, + ...SettingsSchema, +}; // Manage the encryption key. If not present in localStorage, create and store it. const secret = @@ -38,7 +44,9 @@ encrypted(accountsDB, { secretKey: secret }); // Define the schema for our databases accountsDB.version(1).stores(SensitiveSchemas); -db.version(1).stores(NonsensitiveSchemas); +// v1 was contacts & settings +// v2 added logs +db.version(2).stores(NonsensitiveSchemas); // Event handler to initialize the non-sensitive database with default settings db.on("populate", () => { diff --git a/src/db/tables/contacts.ts b/src/db/tables/contacts.ts index b684505..8ffd2fb 100644 --- a/src/db/tables/contacts.ts +++ b/src/db/tables/contacts.ts @@ -6,6 +6,6 @@ export interface Contact { registered?: boolean; } -export const ContactsSchema = { +export const ContactSchema = { contacts: "&did, name, publicKeyBase64, registered, seesMe", }; diff --git a/src/db/tables/logs.ts b/src/db/tables/logs.ts new file mode 100644 index 0000000..2dd99f7 --- /dev/null +++ b/src/db/tables/logs.ts @@ -0,0 +1,7 @@ +export interface Log { + message: string; +} + +export const LogSchema = { + logs: "message", +}; diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index 5ecb1ed..5defa97 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -4,7 +4,19 @@ importScripts( "https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js", ); +self.addEventListener("install", (event) => { + console.log("Service worker scripts importing...", event); + importScripts( + "safari-notifications.js", + "nacl.js", + "noble-curves.js", + "noble-hashes.js", + ); + console.log("Service worker scripts imported."); +}); + function logDbOrConsole(self, message, arg1, arg2) { + console.log(`${new Date().toISOString()} ${message}`, arg1, arg2); let fullMessage = `${new Date().toISOString()} ${message}`; if (arg1) { fullMessage += `: ${JSON.stringify(arg1)}`; @@ -12,24 +24,15 @@ function logDbOrConsole(self, message, arg1, arg2) { if (arg2) { fullMessage += ` -- ${JSON.stringify(arg2)}`; } - const logged = self.logMessage(fullMessage); - if (!logged) { - console.log(`$new Date().toISOString()} ${message}`, arg1, arg2); - } + // const logged = + self.logMessage(fullMessage); + // if (logged || !logged) { + // console.log(`${new Date().toISOString()} ${message}`, arg1, arg2); + // } } -self.addEventListener("install", (event) => { - logDbOrConsole(self, "Installing service worker:", event); - importScripts( - "safari-notifications.js", - "nacl.js", - "noble-curves.js", - "noble-hashes.js", - ); -}); - self.addEventListener("push", function (event) { - logDbOrConsole(self, "Received push event:", event); + logDbOrConsole(this, "Received push event:", event); event.waitUntil( (async () => { try { @@ -58,28 +61,28 @@ self.addEventListener("push", function (event) { }); self.addEventListener("message", (event) => { - logDbOrConsole(self, "Service worker message:", event); + logDbOrConsole(this, "Service worker message:", event); if (event.data && event.data.type === "SEND_LOCAL_DATA") { self.secret = event.data.data; event.ports[0].postMessage({ success: true }); } - logDbOrConsole(self, "Service worker posted message."); + logDbOrConsole(this, "Service worker posted message."); }); self.addEventListener("activate", (event) => { - logDbOrConsole(self, "Service worker activating...", event); + logDbOrConsole(this, "Service worker activating...", event); // see https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim // and https://web.dev/articles/service-worker-lifecycle#clientsclaim event.waitUntil(clients.claim()); - logDbOrConsole(self, "Service worker activated."); + logDbOrConsole(this, "Service worker activated."); }); self.addEventListener("fetch", (event) => { - logDbOrConsole(self, "Got fetch event:", event); + logDbOrConsole(this, "Got fetch event:", event); }); self.addEventListener("error", (event) => { - logDbOrConsole(self, "Error in Service Worker:", event); + logDbOrConsole(this, "Error in Service Worker:", event); console.error("Full Error:", event); console.error("Message:", event.message); console.error("File:", event.filename); diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index 16969ad..e2f6fe0 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -407,16 +407,17 @@ async function setMostRecentNotified(id) { async function logMessage(message) { try { const db = await openIndexedDB("TimeSafari"); - const transaction = db.transaction("worker_log", "readwrite"); - const store = transaction.objectStore("worker_log"); + const transaction = db.transaction("logs", "readwrite"); + const store = transaction.objectStore("logs"); // will only keep one day's worth of logs - let data = await getRecord(store, new Date().toDateString()); + const todayKey = new Date().toDateString(); + let data = await getRecord(store, todayKey); if (!data) { await store.clear(); // clear out anything older than today } data = data || ""; data += `\n${message}`; - await updateRecord(store, data); + await updateRecord(store, { message: data }, todayKey); transaction.oncomplete = () => db.close(); return true; } catch (error) { @@ -442,9 +443,9 @@ function getRecord(store, key) { } // Note that this assumes there is only one record in the store. -function updateRecord(store, data) { +function updateRecord(store, data, key) { return new Promise((resolve, reject) => { - const request = store.put(data); + const request = key ? store.put(data, key) : store.put(data); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); From 8d873b51bdc34003daec8eb663eee9889c3d0cfb Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Thu, 21 Dec 2023 21:03:47 -0700 Subject: [PATCH 3/9] doc: update tasks --- project.task.yaml | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/project.task.yaml b/project.task.yaml index a80de78..1ccd004 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -2,29 +2,19 @@ tasks: - 08 notifications : - - make the app behave correctly when App Notifications are turned off - - write troubleshooting docs for notifications - - hide the "App Notifications" toggle when they switch notifications - - prompt user to install on their home screen https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps + - 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 + - prompt user to install on their home screen https://benborgers.com/posts/pwa-detect-installed - warn if they're using the web (android only?) https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps https://web.dev/articles/get-installed-related-apps - - add windows & mac help at OS & browser level + - add windows & mac help at OS & browser level, in HelpNotificationsView.vue (linked from account page) -- back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity -- 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") - .3 bug - make or edit a project, choose "Include location", and see the map display shows on top of the bottom icons assignee-group:ui -- Got error adding on Firefox user #0 as contact for themselves - .5 If notifications are not enabled, add message to front page with link/button to enable -- 01 server - show all claim details when issued by the issuer -- enhance help page instructions for friends to get notifications, for debugging notifications -- add way to test a push notification -- help instructions for PWA install problems (secret failed, must reinstall) -- look at other examples for better UI friend.tech - - show VC details... somehow: - 01 show my VCs - most interesting, or via search - 01 allow download of each VC (& confirmations, to show that they actually own their data) @@ -44,9 +34,13 @@ tasks: - Other features - donation vs give, show offers, show give & outstanding totals, show network view, restrict registration, connect to contacts blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time -- 01 send visibility signal as a VC and store it -- remove 'rowid' references (that are sqlite-specific) - make identicons for contacts into more-memorable faces (and maybe change project identicons, too) +- 01 server - show all claim details when issued by the issuer +- bug - got error adding on Firefox user #0 as contact for themselves +- bug - back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity +- 01 send visibility signal as a VC and store it +- 04 remove 'rowid' references (that are sqlite-specific); may involve server +- 04 look at other examples for better UI friend.tech - 01 make the prod build copy the sw_scripts - .5 Add start date to project - .3 check that Android shows "back" buttons on screens without bottom tray From e739d0be7ccb3f3d85720ae600b0cfe89df67875 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 22 Dec 2023 09:19:36 -0700 Subject: [PATCH 4/9] update error messages to be less... confusing --- src/components/GiftedDialog.vue | 4 +--- src/components/OfferDialog.vue | 4 +--- src/views/ContactAmountsView.vue | 3 ++- src/views/ContactGiftingView.vue | 3 ++- src/views/HomeView.vue | 3 ++- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/GiftedDialog.vue b/src/components/GiftedDialog.vue index 1dfb153..e236246 100644 --- a/src/components/GiftedDialog.vue +++ b/src/components/GiftedDialog.vue @@ -123,9 +123,7 @@ export default class GiftedDialog extends Vue { group: "alert", type: "danger", title: "Error", - text: - err.message || - "There was an error retrieving the latest sweet, sweet action.", + text: err.message || "There was an error retrieving your settings.", }, -1, ); diff --git a/src/components/OfferDialog.vue b/src/components/OfferDialog.vue index 0ab3700..b61bde8 100644 --- a/src/components/OfferDialog.vue +++ b/src/components/OfferDialog.vue @@ -105,9 +105,7 @@ export default class OfferDialog extends Vue { group: "alert", type: "danger", title: "Error", - text: - err.message || - "There was an error retrieving the latest sweet, sweet action.", + text: err.message || "There was an error retrieving your settings.", }, -1, ); diff --git a/src/views/ContactAmountsView.vue b/src/views/ContactAmountsView.vue index a3dfc73..52412ae 100644 --- a/src/views/ContactAmountsView.vue +++ b/src/views/ContactAmountsView.vue @@ -178,6 +178,7 @@ export default class ContactAmountssView extends Vue { } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { + console.log("Error retrieving settings or gives.", err); this.$notify( { group: "alert", @@ -185,7 +186,7 @@ export default class ContactAmountssView extends Vue { title: "Error", text: err.userMessage || - "There was an error retrieving the latest sweet, sweet action.", + "There was an error retrieving your settings and/or contacts and/or gives.", }, -1, ); diff --git a/src/views/ContactGiftingView.vue b/src/views/ContactGiftingView.vue index 2d2bcb8..35bec25 100644 --- a/src/views/ContactGiftingView.vue +++ b/src/views/ContactGiftingView.vue @@ -145,6 +145,7 @@ export default class ContactGiftingView extends Vue { this.allContacts = await db.contacts.toArray(); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { + console.log("Error retrieving settings & contacts:", err); this.$notify( { group: "alert", @@ -152,7 +153,7 @@ export default class ContactGiftingView extends Vue { title: "Error", text: err.message || - "There was an error retrieving the latest sweet, sweet action.", + "There was an error retrieving your settings and/or contacts.", }, -1, ); diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 3c973b3..daf47c4 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -234,6 +234,7 @@ export default class HomeView extends Vue { // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { + console.log("Error retrieving settings and/or feed.", err); this.$notify( { group: "alert", @@ -241,7 +242,7 @@ export default class HomeView extends Vue { title: "Error", text: err.userMessage || - "There was an error retrieving the latest sweet, sweet action.", + "There was an error retrieving your settings and/or the latest activity.", }, -1, ); From 7fe256dc9efd3c01bfc24978d65e9be67e948be7 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 22 Dec 2023 12:51:18 -0700 Subject: [PATCH 5/9] log service worker messages to the DB (now works) --- README.md | 16 ++++++------- project.task.yaml | 1 + src/App.vue | 1 + src/db/tables/logs.ts | 5 ++++- sw_scripts/additional-scripts.js | 36 +++++++++++++----------------- sw_scripts/safari-notifications.js | 32 ++++++++++++++++---------- 6 files changed, 50 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 34a169a..4a8392d 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,6 @@ npm run lint If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",` -* `npx prettier --write ./sw_scripts/` - -...to make sure the service worker scripts are in proper form - * Update the CHANGELOG.md & the version in package.json, run `npm install`, and commit. * Tag wth the new version: `git tag 0.1.0`. @@ -34,6 +30,10 @@ If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, * `npm run build` +* `npx prettier --write ./sw_scripts/` + +...to make sure the service worker scripts are in proper form + * `cp sw_scripts/[ns]* dist/` ... to copy the contents of the `sw_scripts` folder to the `dist` folder - except additional_scripts.js. @@ -112,10 +112,10 @@ To add an icon, add to main.ts and reference with `fa` element and `icon` attrib ### Clear/Reset data & restart -* Clear cache for site. (In Chrome, go to `chrome://settings/cookies` and "all site data and permissions"; in Firefox, go to `about:preferences` and search for "cache" then "Manage Data".) -* Unregister service worker (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers`). -* Clear notification permission (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search for "notifications"). -* Clear Cache Storage (in Chrome, in dev tools under Application; in Firefox, in dev tools under Storage). +* Clear cache for site. (In Chrome, go to `chrome://settings/cookies` and "all site data and permissions"; in Firefox, go to `about:preferences` and search for "cache" then "Manage Data", and also manually remove the IndexedDB data if the DBs still show.) +* Clear notification permission. (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search for "notifications".) +* Unregister service worker. (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers`.) +* Clear Cache Storage. (in Chrome, in dev tools under Application; in Firefox, in dev tools under Storage.) diff --git a/project.task.yaml b/project.task.yaml index 1ccd004..5ba2e88 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -3,6 +3,7 @@ tasks: - 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 an error registering notifications on Firefox and subscription info is null - prompt user to install on their home screen https://benborgers.com/posts/pwa-detect-installed - warn if they're using the web (android only?) https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps diff --git a/src/App.vue b/src/App.vue index b69bbd0..2c20d32 100644 --- a/src/App.vue +++ b/src/App.vue @@ -373,6 +373,7 @@ export default class App extends Vue { } private askPermission(): Promise { + console.log("Requesting permission for notifications:", navigator); if (!("serviceWorker" in navigator && navigator.serviceWorker.controller)) { return Promise.reject("Service worker not available."); } diff --git a/src/db/tables/logs.ts b/src/db/tables/logs.ts index 2dd99f7..9207a2f 100644 --- a/src/db/tables/logs.ts +++ b/src/db/tables/logs.ts @@ -3,5 +3,8 @@ export interface Log { } export const LogSchema = { - logs: "message", + // Currently keyed by "date" because A) today's log data is what we need so we append, and + // B) we don't want it to grow so we remove everything if this is the first entry today. + // See safari-notifications.js logMessage for the associated logic. + logs: "date, message", }; diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index 5defa97..3582bfc 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -5,34 +5,30 @@ importScripts( ); self.addEventListener("install", (event) => { - console.log("Service worker scripts importing...", event); + console.log("Service worker got install. Importing scripts...", event); importScripts( "safari-notifications.js", "nacl.js", "noble-curves.js", "noble-hashes.js", ); - console.log("Service worker scripts imported."); + console.log("Service worker imported scripts."); }); -function logDbOrConsole(self, message, arg1, arg2) { +function logConsoleAndDb(message, arg1, arg2) { console.log(`${new Date().toISOString()} ${message}`, arg1, arg2); let fullMessage = `${new Date().toISOString()} ${message}`; if (arg1) { - fullMessage += `: ${JSON.stringify(arg1)}`; + fullMessage += `\n${JSON.stringify(arg1)}`; } if (arg2) { - fullMessage += ` -- ${JSON.stringify(arg2)}`; + fullMessage += `\n${JSON.stringify(arg2)}`; } - // const logged = - self.logMessage(fullMessage); - // if (logged || !logged) { - // console.log(`${new Date().toISOString()} ${message}`, arg1, arg2); - // } + self.appendDailyLog(fullMessage); } self.addEventListener("push", function (event) { - logDbOrConsole(this, "Received push event:", event); + logConsoleAndDb("Service worker received a push event.", event); event.waitUntil( (async () => { try { @@ -49,40 +45,40 @@ self.addEventListener("push", function (event) { badge: payload ? payload.badge : "badge.png", }; await self.registration.showNotification(title, options); - logDbOrConsole(self, "Notified user:", options); + logConsoleAndDb("Notified user:", options); } else { - logDbOrConsole(self, "No notification message."); + logConsoleAndDb("No notification message."); } } catch (error) { - logDbOrConsole(self, "Error with push event", event, error); + logConsoleAndDb("Error with push event", event, error); } })(), ); }); self.addEventListener("message", (event) => { - logDbOrConsole(this, "Service worker message:", event); + logConsoleAndDb("Service worker got a message...", event); if (event.data && event.data.type === "SEND_LOCAL_DATA") { self.secret = event.data.data; event.ports[0].postMessage({ success: true }); } - logDbOrConsole(this, "Service worker posted message."); + logConsoleAndDb("Service worker posted a message."); }); self.addEventListener("activate", (event) => { - logDbOrConsole(this, "Service worker activating...", event); + logConsoleAndDb("Service worker activating...", event); // see https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim // and https://web.dev/articles/service-worker-lifecycle#clientsclaim event.waitUntil(clients.claim()); - logDbOrConsole(this, "Service worker activated."); + logConsoleAndDb("Service worker is activated."); }); self.addEventListener("fetch", (event) => { - logDbOrConsole(this, "Got fetch event:", event); + logConsoleAndDb("Service worker got fetch event.", event); }); self.addEventListener("error", (event) => { - logDbOrConsole(this, "Error in Service Worker:", event); + logConsoleAndDb("Service worker error", event); console.error("Full Error:", event); console.error("Message:", event.message); console.error("File:", event.filename); diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index e2f6fe0..22dcf99 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -395,33 +395,41 @@ async function setMostRecentNotified(id) { data["lastNotifiedClaimId"] = id; await updateRecord(store, data); } else { - console.error("IndexedDB settings record not found."); + console.error( + "safari-notifications setMostRecentNotified IndexedDB settings record not found", + ); } transaction.oncomplete = () => db.close(); } catch (error) { - console.error("IndexedDB error:", error); + console.error( + "safari-notifications setMostRecentNotified IndexedDB error", + error, + ); } } -async function logMessage(message) { +async function appendDailyLog(message) { try { const db = await openIndexedDB("TimeSafari"); const transaction = db.transaction("logs", "readwrite"); const store = transaction.objectStore("logs"); // will only keep one day's worth of logs const todayKey = new Date().toDateString(); - let data = await getRecord(store, todayKey); - if (!data) { + const previous = await getRecord(store, todayKey); + if (!previous) { await store.clear(); // clear out anything older than today } - data = data || ""; - data += `\n${message}`; - await updateRecord(store, { message: data }, todayKey); + let fullMessage = (previous && previous.message) || ""; + if (fullMessage) { + fullMessage += "\n"; + } + fullMessage += message; + await updateRecord(store, { date: todayKey, message: fullMessage }); transaction.oncomplete = () => db.close(); return true; } catch (error) { - console.error("IndexedDB logMessage error:", error); + console.error("safari-notifications logMessage IndexedDB error", error); return false; } } @@ -443,9 +451,9 @@ function getRecord(store, key) { } // Note that this assumes there is only one record in the store. -function updateRecord(store, data, key) { +function updateRecord(store, data) { return new Promise((resolve, reject) => { - const request = key ? store.put(data, key) : store.put(data); + const request = store.put(data); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); @@ -547,7 +555,7 @@ async function getNotificationCount() { await setMostRecentNotified(most_recent_notified); } else { console.error( - "The service worker got a bad response status when fetching claims:", + "safari-notifications getNotificationsCount got a bad response status when fetching claims", response.status, response, ); From 44cfe0d88e125733c271b1dad882c5c309cb38db Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Fri, 22 Dec 2023 14:22:13 -0700 Subject: [PATCH 6/9] allow notifications even without an ID --- project.task.yaml | 5 + src/views/HelpNotificationsView.vue | 7 +- sw_scripts/safari-notifications.js | 140 ++++++++++++++-------------- 3 files changed, 81 insertions(+), 71 deletions(-) diff --git a/project.task.yaml b/project.task.yaml index 5ba2e88..df49f3e 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -4,6 +4,11 @@ tasks: - 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 an error registering notifications on Firefox and subscription info is null + - if navigator.serviceWorker is null, then tell the user to wait + - Android DuckDuckGo asked for my permissions, got error, won't download DB + - Android Chrome won't ask permission, will download log but always empty + - + - Chrome will get notification permissions but still complain when I reload (maybe I reload too soon?) - prompt user to install on their home screen https://benborgers.com/posts/pwa-detect-installed - warn if they're using the web (android only?) https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps diff --git a/src/views/HelpNotificationsView.vue b/src/views/HelpNotificationsView.vue index c734ba4..a7c125b 100644 --- a/src/views/HelpNotificationsView.vue +++ b/src/views/HelpNotificationsView.vue @@ -22,7 +22,7 @@
-

Here are things to try to get notifications working.

+

Here are things to get notifications working.

Test

Somehow call the service-worker self.showNotification

@@ -54,7 +54,10 @@
Make sure your OS (above) supports it.

Mobile Phone - Android

-
Chrome requires version 50.
+
+ Chrome requires version 50. Hold icon, select "App info", and enable + notifications. +
diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index 22dcf99..a50980f 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -461,10 +461,10 @@ function updateRecord(store, data) { async function fetchAllAccounts() { return new Promise((resolve, reject) => { - let openRequest = indexedDB.open("TimeSafariAccounts"); + const openRequest = indexedDB.open("TimeSafariAccounts"); openRequest.onupgradeneeded = function (event) { - let db = event.target.result; + const db = event.target.result; if (!db.objectStoreNames.contains("accounts")) { db.createObjectStore("accounts", { keyPath: "id" }); } @@ -474,10 +474,10 @@ async function fetchAllAccounts() { }; openRequest.onsuccess = function (event) { - let db = event.target.result; - let transaction = db.transaction("accounts", "readonly"); - let objectStore = transaction.objectStore("accounts"); - let getAllRequest = objectStore.getAll(); + const db = event.target.result; + const transaction = db.transaction("accounts", "readonly"); + const objectStore = transaction.objectStore("accounts"); + const getAllRequest = objectStore.getAll(); getAllRequest.onsuccess = function () { resolve(getAllRequest.result); @@ -494,76 +494,78 @@ async function fetchAllAccounts() { } async function getNotificationCount() { - let secret = null; let accounts = []; let result = null; - if ("secret" in self) { - secret = self.secret; - const secretUint8Array = self.decodeBase64(secret); - // 1 is our master settings ID; see MASTER_SETTINGS_KEY - const settings = await getSettingById(1); - let lastNotifiedClaimId = null; - if ("lastNotifiedClaimId" in settings) { - lastNotifiedClaimId = settings["lastNotifiedClaimId"]; + // 1 is our master settings ID; see MASTER_SETTINGS_KEY + const settings = await getSettingById(1); + let lastNotifiedClaimId = null; + if ("lastNotifiedClaimId" in settings) { + lastNotifiedClaimId = settings["lastNotifiedClaimId"]; + } + const activeDid = settings["activeDid"]; + console.log("safari-not getNotificationsCount last", lastNotifiedClaimId); + accounts = await fetchAllAccounts(); + let activeAccount = null; + for (let i = 0; i < accounts.length; i++) { + if (accounts[i]["did"] == activeDid) { + activeAccount = accounts[i]; + break; } - const activeDid = settings["activeDid"]; - accounts = await fetchAllAccounts(); - let did = null; - for (var i = 0; i < accounts.length; i++) { - let account = accounts[i]; - let did = account["did"]; - if (did == activeDid) { - let publicKeyHex = account["publicKeyHex"]; - let identity = account["identity"]; - const messageWithNonceAsUint8Array = self.decodeBase64(identity); - const nonce = messageWithNonceAsUint8Array.slice(0, 24); - const message = messageWithNonceAsUint8Array.slice(24, identity.length); - const decoder = new TextDecoder("utf-8"); - const decrypted = self.secretbox.open(message, nonce, secretUint8Array); - - const msg = decoder.decode(decrypted); - const identifier = JSON.parse(JSON.parse(msg)); - - const headers = { - "Content-Type": "application/json", - }; - - headers["Authorization"] = "Bearer " + (await accessToken(identifier)); - - let response = await fetch( - settings["apiServer"] + "/api/v2/report/claims", - { - method: "GET", - headers: headers, - }, - ); - if (response.status == 200) { - let json = await response.json(); - let claims = json["data"]; - let newClaims = 0; - for (var i = 0; i < claims.length; i++) { - let claim = claims[i]; - if (claim["id"] === lastNotifiedClaimId) { - break; - } - newClaims++; - } - if (newClaims > 0) { - result = `There are ${newClaims} new activities on TimeSafari`; - } - const most_recent_notified = claims[0]["id"]; - await setMostRecentNotified(most_recent_notified); - } else { - console.error( - "safari-notifications getNotificationsCount got a bad response status when fetching claims", - response.status, - response, - ); - } + } + + const headers = { + "Content-Type": "application/json", + }; + + const identity = activeAccount && activeAccount["identity"]; + if (identity && "secret" in self) { + const secret = self.secret; + const secretUint8Array = self.decodeBase64(secret); + const messageWithNonceAsUint8Array = self.decodeBase64(identity); + const nonce = messageWithNonceAsUint8Array.slice(0, 24); + const message = messageWithNonceAsUint8Array.slice(24, identity.length); + const decoder = new TextDecoder("utf-8"); + const decrypted = self.secretbox.open(message, nonce, secretUint8Array); + const msg = decoder.decode(decrypted); + const identifier = JSON.parse(JSON.parse(msg)); + + headers["Authorization"] = "Bearer " + (await accessToken(identifier)); + } + + console.log("safari-not getNotificationsCount fetch", headers); + const response = await fetch( + settings["apiServer"] + "/api/v2/report/claims", + { + method: "GET", + headers: headers, + }, + ); + console.log("safari-not getNotificationsCount json", response); + if (response.status == 200) { + const json = await response.json(); + console.log("safari-not getNotificationsCount json", json); + const claims = json["data"]; + let newClaims = 0; + for (let i = 0; i < claims.length; i++) { + const claim = claims[i]; + if (claim["id"] === lastNotifiedClaimId) { break; } + newClaims++; + } + if (newClaims > 0) { + result = `There are ${newClaims} new activities on Time Safari`; } + const most_recent_notified = claims[0]["id"]; + await setMostRecentNotified(most_recent_notified); + } else { + console.error( + "safari-notifications getNotificationsCount got a bad response status when fetching claims", + response.status, + response, + ); } + return result; } From 853eb3c623dacd6bd1c8de7ed055d16587d6f2d0 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Sat, 23 Dec 2023 19:34:26 -0700 Subject: [PATCH 7/9] include the data in the logged info for a service worker "push" --- sw_scripts/additional-scripts.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index 3582bfc..0e2d326 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -28,13 +28,17 @@ function logConsoleAndDb(message, arg1, arg2) { } self.addEventListener("push", function (event) { - logConsoleAndDb("Service worker received a push event.", event); + let text = null; + if (event.data) { + text = event.data.text(); + } + logConsoleAndDb("Service worker received a push event.", text, event); event.waitUntil( (async () => { try { let payload; - if (event.data) { - payload = JSON.parse(event.data.text()); + if (text) { + payload = JSON.parse(text); } const message = await self.getNotificationCount(); if (message) { From 05c6ddda02553ae43559d7aaeb8c3f226ec0abab Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Sun, 24 Dec 2023 21:24:51 -0700 Subject: [PATCH 8/9] allow a test notification from the notification help screen --- README.md | 4 +- project.task.yaml | 14 +++- src/App.vue | 14 ++-- src/constants/app.ts | 12 ++- src/db/index.ts | 4 +- src/views/AccountViewView.vue | 18 +--- src/views/HelpNotificationsView.vue | 125 ++++++++++++++++++++++++++++ src/views/HelpView.vue | 9 ++ sw_scripts/additional-scripts.js | 24 +++++- sw_scripts/safari-notifications.js | 4 - 10 files changed, 183 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 4a8392d..0e943d1 100644 --- a/README.md +++ b/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`. -* 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` * `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/` diff --git a/project.task.yaml b/project.task.yaml index df49f3e..36808bf 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -2,18 +2,23 @@ tasks: - 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 - if navigator.serviceWorker is null, then tell the user to wait - Android DuckDuckGo asked for my permissions, got error, won't download DB - Android Chrome won't ask permission, will download log but always empty - - - - Chrome will get notification permissions but still complain when I reload (maybe I reload too soon?) + - Firefox works + - 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 - warn if they're using the web (android only?) https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps 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") @@ -83,6 +88,7 @@ tasks: - 24 Move to Vite - 32 accept images for projects - 32 accept images for contacts +- import project interactions from GitHub/GitLab and manage signing - linking between projects or plans : - show total time given to & from a project diff --git a/src/App.vue b/src/App.vue index 2c20d32..7b41d47 100644 --- a/src/App.vue +++ b/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 { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; @@ -302,7 +302,7 @@ export default class App extends Vue { try { await db.open(); const settings = await db.settings.get(MASTER_SETTINGS_KEY); - let pushUrl: string = AppString.DEFAULT_PUSH_SERVER; + let pushUrl = DEFAULT_PUSH_SERVER; if (settings?.webPushServer) { pushUrl = settings.webPushServer; } @@ -446,7 +446,9 @@ export default class App extends Vue { } }) .then(() => { - console.log("Subscription data sent to server."); + console.log( + "Subscription data sent to server and all finished successfully.", + ); }) .catch((error) => { console.error( @@ -510,11 +512,7 @@ export default class App extends Vue { resolve(); }) .catch((error) => { - console.error( - "Subscription or server communication failed:", - error, - options, - ); + console.error("Push subscription failed:", error, options); // Inform the user about the issue alert( diff --git a/src/constants/app.ts b/src/constants/app.ts index c92709b..1675806 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -4,22 +4,20 @@ * See also ../libs/veramo/setup.ts */ export enum AppString { - APP_NAME = "Time Safari", - PROD_ENDORSER_API_SERVER = "https://api.endorser.ch", TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch", 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", TEST1_PUSH_SERVER = "https://test.timesafari.app", 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. * From the notiwind package diff --git a/src/db/index.ts b/src/db/index.ts index 644f813..c15f6c9 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -8,7 +8,7 @@ import { Settings, SettingsSchema, } 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 type SensitiveTables = { accounts: Table }; @@ -52,6 +52,6 @@ db.version(2).stores(NonsensitiveSchemas); db.on("populate", () => { db.settings.add({ id: MASTER_SETTINGS_KEY, - apiServer: AppString.DEFAULT_ENDORSER_API_SERVER, + apiServer: DEFAULT_ENDORSER_API_SERVER, }); }); diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index f459c0e..1a19d05 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -133,6 +133,9 @@ Notification status may have changed. Revisit this page to see the latest setting. + + Troubleshoot notifications here. +

Data

@@ -306,13 +309,6 @@ Switch Identity - -

Claim Server

diff --git a/src/views/HelpNotificationsView.vue b/src/views/HelpNotificationsView.vue index a7c125b..12c055f 100644 --- a/src/views/HelpNotificationsView.vue +++ b/src/views/HelpNotificationsView.vue @@ -69,12 +69,34 @@

Auto-detection

Show results of auto-detection whether they're turned on

+ + + +
diff --git a/src/views/HelpView.vue b/src/views/HelpView.vue index 6caae30..53ea284 100644 --- a/src/views/HelpView.vue +++ b/src/views/HelpView.vue @@ -182,6 +182,15 @@ different page.

+

+ Where do I get help with notifications? +

+

+ Here. +

+

How do I access even more functionality?

diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index 0e2d326..b96f5f2 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -38,11 +38,29 @@ self.addEventListener("push", function (event) { try { let payload; 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) { - const title = payload && payload.title ? payload.title : "Message"; const options = { body: message, icon: payload ? payload.icon : "icon.png", diff --git a/sw_scripts/safari-notifications.js b/sw_scripts/safari-notifications.js index a50980f..0d0eb9c 100644 --- a/sw_scripts/safari-notifications.js +++ b/sw_scripts/safari-notifications.js @@ -503,7 +503,6 @@ async function getNotificationCount() { lastNotifiedClaimId = settings["lastNotifiedClaimId"]; } const activeDid = settings["activeDid"]; - console.log("safari-not getNotificationsCount last", lastNotifiedClaimId); accounts = await fetchAllAccounts(); let activeAccount = null; for (let i = 0; i < accounts.length; i++) { @@ -532,7 +531,6 @@ async function getNotificationCount() { headers["Authorization"] = "Bearer " + (await accessToken(identifier)); } - console.log("safari-not getNotificationsCount fetch", headers); const response = await fetch( settings["apiServer"] + "/api/v2/report/claims", { @@ -540,10 +538,8 @@ async function getNotificationCount() { headers: headers, }, ); - console.log("safari-not getNotificationsCount json", response); if (response.status == 200) { const json = await response.json(); - console.log("safari-not getNotificationsCount json", json); const claims = json["data"]; let newClaims = 0; for (let i = 0; i < claims.length; i++) { From fd8877900b7ec9c5756ccb183e95547b11713d24 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Mon, 25 Dec 2023 12:51:06 -0700 Subject: [PATCH 9/9] add another alert message & test button --- project.task.yaml | 1 + src/App.vue | 9 ++++++ src/views/HelpNotificationsView.vue | 44 +++++++++++++++++++++++++++-- sw_scripts/additional-scripts.js | 2 +- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/project.task.yaml b/project.task.yaml index 36808bf..ba36658 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -46,6 +46,7 @@ tasks: blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time - make identicons for contacts into more-memorable faces (and maybe change project identicons, too) +- 04 split out notification logic & tests from web-push-subscription logic & tests - 01 server - show all claim details when issued by the issuer - bug - got error adding on Firefox user #0 as contact for themselves - bug - back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity diff --git a/src/App.vue b/src/App.vue index 7b41d47..85489c8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -449,6 +449,15 @@ export default class App extends Vue { console.log( "Subscription data sent to server and all finished successfully.", ); + this.$notify( + { + group: "alert", + type: "success", + title: "Notifications Turned On", + text: "Notifications are on. You should see one on your device; if not, see the 'Troubleshoot' page.", + }, + -1, + ); }) .catch((error) => { console.error( diff --git a/src/views/HelpNotificationsView.vue b/src/views/HelpNotificationsView.vue index 12c055f..77b284b 100644 --- a/src/views/HelpNotificationsView.vue +++ b/src/views/HelpNotificationsView.vue @@ -22,10 +22,16 @@
-

Here are things to get notifications working.

+

Here are ways to get notifications working.

Test

Somehow call the service-worker self.showNotification

+

Check OS-level permissions

@@ -150,7 +156,7 @@ export default class HelpNotificationsView extends Vue { pushUrl = settings.webPushServer; } - // This should be a constant shared with the service worker. See TEST_PUSH_TITLE in additional-scripts.js + // This is shared with the service worker and should be a constant. Look for the same name 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"; @@ -172,7 +178,7 @@ export default class HelpNotificationsView extends Vue { auth: authB64, p256dh: p256dhB64, }, - message: "This is a test message, hopefully triggered by you.", + message: "This is a test message, triggered by you.", title: DIRECT_PUSH_TITLE, }; console.log("Sending a test web push message:", newPayload); @@ -211,5 +217,37 @@ export default class HelpNotificationsView extends Vue { ); } } + + showTestNotification() { + navigator.serviceWorker.ready + .then((registration) => { + return registration.showNotification("It Worked", { + body: "This is your test notification.", + }); + }) + .then(() => { + this.$notify( + { + group: "alert", + type: "success", + title: "Sent", + text: "A notification was triggered, so one should show on your device soon.", + }, + 5000, + ); + }) + .catch((error) => { + console.error("Got a notification error:", error); + this.$notify( + { + group: "alert", + type: "danger", + title: "Failed", + text: "Got an error sending a notification.", + }, + -1, + ); + }); + } } diff --git a/sw_scripts/additional-scripts.js b/sw_scripts/additional-scripts.js index b96f5f2..79b42a7 100644 --- a/sw_scripts/additional-scripts.js +++ b/sw_scripts/additional-scripts.js @@ -45,7 +45,7 @@ self.addEventListener("push", function (event) { } } - // This should be a constant shared with the notification-test code. See TEST_PUSH_TITLE in HelpNotificationsView.vue + // This is shared with the notification-test code and should be a constant. Look for the same name 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";