Changeset 952baf3 in Klonkt for src/views/pages/admin-push.ejs


Ignore:
Timestamp:
08/07/2026 05:15:52 PM (5 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
ba76bf5
Parents:
f85b2c3 (diff), 0d5bd2c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge GitHub-main (1.7.0) met de VPS-lijn

De twee mains waren een dag gedivergeerd en bevatten elk echt werk. GitHub had 66
commits die nooit langs prutfolio.git zijn gekomen, omdat een parallelle sessie
rechtstreeks naar GitHub pushte vanaf een kloon in /tmp op de VPS. De VPS had twee
commits die GitHub niet had. Geen van beide bevatte de ander, en stable had geen van
de twee.

Bewust een merge en geen rebase: dan blijft beide historie intact en wordt er niets
herschreven waar iemand anders al op voortbouwt.

Drie bestanden raakten beide kanten. Alle drie zijn nagekeken, want dat een merge
automatisch slaagt zegt niets over of hij inhoudelijk klopt:

src/services/ActivityPubService.js

  • de sleutelbinding staat nu boven de nieuwe asSlug-aanroep van 1.7.0, dus de controle komt nog steeds voor de handtekeningcontrole

scripts/klonkt-refresh-updater.sh

  • alleen de opzij-aanpak overleefde; systemctl mask staat nergens meer als code

deploy/MULTI-INSTANCE.md

  • spreekt zichzelf niet tegen: beschrijft opzij zetten, met de reden waarom mask weigert

remarks: het gat dat in de review naar boven kwam staat hiermee ook op de 1.7.0-lijn.
De andere bevindingen uit die review staan nog open en zijn niet in deze merge
opgelost; die horen als beads. Ook nog te doen: dezelfde sleutelbinding op stable
als 1.6.1, want daar is het gat nog open bij self-hosters.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/admin-push.ejs

    rf85b2c3 r952baf3  
    5858  i18n: { on: t('push.state_on'), off: t('push.state_off'), denied: t('push.state_denied'), unknown: t('push.state_unknown'), unsupported: t('push.state_unsupported'), failed: t('push.enable_failed') },
    5959}).replace(/</g, '\\u003c') %></script>
    60 <script>
    61 (function () {
    62   var cfg = JSON.parse(document.getElementById('np-data').textContent);
    63   var elState = document.getElementById('np-state');
    64   var btnOn = document.getElementById('np-on'), btnOff = document.getElementById('np-off'), btnTest = document.getElementById('np-test');
    65   var alertsBox = document.getElementById('np-alerts'), savedMsg = document.getElementById('np-saved');
    66   var currentEndpoint = null;
    67 
    68   var isIos = /iPad|iPhone|iPod/.test(navigator.userAgent);
    69   var standalone = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
    70   if (isIos && !standalone) document.getElementById('np-ios-hint').hidden = false;
    71 
    72   if (!('serviceWorker' in navigator) || !('PushManager' in window) || !('Notification' in window)) {
    73     document.getElementById('np-unsupported').hidden = false;
    74     elState.textContent = cfg.i18n.unsupported;
    75     return;
    76   }
    77 
    78   function b64ToU8(s) {
    79     var pad = '='.repeat((4 - (s.length % 4)) % 4);
    80     var raw = atob((s + pad).replace(/-/g, '+').replace(/_/g, '/'));
    81     var out = new Uint8Array(raw.length);
    82     for (var i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
    83     return out;
    84   }
    85   function post(url, body) {
    86     return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body || {}) });
    87   }
    88   function deviceLabel() {
    89     var ua = navigator.userAgent;
    90     var browser = /Firefox\//.test(ua) ? 'Firefox' : /Edg\//.test(ua) ? 'Edge' : /Chrome\//.test(ua) ? 'Chrome' : /Safari\//.test(ua) ? 'Safari' : 'Browser';
    91     var os = /Android/.test(ua) ? 'Android' : /iPad|iPhone|iPod/.test(ua) ? 'iOS' : /Mac/.test(ua) ? 'macOS' : /Win/.test(ua) ? 'Windows' : /Linux/.test(ua) ? 'Linux' : '';
    92     return (browser + (os ? ' op ' + os : ''));
    93   }
    94   function readAlertBoxes() {
    95     var out = {};
    96     alertsBox.querySelectorAll('input[data-alert]').forEach(function (cb) { out[cb.getAttribute('data-alert')] = cb.checked ? 1 : 0; });
    97     return out;
    98   }
    99   function setAlertBoxes(alerts) {
    100     alertsBox.querySelectorAll('input[data-alert]').forEach(function (cb) {
    101       cb.checked = !!alerts[cb.getAttribute('data-alert')];
    102     });
    103   }
    104 
    105   function render(sub) {
    106     currentEndpoint = sub ? sub.endpoint : null;
    107     elState.textContent = sub ? cfg.i18n.on : (Notification.permission === 'denied' ? cfg.i18n.denied : cfg.i18n.off);
    108     btnOn.hidden = !!sub || Notification.permission === 'denied';
    109     btnOff.hidden = !sub;
    110     btnTest.hidden = !sub;
    111     alertsBox.hidden = !sub;
    112   }
    113 
    114   navigator.serviceWorker.ready.then(function (reg) {
    115     return reg.pushManager.getSubscription();
    116   }).then(function (sub) {
    117     // Show this device's SAVED prefs when we know them, defaults otherwise.
    118     setAlertBoxes((sub && cfg.saved[sub.endpoint]) ? Object.assign({}, cfg.alerts, cfg.saved[sub.endpoint]) : cfg.alerts);
    119     render(sub);
    120   }).catch(function () { elState.textContent = cfg.i18n.unknown; });
    121 
    122   btnOn.addEventListener('click', function () {
    123     btnOn.disabled = true;
    124     Notification.requestPermission().then(function (perm) {
    125       if (perm !== 'granted') { btnOn.disabled = false; render(null); return; }
    126       navigator.serviceWorker.ready.then(function (reg) {
    127         return reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: b64ToU8(cfg.vapid) });
    128       }).then(function (sub) {
    129         return post('/push/subscribe', { subscription: sub.toJSON(), alerts: readAlertBoxes(), uaLabel: deviceLabel() })
    130           .then(function (r) { if (!r.ok) throw new Error('subscribe failed'); render(sub); location.reload(); });
    131       }).catch(function () { btnOn.disabled = false; elState.textContent = cfg.i18n.failed; });
    132     });
    133   });
    134 
    135   btnOff.addEventListener('click', function () {
    136     navigator.serviceWorker.ready.then(function (reg) { return reg.pushManager.getSubscription(); }).then(function (sub) {
    137       if (!sub) { render(null); return; }
    138       var ep = sub.endpoint;
    139       sub.unsubscribe().then(function () { return post('/push/unsubscribe', { endpoint: ep }); })
    140         .then(function () { location.reload(); });
    141     });
    142   });
    143 
    144   btnTest.addEventListener('click', function () {
    145     btnTest.disabled = true;
    146     post('/push/test').then(function () { setTimeout(function () { btnTest.disabled = false; }, 2000); });
    147   });
    148 
    149   alertsBox.addEventListener('change', function () {
    150     if (!currentEndpoint) return;
    151     post('/push/alerts', { endpoint: currentEndpoint, alerts: readAlertBoxes() }).then(function (r) {
    152       if (r.ok) { savedMsg.hidden = false; setTimeout(function () { savedMsg.hidden = true; }, 1500); }
    153     });
    154   });
    155 
    156   document.querySelectorAll('.np-remove').forEach(function (btn) {
    157     btn.addEventListener('click', function () {
    158       post('/push/unsubscribe', { endpoint: btn.getAttribute('data-endpoint') }).then(function () { location.reload(); });
    159     });
    160   });
    161 })();
    162 </script>
     60<%# Het script van deze pagina staat in assets/js/mod/admin-push.js (shaer-bqr). %>
    16361<% } %>
Note: See TracChangeset for help on using the changeset viewer.