Skip to content

Commit

Permalink
Merge pull request #19 from platogo/feature/bulk-log
Browse files Browse the repository at this point in the history
Implement bulk time log support
  • Loading branch information
Daniils Petrovs authored Nov 3, 2023
2 parents 8ecd3df + 8ca3301 commit 9597565
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 101 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ You can also specify a day code (e.g. `wh` for a Work From Home (WFH) day):
atoss-cli log -c wh -e "17:30"
```

If you have a CSV file with your time entries, you can pass that as input too:

```bash
atoss-cli log -f stunden.csv
```

The file must be in the following format:

```csv
date,start,end,code
```

For example:

```csv
25.10.2023,10:00,18:45,wh
```

The code can be optional, just make sure you have the correct number of columns.

If you are unsure about available day codes, you can always check ATOSS manually.

To view the full list of options, call `atoss-cli -h`
Expand Down
1 change: 1 addition & 0 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:min-lein-version "2.0.0"
:dependencies [[org.clojure/clojure "1.11.1"]
[org.clojure/tools.cli "1.0.206"]
[org.clojure/data.csv "1.0.1"]
[etaoin "0.4.6"]
[com.github.pmonks/spinner "2.0.190"]
[clojure-term-colors "0.1.0"]
Expand Down
77 changes: 10 additions & 67 deletions src/atoss_cli/atoss.clj
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,6 @@
(def time-pair-row {:css "div.slick-row"})
(def add-time-pair-btn {:css "ul.z-menupopup-content > li.z-menuitem > a.z-menuitem-content:first-of-type"})

(defprotocol TimeSheetDay
(fmt-row [day]))

(defrecord Day [date
day-of-week
comment
work-pattern
booking-code
day-code
start-time
start-time-correctness
end-time
end-time-correctness
time-logged
saldo
overtime]
TimeSheetDay (fmt-row
[day]
(apply format "%5s | %3s | %4s | %3s | %2s | %3s | %5s | %1s | %5s | %1s | %5s | %5s | %5s" (vals day))))

(defn -max-row-cnt
[driver]
(-> driver
Expand All @@ -54,22 +34,6 @@
;; For example, row indexing starts with 1, with the first day being 3rd row
;; Columns indexing starts with 0, with the first col being the date

;; Monatsubersich columns

;; l0 - date
;; l1 - day of the week
;; l2 - comment
;; l3 - Arbeitsmuster
;; l4 - internal status code (V - vacation, A! - unlogged day)
;; l5 - day code (e.g. wh, empty etc.)
;; l6 - start time
;; l7 - st correctness
;; l8 - end time
;; l9 - et correctness
;; l10 - time logged per day
;; l11 - saldo
;; l12 - overtime

(defn -cell-selector
[row col]
{:css (format "div.ui-widget-content.slick-row:nth-child(%d) > div.slick-cell.l%d.r%d > span" row col col)})
Expand Down Expand Up @@ -134,17 +98,6 @@
(api/click zeitkorr-btn)
(api/wait-visible {:tag :span :fn/has-text "Tagescode"})))

(defn nav-to-month-overview
"Navigate the driver to the current month overview.
This is where every time pair can be parsed."
[driver]
(doto driver
(api/wait-visible nav-menu-btn)
(api/click nav-menu-btn)
(api/wait-visible month-overview-btn)
(api/click month-overview-btn)
(api/wait-visible {:css "div.slick-row"})))

(defn set-date
"Sets the day of the month in time correction that the time pair will be applied to."
[driver date]
Expand All @@ -153,22 +106,18 @@
(api/click date-input)
(api/wait 1)
(api/fill-active date)
(api/fill-active keys/enter)
(api/wait 2)
(api/click update-btn)
(api/wait 1)))
(api/click date-input)))

(defn create-time-pair-entry
"Create a new time entry as a combination of day code and a time pair for a given day."
[driver {day-code :day-code
start :start-time
end :end-time
verbosity :verbosity}]
(when (> verbosity 0)
(println (if (= day-code " ")
"No day code provided"
(str "Day code: " day-code))))
date :date}]

(api/click driver date-input)
(set-date driver date)
(dotimes [_i 4]
(api/fill-active driver keys/tab))
(api/wait driver 3) ;; Do not touch waiters - if it is any less, the UI will not have enough time to update
Expand All @@ -183,15 +132,9 @@
(api/fill-active keys/enter)
(api/wait 2)))

(defn parse-month-table-rows
"Parse day records from month overview. Returns a collection of Days."
[driver]
(let [first-row 3
last-row (- (-max-row-cnt driver) 3)
rows (range first-row last-row)]
(for [row rows]
(let [col-vals (for [col (range 0 13)]
(api/get-element-inner-html driver (-cell-selector row col)))
day (apply ->Day col-vals)]
day))))

(defn create-time-pair-entries
"Create time pair entries from a collection of time pairs."
[driver time-pairs]
(doseq [time-pair time-pairs]
(println "Creating time pair entry for date: " (:date time-pair))
(create-time-pair-entry driver time-pair)))
1 change: 1 addition & 0 deletions src/atoss_cli/cli.clj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Work seamlessly with ATOSS time sheets.")
:default "9:00"]
["-e" "--end-time TIME" "Work end time in the format HH:MM"
:default "17:00"]
["-f" "--file FILE" "Log times based on an input file."]
;; A non-idempotent option (:default is applied first)
["-v" nil "Verbosity level"
:id :verbosity
Expand Down
90 changes: 65 additions & 25 deletions src/atoss_cli/core.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
(ns atoss-cli.core
"Entrypoint module for the ATOSS CLI."
(:require
[clojure.java.io :as io]
[clojure.data.csv :as csv]
[clojure.tools.cli :refer [parse-opts]]
[clojure.term.colors :refer [bold green red]]
[clojure.term.colors :refer [green red]]
[progress.indeterminate :as pi]
[atoss-cli.atoss :as atoss]
[atoss-cli.config :as config]
Expand All @@ -21,25 +23,69 @@
(assoc opts :path-browser mac-chrome-path)
opts)))

(defn log-time
(defn parse-time-pair-file
"Parse a CSV file containing time pairs and return a seq of maps."
[file-path]
(let [lines (-> file-path
io/reader
csv/read-csv)]
(try (->> lines
(filter #(> (count %) 1))
(map #(let [[date start-time end-time day-code] %]
{:date date
:start-time start-time
:end-time end-time
:day-code day-code}))
(doall))
(catch Exception e
(println (red "Error parsing time pair file: " (.getMessage e)))
(shutdown-agents)))))

(defn log-time-single
"Log a time pair for a given date."
[{opts :options}]
(let [driver (atoss/setup-driver (-maybe-inject-mac-chrome-path {:headless true}))
config (config/load-in)
{date :date} opts
session-opts (merge opts config)]
(try
(println (green "Logging time..."))
(pi/animate!
(doto driver
(atoss/login session-opts)
(atoss/nav-to-time-correction)
(atoss/set-date date)
(atoss/create-time-pair-entry session-opts)
(atoss/logout session-opts)
(atoss/end))
(pi/print
(green "Logged time for date: " date))
(green "Logged time for date: " (:date opts)))
(shutdown-agents))

(catch Exception e
(-> e
(.getMessage)
(red)
(println))
(atoss/end driver)))))

(defn log-time-col
"Log a collection of time pairs."
[{opts :options}]
(let [driver (atoss/setup-driver (-maybe-inject-mac-chrome-path {:headless true}))
config (config/load-in)
session-opts (merge opts config)
{file :file} opts
time-pairs (parse-time-pair-file file)]
(try
(println (green "Logging time from file " file))
(pi/animate!
(doto driver
(atoss/login session-opts)
(atoss/nav-to-time-correction)
(atoss/create-time-pair-entries time-pairs)
(atoss/logout session-opts)
(atoss/end))
(pi/print
(green "Logged time from file " file))
(shutdown-agents))

(catch Exception e
Expand All @@ -55,35 +101,29 @@
(let [config (config/load-in)]
(atoss/browse config)))

;; FIXME: very brittle so disabled for now
(defn show-month-overview
"Display the current month overview in the terminal."
[{opts :options}]
(let [driver (atoss/setup-driver)
config (config/load-in)]
(doto driver
(atoss/login (merge opts config))
(atoss/nav-to-month-overview))
(let [days (atoss/parse-month-table-rows driver)]
(println (bold "Month overview:"))
(newline)
(doseq [day days]
(-> day
(atoss/fmt-row)
(println))))))
(defn -config-cmd [args]
(let [[_cmd subcmd k v] args]
(cond
(= subcmd "init") (config/init)
(= subcmd "set") (config/set-val (keyword k) v)
:else (println "Unknown config command"))))

(defn -log-cmd [{options :options :as opts}]
(cond
(options :file) (log-time-col opts)
:else (log-time-single opts)))

(defn -main [& args]
(let [{^Collection arguments :arguments
summary :summary,
options :options,
:as opts} (parse-opts args cli/options)
[cmd subcmd k v] arguments]
[cmd _subcmd] arguments]
(cond
(options :version) (cli/print-project-ver)
(options :help) (cli/print-help summary)
(= cmd "log") (log-time opts)
(= cmd "log") (-log-cmd opts)
(= cmd "web") (web)
(and (= cmd "config") (= subcmd "init")) (config/init)
(and (= cmd "config") (= subcmd "set")) (config/set-val (keyword k) v)
(= cmd "config") (-config-cmd arguments)
:else (cli/print-help summary))
(flush)))
9 changes: 0 additions & 9 deletions test/atoss_cli/atoss_test.clj

This file was deleted.

0 comments on commit 9597565

Please sign in to comment.