Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 1 | # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style |
| 3 | # license that can be found in the LICENSE file or at |
| 4 | # https://developers.google.com/open-source/licenses/bsd |
| 5 | |
| 6 | """Helper functions for creating CSV pagedata.""" |
| 7 | from __future__ import print_function |
| 8 | from __future__ import division |
| 9 | from __future__ import absolute_import |
| 10 | |
| 11 | import types |
| 12 | |
| 13 | from framework import framework_helpers |
| 14 | |
| 15 | |
| 16 | # Whenever the user request one of these columns, we replace it with the |
| 17 | # list of alternate columns. In effect, we split the requested column |
| 18 | # into two CSV columns. |
| 19 | _CSV_COLS_TO_REPLACE = { |
| 20 | 'summary': ['Summary', 'AllLabels'], |
| 21 | 'opened': ['Opened', 'OpenedTimestamp'], |
| 22 | 'closed': ['Closed', 'ClosedTimestamp'], |
| 23 | 'modified': ['Modified', 'ModifiedTimestamp'], |
| 24 | 'ownermodified': ['OwnerModified', 'OwnerModifiedTimestamp'], |
| 25 | 'statusmodified': ['StatusModified', 'StatusModifiedTimestamp'], |
| 26 | 'componentmodified': ['ComponentModified', 'ComponentModifiedTimestamp'], |
| 27 | 'ownerlastvisit': ['OwnerLastVisit', 'OwnerLastVisitDaysAgo'], |
| 28 | } |
| 29 | |
| 30 | |
| 31 | def RewriteColspec(col_spec): |
| 32 | """Rewrite the given colspec to expand special CSV columns.""" |
| 33 | new_cols = [] |
| 34 | |
| 35 | for col in col_spec.split(): |
| 36 | rewriten_cols = _CSV_COLS_TO_REPLACE.get(col.lower(), [col]) |
| 37 | new_cols.extend(rewriten_cols) |
| 38 | |
| 39 | return ' '.join(new_cols) |
| 40 | |
| 41 | |
| 42 | def ReformatRowsForCSV(mr, page_data, url_path): |
| 43 | """Rewrites/adds to the given page_data so the CSV templates can use it.""" |
| 44 | # CSV files are at risk for the PDF content sniffing by Acrobat Reader |
| 45 | page_data['prevent_sniffing'] = True |
| 46 | |
| 47 | # If we're truncating the results, add a URL to the next page of results |
| 48 | page_data['next_csv_link'] = None |
| 49 | pagination = page_data['pagination'] |
| 50 | if pagination.next_url: |
| 51 | page_data['next_csv_link'] = framework_helpers.FormatAbsoluteURL( |
| 52 | mr, url_path, start=pagination.last) |
| 53 | page_data['item_count'] = pagination.last - pagination.start + 1 |
| 54 | |
| 55 | for row in page_data['table_data']: |
| 56 | for cell in row.cells: |
| 57 | for value in cell.values: |
| 58 | value.item = EscapeCSV(value.item) |
| 59 | return page_data |
| 60 | |
| 61 | |
| 62 | def EscapeCSV(s): |
| 63 | """Return a version of string S that is safe as part of a CSV file.""" |
| 64 | if s is None: |
| 65 | return '' |
| 66 | if isinstance(s, types.StringTypes): |
| 67 | s = s.strip().replace('"', '""') |
| 68 | # Prefix any formula cells because some spreadsheets have built-in |
| 69 | # formila functions that can actually have side-effects on the user's |
| 70 | # computer. |
| 71 | if s.startswith(('=', '-', '+', '@')): |
| 72 | s = "'" + s |
| 73 | |
| 74 | return s |