Unified
Split
Showing
with
756 additions
and 1,484 deletions.
- +57 −2 CHANGES.txt
- +1 −1 Procfile
- +2 −2 conf/development.ini
- +4 −3 h/api/models.py
- +9 −8 h/api/test/models_test.py
- +6 −0 h/app.py
- +7 −2 h/browser/chrome/lib/tab-state.js
- +1 −1 h/browser/chrome/test/browser-action-test.js
- +1 −1 h/browser/chrome/test/hypothesis-chrome-extension-test.js
- +9 −0 h/browser/chrome/test/tab-state-test.js
- +0 −188 h/claim/invite.py
- +60 −0 h/debug.py
- +4 −8 h/static/scripts/app-controller.coffee
- +3 −7 h/static/scripts/app.coffee
- +48 −8 h/static/scripts/directive/annotation.coffee
- +0 −30 h/static/scripts/directive/group-list.js
- +82 −2 h/static/scripts/directive/test/annotation-test.coffee
- +3 −34 h/static/scripts/directive/test/group-list-test.js
- +0 −41 h/static/scripts/drafts.coffee
- +84 −0 h/static/scripts/drafts.js
- +1 −1 h/static/scripts/features.js
- +26 −18 h/static/scripts/streamer.js
- +0 −6 h/static/scripts/test/app-controller-test.coffee
- +56 −0 h/static/scripts/test/drafts-test.js
- +33 −28 h/static/scripts/test/streamer-test.js
- +59 −0 h/static/scripts/test/websocket-test.js
- +32 −3 h/static/scripts/test/widget-controller-test.coffee
- +19 −1 h/static/scripts/threading.coffee
- +99 −0 h/static/scripts/websocket.js
- +14 −2 h/static/scripts/widget-controller.coffee
- +0 −4 h/static/styles/app.scss
- +1 −1 h/static/styles/group-form.scss
- +2 −2 h/static/styles/share-link.scss
- +9 −1 h/static/styles/simple-search.scss
- +8 −7 h/templates/client/annotation.html
- +3 −16 h/templates/client/group_list.html
- +0 −58 h/templates/email_preview.html.jinja2
- +0 −911 h/templates/pattern_library.html.jinja2
- +0 −78 h/testing.py
- +11 −4 h/views.py
- +2 −2 package.json
- +0 −3 setup.py
| @@ -1,5 +1,60 @@ | ||
| 0.7.19 (2015-10-28) | ||
| ================== | ||
| 0.7.13 (2015-11-03) | ||
| =================== | ||
| Bug fixes | ||
| --------- | ||
| - Fix a broken reference within our code (502e8df). | ||
| 0.7.12 (2015-11-03) | ||
| =================== | ||
| Bug fixes | ||
| --------- | ||
| - Fix a couple of small display issues (#2704, #2710). | ||
| - Fix an issue where badge URLs were not correctly encoded before being sent to | ||
| the server (#2709). | ||
| 0.7.11 (2015-11-02) | ||
| =================== | ||
| Bug fixes | ||
| --------- | ||
| - Fix a problem where occasionally the set of public annotations would be loaded | ||
| into the initial view rather than the set of annotations for the focused group | ||
| (feature flagged: groups) (#2684). | ||
| - Fix a bug where creating an annotation when signed out (and subsequently | ||
| signing in and saving it) could result in invalid permissions fields (#2687). | ||
| - Fix a problem in Safari where the search box didn't expand when you clicked on | ||
| it (#2699). | ||
| - Fix improper case-sensitivity for tag searches (e.g. searches for "Tag123" now | ||
| correctly return annotations tagged with "tag123") (#2690). | ||
| Features | ||
| -------- | ||
| - Ignore the "gclid" query parameter (a Google AdWords click-tracking param) | ||
| when normalising URLs (72f0509). | ||
| - Draft annotations are now preserved when switching from group to group in the | ||
| sidebar (#2689). | ||
| Miscellanea | ||
| ----------- | ||
| - Improvements to Sentry logging (the current URL, headers, and userid are now | ||
| recorded with exceptions) (#2697). | ||
| - Show the werkzeug debugger on exceptions in development (#2698). | ||
| 0.7.10 (2015-10-28) | ||
| =================== | ||
| Bug fixes | ||
| --------- | ||
| @@ -1,4 +1,4 @@ | ||
| web: gunicorn --paster conf/${HYP_ENV:-production}.ini | ||
| web: gunicorn -w ${WEB_CONCURRENCY:-1} --paster conf/${HYP_ENV:-production}.ini | ||
| notification: hypothesis-worker conf/${HYP_ENV:-production}.ini notification | ||
| nipsa: hypothesis-worker conf/${HYP_ENV:-production}.ini nipsa | ||
| assets: hypothesis assets conf/${HYP_ENV:-production}.ini | ||
| @@ -19,12 +19,12 @@ multiauth.policy.session.use: pyramid.authentication.SessionAuthenticationPolicy | ||
| pyramid.debug_all: True | ||
| pyramid.reload_templates: True | ||
| pyramid.includes: | ||
| h.session | ||
| pyramid_debugtoolbar | ||
| pyramid_mailer | ||
| pyramid_multiauth | ||
| pyramid_tm | ||
| h.testing | ||
| h.debug | ||
| h.session | ||
| # Set a default persistent secret for development. DO NOT copy this into a | ||
| # production settings file. | ||
| @@ -24,7 +24,7 @@ def _format_document_link(href, title, link_text, hostname): | ||
| if hostname and hostname in link_text: | ||
| hostname = "" | ||
| def truncate(content, length=50): | ||
| def truncate(content, length=60): | ||
| """Truncate the given string to at most length chars.""" | ||
| if len(content) <= length: | ||
| return content | ||
| @@ -35,9 +35,10 @@ def truncate(content, length=50): | ||
| link_text = truncate(link_text) | ||
| if href and hostname: | ||
| link = '<a href="{href}" title="{title}">{link_text}</a> ({hostname})' | ||
| link = ('<a href="{href}" title="{title}">{link_text}</a><br>' | ||
| '({hostname})') | ||
| elif hostname: | ||
| link = '<a title="{title}">{link_text}</a> ({hostname})' | ||
| link = '<a title="{title}">{link_text}</a><br>({hostname})' | ||
| elif href: | ||
| link = '<a href="{href}" title="{title}">{link_text}</a>' | ||
| else: | ||
| @@ -407,7 +407,7 @@ def test_document_link_happy_path(hostname_or_filename, href, title, | ||
| assert models.Annotation().document_link == ( | ||
| '<a href="http://www.example.com/example.html" ' | ||
| 'title="Example Document">Example Document</a> (www.example.com)') | ||
| 'title="Example Document">Example Document</a><br>(www.example.com)') | ||
| @document_link_fixtures | ||
| @@ -462,13 +462,13 @@ def test_document_link_truncates_hostname(hostname_or_filename, href, title, | ||
| link_text.return_value = "www.example.com/example.html" | ||
| # .hostname_or_filename is too long. | ||
| hostname_or_filename.return_value = "a" * 60 | ||
| hostname_or_filename.return_value = "a" * 70 | ||
| expected_hostname = "a" * 50 + "…" | ||
| expected_hostname = "a" * 60 + "…" | ||
| expected_result = ( | ||
| '<a href="http://www.example.com/example.html" ' | ||
| 'title="www.example.com/example.html">' | ||
| 'www.example.com/example.html</a> ({hostname})'.format( | ||
| 'www.example.com/example.html</a><br>({hostname})'.format( | ||
| hostname=expected_hostname)) | ||
| assert models.Annotation().document_link == expected_result | ||
| @@ -481,12 +481,12 @@ def test_document_link_truncates_link_text(hostname_or_filename, href, title, | ||
| title.return_value = "www.example.com/example.html" | ||
| # .link_text is too long. | ||
| link_text.return_value = "a" * 60 | ||
| link_text.return_value = "a" * 70 | ||
| expected_link_text = "a" * 50 + "…" | ||
| expected_link_text = "a" * 60 + "…" | ||
| expected_result = ( | ||
| '<a href="http://www.example.com/example.html" ' | ||
| 'title="www.example.com/example.html">{link_text}</a> ' | ||
| 'title="www.example.com/example.html">{link_text}</a><br>' | ||
| '(www.example.com)'.format(link_text=expected_link_text)) | ||
| assert models.Annotation().document_link == expected_result | ||
| @@ -502,7 +502,8 @@ def test_document_link_hostname_but_no_href(hostname_or_filename, href, title, | ||
| href.return_value = "" | ||
| assert models.Annotation().document_link == ( | ||
| '<a title="Example Document">Example Document</a> (www.example.com)') | ||
| '<a title="Example Document">Example Document</a><br>' | ||
| '(www.example.com)') | ||
| @document_link_fixtures | ||
| @@ -5,6 +5,7 @@ | ||
| from pyramid.config import Configurator | ||
| from pyramid.tweens import EXCVIEW | ||
| from pyramid.settings import asbool | ||
| from h.config import settings_from_environment | ||
| from h.security import derive_key | ||
| @@ -18,6 +19,10 @@ def configure_jinja2_assets(config): | ||
| jinja2_env.assets_environment = assets_env | ||
| def in_debug_mode(request): | ||
| return asbool(request.registry.settings.get('pyramid.debug_all')) | ||
| def create_app(global_config, **settings): | ||
| """Configure and add static routes and views. Return the WSGI app.""" | ||
| settings = get_settings(global_config, **settings) | ||
| @@ -43,6 +48,7 @@ def create_app(global_config, **settings): | ||
| def includeme(config): | ||
| config.add_request_method(in_debug_mode, 'debug', reify=True) | ||
| config.include('h.features') | ||
| @@ -1,6 +1,6 @@ | ||
| 'use strict'; | ||
| var assign = require('core-js/modules/$.assign'); | ||
| var assign = require('core-js/modules/$.object-assign'); | ||
| var isShallowEqual = require('is-equal-shallow'); | ||
| var states = { | ||
| @@ -25,6 +25,11 @@ var DEFAULT_STATE = { | ||
| ready: false, | ||
| }; | ||
| /** encodeUriQuery encodes a string for use in a query parameter */ | ||
| function encodeUriQuery(val) { | ||
| return encodeURIComponent(val).replace(/%20/g, '+'); | ||
| } | ||
| /** TabState stores the H state for a tab. This state includes: | ||
| * | ||
| * - Whether the extension has been activated on a tab | ||
| @@ -161,7 +166,7 @@ function TabState(initialState, onchange) { | ||
| self.setState(tabId, {annotationCount: total}); | ||
| }; | ||
| xhr.open('GET', apiUrl + '/badge?uri=' + tabUrl); | ||
| xhr.open('GET', apiUrl + '/badge?uri=' + encodeUriQuery(tabUrl)); | ||
| xhr.send(); | ||
| }; | ||
| @@ -1,4 +1,4 @@ | ||
| var assign = require('core-js/modules/$.assign'); | ||
| var assign = require('core-js/modules/$.object-assign'); | ||
| var proxyquire = require('proxyquire'); | ||
| describe('BrowserAction', function () { | ||
| @@ -1,6 +1,6 @@ | ||
| 'use strict'; | ||
| var assign = require('core-js/modules/$.assign'); | ||
| var assign = require('core-js/modules/$.object-assign'); | ||
| var proxyquire = require('proxyquire'); | ||
| var errors = require('../lib/errors'); | ||
| @@ -136,6 +136,15 @@ describe('TabState', function () { | ||
| assert.equal(request.url, "http://example.com/badge?uri=tabUrl"); | ||
| }); | ||
| it('urlencodes the tabUrl appropriately', function() { | ||
| state.updateAnnotationCount("tabId", "http://foo.com?bar=baz qüx", "http://example.com"); | ||
| assert.equal(server.requests.length, 1); | ||
| var request = server.requests[0]; | ||
| assert.equal(request.method, "GET"); | ||
| assert.equal(request.url, "http://example.com/badge?uri=http%3A%2F%2Ffoo.com%3Fbar%3Dbaz+q%C3%BCx"); | ||
| }); | ||
| it("doesn't set the annotation count if the server's JSON is invalid", function() { | ||
| server.respondWith( | ||
| "GET", "http://example.com/badge?uri=tabUrl", | ||
Oops, something went wrong.