Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions tabcmd/commands/auth/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self):

self.logging_level = "info"
self._read_from_json()
self.logger = log(__name__, self.logging_level) # instantiate here mostly for tests
self.logger = log(__class__.__name__, self.logging_level) # instantiate here mostly for tests
self.tableau_server = None # this one is an object that doesn't get persisted in the file

# called before we connect to the server
Expand Down Expand Up @@ -214,7 +214,7 @@ def create_session(self, args):
self._read_existing_state()
self._update_session_data(args)
self.logging_level = args.logging_level or self.logging_level
self.logger = log(__name__, self.logging_level)
self.logger = log(__class__.__name__, self.logging_level)

credentials = None
if args.password:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get_view_by_content_url(logger, server, view_content_url) -> TSC.ViewItem:
req_option.filter.add(TSC.Filter("contentUrl", TSC.RequestOptions.Operator.Equals, view_content_url))
matching_views, paging = server.views.get(req_option)
except TSC.ServerResponseError as e:
Errors.exit_with_error(logger, _("publish.errors.unexpected_server_response").format(""))
Errors.exit_with_error(logger, _("publish.errors.unexpected_server_response").format(e))
if len(matching_views) < 1:
Errors.exit_with_error(logger, message=_("errors.xmlapi.not_found"))
return matching_views[0]
Expand All @@ -42,3 +42,76 @@ def get_wb_by_content_url(logger, server, workbook_content_url) -> TSC.WorkbookI
if len(matching_workbooks) < 1:
Errors.exit_with_error(logger, message=_("dataalerts.failure.error.workbookNotFound"))
return matching_workbooks[0]

@staticmethod
def apply_values_from_url_params(request_options: TSC.PDFRequestOptions, url, logger) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am assuming that the url type is a string. If yes, can we be sure that the url will always be decoded at this point in the code. Also, is there a url library in python that can abstract getting params from urls that we could use instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a string, yes. It's not a full url, it's the representation of the workbook/view as it would be in a url (tabcmd get "/views/Sales_Analysis/Sales_Report.png") - I'm actually not quite sure how we handle encoding yet and have to do some comparison with behaviors in the original tabcmd, but it's possible a proper library will be better.

# should be able to replace this with request_options._append_view_filters(params)
logger.debug(url)
try:
if "?" in url:
query = url.split("?")[1]
logger.trace("Query parameters: {}".format(query))
else:
logger.debug("No query parameters present in url")
return

params = query.split("&")
logger.trace(params)
for value in params:
if value.startswith(":"):
DatasourcesAndWorkbooks.apply_option_value(request_options, value, logger)
else: # it must be a filter
DatasourcesAndWorkbooks.apply_filter_value(request_options, value, logger)

except BaseException as e:
logger.warn("Error building filter params", e)
# ExportCommand.log_stack(logger) # type: ignore

@staticmethod
def apply_filter_value(request_options: TSC.PDFRequestOptions, value: str, logger) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the apply_filter_value and apply_option_value methods be moved to a class that is more relevant ?

# todo: do we need to strip Parameters.x -> x?
logger.trace("handling filter param {}".format(value))
data_filter = value.split("=")
request_options.vf(data_filter[0], data_filter[1])

@staticmethod
def apply_option_value(request_options: TSC.PDFRequestOptions, value: str, logger) -> None:
logger.trace("handling url option {}".format(value))
setting = value.split("=")
if ":iid" == setting[0]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: this block might read better inside a switch case

logger.debug(":iid value ignored in url")
elif ":refresh" == setting[0] and DatasourcesAndWorkbooks.is_truthy(setting[1]):
# mypy is worried that this is readonly
request_options.max_age = 0 # type:ignore
logger.debug("Set max age to {} from {}".format(request_options.max_age, value))
elif ":size" == setting[0]:
height, width = setting[1].split(",")
logger.warn("Height/weight parameters not yet implemented ({})".format(value))
else:
logger.debug("Parameter[s] not recognized: {}".format(value))

