├── __init__.py ├── apps ├── .gitignore ├── commons │ ├── models.py │ ├── __init__.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_migrations.py │ │ └── test_accepted_locales.py │ ├── context_processors.py │ ├── helpers.py │ ├── middleware.py │ └── urlresolvers.py ├── dll │ ├── __init__.py │ ├── urls.py │ ├── helpers.py │ ├── forms.py │ ├── templates │ │ └── dll │ │ │ ├── create.html │ │ │ ├── pagination.html │ │ │ ├── search.html │ │ │ ├── index.html │ │ │ ├── view.html │ │ │ └── edit.html │ ├── models.py │ └── views.py ├── __init__.py └── users │ ├── auth │ ├── __init__.py │ └── backends.py │ ├── __init__.py │ ├── urls.py │ ├── models.py │ ├── templates │ └── users │ │ ├── settings.html │ │ └── login.html │ ├── email_auth_backend.py │ ├── forms.py │ ├── monkeypatch_template_engine.py │ ├── views.py │ └── tests.py ├── docs ├── _static │ └── .gitignore ├── _build │ └── .gitignore ├── _templates │ └── .gitignore ├── index.rst ├── build-github.zsh ├── Makefile └── conf.py ├── media ├── css │ ├── .gitignore │ ├── examples │ │ └── main.css │ └── dll │ │ └── main.css ├── img │ ├── .gitignore │ └── dll │ │ └── search.png └── js │ ├── .gitignore │ └── dll │ ├── nav.js │ └── detail.js ├── migrations ├── __init__.py ├── 02-unique-filename.sql ├── schematic_settings.py └── 01-base.sql ├── templates ├── .gitignore ├── example_base.html └── base.html ├── vendor-local └── vendor.pth ├── lib └── product_details_json │ ├── thunderbird_beta_builds.json │ ├── mobile_history_stability_releases.json │ ├── mobile_history_major_releases.json │ ├── thunderbird_versions.json │ ├── thunderbird_history_major_releases.json │ ├── mobile_history_development_releases.json │ ├── firefox_history_major_releases.json │ ├── firefox_versions.json │ ├── thunderbird_history_development_releases.json │ ├── thunderbird_history_stability_releases.json │ ├── firefox_history_development_releases.json │ ├── firefox_history_stability_releases.json │ ├── firefox_beta_builds.json │ ├── languages.json │ ├── thunderbird_primary_builds.json │ ├── firefox_primary_builds.json │ └── mobile_details.json ├── .gitmodules ├── requirements ├── compiled.txt ├── dev.txt └── prod.txt ├── settings ├── __init__.py ├── local.py-dist ├── base.py └── base.py-back ├── .gitignore ├── README.md ├── wsgi └── playdoh.wsgi ├── manage.py ├── bin ├── compile-mo.sh └── update_site.py ├── urls.py ├── locale ├── templates │ └── LC_MESSAGES │ │ └── messages.pot ├── fr │ └── LC_MESSAGES │ │ └── messages.po └── en_US │ └── LC_MESSAGES │ └── messages.po └── LICENSE /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/commons/models.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/dll/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_static/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /media/css/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /media/img/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /media/js/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor-local/vendor.pth: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/__init__.py: -------------------------------------------------------------------------------- 1 | # empty 2 | -------------------------------------------------------------------------------- /apps/commons/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/users/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /docs/_templates/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/commons/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/users/__init__.py: -------------------------------------------------------------------------------- 1 | # empty 2 | -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_beta_builds.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /lib/product_details_json/mobile_history_stability_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0.1":"2010-04-13"} -------------------------------------------------------------------------------- /lib/product_details_json/mobile_history_major_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0":"2010-01-28","1.1":"2010-07-01"} -------------------------------------------------------------------------------- /migrations/02-unique-filename.sql: -------------------------------------------------------------------------------- 1 | CREATE UNIQUE INDEX `filename_unqiue` ON dll_file (file_name); -------------------------------------------------------------------------------- /media/img/dll/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peterbe/dragnet/master/media/img/dll/search.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor"] 2 | path = vendor 3 | url = git://github.com/mozilla/playdoh-lib.git 4 | -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_versions.json: -------------------------------------------------------------------------------- 1 | {"LATEST_THUNDERBIRD_VERSION":"3.1.7","LATEST_THUNDERBIRD__OLDER_VERSION":"3.0.11"} -------------------------------------------------------------------------------- /media/js/dll/nav.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $("#id_term").focus(function () { 3 | $(this).attr('value', ''); 4 | }); 5 | }); -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_history_major_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0":"2004-12-07","1.5":"2006-01-11","2.0":"2007-04-18","3.0":"2009-12-08","3.1":"2010-06-24"} -------------------------------------------------------------------------------- /lib/product_details_json/mobile_history_development_releases.json: -------------------------------------------------------------------------------- 1 | {"1.1b1":"2010-04-28","1.1rc1":"2010-06-16","4.0b1":"2010-10-06","4.0b2":"2010-11-04","4.0b3":"2010-12-22"} -------------------------------------------------------------------------------- /lib/product_details_json/firefox_history_major_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0":"2004-11-09","1.5":"2005-11-29","2.0":"2006-10-24","3.0":"2008-06-17","3.5":"2009-06-30","3.6":"2010-01-21"} -------------------------------------------------------------------------------- /requirements/compiled.txt: -------------------------------------------------------------------------------- 1 | MySQL-python==1.2.3c1 2 | Jinja2==2.5.5 3 | python-ldap==2.3.13 4 | 5 | # for bcrypt passwords 6 | hmac==20101005 7 | hashlib==20081119 8 | py-bcrypt==0.2 9 | -------------------------------------------------------------------------------- /lib/product_details_json/firefox_versions.json: -------------------------------------------------------------------------------- 1 | {"LATEST_FIREFOX_VERSION":"3.6.13","LATEST_FIREFOX_DEVEL_VERSION":"4.0b10","LATEST_FIREFOX_RELEASED_DEVEL_VERSION":"4.0b10","LATEST_FIREFOX_OLDER_VERSION":"3.5.16"} -------------------------------------------------------------------------------- /settings/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | try: 3 | from .local import * 4 | except ImportError, exc: 5 | exc.args = tuple(['%s (did you rename settings/local.py-dist?)' % exc.args[0]]) 6 | raise exc 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | settings_local.py 2 | *.py[co] 3 | *.sw[po] 4 | .coverage 5 | pip-log.txt 6 | docs/_gh-pages 7 | build.py 8 | .DS_Store 9 | *-min.css 10 | *-all.css 11 | *-min.js 12 | *-all.js 13 | vendor 14 | .noseids 15 | tmp/* 16 | *~ 17 | *.mo 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DLL Directory 2 | ======= 3 | 4 | The DLL Directory exists as a library for helping engineers determine 5 | the validity and source of various Windows DLLs. 6 | 7 | License 8 | ------- 9 | This software is licensed under the [New BSD License][BSD]. For more 10 | information, read the file ``LICENSE``. 11 | 12 | [BSD]: http://creativecommons.org/licenses/BSD/ 13 | 14 | -------------------------------------------------------------------------------- /apps/commons/context_processors.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.utils import translation 3 | 4 | 5 | def i18n(request): 6 | return {'LANGUAGES': settings.LANGUAGES, 7 | 'LANG': settings.LANGUAGE_URL_MAP.get(translation.get_language()) 8 | or translation.get_language(), 9 | 'DIR': 'rtl' if translation.get_language_bidi() else 'ltr', 10 | } 11 | -------------------------------------------------------------------------------- /apps/dll/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | import views 3 | 4 | 5 | urlpatterns = patterns('dll.views', 6 | url(r'^(\d+)?$', views.home, name='dll.home'), 7 | url(r'^create/?$', views.create, name='dll.create'), 8 | url(r'^file/([\w-]+\.dll)/?$', views.edit, name='dll.edit'), 9 | url(r'^view/([\w-]+\.dll)/?$', views.view, name='dll.view'), 10 | url(r'^search/$', views.search, name='dll.search'), 11 | ) 12 | -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_history_development_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0rc1":"2004-12-01","1.5b1":"2005-09-09","1.5b2":"2005-10-07","1.5rc1":"2005-11-05","1.5rc2":"2005-12-21","2.0b1":"2006-12-12","2.0b2":"2007-01-23","2.0rc1":"2007-04-06","3.0a1":"2008-05-12","3.0a2":"2008-07-13","3.0a3":"2008-10-14","3.0b1":"2008-12-09","3.0b2":"2009-02-26","3.0b3":"2009-07-21","3.0b4":"2009-10-22","3.0rc1":"2009-11-24","3.0rc2":"2009-12-01","3.1a1":"2010-02-03","3.1b1":"2010-03-10","3.1rc1":"2010-05-27","3.1rc2":"2010-06-09"} -------------------------------------------------------------------------------- /requirements/dev.txt: -------------------------------------------------------------------------------- 1 | # This file pulls in everything a developer needs. If it's a basic package 2 | # needed to run the site, it belongs in requirements/prod.txt. If it's a 3 | # package for developers (testing, docs, etc.), it goes in this file. 4 | 5 | -r prod.txt 6 | 7 | # Documentation 8 | Sphinx==1.0.6 9 | 10 | # Testing 11 | nose==1.0.0 12 | -e git://github.com/jbalogh/django-nose.git#egg=django_nose 13 | -e git://github.com/jbalogh/test-utils.git#egg=test-utils 14 | 15 | # L10n 16 | translate-toolkit==1.8.0 17 | -------------------------------------------------------------------------------- /templates/example_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% block page_title %}playdoh examples{% endblock %} 6 | 7 | {% block site_css %} 8 | {{ css('example_css') }} 9 | {% endblock %} 10 | 11 | 12 | {% block content %}{% endblock %} 13 | 14 | {% block site_js %} 15 | {{ js('example_js') }} 16 | {% endblock %} 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /wsgi/playdoh.wsgi: -------------------------------------------------------------------------------- 1 | import os 2 | import site 3 | 4 | os.environ['CELERY_LOADER'] = 'django' 5 | 6 | # Add the app dir to the python path so we can import manage. 7 | wsgidir = os.path.dirname(__file__) 8 | site.addsitedir(os.path.abspath(os.path.join(wsgidir, '../'))) 9 | 10 | # manage adds /apps, /lib, and /vendor to the Python path. 11 | import manage 12 | 13 | import django.core.handlers.wsgi 14 | os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 15 | application = django.core.handlers.wsgi.WSGIHandler() 16 | 17 | # vim: ft=python 18 | -------------------------------------------------------------------------------- /apps/dll/helpers.py: -------------------------------------------------------------------------------- 1 | import jingo 2 | import jinja2 3 | import forms 4 | from babel.dates import format_date, format_datetime 5 | 6 | 7 | @jingo.register.function 8 | def BasicSearchForm(request): 9 | if 'term' in request.GET: 10 | data = {'term': request.GET['term']} 11 | else: 12 | data = {'term': 'Search'} 13 | form = forms.SearchForm(data) 14 | return form 15 | 16 | 17 | @jingo.register.function 18 | def dll_date_format(date): 19 | return format_date(date) 20 | 21 | 22 | @jingo.register.function 23 | def dll_datetime_format(date): 24 | return format_datetime(date) 25 | -------------------------------------------------------------------------------- /apps/dll/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from dll.models import File, Comment 3 | 4 | 5 | class FileForm(forms.ModelForm): 6 | """Using a model form to expedite the creation of DLL records""" 7 | class Meta: 8 | model = File 9 | exclude = ('date_created', 'date_modified', 'created_by', 10 | 'modified_by', ) 11 | 12 | 13 | class CommentForm(forms.ModelForm): 14 | """Comment form for DLL comments""" 15 | class Meta: 16 | model = Comment 17 | exclude = ('user', 'date', 'dll') 18 | 19 | 20 | class SearchForm(forms.Form): 21 | term = forms.CharField() 22 | -------------------------------------------------------------------------------- /media/js/dll/detail.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | 3 | $('ul.tab-list li a').click(function() { 4 | classAttr = $(this).attr('class'); 5 | $('ul.tab-list li').removeClass('active') 6 | $(this).parent().addClass("active") 7 | $('.information').addClass('out-of-focus') 8 | $('#' + classAttr).removeClass('out-of-focus') 9 | }); 10 | 11 | if(window.location.hash == '#comments') { 12 | $('.information').addClass('out-of-focus') 13 | $(window.location.hash).removeClass('out-of-focus') 14 | $('ul.tab-list li').removeClass('active') 15 | $('ul.tab-list li a.comments').parent().addClass('active') 16 | } 17 | 18 | }); -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | try: 6 | # For local development in a virtualenv: 7 | from funfactory import manage 8 | except ImportError: 9 | # Production: 10 | # Add a temporary path so that we can import the funfactory 11 | tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 12 | 'vendor', 'src', 'funfactory') 13 | sys.path.append(tmp_path) 14 | 15 | from funfactory import manage 16 | 17 | # Let the path magic happen in setup_environ() ! 18 | sys.path.remove(tmp_path) 19 | 20 | 21 | manage.setup_environ(__file__) 22 | 23 | if __name__ == "__main__": 24 | manage.main() 25 | -------------------------------------------------------------------------------- /apps/dll/templates/dll/create.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block extrahead %} 4 | 5 | {{ js('detail_js') }} 6 | 7 | {% endblock %} 8 | 9 | {% block mainbody %} 10 |
11 | 12 | 15 |
16 |
17 | {{ csrf() }} 18 | 19 | {{ form }} 20 | 21 |
 
