Skip to content

Commit

Permalink
fix config setting and add file uploads (#752)
Browse files Browse the repository at this point in the history
* fix: remove override of the value when setting the config

* feat: add file uploads

---------

Co-authored-by: Corentin de Boisset <corentin.deboisset@sancare.fr>
  • Loading branch information
CorentinDeBoisset and Corentin de Boisset authored Jan 3, 2024
1 parent 25d55d4 commit 8917d7e
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 14 deletions.
102 changes: 94 additions & 8 deletions pwpush/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ def push(
help="Reference Note. Encrypted & Visible Only to You. E.g. Employee, Record or Ticket ID etc.. Requires login.",
),
# prompt: bool = typer.Option(False, help="Prompt to enter payload interactively via the CLI."),
# file: str = typer.Option('', help="Specify a text file that contains the payload. Note: 1MB max."),
payload: str = typer.Argument(
"",
),
Expand Down Expand Up @@ -185,6 +184,83 @@ def push(
rprint(response.text)


@app.command(name="push-file")
def pushFile(
days: int = typer.Option(None, help="Expire after this many days."),
views: int = typer.Option(None, help="Expire after this many views."),
deletable: bool = typer.Option(
None, help="Allow users to delete passwords once retrieved."
),
retrieval_step: bool = typer.Option(
None,
help="1-click retrieval step: Helps to avoid chat systems and URL scanners from eating up views.",
),
note: str = typer.Option(
None,
help="Reference Note. Encrypted & Visible Only to You. E.g. Employee, Record or Ticket ID etc.. Requires login.",
),
payload: str = typer.Argument(
"",
),
) -> None:
"""
Push a new file.
"""
path = "/f.json"

data = {}
data["file_push"] = {}
data["file_push"]["payload"] = ""

# Option and user preference processing
if days:
data["file_push"]["expire_after_days"] = days
elif user_config["expiration"]["expire_after_days"] != "Not Set":
data["file_push"]["expire_after_days"] = user_config["expiration"][
"expire_after_days"
]

if views:
data["file_push"]["expire_after_views"] = views
elif user_config["expiration"]["expire_after_views"] != "Not Set":
data["file_push"]["expire_after_views"] = user_config["expiration"][
"expire_after_views"
]

if deletable:
data["file_push"]["deletable_by_viewer"] = views
elif user_config["expiration"]["deletable_by_viewer"] != "Not Set":
data["file_push"]["deletable_by_viewer"] = user_config["expiration"][
"deletable_by_viewer"
]

if retrieval_step:
data["file_push"]["retrieval_step"] = views
elif user_config["expiration"]["retrieval_step"] != "Not Set":
data["file_push"]["retrieval_step"] = user_config["expiration"][
"retrieval_step"
]

with open(payload, "rb") as fd:
upload_files = {"file_push[files][]": fd}
response = make_request("POST", path, upload_files=upload_files, post_data=data)

if response.status_code == 201:
body = response.json()
path = "/f/%s/preview.json" % body["url_token"]
response = make_request("GET", path)

body = response.json()
if json_output():
print(body)
else:
rprint(body["url"])
else:
rprint("Error:")
rprint(response.status_code)
rprint(response.text)


@app.command()
def expire(
url_token: str = typer.Argument(
Expand Down Expand Up @@ -333,7 +409,7 @@ def list(expired: bool = typer.Option(False, help="Show only expired pushes."))
rprint(r.text)


def make_request(method, path, post_data=None):
def make_request(method, path, post_data=None, upload_files=None):
debug = debug_output()

url = user_config["instance"]["url"]
Expand All @@ -359,10 +435,16 @@ def make_request(method, path, post_data=None):
elif method == "POST":
if debug:
rprint(
f"Making JSON POST request to {url + path} with headers {auth_headers} and body {post_data}"
f"Making JSON POST request to {url + path} with headers {auth_headers} body {post_data}"
)
if upload_files is not None:
rprint(f"Attaching a file to the upload")
return requests.post(
url + path, headers=auth_headers, json=post_data, timeout=5
url + path,
headers=auth_headers,
json=post_data,
timeout=5,
files=upload_files,
)
elif method == "DELETE":
if debug:
Expand All @@ -371,25 +453,29 @@ def make_request(method, path, post_data=None):


def json_output() -> Boolean:
if cli_options["json"] == True or user_config["cli"]["json"] is True:
user_config_json = user_config["cli"]["json"].lower() in ["true", "yes", "on"]
if cli_options["json"] == True or user_config_json:
return True
return False


def verbose_output() -> Boolean:
if cli_options["verbose"] == True or user_config["cli"]["verbose"] is True:
user_config_verbose = user_config["cli"]["verbose"].lower() in ["true", "yes", "on"]
if cli_options["verbose"] == True or user_config_verbose:
return True
return False


def debug_output() -> Boolean:
if cli_options["debug"] == True or user_config["cli"]["debug"] is True:
user_config_debug = user_config["cli"]["debug"].lower() in ["true", "yes", "on"]
if cli_options["debug"] == True or user_config_debug:
return True
return False


def pretty_output() -> Boolean:
if cli_options["pretty"] == True or user_config["cli"]["pretty"] is True:
user_config_pretty = user_config["cli"]["debug"].lower() in ["true", "yes", "on"]
if cli_options["pretty"] == True or user_config_pretty:
return True
return False

Expand Down
1 change: 0 additions & 1 deletion pwpush/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ def set(
Set a configuration value
"""
key = key.lower()
value = value.lower() in ["true", "yes", "on"]

found = False
for section in user_config.sections():
Expand Down
9 changes: 8 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ def test_config_show_in_json():


def test_config_set():
result = runner.invoke(app, ["config", "set", "--key", "json", "--value", "on"])
result = runner.invoke(app, ["config", "set", "--key", "json", "--value", "True"])
assert "Success" in result.stdout
assert result.exit_code == 0

result = runner.invoke(
app, ["config", "set", "--key", "url", "--value", "https://pwpush.test"]
)
assert "Success" in result.stdout
assert result.exit_code == 0

result = runner.invoke(app, ["--json", "on", "config", "show"])
config = json.loads(result.stdout.strip())
assert config["cli"]["json"] == "True"
assert config["instance"]["url"] == "https://pwpush.test"


def test_config_unset():
Expand Down
46 changes: 42 additions & 4 deletions tests/test_push.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
import json

import requests
from typer.testing import CliRunner

from pwpush.__main__ import app

runner = CliRunner()


def test_basic_push():
def build_request_mock(body):
class MockResponse(object):
def __init__(self, body):
self.status_code = 201
self.body = body

def json(self):
return body

def mock(*args, **kwargs):
return MockResponse(body)

return mock


def test_basic_push(monkeypatch):
monkeypatch.setattr(
requests, "post", build_request_mock({"url_token": "super-token"})
)
monkeypatch.setattr(
requests,
"get",
build_request_mock({"url": "https://pwpush.test/en/p/text-password-url"}),
)

result = runner.invoke(app, ["push", "mypassword"])
assert result.exit_code == 0
assert "https://pwpush.com/en/p/" in result.stdout
assert "https://pwpush.test/en/p/text-password-url\n" in result.stdout


def test_file_push(monkeypatch):
monkeypatch.setattr(
requests, "post", build_request_mock({"url_token": "super-token"})
)
monkeypatch.setattr(
requests,
"get",
build_request_mock({"url": "https://pwpush.test/en/f/secret-file-url"}),
)

result = runner.invoke(app, ["push-file", "./README.md"])
assert result.exit_code == 0
assert "https://pwpush.test/en/f/secret-file-url\n" == result.stdout


def test_config_show_in_json():
Expand Down

0 comments on commit 8917d7e

Please sign in to comment.