latest PDF - Read the Docs

fjord Documentation
Release 1.0.dev
Mozilla
January 20, 2015
Contents
1
Overview
2
Contents
2.1 Join this project! . . . . . . . . . . . . . .
2.2 Getting started . . . . . . . . . . . . . . .
2.3 Development workflow . . . . . . . . . . .
2.4 Project Conventions (git, l10n, Python, etc.)
2.5 Testing in Fjord . . . . . . . . . . . . . . .
2.6 Maintaining the db . . . . . . . . . . . . .
2.7 Maintaining ElasticSearch . . . . . . . . .
2.8 Maintaining l10n . . . . . . . . . . . . . .
2.9 Maintaining Vendor Library . . . . . . . .
1
.
.
.
.
.
.
.
.
.
3
3
4
10
11
14
16
18
19
21
3
Part 2: Using the Site
3.1 Feedback URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Heartbeat API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
25
26
35
4
Part 3: Maintaining The Site
4.1 Maintaining Fjord and Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Service Level Agreement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
41
44
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
ii
CHAPTER 1
Overview
Fjord is the software that runs Mozilla Input. The site has two sides to it: one for gathering product feedback and user
sentiment and the other for exposing that data and analytics on it. The Mozilla Input feedback site helps us understand
what 450 million users are thinking and makes it possible for us to catch issues we wouldn’t otherwise be able to know
about.
This is at heart a Django-powered site. It uses a MySQL database for data storage and an Elasticsearch cluster for
search, analytics and facets.
Project details:
wiki https://wiki.mozilla.org/Firefox/Input
code https://github.com/mozilla/fjord
new bugs https://bugzilla.mozilla.org/enter_bug.cgi?product=Input&rep_platform=all&op_sys=all
irc #input on irc.mozilla.org
mailing list https://mail.mozilla.org/listinfo/input-dev
get involved https://wiki.mozilla.org/Webdev/GetInvolved/input.mozilla.org
1
fjord Documentation, Release 1.0.dev
2
Chapter 1. Overview
CHAPTER 2
Contents
Want to contribute to Input? Then this is the section for you! Start with Join this project! which will guide you through
the rest.
2.1 Join this project!
Fjord is the software that runs Input (input.mozilla.org) which is one of several tools the Mozilla community uses
to gather user sentiment on Mozilla products. This data helps us track down problems, guide new development and
generally make Mozilla products better for users using them.
Interested in helping out? I hope so!
Generally we need help with:
1. Writing code, fixing bugs and writing tests.
2. Localizing.
3. Testing.
4. Improving the Fjord documentation.
5. Making Fjord easier for other people to contribute to.
Before contributing to Fjord, you should make sure you have done the following things:
1. Create a GitHub account. If you don’t want to, that’s ok, but it does make the workflow a little harder. If you’re
new to git or development, we suggest you create a GitHub account since it’ll reduce some of the complexities
in submitting changes.
2. Join the input-dev mailing list. We send status reports, development environment change notices and other
things to the mailing list. Plus it keeps an archive and it makes it possible for us to work together even if we’re
not all in the same time zone. Plus this is the best way to get help when you’re having trouble.
3. Say “hi!” on the #input IRC channel on irc.mozilla.org. If no one says anything back, it’s possible no one
is awake. However, if people are awake, someone will definitely reply and this is one of the best ways to get
familiar with who’s who and one of the places you can go to get help when you’re having trouble.
After you’ve done all that, it’s time to set up a development environment. For that, see the Getting started.
After that, check out our GetInolved page which lists mentored bugs.
If you have problems, please let us know! See Overview.
3
fjord Documentation, Release 1.0.dev
2.2 Getting started
•
•
•
•
•
•
•
•
•
Getting the requirements
Download Fjord
Fix the version mismatch between Virtualbox and the Virtualbox Guest Additions
Building a vm and booting it
Setting up Fjord
Editing code and running it
Getting more sample data
Virtual machine maintenance commands
manage.py commands
– generatedata
– runserver
– collectstatic
– test
– migrate
– shell
– esreindex and esstatus
– update_product_details
– ihavepower
• Helpful tips
– Flushing the cache
– Issues with commit timestamps
• Where to go from here?
This guide walks through getting a development environment set up to allow you to contribute to Fjord.
Note: This definitely works for Mac OSX and Linux and probably works for Windows, too. If you have issues, please
let us know.
2.2.1 Getting the requirements
1. Download and install git if you don’t have it already: http://git-scm.com/
Note: Windows users: When you install git, make sure to choose “Checkout as-is, commit Unix-style line
endings”. If you don’t, then you’ll end up with Windows-style line endings in your checkout and Fjord won’t
work in the virtual machine.
2. Download and install VirtualBox if you don’t have it already: https://www.virtualbox.org/
3. Download and install Vagrant if you don’t have it already: http://www.vagrantup.com/
2.2.2 Download Fjord
If you have a GitHub account, you should fork the Fjord repository and then clone your fork:
git clone https://github.com/<USERNAME>/fjord.git
If you do not have a GitHub account, that’s ok! Clone the official Fjord repository this way:
4
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
git clone https://github.com/mozilla/fjord.git
This creates a directory called fjord/. We’ll call that the “Fjord repository top-level directory”.
2.2.3 Fix the version mismatch between Virtualbox and the Virtualbox Guest Additions
It’s likely there will be a version mismatch between the version of Virtualbox you’re using and the version of the
Virtualbox Guest Additions in the image you’re going to use.
If you’re using Mac OSX or Linux, you can do this from the Fjord repository top-level directory:
./bin/vagrant_fix_guest_additions.sh
If you’re not using Mac OSX or Linux or that doesn’t work, then you can do it by hand:
# Installs the VirtualBox Guest plugin
vagrant plugin install vagrant-vbguest
# Creates and launches the vm without provisioning it
vagrant up --no-provision
# Runs a command in the vm to remove the packages in the vm that
# are the cause of the mismatch
vagrant ssh -c ’sudo apt-get -y -q purge virtualbox-guest-dkms virtualbox-guest-utils virtualbox-gues
# Halts the vm so you can move onwards
vagrant halt
After that, the versions of the two things should be the same and you should be good to go to the next step.
2.2.4 Building a vm and booting it
This will build a VirtualBox vm using Vagrant. The vm will have Ubuntu Linux 14.04 installed in it. Fjord works in
this environment.
Run this commands in the Fjord repository top-level directory:
vagrant up
It takes a while the first time you do this since it has to create the virtual machine and provision it. First it downloads
an Ubuntu Linux 14.04 image (~300mb), then it installs some software in this image like MySQL and Elasticsearch.
Then it sets things up so that Fjord runs in this VM using the files on your machine. This allows you to use whatever
editor you like on your machine to edit code that runs in the VM without having to copy files around.
2.2.5 Setting up Fjord
After you’ve created a vm, we have some minor setup to do:
# Create a shell on the guest virtual machine
vagrant ssh
# Change into the fjord/ directory
cd ~/fjord
2.2. Getting started
5
fjord Documentation, Release 1.0.dev
First we download all the product detail data:
# Update product details
./manage.py update_product_details -f
Then we set up the database:
# Create the database and a superuser
./manage.py syncdb
# Run the db migrations
./manage.py migrate
It will ask if you want to create a superuser. You totally do! Create a superuser that you’ll use to log into Fjord.
The username and password don’t matter, but the email address does. You must choose an email address that is your
Persona identity. If you don’t have a Persona identity, you can create one at the Persona site.
Note: You can create a superuser at any time by doing:
./manage.py createsuperuser
Additionally, you can convert any account into a superuser account by doing:
./manage.py ihavepower <email-address>
After that, let’s generate some data in the database so that we have something to look at. We’ll then need to index that
data so it shows up in searches.
# Generate sample data
./manage.py generatedata
# Index the sample data into Elasticsearch
./manage.py esreindex
That’s it!
2.2.6 Editing code and running it
Fjord is a Django project. We use the Django runserver to run the website to test it.
First, if you haven’t got a running virtual machine, launch it with:
vagrant up
Then, ssh into the virtual machine:
vagrant ssh
This gives you a shell in the virtual machine that lets you run all the Django commands, run the test suite, etc.
To launch the Django runserver, use the vagrant ssh shell and do:
cd ~/fjord
./manage.py runserver 0.0.0.0:8000
Then on your host computer, use your browser and go to http://127.0.0.1:8000. You should see Fjord.
6
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
2.2.7 Getting more sample data
Sample data is tied to a specific moment in time. You’ll need to run the generatedata command every time you need
fresh data.
The generatedata command only generates data and saves it to the db. After running generatedata, you’ll need to add
that data to the Elasticsearch index:
./manage.py generatedata
./manage.py esreindex
Note: You can call generadata as many times as you like.
2.2.8 Virtual machine maintenance commands
Command to run on host
vagrant up
vagrant ssh
vagrant halt
vagrant status
vagrant destroy
Explanation
Launches the vm
SSHs to the vm
Halts the vm
Status of the vm
Destroys the vm (not recoverable!)
See more in the Vagrant documentation. If you have questions, let us know.
2.2.9 manage.py commands
You can see the complete list of ./manage.py commands by typing:
./manage.py
For each command, you can get help by typing:
./manage.py <COMMAND> --help
We use the following ones pretty often:
Command
generatedata
runserver
collectstatic
test
migrate
shell
esreindex
esstatus
update_product_details
ihavepower
Explanation
Generates fake data so Fjord works
Runs the Django server
Collects static files and “compiles” them
Runs the unit tests
Migrates the db with all the migrations specified in the repository
Opens a Python REPL in the Django context for debugging
Reindexes all the db data into Elasticsearch
Shows the status of things in Elasticsearch
Updates the product details with the latest information
Turns a user account into a superuser
generatedata
You can get sample data in your db by running:
./manage.py generatedata
2.2. Getting started
7
fjord Documentation, Release 1.0.dev
This will generate 5 happy things and 5 sad things so that your Fjord instance has something to look at.
If you want to generate a lot of random sample data, then do:
./manage.py generatedata --with=samplesize=1000
That’ll generate 1000 random responses. You can re-run that and also pass it different amounts. It’ll generate random
sample data starting at now and working backwards.
runserver
Vagrant sets up a forward between your host machine and the guest machine. You need to run the runserver in a way
that binds to all the ip addresses.
Run it like this:
./manage.py runserver 0.0.0.0:8000
collectstatic
When you’re running the dev server (i.e. ./manage.py runserver ...), Fjord compiles the LESS files to CSS
files and serves them individually. When you’re running Fjord in a server environment, you run:
./manage.py collectstatic
to compile the LESS files to CSS files and then bundle the CSS files and JS files into single files and minify them. This
reduces the number of HTTP requests the browser has to make to fetch all the relevant CSS and JS files for a page. It
makes our pages load faster.
However, a handful of tests depend on the bundles being built and will fail unless you run collectstatic first.
test
The test suite will create and use this database, to keep any data in your development database safe from tests.
Before you run the tests, make sure you run collectstatic:
./manage.py collectstatic
I run this any time I run the tests with a clean database.
The test suite is run like this:
./manage.py test
For more information about running the tests, writing tests, flags you can pass, running specific tests and other such
things, see the test documentation.
migrate
Over time, code changes to Fjord require changes to the database. We create migrations that change the database from
one version to the next. Whenever there are new migrations, you’ll need to apply them to your database so that your
database version is the version appropriate for the codebase.
To apply database migrations, do this:
8
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
./manage.py migrate
For more information on the database and migrations, see Maintaining the db.
shell
This allows you to open up a Python REPL in the context of the Django project. Do this:
./manage.py shell
esreindex and esstatus
Fjord uses Elasticsearch to index all the feedback responses in a form that’s focused on search. The front page
dashboard and other parts of the site look at the data in Elasticsearch to do what they do. Thus if you have no data in
Elasticsearch, those parts of the site won’t work.
To reindex all the data into Elasticsearch, do:
./manage.py esreindex
If you want to see the status of Elasticsearch configuration, indexes, doctypes, etc, do:
./manage.py esstatus
update_product_details
Event data like Firefox releases and locale data are all located on a server far far away. Fjord keeps a copy of the
product details local because it requires this to run.
Periodically you want to update your local copy of the data. You can do that by running:
./manage.py update_product_details
ihavepower
If you create an account on Fjord and want to turn it into a superuser account that can access the admin, then you need
to grant that account superuser/admin status. To do that, do:
./manage.py ihavepower <email-address>
2.2.10 Helpful tips
Flushing the cache
We use memcached for caching. to flush the cache, do:
echo "flush_all" | nc localhost 11211
2.2. Getting started
9
fjord Documentation, Release 1.0.dev
Issues with commit timestamps
The Ubuntu image that we are using, has UTC as the configured timezone. Due to this, if you are in a different
timezone and make commits from the VM, the commit timestamps will have a different timezone when compared to
the timezone on the host computer. To have matching timezone on the host and the VM, run:
sudo dpkg-reconfigure tzdata
and select your current timezone as the timezone for the VM.
2.2.11 Where to go from here?
Project Conventions (git, l10n, Python, etc.) covers project conventions for Python, JavaScript, git usage, etc.
Development workflow covers the general workflow for taking a bug, working on it and submitting your changes.
Maintaining the db covers database-related things like updating your database with new migrations, creating migrations, etc.
Maintaining ElasticSearch covers Elasticsearch-related things like maintaining your Elasticsearch index, reindexing,
getting status, deleting the index and debugging tools.
Maintaining l10n covers how we do localization in Fjord like links to the svn repository where .po files are stored,
Verbatim links, getting localized strings, updating strings in Verbatim with new strings, testing strings with Dennis,
linting strings, creating new locales, etc.
Testing in Fjord covers testing in Fjord like running the tests, various arguments you can pass to the test runner to
make debugging easier, running specific tests, writing tests, the smoketest system, JavaScript tests, etc.
Maintaining Vendor Library covers maintaining vendor/ and the Python library dependencies in there.
2.3 Development workflow
2.3.1 Taking a bug, working on it, sending in changes
You found a bug you want to work on! Great! Here’s how it works:
1. Comment in the bug that you want to take it. We’ll talk with you and if it sounds like it’s a good fit, we’ll assign
it to you.
2. Create a new branch. I use the bug number, but it doesn’t matter what the branch is named. For example:
git checkout -b 1026503-vagrant-work
3. Work on the changes. Commit your changes to your branch.
4. Go through your changes and make sure they respect our project conventions. They’re listed in Project Conventions (git, l10n, Python, etc.).
FIXME - We should add a script that lints PEP-8, jslint, etc issues so we don’t have to think about those.
5. Send the changes in.
If you have a GitHub account:
(a) Push your branch to your fork on GitHub.
(b) Create a Pull Request.
If you don’t have a GitHub account:
10
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
(a) Use git format-patch to generate a patch:
git format-patch --stdout master > bug_<id>.patch
(b) Attach the patch to the bug.
6. Then we’ll talk about the changes and when they’re good to land, someone with commit permissions will land
them.
2.4 Project Conventions (git, l10n, Python, etc.)
• Coding conventions
– Git pre-commit hook
– Python conventions
– JavaScript
• Git conventions
– Git commit messages
• Localization conventions
– Strings
– Good Practices
– Testing strings
This document contains coding conventions, and things to watch out for, etc.
2.4.1 Coding conventions
Git pre-commit hook
We have a Git pre-commit hook that makes it easier to make sure you’re checking in linted code. To set it up, run:
$ ./bin/hooks/lint.pre-commit
That’ll set up the pre-commit hook. After that, every time you commit something in Git, it’ll run the hook first and if
everything is fine continue with the commit. If things are not fine, it’ll notify you and stop.
Python conventions
Follow PEP-8 for code and PEP-257 for docstrings.
If you don’t have an editor that checks PEP-8 issues and runs pyflakes for you, it’s worth setting it up.
You can also use the linting script bin/flake8_lint.sh:
$ ./bin/flake8_lint.sh <files-to-lint>
JavaScript
Use jshint for JavaScript code. This is automatically done in the pre-commit hook.
Use jsdoc for JavaScript function documentation.
2.4. Project Conventions (git, l10n, Python, etc.)
11
fjord Documentation, Release 1.0.dev
2.4.2 Git conventions
Git commit messages
Git commit messages should have the following form:
[bug xxxxxxx] Short summary
Longer explanation with paragraphs and lists and all that where
each line is under 72 characters.
* bullet 1
* bullet 2
Etc. etc.
Summary line should be capitalized, short and shouldn’t exceed 50 characters. Why? Because this is a convention
many git tools take advantage of.
If the commit relates to a bug, the bug should show up in the summary line in brackets.
Lines shouldn’t exceed 72 characters.
See these guidelines for some more explanation.
2.4.3 Localization conventions
Strings
You can localize strings both in Python code as well as Jinja templates.
In Python:
from tower import ugettext as _, ugettext_lazy as _lazy
yodawg = _lazy(’The Internet’)
def myview(request):
return render(’template.html’, {msg=_(’Hello World’), msg2=yodawg})
_lazy is used when we are not in scope of a request. This lets us evaluate a string, such as yodawg, at the last possible
second when we finally can draw upon the request’s context. E.g. in a template:
{{ msg2 }}
Will be evaluated to whatever The Internet is in the requester’s locale.
In Jinja we can use the following syntax for localized strings:
<h1>{{ _(’Hello’) }}</h1>
{% trans link=’http://mozilla.org’ %}
<p>Go to this <a href="{{ link }}">site</a>.</p>
{% endtrans %}
Good Practices
Let’s say you have some template:
12
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
<h1>Hello</h1>
<p>
Is it <a href="http://about.me/lionel.richie">me</a> you’re
looking for?
</p>
Let’s say you are told to translate this. You could do the following:
{% trans %}
<h1>Hello</h1>
<p>
Is it <a href="http://about.me/yo">me</a> you’re looking for?
</p>
{% endtrans %}
This has a few problems, however:
1. It forces every localizer to mimic your HTML, potentially breaking it.
2. If you decide to change the HTML, you need to either update your .po files or buy all your localizers a nice gift
because of all the pain you’re inflicting upon them.
3. If the URL changes, your localizer has to update everything.
Here’s an alternative:
<h1>_(’Hello’)</h1>
<p>
{% trans about_url=’http://about.me/lionel.richie’ %}
Is it <a href="{{ about_url }}">me</a> you’re looking for?
{% endtrans %}
</p>
or if you have multiple paragraphs:
<h1>_(’Hello’)</h1>
{% trans about_url=’http://about.me/lionel.richie’ %}
<p>
Is it <a href="{{ about_url }}">me</a> you’re looking for?
</p>
<p>
I can see it in your eyes.
</p>
{% endtrans %}
Here are the advantages:
1. Localizers have to do minimal HTML.
2. The links and even structure of the document can change, but the localizations can stay put.
Be mindful of work that localizers will have to do.
See also:
http://playdoh.readthedocs.org/en/latest/userguide/l10n.html#localization-l10n Localization (l10n) in the Playdoh docs
2.4. Project Conventions (git, l10n, Python, etc.)
13
fjord Documentation, Release 1.0.dev
Testing strings
Fjord comes with bin/test_locales.sh script which makes it pretty easy to test that strings in the user interface
are getting gettext’d. It creates a faux “Pirate” translation of the strings in the xx locale.
You need to install polib for the script to work:
$ pip install polib
After that, cd into the project directory and do:
$ bin/test_locales.sh
After that runs, you can see what happened by doing:
$ ./manage.py runserver 0.0.0.0:8000
and going to http://127.0.0.1:8000/xx/.
2.5 Testing in Fjord
Tests in Fjord allow us to make changes and be reasonably sure that the system continues to work. Further, they make
it easier to verify correctness for behavioral details.
2.5.1 Running tests
Setup
Before you run the tests, you have to run the collectstatic command. This compiles LESS files to CSS files and
creates the bundles that some of the tests require to run. If you don’t do this, then a few of the tests will fail.
To run collectstatic, do:
./manage.py collectstatic
You don’t have to do this often. I’d do it the first time and then any time you run the tests with a fresh db.
FIXME: This is annoying and it’d be nice to get it fixed.
Running tests and arguments
To run the test suite, do:
./manage.py test
The NOSE_ARGS setting in fjord/settings/local.py sets some default arguments so you don’t see tons and
tons and tons and tons and tons and tons and tons and tons and tons and tons and tons and tons and tons of debugging
output. Ew.
If you ever need to see that debugging, comment the arguments out.
The --nocapture flag is important if you want to be able to drop into PDB from within tests.
Other helpful flags when debugging are:
-x: Fast fail. Exit immediately on failure. No need to run the whole test suite if you already know something is
broken.
14
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
--pdb: Drop into PDB on an uncaught exception. (These show up as E or errors in the test results, not F or failures.)
--pdb-fail: Drop into PDB on a test failure. This usually drops you right at the assertion.
The test suite will create a new database named test_%s where %s is whatever value you have for
settings.DATABASES[’default’][’NAME’].
If you know there haven’t been any schema changes, you can run the tests with REUSE_DB=1 in the environment.
This will reuse the existing database:
REUSE_DB=1 ./manage.py test -s --noinput --logging-clear-handlers
Further, running the test suite can be a good way to suss out Python warnings and 2to3 problems. To do that, run the
test suite like this:
python -t -3 -Wd ./manage.py test
Argument explanations:
-t Issue warnings about inconsistent tab usage.
-3 Warns about Python 3.x incompatabilities that 2to3 can’t fix.
-Wd Enables default warnings.
See python -h for details and other arguments you can use.
Running specific tests
You can run part of the test suite by specifying the directories of the code you want to run, like:
./manage.py test fjord/feedback/tests
You can specify specific tests:
./manage.py test fjord.feedback.tests.test_ui:TestFeedback.test_happy_url
See the output of ./manage.py test --help for more arguments.
2.5.2 Writing New Tests
Code should be written so it can be tested, and then there should be tests for it.
When adding code to an app, tests should be added in that app that cover the new functionality. All apps have a tests
module where tests should go. They will be discovered automatically by the test runner as long as the look like a test.
• Avoid naming test files test_utils.py, since we use a library with the same name.
test__utils.py instead.
Use
• If you’re expecting reverse to return locales in the URL, use LocalizingClient instead of the default
client for the TestCase class.
• We
use
FactoryBoy
to
generate
model
instances
instead
of
using
fixtures.
fjord.feedback.tests.ResponseFactory generates fjord.feedback.models.Response
instances.
• To add a smoketest, see the README.rst file in the smoketests/ directory.
2.5. Testing in Fjord
15
fjord Documentation, Release 1.0.dev
2.5.3 Writing New JavaScript Tests
JavaScript tests are not run in our normal unit test suite. Instead we have a different test system.
We test JavaScript utility functions using QUnit.
These tests are located in fjord/base/static/tests/.
Running tests
Launch the server with:
./manage.py runserver
Then go to:
http://127.0.0.1:8000/static/tests/index.html
(You might have to use a different protocol, host and port depending on how you have Fjord set up.)
Adding tests
To add a new test suite, add a couple of script lines to index.html in the relevant place and then create a new
test_FILENAMEHERE.js file with your QUnit tests.
2.5.4 Changing tests
Unless the current behavior, and thus the test that verifies that behavior is correct, is demonstrably wrong, don’t change
tests. Tests may be refactored as long as its clear that the result is the same.
2.5.5 Removing tests
On those rare, wonderful occasions when we get to remove code, we should remove the tests for it, as well.
If we liberate some functionality into a new package, the tests for that functionality should move to that package, too.
2.6 Maintaining the db
2.6.1 Updating the db
If someone pushes changes that change the db, you’ll need to apply the new migrations to your db. Do this:
./manage.py syncdb
./manage.py migrate
2.6.2 Creating a schema migration
We use South for database migrations.
To create a new migration the automatic way:
1. make your model changes
16
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
2. run:
./manage.py schemamigration <app> --auto
where <app> is the app name (base, feedback, analytics, ...).
3. run the migration on your machine:
./manage.py migrate
4. run the tests to make sure everything works
5. add the new migration files to git
6. commit
See also:
http://south.readthedocs.org/en/latest/tutorial/index.html South tutorial
2.6.3 Creating a data migration
Creating data migrations is pretty straight-forward in most cases.
To create a data migration the automatic way:
1. run:
./manage.py datamigration <app> <name>
where <app> is the app name (base, feedback, analytics, ...) and <name> is the name of the migration
2. edit the data migration you just created to do what you need it to do
3. add the new migration file to git
4. commit
See also:
http://south.readthedocs.org/en/latest/tutorial/part3.html#data-migrations South tutorial: data migrations
Backwards migrations
Make sure to write backwards code if you can. If there’s no way to undo the migration, then do this:
def backwards(self, orm):
raise RuntimeError("Cannot reverse this migration.")
Data migrations for data in non-Fjord apps
If you’re doing a data migration that adds data to an app that’s not part of Fjord, but is instead a library (e.g. djangowaffle), then create the data migration in the base app and make sure to freeze the library app so that it’s available.
For example, this creates a waffle flag:
./manage.py datamigration base create_gengo_switch --freeze waffle
2.6. Maintaining the db
17
fjord Documentation, Release 1.0.dev
2.7 Maintaining ElasticSearch
2.7.1 Things to know about ElasticSearch
Input uses ElasticSearch to power search.
Input uses ElasticUtils to interface with ElasticSearch.
2.7.2 Command line tools
esreindex: indexing
Do a complete reindexing of everything by:
./manage.py esreindex
This will delete the existing index specified by ES_INDEXES, create a new one, and reindex everything in your
database.
If you need to get stuff done and don’t want to wait for a full indexing, you can index a percentage of things.
For example, this indexes 10% of your data ordered by id:
./manage.py esreindex --percent 10
This indexes 50% of your data ordered by id:
./manage.py esreindex --percent 50
I use this when I’m fiddling with mappings and the indexing code.
You can also specify which models to index:
./manage.py esreindex --models feedback_simple
See --help for more details:
./manage.py esreindex --help
Note: If you kick off indexing with the admin, then indexing gets done in chunks by celery tasks. If you need to halt
indexing, you can purge the tasks with:
./manage.py celeryctl purge
If you purge the tasks, you need to cancel outstanding records. Run this sql in mysql:
UPDATE search_record SET status=2 WHERE status=0 or status=1;
If you do this often, it helps to write a shell script for it.
esstatus: health/statistics
You can see ElasticSearch index status with:
./manage.py esstatus
This lists the indexes, tells you which ones are set to read and write, and tells you how many documents are in the
indexes by mapping type.
18
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
esdelete: deleting indexes
You can use the search admin to delete the index.
On the command line, you can do:
./manage.py esdelete <index-name>
2.7.3 Live Indexing
When you add data to the database, it needs to be added to the index. If the setting ES_LIVE_INDEX is True, then
this will be handled automatically in the post_save hook as long as celery tasks are being handled.
For celery tasks to be handled, you have to either have CELERY_ALWAYS_EAGER set to True, or have at least one
celery worker running, and RabbitMQ working.
Index Maintenance
If you don’t want live indexing, you can also reindex everything using the admin or using the esreindex command-line
tool, as detailed above.
2.7.4 Debugging tools
See ElasticUtils documentation for debugging tools and tips.
2.8 Maintaining l10n
2.8.1 Things to know about l10n
1. translations are done in Verbatim
2. translators are looking at our -dev environment to see the strings in use
3. the -dev environment should have a cronjob kicking off every 10 minutes that updates the svn locale repository
so that translators can see the latest stuff
svn url https://svn.mozilla.org/projects/l10n-misc/trunk/input/locale
viewvc svn http://viewvc.svn.mozilla.org/vc/projects/l10n-misc/trunk/input/locale/
Verbatim https://localize.mozilla.org/projects/input/
2.8.2 Installing localizations from svn
Localizations are not stored in this repository–they’re in Mozilla’s subversion repository.
To get the localizations, do:
cd locale
svn checkout https://svn.mozilla.org/projects/l10n-misc/trunk/input/locale locale
To see the translated strings, you need to first compile the .po files to .mo files:
2.8. Maintaining l10n
19
fjord Documentation, Release 1.0.dev
./bin/compile-mo.sh locale/
2.8.3 Extract/merge/sync strings with svn
First, ping Kadir (or whoever else) and tell him/her we’re merging strings (i.e. extracting them from our codebase and
committing the changes to svn).
Then, update the svn repository:
cd locale
svn update
cd ..
Then, extract the strings from the codebase:
./manage.py extract
./manage.py merge
Then, commit the new strings to svn:
cd locale
svn commit -m ’Input strings update YYYY/MM/DD’
Then, tell him/her that the strings have been extracted. He/she will update Verbatim for all locales.
Note: There are also instructions in ./locale/README.txt.
After that, send an email to the dev-l10n-web mailing list using this template:
Hi!
I’ve just pushed new strings to Verbatim for Input.
https://localize.mozilla.org/projects/input/
< explanation of strings changes here >
To give you an idea of how many untranslated strings there are, I
have computed this list:
< copy and paste output of "./bin/stats-po.sh locale/" >
If you have any questions, please reply to the list.
Thank you so much for your help!
Input development team
Sometimes we have to create bugs for each individual locale to update the translations. It’s nice to copy/paste the
specific strings that need to be translated.
Sometimes the translator says they’ve finished, but the string updates aren’t in svn. If that happens, tell the translator
that they have to push the “Commit to VCS” button/link.
2.8.4 Creating new localization locales
FIXME: This section is probably wrong.
20
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
In your projects settings.py add the new locale to KNOWN_LANGUAGES.
Then run:
$ ./manage.py merge -c
which will create directories for any locales that are missing in locale/.
See also:
http://playdoh.readthedocs.org/en/latest/userguide/l10n.html#creating-new-locales Playdoh docs on creating
new locales
2.9 Maintaining Vendor Library
To help make setup faster and deployment easier, we pull all of our pure-Python dependencies into the “vendor library”.
This chapter talks about that.
• vendor
• Updating vendor
– Updating an existing library with git submodules
– Adding a new library with git submodules
– Updating a library with pip
– Adding a library with pip
2.9.1 vendor
The vendor/ directory contains git submodules and unpacked source for dependencies.
If you cloned Fjord with --recursive, you already have the the vendor library.
If you didn’t clone with --recursive, or you need to update the submodules, run:
$ git submodule update --init --recursive
Note: Aliasing that to something short (e.g. gsu) is recommended.
2.9.2 Updating vendor
From time to time we need to update libraries, either for new versions of libraries or to add a new library. There are
two ways to do that, but the easiest and prefered way is pure git.
Updating an existing library with git submodules
Using git submodules is prefered because it is much easier to maintain, and it keeps the repository size small. Upgrading is as simple as updating a submodule.
If the library is in vendor/src, it was pulled directly from version control, and if that version control was git,
updating the submodule is as easy as:
2.9. Maintaining Vendor Library
21
fjord Documentation, Release 1.0.dev
$
$
$
$
$
$
cd vendor/src/<LIBRARY-DIR>
git fetch origin
git checkout <REFSPEC>
cd ../..
git add vendor/src/<LIBRARY-DIR>
git commit -m "[bug xyz] Update <LIBRARY>"
Easy peasy!
Adding a new library with git submodules
Run:
$
$
$
$
$
$
$
cd vendor/src
git clone <LIBRARY-REPO>
cd <LIBRARY-DIR>
git checkout <LIBRARY-REPO-REV>
cd ../../..
vendor/addsubmodules.sh
vim vendor/vendor.pth
# back to fjord project root
<Add the new library’s dir to vendor.pth>
$ git add vendor/vendor.pth
$ git commit -m "[bug xyz] Add <LIBRARY>"
Updating a library with pip
The easiest way to update a library with pip is to remove it completely and then install the new version.
Do:
$ cd vendor/packages
$ git rm -r <LIBRARY-DIR>
$ cd ../..
This puts you in the repository root directory.
After removing the old version, go ahead and install the new one:
$ pip install --no-install --build=vendor/packages \
--src=vendor/src -I <LIBRARY>
Finally, add the new library to git:
$ cd vendor
$ git add packages
$ git commit -m "Adding version <VERSION> of <LIBRARY>"
Warning: Caveat developer! Sometimes a library has dependencies that are already installed in the vendor repo.
You may need to remove several of them to make everything work easily.
Adding a library with pip
Adding a new library with pip is easy using pip:
22
Chapter 2. Contents
fjord Documentation, Release 1.0.dev
$ pip install --no-install --build=vendor/packages \
--src=vendor/src -I <LIBRARY>
$ cd vendor
$ git add <LIBRARY>
$ vim vendor.pth
<Add the new library’s path>
$ git commit -m "Adding <LIBRARY>"
Make sure you add any dependencies from the new library, as well.
Note: Need to add a specific version of the library? You can tell pip to install a specific version using ==. For
example:
$ pip install --no-install --build=vendor/packages \
--src=vendor/src -I pyes==0.16
2.9. Maintaining Vendor Library
23
fjord Documentation, Release 1.0.dev
24
Chapter 2. Contents
CHAPTER 3
Part 2: Using the Site
Are you an Input user? This is the section for you!
3.1 Feedback URLs
3.1.1 Generic URL
The basic URL is this:
https://input.mozilla.org/feedback
Users sent to that URL will be redirected to a locale-based URL based on the HTTP headers their browser sends.
The locale-base URL version of this URL will show the product picker letting the user pick the product they want to
leave feedback for.
However, you probably don’t want to use the Generic URL—you know what product you’re asking users to leave
feedback for, so you should provide the product in the url.
3.1.2 Product URLs
Product urls have this form:
https://input.mozilla.org/feedback/%PRODUCT%/%VERSION%/
https://input.mozilla.org/%LOCALE%/feedback/%PRODUCT%/%VERSION%/
This allows you to specify the locale, product and version.
locale You can provide this if you know what locale you want the user to leave feedback for.
Alternatively, you can leave this out and the user will see the feedback form in a locale based on the HTTP
headers of the request.
product The product is the slug of the product that is set up on Input. If you haven’t had your product set up on
Input, you must do that first. Please file a bug.
version Any string that represents the product version. e.g. 3.0, 33.1.1, etc.
Examples:
Firefox desktop:
25
fjord Documentation, Release 1.0.dev
https://input.mozilla.org/feedback/firefox
https://input.mozilla.org/en-US/feedback/firefox
https://input.mozilla.org/pt-BR/feedback/firefox/29.0
Firefox for Android:
https://input.mozilla.org/feedback/android
https://input.mozilla.org/en-US/feedback/android
https://input.mozilla.org/de/feedback/android/29.0
Firefox OS:
https://input.mozilla.org/feedback/fxos
https://input.mozilla.org/en-US/feedback/fxos
https://input.mozilla.org/es/feedback/fxos/1.3.0.0
3.1.3 Source/Campaign
If you’re writing an email, blog post, tweet, whatever and link to Input feedback form, you should specify the
utm_source and utm_campaign querystring parameters. For example:
https://input.mozilla.org/feedback/firefox?utm_source=wiki&utm_campaign=wiki_example
For example, you have a link in the Help menu of the product, you would probably use:
utm_source=helpmenu
For example, if you wrote up a blog post on a blog called “Sam’s Dev Blog” asking people for their feedback because
you’ve made some change, you would probably use:
utm_source=samsdevblog&utm_campaign=20141124_feedback_request
Note: When you specify utm_campaign the resulting feedback is considered non-organic feedback because you
requested the feedback. This is distinguished from organic feedback where the user leaves feedback as they so desire.
3.2 API
26
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
• Getting product feedback: GET /api/v1/feedback/
– Filters
– Examples
• Posting product feedback: POST /api/v1/feedback/
– Testing clients using the API
– Required fields
– Optional fields
– Extra context
– Minimal example with curl
– Responses
• Getting event data: /api/v1/events/
– Filters
– Curl example
• Posting heartbeat feedback: /api/v1/hb/
– Testing clients using the API
– Required fields
– Curl examples
Fjord has several POST APIs and one GET API for data.
3.2.1 Getting product feedback: GET /api/v1/feedback/
URL /api/v1/feedback/
Method HTTP GET
Payload format No payload–everything is done in the querystring
Response JSON
Doing a GET without any querystring arguments will return the most recent 1,000 publicly visible responses for all
products.
Warning: This API endpoint is throttled. If you hit it too often, you’ll get throttled. You just need to wait a bit
for the throttle to expire.
Note: This API endpoint is still in flux. The documentation is rudimentary at best. Amongst other things, it’s difficult
to discover valid values for things.
If you’re using this API endpoint and have issues, please open a bug.
Filters
q String. Text query.
Example:
?q=crash
happy Boolean. 0 or 1. Restricts results to either happy feedback or sad feedback.
Example:
?happy=0
3.2. API
27
fjord Documentation, Release 1.0.dev
platforms Strings. Comma separated list of platforms. For valid platforms, see https://input.mozilla.org/.
Examples:
?platforms=linux
?platforms=linux,os x
locales Strings. Comma separated list of locales. For valid locales, see https://input.mozilla.org/.
Examples:
?locales=en-US
?locales=en-US,es,es-BR
products Strings. Comma separated list of products. For valid products, see https://input.mozilla.org/.
Examples:
?products=Firefox
?products=Firefox OS,Firefox
versions Strings.
Comma separated list of versions for a specific product.
https://input.mozilla.org/.
For valid versions, see
You must specify a product in order to specify versions.
Examples:
?products=Firefox&versions=31.0
?products=Firefox&versions=31.0,32.0
date_start Date in YYYY-MM-DD format. Specifies the start for the date range you’re querying for.
Example:
?date_start=2014-08-12
date_end Date in YYYY-MM-DD format. Specifies the end for the date range you’re querying for.
Defaults to today.
Example:
?date_end=2014-08-12
date_delta String. 1d, 7d, 14d, etc. The number of days from date_start or date_end.
Example:
# Shows the last 7 days ending today
?date_delta=7d
# Shows 14 days ending 2014-08-12
?date_end=2014-08-12&date_delta=14d
# Shows 22 days starting 2014-08-12
?date_start=2014-08-12&date_delta=22d
max
Integer. Defaults to 1,000. Maximum is 10,000. Minimum is 1. The maximum number of responses you
want to get back.
Example:
28
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
# Retrieve at most 500 responses
?max=500
# Retrieve at most 10000 responses
?max=10000
Examples
Show all the happy responses for Firefox for the last 7 days for the English locale:
?happy=1&products=Firefox&locales=en-US&date_delta=7d
Show sad responses for Windows platforms for the last day:
?happy=0&platforms=Windows 7,Windows XP, Windows 8.1,Windows 8,Windows Vista,Windows NT&date_delta=1d
3.2.2 Posting product feedback: POST /api/v1/feedback/
URL /api/v1/feedback/
Method HTTP POST
Payload format JSON—make sure to have Content-type:
application/json header
Testing clients using the API
Warning: DO NOT TEST YOUR CLIENT AGAINST OUR PRODUCTION SERVER. IT WILL MAKE
CHENG, MATT, TYLER AND I CROSS.
Seriously. Please don’t test your client against our production server.
Test your client against our stage server which runs the same code that our production server does. The url for the our
stage server is:
https://input.allizom.org/
^^^^^^^
Please make sure to use the correct domain!
Required fields
happy Boolean. All feedback is either happy or sad. This denotes whether this feedback is happy (True) or sad
(False).
Valid values: true, false
description String. Max length: None (but 10,000 characters is probably a good cutoff). This is the feedback text.
Example: "OMG! I love Firefox!"
Note: The form this field is on should have some informational text stating that data in this field will be publicly
available and that the user should not include personally identifyable information.
Example informational text:
3.2. API
29
fjord Documentation, Release 1.0.dev
The content of your feedback will be public, so please be sure
not to include any personal information.
product String. Max length: 20. The name of the product the user is giving feedback on.
Examples:"Firefox for Android", "Firefox OS"
Note: This must be a valid product in the system. Before you start posting to Input, please talk to the User
Advocacy folks or an Input admin to have your product added.
Optional fields
channel String. Max length: 30. The channel of the product the user is giving feedback on.
Examples: "stable", "beta"
version String. Max length: 30. The version of the product the user is giving feedback on as a string.
Examples: "22b2", "1.1"
platform String. Max length: 30. The name of the operating system/platform the product is running on.
Examples: "OS X", "Windows 8", "Firefox OS", "Android", "Linux"
locale String. Max length: 8. The locale the user is using.
Examples: "en-US", "fr", "de"
country String. Max length: 30. The country of origin for the device.
Examples: "Peru", "Mexico"
Note: This is only relevant to Firefox OS phones.
manufacturer String. Max length: 255. The manufacturer of the device the product is running on.
Examples: "Geeksphone", "Samsung"
device String. Max length: 255. The model name of the device the product is running on.
Examples: "Peak", "Galaxy Tab 10.1"
category String. Max length: 50. The category classification for this feedback response.
Examples: "ui", "performance", "bookmarks"
url String. Max length: 200. If the feedback relates to a specific webpage, then the url is the url of the webpage it
refers to.
Examples: "https://facebook.com/", "https://google.com/"
email String. The email address of the user. This allows us to contact the user at some later point to respond to the
user’s feedback or ask for more information.
Example: "[email protected]"
Note: The form this field is in should state that email addresses will not be publicly available.
Example informational text:
While your feedback will be publicly visible, email addresses
are kept private. We understand your privacy is important.
30
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
user_agent String. Max length: 255. The user agent of the client if applicable. For example if the user is using a
Firefox OS device, this would be the user agent of the browser used to send feedback.
Example: ’Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0’
source String. Max length: 100. If this response was initiated by a blog post, wiki page, search, newsletter, tweet or
something like that, this is the source that initiated the response. It has the same semantics as the utm_source
querystring parameter:
https://support.google.com/analytics/answer/1033867
Example: ’Hacks blog’
Note: Don’t set the source if the user is leaving feedback of their own accord. Only set the source if you have
prompted or asked the user to leave feedback.
campaign String. Max length: 100. If this response was initiated by a marketing campaign, this is the name of the
campaign. It has the same semantics as the utm_campaign querystring parameter:
https://support.google.com/analytics/answer/1033867
Example: ’show the firefox love post’
Note: Don’t set the campaign if the user is leaving feedback of their own accord. Only set the campaign if you
have prompted or asked the user to leave feedback.
Extra context
You can provide additional context in the form of key/value pairs by adding additional data to the JSON object.
Any fields that aren’t part of the required or optional fields list will get thrown into a JSON object and dumped in the
feedback response context.
For example, if the product were the Firefox devtools and you want feedback responses to include the theme (dark or
light) that the user was using, you could add this to the JSON object:
{
"happy": true,
"description": "devtools are the best!",
"product": "Devtools",
"theme": "dark"
}
That last key will get added to the feedback response context.
Note: Obviously, don’t use a key that’s already the name of a field. Also, since this is not future proof, you might
want to prepend a unique string to any keys you add.
Note: It’s important you don’t add ids or data that allows you to correlate feedback responses to things in other data
sets. That violates our privacy policy.
3.2. API
31
fjord Documentation, Release 1.0.dev
Minimal example with curl
$ curl -v -XPOST ’https://input.allizom.org/api/v1/feedback’ \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"happy": true,
"description": "Posting by api!",
"product": "Firefox"
}’
Responses
After posting feedback, you’ll get one of several responses:
HTTP 201 Feedback was posted successfully.
HTTP 400 Feedback has errors. Details will be in the response body.
Possibilities include:
• missing required fields
• email address is malformed
• data is in the wrong format
HTTP 429 There has been too many feedback postings from this IP address and the throttle trigger was hit. Try again
later.
3.2.3 Getting event data: /api/v1/events/
URL /api/v1/events/
Method HTTP GET
Payload format No payload–everything is done in the querystring
Response JSON
Doing a GET without any querystring arguments will return all the event data.
Note: This API endpoint is still in flux. The documentation is rudimentary at best. Amongst other things, it’s difficult
to discover valid values for things.
If you’re using this API endpoint and have issues, please open a bug.
Note: The event data is pretty sparse at the moment and only contains releases for Firefox and Firefox for Android.
We plan to add to this data.
Filters
products Strings. Comma separated list of products. For valid products, see https://input.mozilla.org/.
Examples:
32
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
?products=Firefox
?products=Firefox,Firefox for Android
date_start Date in YYYY-MM-DD format. Specifies the start for the date range you’re querying for.
Example:
?date_start=2014-08-12
date_end Date in YYYY-MM-DD format. Specifies the end for the date range you’re querying for.
Defaults to today.
Example:
?date_end=2014-08-12
Curl example
Minimal example:
curl -v https://input.mozilla.org/api/v1/events/?products=Firefox
3.2.4 Posting heartbeat feedback: /api/v1/hb/
URL /api/v1/hb/
Method HTTP POST
Payload format JSON–make sure to have Content-type:
application/json header
Testing clients using the API
Warning: DO NOT TEST YOUR CLIENT AGAINST OUR PRODUCTION SERVER. IT WILL MAKE
CHENG, MATT, TYLER AND I CROSS.
Seriously. Please don’t test your client against our production server.
Test your client against our stage server which runs the same code that our production server does. The url for the our
stage server is:
https://input.allizom.org/
^^^^^^^
Please make sure to use the correct domain!
Required fields
locale String. Max length: 8. The locale of the user interface that the user is using
Examples:"en-US", "fr", "de"
platform String. Max length: 30. The name of the operating system/platform the product is running on.
Examples: "OS X", "Windows 8", "Firefox OS", "Android", "Linux"
3.2. API
33
fjord Documentation, Release 1.0.dev
product String. Max length: 30. The name of the product the user is giving feedback on.
Examples:"Firefox for Android", "Firefox OS"
Note: This must be a valid product in the system. Before you start posting to Input, please talk to the User
Advocacy folks or an Input admin to have your product added.
channel String. Max length: 30. The channel of the product the user is giving feedback on.
Examples:"stable", "beta"
version String. Max length: 30. The version of the product the user is giving feedback on as a string.
Examples:"22b2", "1.1"
String. The operating system the user is using
poll String. Max length: 50. Alpha-numeric characters and - only. The slug of the poll this heartbeat response is for.
Examples:"is-firefox-fast"
Note: The poll must be created on the Input system you’re testing against and enabled. Otherwise you’ll get
errors.
Before you start posting to Input, please talk to the User Advocacy folks or an Input admin to have your product
added.
answer String. Max length: 10. The answer value.
Examples: "true", "false", "4"
Extra data Any additional fields you provide in the POST data will get glommed into a JSON object and stuck in the
db.
Curl examples
Minimal example:
curl -v -XPOST $URL \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"locale": "en-US",
"platform": "Linux",
"product": "Firefox",
"version": "30.0",
"channel": "stable",
"poll": "ou812",
"answer": "42"
}’
Here’s an example providing “extra” data:
curl -v -XPOST $URL \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"locale": "en-US",
34
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
"platform": "Linux",
"product": "Firefox",
"version": "30.0",
"channel": "stable",
"poll": "ou812",
"answer": "42",
"favoritepie": "cherry",
"favoriteUAperson": "tyler"
}’
The extra fields are plucked out and put in a JSON object and stored in the db like this:
{"favoritepie": "cherry", "favoriteUAperson": "tyler"}
3.3 Heartbeat API
• General
• Fields
– Required
– Optional fields
– Extra content
• Responses
– HTTP 201: Success
– HTTP 400: Bad request
– HTTP 500: Server error
• Examples
– Minimal example
– Example flow
This covers the Heartbeat v2 API. The v1 API was phased out.
The Heartbeat v2 API is for sending data from Heartbeat survey addons to Input. The data contains personally
identifyable information so we treat it as such. It is stored in the database and is not publicly accessible.
If you’re interested in Hearbeat data, speak to the User Advocacy group.
3.3.1 General
URL /api/v2/hb/
Method HTTP POST
Payload format JSON—make sure to have Content-type:
application/json header
Response JSON
3.3.2 Fields
Required
These fields are required and have no defaults. If you do not provide them, then you’ll get back an HTTP 400 with a
message stating you missed a required field.
3.3. Heartbeat API
35
fjord Documentation, Release 1.0.dev
field
type
reinsponse_version
teger
notes
This is the version of the packet specification. Any time the values of the packet or the
calculation of the values for the packet change, we should increase the
response_version. This allows us to distinguish between different packet builds when
doing analysis.
string Max length: 50; The version of the experiment addon.
experiment_version
person_id
string Max length: 50; Id representating a person’s browser. Global across surveys and flows.
survey_id
string This is the survey name as it is set up in Input. This is the only field that has a foreign key to
another table in Input and must be set up before running a survey.
flow_id
string Max length: 50; Id uniquely identifying a flow attempt for this survey.
quesstring Max length: 50; Id uniquely identifying a question for this survey. This allows us to tweak
tion_id
the question text for a survey without launching a new survey.
updated_ts inMilliseconds since the epoch for when this packet was created.
teEvery time you update data for a flow attempt, it should include a new and more recent
ger updated_ts.
quesstring Max length: None; Default: ""; The actual question asked. This can be localized.
tion_text
variastring Max length: 100; Default: ""
tion_id
Optional fields
field
score
max_score
flow_began_ts
flow_offered_ts
flow_voted_ts
flow_engaged_ts
platform
channel
version
locale
build_id
partner_id
profile_age
profile_usage
type
float
float
integer
integer
integer
integer
string
string
string
string
string
string
integer
JSON
addons
JSON
extra
is_test
JSON
boolean
notes
Default: null; The answer the user submitted.
Default: null; The maximum of the answer range.
Default: 0; Milliseconds since the epoch of when the flow began
Default: 0
Default: 0; Milliseconds since the epoch of when the user submitted an answer.
Default: 0
Max length: 50; Default: ""; Operating system and version that the user is using.
Max length: 50; Default: ""; The channel of the browser that the user is using.
Max length: 50; Default: ""; The version of the browser that the user is using.
Max length: 50; Default: ""; The locale that the user’s browser’s interface is in.
Max length: 50; Default: ""
Max length: 50; Default: ""
Default: null; Age in days of the user’s browser profile.
Default: {}; JavaScript object of key/value pairs with information about profile
usage.
Default: {}; JavaScript object of key/value pairs with information about the user’s
addons.
Default: {}; Any extra context you want to provide.
Default: false; Whether (true) or not (false) this is a test packet.
Extra content
Provide extra content in the extra field–there is no slop for this API.
3.3.3 Responses
All response bodies are in JSON.
36
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
HTTP 201: Success
The answer was posted successfully.
Example curl:
curl -v -XPOST ’https://input.mozilla.org/api/v2/hb/’ \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"person_id": "c1dd81f2-6ece-11e4-8a01-843a4bc832e4",
"survey_id": "lunch",
"flow_id": "20141117_attempt1",
"experiment_version": "1",
"response_version": 1,
"question_id": "howwaslunch",
"question_text": "how was lunch?",
"variation_id": "1",
"updated_ts": 1416011156000,
"is_test": true
}’
yields this response:
HTTP/1.0 201 CREATED
<uninteresting headers omitted>
Content-Type: application/json; indent=4; charset=utf-8
{
"msg": "success!"
}
HTTP 400: Bad request
Answer has errors. Details will be in the response body.
Possibilities include:
• non-existent survey_id
• disabled survey
• missing required fields
• data is in the wrong format
Example curl:
curl -v -XPOST ’https://input.mozilla.org/api/v2/hb/’ \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"person_id": "c1dd81f2-6ece-11e4-8a01-843a4bc832e4",
"survey_id": "nonexistent",
"flow_id": "20141114_attempt2",
"response_version": 1,
"experiment_version": "1",
"question_id": "howwaslunch",
3.3. Heartbeat API
37
fjord Documentation, Release 1.0.dev
"updated_ts": 1416011156000,
"is_test": true
}’
yields this response:
HTTP/1.0 400 BAD REQUEST
<uninteresting headers omitted>
Content-Type: application/json; indent=4; charset=utf-8
{
"msg": "bad request; see errors",
"errors": {
"survey_id": [
"Object with name=nonexistent does not exist."
],
"question_text": [
"This field is required."
],
"variation_id": [
"This field is required."
]
}
}
Each field with errors will have its own slot in the “errors” section. If there are multiple errors for that field, it’ll show
multiple errors.
HTTP 500: Server error
Tell Will. He has some ‘splaining to do.
3.3.4 Examples
Minimal example
Anything less than this will kick up “required” type errors.
curl -v -XPOST ’https://input.mozilla.org/api/v2/hb/’ \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"person_id": "c1dd81f2-6ece-11e4-8a01-843a4bc832e4",
"survey_id": "lunch",
"flow_id": "20141117_attempt1",
"experiment_version": "1",
"response_version": 1,
"question_id": "howwaslunch",
"question_text": "how was lunch?",
"variation_id": "1",
"updated_ts": 1416011156000,
"is_test": true
}’
38
Chapter 3. Part 2: Using the Site
fjord Documentation, Release 1.0.dev
Example flow
(I’m totally making things up here, but maybe this is what it could look like?)
Began:
curl -v -XPOST $URL \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"person_id": "c1dd81f2-6ece-11e4-8a01-843a4bc832e4",
"survey_id": "lunch",
"flow_id": "20141117_attempt5",
"experiment_version": "1",
"response_version": 1,
"question_id": "howwaslunch",
"updated_ts": 1416011156000,
"question_text": "how was lunch?",
"variation_id": "1",
"score": null,
"max_score": null,
"flow_began_ts": 1416011100000,
"flow_offered_ts": 0,
"flow_voted_ts": 0,
"flow_engaged_ts": 0,
"platform": "",
"channel": "",
"version": "",
"locale": "",
"build_id": "",
"partner_id": "",
"profile_age": null,
"profile_usage": {},
"addons": {},
"extra": {},
"is_test": true
}’
Voted, but not engaged, yet:
curl -v -XPOST $URL \
-H ’Accept: application/json; indent=4’ \
-H ’Content-type: application/json’ \
-d ’
{
"person_id": "c1dd81f2-6ece-11e4-8a01-843a4bc832e4",
"survey_id": "lunch",
"flow_id": "20141117_attempt7",
"experiment_version": "1",
"response_version": 1,
"question_id": "howwaslunch",
"updated_ts": 1416011180000,
"question_text": "how was lunch?",
"variation_id": "1",
"score": 5.0,
"max_score": 10.0,
"flow_began_ts": 1416011100000,
"flow_offered_ts": 1416011120000,
3.3. Heartbeat API
39
fjord Documentation, Release 1.0.dev
"flow_voted_ts": 1416011130000,
"flow_engaged_ts": 0,
"platform": "Windows 7",
"channel": "stable",
"version": "33.1",
"locale": "en-US",
"build_id": "e3b0971e-6ecf-11e4-af44-843a4bc832e4",
"partner_id": "Phil, Prince of Heck",
"profile_age": 365,
"profile_usage": {"avgperday": "5"},
"addons": {"count": 4, "badones": "plenty"},
"extra": {"moonphase": "waning gibbous"},
"is_test": true
}’
40
Chapter 3. Part 2: Using the Site
CHAPTER 4
Part 3: Maintaining The Site
Are you one of those super sekret gnomes that maintain the site through wintry blizzards and fiery summers? This is
the section for you!
4.1 Maintaining Fjord and Input
•
•
•
•
•
•
•
Onboarding a new developer
Triaging bugs for contributors
Adding support for a new product
Adding a new locale
Making strings changes to feedback forms
Dealing with errors in translated strings
EXPERIMENTAL: Update training data
4.1.1 Onboarding a new developer
1. Watch the “Input” product and “__Any__” component in Bugzilla in your Bugzilla Component Watching preferences
2. Hop on the #input IRC channel on irc.mozilla.org
3. Create an IT bug for getting added to error email lists
4. Ask an existing developer with an admin account on Input to create an admin account for you
5. Get access to push changes to https://github.com/mozilla/fjord
6. Update the wiki page
7. Read the documentation:
manual http://fjord.rtfd.org/
wiki page https://wiki.mozilla.org/Firefox/Input
8. Set up your development environment by reading through and doing all the things in the Getting started
9. If you haven’t read through the Webdev Bootcamp, now is a good time
10. Bask in the tranquil rhythmic sounds of the Fjord
41
fjord Documentation, Release 1.0.dev
4.1.2 Triaging bugs for contributors
Bugs designated for contributors fall into two groups:
1. good first bugs
2. good next bugs
Good first bugs should ideally touch one aspect of the code base, be self-contained, and not require a lot of knowledge
about how the system works.
Good first bugs are denoted in Bugzilla with:
• [good first bug] in the Whiteboard field
• a mentor listed in the Mentors field
• a comment explaining the problem and what needs to be done to fix it
Good next bugs are everything else and are denoted in Bugzilla with:
• a mentor listed in the Mentors field
• a comment explaining the problem and what needs to be done to fix it
It’s good to go through bugs once a month to see if any new bugs popped up that’d be good for contributors as well as
for bugs that currently exist that probably should get closed out.
Comment template:
<required skills>
<explanation of how to implement>
<note any wry twists>
Marking this as a mentored bug. If you’re interested in working on it,
please read through our "Join this project" guide [1], complete the
list of things you need to do before contributing and then add a comment
to this bug asking to have it assigned to you.
If you have any questions, please ask on the mailing list or in the
#input channel on irc.mozilla.org.
[1] http://fjord.readthedocs.org/en/latest/welcome.html
Once a week, go through any assigned mentored bugs and ping them to see how they’re coming along.
4.1.3 Adding support for a new product
To add support for a new product via product urls for the feedback form or the Input API, add a new entry to the
Products table.
4.1.4 Adding a new locale
To add a new locale so that https://input.mozilla.org/%NEWLOCALE% works and so that people can see
the site in that language and submit feedback:
1. In your local repository, run:
42
Chapter 4. Part 3: Maintaining The Site
fjord Documentation, Release 1.0.dev
$ ./manage.py update_product_details
2. Check lib/product_details_json/languages.json to see if the language is there.
(a) If not, you need to file a bug to get it added. See https://bugzilla.mozilla.org/show_bug.cgi?id=839506 for
example.
Once the locale is listed in lib/product_details_json/languages.json, proceed.
3. Update locale/ and check to see if the locale is listed there.
(a) If you don’t have a locale/ directory or don’t know how to update it, see Maintaining l10n.
(b) If the locale isn’t in the locale/ directory, ask Milos to add Input to the list of translated projects for
that locale. See https://bugzilla.mozilla.org/show_bug.cgi?id=860754 for better language because I only
vaguely understand how the Verbatim side works.
Once the locale is in svn and locale/, proceed.
4. Add the locale code to the PROD_LANGUAGES list in fjord/settings/base.py.
5. Commit the changes to fjord/settings/base.py and product details stuff to git.
4.1.5 Making strings changes to feedback forms
Feedback forms must be fully translated in specific target locales before they can be pushed to production.
Process for making feedback form strings changes:
1. create a new branch
2. make the changes you need to make
3. submit a pull request
4. after the pull request is approved (r+), extract and merge strings from that branch
5. send an email to the dev-l10n-web mailing list—see Extract/merge/sync strings with svn for details
Now you have to wait until the target locales have fully translated the new strings.
Use the bin/l10n_status.py script to tell you whether things are good to go or not.
Once they’re good to go, you can land the changes in master and push to stage and production.
For the list of target locales per form, see Cheng, Matt or Will.
4.1.6 Dealing with errors in translated strings
When we deploy a new version of Fjord, it updates the .po files and picks up newly translated strings.
.po files that have errors will not get compiled to .mo files and thus won’t go to production and thus won’t cause
fires.
Note that this doesn’t mean that this locale will have no translations—we’ll use the previously compiled .mo file.
If there is no .mo file, then the deployment will compile a .mo file even if there are errors with the figuring that a
problematic .mo file is better than nothing and that this should be an exceedingly rare occurrence.
If .po files have errors, then those errors are noted in the postatus.txt files:
• dev: https://input-dev.allizom.org/media/postatus.txt
• stage: https://input.allizom.org/media/postatus.txt
4.1. Maintaining Fjord and Input
43
fjord Documentation, Release 1.0.dev
• prod: https://input.mozilla.org/media/postatus.txt
If there are errors in those files, we need to open up a bug in Mozilla Localizations -> locale code with the specifics.
Bug description template:
We found errors in the translated strings for Input (https://input.mozilla.org/).
The errors are as follows:
<paste errors here>
Until these errors are fixed, we can’t deploy updates to the strings for this locale.
If you have any questions, let me know.
4.1.7 EXPERIMENTAL: Update training data
Note: This is here solely to support the spicedham prototype integration. It’s liable to change.
Create a directory structure:
- corpus
\
|- abuse
| \- bunch of [respid].json files
|
\- not_abuse
\- bunch of [respid].json files
Each file is the JSON for a single response.
4011021.json.
The files are titled <response-id>.json.
For example,
To generate training data:
$ python manage.py trainabuse corpus/
To generate new fixture:
$ python manage.py dumpdata --indent=2 --format=json \
flags flags.Store > fjord/flags/fixtures/abuse_training.json
To load the fixture:
$ python manage.py loaddata flags abuse_training.json
4.2 Service Level Agreement
If you notice issues with this SLA, please update it.
Last updated February 26th, 2013
4.2.1 Feedback submitters
We support feedback from the following things:
44
Chapter 4. Part 3: Maintaining The Site
fjord Documentation, Release 1.0.dev
1. Firefox Desktop stable using the feedback form
2. Firefox for Android stable using the feedback form
3. Firefox for Android stable about:feedback
This requires some funky code because we changed the way feedback posting worked between the old code
base and the new one.
We need to update Firefox for Android so it posts to the new codebase, then we can ditch a bunch of the funky
code.
4. FirefoxOS: v1.0
4.2. Service Level Agreement
45