@staticmethod
def is_truthy(value: str):
return value.lower() in ["yes", "y", "1", "true"]

@staticmethod
def apply_png_options(request_options: TSC.ImageRequestOptions, args, logger):
if args.height or args.width:
# only applicable for png
logger.warn("Height/width arguments not yet implemented in export")
if args.image_resolution:
request_options.image_resolution = args.image_resolution

@staticmethod
def save_to_data_file(logger, output, filename):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.writelines(output)
logger.info(_("export.success").format("", filename))

@staticmethod
def save_to_file(logger, output, filename):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.write(output)
logger.info(_("export.success").format("", filename))
122 changes: 56 additions & 66 deletions tabcmd/commands/datasources_and_workbooks/export_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ def define_args(export_parser):
help="page orientation (landscape or portrait) of the exported PDF",
)
export_parser.add_argument("--pagesize", default="letter", help="Set the page size of the exported PDF")
export_parser.add_argument("--width", default=800, help="Set the width in pixels. Default is 800 px")
export_parser.add_argument(
"--image-resolution", default="High", help="Set the image resolution of the exported image"
)

export_parser.add_argument(
"--width", default=800, help="Set the width of the image in pixels. Default is 800 px"
)
export_parser.add_argument("--filename", "-f", help="filename to store the exported data")
export_parser.add_argument("--height", default=600, help=_("export.options.height"))
export_parser.add_argument(
"--filter",
"-vf",
metavar="COLUMN:VALUE",
help="View filter to apply to the view",
)
Expand All @@ -52,29 +57,29 @@ def run_command(args):
view_content_url, wb_content_url = ExportCommand.parse_export_url_to_workbook_and_view(logger, args.url)
logger.debug([view_content_url, wb_content_url])
if not view_content_url and not wb_content_url:
Errors.exit_with_error(logger, _("export.errors.requires_workbook_view_param").format(ExportCommand))

logger.debug(args.pagelayout, args.pagesize, args.filename, args.width, args.height, args.filter)
view_example = "/workbook_name/view_name"
message = "{} [{}]".format(
_("export.errors.requires_workbook_view_param").format(__class__.__name__), view_example
)
Errors.exit_with_error(logger, message)

try:
if args.fullpdf: # it's a workbook
workbook_item = ExportCommand.get_wb_by_content_url(logger, server, wb_content_url)
output = ExportCommand.download_wb_pdf(server, workbook_item, args.url, logger)

output = ExportCommand.download_wb_pdf(server, workbook_item, args, logger)
default_filename = "{}.pdf".format(workbook_item.name)

elif args.pdf or args.png or args.csv: # it's a view
view_item = ExportCommand.get_view_by_content_url(logger, server, view_content_url)

if args.pdf:
output = ExportCommand.download_view_pdf(server, view_item, args.url, logger)
output = ExportCommand.download_view_pdf(server, view_item, args, logger)
default_filename = "{}.pdf".format(view_item.name)
elif args.csv:
output = ExportCommand.download_csv(server, view_item, args.url, logger)
output = ExportCommand.download_csv(server, view_item, args, logger)
default_filename = "{}.csv".format(view_item.name)
elif args.png:
output = ExportCommand.download_png(server, view_item, args.url, logger)

output = ExportCommand.download_png(server, view_item, args, logger)
default_filename = "{}.png".format(view_item.name)

except Exception as e:
Expand All @@ -87,63 +92,62 @@ def run_command(args):
else:
ExportCommand.save_to_file(logger, output, save_name)


except Exception as e:
Errors.exit_with_error(logger, "Error saving to file", e)

@staticmethod
def extract_filter_values_from_url_params(request_options: TSC.PDFRequestOptions, url, logger=None) -> None:
try:
# todo make logging better
logger = logger or log(ExportCommand.__class__.__name__, "DEBUG")
logger.debug(url)

if "?" in url:
query = url.split("?")[1]
else:
return

