ソースを参照

Foursquare settings in db

Innokenty Enikeev 10 年 前
コミット
1e23858fe2
3 ファイル変更58 行追加31 行削除
  1. 14 20
      chatikbot.lisp
  2. 44 4
      db.lisp
  3. 0 7
      foursquare.lisp

+ 14 - 20
chatikbot.lisp

@@ -245,9 +245,6 @@
 
 
 ;; Foursquare
-(defvar *fsq-send-to* (make-hash-table)
-  "Hash of chat-id's to fsq users list to send checkings to")
-
 (defun fsq-user-name (user)
   (when user
     (format nil "~@[~A~]~@[ ~A~]"
@@ -257,7 +254,7 @@
 (defun handle-cmd-post-checkins (chat-id message-id args)
   (log:info "handle-cmd-post-checkins" chat-id message-id args)
   (handler-case
-      (let ((users (gethash chat-id *fsq-send-to*))
+      (let ((users (db-fsq-get-chat-users chat-id))
             (friends (fsq-fetch-friends)))
         (if (null args)
             (telegram-send-message chat-id
@@ -283,8 +280,7 @@
                         (progn
                           (push user users)
                           (telegram-send-message chat-id (format nil "Теперь палим ~A" username)))))))
-              (setf (gethash chat-id *fsq-send-to*) users)
-              (save-settings))))
+              (db-fsq-set-chat-users chat-id users))))
     (error (e)
       (log:error e)
       (telegram-send-message chat-id "Ошибочка вышла"))))
