OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered 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 """Issue Tracker code to serve out issue attachments. |
| 7 |
| 8 Summary of page classes: |
| 9 AttachmentPage: Serve the content of an attachment w/ the appropriate |
| 10 MIME type. |
| 11 IssueAttachmentDeletion: Form handler for deleting attachments. |
| 12 """ |
| 13 |
| 14 import base64 |
| 15 import logging |
| 16 import os |
| 17 import re |
| 18 import urllib |
| 19 |
| 20 import webapp2 |
| 21 |
| 22 from google.appengine.api import app_identity |
| 23 from google.appengine.api import images |
| 24 |
| 25 from framework import framework_helpers |
| 26 from framework import gcs_helpers |
| 27 from framework import permissions |
| 28 from framework import servlet |
| 29 from framework import urls |
| 30 from services import issue_svc |
| 31 from tracker import tracker_helpers |
| 32 from tracker import tracker_views |
| 33 |
| 34 |
| 35 # This will likely appear blank or as a broken image icon in the browser. |
| 36 NO_PREVIEW_ICON = '' |
| 37 NO_PREVIEW_MIME_TYPE = 'image/png' |
| 38 |
| 39 FILE_RE = re.compile('^[-_.a-zA-Z0-9 #+()]+$') |
| 40 |
| 41 |
| 42 class AttachmentPage(servlet.Servlet): |
| 43 """AttachmentPage serves issue attachments.""" |
| 44 |
| 45 def GatherPageData(self, mr): |
| 46 """Parse the attachment ID from the request and serve its content. |
| 47 |
| 48 Args: |
| 49 mr: commonly used info parsed from the request. |
| 50 |
| 51 Returns: dict of values used by EZT for rendering the page. |
| 52 """ |
| 53 try: |
| 54 attachment, _issue = tracker_helpers.GetAttachmentIfAllowed( |
| 55 mr, self.services) |
| 56 except issue_svc.NoSuchIssueException: |
| 57 webapp2.abort(404, 'issue not found') |
| 58 except issue_svc.NoSuchAttachmentException: |
| 59 webapp2.abort(404, 'attachment not found') |
| 60 except issue_svc.NoSuchCommentException: |
| 61 webapp2.abort(404, 'comment not found') |
| 62 |
| 63 if not attachment.gcs_object_id: |
| 64 webapp2.abort(404, 'attachment data not found') |
| 65 |
| 66 bucket_name = app_identity.get_default_gcs_bucket_name() |
| 67 object_path = '/' + bucket_name + attachment.gcs_object_id |
| 68 |
| 69 if mr.thumb: |
| 70 url = gcs_helpers.SignUrl(object_path + '-thumbnail') |
| 71 self.redirect(url, abort=True) |
| 72 |
| 73 # By default GCS will return images and attachments displayable inline. |
| 74 url = gcs_helpers.SignUrl(object_path) |
| 75 if not mr.inline: |
| 76 filename = attachment.filename |
| 77 if not FILE_RE.match(filename): |
| 78 print "bad file name: %s" % attachment.attachment_id |
| 79 filename = 'attachment-%d.dat' % attachment.attachment_id |
| 80 |
| 81 url = url + '&' + urllib.urlencode( |
| 82 {'response-content-disposition': |
| 83 ('attachment; filename=%s' % filename)}) |
| 84 |
| 85 self.redirect(url, abort=True) |
| 86 |
| 87 |
| 88 class IssueAttachmentDeletion(servlet.Servlet): |
| 89 """Form handler that allows user to hard-delete attachments.""" |
| 90 |
| 91 def ProcessFormData(self, mr, post_data): |
| 92 """Process the form that soft-deletes an issue attachment. |
| 93 |
| 94 Args: |
| 95 mr: commonly used info parsed from the request. |
| 96 post_data: HTML form data from the request. |
| 97 |
| 98 Returns: |
| 99 String URL to redirect the user to after processing. |
| 100 """ |
| 101 local_id = int(post_data['id']) |
| 102 sequence_num = int(post_data['sequence_num']) |
| 103 attachment_id = int(post_data['aid']) |
| 104 delete = 'delete' in post_data |
| 105 |
| 106 issue = self.services.issue.GetIssueByLocalID( |
| 107 mr.cnxn, mr.project_id, local_id) |
| 108 |
| 109 all_comments = self.services.issue.GetCommentsForIssue( |
| 110 mr.cnxn, issue.issue_id) |
| 111 logging.info('comments on %s are: %s', local_id, all_comments) |
| 112 comment = all_comments[sequence_num] |
| 113 |
| 114 if not permissions.CanDelete( |
| 115 mr.auth.user_id, mr.auth.effective_ids, mr.perms, |
| 116 comment.deleted_by, comment.user_id, mr.project, |
| 117 permissions.GetRestrictions(issue)): |
| 118 raise permissions.PermissionException( |
| 119 'Cannot un/delete attachment') |
| 120 |
| 121 self.services.issue.SoftDeleteAttachment( |
| 122 mr.cnxn, mr.project_id, local_id, sequence_num, |
| 123 attachment_id, self.services.user, delete=delete) |
| 124 |
| 125 return framework_helpers.FormatAbsoluteURL( |
| 126 mr, urls.ISSUE_DETAIL, id=local_id) |
OLD | NEW |