Ver código fonte

refactor(core): check notification permission on the Rust endpoint [TRI-017] (#23)

Lucas Nogueira 3 anos atrás
pai
commit
239bba5666

+ 5 - 0
.changes/refactor-notification-permission-check.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+The notification endpoint now checks for the permission flag and requests if the value is not set.

+ 14 - 20
core/tauri/scripts/core.js

@@ -210,26 +210,20 @@
       Object.freeze(options)
     }
 
-    isPermissionGranted().then(function (permission) {
-      if (permission) {
-        return window.__TAURI_INVOKE__(
-          'tauri',
-          {
-            __tauriModule: 'Notification',
-            message: {
-              cmd: 'notification',
-              options:
-                typeof options === 'string'
-                  ? {
-                      title: options
-                    }
-                  : options
-            }
-          },
-          _KEY_VALUE_
-        )
-      }
-    })
+    return window.__TAURI_INVOKE__(
+      'tauri', {
+        __tauriModule: 'Notification',
+        message: {
+          cmd: 'notification',
+          options: typeof options === 'string' ?
+            {
+              title: options
+            } :
+            options
+        }
+      },
+      _KEY_VALUE_
+    )
   }
 
   window.Notification = function (title, options) {

+ 52 - 39
core/tauri/src/endpoints/notification.rs

@@ -45,6 +45,13 @@ impl Cmd {
     context: InvokeContext<R>,
     options: NotificationOptions,
   ) -> crate::Result<()> {
+    let allowed = match is_permission_granted(&context) {
+      Some(p) => p,
+      None => request_permission(&context),
+    };
+    if !allowed {
+      return Err(crate::Error::NotificationNotAllowed);
+    }
     let mut notification =
       Notification::new(context.config.tauri.bundle.identifier.clone()).title(options.title);
     if let Some(body) = options.body {
@@ -61,39 +68,7 @@ impl Cmd {
   fn request_notification_permission<R: Runtime>(
     context: InvokeContext<R>,
   ) -> crate::Result<&'static str> {
-    let mut settings = crate::settings::read_settings(
-      &context.config,
-      &context.package_info,
-      context.window.state::<Env>().inner(),
-    );
-    if let Some(allow_notification) = settings.allow_notification {
-      return Ok(if allow_notification {
-        PERMISSION_GRANTED
-      } else {
-        PERMISSION_DENIED
-      });
-    }
-    let (tx, rx) = std::sync::mpsc::channel();
-    crate::api::dialog::ask(
-      Some(&context.window),
-      "Permissions",
-      "This app wants to show notifications. Do you allow?",
-      move |answer| {
-        tx.send(answer).unwrap();
-      },
-    );
-
-    let answer = rx.recv().unwrap();
-
-    settings.allow_notification = Some(answer);
-    crate::settings::write_settings(
-      &context.config,
-      &context.package_info,
-      context.window.state::<Env>().inner(),
-      settings,
-    )?;
-
-    if answer {
+    if request_permission(&context) {
       Ok(PERMISSION_GRANTED)
     } else {
       Ok(PERMISSION_DENIED)
@@ -111,12 +86,7 @@ impl Cmd {
   fn is_notification_permission_granted<R: Runtime>(
     context: InvokeContext<R>,
   ) -> crate::Result<Option<bool>> {
-    let settings = crate::settings::read_settings(
-      &context.config,
-      &context.package_info,
-      context.window.state::<Env>().inner(),
-    );
-    if let Some(allow_notification) = settings.allow_notification {
+    if let Some(allow_notification) = is_permission_granted(&context) {
       Ok(Some(allow_notification))
     } else {
       Ok(None)
@@ -130,3 +100,46 @@ impl Cmd {
     Ok(Some(false))
   }
 }
+
+#[cfg(notification_all)]
+fn request_permission<R: Runtime>(context: &InvokeContext<R>) -> bool {
+  let mut settings = crate::settings::read_settings(
+    &context.config,
+    &context.package_info,
+    context.window.state::<Env>().inner(),
+  );
+  if let Some(allow_notification) = settings.allow_notification {
+    return allow_notification;
+  }
+  let (tx, rx) = std::sync::mpsc::channel();
+  crate::api::dialog::ask(
+    Some(&context.window),
+    "Permissions",
+    "This app wants to show notifications. Do you allow?",
+    move |answer| {
+      tx.send(answer).unwrap();
+    },
+  );
+
+  let answer = rx.recv().unwrap();
+
+  settings.allow_notification = Some(answer);
+  let _ = crate::settings::write_settings(
+    &context.config,
+    &context.package_info,
+    context.window.state::<Env>().inner(),
+    settings,
+  );
+
+  answer
+}
+
+#[cfg(notification_all)]
+fn is_permission_granted<R: Runtime>(context: &InvokeContext<R>) -> Option<bool> {
+  crate::settings::read_settings(
+    &context.config,
+    &context.package_info,
+    context.window.state::<Env>().inner(),
+  )
+  .allow_notification
+}

+ 3 - 0
core/tauri/src/error.rs

@@ -84,6 +84,9 @@ pub enum Error {
   /// Path not allowed by the scope.
   #[error("path not allowed on the configured scope: {0}")]
   PathNotAllowed(PathBuf),
+  /// The user did not allow sending notifications.
+  #[error("sending notification was not allowed by the user")]
+  NotificationNotAllowed,
 }
 
 impl From<serde_json::Error> for Error {

+ 4 - 1
examples/api/src/components/Notifications.svelte

@@ -1,12 +1,15 @@
 <script>
   export let onMessage;
 
+  // send the notification directly
+  // the backend is responsible for checking the permission
   function _sendNotification() {
     new Notification("Notification title", {
       body: "This is the notification body",
     });
   }
 
+  // alternatively, check the permission ourselves
   function sendNotification() {
     if (Notification.permission === "default") {
       Notification.requestPermission()
@@ -26,6 +29,6 @@
   }
 </script>
 
-<button class="button" id="notification" on:click={sendNotification}>
+<button class="button" id="notification" on:click={_sendNotification}>
   Send test notification
 </button>