params = query.split("&")
logger.trace(params)
def apply_values_from_args(request_options: TSC.PDFRequestOptions, args, logger=None) -> None:
logger.debug(
"Args: {}, {}, {}, {}, {}".format(args.pagelayout, args.pagesize, args.width, args.height, args.filter)
)
if args.pagelayout:
request_options.orientation = args.pagelayout
if args.pagesize:
request_options.page_type = args.pagesize
if args.filter:
params = args.filter.split("&")
for value in params:
data_filter = value.split("=")
request_options.vf(data_filter[0], data_filter[1])
except BaseException as e:
logger.error("Error building filter params", e)
ExportCommand.log_stack(logger) # type: ignore
ExportCommand.apply_filter_value(request_options, value, logger)

@staticmethod
def download_wb_pdf(server, workbook_item, url, logger):
logger.trace(url)
pdf = TSC.PDFRequestOptions(maxage=1)
ExportCommand.extract_filter_values_from_url_params(pdf, url)

server.workbooks.populate_pdf(workbook_item, pdf)
def download_wb_pdf(server, workbook_item, args, logger):
logger.trace(args.url)
pdf_options = TSC.PDFRequestOptions(maxage=1)
ExportCommand.apply_values_from_url_params(pdf_options, args.url, logger)
ExportCommand.apply_values_from_args(pdf_options, args, logger)
logger.trace(pdf_options)
server.workbooks.populate_pdf(workbook_item, pdf_options)
return workbook_item.pdf

@staticmethod
def download_view_pdf(server, view_item, url, logger):
logger.trace(url)
pdf = TSC.PDFRequestOptions(maxage=1)
ExportCommand.extract_filter_values_from_url_params(pdf, url)
logger.trace(pdf.view_filters)
server.views.populate_pdf(view_item, pdf)
def download_view_pdf(server, view_item, args, logger):
logger.trace(args.url)
pdf_options = TSC.PDFRequestOptions(maxage=1)
ExportCommand.apply_values_from_url_params(pdf_options, args.url, logger)
ExportCommand.apply_values_from_args(pdf_options, args, logger)
logger.trace(pdf_options)
server.views.populate_pdf(view_item, pdf_options)
return view_item.pdf

@staticmethod
def download_csv(server, view_item, url, logger):
logger.trace(url)
csv = TSC.CSVRequestOptions(maxage=1)
ExportCommand.extract_filter_values_from_url_params(csv, url)
server.views.populate_csv(view_item, csv)
def download_csv(server, view_item, args, logger):
logger.trace(args.url)
csv_options = TSC.CSVRequestOptions(maxage=1)
ExportCommand.apply_values_from_url_params(csv_options, args.url, logger)
ExportCommand.apply_values_from_args(csv_options, args, logger)
logger.trace(csv_options)
server.views.populate_csv(view_item, csv_options)
return view_item.csv

@staticmethod
def download_png(server, view_item, url, logger):
logger.trace(url)
req_option_image = TSC.ImageRequestOptions(maxage=1)
ExportCommand.extract_filter_values_from_url_params(req_option_image, url)
server.views.populate_image(view_item, req_option_image)
def download_png(server, view_item, args, logger):
logger.trace(args.url)
image_options = TSC.ImageRequestOptions(maxage=1)
ExportCommand.apply_values_from_url_params(image_options, args.url, logger)
ExportCommand.apply_values_from_args(image_options, args, logger)
DatasourcesAndWorkbooks.apply_png_options(image_options, args, logger)
logger.trace(image_options)
server.views.populate_image(view_item, image_options)
return view_item.png

@staticmethod
Expand All @@ -163,17 +167,3 @@ def parse_export_url_to_workbook_and_view(logger, url):
workbook = name_parts[0]
view = "{}/sheets/{}".format(workbook, name_parts[1])
return view, workbook

@staticmethod
def save_to_data_file(logger, output, filename):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.writelines(output)
logger.info(_("export.success").format("", filename))

@staticmethod
def save_to_file(logger, output, filename):
logger.info(_("httputils.found_attachment").format(filename))
with open(filename, "wb") as f:
f.write(output)
logger.info(_("export.success").format("", filename))
Loading