Skip to content
This repository has been archived by the owner on Feb 23, 2020. It is now read-only.

Commit

Permalink
#622 #619 Series fixes from prod (#628)
Browse files Browse the repository at this point in the history
* #622  Fix not shown item names at the search results

* #619  Return 404 for category with no options

* #622  Return 404 for categories with no active options

* #622  Rm redundant CategoryTile tests

* #622  Show mark column at the options list on product page

* #622  Fix test

* #622  Drop unused import

* #622  Fix test
  • Loading branch information
duker33 authored Apr 21, 2019
1 parent d332073 commit 0b17e23
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 59 deletions.
4 changes: 4 additions & 0 deletions stroyprombeton/context/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from functools import partial

from django import http
from django.conf import settings
from django.shortcuts import get_object_or_404

Expand Down Expand Up @@ -82,6 +83,9 @@ def context(self) -> typing.ContextDict:
tags = FilteredTags(stb_models.Tag.objects.all(), self.request_data)
options_ = options.Filtered(self.category, tags.qs(), self.request_data)

if not options_.qs():
raise http.Http404('<h1>В категории нет изделий</h1')

# @todo #514:60m Create PaginatedOptions class.
# Without code doubling between the new class
# and `context.products.PaginatedProducts` one.
Expand Down
4 changes: 4 additions & 0 deletions stroyprombeton/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class Category(catalog.models.AbstractCategory, pages.models.PageMixin):
verbose_name=_('specification'),
)

@property
def catalog_name(self):
return self.name

@classmethod
def get_default_parent(cls):
return pages.models.CustomPage.objects.filter(slug='gbi').first()
Expand Down
2 changes: 1 addition & 1 deletion stroyprombeton/tests/tests_selenium.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ def test_search_have_results(self):

self.assertTrue(
self.browser.find_element_by_link_text(
'Product #10 of Category #1 of #42 mark #10'
'Product #10 of Category #1 of #42'
)
)

Expand Down
91 changes: 40 additions & 51 deletions stroyprombeton/tests/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,54 +96,6 @@ def test_content(self):
)


@tag('fast', 'catalog')
class CategoryTile(TestCase, TestPageMixin):
"""
Test for CategoryPage view.
With condition, that using CategoryTile template.
"""

def setUp(self):
"""Create root and child category."""
# @todo #142:30m Move tests custom data to test_db.
# Use this command `stroyprombeton/management/commands/test_db.py`
self.data = {
'name': 'Test root category',
'page': ModelPage.objects.create(
content='Козырьки устанавливают над входами зданий.',
name='Козырьки',
),
}

self.root_category = models.Category.objects.create(**self.data)

self.child_data = {
'name': 'Test child category',
'parent': self.root_category,
'page': ModelPage.objects.create(
content='Козырьки применяют при строительстве зданий.',
name='Козырьки входов, плиты парапетные.',
)
}

models.Category.objects.create(**self.child_data)

self.response = self.client.get(f'/gbi/categories/{self.root_category.id}/')

def test_children_categories_quantity(self):
self.assertEqual(
len(self.response.context['children']),
1
)

def test_children_category_name(self):
self.assertEqual(
self.response.context['children'][0].name,
self.child_data['name']
)


@tag('fast', 'catalog')
class Category(BaseCatalogTestCase, TestPageMixin):
"""
Expand Down Expand Up @@ -349,6 +301,12 @@ def test_series_list(self):
[s.text.strip() for s in series_app]
)

def test_empty_products_404(self):
"""Category with no products should return 404 response."""
category = models.Category.objects.get(name='Category root empty #17')
response = self.get_category_page(category)
self.assertEqual(404, response.status_code)


@tag('fast', 'catalog')
class CatalogPagination(BaseCatalogTestCase):
Expand Down Expand Up @@ -494,11 +452,12 @@ def test_tags_table(self):
response.content.decode('utf-8'),
'html.parser'
).find(class_='options-table')
groups = table.find_all('th')
# the first column is hardcoded field mark
groups = table.find_all('th')[1:]
for tag_, group in zip(tags, groups):
self.assertIn(tag_.group.name, group)

parsed_tags = table.find_all('tr')[1].find_all(class_='option-td')
parsed_tags = table.find_all('tr')[1].find_all(class_='option-td')[1:]
for tag_, parsed in zip(tags, parsed_tags):
self.assertEqual(tag_.name, parsed.string.strip())

Expand Down Expand Up @@ -619,12 +578,33 @@ def get_search_url(self, term=''):
get_params=get_params.urlencode()
)

def get_results_page(self, *args, **kwargs):
return self.client.get(self.get_search_url(*args, **kwargs))

def get_results_soup(self, *args, **kwargs):
page = self.get_results_page(*args, **kwargs)
return BeautifulSoup(
page.content.decode('utf-8'),
'html.parser'
)

def test_result_page_contains_query(self):
"""Search results page should contain it's search query."""
url = self.get_search_url(term=self.WRONG_TERM)
response = self.client.get(url)
self.assertNotContains(response, self.WRONG_TERM)

