Skip to content

Commit

Permalink
Merge branch 'master' into bg-product-pages-share
Browse files Browse the repository at this point in the history
  • Loading branch information
mmmavis committed Oct 19, 2018
2 parents afc7311 + 41f6b7e commit f8bcc1f
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 27 deletions.
20 changes: 20 additions & 0 deletions network-api/networkapi/buyersguide/migrations/0008_product_slug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-10-18 20:46
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('buyersguide', '0007_auto_20181012_2045'),
]

operations = [
migrations.AddField(
model_name='product',
name='slug',
field=models.CharField(blank=True, default=None, editable=False, help_text='slug used in urls', max_length=256, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-10-18 20:47
from __future__ import unicode_literals

from django.db import migrations
from django.utils.text import slugify


def generate_slugs(apps, schema_editor):
Product = apps.get_model('buyersguide', 'Product')
for product in Product.objects.all():
product.slug = slugify(product.name)
product.save()


def remove_slug():
# It's safe for these to just get deleted
pass


class Migration(migrations.Migration):

dependencies = [
('buyersguide', '0008_product_slug'),
]

operations = [
migrations.RunPython(generate_slugs, remove_slug)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.16 on 2018-10-18 20:53
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('buyersguide', '0009_auto_20181018_2047'),
]

operations = [
migrations.AlterField(
model_name='product',
name='slug',
field=models.CharField(blank=True, default=None, editable=False, help_text='slug used in urls', max_length=256),
),
]
14 changes: 14 additions & 0 deletions network-api/networkapi/buyersguide/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator
from django.forms import model_to_dict
from django.utils.text import slugify

from networkapi.buyersguide.validators import ValueListValidator
from networkapi.utility.images import get_image_upload_path
Expand Down Expand Up @@ -77,6 +78,14 @@ class Product(models.Model):
blank="True",
)

slug = models.CharField(
max_length=256,
help_text='slug used in urls',
blank=True,
default=None,
editable=False
)

company = models.CharField(
max_length=100,
help_text='Name of Company',
Expand Down Expand Up @@ -323,8 +332,13 @@ def votes(self):
def to_dict(self):
model_dict = model_to_dict(self)
model_dict['votes'] = self.votes
model_dict['slug'] = self.slug
return model_dict

def save(self, *args, **kwargs):
self.slug = slugify(self.name)
models.Model.save(self, *args, **kwargs)

def __str__(self):
return str(self.name)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ <h1 class="h1-heading text-center mt-4">Shop Safe This Holiday Season</h1>
<div class="recommendation stay-away m-2"></div>
{% endif %}
{% endif %}
<a class="" href="/privacynotincluded/products/{{ product.name | urlencode}}">
<a class="" href="/privacynotincluded/products/{{ product.slug }}">
<div>
<img src="{{mediaUrl}}{{"AWS_LOCATION"|env}}/{{product.image }}">
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ <h1 class="h3-heading">{{ category.name }}</h1>
<div class="categories-container">
{% for product in products %}
<div class="category-item-container" >
<a class="" href="/privacynotincluded/products/{{ product.name | urlencode }}">
<a class="" href="/privacynotincluded/products/{{ product.slug }}">
<div class="category-image-container">
<img src="{{mediaUrl}}{{"AWS_LOCATION"|env}}/{{product.image }}">
<img src="{{ mediaUrl }}{{ "AWS_LOCATION" | env }}/{{ product.image }}">
</div>
<h3 class="mb-2 h6-heading-uppercase">{{ product.company }}</h3>
<h3 class="mb-5 h5-heading">{{ product.name }}</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ <h3 class="h3-heading mb-3 mt-5">Related Products</h3>
<div class="row">
{% for product in product.related_products %}
<div class="col-12 col-md-3">
<a href="/privacynotincluded/products/{{ product.name }}">
<a href="/privacynotincluded/products/{{ product.slug }}">
<img src="{{mediaUrl}}{{"AWS_LOCATION"|env}}/{{product.image}}"/>
</a>
</div>
Expand Down
15 changes: 14 additions & 1 deletion network-api/networkapi/buyersguide/tests.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from django.contrib.auth.models import User
from django.http import Http404
from django.urls import reverse
from django.utils.text import slugify
from rest_framework.test import APITestCase
from django.test import TestCase, RequestFactory

from networkapi.buyersguide.factory import ProductFactory
from networkapi.buyersguide.models import RangeVote, BooleanVote
from networkapi.buyersguide.models import RangeVote, BooleanVote, Product
from networkapi.buyersguide.views import buyersguide_home, product_view, category_view
from django.core.management import call_command

Expand Down Expand Up @@ -337,3 +338,15 @@ def test_category_view_404(self):
request = self.factory.get('/privacynotincluded/categories/this is not a category')
request.user = self.user
self.assertRaises(Http404, category_view, request, 'this is not a category')


class ProductTests(TestCase):
def test_product_slug(self):
p = Product.objects.create(name='this name should get slugified')
self.assertEqual(p.slug, slugify(p.name))

def name_change_changes_slug(self):
p = Product.objects.create(name='this will change')
p.name = 'name changed'
p.save()
self.assertEqual(p.slug, slugify(p.name))
2 changes: 1 addition & 1 deletion network-api/networkapi/buyersguide/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
url(r'^$', views.buyersguide_home, name='buyersguide-home'),
url(r'^about/', views.about_view, name='about-view'),
url(r'^categories/(?P<categoryname>[\w\W]+)/', views.category_view, name='category-view'),
url(r'^products/(?P<productname>[\w ]+)/', views.product_view, name='product-view'),
url(r'^products/(?P<slug>[-\w]+)/$', views.product_view, name='product-view'),
url(r'^vote$', views.product_vote, name='product-vote'),
]
11 changes: 2 additions & 9 deletions network-api/networkapi/buyersguide/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import Error
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.views.decorators.csrf import csrf_protect
from rest_framework.parsers import JSONParser
Expand All @@ -28,9 +27,6 @@ def get_average_creepiness(product):
return 50


# Login required so we can continue to develop this and merge into master without the public seeing it.
# Remove this when we're ready to launch.
@login_required
def buyersguide_home(request):
products = [p.to_dict() for p in Product.objects.all()]
products.sort(key=lambda p: get_average_creepiness(p))
Expand All @@ -41,7 +37,6 @@ def buyersguide_home(request):
})


