Skip to content

Commit

Permalink
fixes bug 1064968 - Deprecate CurrentVersions, CurrentProducts and Pr…
Browse files Browse the repository at this point in the history
…oductsVersions
  • Loading branch information
peterbe committed Mar 31, 2016
1 parent 500b2fe commit 49a70b5
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 141 deletions.
6 changes: 6 additions & 0 deletions webapp-django/crashstats/api/jinja2/api/documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,16 @@ <h2><a href="#{{ endpoint.name }}">{{ endpoint.name }}</a></h2>
<code>{{ base_url }}{{ endpoint.url }}</code>
</p>

{% if endpoint.deprecation_warning %}
<p class="deprecation-warning">Deprecation Warning</p>
<pre class="deprecation-warning">{{ endpoint.deprecation_warning }}</pre>
{% endif %}

{% if endpoint.docstring %}
<p class="docstring">Documentation notes</p>
<pre class="docstring">{{ endpoint.docstring }}</pre>
{% endif %}

{% if endpoint.parameters %}
<table class="data-table vertical">
<thead>
Expand Down
8 changes: 8 additions & 0 deletions webapp-django/crashstats/api/static/api/css/documentation.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,11 @@ form.testdrive td ul li {
display: inline;
margin-right: 10px;
}

.deprecation-warning {
font-weight: bold;
color: rgb(194, 110, 0);
}
p.deprecation-warning {
text-transform: uppercase;
}
87 changes: 49 additions & 38 deletions webapp-django/crashstats/api/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from crashstats.crashstats.models import (
ProductVersions,
CrontabberState,
CurrentProducts,
)
from crashstats.tokens.models import Token

Expand Down Expand Up @@ -294,44 +295,54 @@ def mocked_get(url, params, **options):
})
eq_(response.status_code, 200)

# Commented out because these are soon going to be completely re-written
# @mock.patch('requests.get')
# def test_CurrentVersions(self, rget):
# url = reverse('api:model_wrapper', args=('CurrentVersions',))
# response = self.client.get(url)
# eq_(response.status_code, 200)
# dump = json.loads(response.content)
# ok_(isinstance(dump, list))
# first = dump[0]
# ok_('product' in first)
#
# @mock.patch('requests.get')
# def test_CurrentProducts(self, rget):
# url = reverse('api:model_wrapper', args=('CurrentProducts',))
# response = self.client.get(url)
# eq_(response.status_code, 200)
# dump = json.loads(response.content)
# ok_(dump['hits'])
# ok_(dump['products'])
# ok_(dump['total'])
#
# @mock.patch('requests.get')
# def test_ProductsVersions(self, rget):
# url = reverse('api:model_wrapper', args=('ProductsVersions',))
# response = self.client.get(url)
# eq_(response.status_code, 200)
# dump = json.loads(response.content)
# ok_('WaterWolf' in dump)
# ok_('NightTrain' in dump)
# versions = dump['WaterWolf']
# version = versions[0]
# ok_('product' in version)
# ok_('version' in version)
# ok_('throttle' in version)
# ok_('start_date' in version)
# ok_('end_date' in version)
# ok_('featured' in version)
# ok_('release' in version)
def test_CurrentVersions(self):
url = reverse('api:model_wrapper', args=('CurrentVersions',))
response = self.client.get(url)
eq_(response.status_code, 200)
dump = json.loads(response.content)
ok_(isinstance(dump, list))
first = dump[0]
ok_('product' in first)
eq_(
response['Deprecation-warning'],
CurrentProducts.deprecation_warning.replace('\n', ' ')
)

def test_CurrentProducts(self):
url = reverse('api:model_wrapper', args=('CurrentProducts',))
response = self.client.get(url)
eq_(response.status_code, 200)
dump = json.loads(response.content)
ok_(dump['hits'])
ok_(dump['products'])
ok_(dump['total'])
eq_(dump['DEPRECATION_WARNING'], CurrentProducts.deprecation_warning)
eq_(
response['Deprecation-warning'],
CurrentProducts.deprecation_warning.replace('\n', ' ')
)

def test_ProductsVersions(self): # Note the 's' in ProductSVersions
url = reverse('api:model_wrapper', args=('ProductsVersions',))
response = self.client.get(url)
eq_(response.status_code, 200)
dump = json.loads(response.content)
ok_('WaterWolf' in dump)
ok_('NightTrain' in dump)
versions = dump['WaterWolf']
version = versions[0]
ok_('product' in version)
ok_('version' in version)
ok_('throttle' in version)
ok_('start_date' in version)
ok_('end_date' in version)
ok_('featured' in version)
ok_('release' in version)
eq_(dump['DEPRECATION_WARNING'], CurrentProducts.deprecation_warning)
eq_(
response['Deprecation-warning'],
CurrentProducts.deprecation_warning.replace('\n', ' ')
)