22 |
23 |
24 |
25 | {% endblock %} -------------------------------------------------------------------------------- /bin/compile-mo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TARGET=$1 4 | LOCKFILE="/tmp/compile-mo-${2}.lock" 5 | 6 | function usage() { 7 | echo "syntax:" 8 | echo " compile-mo.sh locale-dir/ [unique]" 9 | echo "unique is an optional string that will be used as the name of the lockfile" 10 | exit 1 11 | } 12 | 13 | # check if file and dir are there 14 | if [[ ($# -gt 2) || (! -d "$TARGET") ]]; then usage; fi 15 | 16 | # check if the lockfile exists 17 | if [ -e $LOCKFILE ]; then 18 | echo "$LOCKFILE present, exiting" 19 | exit 99 20 | fi 21 | 22 | touch $LOCKFILE 23 | for lang in `find $TARGET -type f -name "*.po"`; do 24 | dir=`dirname $lang` 25 | stem=`basename $lang .po` 26 | msgfmt -o ${dir}/${stem}.mo $lang 27 | done 28 | rm $LOCKFILE 29 | -------------------------------------------------------------------------------- /requirements/prod.txt: -------------------------------------------------------------------------------- 1 | # Django stuff 2 | -e git://github.com/django/django@36c82ac8#egg=django 3 | 4 | # Templates 5 | -e git://github.com/jbalogh/jingo.git#egg=jingo 6 | -e git://github.com/jsocol/jingo-minify.git#egg=jingo-minify 7 | GitPython==0.1.7 8 | 9 | # Various tidbits 10 | -e git://github.com/jsocol/commonware.git#egg=commonware 11 | -e git://github.com/mozilla/nuggets.git#egg=nuggets 12 | 13 | # Security 14 | -e git://github.com/fwenzel/django-sha2.git#egg=django-sha2 15 | -e git://github.com/jsocol/bleach.git#egg=bleach 16 | 17 | # Celery: Message queue 18 | celery 19 | django-celery 20 | 21 | # L10n 22 | Babel>=0.9.4 23 | -e git://github.com/clouserw/tower.git#egg=tower 24 | -e git://github.com/fwenzel/django-mozilla-product-details#egg=django-mozilla-product-details 25 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ======================================== 2 | Welcome to this project's documentation! 3 | ======================================== 4 | 5 | This is a documentation template for a **web application based on Playdoh**. 6 | Feel free to change this to your liking. 7 | 8 | 9 | About playdoh 10 | ------------- 11 | 12 | This project is based on **playdoh**. Mozilla's Playdoh is an open source 13 | web application template based on `Django `_. 14 | 15 | To learn more about it, step by the `playdoh project page 16 | `_. 17 | 18 | Contents 19 | -------- 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | 24 | 25 | Indices and tables 26 | ------------------ 27 | 28 | * :ref:`genindex` 29 | * :ref:`modindex` 30 | * :ref:`search` 31 | -------------------------------------------------------------------------------- /migrations/schematic_settings.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 5 | 6 | # Set up playdoh. 7 | import manage 8 | from django.conf import settings 9 | 10 | config = settings.DATABASES['default'] 11 | config['HOST'] = config.get('HOST', 'localhost') 12 | config['PORT'] = config.get('PORT', '3306') 13 | 14 | if not config['HOST'] or config['HOST'].endswith('.sock'): 15 | """Oh, you meant 'localhost'!""" 16 | config['HOST'] = 'localhost' 17 | 18 | s = 'mysql --silent {NAME} -h{HOST} -u{USER}' 19 | 20 | if config['PASSWORD']: 21 | s += ' -p{PASSWORD}' 22 | else: 23 | del config['PASSWORD'] 24 | if config['PORT']: 25 | s += ' -P{PORT}' 26 | else: 27 | del config['PORT'] 28 | 29 | db = s.format(**config) 30 | table = 'schema_version' 31 | -------------------------------------------------------------------------------- /apps/dll/templates/dll/pagination.html: -------------------------------------------------------------------------------- 1 | {% macro dll_paginator(page_url, dlls) %} 2 | 23 | {% endmacro %} -------------------------------------------------------------------------------- /apps/dll/templates/dll/search.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block mainbody %} 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% for file in dlls %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% endfor %} 26 |
Date CreatedFile NameCommon NameVendorStatusDescription
{{ dll_date_format(file.date_created) }}{{file.file_name}}{{ file.common_name }}{{ file.vendor }}{{ file.status }}{{ file.description }}
27 |
28 | 29 | {%endblock%} -------------------------------------------------------------------------------- /docs/build-github.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # A useful build script for projects hosted on github: 4 | # It can build your Sphinx docs and push them straight to your gh-pages branch. 5 | 6 | # Should be run from the docs directory: (cd docs && ./build-github.zsh) 7 | 8 | REPO=$(git config remote.origin.url) 9 | HERE=$(dirname $0) 10 | GH=$HERE/_gh-pages 11 | 12 | 13 | # Checkout the gh-pages branch, if necessary. 14 | if [[ ! -d $GH ]]; then 15 | git clone $REPO $GH 16 | pushd $GH 17 | git checkout -b gh-pages origin/gh-pages 18 | popd 19 | fi 20 | 21 | # Update and clean out the _gh-pages target dir. 22 | pushd $GH 23 | git pull && rm -rf * 24 | popd 25 | 26 | # Make a clean build. 27 | pushd $HERE 28 | make clean dirhtml 29 | 30 | # Move the fresh build over. 31 | cp -r _build/dirhtml/* $GH 32 | pushd $GH 33 | 34 | # Commit. 35 | git add . 36 | git commit -am "gh-pages build on $(date)" 37 | git push origin gh-pages 38 | 39 | popd 40 | popd 41 | -------------------------------------------------------------------------------- /urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.defaults import * 3 | 4 | # Uncomment the next two lines to enable the admin: 5 | # from django.contrib import admin 6 | # admin.autodiscover() 7 | 8 | urlpatterns = patterns('', 9 | # Example: 10 | (r'', include('dll.urls')), 11 | (r'^users/', include('users.urls')), 12 | 13 | # Uncomment the admin/doc line below to enable admin documentation: 14 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')), 15 | 16 | # Uncomment the next line to enable the admin: 17 | # (r'^admin/', include(admin.site.urls)), 18 | ) 19 | 20 | ## In DEBUG mode, serve media files through Django. 21 | if settings.DEBUG: 22 | # Remove leading and trailing slashes so the regex matches. 23 | media_url = settings.MEDIA_URL.lstrip('/').rstrip('/') 24 | urlpatterns += patterns('', 25 | (r'^%s/(?P.*)$' % media_url, 'django.views.static.serve', 26 | {'document_root': settings.MEDIA_ROOT}), 27 | ) 28 | -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_history_stability_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0.2":"2005-03-21","1.0.5":"2005-07-13","1.0.6":"2005-07-19","1.0.7":"2005-09-29","1.0.8":"2006-04-21","1.5.0.2":"2006-04-21","1.5.0.4":"2006-06-01","1.5.0.5":"2006-07-27","1.5.0.7":"2006-09-14","1.5.0.8":"2006-11-08","1.5.0.9":"2006-12-19","1.5.0.10":"2007-03-01","1.5.0.12":"2007-05-30","1.5.0.13":"2007-08-23","2.0.0.4":"2007-06-14","2.0.0.5":"2007-07-19","2.0.0.6":"2007-08-01","2.0.0.9":"2007-11-14","2.0.0.12":"2008-02-26","2.0.0.14":"2008-05-01","2.0.0.16":"2008-07-23","2.0.0.17":"2008-09-25","2.0.0.18":"2008-11-19","2.0.0.19":"2008-12-30","2.0.0.21":"2009-03-18","2.0.0.22":"2009-06-22","2.0.0.23":"2009-08-20","2.0.0.24":"2010-03-16","3.0.1":"2010-01-20","3.0.2":"2010-02-25","3.0.3":"2010-03-01","3.0.4":"2010-03-30","3.0.5":"2010-06-17","3.0.6":"2010-07-20","3.0.7":"2010-09-07","3.0.8":"2010-09-16","3.0.9":"2010-10-19","3.0.10":"2010-10-27","3.1.1":"2010-07-20","3.1.2":"2010-08-05","3.1.3":"2010-09-07","3.1.4":"2010-09-16","3.1.5":"2010-10-19","3.1.6":"2010-10-27"} -------------------------------------------------------------------------------- /locale/templates/LC_MESSAGES/messages.pot: -------------------------------------------------------------------------------- 1 | #, fuzzy 2 | msgid "" 3 | msgstr "" 4 | "Project-Id-Version: PACKAGE VERSION\n" 5 | "Report-Msgid-Bugs-To: \n" 6 | "POT-Creation-Date: 2011-06-03 19:07-0700\n" 7 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 8 | "Last-Translator: FULL NAME \n" 9 | "Language-Team: LANGUAGE \n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=utf-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "X-Generator: Translate Toolkit 1.8.0\n" 14 | 15 | #: apps/examples/templates/examples/home.html:5 16 | msgid "Hello world" 17 | msgstr "" 18 | 19 | #. This is a localizer comment 20 | #: apps/examples/templates/examples/home.html:9 21 | msgid "This is a test view." 22 | msgstr "" 23 | 24 | #: apps/examples/templates/examples/home.html:11 25 | msgid "" 26 | "Learn you some Playdoh and then go build " 27 | "something awesome." 28 | msgstr "" 29 | 30 | #: apps/examples/templates/examples/home.html:17 31 | msgid "Current locale: %(LANG)s.
Available locales: %(langs)s." 32 | msgstr "" 33 | -------------------------------------------------------------------------------- /lib/product_details_json/firefox_history_development_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0rc1":"2004-10-27","1.0rc2":"2004-11-03","1.5rc1":"2005-11-01","1.5rc2":"2005-11-10","1.5rc3":"2005-11-17","2.0b1":"2006-07-12","2.0b2":"2006-08-31","2.0rc1":"2006-09-26","2.0rc2":"2006-10-06","2.0rc3":"2007-10-16","3.0b1":"2007-11-19","3.0b2":"2007-12-18","3.0b3":"2008-02-12","3.0b4":"2008-03-10","3.0b5":"2008-04-02","3.0rc1":"2008-05-16","3.0rc2":"2008-06-03","3.1b1":"2008-08-14","3.1b2":"2008-12-08","3.1b3":"2009-03-12","3.5b4":"2009-04-27","3.5rc2":"2009-06-19","3.5rc3":"2009-06-24","3.6b1":"2009-10-30","3.6b2":"2009-11-10","3.6b3":"2009-11-17","3.6b4":"2009-11-26","3.6b5":"2009-12-17","3.6rc1":"2010-01-08","3.6rc2":"2010-01-17","3.6.3plugin1":"2010-04-08","3.6.4build1":"2010-04-20","3.6.4build3":"2010-05-04","3.6.4build4":"2010-05-14","3.6.4build5":"2010-05-26","3.6.4build6":"2010-05-28","3.6.4build7":"2010-06-14","3.6.7build1":"2010-07-02","4.0b1":"2010-07-06","4.0b2":"2010-07-27","4.0b3":"2010-08-11","4.0b4":"2010-08-24","4.0b5":"2010-09-07","4.0b6":"2010-09-14","4.0b7":"2010-11-10","4.0b8":"2010-12-22","4.0b9":"2011-01-14","4.0b10":"2011-01-25"} -------------------------------------------------------------------------------- /apps/dll/templates/dll/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% set page_url = 'dll.home' %} 3 | {% import 'dll/pagination.html' as dp %} 4 | {% block mainbody %} 5 |
6 | {{ dp.dll_paginator(page_url, dlls) }} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for file in dlls.object_list %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% endfor %} 28 |
Date CreatedFile NameCommon NameVendorStatusDescription
{{ dll_date_format(file.date_created) }}{{file.file_name}}{{ file.common_name }}{{ file.vendor }}{{ file.status }}{{ file.description }}
29 | {{ dp.dll_paginator(page_url, dlls) }} 30 |
31 | 32 | {%endblock%} -------------------------------------------------------------------------------- /locale/fr/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: PACKAGE VERSION\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2011-06-03 19:07-0700\n" 6 | "Last-Translator: Automatically generated\n" 7 | "Language-Team: none\n" 8 | "Language: fr\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 13 | 14 | #: apps/examples/templates/examples/home.html:5 15 | msgid "Hello world" 16 | msgstr "Bonjour le monde" 17 | 18 | #. This is a localizer comment 19 | #: apps/examples/templates/examples/home.html:9 20 | msgid "This is a test view." 21 | msgstr "Ceci est une vue de test." 22 | 23 | #: apps/examples/templates/examples/home.html:11 24 | msgid "Learn you some Playdoh and then go build something awesome." 25 | msgstr "Apprends à jouer avec Playdoh et construis quelque chose de génial." 26 | 27 | #: apps/examples/templates/examples/home.html:17 28 | msgid "Current locale: %(LANG)s.
Available locales: %(langs)s." 29 | msgstr "Langue active : %(LANG)s.
Langues disponibles : %(langs)s." 30 | -------------------------------------------------------------------------------- /media/css/examples/main.css: -------------------------------------------------------------------------------- 1 | /* An example CSS file that will be minified. */ 2 | body { 3 | font-family: sans-serif; 4 | background-color: rgb(56,142,222); 5 | background-image: -webkit-gradient( 6 | linear, 7 | left bottom, 8 | left top, 9 | color-stop(0.19, rgb(56,142,222)), 10 | color-stop(0.6, rgb(82,186,255)) 11 | ); 12 | background-image: -moz-linear-gradient( 13 | center bottom, 14 | rgb(56,142,222) 19%, 15 | rgb(82,186,255) 60% 16 | ); 17 | background-repeat: repeat-x; 18 | min-height: 800px; 19 | padding-left: 30px; 20 | } 21 | h1 { 22 | font-family: Helvetica, sans-serif; 23 | } 24 | section, p, ul { 25 | background-color: rgba(255,255,255,0.3);; 26 | color: #333; 27 | font-family: Courier, serif; 28 | line-height: 1.4; 29 | padding: 5px; 30 | width: 600px; 31 | } 32 | li { 33 | margin-left: 30px; 34 | } 35 | 36 | #bleachform { 37 | margin: 50px 0; 38 | } 39 | #bleachform p { 40 | font-size: 80%; 41 | } 42 | #bleachform textarea { 43 | height: 100px; 44 | width: 600px; 45 | } 46 | #bleached { 47 | background-color: rgba(255, 0, 0, .5); 48 | margin: 50px 0; 49 | } 50 | #bleached p { 51 | background-color: transparent; 52 | } 53 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% block title %}Mozilla Dragnet{% endblock %} 4 | {% block site_css %} 5 | {{ css('common_css') }} 6 | {% endblock %} 7 | 8 | {% block site_js %} 9 | {{ js('common_js') }} 10 | {% endblock %} 11 | 12 | {% block extrahead %}{% endblock %} 13 | 14 | 15 | 16 | 24 |
25 | {% block mainbody %}{% endblock %} 26 |
27 |
28 | {% if request.user.is_authenticated() %} 29 | Welcome {{ request.user.first_name }}. Create New DLL  Log Out 30 | {% else %} 31 | Log In 32 | {% endif %} 33 |
34 | 35 | -------------------------------------------------------------------------------- /locale/en_US/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: PACKAGE VERSION\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: 2011-05-26 18:11-0700\n" 6 | "PO-Revision-Date: 2011-05-26 18:11-0700\n" 7 | "Last-Translator: Automatically generated\n" 8 | "Language-Team: none\n" 9 | "Language: en_US\n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "X-Generator: Translate Toolkit 1.8.0\n" 14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 | 16 | #: apps/examples/templates/examples/home.html:5 17 | msgid "Hello world" 18 | msgstr "Hello world" 19 | 20 | #. This is a localizer comment 21 | #: apps/examples/templates/examples/home.html:9 22 | msgid "This is a test view." 23 | msgstr "This is a test view." 24 | 25 | #: apps/examples/templates/examples/home.html:11 26 | msgid "Learn you some Playdoh and then go build something awesome." 27 | msgstr "Learn you some Playdoh and then go build something awesome." 28 | 29 | #: apps/examples/templates/examples/home.html:17 30 | msgid "Current locale: %(LANG)s.
Available locales: %(langs)s." 31 | msgstr "Current locale: %(LANG)s.
Available locales: %(langs)s." 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Mozilla 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of the copyright owner nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /settings/local.py-dist: -------------------------------------------------------------------------------- 1 | # This is an example settings_local.py file. 2 | # Copy it and add your local settings here. 3 | 4 | from settings import * 5 | 6 | 7 | DATABASES = { 8 | 'default': { 9 | 'ENGINE': 'django.db.backends.mysql', 10 | 'NAME': '', 11 | 'USER': '', 12 | 'PASSWORD': '', 13 | 'HOST': '', 14 | 'PORT': '', 15 | 'OPTIONS': { 16 | 'init_command': 'SET storage_engine=InnoDB', 17 | 'charset' : 'utf8', 18 | 'use_unicode' : True, 19 | }, 20 | 'TEST_CHARSET': 'utf8', 21 | 'TEST_COLLATION': 'utf8_general_ci', 22 | }, 23 | # 'slave': { 24 | # ... 25 | # }, 26 | } 27 | 28 | # Recipients of traceback emails and other notifications. 29 | ADMINS = ( 30 | # ('Your Name', 'your_email@domain.com'), 31 | ) 32 | MANAGERS = ADMINS 33 | 34 | # Debugging displays nice error messages, but leaks memory. Set this to False 35 | # on all server instances and True only for development. 36 | DEBUG = TEMPLATE_DEBUG = True 37 | 38 | # Is this a development instance? Set this to True on development/master 39 | # instances and False on stage/prod. 40 | DEV = True 41 | 42 | # Playdoh ships with sha512 password hashing by default. Bcrypt+HMAC is safer, 43 | # so it is recommended. Please read , 44 | # then switch this to bcrypt and pick a secret HMAC key for your application. 45 | #PWD_ALGORITHM = 'bcrypt' 46 | #HMAC_KEYS = { # for bcrypt only 47 | # '2011-01-01': 'cheesecake', 48 | #} 49 | 50 | AUTH_LDAP_SERVER_URI = 'ldap://pm-ns.mozilla.org' 51 | AUTH_LDAP_BIND_DN = '' 52 | AUTH_LDAP_BIND_PASSWORD = '' 53 | -------------------------------------------------------------------------------- /lib/product_details_json/firefox_history_stability_releases.json: -------------------------------------------------------------------------------- 1 | {"1.0.1":"2005-02-24","1.0.2":"2005-03-23","1.0.3":"2005-04-15","1.0.4":"2005-05-11","1.0.5":"2005-07-12","1.0.6":"2005-07-19","1.0.7":"2005-09-20","1.0.8":"2006-04-13","1.5.0.1":"2006-02-01","1.5.0.2":"2006-04-13","1.5.0.3":"2006-05-02","1.5.0.4":"2006-06-01","1.5.0.5":"2006-07-26","1.5.0.6":"2006-08-02","1.5.0.7":"2006-09-14","1.5.0.8":"2006-11-07","1.5.0.9":"2006-12-19","1.5.0.10":"2007-02-23","1.5.0.11":"2007-03-20","1.5.0.12":"2007-05-30","2.0.0.1":"2006-12-19","2.0.0.2":"2007-02-23","2.0.0.3":"2007-03-20","2.0.0.4":"2007-05-30","2.0.0.5":"2007-07-17","2.0.0.6":"2007-07-30","2.0.0.7":"2007-09-18","2.0.0.8":"2007-10-18","2.0.0.9":"2007-11-01","2.0.0.10":"2007-11-26","2.0.0.11":"2007-11-30","2.0.0.12":"2008-02-07","2.0.0.13":"2008-03-25","2.0.0.14":"2008-04-16","2.0.0.15":"2008-07-01","2.0.0.16":"2008-07-15","2.0.0.17":"2008-09-23","2.0.0.18":"2008-11-12","2.0.0.19":"2008-12-16","2.0.0.20":"2008-12-18","3.0.1":"2008-07-16","3.0.2":"2008-09-23","3.0.3":"2008-09-26","3.0.4":"2008-11-12","3.0.5":"2008-12-16","3.0.6":"2009-02-03","3.0.7":"2009-03-04","3.0.8":"2009-03-27","3.0.9":"2009-04-21","3.0.10":"2009-04-27","3.0.11":"2009-06-11","3.0.12":"2009-07-21","3.0.13":"2009-08-03","3.0.14":"2009-09-09","3.0.15":"2009-10-27","3.0.16":"2009-12-15","3.0.17":"2010-01-05","3.0.18":"2010-02-17","3.0.19":"2010-03-30","3.5.1":"2009-07-17","3.5.2":"2009-08-03","3.5.3":"2009-09-09","3.5.4":"2009-10-27","3.5.5":"2009-11-05","3.5.6":"2009-12-15","3.5.7":"2010-01-05","3.5.8":"2010-02-17","3.5.9":"2010-03-30","3.5.10":"2010-06-22","3.5.11":"2010-07-20","3.5.12":"2010-09-07","3.5.13":"2010-09-15","3.5.14":"2010-10-19","3.5.15":"2010-10-27","3.6.16":"2010-12-09","3.6.2":"2010-03-22","3.6.3":"2010-04-01","3.6.4":"2010-06-22","3.6.6":"2010-06-26","3.6.7":"2010-07-20","3.6.8":"2010-07-23","3.6.9":"2010-09-07","3.6.10":"2010-09-15","3.6.11":"2010-10-19","3.6.12":"2010-10-27","3.6.13":"2010-12-09"} -------------------------------------------------------------------------------- /lib/product_details_json/firefox_beta_builds.json: -------------------------------------------------------------------------------- 1 | {"ast":{"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}},"4.0b10":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.6}}},"es-CL":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}}},"es-MX":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}}},"gd":{"4.0b10":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}},"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}}},"kk":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.6}}},"ku":{"3.5.16":[],"3.6.13":{"Windows":{"filesize":7.9},"OS X":{"filesize":19},"Linux":{"filesize":9.6}}},"mn":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":[]},"or":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":8},"OS X":{"filesize":19},"Linux":{"filesize":9.8}}},"rm":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"4.0b10":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.5}},"3.6.13":{"Windows":{"filesize":7.8},"OS X":{"filesize":19},"Linux":{"filesize":9.6}}},"ta":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":8},"OS X":{"filesize":19},"Linux":{"filesize":9.8}}},"ta-LK":{"3.5.16":{"Windows":{"filesize":7.6},"OS X":{"filesize":17.4},"Linux":{"filesize":9.2}},"3.6.13":{"Windows":{"filesize":7.9},"OS X":{"filesize":19},"Linux":{"filesize":9.6}}}} -------------------------------------------------------------------------------- /apps/users/urls.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django.conf.urls.defaults import * 37 | import views 38 | 39 | urlpatterns = patterns('', 40 | url('^login/', views.login, name='users.login'), 41 | url('^logout/', views.logout, name='users.logout'), 42 | url('^settings/', views.settings_page, name='users.settings'), 43 | ) 44 | -------------------------------------------------------------------------------- /apps/commons/helpers.py: -------------------------------------------------------------------------------- 1 | import cgi 2 | import datetime 3 | import urllib 4 | import urlparse 5 | 6 | from django.conf import settings 7 | from django.template import defaultfilters 8 | from django.utils.html import strip_tags 9 | 10 | from jingo import register 11 | import jinja2 12 | 13 | from .urlresolvers import reverse 14 | 15 | 16 | # Yanking filters from Django. 17 | register.filter(strip_tags) 18 | register.filter(defaultfilters.timesince) 19 | register.filter(defaultfilters.truncatewords) 20 | 21 | 22 | 23 | @register.function 24 | def thisyear(): 25 | """The current year.""" 26 | return jinja2.Markup(datetime.date.today().year) 27 | 28 | 29 | @register.function 30 | def url(viewname, *args, **kwargs): 31 | """Helper for Django's ``reverse`` in templates.""" 32 | return reverse(viewname, args=args, kwargs=kwargs) 33 | 34 | 35 | @register.filter 36 | def urlparams(url_, hash=None, **query): 37 | """ 38 | Add a fragment and/or query paramaters to a URL. 39 | 40 | New query params will be appended to exising parameters, except duplicate 41 | names, which will be replaced. 42 | """ 43 | url = urlparse.urlparse(url_) 44 | fragment = hash if hash is not None else url.fragment 45 | 46 | # Use dict(parse_qsl) so we don't get lists of values. 47 | q = url.query 48 | query_dict = dict(urlparse.parse_qsl(smart_str(q))) if q else {} 49 | query_dict.update((k, v) for k, v in query.items()) 50 | 51 | query_string = _urlencode([(k, v) for k, v in query_dict.items() 52 | if v is not None]) 53 | new = urlparse.ParseResult(url.scheme, url.netloc, url.path, url.params, 54 | query_string, fragment) 55 | return new.geturl() 56 | 57 | def _urlencode(items): 58 | """A Unicode-safe URLencoder.""" 59 | try: 60 | return urllib.urlencode(items) 61 | except UnicodeEncodeError: 62 | return urllib.urlencode([(k, smart_str(v)) for k, v in items]) 63 | 64 | 65 | @register.filter 66 | def urlencode(txt): 67 | """Url encode a path.""" 68 | return urllib.quote_plus(txt) 69 | -------------------------------------------------------------------------------- /apps/commons/middleware.py: -------------------------------------------------------------------------------- 1 | """ 2 | Taken from zamboni.amo.middleware. 3 | 4 | This is django-localeurl, but with mozilla style capital letters in 5 | the locale codes. 6 | """ 7 | 8 | import urllib 9 | 10 | from django.http import HttpResponsePermanentRedirect 11 | from django.utils.encoding import smart_str 12 | 13 | import tower 14 | 15 | from . import urlresolvers 16 | from .helpers import urlparams 17 | 18 | class LocaleURLMiddleware(object): 19 | """ 20 | 1. Search for the locale. 21 | 2. Save it in the request. 22 | 3. Strip them from the URL. 23 | """ 24 | 25 | def process_request(self, request): 26 | prefixer = urlresolvers.Prefixer(request) 27 | urlresolvers.set_url_prefix(prefixer) 28 | full_path = prefixer.fix(prefixer.shortened_path) 29 | 30 | if 'lang' in request.GET: 31 | # Blank out the locale so that we can set a new one. Remove lang 32 | # from the query params so we don't have an infinite loop. 33 | prefixer.locale = '' 34 | new_path = prefixer.fix(prefixer.shortened_path) 35 | query = dict((smart_str(k), request.GET[k]) for k in request.GET) 36 | query.pop('lang') 37 | return HttpResponsePermanentRedirect(urlparams(new_path, **query)) 38 | 39 | if full_path != request.path: 40 | query_string = request.META.get('QUERY_STRING', '') 41 | full_path = urllib.quote(full_path.encode('utf-8')) 42 | 43 | if query_string: 44 | full_path = '%s?%s' % (full_path, query_string) 45 | 46 | response = HttpResponsePermanentRedirect(full_path) 47 | 48 | # Vary on Accept-Language if we changed the locale 49 | old_locale = prefixer.locale 50 | new_locale, _ = prefixer.split_path(full_path) 51 | if old_locale != new_locale: 52 | response['Vary'] = 'Accept-Language' 53 | 54 | return response 55 | 56 | request.path_info = '/' + prefixer.shortened_path 57 | request.locale = prefixer.locale 58 | tower.activate(prefixer.locale) 59 | -------------------------------------------------------------------------------- /apps/users/models.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django.db import models 37 | from django.contrib.auth.models import User 38 | 39 | 40 | def get_user_profile(user): 41 | try: 42 | return user.get_profile() 43 | except UserProfile.DoesNotExist: 44 | return UserProfile.objects.create(user=user) 45 | 46 | 47 | class UserProfile(models.Model): 48 | user = models.ForeignKey(User) 49 | notes = models.TextField(blank=True) 50 | -------------------------------------------------------------------------------- /apps/commons/tests/test_migrations.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import listdir 3 | from os.path import join, dirname 4 | 5 | import test_utils 6 | 7 | import manage 8 | 9 | 10 | class MigrationTests(test_utils.TestCase): 11 | """Sanity checks for the SQL migration scripts.""" 12 | 13 | @staticmethod 14 | def _migrations_path(): 15 | """Return the absolute path to the migration script folder.""" 16 | return manage.path('migrations') 17 | 18 | def test_unique(self): 19 | """Assert that the numeric prefixes of the DB migrations are unique.""" 20 | leading_digits = re.compile(r'^\d+') 21 | seen_numbers = set() 22 | path = self._migrations_path() 23 | for filename in listdir(path): 24 | match = leading_digits.match(filename) 25 | if match: 26 | number = match.group() 27 | if number in seen_numbers: 28 | self.fail('There is more than one migration #%s in %s.' % 29 | (number, path)) 30 | seen_numbers.add(number) 31 | 32 | def test_innodb_and_utf8(self): 33 | """Make sure each created table uses the InnoDB engine and UTF-8.""" 34 | # Heuristic: make sure there are at least as many "ENGINE=InnoDB"s as 35 | # "CREATE TABLE"s. (There might be additional "InnoDB"s in ALTER TABLE 36 | # statements, which are fine.) 37 | path = self._migrations_path() 38 | for filename in sorted(listdir(path)): 39 | with open(join(path, filename)) as f: 40 | contents = f.read() 41 | creates = contents.count('CREATE TABLE') 42 | engines = contents.count('ENGINE=InnoDB') 43 | encodings = (contents.count('CHARSET=utf8') + 44 | contents.count('CHARACTER SET utf8')) 45 | assert engines >= creates, ("There weren't as many " 46 | 'occurrences of "ENGINE=InnoDB" as of "CREATE TABLE" in ' 47 | 'migration %s.' % filename) 48 | assert encodings >= creates, ("There weren't as many " 49 | 'UTF-8 declarations as "CREATE TABLE" occurrences in ' 50 | 'migration %s.' % filename) 51 | -------------------------------------------------------------------------------- /apps/users/templates/users/settings.html: -------------------------------------------------------------------------------- 1 | {# 2 | 37 | #} 38 | 39 | {% extends "base.html" %} 40 | 41 | {% block content %} 42 |