@login_required
def category_view(request, categoryname):
category = get_object_or_404(BuyersGuideProductCategory, name__iexact=categoryname)
products = [p.to_dict() for p in Product.objects.filter(product_category__in=[category]).distinct()]
Expand All @@ -53,9 +48,8 @@ def category_view(request, categoryname):
})


@login_required
def product_view(request, productname):
product = get_object_or_404(Product, name__iexact=productname)
def product_view(request, slug):
product = get_object_or_404(Product, slug=slug)
return render(request, 'product_page.html', {
'categories': BuyersGuideProductCategory.objects.all(),
'product': product.to_dict(),
Expand All @@ -64,7 +58,6 @@ def product_view(request, productname):
})


@login_required
def about_view(request):
return render(request, 'about.html', {
'categories': BuyersGuideProductCategory.objects.all(),
Expand Down
33 changes: 28 additions & 5 deletions source/js/buyers-guide/components/creep-vote/creep-vote.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,41 @@ import CreepChart from '../creepiness-chart/creepiness-chart.jsx';
import LikelyhoodChart from '../likelyhood-chart/likelyhood-chart.jsx';
import SocialShare from '../social-share/social-share.jsx';

import CREEPINESS_LABELS from "../creepiness-labels.js";

export default class CreepVote extends React.Component {
constructor(props) {
super(props);
this.state = this.getInitialState();
}

getInitialState() {
// let conf = this.props.votes.confidence;
let totalVotes = this.props.votes.total;
let votes = this.props.votes;
let totalVotes = votes.total;

let c_breakdown = votes.creepiness['vote_breakdown'];
let creepiness = 0;
let creepinessId = 0;

Object.keys(c_breakdown).forEach(id => {
let v = c_breakdown[id];
if (v>creepiness) {
creepiness = v;
creepinessId = id;
}
});

let confidence = votes.confidence;

return {
totalVotes,
creepiness: 50,
confidence: undefined,
didVote: false
didVote: false,
majority: {
creepiness: creepinessId,
confidence: confidence[0] > confidence[1] ? 0 : 1
}
};
}

Expand Down Expand Up @@ -96,19 +116,22 @@ export default class CreepVote extends React.Component {
* @returns {jsx} What users see when they haven't voted on this product yet.
*/
renderVoteAsk() {
let creepJudgement = CREEPINESS_LABELS[this.state.majority.creepiness].toLowerCase();
let confJudgement = this.state.majority.confidence ? `likely` : `not likely`;

return (<form method="post" id="creep-vote" onSubmit={evt => this.submitVote(evt)}>
<div className="row mb-5">
<div className="col-12 col-md-6">
<div className="mb-4 text-center">
<h3 className="h5-heading mb-2">How creepy is this product?</h3>
<p className="help-text">Majority of voters think it is super creepy</p>
<p className="help-text">Majority of voters think it is {creepJudgement}</p>
</div>
<Creepometer initialValue={this.state.creepiness} onChange={value => this.setCreepiness(value)}></Creepometer>
</div>
<div className="col-12 col-md-6">
<div className="mb-4 text-center">
<h3 className="h5-heading mb-2">How likely are you to buy it?</h3>
<p className="help-text">Majority of voters are not likely to buy it</p>
<p className="help-text">Majority of voters are {confJudgement} to buy it</p>
</div>
<div className="text-center">
<div class="btn-group btn-group-toggle mt-5" data-toggle="buttons">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import CREEPINESS_LABELS from "../creepiness-labels.js";

export default class CreepChart extends React.Component {
constructor(props) {
Expand All @@ -9,11 +10,11 @@ export default class CreepChart extends React.Component {
getInitialState() {
let values = this.props.values;
let data = [
{c: `no-creep`, label: `Not creepy`, value: values[0], offset: 0},
{c: `little-creep`, label: `A little creepy`, value: values[1], offset: 225},
{c: `somewhat-creep`, label: `Somewhat creepy`, value: values[2], offset: 475},
{c: `very-creep`, label: `Very creepy`, value: values[3], offset: 725},
{c: `super-creep`, label: `Super creepy`, value: values[4], offset: 975}
{c: `no-creep`, label: CREEPINESS_LABELS[0], value: values[0], offset: 0},
{c: `little-creep`, label: CREEPINESS_LABELS[1], value: values[1], offset: 225},
{c: `somewhat-creep`, label: CREEPINESS_LABELS[2], value: values[2], offset: 475},
{c: `very-creep`, label: CREEPINESS_LABELS[3], value: values[3], offset: 725},
{c: `super-creep`, label: CREEPINESS_LABELS[4], value: values[4], offset: 975}
];
let sum = data.reduce((tally, v) => tally + v.value, 0);

Expand Down
9 changes: 9 additions & 0 deletions source/js/buyers-guide/components/creepiness-labels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const CREEPINESS_LABELS = [
`Not creepy`,
`A little creepy`,
`Somewhat creepy`,
`Very creepy`,
`Super creepy`
];

export default CREEPINESS_LABELS;
3 changes: 1 addition & 2 deletions source/sass/buyers-guide/views/category.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
}

.category-image-container {
padding: 32.3% 0;
margin-bottom: 20px;
box-shadow: 0 0 1px 1px #e1e1e1;
overflow: hidden;
Expand All @@ -63,7 +62,7 @@
img {
display: block;
width: 100%;
transform: scale(3);
height: auto;
}

.category-item-label {
Expand Down

0 comments on commit f8bcc1f

Please sign in to comment.