def test_ProductVersions(self):

Expand Down
11 changes: 11 additions & 0 deletions webapp-django/crashstats/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,16 @@ def model_wrapper(request, model_name):
)
return response

if (
getattr(model, 'deprecation_warning', False)
):
if isinstance(result, dict):
result['DEPRECATION_WARNING'] = model.deprecation_warning
# If you return a tuple of two dicts, the second one becomes
# the extra headers.
return result, {
'DEPRECATION-WARNING': model.deprecation_warning.replace('\n', ' ')
}
return result


Expand Down Expand Up @@ -462,6 +472,7 @@ def _describe_model(model):
'methods': methods,
'docstring': docstring,
'required_permissions': required_permissions,
'deprecation_warning': getattr(model, 'deprecation_warning', None),
}
return data

Expand Down
79 changes: 76 additions & 3 deletions webapp-django/crashstats/crashstats/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@
from crashstats import scrubber
from crashstats.api.cleaner import Cleaner


logger = logging.getLogger('crashstats_models')


class DeprecatedModelError(DeprecationWarning):
"""Used when a deprecated model is being used in debug mode"""


def config_from_configman():
return configuration(
definition_source=[
Expand Down Expand Up @@ -594,8 +599,14 @@ def post(self, **data):
return self.get_implementation().post(**data)


# Delete this at the end of 2016.
class CurrentVersions(SocorroMiddleware):

deprecation_warning = """
This API endpoint is deprecated and will cease to exist at the
end of 2016. The new, supported, endpoint is /api/ProductVersions/.
""".strip()

API_WHITELIST = (
'end_date',
'featured',
Expand All @@ -621,9 +632,10 @@ def get(self, currentproducts=None):
return currentversions


# Delete this at the end of 2016.
class CurrentProducts(SocorroMiddleware):

URL_PREFIX = '/products/'
deprecation_warning = CurrentVersions.deprecation_warning

possible_params = (
'versions',
Expand All @@ -644,9 +656,66 @@ class CurrentProducts(SocorroMiddleware):
}
}

def get(self, **params):
if settings.DEBUG: # pragma: no cover
raise DeprecatedModelError("you're not supposed to use this")
api = ProductVersions()

# Because of the API documentation, you might get this passed
# but as an empty string. If so, ignore it.
if 'versions' in params and not params['versions']:
del params['versions']

if params.get('versions'):
# Serious legacy hacking! I'm glad this is deprecated.
# When a versions thing is provided, return a *list* of
# product version dicts instead.
product, version = params.pop('versions').split(':')
params['product'] = product
params['version'] = version
hits = []
for pv in api.get(**params)['hits']:
hits.append({
'product': pv['product'],
'throttle': pv['throttle'],
'end_date': pv['end_date'],
'featured': pv['is_featured'],
'version': pv['version'],
'release': pv['build_type'],
'has_builds': pv['has_builds'],
'start_date': pv['start_date'],
})
return {'hits': hits, 'total': len(hits)}

hits = {}
products = []
total = 0
for pv in api.get()['hits']:
if pv['product'] not in hits:
hits[pv['product']] = []
if pv['product'] not in products:
# Doing it this way preserves the sort order.
# In other words, Firefox comes first.
products.append(pv['product'])
hits[pv['product']].append({
'product': pv['product'],
'throttle': pv['throttle'],
'end_date': pv['end_date'],
'featured': pv['is_featured'],
'version': pv['version'],
'release': pv['build_type'],
'has_builds': pv['has_builds'],
'start_date': pv['start_date'],
})
total += 1
return {
'hits': hits,
'total': total,
'products': products,
}

def post(self, **data):
# why does this feel so clunky?!
return super(CurrentProducts, self).post(self.URL_PREFIX, data)
raise DeprecatedModelError("you're not supposed to use this")


class Releases(SocorroMiddleware):
Expand Down Expand Up @@ -693,6 +762,7 @@ def put(self, **data):
return super(ReleasesFeatured, self).put(self.URL_PREFIX, payload)


# Delete this at the end of 2016.
class ProductsVersions(CurrentVersions):

API_WHITELIST = {
Expand All @@ -708,6 +778,9 @@ class ProductsVersions(CurrentVersions):
}

def get(self):
if settings.DEBUG: # pragma: no cover
raise DeprecatedModelError("you're not supposed to use this")

versions = super(ProductsVersions, self).get()
products = {}
for version in versions:
Expand Down
Loading

0 comments on commit 49a70b5

Please sign in to comment.