Settings

43 | 44 |
{{ csrf() }} 45 | 46 | {{ form|safe }} 47 | 48 | 49 | 50 | 51 |
 
52 |
53 | 54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /apps/users/templates/users/login.html: -------------------------------------------------------------------------------- 1 | {# 2 | 37 | #} 38 | 39 | {% extends "base.html" %} 40 | 41 | {% block mainbody %} 42 |
43 |
{{ csrf() }} 44 | {% if next %} 45 |
46 | {% endif %} 47 | 48 | {{ form.as_table()|safe }} 49 | 50 | 51 | 52 | 53 |
 
54 |
55 |
56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /settings/base.py: -------------------------------------------------------------------------------- 1 | # Django settings file for a project based on the playdoh template. 2 | 3 | from funfactory.settings_base import * 4 | 5 | MINIFY_BUNDLES = { 6 | 'css': { 7 | 'common_css': ( 8 | 'css/dll/main.css', 9 | ), 10 | }, 11 | 'js': { 12 | 'common_js': ( 13 | 'js/libs/jquery-1.6.2.js', 14 | 'js/dll/nav.js', 15 | ), 16 | 'detail_js': ( 17 | 'js/dll/detail.js', 18 | ), 19 | } 20 | } 21 | 22 | INSTALLED_APPS += ( 23 | 'dll', 24 | 'users', 25 | ) 26 | 27 | # Because Jinja2 is the default template loader, add any non-Jinja templated 28 | # apps here: 29 | JINGO_EXCLUDE_APPS = [ 30 | 'admin', 31 | 'debug_toolbar', 32 | ] 33 | 34 | # Tells the extract script what files to look for L10n in and what function 35 | # handles the extraction. The Tower library expects this. 36 | 37 | # # Use this if you have localizable HTML files: 38 | # DOMAIN_METHODS['lhtml'] = [ 39 | # ('**/templates/**.lhtml', 40 | # 'tower.management.commands.extract.extract_tower_template'), 41 | # ] 42 | 43 | # # Use this if you have localizable HTML files: 44 | # DOMAIN_METHODS['javascript'] = [ 45 | # # Make sure that this won't pull in strings from external libraries you 46 | # # may use. 47 | # ('media/js/**.js', 'javascript'), 48 | # ] 49 | 50 | LOGGING = dict(loggers=dict(playdoh = {'level': logging.DEBUG})) 51 | 52 | AUTH_PROFILE_MODULE = 'users.UserProfile' 53 | LOGIN_URL = '/users/login/' 54 | LOGOUT_REDIRECT_URL = '/' 55 | LOGIN_REDIRECT_URL = '/' 56 | 57 | try: 58 | ## LDAP 59 | import ldap 60 | 61 | AUTHENTICATION_BACKENDS = ( 62 | 'users.email_auth_backend.EmailOrUsernameModelBackend', 63 | 'users.auth.backends.MozillaLDAPBackend', 64 | 'django.contrib.auth.backends.ModelBackend', 65 | ) 66 | 67 | # these must be set in settings/local.py! 68 | AUTH_LDAP_SERVER_URI = '' 69 | AUTH_LDAP_BIND_DN = '' 70 | AUTH_LDAP_BIND_PASSWORD = '' 71 | 72 | AUTH_LDAP_START_TLS = True 73 | AUTH_LDAP_USER_ATTR_MAP = { 74 | "first_name": "givenName", 75 | "last_name": "sn", 76 | "email": "mail", 77 | } 78 | from django_auth_ldap.config import LDAPSearch 79 | AUTH_LDAP_USER_SEARCH = LDAPSearch( 80 | "dc=mozilla", 81 | ldap.SCOPE_SUBTREE, 82 | "mail=%(user)s" 83 | ) 84 | 85 | except ImportError: 86 | AUTHENTICATION_BACKENDS = ( 87 | 'users.email_auth_backend.EmailOrUsernameModelBackend', 88 | 'django.contrib.auth.backends.ModelBackend', 89 | ) 90 | -------------------------------------------------------------------------------- /apps/users/email_auth_backend.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django.contrib.auth.models import User 37 | 38 | 39 | class EmailOrUsernameModelBackend(object): 40 | 41 | supports_object_permissions = False 42 | supports_anonymous_user = False 43 | supports_inactive_user = False 44 | 45 | def authenticate(self, username=None, password=None): 46 | if '@' in username: 47 | kwargs = {'email__iexact': username} 48 | else: 49 | kwargs = {'username': username} 50 | try: 51 | user = User.objects.get(**kwargs) 52 | if user.check_password(password): 53 | return user 54 | except User.DoesNotExist: 55 | return None 56 | 57 | def get_user(self, user_id): 58 | try: 59 | return User.objects.get(pk=user_id) 60 | except User.DoesNotExist: # pragma: no cover 61 | return None 62 | -------------------------------------------------------------------------------- /apps/users/forms.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django import forms 37 | from django.contrib.auth.models import User 38 | import django.contrib.auth.forms 39 | 40 | 41 | class EmailInput(forms.widgets.Input): 42 | input_type = 'email' 43 | 44 | def render(self, name, value, attrs=None): 45 | if attrs is None: 46 | attrs = {} 47 | attrs.update(dict(autocorrect='off', 48 | autocapitalize='off', 49 | spellcheck='false')) 50 | return super(EmailInput, self).render(name, value, attrs=attrs) 51 | 52 | class AuthenticationForm(django.contrib.auth.forms.AuthenticationForm): 53 | """override the authentication form because we use the email address as the 54 | key to authentication.""" 55 | # allows for using email to log in 56 | username = forms.CharField(label="Username", max_length=75, 57 | widget=EmailInput()) 58 | rememberme = forms.BooleanField(label="Remember me", required=False) 59 | 60 | class SettingsForm(forms.Form): 61 | username = forms.CharField(label="Username", max_length=75) 62 | 63 | def __init__(self, user, *args, **kwargs): 64 | self.user = user 65 | super(SettingsForm, self).__init__(*args, **kwargs) 66 | 67 | def clean_username(self): 68 | value = self.cleaned_data['username'].strip() 69 | if (User.objects 70 | .filter(username__iexact=value) 71 | .exclude(pk=self.user.pk) 72 | .exists()): 73 | raise forms.ValidationError("Username already used by someone else") 74 | return value 75 | -------------------------------------------------------------------------------- /apps/dll/templates/dll/view.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block extrahead %} 4 | 5 | {{ js('detail_js') }} 6 | 7 | {% endblock %} 8 | 9 | {% block mainbody %} 10 |
11 | 12 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
Created{{ dll_datetime_format(dlldata.date_created) }} by {{ dlldata.created_by }}
Modified{{ dll_datetime_format(dlldata.date_modified) }} by {{ dlldata.modified_by }}
File Name{{ dlldata.file_name }}
Common Name{{ dlldata.common_name }}
Vendor{{ dlldata.vendor }}
Distributors{{ dlldata.distributors }}
MD5 Hash{{ dlldata.md5_hash }}
Debug{{ dlldata.debug }}
Status{{ dlldata.status }}
Released{{ dlldata.released }}
Obsolete{{ dlldata.obsolete }}
Replaced By{{ dlldata.replaced_by }}
Details{{ dlldata.details }}
35 |
36 |
37 | {% for comment in comments %} 38 |
39 | {{ comment.user }} wrote at {{ comment.date }}: 40 | {{ comment.comment|nl2br }} 41 |
42 | {% endfor %} 43 |
44 |
45 | 46 | {% for x in history %} 47 | 48 | 49 | 67 | 68 | {% endfor %} 69 |
{{ x }} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {% for y in history[x] %} 58 | 59 | 60 | 61 | 62 | 63 | 64 | {% endfor %} 65 |
WhoWhatRemovedAdded
{{ y.user }}{{ y.field }}{{ y.original_state }}{{ y.changed_state }}
66 |
70 |
71 |
72 | {% endblock %} -------------------------------------------------------------------------------- /apps/dll/templates/dll/edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block extrahead %} 4 | 5 | {{ js('detail_js') }} 6 | 7 | {% endblock %} 8 | 9 | {% block mainbody %} 10 |
11 | 12 | 17 |
18 | 19 |
20 | 21 | 22 | 23 | {{ csrf() }} 24 | 25 | 26 | 27 | 28 | {{ form }} 29 | 30 |
Created{{ dll_datetime_format(form.instance.date_created) }} by {{ form.instance.created_by }}
Modified{{ dll_datetime_format(form.instance.date_modified) }} by {{ form.instance.modified_by }}
 
