Permalink
Browse files

Fixes 863381 - Creates a system for internal redirects of products in…

…side Bouncer.
  • Loading branch information...
1 parent 226d71c commit c7bc42b8e0bbeaae6c7b0903bc0ddb0590757408 @brandonsavage brandonsavage committed Aug 14, 2013
@@ -0,0 +1,33 @@
+{% extends "api/api_doc_template.html" %}
+
+{% block description %}
+Create or update a product alias
+{% endblock %}
+
+{% block auth %}Needs HTTP authentication. Staff members only.{% endblock %}
+
+{% block post_required %}
+* ``alias``: The alias that you wish to create or update.
+* ``related_product``: The product name you wish to have the alias redirect
+{% endblock %}
+
+{% block errorcodes %}
+* ``101``: Unknown validation error occurred
+* ``102``: Alias name not provided
+* ``103``: Related product name not provided
+* ``104``: The product name specified was not a valid product name
+* ``105``: The alias name specified matches the name of an existing product and must be different
+{% endblock %}
+
+{% block example %}
+Success:
+
+ <success>Created/updated alias firefox-latest</success>
+
+Failure:
+
+ <error number="101">
+ alias name is required.
+ </error>
+{% endblock %}
+
@@ -4,6 +4,7 @@
from django.core.urlresolvers import reverse
from mirror.models import Product
+from mirror.forms import ProductAliasForm
from . import testcases
@@ -170,3 +171,65 @@ def test_product_language_delete_all(self):
assert not myprod.languages.count(), (
'Wildcard must delete all languages.')
+
+ def test_create_update_alias(self):
+
+ Product.objects.create(name='MyTestProduct')
+
+ response = self.c.post(reverse('api.views.create_update_alias'),
+ {'alias': 'my-test-alias',
+ 'related_product': 'MyTestProduct'})
+
+ self.assertEqual(response.status_code, 200,
+ 'Status code should be 200 when alias created')
+
+ def test_create_update_alias_requires_alias_name(self):
+ Product.objects.create(name='MyTestProduct')
+
+ response = self.c.post(reverse('api.views.create_update_alias'),
+ {'alias': '',
+ 'related_product': 'MyTestProduct'})
+
+ xmldoc = minidom.parseString(response.content)
+
+ msg = xmldoc.getElementsByTagName('error')
+ errno = msg[0].getAttribute('number')
+ self.assertEqual(int(errno), ProductAliasForm.E_ALIAS_REQUIRED,
+ 'alias is a required field')
+
+ def test_create_update_alias_requires_valid_product_name(self):
+ response = self.c.post(reverse('api.views.create_update_alias'),
+ {'alias': 'my-test-alias',
+ 'related_product': ''})
+
+ xmldoc = minidom.parseString(response.content)
+
+ msg = xmldoc.getElementsByTagName('error')
+ errno = msg[0].getAttribute('number')
+
+ self.assertEqual(int(errno), ProductAliasForm.E_RELATED_NAME_REQUIRED,
+ 'related_product is a required field')
+
+ response = self.c.post(reverse('api.views.create_update_alias'),
+ {'alias': 'my-test-alias',
+ 'related_product': 'MyTestProduct'})
+
+ xmldoc = minidom.parseString(response.content)
+
+ msg = xmldoc.getElementsByTagName('error')
+ errno = msg[0].getAttribute('number')
+
+ self.assertEqual(int(errno), ProductAliasForm.E_PRODUCT_DOESNT_EXIST,
+ 'Must provide a valid product name')
+
+ Product.objects.create(name='MyTestProduct')
+
+ response = self.c.post(reverse('api.views.create_update_alias'),
+ {'alias': 'myMyTestProduct',
+ 'related_product': 'MyTestProduct'})
+
+ xmldoc = minidom.parseString(response.content)
+ msg = xmldoc.getElementsByTagName('error')
+ errno = msg[0].getAttribute('number')
+ self.assertEqual(int(errno), ProductAliasForm.E_ALIAS_PRODUCT_MATCH,
+ 'Cannot specify the same alias as a product name')
@@ -16,6 +16,7 @@ def setUp(self):
self.user = User.objects.create_user(
username, 'lennon@thebeatles.com', pw
)
+
self.user.is_staff = True
self.user.save()
self.c = test.client.Client()
View
@@ -16,5 +16,7 @@
(r'^uptake/?$', 'uptake'),
(r'^mirror_list/?$', 'mirror_list'),
+
+ (r'^create_update_alias/?$', 'create_update_alias'),
)
View
@@ -10,12 +10,11 @@
from product_details import product_details
from api.decorators import has_perm_or_basicauth, logged_in_or_basicauth
-from mirror.models import Location, Mirror, OS, Product
-
+from mirror.models import Location, Mirror, OS, Product, ProductAlias
+from mirror.forms import ProductAliasForm
HTTP_AUTH_REALM = 'Bouncer API'
-
def _get_command_list():
templates = os.listdir(os.path.join(os.path.dirname(__file__), 'templates',
'api', 'docs'))
@@ -357,6 +356,65 @@ def location_delete(request):
return xml.success('Deleted location: %s' % location)
+@require_POST
+@csrf_exempt
+@has_perm_or_basicauth("mirror.create_update_alias", HTTP_AUTH_REALM)
+def create_update_alias(request):
+ """Create or update an alias for a product"""
+
+ xml = XMLRenderer()
+
+ form = ProductAliasForm(request.POST)
+ if not form.is_valid():
+ if 'alias' in form.errors:
+ if 'required' in form.errors['alias'][0]:
+ return xml.error(
+ 'alias name is required.',
+ errno=form.E_ALIAS_REQUIRED
+ )
+
+ if 'same name' in form.errors['alias'][0]:
+ return xml.error(
+ 'You cannot create an alias with the same name as a product',
+ errno=form.E_ALIAS_PRODUCT_MATCH
+ )
+ if 'related_product' in form.errors:
+ if 'required' in form.errors['related_product'][0]:
+ return xml.error(
+ 'related_product name is required.',
+ errno=form.E_RELATED_NAME_REQUIRED
+ )
+ if 'same name as an existing' in form.errors['related_product'][0]:
+ return xml.error(
+ 'You cannot create alias with the same name as a product',
+ errno=form.E_ALIAS_PRODUCT_MATCH
+ )
+ if 'invalid' in form.errors['related_product'][0]:
+ return xml.error(
+ 'You must specify a valid product to match with an alias',
+ errno=form.E_PRODUCT_DOESNT_EXIST
+ )
+
+ return xml.error(
+ 'There was a problem validating the data provided',
+ errno=form.E_ALIAS_GENERAL_VALIDATION_ERROR
+ )
+
+ alias = form.cleaned_data['alias']
+ redirect = form.cleaned_data['related_product']
+
+ alias_obj, created = ProductAlias.objects.get_or_create(
+ alias=alias,
+ defaults={'related_product': redirect}
+ )
+
+ if not created:
+ alias_obj.related_product = redirect
+ alias_obj.save()
+
+ return xml.success('Created/updated alias %s' % alias)
+
+
class XMLRenderer(object):
"""Render API data as XML"""
View
@@ -1,6 +1,14 @@
from django.contrib import admin
-from mirror.models import Mirror, OS, Product, Location, ProductLanguage
+from mirror.models import (Mirror, OS, Product, Location, ProductLanguage,
+ ProductAlias)
+from mirror.forms import ProductAliasForm
+
+
+class ProductAliasAdmin(admin.ModelAdmin):
+ list_display = ('alias', 'related_product')
+ form = ProductAliasForm
+admin.site.register(ProductAlias, ProductAliasAdmin)
class LocationAdmin(admin.ModelAdmin):
@@ -34,7 +42,8 @@ class ProductLanguageInline(admin.TabularInline):
class ProductAdmin(admin.ModelAdmin):
- list_display = ('name', 'priority', 'count', 'active', 'checknow', 'ssl_only')
+ list_display = ('name', 'priority', 'count', 'active', 'checknow',
+ 'ssl_only')
list_filter = ('active', 'checknow', 'ssl_only')
ordering = ('name',)
actions = ('mark_for_checknow',)
View
@@ -1,8 +1,35 @@
from django import forms
-from models import Product
+from models import Product, ProductAlias
+from django.core import validators
class UptakeForm(forms.Form):
p = forms.ModelMultipleChoiceField(
queryset=Product.objects.order_by('name'),
label='Products')
+
+class ProductAliasForm(forms.ModelForm):
+
+ E_ALIAS_GENERAL_VALIDATION_ERROR= 101
+ E_ALIAS_REQUIRED = 102
+ E_PRODUCT_DOESNT_EXIST = 103
+ E_ALIAS_PRODUCT_MATCH = 104
+ E_RELATED_NAME_REQUIRED = 105
+
+ class Meta:
+ model = ProductAlias
+
+ def clean_alias(self):
+ if Product.objects.filter(name=self.cleaned_data['alias']).exists():
+ raise forms.ValidationError(
+ "Your alias cannot share the same name as an existing product!"
+ )
+ return self.cleaned_data['alias']
+
+ def clean_related_product(self):
+ if not Product.objects.filter(
+ name=self.cleaned_data['related_product']).exists():
+ raise forms.ValidationError(
+ "The product you entered was invalid"
+ )
+ return self.cleaned_data['related_product']
Oops, something went wrong.

0 comments on commit c7bc42b

Please sign in to comment.