3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
21 """Used to confirm and act on delete requests from the Admin Console."""
31 from google
.appengine
.api
import capabilities
32 from google
.appengine
.api
import datastore
33 from google
.appengine
.ext
import webapp
34 from google
.appengine
.ext
.datastore_admin
import config
35 from google
.appengine
.ext
.datastore_admin
import utils
36 from google
.appengine
.ext
.mapreduce
import model
37 from google
.appengine
.ext
.mapreduce
import operation
39 MAPREDUCE_OBJECTS
= [model
.MapreduceState
.kind(),
40 model
.ShardState
.kind()]
41 XSRF_ACTION
= 'delete'
42 KIND_AND_SIZE_RE
= re
.compile('^(.*)\|(-?[0-9]+)$')
45 def DeleteEntity(key
):
46 """Delete function which deletes all processed entities.
49 key: key of the entity to delete.
52 a delete operation if the entity is not an active mapreduce or
53 DatastoreAdminOperation object.
55 if key
.kind() in MAPREDUCE_OBJECTS
:
56 entity
= datastore
.Get(key
)
57 if entity
and not entity
["active"]:
58 yield operation
.db
.Delete(key
)
59 elif key
.kind() == utils
.DatastoreAdminOperation
.kind():
60 entity
= datastore
.Get(key
)
61 if entity
and not entity
["active_jobs"]:
62 yield operation
.db
.Delete(key
)
64 yield operation
.db
.Delete(key
)
67 class ConfirmDeleteHandler(webapp
.RequestHandler
):
68 """Handler to deal with requests from the admin console to delete data."""
70 SUFFIX
= 'confirm_delete'
73 def Render(cls
, handler
):
74 """Rendering method that can be called by main.py or get.
76 This method executes no action, so the method by which it is accessed is
77 immaterial. Creating a form with get may be a desirable function. That is,
78 if this builtin is turned on, anyone can create a form to delete a kind by
79 simply linking to the ConfirmDeleteHandler like so:
80 <a href="/_ah/datastore_admin/confirm_delete?kind=trash">
81 Delete all Trash Objects</a>
84 handler: the webapp.RequestHandler invoking the method
86 readonly_warning
= not capabilities
.CapabilitySet(
87 'datastore_v3', capabilities
=['write']).is_enabled()
88 namespace
= handler
.request
.get('namespace')
89 kinds
= handler
.request
.get_all('kind')
90 sizes_known
, size_total
, remainder
= utils
.ParseKindsAndSizes(kinds
)
92 (namespace_str
, kind_str
) = utils
.GetPrintableStrs(namespace
, kinds
)
94 'readonly_warning': readonly_warning
,
95 'form_target': DoDeleteHandler
.SUFFIX
,
97 'remainder': remainder
,
98 'sizes_known': sizes_known
,
99 'size_total': size_total
,
100 'app_id': handler
.request
.get('app_id'),
101 'datastore_admin_home': utils
.GenerateHomeUrl(handler
.request
),
102 'kind_str': kind_str
,
103 'namespace_str': namespace_str
,
104 'xsrf_token': utils
.CreateXsrfToken(XSRF_ACTION
),
106 utils
.RenderToResponse(handler
, 'confirm_delete.html', template_params
)
109 """Handler for get requests to datastore_admin/confirm_delete."""
110 ConfirmDeleteHandler
.Render(self
)
113 class DoDeleteHandler(webapp
.RequestHandler
):
114 """Handler to deal with requests from the admin console to delete data."""
118 'google.appengine.ext.datastore_admin.delete_handler.DeleteEntity')
120 'google.appengine.ext.mapreduce.input_readers.DatastoreKeyInputReader')
121 MAPREDUCE_DETAIL
= config
.MAPREDUCE_PATH
+ '/detail?mapreduce_id='
124 """Handler for get requests to datastore_admin/delete.do.
126 Status of executed jobs is displayed.
128 jobs
= self
.request
.get_all('job')
129 error
= self
.request
.get('error', '')
130 xsrf_error
= self
.request
.get('xsrf_error', '')
131 noconfirm_error
= self
.request
.get('noconfirm_error', '')
135 'mapreduce_detail': self
.MAPREDUCE_DETAIL
,
137 'xsrf_error': xsrf_error
,
138 'noconfirm_error': noconfirm_error
,
139 'datastore_admin_home': config
.BASE_PATH
,
141 utils
.RenderToResponse(self
, 'do_delete.html', template_params
)
144 """Handler for post requests to datastore_admin/delete.do.
146 Jobs are executed and user is redirected to the get handler.
148 namespace
= self
.request
.get('namespace')
149 kinds
= self
.request
.get_all('kind')
150 (namespace_str
, kinds_str
) = utils
.GetPrintableStrs(namespace
, kinds
)
151 token
= self
.request
.get('xsrf_token')
152 readonly_warning
= self
.request
.get('readonly_warning')
156 if (readonly_warning
== 'True') and not self
.request
.get(
157 'confirm_readonly_delete'):
158 parameters
= [('noconfirm_error', '1')]
160 if utils
.ValidateXsrfToken(token
, XSRF_ACTION
):
162 op
= utils
.StartOperation(
163 'Deleting %s%s' % (kinds_str
, namespace_str
))
164 name_template
= 'Delete all %(kind)s objects%(namespace)s'
165 mapreduce_params
= {'force_ops_writes': True}
166 queue
= self
.request
.get('queue')
167 queue
= queue
or os
.environ
.get(
168 'HTTP_X_APPENGINE_QUEUENAME', 'default')
172 jobs
= utils
.RunMapForKinds(
180 mapreduce_params
=mapreduce_params
,
182 max_shard_count
=utils
.MAPREDUCE_DEFAULT_SHARDS
)
187 error
= self
._HandleException
(e
)
189 parameters
= [('job', job
) for job
in jobs
]
191 parameters
.append(('error', error
))
193 parameters
= [('xsrf_error', '1')]
195 query
= urllib
.urlencode(parameters
)
197 self
.redirect('%s/%s?%s' % (config
.BASE_PATH
, self
.SUFFIX
, query
))
199 def _HandleException(self
, e
):
200 """Make exception handling overrideable by tests.
202 In normal cases, return only the error string; do not fail to render the