Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: notebooks for hours conversion #17

Merged
merged 27 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
98eff71
feat(devcontainer): setup for jupyter notebooks
thekaveman Apr 5, 2024
dde5e33
chore(data): add sample harvest export data
thekaveman Apr 5, 2024
0c754c5
feat(harvest): setup notebook for toggl conversion
thekaveman Apr 5, 2024
7e90102
feat(harvest): simple column updates/conversions
thekaveman Apr 5, 2024
51d917d
feat(harvest): add billable static column
thekaveman Apr 15, 2024
d8bb63c
refactor(harvest): helper formats duration string
thekaveman Apr 15, 2024
2e76702
fix(harvest): sentence case field
thekaveman Apr 15, 2024
84858e6
fix(harvest): keep duration as timedelta for offset calc
thekaveman Apr 15, 2024
2abd102
feat(harvest): calculate the start time
thekaveman Apr 15, 2024
ff6cf7b
feat(harvest): convert back to strings, export to CSV
thekaveman Apr 15, 2024
ea6934a
chore(harvest): remove debug prints
thekaveman Apr 15, 2024
5676a1f
chore(data): add sample toggl data
thekaveman Apr 15, 2024
1f2a722
feat(toggl): setup notebook for harvest conversion
thekaveman Apr 15, 2024
2e45fe1
feat(toggl): simple column updates/conversions
thekaveman Apr 15, 2024
30a3f22
feat(toggl): read/write a user info file
thekaveman Apr 16, 2024
84c5be0
feat(toggl): cache the user info in memory
thekaveman Apr 16, 2024
0330774
feat(toggl): get first name from email
thekaveman Apr 16, 2024
85cb99a
refactor(commands): move return codes to top level
thekaveman Apr 16, 2024
0c887a7
refactor(tests): don't hardcode temp file lines
thekaveman Apr 16, 2024
da48171
feat(google): get a user info dict
thekaveman Apr 16, 2024
39f1267
feat(toggl): get last name from google
thekaveman Apr 16, 2024
d99d906
feat(toggl): write user info back to file
thekaveman Apr 16, 2024
761c594
fix(toggl): forgot to import Description field
thekaveman Apr 16, 2024
19a0165
feat(toggl): calculate decimal hours from duration str
thekaveman Apr 16, 2024
3ea66b0
feat(toggl): save resulting data as CSV
thekaveman Apr 16, 2024
8deb4f7
chore(toggl): clean up debug prints
thekaveman Apr 16, 2024
27c23ba
feat(toggl): project info file can override project name
thekaveman Apr 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
"extensions": [
"eamodio.gitlens",
"esbenp.prettier-vscode",
"mechatroner.rainbow-csv",
"mhutchie.git-graph",
"ms-python.python",
"ms-python.black-formatter",
"ms-python.flake8",
"ms-toolsai.jupyter",
"tamasfe.even-better-toml"
]
}
Expand Down
5 changes: 5 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
HARVEST_CLIENT_NAME=Client1
HARVEST_DATA=data/harvest-sample.csv
TOGGL_DATA=data/toggl-sample.csv
TOGGL_PROJECT_INFO=data/toggl-project-info-sample.json
TOGGL_USER_INFO=data/toggl-user-info-sample.json
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ __pycache__
!.config/README.md
.coverage
.downloads
.env
.pytest_cache
*.csv
*.egg-info
notebooks/data/*
!notebooks/data/harvest-sample.csv
!notebooks/data/toggl-project-info-sample.json
!notebooks/data/toggl-sample.csv
!notebooks/data/toggl-user-info-sample.json
3 changes: 3 additions & 0 deletions compiler_admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from importlib.metadata import version, PackageNotFoundError

RESULT_SUCCESS = 0
RESULT_FAILURE = 1

try:
__version__ = version("compiler_admin")
except PackageNotFoundError:
Expand Down
2 changes: 0 additions & 2 deletions compiler_admin/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
RESULT_SUCCESS = 0
RESULT_FAILURE = 1
2 changes: 1 addition & 1 deletion compiler_admin/commands/convert.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from argparse import Namespace

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import (
GROUP_PARTNERS,
GROUP_STAFF,
Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/create.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from argparse import Namespace
from typing import Sequence

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import GROUP_TEAM, add_user_to_group, CallGAMCommand, user_account_name, user_exists


Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/delete.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from argparse import Namespace

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import CallGAMCommand, user_account_name, user_exists


Expand Down
3 changes: 1 addition & 2 deletions compiler_admin/commands/info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from compiler_admin import __version__ as version
from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import __version__ as version, RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import CallGAMCommand, CallGYBCommand


Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from shutil import rmtree
import subprocess

from compiler_admin.commands import RESULT_FAILURE, RESULT_SUCCESS
from compiler_admin import RESULT_FAILURE, RESULT_SUCCESS
from compiler_admin.services.google import USER_ARCHIVE, CallGAMCommand


Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/offboard.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from argparse import Namespace
from tempfile import NamedTemporaryFile

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.commands.delete import delete
from compiler_admin.commands.signout import signout
from compiler_admin.services.google import (
Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/reset_password.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from argparse import Namespace

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.commands.signout import signout
from compiler_admin.services.google import USER_HELLO, CallGAMCommand, user_account_name, user_exists

Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/restore.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from argparse import Namespace
import pathlib

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import USER_ARCHIVE, CallGYBCommand, user_account_name


Expand Down
2 changes: 1 addition & 1 deletion compiler_admin/commands/signout.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from argparse import Namespace

from compiler_admin.commands import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin import RESULT_SUCCESS, RESULT_FAILURE
from compiler_admin.services.google import CallGAMCommand, user_account_name, user_exists


Expand Down
35 changes: 33 additions & 2 deletions compiler_admin/services/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from tempfile import NamedTemporaryFile
from typing import Any, Sequence, IO

from compiler_admin import RESULT_SUCCESS

# import and alias CallGAMCommand so we can simplify usage in this app
from gam import CallGAMCommand as __CallGAMCommand, initializeLogging

Expand Down Expand Up @@ -96,9 +98,38 @@ def user_exists(username: str) -> bool:
print(f"User not in domain: {username}")
return False

res = CallGAMCommand(("info", "user", username, "quick"))
info = user_info(username)

return info != {}


return res == 0
def user_info(username: str) -> dict:
"""Get a dict of basic user information.

Args:
username (str): The [email protected] to get.
Returns:
A dict of user information
"""
if not str(username).endswith(DOMAIN):
print(f"User not in domain: {username}")
return {}

with NamedTemporaryFile("w+") as stdout:
res = CallGAMCommand(("info", "user", username, "quick"), stdout=stdout.name)
if res != RESULT_SUCCESS:
# user doesn't exist
return {}
# user exists, read data
lines = stdout.readlines()
# split on newline and filter out lines that aren't line "Key:Value" and empty value lines like "Key:<empty>"
lines = [L.strip() for L in lines if len(L.split(":")) == 2 and L.split(":")[1].strip()]
# make a map by splitting the lines, trimming key and value
info = {}
for line in lines:
k, v = line.split(":")
info[k.strip()] = v.strip()
return info


def user_in_group(username: str, group: str) -> bool:
Expand Down
Loading
Loading