31 |
32 |
33 |
34 |
35 | 36 | {{ csrf() }} 37 | 38 | {{ comment_form }} 39 | 40 | 41 | 43 |
  42 |
44 | 45 | 46 | {% for comment in comments %} 47 |
48 | {{ comment.user }} wrote at {{ comment.date }}: 49 | {{ comment.comment|nl2br }} 50 |
51 | {% endfor %} 52 |
53 |
54 |
55 | 56 | {% for x in history %} 57 | 58 | 59 | 77 | 78 | {% endfor %} 79 |
{{ x }} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {% for y in history[x] %} 68 | 69 | 70 | 71 | 72 | 73 | 74 | {% endfor %} 75 |
WhoWhatRemovedAdded
{{ y.user }}{{ y.field }}{{ y.original_state }}{{ y.changed_state }}
76 |
80 |
81 | 82 |
83 | {% endblock %} -------------------------------------------------------------------------------- /media/css/dll/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial,Helvetica,sans-serif; 3 | font-size: 12px; 4 | background-color: #d8ffc1; 5 | margin: 0px; 6 | padding: 0px; 7 | } 8 | 9 | .page-header { 10 | background-color: #377810; 11 | background: -moz-linear-gradient(center top , #73A058 0%, #377810 100%); 12 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #73A058), color-stop(1, #377810)); /* webkit */ 13 | box-shadow: 0 0 3px #666666; 14 | -moz-box-shadow: 0 0 3px #666666; 15 | -webkit-box-shadow: 0 0 3px #666666; 16 | height: 75px; 17 | position: relative; 18 | } 19 | 20 | .page-header p { 21 | font-size: 30px; 22 | color: white; 23 | margin: 0px; 24 | padding: 15px; 25 | } 26 | 27 | .page-header a { 28 | color: White; 29 | text-decoration: none; 30 | } 31 | 32 | .page-header input { 33 | top: 20px; 34 | right: 20px; 35 | position: absolute; 36 | border-radius: 0.5em; 37 | -webkit-border-radius: 0.5em; 38 | -moz-border-radius: 0.5em; 39 | border: 1px solid #A0A0A0; 40 | width: 240px; 41 | background: url("/media/img/dll/search.png") no-repeat scroll 5px center #FFFFFF; 42 | font-size: 12px; 43 | padding: 3px 4px 4px 28px 44 | } 45 | 46 | .body { 47 | margin: 1em 2em; 48 | position: relative; 49 | text-align: left; 50 | } 51 | 52 | .right { 53 | text-align: right; 54 | } 55 | 56 | .panel { 57 | background: #FFFFFF; 58 | border-radius: 9px; 59 | -webkit-border-radius: 9px; 60 | -moz-border-radius: 9px; 61 | box-shadow: 0 0 3px #CCCCCC; 62 | -moz-box-shadow: 0 0 3px #CCCCCC; 63 | -webkit-box-shadow: 0 0 3px #CCCCCC; 64 | border: 1px solid #D7D7D7; 65 | padding: 10px; 66 | } 67 | 68 | .panel table { 69 | border-collapse: collapse; 70 | width: 100%; 71 | font-size: 10pt; 72 | } 73 | 74 | .panel th, span.comment-meta { 75 | text-align: left; 76 | background-color: #85c162; 77 | } 78 | 79 | span.comment-meta { 80 | font-weight: bold; 81 | 82 | } 83 | 84 | span.comment-meta, span.comment-data { 85 | display: block; 86 | padding: 3px; 87 | } 88 | 89 | .single-comment { 90 | font-size: 11pt; 91 | width: 600px; 92 | border: 1px solid #D7D7D7; 93 | margin: 10px; 94 | } 95 | 96 | .panel td, th { 97 | border: 1px solid Black; 98 | padding: 3px; 99 | } 100 | 101 | .panel tr:hover { 102 | background-color: #d0f5ba; 103 | } 104 | 105 | a { 106 | color: #3B7B15; 107 | } 108 | 109 | .pagination { 110 | font-size: 11pt; 111 | text-align: right; 112 | padding: 3px 0px 5px; 113 | } 114 | 115 | ul.tab-list { 116 | list-style: none; 117 | padding: 0; 118 | margin: 5px 0px 0px 8px; 119 | } 120 | 121 | ul.tab-list li { 122 | display: inline; 123 | border: solid #85C162; 124 | border-width: 1px 1px 0 1px; 125 | margin: 0 0.3em 0 0; 126 | padding: 3px 3px 0px 3px; 127 | font-size: 11pt; 128 | } 129 | 130 | ul.tab-list li.active { 131 | background-color: #85C162; 132 | padding-top: 7px; 133 | border-radius: 5px 5px 0px 0px; 134 | -webkit-border-radius: 5px 5px 0px 0px; 135 | -moz-border-radius: 5px 5px 0px 0px; 136 | } 137 | 138 | ul.tab-list a { 139 | color: black; 140 | text-decoration: none; 141 | } 142 | 143 | .information { 144 | border: 1px solid #85C162; 145 | padding: 5px; 146 | } 147 | 148 | .out-of-focus { 149 | display: none; 150 | } 151 | 152 | table.history td { 153 | width: 25%; 154 | } -------------------------------------------------------------------------------- /apps/dll/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.db.models.signals import pre_save 3 | from django.dispatch import receiver 4 | from django.contrib.auth.models import User 5 | import datetime 6 | 7 | 8 | class File(models.Model): 9 | """The actual DLL file itself""" 10 | STATUS_UNKNOWN = 'unknown' 11 | STATUS_VALID = 'valid' 12 | STATUS_MALWARE = 'malware' 13 | STATUS_CHOICES = ( 14 | (STATUS_UNKNOWN, 'Unknown'), 15 | (STATUS_VALID, 'Valid'), 16 | (STATUS_MALWARE, 'Malware') 17 | ) 18 | date_created = models.DateTimeField(default=datetime.datetime.utcnow) 19 | date_modified = models.DateTimeField(default=datetime.datetime.utcnow, 20 | auto_now=True) 21 | created_by = models.ForeignKey(User, related_name="created_by") 22 | modified_by = models.ForeignKey(User, related_name="modified_by") 23 | file_name = models.CharField(max_length=200, unique=True) 24 | common_name = models.CharField(max_length=200, blank=True, null=True) 25 | vendor = models.CharField(max_length=200, blank=True, null=True) 26 | distributors = models.CharField(max_length=200, blank=True, null=True) 27 | md5_hash = models.CharField(max_length=32, blank=True, null=True) 28 | debug = models.CharField(max_length=60, blank=True, null=True) 29 | status = models.CharField(max_length=10, choices=STATUS_CHOICES) 30 | released = models.DateField(blank=True, null=True) 31 | obsolete = models.BooleanField(default=False) 32 | replaced_by = models.CharField(max_length=200, blank=True, null=True) 33 | details = models.TextField(blank=True, null=True) 34 | 35 | def __unicode__(self): 36 | return self.file_name 37 | 38 | 39 | class Comment(models.Model): 40 | """Comments users have made on given DLL files""" 41 | user = models.ForeignKey(User) 42 | dll = models.ForeignKey(File) 43 | date = models.DateTimeField(default=datetime.datetime.utcnow, 44 | auto_now=True) 45 | comment = models.TextField() 46 | 47 | 48 | class FileHistory(models.Model): 49 | """A historical record of the DLL file and the changes made to it over 50 | time""" 51 | dll = models.ForeignKey(File) 52 | user = models.ForeignKey(User) 53 | date_changed = models.DateTimeField(auto_now=True) 54 | field = models.CharField(max_length=40) 55 | original_state = models.CharField(max_length=200, blank=True, null=True) 56 | changed_state = models.CharField(max_length=200, blank=True, null=True) 57 | 58 | 59 | @receiver(pre_save, sender=File) 60 | def compare_history(sender, instance, **kwargs): 61 | if not File.objects.filter(pk=instance.pk).exists(): 62 | return sender 63 | EVALUATE = ('file_name', 'common_name', 'vendor', 'distributors', 64 | 'md5_hash', 'debug', 'status', 'released', 'obsolete', 65 | 'replaced_by', 'details', ) 66 | 67 | existing = File.objects.get(pk=instance.id) 68 | for key in EVALUATE: 69 | if getattr(existing, key) != getattr(instance, key) and any([getattr(existing, key), getattr(instance, key)]): 70 | user = User.objects.get(pk=instance.modified_by_id) 71 | FileHistory.objects.create(user=user, 72 | dll=existing, 73 | field=key, 74 | original_state=getattr(existing, key), 75 | changed_state=getattr(instance, key)) 76 | return sender 77 | -------------------------------------------------------------------------------- /apps/users/monkeypatch_template_engine.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django.template import loader 37 | from django.template.response import SimpleTemplateResponse 38 | 39 | import jingo 40 | 41 | 42 | def jinja_for_django(template_name, context=None, **kw): 43 | """ 44 | If you want to use some built in logic (or a contrib app) but need to 45 | override the templates to work with Jinja, replace the object's 46 | render_to_response function with this one. That will render a Jinja 47 | template through Django's functions. An example can be found in the users 48 | app. 49 | """ 50 | if context is None: 51 | context = {} 52 | context_instance = kw.pop('context_instance') 53 | request = context_instance['request'] 54 | for d in context_instance.dicts: 55 | context.update(d) 56 | return jingo.render(request, template_name, context, **kw) 57 | 58 | 59 | ## We monkeypatch SimpleTemplateResponse.rendered_content to use our jinja 60 | ## rendering pipeline (most of the time). The exception is the admin app, where 61 | ## we render their Django templates and pipe the result through jinja to render 62 | ## our page skeleton. 63 | #def rendered_content(self): 64 | # template = self.template_name 65 | # context_instance = self.resolve_context(self.context_data) 66 | # request = context_instance['request'] 67 | # 68 | # # Gross, let's figure out if we're in the admin. 69 | # if self._current_app == 'admin': 70 | # source = loader.render_to_string(template, context_instance) 71 | # template = jingo.env.from_string(source) 72 | # # This interferes with our media() helper. 73 | # if 'media' in self.context_data: 74 | # del self.context_data['media'] 75 | # 76 | # return jingo.render_to_string(request, template, self.context_data) 77 | # 78 | #SimpleTemplateResponse.rendered_content = property(rendered_content) 79 | # 80 | -------------------------------------------------------------------------------- /apps/commons/tests/test_accepted_locales.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from django.conf import settings 5 | import test_utils 6 | 7 | import manage 8 | 9 | 10 | class AcceptedLocalesTest(test_utils.TestCase): 11 | """Test lazy evaluation of locale related settings. 12 | 13 | Verify that some localization-related settings are lazily evaluated based 14 | on the current value of the DEV variable. Depending on the value, 15 | DEV_LANGUAGES or PROD_LANGUAGES should be used. 16 | 17 | """ 18 | locale = manage.path('locale') 19 | locale_bkp = manage.path('locale_bkp') 20 | 21 | @classmethod 22 | def setup_class(cls): 23 | """Create a directory structure for locale/. 24 | 25 | Back up the existing locale/ directory and create the following 26 | hierarchy in its place: 27 | 28 | - locale/en-US/LC_MESSAGES 29 | - locale/fr/LC_MESSAGES 30 | - locale/templates/LC_MESSAGES 31 | - locale/empty_file 32 | 33 | Also, set PROD_LANGUAGES to ('en-US',). 34 | 35 | """ 36 | if os.path.exists(cls.locale_bkp): 37 | raise Exception('A backup of locale/ exists at %s which might ' 38 | 'mean that previous tests didn\'t end cleanly. ' 39 | 'Skipping the test suite.' % cls.locale_bkp) 40 | cls.DEV = settings.DEV 41 | cls.PROD_LANGUAGES = settings.PROD_LANGUAGES 42 | cls.DEV_LANGUAGES = settings.DEV_LANGUAGES 43 | settings.PROD_LANGUAGES = ('en-US',) 44 | os.rename(cls.locale, cls.locale_bkp) 45 | for loc in ('en-US', 'fr', 'templates'): 46 | os.makedirs(os.path.join(cls.locale, loc, 'LC_MESSAGES')) 47 | open(os.path.join(cls.locale, 'empty_file'), 'w').close() 48 | 49 | @classmethod 50 | def teardown_class(cls): 51 | """Remove the testing locale/ dir and bring back the backup.""" 52 | 53 | settings.DEV = cls.DEV 54 | settings.PROD_LANGUAGES = cls.PROD_LANGUAGES 55 | settings.DEV_LANGUAGES = cls.DEV_LANGUAGES 56 | shutil.rmtree(cls.locale) 57 | os.rename(cls.locale_bkp, cls.locale) 58 | 59 | def test_build_dev_languages(self): 60 | """Test that the list of dev locales is built properly. 61 | 62 | On dev instances, the list of accepted locales should correspond to 63 | the per-locale directories in locale/. 64 | 65 | """ 66 | settings.DEV = True 67 | assert (settings.DEV_LANGUAGES == ['en-US', 'fr'] or 68 | settings.DEV_LANGUAGES == ['fr', 'en-US']), \ 69 | 'DEV_LANGUAGES do not correspond to the contents of locale/.' 70 | 71 | def test_dev_languages(self): 72 | """Test the accepted locales on dev instances. 73 | 74 | On dev instances, allow locales defined in DEV_LANGUAGES. 75 | 76 | """ 77 | settings.DEV = True 78 | # simulate the successful result of the DEV_LANGUAGES list 79 | # comprehension defined in settings. 80 | settings.DEV_LANGUAGES = ['en-US', 'fr'] 81 | assert settings.LANGUAGE_URL_MAP == {'en-us': 'en-US', 'fr': 'fr'}, \ 82 | ('DEV is True, but DEV_LANGUAGES are not used to define the ' 83 | 'allowed locales.') 84 | 85 | def test_prod_languages(self): 86 | """Test the accepted locales on prod instances. 87 | 88 | On stage/prod instances, allow locales defined in PROD_LANGUAGES. 89 | 90 | """ 91 | settings.DEV = False 92 | assert settings.LANGUAGE_URL_MAP == {'en-us': 'en-US'}, \ 93 | ('DEV is False, but PROD_LANGUAGES are not used to define the ' 94 | 'allowed locales.') 95 | -------------------------------------------------------------------------------- /apps/users/auth/backends.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | from django.contrib.auth.models import User 37 | from django_auth_ldap.backend import LDAPBackend 38 | 39 | 40 | class MozillaLDAPBackend(LDAPBackend): 41 | """Overriding this class so that I can transform emails to usernames. 42 | 43 | At Mozilla we use email addresses as the username but in django I want, 44 | for example: 45 | INPUT: 46 | username -> pbengtsson@mozilla.com 47 | OUTPUT: 48 | username -> pbengtsson 49 | email -> pbengtsson@mozilla.com 50 | 51 | I can map (in settings.AUTH_LDAP_USER_ATTR_MAP): 52 | 'username' -> 'uid' 53 | and 54 | 'email -> 'mail 55 | 56 | But that means that the second time a user logs in, it's not going to 57 | find a username that is 'pbengtsson@mozilla.com' so it'll go ahead and 58 | create it again and you'll end up with duplicates once the attribute 59 | conversion is done. 60 | 61 | The other thing that this backend accomplishes is to change username 62 | entirely. Suppose, for example, that your mozilla LDAP email is 63 | 'pbengtsson@mozilla.com' but you prefer your own custom alias of 64 | 'peterbe'. What it does then, is looking at existing users that match 65 | the *email address* and returns the username for that one. 66 | """ 67 | 68 | def get_or_create_user(self, username, ldap_user): 69 | """ 70 | This must return a (User, created) 2-tuple for the given LDAP user. 71 | username is the Django-friendly username of the user. ldap_user.dn is 72 | the user's DN and ldap_user.attrs contains all of their LDAP attributes. 73 | """ 74 | # users on this site can't change their email but they can change their 75 | # username 76 | if ldap_user.attrs.get('mail'): 77 | for user in (User.objects 78 | .filter(email__iexact=ldap_user.attrs.get('mail')[0])): 79 | return (user, False) 80 | 81 | # use the default from django-auth-ldap 82 | return User.objects.get_or_create( 83 | username__iexact=username, 84 | defaults={'username': username.lower()} 85 | ) 86 | 87 | 88 | def ldap_to_django_username(self, username): 89 | """Allow users to use a different username""" 90 | try: 91 | return User.objects.get(email=username).username 92 | except User.DoesNotExist: 93 | return username.split('@')[0] 94 | -------------------------------------------------------------------------------- /apps/commons/urlresolvers.py: -------------------------------------------------------------------------------- 1 | from threading import local 2 | 3 | from django.conf import settings 4 | from django.core.urlresolvers import reverse as django_reverse 5 | from django.utils.translation.trans_real import parse_accept_lang_header 6 | 7 | 8 | # Thread-local storage for URL prefixes. Access with (get|set)_url_prefix. 9 | _local = local() 10 | 11 | 12 | def set_url_prefix(prefix): 13 | """Set the ``prefix`` for the current thread.""" 14 | _local.prefix = prefix 15 | 16 | 17 | def get_url_prefix(): 18 | """Get the prefix for the current thread, or None.""" 19 | return getattr(_local, 'prefix', None) 20 | 21 | 22 | def reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None): 23 | """Wraps Django's reverse to prepend the correct locale.""" 24 | prefixer = get_url_prefix() 25 | 26 | if prefixer: 27 | prefix = prefix or '/' 28 | url = django_reverse(viewname, urlconf, args, kwargs, prefix) 29 | if prefixer: 30 | return prefixer.fix(url) 31 | else: 32 | return url 33 | 34 | 35 | def find_supported(test): 36 | return [settings.LANGUAGE_URL_MAP[x] for 37 | x in settings.LANGUAGE_URL_MAP if 38 | x.split('-', 1)[0] == test.lower().split('-', 1)[0]] 39 | 40 | 41 | class Prefixer(object): 42 | 43 | def __init__(self, request): 44 | self.request = request 45 | split = self.split_path(request.path_info) 46 | self.locale, self.shortened_path = split 47 | 48 | def split_path(self, path_): 49 | """ 50 | Split the requested path into (locale, path). 51 | 52 | locale will be empty if it isn't found. 53 | """ 54 | path = path_.lstrip('/') 55 | 56 | # Use partitition instead of split since it always returns 3 parts 57 | first, _, rest = path.partition('/') 58 | 59 | lang = first.lower() 60 | if lang in settings.LANGUAGE_URL_MAP: 61 | return settings.LANGUAGE_URL_MAP[lang], rest 62 | else: 63 | supported = find_supported(first) 64 | if len(supported): 65 | return supported[0], rest 66 | else: 67 | return '', path 68 | 69 | def get_language(self): 70 | """ 71 | Return a locale code we support on the site using the 72 | user's Accept-Language header to determine which is best. This 73 | mostly follows the RFCs but read bug 439568 for details. 74 | """ 75 | if 'lang' in self.request.GET: 76 | lang = self.request.GET['lang'].lower() 77 | if lang in settings.LANGUAGE_URL_MAP: 78 | return settings.LANGUAGE_URL_MAP[lang] 79 | 80 | if self.request.META.get('HTTP_ACCEPT_LANGUAGE'): 81 | best = self.get_best_language( 82 | self.request.META['HTTP_ACCEPT_LANGUAGE']) 83 | if best: 84 | return best 85 | return settings.LANGUAGE_CODE 86 | 87 | def get_best_language(self, accept_lang): 88 | """Given an Accept-Language header, return the best-matching language.""" 89 | LUM = settings.LANGUAGE_URL_MAP 90 | PREFIXES = dict((x.split('-')[0], LUM[x]) for x in LUM) 91 | langs = dict(LUM) 92 | langs.update((k.split('-')[0], v) for k, v in LUM.items() if 93 | k.split('-')[0] not in langs) 94 | ranked = parse_accept_lang_header(accept_lang) 95 | for lang, _ in ranked: 96 | lang = lang.lower() 97 | if lang in langs: 98 | return langs[lang] 99 | pre = lang.split('-')[0] 100 | if pre in langs: 101 | return langs[pre] 102 | # Could not find an acceptable language. 103 | return False 104 | 105 | def fix(self, path): 106 | path = path.lstrip('/') 107 | url_parts = [self.request.META['SCRIPT_NAME']] 108 | 109 | if path.partition('/')[0] not in settings.SUPPORTED_NONLOCALES: 110 | locale = self.locale if self.locale else self.get_language() 111 | url_parts.append(locale) 112 | 113 | url_parts.append(path) 114 | 115 | return '/'.join(url_parts) 116 | -------------------------------------------------------------------------------- /apps/dll/views.py: -------------------------------------------------------------------------------- 1 | import collections 2 | from time import mktime 3 | 4 | from django import http 5 | from django.shortcuts import redirect, get_object_or_404 6 | from django.contrib.auth.decorators import login_required 7 | 8 | from django.views.decorators.csrf import csrf_exempt 9 | import bleach 10 | import jingo 11 | 12 | from dll.forms import FileForm, CommentForm, SearchForm 13 | from dll.models import File, Comment, FileHistory 14 | from django.core.paginator import Paginator, EmptyPage, InvalidPage 15 | 16 | from django.db.models import Q 17 | 18 | PAGE_LENGTH = 50 19 | 20 | 21 | def home(request, page_no): 22 | dll_list = File.objects.all().order_by('-date_created') 23 | paginator = Paginator(dll_list, PAGE_LENGTH) 24 | try: 25 | page = int(page_no) 26 | except (ValueError, TypeError): 27 | page = 1 28 | 29 | try: 30 | dlls = paginator.page(page) 31 | except (EmptyPage, InvalidPage): 32 | dlls = paginator.page(paginator.num_pages) 33 | 34 | data = {'dlls': dlls, 'last_page': paginator.num_pages, } 35 | return jingo.render(request, 'dll/index.html', data) 36 | 37 | 38 | @csrf_exempt 39 | def search(request): 40 | search = SearchForm(data=request.GET) 41 | if search.is_valid(): 42 | term = search.cleaned_data['term'] 43 | results = File.objects.filter(Q(file_name__icontains=term) | 44 | Q(common_name__icontains=term) | 45 | Q(vendor__icontains=term) | 46 | Q(distributors__icontains=term)) 47 | else: 48 | term = '' 49 | results = [] 50 | data = {'count': len(results), 'dlls': results, 'term': term, } 51 | return jingo.render(request, 'dll/search.html', data) 52 | 53 | 54 | def view(request, dllname): 55 | thefile = get_object_or_404(File, file_name__exact=dllname) 56 | comments = Comment.objects.order_by('date').filter(dll__exact=thefile) 57 | hist = FileHistory.objects.filter(dll__exact=thefile) 58 | history = _organize_history(hist) 59 | data = {'dllname': dllname, 'dlldata': thefile, 'comments': comments, 60 | 'history': history} 61 | return jingo.render(request, 'dll/view.html', data) 62 | 63 | 64 | @login_required 65 | def create(request): 66 | """Main view.""" 67 | if request.method == 'POST': 68 | form = FileForm(request.POST) 69 | if form.is_valid(): 70 | form.instance.created_by = request.user 71 | form.instance.modified_by = request.user 72 | form.save() 73 | return redirect('dll.edit', form.cleaned_data['file_name']) 74 | else: 75 | form = FileForm() 76 | data = {'form': form} 77 | return jingo.render(request, 'dll/create.html', data) 78 | 79 | 80 | def edit(request, dllname): 81 | if not request.user.is_authenticated(): 82 | return redirect('dll.view', dllname) 83 | thefile = get_object_or_404(File, file_name__exact=dllname) 84 | comments = Comment.objects.order_by('date').filter(dll__exact=thefile) 85 | hist = FileHistory.objects.filter(dll__exact=thefile) 86 | history = _organize_history(hist) 87 | form = FileForm(instance=thefile) 88 | comment_form = CommentForm() 89 | if request.method == 'POST': 90 | if 'update_file' in request.POST: 91 | form = FileForm(request.POST, instance=thefile) 92 | if form.is_valid(): 93 | form.instance.modified_by = request.user 94 | form.save() 95 | return redirect('dll.edit', thefile.file_name) 96 | elif 'update_comment' in request.POST: 97 | comment_form = CommentForm(request.POST) 98 | if comment_form.is_valid(): 99 | Comment.objects.create(user=request.user, 100 | dll=thefile, 101 | comment=comment_form.cleaned_data['comment']) 102 | return redirect('dll.edit', thefile.file_name) 103 | data = {'dllname': dllname, 'form': form, 'comment_form': comment_form, 104 | 'comments': comments, 'history': history} 105 | return jingo.render(request, 'dll/edit.html', data) 106 | 107 | 108 | def _organize_history(resultset): 109 | res = collections.defaultdict(list) 110 | for x in resultset: 111 | res[x.date_changed].append(x) 112 | return res 113 | -------------------------------------------------------------------------------- /apps/users/views.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | import logging 37 | from django import http 38 | from django.shortcuts import redirect 39 | from django.core.urlresolvers import reverse 40 | from django.contrib.auth import REDIRECT_FIELD_NAME 41 | from django.contrib.auth.decorators import login_required 42 | from django.db import transaction 43 | from django.contrib import messages 44 | import django.contrib.auth.views 45 | from django.conf import settings 46 | import jingo 47 | import forms 48 | from models import get_user_profile 49 | from django.shortcuts import render_to_response as django_render_to_response 50 | from django.contrib.auth import logout as auth_logout 51 | 52 | def login(request): 53 | # mostly copied from zamboni 54 | logout(request) 55 | 56 | from monkeypatch_template_engine import jinja_for_django as jfd 57 | django.contrib.auth.views.render_to_response = jfd 58 | r = django.contrib.auth.views.login(request, 59 | template_name='users/login.html', 60 | redirect_field_name=REDIRECT_FIELD_NAME, 61 | authentication_form=forms.AuthenticationForm) 62 | 63 | if isinstance(r, http.HttpResponseRedirect): 64 | # Succsesful log in according to django. Now we do our checks. I do 65 | # the checks here instead of the form's clean() because I want to use 66 | # the messages framework and it's not available in the request there 67 | user = get_user_profile(request.user) 68 | rememberme = request.POST.get('rememberme', None) 69 | if rememberme: 70 | request.session.set_expiry(settings.SESSION_COOKIE_AGE) 71 | logging.debug((u'User (%s) logged in successfully with ' 72 | '"remember me" set') % user) 73 | 74 | return r 75 | 76 | 77 | def logout(request): 78 | auth_logout(request) 79 | next = request.GET.get('next') or settings.LOGOUT_REDIRECT_URL 80 | response = http.HttpResponseRedirect(next) 81 | return response 82 | 83 | 84 | @transaction.commit_on_success 85 | @login_required 86 | def settings_page(request): 87 | data = {} 88 | if request.method == 'POST': 89 | form = forms.SettingsForm(user=request.user, data=request.POST) 90 | if form.is_valid(): 91 | username = form.cleaned_data['username'] 92 | request.user.username = username 93 | request.user.save() 94 | 95 | messages.info( 96 | request, 97 | "Username changed to %s" % username 98 | ) 99 | return redirect(reverse('cal.home')) 100 | 101 | else: 102 | initial = {'username': request.user.username} 103 | form = forms.SettingsForm(user=request.user, initial=initial) 104 | 105 | data['form'] = form 106 | return jingo.render(request, 'users/settings.html', data) 107 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/playdoh.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/playdoh.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/playdoh" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/playdoh" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /bin/update_site.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: update_site.py [options] 4 | Updates a server's sources, vendor libraries, packages CSS/JS 5 | assets, migrates the database, and other nifty deployment tasks. 6 | 7 | Options: 8 | -h, --help show this help message and exit 9 | -e ENVIRONMENT, --environment=ENVIRONMENT 10 | Type of environment. One of (prod|dev|stage) Example: 11 | update_site.py -e stage 12 | -v, --verbose Echo actions before taking them. 13 | """ 14 | 15 | import os 16 | import sys 17 | from textwrap import dedent 18 | from optparse import OptionParser 19 | from hashlib import md5 20 | 21 | # Constants 22 | PROJECT = 0 23 | VENDOR = 1 24 | 25 | ENV_BRANCH = { 26 | # 'environment': [PROJECT_BRANCH, VENDOR_BRANCH], 27 | 'dev': ['base', 'master'], 28 | 'stage': ['master', 'master'], 29 | 'prod': ['prod', 'master'], 30 | } 31 | 32 | # The URL of the SVN repository with the localization files (*.po). If you set 33 | # it to a non-empty value, remember to `git rm --cached -r locale` in the root 34 | # of the project. Example: 35 | # LOCALE_REPO_URL = 'https://svn.mozilla.org/projects/l10n-misc/trunk/playdoh/locale' 36 | LOCALE_REPO_URL = '' 37 | 38 | GIT_PULL = "git pull -q origin %(branch)s" 39 | GIT_SUBMODULE = "git submodule update --init" 40 | SVN_CO = "svn checkout --force %(url)s locale" 41 | SVN_UP = "svn update" 42 | COMPILE_MO = "./bin/compile-mo.sh %(localedir)s %(unique)s" 43 | 44 | EXEC = 'exec' 45 | CHDIR = 'chdir' 46 | 47 | 48 | def update_site(env, debug): 49 | """Run through commands to update this site.""" 50 | error_updating = False 51 | here = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 52 | locale = os.path.join(here, 'locale') 53 | unique = md5(locale).hexdigest() 54 | project_branch = {'branch': ENV_BRANCH[env][PROJECT]} 55 | vendor_branch = {'branch': ENV_BRANCH[env][VENDOR]} 56 | 57 | commands = [ 58 | (CHDIR, here), 59 | (EXEC, GIT_PULL % project_branch), 60 | (EXEC, GIT_SUBMODULE), 61 | ] 62 | 63 | # Checkout the locale repo into locale/ if the URL is known 64 | if LOCALE_REPO_URL and not os.path.exists(os.path.join(locale, '.svn')): 65 | commands += [ 66 | (EXEC, SVN_CO % {'url': LOCALE_REPO_URL}), 67 | (EXEC, COMPILE_MO % {'localedir': locale, 'unique': unique}), 68 | ] 69 | 70 | # Update locale dir if applicable 71 | if os.path.exists(os.path.join(locale, '.svn')): 72 | commands += [ 73 | (CHDIR, locale), 74 | (EXEC, SVN_UP), 75 | (CHDIR, here), 76 | (EXEC, COMPILE_MO % {'localedir': locale, 'unique': unique}), 77 | ] 78 | elif os.path.exists(os.path.join(locale, '.git')): 79 | commands += [ 80 | (CHDIR, locale), 81 | (EXEC, GIT_PULL % 'master'), 82 | (CHDIR, here), 83 | ] 84 | 85 | commands += [ 86 | (CHDIR, os.path.join(here, 'vendor')), 87 | (EXEC, GIT_PULL % vendor_branch), 88 | (EXEC, GIT_SUBMODULE), 89 | (CHDIR, os.path.join(here)), 90 | (EXEC, 'python2.6 vendor/src/schematic/schematic migrations/'), 91 | (EXEC, 'python2.6 manage.py compress_assets'), 92 | ] 93 | 94 | for cmd, cmd_args in commands: 95 | if CHDIR == cmd: 96 | if debug: 97 | sys.stdout.write("cd %s\n" % cmd_args) 98 | os.chdir(cmd_args) 99 | elif EXEC == cmd: 100 | if debug: 101 | sys.stdout.write("%s\n" % cmd_args) 102 | if not 0 == os.system(cmd_args): 103 | error_updating = True 104 | break 105 | else: 106 | raise Exception("Unknown type of command %s" % cmd) 107 | 108 | if error_updating: 109 | sys.stderr.write("There was an error while updating. Please try again " 110 | "later. Aborting.\n") 111 | 112 | 113 | def main(): 114 | """ Handels command line args. """ 115 | debug = False 116 | usage = dedent("""\ 117 | %prog [options] 118 | Updates a server's sources, vendor libraries, packages CSS/JS 119 | assets, migrates the database, and other nifty deployment tasks. 120 | """.rstrip()) 121 | 122 | options = OptionParser(usage=usage) 123 | e_help = "Type of environment. One of (%s) Example: update_site.py \ 124 | -e stage" % '|'.join(ENV_BRANCH.keys()) 125 | options.add_option("-e", "--environment", help=e_help) 126 | options.add_option("-v", "--verbose", 127 | help="Echo actions before taking them.", 128 | action="store_true", dest="verbose") 129 | (opts, _) = options.parse_args() 130 | 131 | if opts.verbose: 132 | debug = True 133 | if opts.environment in ENV_BRANCH.keys(): 134 | update_site(opts.environment, debug) 135 | else: 136 | sys.stderr.write("Invalid environment!\n") 137 | options.print_help(sys.stderr) 138 | sys.exit(1) 139 | 140 | 141 | if __name__ == '__main__': 142 | main() 143 | -------------------------------------------------------------------------------- /lib/product_details_json/languages.json: -------------------------------------------------------------------------------- 1 | {"af":{"English":"Afrikaans","native":"Afrikaans"},"ak":{"English":"Akan","native":"Akan"},"ast":{"English":"Asturian","native":"Asturianu"},"ar":{"English":"Arabic","native":"\u0639\u0631\u0628\u064a"},"as":{"English":"Assamese","native":"\u0985\u09b8\u09ae\u09c0\u09af\u09bc\u09be"},"be":{"English":"Belarusian","native":"\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f"},"bg":{"English":"Bulgarian","native":"\u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438"},"bn-BD":{"English":"Bengali (Bangladesh)","native":"\u09ac\u09be\u0982\u09b2\u09be (\u09ac\u09be\u0982\u09b2\u09be\u09a6\u09c7\u09b6)"},"bn-IN":{"English":"Bengali (India)","native":"\u09ac\u09be\u0982\u09b2\u09be (\u09ad\u09be\u09b0\u09a4)"},"br":{"English":"Breton","native":"Brezhoneg"},"ca":{"English":"Catalan","native":"catal\u00e0"},"ca-valencia":{"English":"Catalan (Valencian)","native":"catal\u00e0 (valenci\u00e0)"},"cs":{"English":"Czech","native":"\u010ce\u0161tina"},"cy":{"English":"Welsh","native":"Cymraeg"},"da":{"English":"Danish","native":"Dansk"},"de":{"English":"German","native":"Deutsch"},"de-AT":{"English":"German (Austria)","native":"Deutsch (\u00d6sterreich)"},"de-CH":{"English":"German (Switzerland)","native":"Deutsch (Schweiz)"},"de-DE":{"English":"German (Germany)","native":"Deutsch (Deutschland)"},"dsb":{"English":"Lower Sorbian","native":"Dolnoserb\u0161\u0107ina"},"el":{"English":"Greek","native":"\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac"},"en-AU":{"English":"English (Australian)","native":"English (Australian)"},"en-CA":{"English":"English (Canadian)","native":"English (Canadian)"},"en-GB":{"English":"English (British)","native":"English (British)"},"en-NZ":{"English":"English (New Zealand)","native":"English (New Zealand)"},"en-US":{"English":"English (US)","native":"English (US)"},"en-ZA":{"English":"English (South African)","native":"English (South African)"},"eo":{"English":"Esperanto","native":"Esperanto"},"es":{"English":"Spanish","native":"Espa\u00f1ol"},"es-AR":{"English":"Spanish (Argentina)","native":"Espa\u00f1ol (de Argentina)"},"es-CL":{"English":"Spanish (Chile)","native":"Espa\u00f1ol (de Chile)"},"es-ES":{"English":"Spanish (Spain)","native":"Espa\u00f1ol (de Espa\u00f1a)"},"es-MX":{"English":"Spanish (Mexico)","native":"Espa\u00f1ol (de M\u00e9xico)"},"et":{"English":"Estonian","native":"Eesti keel"},"eu":{"English":"Basque","native":"Euskara"},"fa":{"English":"Persian","native":"\u0641\u0627\u0631\u0633\u06cc"},"fi":{"English":"Finnish","native":"suomi"},"fj-FJ":{"English":"Fijian","native":"Vosa vaka-Viti"},"fr":{"English":"French","native":"Fran\u00e7ais"},"fur-IT":{"English":"Friulian","native":"Furlan"},"fy-NL":{"English":"Frisian","native":"Frysk"},"ga":{"English":"Irish","native":"Gaeilge"},"ga-IE":{"English":"Irish (Ireland)","native":"Gaeilge (\u00c9ire)"},"gd":{"English":"Gaelic (Scotland)","native":"G\u00e0idhlig"},"gl":{"English":"Galician","native":"Galego"},"gu-IN":{"English":"Gujarati","native":"\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0"},"he":{"English":"Hebrew","native":"\u05e2\u05d1\u05e8\u05d9\u05ea"},"hi":{"English":"Hindi","native":"\u0939\u093f\u0928\u094d\u0926\u0940"},"hi-IN":{"English":"Hindi (India)","native":"\u0939\u093f\u0928\u094d\u0926\u0940 (\u092d\u093e\u0930\u0924)"},"hr":{"English":"Croatian","native":"Hrvatski"},"hsb":{"English":"Upper Sorbian","native":"Hornjoserbsce"},"hu":{"English":"Hungarian","native":"Magyar"},"hy-AM":{"English":"Armenian","native":"\u0540\u0561\u0575\u0565\u0580\u0565\u0576"},"id":{"English":"Indonesian","native":"Bahasa Indonesia"},"is":{"English":"Icelandic","native":"\u00edslenska"},"it":{"English":"Italian","native":"Italiano"},"ja":{"English":"Japanese","native":"\u65e5\u672c\u8a9e"},"ja-JP-mac":{"English":"Japanese","native":"\u65e5\u672c\u8a9e"},"ka":{"English":"Georgian","native":"\u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8"},"kk":{"English":"Kazakh","native":"\u049a\u0430\u0437\u0430\u049b"},"kn":{"English":"Kannada","native":"\u0c95\u0ca8\u0ccd\u0ca8\u0ca1"},"ko":{"English":"Korean","native":"\ud55c\uad6d\uc5b4"},"ku":{"English":"Kurdish","native":"Kurd\u00ee"},"la":{"English":"Latin","native":"Latina"},"lg":{"English":"Luganda","native":"Luganda"},"lt":{"English":"Lithuanian","native":"lietuvi\u0173 kalba"},"lv":{"English":"Latvian","native":"Latvie\u0161u"},"mai":{"English":"Maithili","native":"\u092e\u0948\u0925\u093f\u0932\u0940 \u09ae\u09c8\u09a5\u09bf\u09b2\u09c0"},"mg":{"English":"Malagasy","native":"Malagasy"},"mi":{"English":"Maori (Aotearoa)","native":"M\u0101ori (Aotearoa)"},"mk":{"English":"Macedonian","native":"\u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438"},"ml":{"English":"Malayalam","native":"\u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02"},"mn":{"English":"Mongolian","native":"\u041c\u043e\u043d\u0433\u043e\u043b"},"mr":{"English":"Marathi","native":"\u092e\u0930\u093e\u0920\u0940"},"nb-NO":{"English":"Norwegian (Bokm\u00e5l)","native":"Norsk bokm\u00e5l"},"ne-NP":{"English":"Nepali","native":"\u0928\u0947\u092a\u093e\u0932\u0940"},"nn-NO":{"English":"Norwegian (Nynorsk)","native":"Norsk nynorsk"},"nl":{"English":"Dutch","native":"Nederlands"},"nr":{"English":"Ndebele, South","native":"isiNdebele"},"nso":{"English":"Northern Sotho","native":"Sepedi"},"oc":{"English":"Occitan (Lengadocian)","native":"occitan (lengadocian)"},"or":{"English":"Oriya","native":"\u0b13\u0b21\u0b3c\u0b3f\u0b06"},"pa-IN":{"English":"Punjabi","native":"\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40"},"pl":{"English":"Polish","native":"Polski"},"pt-BR":{"English":"Portuguese (Brazilian)","native":"Portugu\u00eas (do Brasil)"},"pt-PT":{"English":"Portuguese (Portugal)","native":"Portugu\u00eas (Europeu)"},"ro":{"English":"Romanian","native":"rom\u00e2n\u0103"},"rm":{"English":"Romansh","native":"rumantsch"},"ru":{"English":"Russian","native":"\u0420\u0443\u0441\u0441\u043a\u0438\u0439"},"rw":{"English":"Kinyarwanda","native":"Ikinyarwanda"},"si":{"English":"Sinhala","native":"\u0dc3\u0dd2\u0d82\u0dc4\u0dbd"},"sk":{"English":"Slovak","native":"sloven\u010dina"},"sl":{"English":"Slovenian","native":"slovensko"},"son":{"English":"Songhai","native":"So\u014bay"},"sq":{"English":"Albanian","native":"Shqip"},"sr":{"English":"Serbian","native":"\u0421\u0440\u043f\u0441\u043a\u0438"},"sr-Latn":{"English":"Serbian","native":"Srpski"},"ss":{"English":"Siswati","native":"siSwati"},"st":{"English":"Southern Sotho","native":"Sesotho"},"sv-SE":{"English":"Swedish","native":"Svenska"},"ta":{"English":"Tamil","native":"\u0ba4\u0bae\u0bbf\u0bb4\u0bcd"},"ta-IN":{"English":"Tamil (India)","native":"\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe)"},"ta-LK":{"English":"Tamil (Sri Lanka)","native":"\u0ba4\u0bae\u0bbf\u0bb4\u0bcd (\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8)"},"te":{"English":"Telugu","native":"\u0c24\u0c46\u0c32\u0c41\u0c17\u0c41"},"th":{"English":"Thai","native":"\u0e44\u0e17\u0e22"},"tn":{"English":"Tswana","native":"Setswana"},"tr":{"English":"Turkish","native":"T\u00fcrk\u00e7e"},"ts":{"English":"Tsonga","native":"Xitsonga"},"tt-RU":{"English":"Tatar","native":"Tatar\u00e7a"},"uk":{"English":"Ukrainian","native":"\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430"},"ur":{"English":"Urdu","native":"\u0627\u064f\u0631\u062f\u0648"},"ve":{"English":"Venda","native":"Tshiven\u1e13a"},"vi":{"English":"Vietnamese","native":"Ti\u1ebfng Vi\u1ec7t"},"wo":{"English":"Wolof","native":"Wolof"},"xh":{"English":"Xhosa","native":"isiXhosa"},"zh-CN":{"English":"Chinese (Simplified)","native":"\u4e2d\u6587 (\u7b80\u4f53)"},"zh-TW":{"English":"Chinese (Traditional)","native":"\u6b63\u9ad4\u4e2d\u6587 (\u7e41\u9ad4)"},"zu":{"English":"Zulu","native":"isiZulu"}} -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # playdoh documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jan 4 15:11:09 2011. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'a playdoh-based project' 44 | copyright = u'2011, the authors' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '1.0' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '1.0' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. See the documentation for 93 | # a list of builtin themes. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | #html_theme_options = {} 100 | 101 | # Add any paths that contain custom themes here, relative to this directory. 102 | #html_theme_path = [] 103 | 104 | # The name for this set of Sphinx documents. If None, it defaults to 105 | # " v documentation". 106 | #html_title = None 107 | 108 | # A shorter title for the navigation bar. Default is the same as html_title. 109 | #html_short_title = None 110 | 111 | # The name of an image file (relative to this directory) to place at the top 112 | # of the sidebar. 113 | #html_logo = None 114 | 115 | # The name of an image file (within the static path) to use as favicon of the 116 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 117 | # pixels large. 118 | #html_favicon = None 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ['_static'] 124 | 125 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 126 | # using the given strftime format. 127 | #html_last_updated_fmt = '%b %d, %Y' 128 | 129 | # If true, SmartyPants will be used to convert quotes and dashes to 130 | # typographically correct entities. 131 | #html_use_smartypants = True 132 | 133 | # Custom sidebar templates, maps document names to template names. 134 | #html_sidebars = {} 135 | 136 | # Additional templates that should be rendered to pages, maps page names to 137 | # template names. 138 | #html_additional_pages = {} 139 | 140 | # If false, no module index is generated. 141 | #html_domain_indices = True 142 | 143 | # If false, no index is generated. 144 | #html_use_index = True 145 | 146 | # If true, the index is split into individual pages for each letter. 147 | #html_split_index = False 148 | 149 | # If true, links to the reST sources are added to the pages. 150 | #html_show_sourcelink = True 151 | 152 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 153 | #html_show_sphinx = True 154 | 155 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 156 | #html_show_copyright = True 157 | 158 | # If true, an OpenSearch description file will be output, and all pages will 159 | # contain a tag referring to it. The value of this option must be the 160 | # base URL from which the finished HTML is served. 161 | #html_use_opensearch = '' 162 | 163 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 164 | #html_file_suffix = None 165 | 166 | # Output file base name for HTML help builder. 167 | htmlhelp_basename = 'playdohdoc' 168 | 169 | 170 | # -- Options for LaTeX output -------------------------------------------------- 171 | 172 | # The paper size ('letter' or 'a4'). 173 | #latex_paper_size = 'letter' 174 | 175 | # The font size ('10pt', '11pt' or '12pt'). 176 | #latex_font_size = '10pt' 177 | 178 | # Grouping the document tree into LaTeX files. List of tuples 179 | # (source start file, target name, title, author, documentclass [howto/manual]). 180 | latex_documents = [ 181 | ('index', 'playdoh.tex', u'playdoh Documentation', 182 | u'Mozilla', 'manual'), 183 | ] 184 | 185 | # The name of an image file (relative to this directory) to place at the top of 186 | # the title page. 187 | #latex_logo = None 188 | 189 | # For "manual" documents, if this is true, then toplevel headings are parts, 190 | # not chapters. 191 | #latex_use_parts = False 192 | 193 | # If true, show page references after internal links. 194 | #latex_show_pagerefs = False 195 | 196 | # If true, show URL addresses after external links. 197 | #latex_show_urls = False 198 | 199 | # Additional stuff for the LaTeX preamble. 200 | #latex_preamble = '' 201 | 202 | # Documents to append as an appendix to all manuals. 203 | #latex_appendices = [] 204 | 205 | # If false, no module index is generated. 206 | #latex_domain_indices = True 207 | 208 | 209 | # -- Options for manual page output -------------------------------------------- 210 | 211 | # One entry per manual page. List of tuples 212 | # (source start file, name, description, authors, manual section). 213 | man_pages = [ 214 | ('index', 'a-playdoh-app', u"a-playdoh-app's Documentation", 215 | [u'the authors'], 1) 216 | ] 217 | 218 | 219 | # Example configuration for intersphinx: refer to the Python standard library. 220 | intersphinx_mapping = {'http://docs.python.org/': None} 221 | -------------------------------------------------------------------------------- /lib/product_details_json/thunderbird_primary_builds.json: -------------------------------------------------------------------------------- 1 | {"af":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"ar":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"be":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.7}}},"bg":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"bn-BD":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"ca":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"cs":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"da":{"3.0.11":{"Windows":{"filesize":8.9},"OS X":{"filesize":19.8},"Linux":{"filesize":10.8}},"3.1.7":{"Windows":{"filesize":9.3},"OS X":{"filesize":21},"Linux":{"filesize":11.3}}},"de":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"el":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"en-GB":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"en-US":{"3.0.11":{"Windows":{"filesize":8.6},"OS X":{"filesize":19.5},"Linux":{"filesize":10.5}},"3.1.7":{"Windows":{"filesize":9},"OS X":{"filesize":20.6},"Linux":{"filesize":11}}},"es-AR":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"es-ES":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.8},"OS X":{"filesize":20.4},"Linux":{"filesize":10.7}}},"et":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"eu":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"fi":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"fr":{"3.0.11":{"Windows":{"filesize":8.7},"OS X":{"filesize":19.5},"Linux":{"filesize":10.5}},"3.1.7":{"Windows":{"filesize":9.1},"OS X":{"filesize":20.7},"Linux":{"filesize":11}}},"fy-NL":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"ga-IE":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"gd":{"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"gl":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"he":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"hu":{"3.0.11":{"Windows":{"filesize":9},"OS X":{"filesize":19.9},"Linux":{"filesize":10.9}},"3.1.7":{"Windows":{"filesize":9.4},"OS X":{"filesize":21.1},"Linux":{"filesize":11.4}}},"id":{"3.0.11":{"Windows":{"filesize":8.6},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.5},"Linux":{"filesize":10.9}}},"is":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"it":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.8},"OS X":{"filesize":20.4},"Linux":{"filesize":10.7}}},"ja":{"3.0.11":{"Windows":{"filesize":8.7},"OS X":{"filesize":19.5},"Linux":{"filesize":10.5}},"3.1.7":{"Windows":{"filesize":9},"OS X":{"filesize":20.7},"Linux":{"filesize":11}}},"ka":{"3.0.11":{"Windows":{"filesize":8.7},"OS X":{"filesize":19.5},"Linux":{"filesize":10.5}}},"ko":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"lt":{"3.0.11":{"Windows":{"filesize":8.8},"OS X":{"filesize":19.6},"Linux":{"filesize":10.6}},"3.1.7":{"Windows":{"filesize":9.2},"OS X":{"filesize":20.8},"Linux":{"filesize":11.1}}},"nb-NO":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"nl":{"3.0.11":{"Windows":{"filesize":9.3},"OS X":{"filesize":20.1},"Linux":{"filesize":11}},"3.1.7":{"Windows":{"filesize":9.7},"OS X":{"filesize":21.3},"Linux":{"filesize":11.6}}},"nn-NO":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"pa-IN":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"pl":{"3.0.11":{"Windows":{"filesize":9.3},"OS X":{"filesize":20.2},"Linux":{"filesize":11.3}},"3.1.7":{"Windows":{"filesize":9.7},"OS X":{"filesize":21.4},"Linux":{"filesize":11.8}}},"pt-BR":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"pt-PT":{"3.0.11":{"Windows":{"filesize":8.7},"OS X":{"filesize":19.4},"Linux":{"filesize":10.4}},"3.1.7":{"Windows":{"filesize":9},"OS X":{"filesize":20.6},"Linux":{"filesize":11}}},"ro":{"3.0.11":{"Windows":{"filesize":8.9},"OS X":{"filesize":19.8},"Linux":{"filesize":10.8}},"3.1.7":{"Windows":{"filesize":9.3},"OS X":{"filesize":21},"Linux":{"filesize":11.3}}},"ru":{"3.0.11":{"Windows":{"filesize":8.9},"OS X":{"filesize":19.7},"Linux":{"filesize":10.7}},"3.1.7":{"Windows":{"filesize":9.3},"OS X":{"filesize":20.9},"Linux":{"filesize":11.2}}},"si":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"sk":{"3.0.11":{"Windows":{"filesize":9},"OS X":{"filesize":19.8},"Linux":{"filesize":10.8}},"3.1.7":{"Windows":{"filesize":9.3},"OS X":{"filesize":21},"Linux":{"filesize":11.4}}},"sl":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"sq":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"sr":{"3.0.11":{"Windows":{"filesize":9.6},"OS X":{"filesize":20.9},"Linux":{"filesize":12.1}},"3.1.7":{"Windows":{"filesize":10},"OS X":{"filesize":22.1},"Linux":{"filesize":12.6}}},"sv-SE":{"3.0.11":{"Windows":{"filesize":8.7},"OS X":{"filesize":19.6},"Linux":{"filesize":10.6}},"3.1.7":{"Windows":{"filesize":9.1},"OS X":{"filesize":20.8},"Linux":{"filesize":11.1}}},"ta-LK":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}}},"tr":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"uk":{"3.0.11":{"Windows":{"filesize":8.9},"OS X":{"filesize":19.7},"Linux":{"filesize":10.7}},"3.1.7":{"Windows":{"filesize":9.3},"OS X":{"filesize":20.8},"Linux":{"filesize":11.2}}},"vi":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.3}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.5},"Linux":{"filesize":10.8}}},"zh-CN":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.2},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}},"zh-TW":{"3.0.11":{"Windows":{"filesize":8.5},"OS X":{"filesize":19.3},"Linux":{"filesize":10.2}},"3.1.7":{"Windows":{"filesize":8.9},"OS X":{"filesize":20.4},"Linux":{"filesize":10.8}}}} -------------------------------------------------------------------------------- /settings/base.py-back: -------------------------------------------------------------------------------- 1 | # Django settings file for a project based on the playdoh template. 2 | 3 | import os 4 | 5 | from django.utils.functional import lazy 6 | 7 | # Make file paths relative to settings. 8 | ROOT = os.path.dirname(os.path.abspath(__file__)) 9 | path = lambda *a: os.path.join(ROOT, *a) 10 | 11 | ROOT_PACKAGE = os.path.basename(ROOT) 12 | 13 | # Is this a dev instance? 14 | DEV = False 15 | 16 | DEBUG = False 17 | TEMPLATE_DEBUG = DEBUG 18 | 19 | ADMINS = () 20 | MANAGERS = ADMINS 21 | 22 | DATABASES = {} # See settings_local. 23 | 24 | # Site ID is used by Django's Sites framework. 25 | SITE_ID = 1 26 | 27 | 28 | ## Internationalization. 29 | 30 | # Local time zone for this installation. Choices can be found here: 31 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 32 | # although not all choices may be available on all operating systems. 33 | # On Unix systems, a value of None will cause Django to use the same 34 | # timezone as the operating system. 35 | # If running in a Windows environment this must be set to the same as your 36 | # system time zone. 37 | TIME_ZONE = 'America/Los_Angeles' 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale 45 | USE_L10N = True 46 | 47 | # Gettext text domain 48 | TEXT_DOMAIN = 'messages' 49 | STANDALONE_DOMAINS = [TEXT_DOMAIN, 'javascript'] 50 | TOWER_KEYWORDS = {'_lazy': None} 51 | TOWER_ADD_HEADERS = True 52 | 53 | # Language code for this installation. All choices can be found here: 54 | # http://www.i18nguy.com/unicode/language-identifiers.html 55 | LANGUAGE_CODE = 'en-US' 56 | 57 | ## Accepted locales 58 | 59 | # On dev instances, the list of accepted locales defaults to the contents of 60 | # the `locale` directory. A localizer can add their locale in the l10n 61 | # repository (copy of which is checked out into `locale`) in order to start 62 | # testing the localization on the dev server. 63 | try: 64 | DEV_LANGUAGES = [ 65 | loc.replace('_', '-') for loc in os.listdir(path('locale')) 66 | if os.path.isdir(path('locale', loc)) and loc != 'templates' 67 | ] 68 | except OSError: 69 | DEV_LANGUAGES = ('en-US',) 70 | 71 | # On stage/prod, the list of accepted locales is manually maintained. Only 72 | # locales whose localizers have signed off on their work should be listed here. 73 | PROD_LANGUAGES = ( 74 | 'en-US', 75 | ) 76 | 77 | def lazy_lang_url_map(): 78 | from django.conf import settings 79 | langs = settings.DEV_LANGUAGES if settings.DEV else settings.PROD_LANGUAGES 80 | return dict([(i.lower(), i) for i in langs]) 81 | 82 | LANGUAGE_URL_MAP = lazy(lazy_lang_url_map, dict)() 83 | 84 | # Override Django's built-in with our native names 85 | def lazy_langs(): 86 | from django.conf import settings 87 | from product_details import product_details 88 | langs = DEV_LANGUAGES if settings.DEV else PROD_LANGUAGES 89 | return dict([(lang.lower(), product_details.languages[lang]['native']) 90 | for lang in langs]) 91 | 92 | # Where to store product details etc. 93 | PROD_DETAILS_DIR = path('lib/product_details_json') 94 | 95 | LANGUAGES = lazy(lazy_langs, dict)() 96 | 97 | # Paths that don't require a locale code in the URL. 98 | SUPPORTED_NONLOCALES = ['media'] 99 | 100 | 101 | ## Media and templates. 102 | 103 | # Absolute path to the directory that holds media. 104 | # Example: "/home/media/media.lawrence.com/" 105 | MEDIA_ROOT = path('media') 106 | 107 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 108 | # trailing slash if there is a path component (optional in other cases). 109 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 110 | MEDIA_URL = '/media/' 111 | 112 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 113 | # trailing slash. 114 | # Examples: "http://foo.com/media/", "/media/". 115 | ADMIN_MEDIA_PREFIX = '/admin-media/' 116 | 117 | # Make this unique, and don't share it with anybody. 118 | SECRET_KEY = '1iz#v0m55@h26^m6hxk3a7at*h$qj_2a$juu1#nv50548j(x1v' 119 | 120 | # List of callables that know how to import templates from various sources. 121 | TEMPLATE_LOADERS = ( 122 | 'django.template.loaders.filesystem.Loader', 123 | 'django.template.loaders.app_directories.Loader', 124 | # 'django.template.loaders.eggs.Loader', 125 | ) 126 | 127 | TEMPLATE_CONTEXT_PROCESSORS = ( 128 | 'django.contrib.auth.context_processors.auth', 129 | 'django.core.context_processors.debug', 130 | 'django.core.context_processors.media', 131 | 'django.core.context_processors.request', 132 | 'django.core.context_processors.csrf', 133 | 'django.contrib.messages.context_processors.messages', 134 | 135 | 'commons.context_processors.i18n', 136 | #'jingo_minify.helpers.build_ids', 137 | ) 138 | 139 | TEMPLATE_DIRS = ( 140 | path('templates'), 141 | ) 142 | 143 | def JINJA_CONFIG(): 144 | import jinja2 145 | from django.conf import settings 146 | # from caching.base import cache 147 | config = {'extensions': ['tower.template.i18n', 'jinja2.ext.do', 148 | 'jinja2.ext.with_', 'jinja2.ext.loopcontrols'], 149 | 'finalize': lambda x: x if x is not None else ''} 150 | # if 'memcached' in cache.scheme and not settings.DEBUG: 151 | # We're passing the _cache object directly to jinja because 152 | # Django can't store binary directly; it enforces unicode on it. 153 | # Details: http://jinja.pocoo.org/2/documentation/api#bytecode-cache 154 | # and in the errors you get when you try it the other way. 155 | # bc = jinja2.MemcachedBytecodeCache(cache._cache, 156 | # "%sj2:" % settings.CACHE_PREFIX) 157 | # config['cache_size'] = -1 # Never clear the cache 158 | # config['bytecode_cache'] = bc 159 | return config 160 | 161 | # Bundles is a dictionary of two dictionaries, css and js, which list css files 162 | # and js files that can be bundled together by the minify app. 163 | MINIFY_BUNDLES = { 164 | 'css': { 165 | 'common_css': ( 166 | 'css/dll/main.css', 167 | ), 168 | }, 169 | 'js': { 170 | 'common_js': ( 171 | 'js/libs/jquery-1.6.2.js', 172 | 'js/dll/nav.js', 173 | ), 174 | 'detail_js': ( 175 | 'js/dll/detail.js', 176 | ), 177 | } 178 | } 179 | 180 | 181 | ## Middlewares, apps, URL configs. 182 | 183 | MIDDLEWARE_CLASSES = ( 184 | 'commons.middleware.LocaleURLMiddleware', 185 | 'django.middleware.common.CommonMiddleware', 186 | 'django.contrib.sessions.middleware.SessionMiddleware', 187 | 'django.middleware.csrf.CsrfViewMiddleware', 188 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 189 | 'django.contrib.messages.middleware.MessageMiddleware', 190 | 191 | 'commonware.middleware.FrameOptionsHeader', 192 | ) 193 | 194 | ROOT_URLCONF = '%s.urls' % ROOT_PACKAGE 195 | 196 | INSTALLED_APPS = ( 197 | # Local apps 198 | 'commons', # Content common to most playdoh-based apps. 199 | 'jingo_minify', 200 | 'tower', # for ./manage.py extract (L10n) 201 | 202 | # DLL Specific 203 | 'dll', 204 | 'users', 205 | 206 | # We need this so the jsi18n view will pick up our locale directory. 207 | ROOT_PACKAGE, 208 | 209 | # Third-party apps 210 | 'commonware.response.cookies', 211 | 'djcelery', 212 | 'django_nose', 213 | 214 | # Django contrib apps 215 | 'django.contrib.auth', 216 | 'django_sha2', # Load after auth to monkey-patch it. 217 | 218 | 'django.contrib.contenttypes', 219 | 'django.contrib.sessions', 220 | # 'django.contrib.sites', 221 | # 'django.contrib.messages', 222 | # Uncomment the next line to enable the admin: 223 | # 'django.contrib.admin', 224 | # Uncomment the next line to enable admin documentation: 225 | # 'django.contrib.admindocs', 226 | 227 | # L10n 228 | 'product_details', 229 | 230 | ) 231 | 232 | # Tells the extract script what files to look for L10n in and what function 233 | # handles the extraction. The Tower library expects this. 234 | DOMAIN_METHODS = { 235 | 'messages': [ 236 | ('apps/**.py', 237 | 'tower.management.commands.extract.extract_tower_python'), 238 | ('**/templates/**.html', 239 | 'tower.management.commands.extract.extract_tower_template'), 240 | ], 241 | 242 | ## Use this if you have localizable HTML files: 243 | #'lhtml': [ 244 | # ('**/templates/**.lhtml', 245 | # 'tower.management.commands.extract.extract_tower_template'), 246 | #], 247 | 248 | ## Use this if you have localizable JS files: 249 | #'javascript': [ 250 | # Make sure that this won't pull in strings from external libraries you 251 | # may use. 252 | # ('media/js/**.js', 'javascript'), 253 | #], 254 | } 255 | 256 | # Path to Java. Used for compress_assets. 257 | JAVA_BIN = '/usr/bin/java' 258 | 259 | ## Auth 260 | PWD_ALGORITHM = 'sha512' # recommended: 'bcrypt' 261 | HMAC_KEYS = { # for bcrypt only 262 | #'2011-01-01': 'cheesecake', 263 | } 264 | 265 | ## Tests 266 | TEST_RUNNER = 'test_utils.runner.RadicalTestSuiteRunner' 267 | 268 | ## Celery 269 | BROKER_HOST = 'localhost' 270 | BROKER_PORT = 5672 271 | BROKER_USER = 'playdoh' 272 | BROKER_PASSWORD = 'playdoh' 273 | BROKER_VHOST = 'playdoh' 274 | BROKER_CONNECTION_TIMEOUT = 0.1 275 | CELERY_RESULT_BACKEND = 'amqp' 276 | CELERY_IGNORE_RESULT = True 277 | 278 | AUTH_PROFILE_MODULE = 'users.UserProfile' 279 | LOGIN_URL = '/users/login/' 280 | LOGOUT_REDIRECT_URL = '/' 281 | LOGIN_REDIRECT_URL = '/' 282 | 283 | try: 284 | ## LDAP 285 | import ldap 286 | 287 | AUTHENTICATION_BACKENDS = ( 288 | 'users.email_auth_backend.EmailOrUsernameModelBackend', 289 | 'users.auth.backends.MozillaLDAPBackend', 290 | 'django.contrib.auth.backends.ModelBackend', 291 | ) 292 | 293 | # these must be set in settings/local.py! 294 | AUTH_LDAP_SERVER_URI = '' 295 | AUTH_LDAP_BIND_DN = '' 296 | AUTH_LDAP_BIND_PASSWORD = '' 297 | 298 | AUTH_LDAP_START_TLS = True 299 | AUTH_LDAP_USER_ATTR_MAP = { 300 | "first_name": "givenName", 301 | "last_name": "sn", 302 | "email": "mail", 303 | } 304 | from django_auth_ldap.config import LDAPSearch 305 | AUTH_LDAP_USER_SEARCH = LDAPSearch( 306 | "dc=mozilla", 307 | ldap.SCOPE_SUBTREE, 308 | "mail=%(user)s" 309 | ) 310 | 311 | except ImportError: 312 | AUTHENTICATION_BACKENDS = ( 313 | 'users.email_auth_backend.EmailOrUsernameModelBackend', 314 | 'django.contrib.auth.backends.ModelBackend', 315 | ) 316 | -------------------------------------------------------------------------------- /apps/users/tests.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN LICENSE BLOCK ***** 2 | # Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | # 4 | # The contents of this file are subject to the Mozilla Public License Version 5 | # 1.1 (the "License"); you may not use this file except in compliance with 6 | # the License. You may obtain a copy of the License at 7 | # http://www.mozilla.org/MPL/ 8 | # 9 | # Software distributed under the License is distributed on an "AS IS" basis, 10 | # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | # for the specific language governing rights and limitations under the 12 | # License. 13 | # 14 | # The Original Code is Mozilla Sheriff Duty. 15 | # 16 | # The Initial Developer of the Original Code is Mozilla Corporation. 17 | # Portions created by the Initial Developer are Copyright (C) 2011 18 | # the Initial Developer. All Rights Reserved. 19 | # 20 | # Contributor(s): 21 | # 22 | # Alternatively, the contents of this file may be used under the terms of 23 | # either the GNU General Public License Version 2 or later (the "GPL"), or 24 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 25 | # in which case the provisions of the GPL or the LGPL are applicable instead 26 | # of those above. If you wish to allow use of your version of this file only 27 | # under the terms of either the GPL or the LGPL, and not to allow others to 28 | # use your version of this file under the terms of the MPL, indicate your 29 | # decision by deleting the provisions above and replace them with the notice 30 | # and other provisions required by the GPL or the LGPL. If you do not delete 31 | # the provisions above, a recipient may use your version of this file under 32 | # the terms of any one of the MPL, the GPL or the LGPL. 33 | # 34 | # ***** END LICENSE BLOCK ***** 35 | 36 | import re 37 | from urlparse import urlparse 38 | import datetime 39 | from django.test import TestCase 40 | from django.conf import settings 41 | from django.core.urlresolvers import reverse 42 | from django.contrib.auth.models import User 43 | from django.contrib.auth import REDIRECT_FIELD_NAME 44 | from nose.tools import eq_, ok_ 45 | from commons.urlresolvers import reverse 46 | 47 | try: 48 | import ldap 49 | from users.auth.backends import MozillaLDAPBackend 50 | except ImportError: 51 | MozillaLDAPBackend = None 52 | 53 | 54 | class UsersTest(TestCase): 55 | 56 | def test_login(self): 57 | self.client.get('/') 58 | url = reverse('users.login') 59 | 60 | response = self.client.get(url) 61 | eq_(response.status_code, 200) 62 | 63 | mortal = User.objects.create( 64 | username='mortal', 65 | first_name='Mortal', 66 | last_name='Joe' 67 | ) 68 | mortal.set_password('secret') 69 | mortal.save() 70 | 71 | response = self.client.post(url, {'username': 'mortal', 72 | 'password': 'wrong'}) 73 | eq_(response.status_code, 200) 74 | ok_('errorlist' in response.content) 75 | 76 | response = self.client.post(url, {'username': 'mortal', 77 | 'password': 'secret'}) 78 | eq_(response.status_code, 302) 79 | path = urlparse(response['location']).path 80 | eq_(path, settings.LOGIN_REDIRECT_URL) 81 | 82 | response = self.client.get('/') 83 | eq_(response.status_code, 200) 84 | ok_('Mortal' in response.content) 85 | 86 | url = reverse('users.logout') 87 | response = self.client.get(url) 88 | eq_(response.status_code, 302) 89 | path = urlparse(response['location']).path 90 | eq_(path, settings.LOGOUT_REDIRECT_URL) 91 | 92 | response = self.client.get('/') 93 | eq_(response.status_code, 200) 94 | ok_('Mortal' not in response.content) 95 | 96 | def _get_all_inputs(self, html): 97 | _input_regex = re.compile('', re.M | re.DOTALL) 98 | _attrs_regex = re.compile('(\w+)="([^"]+)"') 99 | all_attrs = {} 100 | for input in _input_regex.findall(html): 101 | attrs = dict(_attrs_regex.findall(input)) 102 | all_attrs[attrs.get('name', attrs.get('id', ''))] = attrs 103 | return all_attrs 104 | 105 | def test_login_next_redirect(self): 106 | url = reverse('users.login') 107 | response = self.client.get(url, {'next': '/foo/bar'}) 108 | eq_(response.status_code, 200) 109 | attrs = self._get_all_inputs(response.content) 110 | ok_(attrs[REDIRECT_FIELD_NAME]) 111 | eq_(attrs[REDIRECT_FIELD_NAME]['value'], '/foo/bar') 112 | 113 | mortal = User.objects.create_user( 114 | 'mortal', 'mortal', password='secret' 115 | ) 116 | mortal.set_password('secret') 117 | mortal.save() 118 | 119 | response = self.client.post(url, {'username': 'mortal', 120 | 'password': 'secret', 121 | 'next': '/foo/bar'}) 122 | eq_(response.status_code, 302) 123 | path = urlparse(response['location']).path 124 | eq_(path, '/foo/bar') 125 | 126 | def test_login_failure(self): 127 | url = reverse('users.login') 128 | mortal = User.objects.create( 129 | username='mortal', 130 | first_name='Mortal', 131 | last_name='Joe', 132 | email='mortal@mozilla.com', 133 | ) 134 | mortal.set_password('secret') 135 | mortal.save() 136 | 137 | response = self.client.post(url, {'username': 'mortal', 138 | 'password': 'xxx'}) 139 | eq_(response.status_code, 200) 140 | ok_('errorlist' in response.content) 141 | 142 | response = self.client.post(url, {'username': 'xxx', 143 | 'password': 'secret'}) 144 | eq_(response.status_code, 200) 145 | ok_('errorlist' in response.content) 146 | 147 | def test_login_rememberme(self): 148 | url = reverse('users.login') 149 | mortal = User.objects.create( 150 | username='mortal', 151 | first_name='Mortal', 152 | last_name='Joe' 153 | ) 154 | mortal.set_password('secret') 155 | mortal.save() 156 | 157 | response = self.client.post(url, {'username': 'mortal', 158 | 'password': 'secret', 159 | 'rememberme': 'yes'}) 160 | eq_(response.status_code, 302) 161 | expires = self.client.cookies['sessionid']['expires'] 162 | date = expires.split()[1] 163 | then = datetime.datetime.strptime(date, '%d-%b-%Y') 164 | today = datetime.datetime.today() 165 | days = settings.SESSION_COOKIE_AGE / 24 / 3600 166 | eq_((then - today).days + 1, days) 167 | 168 | def test_login_by_email(self): 169 | url = reverse('users.login') 170 | 171 | mortal = User.objects.create( 172 | username='mortal', 173 | email='mortal@hotmail.com', 174 | first_name='Mortal', 175 | last_name='Joe' 176 | ) 177 | mortal.set_password('secret') 178 | mortal.save() 179 | 180 | response = self.client.post(url, {'username': 'Mortal@hotmail.com', 181 | 'password': 'secret'}) 182 | eq_(response.status_code, 302) 183 | 184 | response = self.client.get('/') 185 | eq_(response.status_code, 200) 186 | ok_('Mortal' in response.content) 187 | 188 | def test_changing_your_username(self): 189 | url = reverse('users.settings') 190 | response = self.client.get(url) 191 | eq_(response.status_code, 302) 192 | path = urlparse(response['location']).path 193 | eq_(path, settings.LOGIN_URL) 194 | 195 | mortal = User.objects.create( 196 | username='mortal', 197 | email='mortal@hotmail.com', 198 | first_name='Mortal', 199 | last_name='Joe' 200 | ) 201 | mortal.set_password('secret') 202 | mortal.save() 203 | assert self.client.login(username='mortal', password='secret') 204 | 205 | url = reverse('users.settings') 206 | response = self.client.get(url) 207 | eq_(response.status_code, 200) 208 | 209 | ok_('value="%s"' % mortal.username in response.content) 210 | 211 | User.objects.create_user( 212 | 'maxpower', 213 | 'maxpower@mozilla.com', 214 | password='secret', 215 | ) 216 | 217 | response = self.client.post(url, {'username':' Maxpower '}) 218 | eq_(response.status_code, 200) 219 | ok_('errorlist' in response.content) 220 | 221 | response = self.client.post(url, {'username':'homer '}) 222 | eq_(response.status_code, 302) 223 | 224 | ok_(User.objects.get(username='homer')) 225 | ok_(not User.objects.filter(username='mortal').exists()) 226 | 227 | # stupid but I should be able to save my own username twice 228 | response = self.client.post(url, {'username':'homer'}) 229 | ok_(User.objects.get(username='homer')) 230 | 231 | response = self.client.post(url, {'username':'Homer'}) 232 | ok_(User.objects.get(username='Homer')) 233 | 234 | def test_mozilla_ldap_backend_basic(self): 235 | if MozillaLDAPBackend is None: 236 | return 237 | back = MozillaLDAPBackend() 238 | class LDAPUser: 239 | def __init__(self, attrs): 240 | self.attrs = attrs 241 | ldap_user = LDAPUser({'mail':['mail@peterbe.com']}) 242 | user, created = back.get_or_create_user('peter', ldap_user) 243 | ok_(created) 244 | ok_(user) 245 | eq_(user.username, 'peter') 246 | 247 | peppe = User.objects.create_user( 248 | 'peppe', 249 | 'mail@peterbe.com', 250 | ) 251 | user, created = back.get_or_create_user('peter', ldap_user) 252 | ok_(not created) 253 | eq_(user, peppe) 254 | 255 | username = back.ldap_to_django_username('mail@peterbe.com') 256 | eq_(username, 'peppe') 257 | username = back.ldap_to_django_username('lois@peterbe.com') 258 | eq_(username, 'lois') 259 | 260 | def test_login_username_form_field(self): 261 | url = reverse('users.login') 262 | response = self.client.get(url) 263 | eq_(response.status_code, 200) 264 | html = response.content.split('