(in-package #:chatikbot) (defvar *nalunch-username* nil "Username") (defvar *nalunch-password* nil "Password") (defvar *nalunch-cookie-jar* (make-instance 'drakma:cookie-jar) "Cookie storage") (defparameter +mobile-ua+ "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36" "Mobile UA") (defparameter +nalunch-mobile+ (puri:uri "https://www.nalunch.ru/Mobile/")) (defparameter +nalunch-login+ (puri:uri "https://www.nalunch.ru/Mobile/Account/Login")) (defun nalunch-auth (&optional body) (let* ((body (or body (drakma:http-request +nalunch-login+ :cookie-jar *nalunch-cookie-jar* :user-agent +mobile-ua+))) (dom (plump:parse body)) (form (plump:get-element-by-id dom "LoginForm")) (parameters (loop for input in (get-by-tag form "input") for name = (plump:get-attribute input "name") for value = (plump:get-attribute input "value") when (and name value) collect (cons name value) when (string= name "UserName") collect (cons name *nalunch-username*) when (string= name "Password") collect (cons name *nalunch-password*))) (response (drakma:http-request +nalunch-login+ :method :post :parameters parameters :cookie-jar *nalunch-cookie-jar* :user-agent +mobile-ua+))) (when (search "id=\"LoginForm\"" response) (error "Bad username or password")) response)) (defun nalunch-recent () (multiple-value-bind (body status headers uri) (drakma:http-request +nalunch-mobile+ :cookie-jar *nalunch-cookie-jar* :user-agent +mobile-ua+) (declare (ignore status headers)) (let* ((body (if (puri:uri= uri +nalunch-mobile+) body (nalunch-auth body))) (dom (plump:parse body)) (balance (parse-integer (plump:text (elt (clss:select ".newswire-header_balance" dom) 0)))) (recent (loop for day across (clss:select ".day-feed" dom) append (loop for el across (clss:select ".media" day) for date = (select-text ".day-feed_date" day) for time = (select-text ".transaction_time" el) for price = (parse-integer (select-text ".transaction_price" el)) for place = (select-text ".transaction-title" el) collect (list (cons :time (format nil "~A ~A" date time)) (cons :price price) (cons :place place)))))) (list (cons :balance balance) (cons :recent recent))))) (defun nalunch-format (result &optional last) (let* ((balance (aget :balance result)) (all (aget :recent result)) (recent (cons (car all) (unless last (cdr all))))) (format nil "🍴 Баланс ~A руб.~{~&~A~}" balance (mapcar (lambda (meal) (format nil "~A @ ~A — ~A руб." (aget :time meal) (aget :place meal) (aget :price meal))) recent))))