@@ -292,7 +288,7 @@
 (defun handle-cmd-fsq-friends (chat-id message-id args)
   (log:info "handle-cmd-fsq-friends" chat-id message-id args)
   (handler-case
-      (let ((users (gethash chat-id *fsq-send-to*))
+      (let ((users (db-fsq-get-chat-users chat-id))
             (friends (fsq-fetch-friends)))
         (telegram-send-message
          chat-id
@@ -309,7 +305,7 @@
 (defun handle-cmd-checkins (chat-id message-id args)
   (log:info "handle-cmd-checkins" chat-id message-id args)
   (handler-case
-      (let ((users (gethash chat-id *fsq-send-to*)))
+      (let ((users (db-fsq-get-chat-users chat-id)))
         (when users
           (telegram-send-message
            chat-id
@@ -320,20 +316,19 @@
     (error (e) (log:error e))))
 
 
-(defvar *fsq-seen-ids* nil "Ids of seen checkins")
-
 (defun process-latest-checkins ()
   (handler-case
-      (let ((checkins (make-hash-table)))
-        (dolist (checkin (fsq-fetch-new-checkins))
+      (let ((checkins (make-hash-table))
+            (ts (princ-to-string (1+ (or (db-fsq-last-created) -1)))))
+        (dolist (checkin (fsq-fetch-checkins ts))
           (let ((id (aget "id" checkin))
+                (created-at (aget "createdAt" checkin))
                 (user (aget "id" (aget "user" checkin))))
-            (unless (find id *fsq-seen-ids* :test #'equal)
-              (loop for chat-id being the hash-keys in *fsq-send-to* using (hash-value users)
-                 do (when (member user users :test #'equal)
-                      (push (fsq-format-checkin checkin)
-                            (gethash chat-id checkins))))
-              (push id *fsq-seen-ids*))))
+            (unless (db-fsq-has-seen id)
+              (dolist (chat-id (db-fsq-get-user-chats user))
+                (push (fsq-format-checkin checkin)
+                      (gethash chat-id checkins)))
+              (db-fsq-add-seen id created-at))))
         (loop for chat-id being the hash-keys in checkins using (hash-value texts)
            do (log:info "Sending checkins" chat-id texts)
              (telegram-send-message chat-id (format nil "~{~A~^~%~}" texts))))
@@ -453,8 +448,7 @@
                        :if-does-not-exist :create)
       (write '(in-package #:chatikbot) :stream s)
       (write
-       `(setf *fsq-send-to* (alexandria:alist-hash-table ',(alexandria:hash-table-alist *fsq-send-to*))
-              *chat-locations* ',*chat-locations*
+       `(setf *chat-locations* ',*chat-locations*
               *akb-send-to* ',*akb-send-to*
               *akb-last-id* ,*akb-last-id*
               *rss-chat-feeds* (%load-rss-feeds ',(%save-rss-feeds)))

+ 44 - 4
db.lisp

@@ -7,12 +7,25 @@
                    (asdf:component-pathname
                     (asdf:find-system '#:chatikbot))))
 
+(defmacro with-db ((db) &body body)
+  `(sqlite:with-open-database (,db (db-path) :busy-timeout 10)
+     ,@body))
+
 (defun db-init ()
-  (unless (probe-file (db-path))
-    (sqlite:with-open-database (db (db-path))
-      (sqlite:execute-non-query db "create table finance (ts, usd, eur, gbp, brent)")
-      (sqlite:execute-non-query db "create index fin_ts_ids on finance (ts)"))))
+  (sqlite:with-open-database (db (db-path))
+    ;; Finance
+    (sqlite:execute-non-query db "create table if not exists finance (ts, usd, eur, gbp, brent)")
+    (sqlite:execute-non-query db "create index if not exists fin_ts_ids on finance (ts)")
+
+    ;; Foursquare
+    (sqlite:execute-non-query db "create table if not exists fsq_chat_users (chat_id, user_id)")
+    (sqlite:execute-non-query db "create index if not exists fsq_chat_users_chat_idx on fsq_chat_users (chat_id)")
+    (sqlite:execute-non-query db "create index if not exists fsq_chat_users_user_idx on fsq_chat_users (user_id)")
 
+    (sqlite:execute-non-query db "create table if not exists fsq_seen (id, created_at)")
+    (sqlite:execute-non-query db "create index if not exists fsq_seen_idx on fsq_seen (id)")))
+
+;; Finance
 (defun db-add-finance (ts usd eur gbp brent)
   (sqlite:with-open-database (db (db-path) :busy-timeout 10)
     (sqlite:execute-non-query db "insert into finance (ts, usd, eur, gbp, brent) values (?, ?, ?, ?, ?)"
@@ -43,3 +56,30 @@
          collect (%finance-alist statement)
          finally (sqlite:finalize-statement statement)))))
 
+;; Foursquare
+(defun db-fsq-get-chat-users (chat-id)
+  (flatten (with-db (db)
+             (sqlite:execute-to-list db "select user_id from fsq_chat_users where chat_id = ?" chat-id))))
+
+(defun db-fsq-get-user-chats (user-id)
+  (flatten (with-db (db)
+             (sqlite:execute-to-list db "select chat_id from fsq_chat_users where user_id = ?" user-id))))
+
+(defun db-fsq-set-chat-users (chat-id users)
+  (with-db (db)
+    (sqlite:with-transaction db
+      (sqlite:execute-non-query db "delete from fsq_chat_users where chat_id = ?" chat-id)
+      (dolist (user-id users)
+        (sqlite:execute-non-query db "insert into fsq_chat_users (chat_id, user_id) values (?, ?)" chat-id user-id)))))
+
+(defun db-fsq-add-seen (id created-at)
+  (with-db (db)
+    (sqlite:execute-non-query db "insert into fsq_seen (id, created_at) values (?, ?)" id created-at)))
+
+(defun db-fsq-has-seen (id)
+  (with-db (db)
+    (sqlite:execute-single db "select id from fsq_seen where id = ? limit 1" id)))
+
+(defun db-fsq-last-created ()
+  (with-db (db)
+    (sqlite:execute-single db "select created_at from fsq_seen order by created_at desc limit 1")))

+ 0 - 7
foursquare.lisp

@@ -6,7 +6,6 @@
   "Foursquare API URL")
 
 (defvar *fsq-access-token* nil "Access token for a user under which the process is run")
-(defvar *fsq-last-timestamp* nil "Timestamp of the last checkin. To only fetch latest")
 
 (defun %fsq-api-call (method &optional params)
   (let* ((resp
@@ -30,12 +29,6 @@
                        (list (cons "afterTimestamp" (or after-timestamp "0"))
                              (cons "limit" (or limit "20"))))))
 
-(defun fsq-fetch-new-checkins ()
-  (let ((recent (fsq-fetch-checkins *fsq-last-timestamp*)))
-    (when (first recent)
-      (setf *fsq-last-timestamp* (princ-to-string (1+ (aget "createdAt" (first recent))))))
-    recent))
-
 (defun fsq-fetch-friends (&optional offset)
   (list*
    (aget "user" (%fsq-api-call "users/self"))