mirror of
https://github.com/mruwnik/invoices.git
synced 2025-06-08 21:34:44 +02:00
Get worklogs from emails
This commit is contained in:
parent
b67a6138a0
commit
c7c0dc92d7
@ -6,6 +6,8 @@
|
|||||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||||
[org.clojure/tools.cli "0.4.2"]
|
[org.clojure/tools.cli "0.4.2"]
|
||||||
[com.draines/postal "2.0.3"]
|
[com.draines/postal "2.0.3"]
|
||||||
|
[io.forward/clojure-mail "1.0.8"]
|
||||||
|
[commons-net "3.6"]
|
||||||
[clj-http "3.10.0"]
|
[clj-http "3.10.0"]
|
||||||
[cheshire "5.9.0"]
|
[cheshire "5.9.0"]
|
||||||
[clj-pdf "2.4.0"]]
|
[clj-pdf "2.4.0"]]
|
||||||
|
@ -1,30 +1,18 @@
|
|||||||
(ns invoices.core
|
(ns invoices.core
|
||||||
(:require [invoices.pdf :as pdf]
|
(:require [invoices.pdf :as pdf]
|
||||||
[invoices.settings :refer [invoices]]
|
[invoices.settings :refer [invoices]]
|
||||||
[invoices.jira :refer [prev-timesheet]]
|
[invoices.timesheets :refer [prev-timesheet]]
|
||||||
[invoices.time :refer [prev-month last-working-day date-applies?]]
|
[invoices.time :refer [prev-month last-working-day date-applies?]]
|
||||||
[invoices.calc :refer [set-price]]
|
[invoices.calc :refer [set-price]]
|
||||||
|
[invoices.email :refer [send-email]]
|
||||||
[clojure.tools.cli :refer [parse-opts]]
|
[clojure.tools.cli :refer [parse-opts]]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clojure.java.shell :refer [sh]]
|
[clojure.java.shell :refer [sh]])
|
||||||
[postal.core :refer [send-message]])
|
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
(defn invoice-number [when number]
|
(defn invoice-number [when number]
|
||||||
(->> [(or number 1) (-> when .getMonthValue) (-> when .getYear)] (map str) (str/join "/")))
|
(->> [(or number 1) (-> when .getMonthValue) (-> when .getYear)] (map str) (str/join "/")))
|
||||||
|
|
||||||
(defn send-email [to from {smtp :smtp} invoice]
|
|
||||||
(when (not-any? nil? [to from smtp invoice])
|
|
||||||
(->>
|
|
||||||
(send-message smtp {:from from
|
|
||||||
:to [to]
|
|
||||||
:subject invoice
|
|
||||||
:body [{:type :attachment
|
|
||||||
:content (java.io.File. (str invoice ".pdf"))
|
|
||||||
:content-type "application/pdf"}]})
|
|
||||||
:error (= :SUCCESS)
|
|
||||||
(println " - email sent: "))))
|
|
||||||
|
|
||||||
(defn run-callback [file callback]
|
(defn run-callback [file callback]
|
||||||
(let [command (concat callback [file])
|
(let [command (concat callback [file])
|
||||||
str-command (str/join " " command)
|
str-command (str/join " " command)
|
||||||
|
74
src/invoices/email.clj
Normal file
74
src/invoices/email.clj
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
(ns invoices.email
|
||||||
|
(:require [clojure.string :as str]
|
||||||
|
[invoices.time :as time]
|
||||||
|
[postal.core :refer [send-message]]
|
||||||
|
[clojure-mail.core :as mail]
|
||||||
|
[clojure-mail.gmail :as gmail]
|
||||||
|
[clojure-mail.folder :as folder]
|
||||||
|
[clojure-mail.message :refer (read-message) :as mess]))
|
||||||
|
|
||||||
|
(defn send-email [to from {smtp :smtp} invoice]
|
||||||
|
(when (not-any? nil? [to from smtp invoice])
|
||||||
|
(->>
|
||||||
|
(send-message smtp {:from from
|
||||||
|
:to [to]
|
||||||
|
:subject invoice
|
||||||
|
:body [{:type :attachment
|
||||||
|
:content (java.io.File. (str invoice ".pdf"))
|
||||||
|
:content-type "application/pdf"}]})
|
||||||
|
:error (= :SUCCESS)
|
||||||
|
(println " - email sent: "))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn server-find-messages
|
||||||
|
"Find all messages in the given folder, filtering them by subject and sender (use nil to ignore)."
|
||||||
|
[client folder subject from]
|
||||||
|
(->>
|
||||||
|
{:subject subject :from from}
|
||||||
|
(remove (comp nil? second))
|
||||||
|
flatten
|
||||||
|
(apply folder/search (mail/open-folder client folder :readonly))
|
||||||
|
(into [])))
|
||||||
|
|
||||||
|
(defn manual-find-messages
|
||||||
|
"Find all messages in the given folder, filtering them by subject and sender (use nil to ignore).
|
||||||
|
|
||||||
|
WARNING: This can be very slow, as it fetches each message seperately.
|
||||||
|
"
|
||||||
|
[client folder subject from]
|
||||||
|
(let [subjecter (if subject #(str/includes? (mess/subject %) subject) identity)
|
||||||
|
fromer (if from #(str/includes? (-> % mess/from first :address) from) identity)]
|
||||||
|
(filter
|
||||||
|
#(and (subjecter %) (fromer %))
|
||||||
|
(mail/all-messages client folder))))
|
||||||
|
|
||||||
|
(defn find-messages
|
||||||
|
"Get all messages for the given month from the given imap server."
|
||||||
|
[month
|
||||||
|
{imap :host user :user password :pass try-manual :try-manual folder :folder from :from subject :subject}]
|
||||||
|
(let [client (mail/store "imaps" imap user password)
|
||||||
|
subject (time/format-month subject month)
|
||||||
|
messages (server-find-messages client folder subject from)]
|
||||||
|
(if (and (empty? messages) try-manual)
|
||||||
|
(manual-find-messages client folder subject from)
|
||||||
|
messages)))
|
||||||
|
|
||||||
|
(defn split-cells [content]
|
||||||
|
(->> content
|
||||||
|
str/split-lines
|
||||||
|
(remove str/blank?)
|
||||||
|
(map #(str/split % #"[\s;]"))))
|
||||||
|
|
||||||
|
(defn zip-item [headers cell]
|
||||||
|
(into (sorted-map) (map vector headers cell)))
|
||||||
|
|
||||||
|
(defn extract-items [headers message]
|
||||||
|
(->> message
|
||||||
|
mess/get-content
|
||||||
|
split-cells
|
||||||
|
(map (partial zip-item headers))))
|
||||||
|
|
||||||
|
(defn get-worklogs
|
||||||
|
"Get all worklogs for the given month from the given imap server."
|
||||||
|
[month imap]
|
||||||
|
(->> imap (find-messages month) (map (partial extract-items (:headers imap))) flatten))
|
@ -1,4 +1,5 @@
|
|||||||
(ns invoices.time)
|
(ns invoices.time
|
||||||
|
(:require [clojure.string :as str]))
|
||||||
|
|
||||||
|
|
||||||
(defn last-day
|
(defn last-day
|
||||||
@ -25,3 +26,6 @@
|
|||||||
[date {to :to from :from}]
|
[date {to :to from :from}]
|
||||||
(and (or (nil? to) (-> date .toString (compare to) (< 0)))
|
(and (or (nil? to) (-> date .toString (compare to) (< 0)))
|
||||||
(or (nil? from) (-> date .toString (compare from) (>= 0)))))
|
(or (nil? from) (-> date .toString (compare from) (>= 0)))))
|
||||||
|
|
||||||
|
(defn format-month [formatter month]
|
||||||
|
(->> formatter (java.time.format.DateTimeFormatter/ofPattern) (.format month)))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(ns invoices.jira
|
(ns invoices.timesheets
|
||||||
(:require [clj-http.client :as client]
|
(:require [clj-http.client :as client]
|
||||||
[invoices.time :refer [last-day prev-month]]))
|
[invoices.time :refer [last-day prev-month]]))
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user