Sfoglia il codice sorgente

tweak: use timestamps to track notif awks

KernelDeimos 11 mesi fa
parent
commit
ef8f4de962

+ 16 - 8
packages/backend/src/om/entitystorage/NotificationES.js

@@ -16,22 +16,30 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
-const { Eq } = require("../query/query");
+const { Eq, IsNotNull } = require("../query/query");
 const { BaseES } = require("./BaseES");
 
 class NotificationES extends BaseES {
     static METHODS = {
         async create_predicate (id) {
-            if ( id === 'unread' ) {
+            if ( id === 'unseen' ) {
                 return new Eq({
-                    key: 'read',
-                    value: 0,
-                });
+                    key: 'shown',
+                    value: null,
+                }).and(new Eq({
+                    key: 'awknowledged',
+                    value: null,
+                }));
             }
-            if ( id === 'read' ) {
+            if ( id === 'unawknowledged' ) {
                 return new Eq({
-                    key: 'read',
-                    value: 1,
+                    key: 'awknowledged',
+                    value: null,
+                });
+            }
+            if ( id === 'awknowledged' ) {
+                return new IsNotNull({
+                    key: 'awknowledged',
                 });
             }
         },

+ 18 - 2
packages/backend/src/om/entitystorage/SQLES.js

@@ -22,7 +22,7 @@ const { BaseES } = require("./BaseES");
 const APIError = require("../../api/APIError");
 const { Entity } = require("./Entity");
 const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait");
-const { And, Or, Eq, Like, Null, Predicate, PredicateUtil } = require("../query/query");
+const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull } = require("../query/query");
 const { DB_WRITE } = require("../../services/database/consts");
 
 class RawCondition extends AdvancedBase {
@@ -350,7 +350,23 @@ class SQLES extends BaseES {
                 const options = prop.descriptor.sql ?? {};
                 const col_name = options.column_name ?? prop.name;
 
-                const sql = `${col_name} = ?`;
+                const sql = value === null ? `${col_name} IS NULL` : `${col_name} = ?`;
+                const values = value === null ? [] : [value];
+
+                return new RawCondition({ sql, values });
+            }
+
+            if ( om_query instanceof IsNotNull ) {
+                const key = om_query.key;
+                let value = om_query.value;
+                const prop = this.om.properties[key];
+
+                value = await prop.sql_reference(value);
+
+                const options = prop.descriptor.sql ?? {};
+                const col_name = options.column_name ?? prop.name;
+
+                const sql = `${col_name} IS NOT NULL`;
                 const values = [value];
 
                 return new RawCondition({ sql, values });

+ 7 - 0
packages/backend/src/om/query/query.js

@@ -50,6 +50,12 @@ class Eq extends Predicate {
     }
 }
 
+class IsNotNull extends Predicate {
+    async check (entity) {
+        return (await entity.get(this.key)) !== null;
+    }
+}
+
 class Like extends Predicate {
     async check (entity) {
         // Convert SQL LIKE pattern to RegExp
@@ -114,5 +120,6 @@ module.exports = {
     And,
     Or,
     Eq,
+    IsNotNull,
     Like,
 };

+ 26 - 23
packages/backend/src/services/NotificationService.js

@@ -41,36 +41,39 @@ class NotificationService extends BaseService {
         
         router.use(auth2);
         
-        Endpoint({
-            route: '/mark-read',
-            methods: ['POST'],
-            handler: async (req, res) => {
-                // TODO: validate uid
-                if ( typeof req.body.uid !== 'string' ) {
-                    throw APIError.create('field_invalid', null, {
-                        key: 'uid',
-                        expected: 'a valid UUID',
-                        got: 'non-string value'
-                    })
+        [['awk','awknowledged'],['read','read']].forEach(([ep_name, col_name]) => {
+            Endpoint({
+                route: '/mark-' + ep_name,
+                methods: ['POST'],
+                handler: async (req, res) => {
+                    // TODO: validate uid
+                    if ( typeof req.body.uid !== 'string' ) {
+                        throw APIError.create('field_invalid', null, {
+                            key: 'uid',
+                            expected: 'a valid UUID',
+                            got: 'non-string value'
+                        })
+                    }
+                    
+                    const awk_ts = Math.floor(Date.now() / 1000);
+                    await this.db.write(
+                        'UPDATE `notification` SET ' + col_name + ' = ? ' +
+                        'WHERE uid = ? AND user_id = ? ' +
+                        'LIMIT 1',
+                        [awk_ts, req.body.uid, req.user.id],
+                    );
+                    
+                    res.json({});
                 }
-                
-                await this.db.write(
-                    'UPDATE `notification` SET read=1 ' +
-                    'WHERE uid = ? AND user_id = ? ' +
-                    'LIMIT 1',
-                    [req.body.uid, req.user.id],
-                );
-                
-                res.json({});
-            }
-        }).attach(router);
+            }).attach(router);
+        });
     }
     
     async on_user_connected ({ user }) {
         // query the users unread notifications
         const notifications = await this.db.read(
             'SELECT * FROM `notification` ' +
-            'WHERE user_id=? AND read=0 ' +
+            'WHERE user_id=? AND shown IS NULL AND awknowledged IS NULL ' +
             'ORDER BY created_at ASC',
             [user.id]
         );

+ 2 - 1
packages/backend/src/services/database/sqlite_setup/0011_notification.sql

@@ -3,6 +3,7 @@ CREATE TABLE `notification` (
     `user_id` INTEGER NOT NULL,
     `uid` TEXT NOT NULL UNIQUE,
     `value` JSON NOT NULL,
-    `read` tinyint(1) DEFAULT '0',
+    `awknowledged` INTEGER DEFAULT NULL,
+    `shown` INTEGER DEFAULT NULL,
     `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
 );