Skip to content
Snippets Groups Projects
Select Git revision
  • dc065fd65e8b235c995ab573b55d0bff47af3205
  • master default protected
2 results

splay_operation.h

Blame
  • table.py 4.35 KiB
    import csv
    from dataclasses import dataclass
    from flask import Response, url_for
    from html import escape
    import io
    from markupsafe import Markup
    from typing import Sequence, Optional, Iterable
    import urllib.parse
    import werkzeug.exceptions
    
    import mo.csv
    import mo.db as db
    from mo.web import app
    
    
    @dataclass
    class Column:
        key: str                # Jméno klíče ve slovnících
        name: str               # Název v hlavičce CSV
        title: str              # Titulek v HTML tabulkách
    
        def __init__(self, key: str, name: Optional[str] = None, title: Optional[str] = None):
            self.key = key
            self.name = name or key
            self.title = title or self.name
    
    
    class Cell:
        """Buňka tabulky může mít dvě verze: textovou a HTML."""
        text: str
    
        def __init__(self, text: str):
            self.text = text
    
        def __str__(self) -> str:
            return self.text
    
        def to_html(self) -> str:
            return escape(self.text)
    
    
    class CellLink(Cell):
        url: str
        hint: Optional[str]
    
        def __init__(self, text: str, url: str, hint: Optional[str] = None):
            Cell.__init__(self, text)
            self.url = url
            self.hint = hint
    
        def to_html(self) -> str:
            a = '<a href="' + escape(self.url) + '"'
            if self.hint:
                a += ' title="' + escape(self.hint) + '"'
            return a + '>' + escape(self.text) + '</a>'
    
    
    class Table:
        columns: Sequence[Column]
        rows: Iterable[dict]
        filename: str
    
        def __init__(self, columns: Sequence[Column], rows: Iterable[dict], filename: str):
            self.columns = columns
            self.rows = rows
            self.filename = filename
    
        def to_html(self) -> str:
            tab = ['<table class=data>', '<tr>']
    
            for c in self.columns:
                tab.append(f'\t<th>{c.title}')
    
            for r in self.rows:
                tab.append('<tr>')
                for c in self.columns:
                    val = r.get(c.key)
                    if isinstance(val, Cell):
                        vals = val.to_html()
                    else:
                        vals = escape(str(val))
                    tab.append(f'\t<td>{vals}')
    
            tab.append('</table>')
            tab.append("<p>Stáhnout jako <a href='?format=csv'>CSV</a> nebo <a href='?format=tsv'>TSV</a>.")
            return Markup("\n".join(tab))
    
        def to_csv(self, dialect: str) -> str:
            out = io.StringIO()
            writer = csv.writer(out, dialect=dialect)
    
            header = [c.name for c in self.columns]
            writer.writerow(header)
    
            for row in self.rows:
                r = [row.get(c.key) for c in self.columns]
                writer.writerow(r)
    
            return out.getvalue()
    
        def to_csv_stream(self, dialect: str) -> Iterable[str]:
            out = io.StringIO()
            writer = csv.writer(out, dialect=dialect)
    
            header = [c.name for c in self.columns]
            writer.writerow(header)
    
            nrows = 0
            for row in self.rows:
                r = [row.get(c.key) for c in self.columns]
                writer.writerow(r)
    
                nrows += 1
                if nrows >= 100:
                    yield out.getvalue()
                    out.seek(0)
                    out.truncate()
                    nrows = 0
    
            yield out.getvalue()
    
        def send_as(self, format: str, streaming: bool = False) -> Response:
            if format == 'csv':
                dialect = 'excel'
                ctype = 'text/csv; charset=utf=8'
                filename = self.filename + '.csv'
            elif format == 'tsv':
                dialect = 'tsv'
                ctype = 'text/tab-separated-values; charset=utf=8'
                filename = self.filename + '.tsv'
            else:
                raise werkzeug.exceptions.NotFound()
    
            if streaming:
                resp = Response(self.to_csv_stream(dialect=dialect))
            else:
                out = self.to_csv(dialect=dialect)
                resp = app.make_response(out)
    
            resp.content_type = ctype
            resp.headers.add('Content-Disposition', f'attachment; filename={filename}')
            return resp
    
    
    # Pomocné funkce na generování různých typů odkazů
    
    def cell_email_link(user: db.User) -> CellLink:
        return CellLink(user.email, 'mailto:' + urllib.parse.quote(user.email, safe='@'))
    
    
    def cell_user_link(user: db.User, text: str) -> CellLink:
        return CellLink(text, url_for('org_user', id=user.user_id))
    
    
    def cell_place_link(place: db.Place, text: str) -> CellLink:
        return CellLink(text, url_for('org_place', id=place.place_id), hint=place.name)