Skip to content

Commit 7a6ec64

Browse files
authored
cli-setup (#24)
- adding cli initial config setup - adding create new tests cases
1 parent 6006c9c commit 7a6ec64

10 files changed

Lines changed: 1769 additions & 41 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ var/
3030
# before PyInstaller builds the exe, so as to inject date/other infos into it.
3131
*.manifest
3232
*.spec
33+
**/*_real.yaml
34+
**/*_real.json
3335

3436
# Installer logs
3537
pip-log.txt

README.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@ pipx install salesforce-timecard
2424

2525
## Configuration
2626

27+
### Automatic Setup
28+
29+
using the cli you can setup the cli as described in here
30+
31+
```bash
32+
$ timecard setup
33+
[2021-08-09 11:44:30,565][WARNING] no config file found
34+
Please enter your salesforce username: your-salesforce-email@example.com
35+
{
36+
"username": "your-salesforce-email@example.com",
37+
"credential_store": "keyring"
38+
}
39+
can I create this config on /Users/your-username/.pse.json ? [Y/n]: y
40+
41+
Insert your Saleforce Password: **********
42+
Insert your Saleforce Token: **********
43+
44+
Setup Completed
45+
```
46+
47+
### Manual actions
48+
49+
2750
The script requires a local configuration file with your SalesForce credentials
2851
included in it, located at `~/.pse.json`. It should look like:
2952

@@ -55,6 +78,7 @@ Default values for the keyring assume everything is stored under the `salesforce
5578

5679
Under MacOS this can be added with the "Keychain Access" application, under the default "login" keychain. `salesforce_cli` is the Keychain Item Name for both instances, and the `your-salesforce-email@example.com_password` or `your-salesforce-email@example.com_token` string is the Account Name.
5780

81+
5882
## Examples
5983

6084
Adding 3 hours of personal development on Wednesday:
@@ -145,12 +169,6 @@ timecard TCH-08-26-2019-079768 submitted
145169
timecard TCH-08-26-2019-079769 submitted
146170
```
147171

148-
## TODO
149-
150-
- Clean up remaining documentation
151-
- Run linter over the code
152-
- Setup tool for initial config file generation / keychain seeding
153-
154172
## License
155173

156174
`salesforce-timecard` is licensed under the [WTFPL](LICENSE).

salesforce_timecard/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
__title__ = "salesforce-timecard"
22
__description__ = "PSE Timecard CLI"
33
__url__ = "https://github.com/giuliocalzolari/salesforce-timecard"
4-
__version__ = "2.0.2"
4+
__version__ = "2.0.3"
55
__author__ = "giuliocalzolari"
66
__author_email__ = "giuliocalzolari@users.noreply.github.com"
77
__license__ = "WTFPL"

salesforce_timecard/cli.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
import sys
44
import re
5+
import os
56
import logging
67
import json
78
import yaml
9+
import keyring
810
from functools import wraps
911
import click
1012
from click_aliases import ClickAliasedGroup
@@ -24,6 +26,7 @@
2426
te = TimecardEntry()
2527

2628

29+
2730
def process_row(ctx, project, notes, hours, weekday, w, file):
2831
assignment_id = None
2932
active_assignment = te.get_assignments_active()
@@ -301,4 +304,35 @@ def sample_timecard():
301304
"username": "YourName@example.com",
302305
"credential_store": "keyring"
303306
}, indent = 4)
304-
)
307+
)
308+
309+
310+
@cli.command(name="setup", aliases=["setup"])
311+
def setup_cli():
312+
"""setup_cli"""
313+
314+
username = click.prompt('Please enter your salesforce username', type=str)
315+
316+
cfg = {
317+
"username": username,
318+
"credential_store": "keyring"
319+
}
320+
click.echo(
321+
json.dumps(cfg, indent=4)
322+
)
323+
cfg_file = os.path.expanduser("~/.pse.json")
324+
click.confirm(f"can I create this config on {cfg_file} ?", default=True, abort=True)
325+
click.echo()
326+
327+
with open(cfg_file, "w") as outfile:
328+
json.dump(cfg,outfile, indent=4)
329+
330+
password = click.prompt("Insert your Saleforce Password", prompt_suffix=': ',hide_input=True, show_default=False, type=str)
331+
click.echo()
332+
token = click.prompt("Insert your Saleforce Token", prompt_suffix=': ', hide_input=True, show_default=False, type=str)
333+
click.echo()
334+
335+
keyring.set_password("salesforce_cli", f"{username}_password", password)
336+
keyring.set_password("salesforce_cli", f"{username}_token", token)
337+
338+
click.echo("Setup Completed")

