Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1929)

Unified Diff: appengine/monorail/tracker/issueattachment.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « appengine/monorail/tracker/issueadvsearch.py ('k') | appengine/monorail/tracker/issueattachmenttext.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/monorail/tracker/issueattachment.py
diff --git a/appengine/monorail/tracker/issueattachment.py b/appengine/monorail/tracker/issueattachment.py
new file mode 100644
index 0000000000000000000000000000000000000000..27f84a1633ed8fa9a95a56f587d5b8ed290b46ad
--- /dev/null
+++ b/appengine/monorail/tracker/issueattachment.py
@@ -0,0 +1,126 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is govered by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""Issue Tracker code to serve out issue attachments.
+
+Summary of page classes:
+ AttachmentPage: Serve the content of an attachment w/ the appropriate
+ MIME type.
+ IssueAttachmentDeletion: Form handler for deleting attachments.
+"""
+
+import base64
+import logging
+import os
+import re
+import urllib
+
+import webapp2
+
+from google.appengine.api import app_identity
+from google.appengine.api import images
+
+from framework import framework_helpers
+from framework import gcs_helpers
+from framework import permissions
+from framework import servlet
+from framework import urls
+from services import issue_svc
+from tracker import tracker_helpers
+from tracker import tracker_views
+
+
+# This will likely appear blank or as a broken image icon in the browser.
+NO_PREVIEW_ICON = ''
+NO_PREVIEW_MIME_TYPE = 'image/png'
+
+FILE_RE = re.compile('^[-_.a-zA-Z0-9 #+()]+$')
+
+
+class AttachmentPage(servlet.Servlet):
+ """AttachmentPage serves issue attachments."""
+
+ def GatherPageData(self, mr):
+ """Parse the attachment ID from the request and serve its content.
+
+ Args:
+ mr: commonly used info parsed from the request.
+
+ Returns: dict of values used by EZT for rendering the page.
+ """
+ try:
+ attachment, _issue = tracker_helpers.GetAttachmentIfAllowed(
+ mr, self.services)
+ except issue_svc.NoSuchIssueException:
+ webapp2.abort(404, 'issue not found')
+ except issue_svc.NoSuchAttachmentException:
+ webapp2.abort(404, 'attachment not found')
+ except issue_svc.NoSuchCommentException:
+ webapp2.abort(404, 'comment not found')
+
+ if not attachment.gcs_object_id:
+ webapp2.abort(404, 'attachment data not found')
+
+ bucket_name = app_identity.get_default_gcs_bucket_name()
+ object_path = '/' + bucket_name + attachment.gcs_object_id
+
+ if mr.thumb:
+ url = gcs_helpers.SignUrl(object_path + '-thumbnail')
+ self.redirect(url, abort=True)
+
+ # By default GCS will return images and attachments displayable inline.
+ url = gcs_helpers.SignUrl(object_path)
+ if not mr.inline:
+ filename = attachment.filename
+ if not FILE_RE.match(filename):
+ print "bad file name: %s" % attachment.attachment_id
+ filename = 'attachment-%d.dat' % attachment.attachment_id
+
+ url = url + '&' + urllib.urlencode(
+ {'response-content-disposition':
+ ('attachment; filename=%s' % filename)})
+
+ self.redirect(url, abort=True)
+
+
+class IssueAttachmentDeletion(servlet.Servlet):
+ """Form handler that allows user to hard-delete attachments."""
+
+ def ProcessFormData(self, mr, post_data):
+ """Process the form that soft-deletes an issue attachment.
+
+ Args:
+ mr: commonly used info parsed from the request.
+ post_data: HTML form data from the request.
+
+ Returns:
+ String URL to redirect the user to after processing.
+ """
+ local_id = int(post_data['id'])
+ sequence_num = int(post_data['sequence_num'])
+ attachment_id = int(post_data['aid'])
+ delete = 'delete' in post_data
+
+ issue = self.services.issue.GetIssueByLocalID(
+ mr.cnxn, mr.project_id, local_id)
+
+ all_comments = self.services.issue.GetCommentsForIssue(
+ mr.cnxn, issue.issue_id)
+ logging.info('comments on %s are: %s', local_id, all_comments)
+ comment = all_comments[sequence_num]
+
+ if not permissions.CanDelete(
+ mr.auth.user_id, mr.auth.effective_ids, mr.perms,
+ comment.deleted_by, comment.user_id, mr.project,
+ permissions.GetRestrictions(issue)):
+ raise permissions.PermissionException(
+ 'Cannot un/delete attachment')
+
+ self.services.issue.SoftDeleteAttachment(
+ mr.cnxn, mr.project_id, local_id, sequence_num,
+ attachment_id, self.services.user, delete=delete)
+
+ return framework_helpers.FormatAbsoluteURL(
+ mr, urls.ISSUE_DETAIL, id=local_id)
« no previous file with comments | « appengine/monorail/tracker/issueadvsearch.py ('k') | appengine/monorail/tracker/issueattachmenttext.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698