# @todo #622:60m Fix search engine logic.
# If query fully equals some product.name,
# search results should return this product as the first results entry.
@unittest.expectedFailure
def test_search_by_product_name(self):
"""Search results page should contain product names."""
product = models.Product.objects.first()
soup = self.get_results_soup(term=product.name)
first = soup.find(class_='table-link')
self.assertEqual(product.name, first.text.strip())

def test_search_by_id(self):
"""Search view should return redirect on model page, if id was received as term."""
product = models.Product.objects.first()
Expand Down Expand Up @@ -1040,6 +1020,16 @@ def test_all_series_matrix_page(self):
)
)

def test_emtpy_404(self):
"""Series with not active options should return response 404."""
series = (
models.Series.objects
.annotate(count=Count('options'))
.filter(count=0)
).first()
response = self.get_series_page(series)
self.assertEqual(404, response.status_code)

# @todo #570:30m Implement product images on series page.
# Take this feature from categories.
# Depends from #565 - images repairing.
Expand All @@ -1066,7 +1056,6 @@ def get_series_url(series: models.Series, category: models.Category):
)

def get_series_page(self, *args, **kwargs):
print('get series page')
return self.client.get(self.get_series_url(*args, **kwargs))

def get_series_soup(self, *args, **kwargs) -> BeautifulSoup:
Expand Down
21 changes: 15 additions & 6 deletions stroyprombeton/views/catalog.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from csv import writer as CSVWriter

from django import http
from django.conf import settings
from django.http import HttpResponseBadRequest, StreamingHttpResponse
from django.shortcuts import get_object_or_404, render
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
Expand All @@ -24,7 +24,7 @@ def fetch_products(request):
# @todo #451:60m Create middleware to for http errors. se2
# Middleware should transform http exceptions to http errors errors.
except exception.Http400 as e:
return HttpResponseBadRequest(str(e))
return http.HttpResponseBadRequest(str(e))

return render(request, 'catalog/options.html', context_.context())

Expand Down Expand Up @@ -57,7 +57,7 @@ def serialize_categories(categories):
models.CategoryPage.objects.active()
)

response = StreamingHttpResponse(
response = http.StreamingHttpResponse(
(writer.writerow(c) for c in categories),
content_type="text/csv",
)
Expand Down Expand Up @@ -205,12 +205,20 @@ def series_matrix(request, page='series'):

def series(request, series_slug: str):
series = get_object_or_404(models.Series.objects, slug=series_slug)

options = series.options.active()
# @todo #619:60m Prevent code doubling in series views.
# Now series and series_matrix have doubled code.
# Possible solutions:
# - Use only one view for series and series+category. As category page does
# - Use view context system. Category view does it too.
# Those solutions don't except each other.
if not options:
raise http.Http404('<h1>В секции нет изделий</h1')
return render(
request,
'catalog/series.html',
{
'products': series.options.active(),
'products': options,
'page': series.page,
}
)
Expand All @@ -219,14 +227,15 @@ def series(request, series_slug: str):
def series_by_category(request, series_slug: str, category_id: int):
series = get_object_or_404(models.Series.objects, slug=series_slug)
category = get_object_or_404(models.Category.objects, id=category_id)
# @todo #610:30m Return 404 if options list is empty not found.
options = (
models.Option.objects
.bind_fields()
.filter(series=series)
.filter_descendants(category)
.active()
)
if not options:
raise http.Http404('<h1>В секции нет изделий</h1')

return render(
request,
Expand Down
2 changes: 2 additions & 0 deletions templates/catalog/product.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<div class="option-order row">
<table class="options-table table">
<tr>
<th>Марка</th>
{% for group in tag_groups %}
<th>{{ group.name }}</th>
{% endfor %}
Expand All @@ -66,6 +67,7 @@
</tr>
{% for option in product.options.all %}
<tr>
<td class="option-td">{{ option.mark }}</td>
{% for group in tag_groups %}
<td class="option-td">
{% get_tag_name group option %}
Expand Down
2 changes: 1 addition & 1 deletion templates/search/items_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</td>
<td class="table-td table-name">
<a class="table-link" href="{{ item.get_absolute_url }}">
{{ item.catalog_name }}
{{ item.name }}
</a>
</td>
{% if item|hasattr_:'price' %}
Expand Down

4 comments on commit 0b17e23

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 0b17e23 Apr 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 142-0a53b98c disappeared from stroyprombeton/tests/tests_views.py, that's why I closed #211. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 0b17e23 Apr 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 610-5746c113 disappeared from stroyprombeton/views/catalog.py, that's why I closed #619. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 0b17e23 Apr 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 619-70cad134 discovered in stroyprombeton/views/catalog.py and submitted as #631. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 0b17e23 Apr 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 622-d7fa0399 discovered in stroyprombeton/tests/tests_views.py and submitted as #632. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.