salesforce_timecard/core.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,32 +39,35 @@ def cred_store(cls, v, values):
3939
class TimecardEntry:
4040
def __init__(self, cfg="~/.pse.json"):
4141

42+
43+
self.get_week(date.today().strftime("%d-%m-%Y"))
4244
self.cfg_file = os.path.expanduser(cfg)
43-
with open(self.cfg_file) as inf:
44-
try:
45-
self.cfg = AppConfig(**json.load(inf))
46-
except json.decoder.JSONDecodeError:
47-
sys.exit(f"Unable to decode JSON config at {self.cfg_file}")
4845

49-
try:
50-
self.sf = Salesforce(
51-
username=self.cfg.username,
52-
password=self.cfg.password,
53-
security_token=self.cfg.token,
54-
domain=self.cfg.domain,
55-
client_id="FF",
56-
)
57-
except SalesforceAuthenticationFailed as e:
58-
logger.error(e)
59-
sys.exit(1)
46+
if os.path.isfile(self.cfg_file):
47+
with open(self.cfg_file) as inf:
48+
try:
49+
self.cfg = AppConfig(**json.load(inf))
50+
except json.decoder.JSONDecodeError:
51+
sys.exit(f"Unable to decode JSON config at {self.cfg_file}")
6052

61-
self.contact_id = self.get_contact_id(self.cfg.username)
62-
self.assignments = self.get_assignments_active()
63-
self.global_project = self.get_global_project()
53+
try:
54+
self.sf = Salesforce(
55+
username=self.cfg.username,
56+
password=self.cfg.password,
57+
security_token=self.cfg.token,
58+
domain=self.cfg.domain,
59+
client_id="FF",
60+
)
61+
except SalesforceAuthenticationFailed as e:
62+
logger.error(e)
63+
sys.exit(1)
64+
65+
self.contact_id = self.get_contact_id(self.cfg.username)
66+
self.assignments = self.get_assignments_active()
67+
self.global_project = self.get_global_project()
68+
else:
69+
logger.warning("no config file found")
6470

65-
today = date.today()
66-
day = today.strftime("%d-%m-%Y")
67-
self.get_week(day)
6871

6972
def get_week(self, day):
7073
dt = datetime.strptime(day, "%d-%m-%Y")
@@ -254,7 +257,7 @@ def get_global_project(self):
254257

255258
def delete_time_entry(self, _id):
256259
try:
257-
self.sf.pse__Timecard_Header__c.delete(_id)
260+
return self.sf.pse__Timecard_Header__c.delete(_id)
258261
except SalesforceError:
259262
logger.error("failed on deletion id:{}".format(_id))
260263
logger.error(sys.exc_info()[1])
@@ -305,15 +308,15 @@ def add_time_entry(self, assignment_id, day_n, hours, notes):
305308
"pse__Status__c not in ('Submitted', 'Approved') "
306309
)
307310

308-
new_timecard["pse__" + day_n + "_Hours__c"] = hours
309-
new_timecard["pse__" + day_n + "_Notes__c"] = notes
311+
new_timecard[f"pse__{day_n}_Hours__c"] = hours
312+
new_timecard[f"pse__{day_n}_Notes__c"] = notes
310313

311314
results = self.safe_sql(sql_query)
312315
logger.debug(json.dumps(new_timecard, indent=4))
313316
if len(results["records"]) > 0:
314317
logger.debug("required update")
315318
try:
316-
self.sf.pse__Timecard_Header__c.update(
319+
return self.sf.pse__Timecard_Header__c.update(
317320
results["records"][0]["Id"], new_timecard
318321
)
319322
except SalesforceError:
@@ -323,7 +326,7 @@ def add_time_entry(self, assignment_id, day_n, hours, notes):
323326

324327
else:
325328
try:
326-
self.sf.pse__Timecard_Header__c.create(new_timecard)
329+
return self.sf.pse__Timecard_Header__c.create(new_timecard)
327330
except SalesforceError:
328331
logger.error("failed on creation")
329332
logger.error(sys.exc_info()[1])

0 commit comments

Comments
 (0)