add html output format
This commit is contained in:
parent
dbaf301911
commit
30d8f9f350
@ -12,6 +12,7 @@ CLI tool to query LDAP/AD servers
|
|||||||
* JSON stream (with detailed or simplified attribute values)
|
* JSON stream (with detailed or simplified attribute values)
|
||||||
* CSV
|
* CSV
|
||||||
* Markdown table with stretched columns (for viewing in CLI/for monospaces fonts)
|
* Markdown table with stretched columns (for viewing in CLI/for monospaces fonts)
|
||||||
|
* HTML
|
||||||
* Decodes certain well-known attributes (UUIDs, Timestamps, SID, userAccountControl)
|
* Decodes certain well-known attributes (UUIDs, Timestamps, SID, userAccountControl)
|
||||||
* Requires server to support [RFC 2696: Simple Paged Results](https://www.rfc-editor.org/rfc/rfc2696) for proper pagination
|
* Requires server to support [RFC 2696: Simple Paged Results](https://www.rfc-editor.org/rfc/rfc2696) for proper pagination
|
||||||
* By default the first 1000 entries are shown, and it errors if there are more results
|
* By default the first 1000 entries are shown, and it errors if there are more results
|
||||||
|
@ -4,6 +4,7 @@ import argparse
|
|||||||
import csv
|
import csv
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import enum
|
import enum
|
||||||
|
import html
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
@ -16,6 +17,13 @@ from ldaptool._utils.ldap import Result, SizeLimitExceeded
|
|||||||
class TableOutput(enum.StrEnum):
|
class TableOutput(enum.StrEnum):
|
||||||
MARKDOWN = "markdown"
|
MARKDOWN = "markdown"
|
||||||
CSV = "csv"
|
CSV = "csv"
|
||||||
|
HTML = "html"
|
||||||
|
|
||||||
|
|
||||||
|
def _html_escape_line(columns: typing.Sequence[str], *, cell: str = "td") -> str:
|
||||||
|
cell_s = f"<{cell}>"
|
||||||
|
cell_e = f"</{cell}>"
|
||||||
|
return "<tr>" + ("".join(cell_s + html.escape(col) + cell_e for col in columns)) + "</tr>\n"
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(slots=True, kw_only=True)
|
@dataclasses.dataclass(slots=True, kw_only=True)
|
||||||
@ -35,6 +43,12 @@ class Arguments(search.Arguments):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
table_output: typing.Optional[TableOutput] = None
|
table_output: typing.Optional[TableOutput] = None
|
||||||
|
html: bool = dataclasses.field(
|
||||||
|
default=False,
|
||||||
|
metadata=argclasses.arg(
|
||||||
|
help="HTML table output - requires list of attributes",
|
||||||
|
),
|
||||||
|
)
|
||||||
sort: bool = dataclasses.field(
|
sort: bool = dataclasses.field(
|
||||||
default=False,
|
default=False,
|
||||||
metadata=argclasses.arg(
|
metadata=argclasses.arg(
|
||||||
@ -45,14 +59,16 @@ class Arguments(search.Arguments):
|
|||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
super(Arguments, self).__post_init__() # super() not working here, unclear why.
|
super(Arguments, self).__post_init__() # super() not working here, unclear why.
|
||||||
|
|
||||||
# pick at most one in csv, (markdown) table
|
# pick at most one in csv, (markdown) table, html
|
||||||
if [self.csv, self.table].count(True) > 1:
|
if [self.csv, self.table, self.html].count(True) > 1:
|
||||||
raise SystemExit("Can't use more than one table output type")
|
raise SystemExit("Can't use more than one table output type")
|
||||||
|
|
||||||
if self.csv:
|
if self.csv:
|
||||||
self.table_output = TableOutput.CSV
|
self.table_output = TableOutput.CSV
|
||||||
elif self.table:
|
elif self.table:
|
||||||
self.table_output = TableOutput.MARKDOWN
|
self.table_output = TableOutput.MARKDOWN
|
||||||
|
elif self.html:
|
||||||
|
self.table_output = TableOutput.HTML
|
||||||
|
|
||||||
if self.sort and self.table_output is None:
|
if self.sort and self.table_output is None:
|
||||||
# default to markdown table
|
# default to markdown table
|
||||||
@ -135,11 +151,20 @@ class _Context:
|
|||||||
if self.arguments.sort:
|
if self.arguments.sort:
|
||||||
line_iterator = sorted(line_iterator)
|
line_iterator = sorted(line_iterator)
|
||||||
|
|
||||||
|
if self.arguments.table_output in [TableOutput.CSV, TableOutput.MARKDOWN]:
|
||||||
csv_out = csv.writer(stream, lineterminator="\n")
|
csv_out = csv.writer(stream, lineterminator="\n")
|
||||||
csv_out.writerow(self.arguments.columns)
|
csv_out.writerow(self.arguments.columns)
|
||||||
|
|
||||||
for line in line_iterator:
|
for line in line_iterator:
|
||||||
csv_out.writerow(line)
|
csv_out.writerow(line)
|
||||||
|
else:
|
||||||
|
assert self.arguments.table_output == TableOutput.HTML
|
||||||
|
|
||||||
|
stream.write("<table>\n")
|
||||||
|
stream.write(_html_escape_line(self.arguments.columns, cell="th"))
|
||||||
|
for line in line_iterator:
|
||||||
|
stream.write(_html_escape_line(line))
|
||||||
|
stream.write("</table>\n")
|
||||||
|
|
||||||
def _ldif_or_json_output(self, search_iterator: typing.Iterable[Result], *, stream: typing.IO[str]) -> None:
|
def _ldif_or_json_output(self, search_iterator: typing.Iterable[Result], *, stream: typing.IO[str]) -> None:
|
||||||
decoder = decode.Decoder(arguments=self.arguments)
|
decoder = decode.Decoder(arguments=self.arguments)
|
||||||
|
Loading…
Reference in New Issue
Block a user