This repository has been archived by the owner on Jan 31, 2018. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[bug 1086643] [bug 1086650] Redo infrastructure for product picker ve…
…rsion This redoes the infrastructure for having the generic form and the product-picker version of it "live" simultaneously. * nixed all the extra routing in favor of a waffle flag "feedbackdev" * extracted product-picker specific unit tests and put them in their own file * wrote a with_waffle class/function decorator that lets us more easily test waffley things * added WAFFLE_OVERRIDE=True to settings--we always want to be able to explicitly set the waffle flag via the url * added smoke tests for the dev form and product picker page
- Loading branch information
Showing
20 changed files
with
1,012 additions
and
275 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# -*- coding: utf-8 -*- | ||
import datetime | ||
from south.db import db | ||
from south.v2 import DataMigration | ||
from django.db import models | ||
|
||
class Migration(DataMigration): | ||
|
||
def forwards(self, orm): | ||
"Write your forwards methods here." | ||
# Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." | ||
# Adds the waffle flag for a/b testing. | ||
Flag = orm['waffle.flag'] | ||
flag = Flag( | ||
name='feedbackdev', | ||
everyone=False, | ||
superusers=False, | ||
staff=False, | ||
authenticated=False, | ||
rollout=False, | ||
note='', | ||
testing=False | ||
) | ||
flag.save() | ||
|
||
def backwards(self, orm): | ||
"Write your backwards methods here." | ||
Flag = orm['waffle.flag'] | ||
try: | ||
flag = Flag.objects.filter(name='feedbackdev')[0] | ||
flag.delete() | ||
except Flag.DoesNotExist: | ||
pass | ||
|
||
models = { | ||
u'auth.group': { | ||
'Meta': {'object_name': 'Group'}, | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), | ||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) | ||
}, | ||
u'auth.permission': { | ||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, | ||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | ||
}, | ||
u'auth.user': { | ||
'Meta': {'object_name': 'User'}, | ||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), | ||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), | ||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), | ||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), | ||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) | ||
}, | ||
u'base.profile': { | ||
'Meta': {'object_name': 'Profile'}, | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'}) | ||
}, | ||
u'contenttypes.contenttype': { | ||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, | ||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | ||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) | ||
}, | ||
u'waffle.flag': { | ||
'Meta': {'object_name': 'Flag'}, | ||
'authenticated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), | ||
'everyone': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), | ||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'languages': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), | ||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), | ||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
'percent': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '1', 'blank': 'True'}), | ||
'rollout': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'superusers': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | ||
'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'}) | ||
}, | ||
u'waffle.sample': { | ||
'Meta': {'object_name': 'Sample'}, | ||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), | ||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}), | ||
'percent': ('django.db.models.fields.DecimalField', [], {'max_digits': '4', 'decimal_places': '1'}) | ||
}, | ||
u'waffle.switch': { | ||
'Meta': {'object_name': 'Switch'}, | ||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), | ||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), | ||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}) | ||
} | ||
} | ||
|
||
complete_apps = ['waffle', 'base'] | ||
symmetrical = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 23 additions & 110 deletions
133
fjord/feedback/templates/feedback/generic_feedback.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,117 +1,30 @@ | ||
{% extends "feedback/base.html" %} | ||
|
||
{% block page_title %}{{ _('Submit Your Feedback') }}{% endblock %} | ||
|
||
{% set extra_body_attrs = {'data-form-name': 'generic'} %} | ||
|
||
{% block body %} | ||
<form id="responseform" action="" method="post"> | ||
<x-deck transition-type="slide-left"> | ||
<x-card id="intro"> | ||
<x-appbar> | ||
<header>{{ _('Submit Your Feedback') }}</header> | ||
</x-appbar> | ||
|
||
<section> | ||
<div id="sentiment"> | ||
<p>{{ _('Your feedback helps us improve Firefox.') }}</p> | ||
<div id="buttons"> | ||
<button class="happy">{{ _('Firefox made me happy') }}</button> | ||
<button class="sad">{{ _('Firefox made me sad') }}</button> | ||
</div> | ||
</div> | ||
|
||
<aside> | ||
<div> | ||
{% trans support_url='http://support.mozilla.org/' %} | ||
If you need help or have a problem | ||
with Firefox, please visit <a href="{{ support_url }}">Firefox Support</a>. | ||
{% endtrans %} | ||
</div> | ||
</aside> | ||
</section> | ||
</x-card> | ||
|
||
<x-card id="moreinfo"> | ||
<x-appbar> | ||
<button class="back"></button> | ||
<header>{{ _('Details') }}</header> | ||
</x-appbar> | ||
|
||
<section> | ||
<aside> | ||
<div> | ||
{% trans %} | ||
The content of your feedback will be public, so please be | ||
sure not to include any personal information. | ||
{% endtrans %} | ||
</div> | ||
</aside> | ||
|
||
<p> | ||
<label class="happy" for="description"> | ||
{{ _('Please describe what you liked.') }} | ||
</label> | ||
<label class="sad" for="description"> | ||
{{ _('Please describe your problem below.') }} | ||
{{ _('Please be as specific as you can.') }} | ||
</label> | ||
</p> | ||
|
||
<div id="description-counter"></div> | ||
<textarea data-max-length="10000" id="description" name="description" cols="40" rows="4"></textarea> | ||
|
||
<div> | ||
<label for="id_url"> | ||
{{ _('If your feedback is related to a website, you can include it here.') }} | ||
</label> | ||
<p>{{ form.url }}</p> | ||
{{ form.url.errors }} | ||
</div> | ||
|
||
<button id="description-next-btn" class="next btn submit">{{ _('Next') }}</button> | ||
</section> | ||
</x-card> | ||
|
||
<x-card id="email"> | ||
<x-appbar> | ||
<button class="back"></button> | ||
<header>{{ _('Can we contact you?') }}</header> | ||
</x-appbar> | ||
|
||
<section> | ||
<label class="email-ok"> | ||
<p> | ||
<input id="email-ok" type="checkbox" name="email_ok"/> | ||
{{ _('Check here to let us contact you to follow up on your feedback.') }} | ||
</p> | ||
</label> | ||
{% block site_css %} | ||
{% if waffle.flag('feedbackdev') %} | ||
{{ css('generic_feedback_dev') }} | ||
{% else %} | ||
{{ css('generic_feedback') }} | ||
{% endif %} | ||
{% endblock %} | ||
|
||
<div id="email-details"> | ||
<label for="id_email"> | ||
{{ _('Email address (optional):') }} | ||
</label> | ||
<p>{{ form.email }}</p> | ||
{{ form.email.errors }} | ||
{% block site_js %} | ||
<script src="{{ settings.STATIC_URL }}js/lib/brick-1.0.0.byob.min.js"></script> | ||
{% if waffle.flag('feedbackdev') %} | ||
{{ js('generic_feedback_dev') }} | ||
{% else %} | ||
{{ js('generic_feedback') }} | ||
{% endif %} | ||
{% endblock %} | ||
|
||
<aside> | ||
<div> | ||
{% trans %} | ||
While your feedback will be publicly visible, email addresses are | ||
kept private. We understand your privacy is important. | ||
{% endtrans %} | ||
</div> | ||
</aside> | ||
</div> | ||
{% block page_title %}{% if waffle.flag('feedbackdev') %}[DEV] {% endif %}{{ _('Submit Your Feedback') }}{% endblock %} | ||
|
||
<button id="form-submit-btn" class="complete btn submit">{{ _('Send Feedback') }}</button> | ||
</section> | ||
</x-card> | ||
{% set extra_body_attrs = {'data-form-name': 'generic'} %} | ||
|
||
</x-deck> | ||
{% for hidden in form.hidden_fields() %} | ||
{{ hidden }} | ||
{% endfor %} | ||
{{ csrf() }} | ||
</form> | ||
{% block body %} | ||
{% if waffle.flag('feedbackdev') %} | ||
{% include 'feedback/generic_feedback_form_dev.html' %} | ||
{% else %} | ||
{% include 'feedback/generic_feedback_form.html' %} | ||
{% endif %} | ||
{% endblock %} |
Oops, something went wrong.