Kaynağa Gözat

Foursquare checkins

Innokenty Enikeev 10 yıl önce
ebeveyn
işleme
683713af3e
4 değiştirilmiş dosya ile 94 ekleme ve 5 silme
  1. 1 0
      chatikbot.asd
  2. 45 2
      chatikbot.lisp
  3. 2 3
      config.lisp.example
  4. 46 0
      foursquare.lisp

+ 1 - 0
chatikbot.asd

@@ -8,6 +8,7 @@
 ;;               #:cl-oauth
                #:clon
                #:dexador
+               #:drakma
                #:flexi-streams
                #:local-time
                #:log4cl

+ 45 - 2
chatikbot.lisp

@@ -67,6 +67,7 @@
               (:hourly (handle-cmd-weather chat-id id '("hourly")))
               (:daily (handle-cmd-weather chat-id id '("daily")))
               (:rates (handle-cmd-rates chat-id id args))
+              (:postcheckins (handle-cmd-post-checkins chat-id id args))
               (otherwise (handle-admin-cmd chat-id text cmd args))))
           (send-dont-understand chat-id (preprocess-input text))))
     (when location
@@ -103,6 +104,8 @@
         (otherwise (send-dont-understand chat-id (preprocess-input (subseq text 1)))))
       (send-dont-understand chat-id (preprocess-input (subseq text 1)))))
 
+
+;; AKB
 (defparameter +akb-vk-domain+ "baneks" "VK.com username of 'B-category anekdotes'")
 (defvar *akb-send-to* nil "List of chat-id's to send AKBs to")
 
@@ -161,13 +164,14 @@
       (log:error e)
       (telegram-send-message chat-id "Ошибочка вышла"))))
 
-
+;; Finance
 (defun handle-cmd-rates (chat-id message-id args)
   (log:info "handle-cmd-rates" chat-id message-id args)
   (let ((rates (get-rates)))
     (telegram-send-message chat-id
 			   (format nil "Зеленый ~A, гейро ~A, британец ~A" (cdar rates) (cdadr rates) (cdaddr rates)))))
 
+;; Weather
 (defun handle-cmd-weather (chat-id message-id args)
   (log:info "handle-cmd-weather" chat-id message-id args)
   (let ((location (cdr (assoc chat-id *chat-locations*))))
@@ -183,7 +187,40 @@
 	   (error (e)
 	     (log:error e)
 	     "Ошибочка вышла"))
-         "Так а ты чьих будешь?"))))
+     "Так а ты чьих будешь?"))))
+
+
+;; Foursquare
+(defvar *fsq-send-to* (make-hash-table)
+  "Hash of chat-id's to fsq users list to send checkings to")
+
+(defun handle-cmd-post-checkins (chat-id message-id args)
+  (log:info "handle-cmd-post-checkins" chat-id message-id args)
+  (let ((users (gethash chat-id *fsq-send-to*)))
+    (if (null args)
+        (telegram-send-message chat-id
+                               (if (null users)
+                                   "Пока никого не палим"
+                                   (format nil "Палим ~{~A~^, ~}" users)))
+        (progn
+          (dolist (user args)
+            (if (member user users :test #'equal)
+                (progn
+                  (setf users (remove user users :test #'equal))
+                  (telegram-send-message chat-id (format nil "Больше не палим ~A" user)))
+                (progn
+                  (push user users)
+                  (telegram-send-message chat-id (format nil "Теперь палим ~A" user)))))
+          (setf (gethash chat-id *fsq-send-to*) users)))))
+
+(defun process-latest-checkins ()
+  (handler-case
+      (dolist (checkin (fsq-fetch-new-checkins))
+        (let ((user (aget "id" (aget "user" checkin))))
+          (loop for chat-id being the hash-keys in *fsq-send-to* using (hash-value users)
+             do (when (member user users :test #'equal)
+                  (telegram-send-message chat-id (fsq-format-checkin checkin))))))
+    (error (e) (log:error e))))
 
 
 (defun start ()
@@ -200,6 +237,12 @@
     (clon:make-typed-cron-schedule :minute '* :hour '*)
     :allow-now-p t)
    :thread t)
+  (clon:schedule-function
+   (lambda () (process-latest-checkins))
+   (clon:make-scheduler
+    (clon:make-typed-cron-schedule :minute '* :hour '*)
+    :allow-now-p t)
+   :thread t)
   (bordeaux-threads:make-thread
    (lambda ()
      (in-package #:chatikbot)

+ 2 - 3
config.lisp.example

@@ -6,9 +6,8 @@
 ;; Forecast.io
 (setf *forecast-api-key* "<forecast-key>")
 
-;; Tits tumblr
-(setf *tumblr-roll* '("http://boobs-selfshots.tumblr.com"
-                      "http://bbt12.tumblr.com"))
+;; Foursquare
+(setf *fsq-access-token* "<foursquare-token>")
 
 ;; Admins
 (setf *admins* '(<user-id> <user-id>))

+ 46 - 0
foursquare.lisp

@@ -0,0 +1,46 @@
+(in-package #:chatikbot)
+
+(defparameter *fsq-checkins-url* "https://api.foursquare.com/v2/checkins/recent"
+  "URL of recent checkins API")
+
+(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-fetch-checkins (&optional after-timestamp)
+  (let* ((resp
+          (yason:parse
+           (flexi-streams:octets-to-string
+            (handler-case
+                (bordeaux-threads:with-timeout (5)
+                  (drakma:http-request
+                   *fsq-checkins-url*
+                   :parameters
+                   (list
+                    (cons "oauth_token" *fsq-access-token*)
+                    (cons "afterTimestamp" (or after-timestamp "0"))
+                    (cons "v" "20150811"))))
+              (bordeaux-threads:timeout (e)
+                (declare (ignore e))
+                (error "Timeout")))
+            :external-format :utf-8)
+           :object-as :alist))
+         (meta (aget "meta" resp)))
+    (when (not (= 200 (aget "code" meta)))
+      (error (format nil "Foursquare API error, code ~A, errorType '~A', errorDetail '~A'"
+                     (aget "code" meta) (aget "errorType" meta) (aget "errorDetail" meta))))    
+    (aget "recent" (aget "response" resp))))
+
+(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-format-checkin (checkin)
+  (when checkin
+    (let ((user (aget "user" checkin))
+          (venue (aget "venue" checkin)))
+      (format nil "📍 ~@[~A~]~@[ ~A~]~@[ в ~A~]~@[ (~A)~]~@[ 📢~A~]"
+              (aget "firstName" user) (aget "lastName" user)
+              (aget "name" venue) (first (aget "formattedAddress" (aget "location" venue)))
+              (aget "shout" checkin)))))