Merge branch 'master' into greenkeeper/clean-css-4.0.7
This commit is contained in:
Коммит
aa334094ec
|
@ -287,6 +287,7 @@ This endpoint allows you to fetch a single version belonging to a specific add-o
|
|||
:>json int files[].id: The size for a file, in bytes.
|
||||
:>json int files[].status: The :ref:`status <addon-detail-status>` for a file.
|
||||
:>json string files[].url: The (absolute) URL to download a file. An optional ``src`` query parameter can be added to indicate the source page (See :ref:`download sources <download-sources>`).
|
||||
:>json array files[].permissions[]: Array of the webextension permissions for this File, as strings. Empty for non-webextensions.
|
||||
:>json object license: Object holding information about the license for the version.
|
||||
:>json string|object|null license.name: The name of the license (See :ref:`translated fields <api-overview-translations>`).
|
||||
:>json string|object|null license.text: The text of the license (See :ref:`translated fields <api-overview-translations>`).
|
||||
|
|
|
@ -8,17 +8,21 @@ Reviews
|
|||
may change without warning. The only authentication method available at
|
||||
the moment is :ref:`the internal one<api-auth-internal>`.
|
||||
|
||||
-------------------
|
||||
List Add-on reviews
|
||||
-------------------
|
||||
------------
|
||||
List reviews
|
||||
------------
|
||||
|
||||
.. review-list-addon:
|
||||
.. review-list:
|
||||
|
||||
This endpoint allows you to fetch reviews for a given add-on.
|
||||
This endpoint allows you to fetch reviews for a given add-on or user. Either
|
||||
``addon`` or ``user`` query parameters are required, and they can be
|
||||
combined together.
|
||||
|
||||
.. http:get:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/
|
||||
.. http:get:: /api/v3/reviews/review/
|
||||
|
||||
:query string addon: The add-on id to fetch reviews from. When passed, the reviews shown will always be the latest posted by each user on this particular add-on (which means there should only be one review per user in the results).
|
||||
:query string filter: The :ref:`filter <review-filtering-param>` to apply.
|
||||
:query string user: The user id to fetch reviews from.
|
||||
:query int show_grouped_ratings: Whether or not to show ratings aggregates for this add-on in the response.
|
||||
:>json int count: The number of results for this query.
|
||||
:>json string next: The URL of the next page of results.
|
||||
|
@ -32,23 +36,6 @@ This endpoint allows you to fetch reviews for a given add-on.
|
|||
can change that with the ``filter=with_deleted`` query parameter, which
|
||||
requires the Addons:Edit permission.
|
||||
|
||||
----------------------
|
||||
List reviews by a user
|
||||
----------------------
|
||||
|
||||
.. review-list-user:
|
||||
|
||||
This endpoint allows you to fetch reviews posted by a specific user.
|
||||
|
||||
.. http:get:: /api/v3/accounts/account/(int:id)/reviews/
|
||||
|
||||
:query string filter: The :ref:`filter <review-filtering-param>` to apply.
|
||||
:param int id: The user id.
|
||||
:>json int count: The number of results for this query.
|
||||
:>json string next: The URL of the next page of results.
|
||||
:>json string previous: The URL of the previous page of results.
|
||||
:>json array results: An array of :ref:`reviews <review-detail-object>`.
|
||||
|
||||
------
|
||||
Detail
|
||||
------
|
||||
|
@ -57,7 +44,7 @@ Detail
|
|||
|
||||
This endpoint allows you to fetch a review by its id.
|
||||
|
||||
.. http:get:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/(int:id)/
|
||||
.. http:get:: /api/v3/reviews/review/(int:id)/
|
||||
|
||||
.. _review-detail-object:
|
||||
|
||||
|
@ -89,12 +76,13 @@ If successful a :ref:`review object <review-detail-object>` is returned.
|
|||
Requires authentication.
|
||||
|
||||
|
||||
.. http:post:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/
|
||||
.. http:post:: /api/v3/reviews/review/
|
||||
|
||||
:<json string addon: The add-on id the review applies to (required).
|
||||
:<json string|null body: The text of the review.
|
||||
:<json string|null title: The title of the review.
|
||||
:<json int rating: The rating the user wants to give as part of the review (required).
|
||||
:<json int version: The add-on version id the review applies to.
|
||||
:<json int version: The add-on version id the review applies to (required).
|
||||
|
||||
----
|
||||
Edit
|
||||
|
@ -111,7 +99,7 @@ If successful a :ref:`review object <review-detail-object>` is returned.
|
|||
|
||||
Only body, title and rating are allowed for modification.
|
||||
|
||||
.. http:patch:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/(int:id)/
|
||||
.. http:patch:: /api/v3/reviews/review/(int:id)/
|
||||
|
||||
:<json string|null body: The text of the review.
|
||||
:<json string|null title: The title of the review.
|
||||
|
@ -132,7 +120,7 @@ This endpoint allows you to delete an existing review by its id.
|
|||
not delete a review from somebody else if it was posted on an add-on they
|
||||
are listed as a developer of.
|
||||
|
||||
.. http:delete:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/(int:id)/
|
||||
.. http:delete:: /api/v3/reviews/review/(int:id)/
|
||||
|
||||
|
||||
-----
|
||||
|
@ -148,7 +136,7 @@ If successful a :ref:`review reply object <review-detail-object>` is returned.
|
|||
Requires authentication and either Addons:Edit permission or a user account
|
||||
listed as a developer of the add-on.
|
||||
|
||||
.. http:post:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/(int:id)/reply/
|
||||
.. http:post:: /api/v3/reviews/review/(int:id)/reply/
|
||||
|
||||
:<json string body: The text of the reply (required).
|
||||
:<json string|null title: The title of the reply.
|
||||
|
@ -169,7 +157,7 @@ An empty response will be returned on success.
|
|||
Requires authentication and a user account different from the one that
|
||||
posted the review.
|
||||
|
||||
.. http:post:: /api/v3/addons/addon/(int:id|string:slug|string:guid)/reviews/(int:id)/flag/
|
||||
.. http:post:: /api/v3/reviews/review/(int:id)/flag/
|
||||
|
||||
:<json string flag: A :ref:`constant<review-flag-constants>` describing the reason behind the flagging.
|
||||
:<json string|null note: A note to explain further the reason behind the flagging.
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT 1.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2017-01-29 11:39+0000\n"
|
||||
"PO-Revision-Date: 2017-02-16 06:40+0000\n"
|
||||
"Last-Translator: Bjørn I. <bjorn.svindseth@online.no>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: nn_NO\n"
|
||||
|
@ -278,17 +278,13 @@ msgstr "Hjelp til og støtt vidare utvikling av <strong>%(addon_name)s</strong>
|
|||
|
||||
#: src/olympia/addons/templates/addons/contributions_lightbox.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To show your support for <b>%(addon_name)s</b>, the developer asks that you make a donation to the <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgid "To show your support for <b>%(addon_name)s</b>, the developer asks that you make a donation to the <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgstr "For å visa støtta di til <b>%(addon_name)s</b>, ber utviklaren deg donera til <a href=\"%(charity_url)s\">%(charity_name)s</a> med <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
|
||||
#: src/olympia/addons/templates/addons/contributions_lightbox.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To show your support for <b>%(addon_name)s</b>, the developer asks that you make a small contribution to <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</"
|
||||
"a>."
|
||||
msgstr ""
|
||||
"For at visa støtta di til <b>%(addon_name)s</b>, ber udviklaren deg om at du gjev eit mindre bidrag til <a href=\"%(charity_url)s\">%(charity_name)s</a> via <a href=\"%(paypal_url)s\">Paypal</a>."
|
||||
msgid "To show your support for <b>%(addon_name)s</b>, the developer asks that you make a small contribution to <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgstr "For at visa støtta di til <b>%(addon_name)s</b>, ber udviklaren deg om at du gjev eit mindre bidrag til <a href=\"%(charity_url)s\">%(charity_name)s</a> via <a href=\"%(paypal_url)s\">Paypal</a>."
|
||||
|
||||
#: src/olympia/addons/templates/addons/contributions_lightbox.html
|
||||
msgid "How much would you like to contribute?"
|
||||
|
@ -758,8 +754,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/addons/templates/addons/popups.html
|
||||
msgid ""
|
||||
"<strong>Caution:</strong> This add-on has not been reviewed by Mozilla and can't be installed on release versions of Firefox 43 and above. Be careful when installing third-party software that "
|
||||
"might harm your computer."
|
||||
"<strong>Caution:</strong> This add-on has not been reviewed by Mozilla and can't be installed on release versions of Firefox 43 and above. Be careful when installing third-party software that might"
|
||||
" harm your computer."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/addons/templates/addons/popups.html
|
||||
|
@ -968,14 +964,12 @@ msgid "Manage"
|
|||
msgstr "Handsam"
|
||||
|
||||
#: src/olympia/addons/templates/addons/impala/details.html src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
#, fuzzy
|
||||
msgid "Add-on Review"
|
||||
msgstr "Full vurdering av utviding"
|
||||
msgstr "Vurdering av utviding"
|
||||
|
||||
#: src/olympia/addons/templates/addons/impala/details.html src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
#, fuzzy
|
||||
msgid "Admin Manage"
|
||||
msgstr "Handsam"
|
||||
msgstr "Administrashandsaming"
|
||||
|
||||
#. {0} is an add-on name.
|
||||
#: src/olympia/addons/templates/addons/impala/details.html
|
||||
|
@ -1379,9 +1373,8 @@ msgid "Manage API Keys"
|
|||
msgstr "Handsam API-nøklar"
|
||||
|
||||
#: src/olympia/amo/context_processors.py src/olympia/editors/helpers.py src/olympia/editors/templates/editors/base.html
|
||||
#, fuzzy
|
||||
msgid "Reviewer Tools"
|
||||
msgstr "Utviklar"
|
||||
msgstr "Vurderingsverktøy"
|
||||
|
||||
#: src/olympia/amo/context_processors.py
|
||||
msgid "Admin Tools"
|
||||
|
@ -1703,9 +1696,8 @@ msgid "Addon id {0} with GUID {1} has been deleted"
|
|||
msgstr "Utvidings-ID {0} med GUID {1} er sletta"
|
||||
|
||||
#: src/olympia/amo/log.py
|
||||
#, fuzzy
|
||||
msgid "{addon} migrated from preliminary."
|
||||
msgstr "{addon} {version} er førebels vurdert."
|
||||
msgstr "{addon} migrert frå førebuande."
|
||||
|
||||
#: src/olympia/amo/log.py
|
||||
#, fuzzy
|
||||
|
@ -1713,9 +1705,8 @@ msgid "Reply by developer on {addon} {version}."
|
|||
msgstr "Kommentar på {addon} {version}."
|
||||
|
||||
#: src/olympia/amo/log.py
|
||||
#, fuzzy
|
||||
msgid "Developer Reply"
|
||||
msgstr "Utviklar"
|
||||
msgstr "Utviklarsvar"
|
||||
|
||||
#: src/olympia/amo/log.py
|
||||
#, fuzzy
|
||||
|
@ -1766,8 +1757,8 @@ msgstr "Ikkje funne"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"<h1>We're sorry, but we can't find what you're looking for.</h1> <p> The page or file you requested wasn't found on our site. It's possible that you clicked a link that's out of date, or typed in "
|
||||
"the address incorrectly. </p> <ul> <li>If you typed in the address, please double check the spelling.</li> <li> If you followed a link from somewhere, please <a href=\"https://github.com/mozilla/"
|
||||
"addons-server/issues/new/\">file an issue</a>. Tell us where you came from and what you were looking for, and we'll do our best to fix it. </li> </ul> <p>Or you can just jump over to some of the "
|
||||
"the address incorrectly. </p> <ul> <li>If you typed in the address, please double check the spelling.</li> <li> If you followed a link from somewhere, please <a href=\"https://github.com/mozilla"
|
||||
"/addons-server/issues/new/\">file an issue</a>. Tell us where you came from and what you were looking for, and we'll do our best to fix it. </li> </ul> <p>Or you can just jump over to some of the "
|
||||
"popular pages on our website.</p> <ul> <li>Are you interested in a <a href=\"%(rec)s\">list of featured add-ons</a>?</li> <li> Do you want to <a href=\"%(search)s\">search for add-ons</a>? You may "
|
||||
"go to the <a href=\"%(search)s\">search page</a> or just use the search field above. </li> <li> If you prefer to start over, just go to the <a href=\"%(home)s\">add-ons front page</a>. </li> </ul>"
|
||||
msgstr ""
|
||||
|
@ -2275,8 +2266,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/collection_detail.html
|
||||
msgid ""
|
||||
"Add-ons that you mark as favorites using the <b>Add to Favorites</b> feature appear below. This collection is currently <b>private</b>, which means only you can see it. If you would like everyone "
|
||||
"to be able to see your favorites, click the button below to make it public."
|
||||
"Add-ons that you mark as favorites using the <b>Add to Favorites</b> feature appear below. This collection is currently <b>private</b>, which means only you can see it. If you would like everyone to"
|
||||
" be able to see your favorites, click the button below to make it public."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/collection_detail.html
|
||||
|
@ -2935,8 +2926,8 @@ msgstr ""
|
|||
#: src/olympia/compat/templates/compat/reporter.html src/olympia/compat/templates/compat/reporter_detail.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<p> Reports submitted to us through the <a href=\"%(url_)s\">Add-on Compatibility Reporter</a> are collected here for developers to view. These reports help us determine which add-ons will need "
|
||||
"help supporting an upcoming Firefox version. </p>"
|
||||
"<p> Reports submitted to us through the <a href=\"%(url_)s\">Add-on Compatibility Reporter</a> are collected here for developers to view. These reports help us determine which add-ons will need help"
|
||||
" supporting an upcoming Firefox version. </p>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/compat/templates/compat/reporter.html
|
||||
|
@ -2993,9 +2984,8 @@ msgid "e10s Enabled"
|
|||
msgstr "e10s slått på"
|
||||
|
||||
#: src/olympia/compat/templates/compat/reporter_detail.html
|
||||
#, fuzzy
|
||||
msgid "e10s Compatible"
|
||||
msgstr "Kompatibel"
|
||||
msgstr "e10s kompatibel"
|
||||
|
||||
#: src/olympia/compat/templates/compat/reporter_detail.html src/olympia/editors/templates/editors/themes/themes.html
|
||||
msgid "Submitted"
|
||||
|
@ -3207,9 +3197,8 @@ msgid "Updated Dictionary Review"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/constants/base.py
|
||||
#, fuzzy
|
||||
msgid "New Language Pack Review"
|
||||
msgstr "Språkpakke"
|
||||
msgstr "Ny språkpakke-vurdering"
|
||||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Preliminary Language Pack Review"
|
||||
|
@ -3334,9 +3323,8 @@ msgid "Games & Entertainment"
|
|||
msgstr "Spel og underhaldning"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
#, fuzzy
|
||||
msgid "Language Support"
|
||||
msgstr "Språk"
|
||||
msgstr "Språkstøtte"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Photos, Music & Videos"
|
||||
|
@ -3359,9 +3347,8 @@ msgid "Tabs"
|
|||
msgstr "Faner"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
#, fuzzy
|
||||
msgid "Web Development"
|
||||
msgstr "Vis utviklingsversjon"
|
||||
msgstr "Nettutvikling"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Animals"
|
||||
|
@ -3384,9 +3371,8 @@ msgid "Modern"
|
|||
msgstr "Moderne"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
#, fuzzy
|
||||
msgid "Nature"
|
||||
msgstr "Framheva"
|
||||
msgstr "Natur"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "OS Integration"
|
||||
|
@ -3545,9 +3531,8 @@ msgid "Message Composition"
|
|||
msgstr "Gje bidrag"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
#, fuzzy
|
||||
msgid "Contacts"
|
||||
msgstr "Innhald"
|
||||
msgstr "Kontaktar"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Folders and Filters"
|
||||
|
@ -3559,7 +3544,7 @@ msgstr "Import/eksport"
|
|||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Message and News Reading"
|
||||
msgstr ""
|
||||
msgstr "Meldings- og nyhendelesing"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Privacy and Security"
|
||||
|
@ -3914,8 +3899,7 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
msgid ""
|
||||
"On your own. <span class=\"helptext\">Your submission will be immediately signed for self-distribution. Updates should be handled by you via an updateURL or external application updates.</span>"
|
||||
msgid "On your own. <span class=\"helptext\">Your submission will be immediately signed for self-distribution. Updates should be handled by you via an updateURL or external application updates.</span>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/helpers.py
|
||||
|
@ -4193,9 +4177,9 @@ msgstr "Lær alt om utvidingar"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/index-legacy.html
|
||||
msgid ""
|
||||
"Add-ons let millions of Firefox users enhance and customize their browsing experience. If you're a Web developer and know <a href=\"https://developer.mozilla.org/docs/Web/HTML\">HTML</a>, <a href="
|
||||
"\"https://developer.mozilla.org/docs/Web/JavaScript\">JavaScript</a>, and <a href=\"https://developer.mozilla.org/docs/Web/CSS\">CSS</a>, you already have all the necessary skills to make a great "
|
||||
"add-on."
|
||||
"Add-ons let millions of Firefox users enhance and customize their browsing experience. If you're a Web developer and know <a href=\"https://developer.mozilla.org/docs/Web/HTML\">HTML</a>, <a "
|
||||
"href=\"https://developer.mozilla.org/docs/Web/JavaScript\">JavaScript</a>, and <a href=\"https://developer.mozilla.org/docs/Web/CSS\">CSS</a>, you already have all the necessary skills to make a "
|
||||
"great add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/index-legacy.html
|
||||
|
@ -4375,9 +4359,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_error.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"#\" class=\"button compat-update\" data-updateurl=\"%(update_url)s\">Update Compatibility</a> <a href=\"%(version_url)s\" class=\"button\">Upload New Version</a> or <a href=\"#\" class="
|
||||
"\"close\">Ignore</a>"
|
||||
msgid "<a href=\"#\" class=\"button compat-update\" data-updateurl=\"%(update_url)s\">Update Compatibility</a> <a href=\"%(version_url)s\" class=\"button\">Upload New Version</a> or <a href=\"#\" class=\"close\">Ignore</a>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_status.html
|
||||
|
@ -4430,9 +4412,8 @@ msgstr[0] ""
|
|||
msgstr[1] ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit.html src/olympia/devhub/templates/devhub/addons/listing/item_actions.html src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
#, fuzzy
|
||||
msgid "Edit Information"
|
||||
msgstr "Versjonsinformasjon"
|
||||
msgstr "Rediger informasjon"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit.html src/olympia/devhub/templates/devhub/includes/macros.html src/olympia/translations/templates/translations/all-locales.html
|
||||
msgid "None"
|
||||
|
@ -4515,9 +4496,8 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
#, fuzzy
|
||||
msgid "Experimental?"
|
||||
msgstr "Eksperimentell"
|
||||
msgstr "Eksperimentell?"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
msgid "If your add-on on is experimental or otherwise not ready for general use. The add-on will be listed but will have reduced visibility. "
|
||||
|
@ -4537,8 +4517,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Categories cannot be changed while your add-on is featured for this application. Please email <a href=\"mailto:%(email)s\">%(email)s</a> if there is a reason you need to modify your categories."
|
||||
msgid "Categories cannot be changed while your add-on is featured for this application. Please email <a href=\"mailto:%(email)s\">%(email)s</a> if there is a reason you need to modify your categories."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
|
@ -4606,8 +4585,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/support.html
|
||||
msgid ""
|
||||
"If you wish to display an e-mail address for support inquiries, enter it here. If you have different addresses for each language multiple translations of this field can be added. It is only "
|
||||
"relevant for listed add-ons."
|
||||
"If you wish to display an e-mail address for support inquiries, enter it here. If you have different addresses for each language multiple translations of this field can be added. It is only relevant"
|
||||
" for listed add-ons."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/support.html
|
||||
|
@ -4964,24 +4943,20 @@ msgstr[0] ""
|
|||
msgstr[1] ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/base.html
|
||||
#, fuzzy
|
||||
msgid "Submit a New File"
|
||||
msgstr "Send inn eit nytt tema"
|
||||
msgstr "Send inn ei ny fil"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/base.html
|
||||
#, fuzzy
|
||||
msgid "Submit a New Version"
|
||||
msgstr "Send inn ei ny utviding"
|
||||
msgstr "Send inn ein ny versjon"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/describe.html src/olympia/devhub/templates/devhub/addons/submit/describe_minimal.html
|
||||
#, fuzzy
|
||||
msgid "Describe Add-on"
|
||||
msgstr "Fleire utvidingar"
|
||||
msgstr "Beskriv utvidinga"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/describe.html
|
||||
#, fuzzy
|
||||
msgid "Add-on URL:"
|
||||
msgstr "Utviding"
|
||||
msgstr "URL for utviding:"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/describe.html src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "Please use only letters, numbers, underscores, and dashes in your URL."
|
||||
|
@ -5184,9 +5159,8 @@ msgid "Administrative overrides"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/upload.html
|
||||
#, fuzzy
|
||||
msgid "Submit File"
|
||||
msgstr "Send inn eit nytt tema"
|
||||
msgstr "Send inn fil"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/upload.html
|
||||
#, fuzzy
|
||||
|
@ -5221,8 +5195,8 @@ msgstr ""
|
|||
#: src/olympia/devhub/templates/devhub/api/key.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To make API requests, send a <a href=\"%(jwt_url)s\">JSON Web Token (JWT)</a> as the authorization header. You'll need to generate a JWT for every request as explained in the <a href=\"%(docs_url)s"
|
||||
"\">API documentation</a>."
|
||||
"To make API requests, send a <a href=\"%(jwt_url)s\">JSON Web Token (JWT)</a> as the authorization header. You'll need to generate a JWT for every request as explained in the <a "
|
||||
"href=\"%(docs_url)s\">API documentation</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/api/key.html
|
||||
|
@ -5442,28 +5416,24 @@ msgid "{0} Add-ons"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/blog_posts.html
|
||||
#, fuzzy
|
||||
msgid "Latest News"
|
||||
msgstr "Siste versjon:"
|
||||
msgstr "Siste nytt"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/blog_posts.html
|
||||
msgid "Read more in our Blog"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Resources"
|
||||
msgstr "Fleire resursar"
|
||||
msgstr "Resursar"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "WebExtensions"
|
||||
msgstr "Utvidingar"
|
||||
msgstr "WebUtvidingar"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Community"
|
||||
msgstr "Kommentar"
|
||||
msgstr "Fellesskap"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/templates/footer.html
|
||||
msgid "About"
|
||||
|
@ -5478,9 +5448,8 @@ msgid "Blog"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Contact Us"
|
||||
msgstr "Innhald"
|
||||
msgstr "Kontakt oss"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
|
@ -5492,9 +5461,8 @@ msgid "FAQ"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Report Bug"
|
||||
msgstr "Rapporter misbruk"
|
||||
msgstr "Rapporter feil"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/templates/copyright.html
|
||||
msgid "Site Status"
|
||||
|
@ -5536,9 +5504,8 @@ msgid "Legal Notices"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Review Add-ons"
|
||||
msgstr "Fleire utvidingar"
|
||||
msgstr "Vurder utvidingar"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
msgid "Volunteer reviewers help keep add-ons safe and reliable to use. They enjoy great perks too!"
|
||||
|
@ -5592,14 +5559,12 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/manage_your_addon.html src/olympia/devhub/templates/devhub/new-landing/components/my-addons.html
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/port_chrome_ext.html
|
||||
#, fuzzy
|
||||
msgid "Learn How"
|
||||
msgstr "Les meir"
|
||||
msgstr "Lær deg korleis"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/my-addons.html
|
||||
#, fuzzy
|
||||
msgid "What's New"
|
||||
msgstr "Siste versjon:"
|
||||
msgstr "Kva er nytt"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/my-addons.html
|
||||
msgid "Happy New Year! See what's in store for add-ons in 2017."
|
||||
|
@ -5659,8 +5624,8 @@ msgstr "Tilpass Firefox"
|
|||
#: src/olympia/devhub/templates/devhub/new-landing/components/overview.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons let millions of Firefox users enhance their browsing experience. If you know <a href=\"%(html_link)s\">HTML</a>, <a href=\"%(js_link)s\">JavaScript</a>, and <a href=\"%(css_link)s\">CSS</"
|
||||
"a>, you already have all the necessary skills to make a great add-on."
|
||||
"Add-ons let millions of Firefox users enhance their browsing experience. If you know <a href=\"%(html_link)s\">HTML</a>, <a href=\"%(js_link)s\">JavaScript</a>, and <a href=\"%(css_link)s\">CSS</a>,"
|
||||
" you already have all the necessary skills to make a great add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/overview.html
|
||||
|
@ -5693,9 +5658,8 @@ msgid "Sign In"
|
|||
msgstr "Utviding"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/tools.html
|
||||
#, fuzzy
|
||||
msgid "Validator"
|
||||
msgstr "Valider no."
|
||||
msgstr "Validator"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/tools.html
|
||||
msgid "Automated code tests for your add-on."
|
||||
|
@ -6463,11 +6427,10 @@ msgstr[0] "Utvidingar for {0}"
|
|||
msgstr[1] "Utvidingar for {0}"
|
||||
|
||||
#: src/olympia/editors/helpers.py
|
||||
#, fuzzy
|
||||
msgid "Update ({0})"
|
||||
msgid_plural "Updates ({0})"
|
||||
msgstr[0] "Oppdatert {0}"
|
||||
msgstr[1] "Oppdatert {0}"
|
||||
msgstr[0] "Oppdatering ({0})"
|
||||
msgstr[1] "Oppdateringar ({0})"
|
||||
|
||||
#: src/olympia/editors/helpers.py
|
||||
msgid "Moderated Review ({0})"
|
||||
|
@ -6704,9 +6667,8 @@ msgid "Queues"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/editors/templates/editors/base.html
|
||||
#, fuzzy
|
||||
msgid "New Add-ons"
|
||||
msgstr "Fleire utvidingar"
|
||||
msgstr "Nye utvidingar"
|
||||
|
||||
#: src/olympia/editors/templates/editors/base.html
|
||||
msgid "Moderated Reviews"
|
||||
|
@ -6819,9 +6781,8 @@ msgid "Reviews This Month"
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/editors/templates/editors/home.html
|
||||
#, fuzzy
|
||||
msgid "New Reviewers"
|
||||
msgstr "AMO-vurderarar"
|
||||
msgstr "Nye vurderarar"
|
||||
|
||||
#: src/olympia/editors/templates/editors/home.html
|
||||
msgid "You're #{0} with {1} reviews"
|
||||
|
@ -8437,8 +8398,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Help improve this website. It's open source, and you can file bugs and submit patches. <a href=\"%(url)s\"> GitHub</a> contains all of our current bugs, legacy bugs can still be found in Bugzilla."
|
||||
msgid "Help improve this website. It's open source, and you can file bugs and submit patches. <a href=\"%(url)s\"> GitHub</a> contains all of our current bugs, legacy bugs can still be found in Bugzilla."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
|
@ -8464,9 +8424,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"A good place to start is our <a href=\"%(faq_url)s\"><abbr title=\"Frequently Asked Questions\">FAQ</abbr></a>. If you don't find an answer there, you can <a href=\"%(forum_url)s\"> ask on our "
|
||||
"forums</a>."
|
||||
msgid "A good place to start is our <a href=\"%(faq_url)s\"><abbr title=\"Frequently Asked Questions\">FAQ</abbr></a>. If you don't find an answer there, you can <a href=\"%(forum_url)s\"> ask on our forums</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
|
@ -8481,8 +8439,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Over the years, many people have contributed to this website, including both volunteers from the community and a dedicated AMO team. A list of significant contributors can be found on our <a href="
|
||||
"\"%(url)s\"> Site Credits</a> page."
|
||||
"Over the years, many people have contributed to this website, including both volunteers from the community and a dedicated AMO team. A list of significant contributors can be found on our <a "
|
||||
"href=\"%(url)s\"> Site Credits</a> page."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/acr_firstrun.html
|
||||
|
@ -8696,8 +8654,8 @@ msgstr ""
|
|||
#, python-format
|
||||
msgid ""
|
||||
"This file, called an <a href=\"%(url)s\">Install Manifest</a>, is used by Add-on Manager-enabled XUL applications to determine information about an add-on as it is being installed. It contains "
|
||||
"metadata identifying the add-on, providing information about who created it, where more information can be found about it, which versions of what applications it is compatible with, how it should "
|
||||
"be updated, and so on. The format of the Install Manifest is RDF/XML."
|
||||
"metadata identifying the add-on, providing information about who created it, where more information can be found about it, which versions of what applications it is compatible with, how it should be"
|
||||
" updated, and so on. The format of the Install Manifest is RDF/XML."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8744,9 +8702,9 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"To ensure compatibility with the latest Mozilla software, it's important to download updates as they become available and test your add-on to ensure that it is still functioning as expected. In "
|
||||
"many cases, the latest version of Mozilla software may be a beta release. Since these releases at times introduce architectural changes that may impact the functionality of your add-on, it's "
|
||||
"important to be actively involved in the beta process to ensure that your add-on users are not negatively impacted upon final release of Mozilla software."
|
||||
"To ensure compatibility with the latest Mozilla software, it's important to download updates as they become available and test your add-on to ensure that it is still functioning as expected. In many"
|
||||
" cases, the latest version of Mozilla software may be a beta release. Since these releases at times introduce architectural changes that may impact the functionality of your add-on, it's important "
|
||||
"to be actively involved in the beta process to ensure that your add-on users are not negatively impacted upon final release of Mozilla software."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8756,8 +8714,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Poorly written extensions can have a severe impact on the browsing experience, including on the overall performance of Firefox itself. The following page contains many good <a href=\"%(url)s"
|
||||
"\">guides</a> that help you improve performance, whether you're developing core Mozilla code or an add-on."
|
||||
"Poorly written extensions can have a severe impact on the browsing experience, including on the overall performance of Firefox itself. The following page contains many good <a "
|
||||
"href=\"%(url)s\">guides</a> that help you improve performance, whether you're developing core Mozilla code or an add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8828,8 +8786,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Yes. You may find 3rd party developers via the <a href=\"%(forum_url)s\">Add-ons forum</a>, <a href=\"%(list_url)s\">mozilla.jobs list</a>, <a href=\"%(mz_url)s\">mozillaZine forums</a> or <a href="
|
||||
"\"%(wiki_url)s\">the Mozilla Wiki</a>. Please note that Mozilla does not offer developer recommendations."
|
||||
"Yes. You may find 3rd party developers via the <a href=\"%(forum_url)s\">Add-ons forum</a>, <a href=\"%(list_url)s\">mozilla.jobs list</a>, <a href=\"%(mz_url)s\">mozillaZine forums</a> or <a "
|
||||
"href=\"%(wiki_url)s\">the Mozilla Wiki</a>. Please note that Mozilla does not offer developer recommendations."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8918,8 +8876,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"The choice of category is dependent on what type of audience you are targeting and the functionality of your add-on. If you're unsure of which category your add-on falls into, please choose \"Other"
|
||||
"\". The AMO team may re-categorize your add-on if it's determined that it's better suited in a different category."
|
||||
"The choice of category is dependent on what type of audience you are targeting and the functionality of your add-on. If you're unsure of which category your add-on falls into, please choose "
|
||||
"\"Other\". The AMO team may re-categorize your add-on if it's determined that it's better suited in a different category."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8956,9 +8914,9 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons are reviewed by the Add-on Reviewers, a group of talented developers that volunteer to help the Mozilla project by reviewing add-ons to ensure a stable and safe experience for Mozilla "
|
||||
"users. When communicating with reviewer, please be courteous, patient and respectful as they are working hard to ensure that your add-on is set up correctly and follows the guidelines outlined in "
|
||||
"the <a href=\"%(url)s\">Add-on Review Guide</a>."
|
||||
"Add-ons are reviewed by the Add-on Reviewers, a group of talented developers that volunteer to help the Mozilla project by reviewing add-ons to ensure a stable and safe experience for Mozilla users."
|
||||
" When communicating with reviewer, please be courteous, patient and respectful as they are working hard to ensure that your add-on is set up correctly and follows the guidelines outlined in the <a "
|
||||
"href=\"%(url)s\">Add-on Review Guide</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -8998,8 +8956,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This is why it's very important to read the <a href=\"%(g_url)s\">Add-on Review Guide</a> to ensure that your add-on is setup as expected. It's also a good idea to read the blog post, <a href="
|
||||
"\"%(blog_url)s\">Successfully Getting your Add-on Reviewed</a> which provides excellent insight into ensuring a smooth review of your add-on."
|
||||
"This is why it's very important to read the <a href=\"%(g_url)s\">Add-on Review Guide</a> to ensure that your add-on is setup as expected. It's also a good idea to read the blog post, <a "
|
||||
"href=\"%(blog_url)s\">Successfully Getting your Add-on Reviewed</a> which provides excellent insight into ensuring a smooth review of your add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9087,10 +9045,10 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"Do you need more information about the various open source licenses? Are you confused as to which license you should select? What rights does a specific license grant? While nothing replaces "
|
||||
"reading the full terms of a license, below are some sites that contain information about some of the key open source licenses that may help you sort out the differences between them. These sites "
|
||||
"are being provided solely for your convenience and as a reference for your personal use. These resources do not constitute legal advice nor should they be used in lieu of such advice. Mozilla "
|
||||
"neither guarantees nor is responsible for the content of these sites or your reliance on such content."
|
||||
"Do you need more information about the various open source licenses? Are you confused as to which license you should select? What rights does a specific license grant? While nothing replaces reading"
|
||||
" the full terms of a license, below are some sites that contain information about some of the key open source licenses that may help you sort out the differences between them. These sites are being "
|
||||
"provided solely for your convenience and as a reference for your personal use. These resources do not constitute legal advice nor should they be used in lieu of such advice. Mozilla neither "
|
||||
"guarantees nor is responsible for the content of these sites or your reliance on such content."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9148,9 +9106,10 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons listed in this gallery only work with Mozilla-based applications, such as <a href=\"%(getfirefox_url)s\">Firefox</a>, <a href=\"%(getmobile_url)s\">Firefox Mobile</a>, <a href="
|
||||
"\"%(getseamonkey_url)s\">SeaMonkey</a>, and <a href=\"%(getthunderbird_url)s\">Thunderbird</a>. However, not all add-ons work with each of those applications or every version of those applications. "
|
||||
"Each add-on specifies which applications and versions it works with, such as Firefox 2.0 - 3.6.*. For Firefox add-ons, the install buttons will indicate whether the add-on is compatible or not."
|
||||
"Add-ons listed in this gallery only work with Mozilla-based applications, such as <a href=\"%(getfirefox_url)s\">Firefox</a>, <a href=\"%(getmobile_url)s\">Firefox Mobile</a>, <a "
|
||||
"href=\"%(getseamonkey_url)s\">SeaMonkey</a>, and <a href=\"%(getthunderbird_url)s\">Thunderbird</a>. However, not all add-ons work with each of those applications or every version of those "
|
||||
"applications. Each add-on specifies which applications and versions it works with, such as Firefox 2.0 - 3.6.*. For Firefox add-ons, the install buttons will indicate whether the add-on is "
|
||||
"compatible or not."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9213,8 +9172,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"In Firefox, add-ons marked with \"No restart required\" can be installed without restarting. These add-ons have been created using the <a href=\"%(sdk_url)s\">Add-on SDK</a> or <a href="
|
||||
"\"%(bootstrap_url)s\">bootstrapping</a>. Other add-ons will still require a restart before you can use them."
|
||||
"In Firefox, add-ons marked with \"No restart required\" can be installed without restarting. These add-ons have been created using the <a href=\"%(sdk_url)s\">Add-on SDK</a> or <a "
|
||||
"href=\"%(bootstrap_url)s\">bootstrapping</a>. Other add-ons will still require a restart before you can use them."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9225,8 +9184,8 @@ msgstr ""
|
|||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons, unlike plugins, are automatically checked for updates once every day. In Firefox, updates are automatically installed by default. Versions of Firefox prior to 4 (and other applications) "
|
||||
"will alert you that updates to your add-ons are available. <a href=\"%(plugin_url)s\">Plugins</a> are not currently automatically checked for updates, so be sure to regularly visit the <a href="
|
||||
"\"%(plugincheck_url)s\">Plugin Check</a> page to stay up-to-date."
|
||||
"will alert you that updates to your add-ons are available. <a href=\"%(plugin_url)s\">Plugins</a> are not currently automatically checked for updates, so be sure to regularly visit the <a "
|
||||
"href=\"%(plugincheck_url)s\">Plugin Check</a> page to stay up-to-date."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9237,8 +9196,8 @@ msgstr ""
|
|||
#, python-format
|
||||
msgid ""
|
||||
"Unless clearly marked otherwise, add-ons available from this gallery have been checked and approved by Mozilla's team of editors and are safe to install. We recommend that you only install approved "
|
||||
"add-ons. If you wish to install unapproved add-ons or add-ons from third-party websites, use caution as these add-ons may harm your computer or violate your privacy. <a href=\"%(learnmore_url)s"
|
||||
"\">Learn more about our approval process</a>"
|
||||
"add-ons. If you wish to install unapproved add-ons or add-ons from third-party websites, use caution as these add-ons may harm your computer or violate your privacy. <a "
|
||||
"href=\"%(learnmore_url)s\">Learn more about our approval process</a>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9322,8 +9281,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"While all add-ons publicly available in our gallery are reviewed by an editor, you may receive a direct link to an add-on that hasn't yet been reviewed. Use caution when installing these add-ons, "
|
||||
"as they could harm your computer or violate your privacy. We recommend that you only install reviewed add-ons. <a href=\"%(url)s\">Learn more about our review process</a></dd>"
|
||||
"While all add-ons publicly available in our gallery are reviewed by an editor, you may receive a direct link to an add-on that hasn't yet been reviewed. Use caution when installing these add-ons, as"
|
||||
" they could harm your computer or violate your privacy. We recommend that you only install reviewed add-ons. <a href=\"%(url)s\">Learn more about our review process</a></dd>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9350,8 +9309,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
msgid ""
|
||||
"Beta add-ons are unreviewed versions which represent the latest work of an add-on author. While different authors have different standards for beta code quality, you should assume that these add-"
|
||||
"ons are less stable than the general add-on releases."
|
||||
"Beta add-ons are unreviewed versions which represent the latest work of an add-on author. While different authors have different standards for beta code quality, you should assume that these add-ons"
|
||||
" are less stable than the general add-on releases."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9394,9 +9353,9 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The source code used to create an add-on is an exclusive copyright of the add-on author, unless otherwise declared in a source code license. Many add-ons on this site have <a href=\"%(url)s\" lang="
|
||||
"\"en\">open source licenses</a> that make the source code publicly available for copy and reuse under conditions determined by the author. Most authors choose widely known open source licenses like "
|
||||
"the GPL or BSD licenses instead of making up their own."
|
||||
"The source code used to create an add-on is an exclusive copyright of the add-on author, unless otherwise declared in a source code license. Many add-ons on this site have <a href=\"%(url)s\" "
|
||||
"lang=\"en\">open source licenses</a> that make the source code publicly available for copy and reuse under conditions determined by the author. Most authors choose widely known open source licenses "
|
||||
"like the GPL or BSD licenses instead of making up their own."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9435,8 +9394,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Mobile add-ons work with <a href=\"%(mobile_url)s\">Firefox for Mobile</a> and add or modify functionality just like desktop add-ons. You can find add-ons that work with Firefox for Mobile in our "
|
||||
"<a href=\"%(gallery_url)s\">gallery</a>."
|
||||
"Mobile add-ons work with <a href=\"%(mobile_url)s\">Firefox for Mobile</a> and add or modify functionality just like desktop add-ons. You can find add-ons that work with Firefox for Mobile in our <a"
|
||||
" href=\"%(gallery_url)s\">gallery</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9467,8 +9426,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/review_guide.html
|
||||
msgid ""
|
||||
"Add-on reviews are a way for you to share your opinions about the add-ons you’ve installed and used. Our review moderation team reserves the right to refuse or remove any review that does not "
|
||||
"comply with these guidelines."
|
||||
"Add-on reviews are a way for you to share your opinions about the add-ons you’ve installed and used. Our review moderation team reserves the right to refuse or remove any review that does not comply"
|
||||
" with these guidelines."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/review_guide.html
|
||||
|
@ -9673,10 +9632,10 @@ msgstr ""
|
|||
msgid ""
|
||||
"<h2>Keep these tips in mind:</h2> <ul> <li> Write like you're telling a friend about your experience with the add-on. Give specifics and helpful details, such as what features you liked and/or "
|
||||
"disliked, how easy to use it is, and any disadvantages it has. Avoid generic language such as calling it \"Great\" or \"Bad\" unless you can give reasons why you believe this is so. </li> <li> "
|
||||
"Please do not post bug reports here. We do not make your email address available to add-on developers, so they can't contact you to resolve your issue. See this add-on's <a href=\"%(support)s"
|
||||
"\">support section</a> to find out if assistance is available. You can also try asking the <a href=\"https://discourse.mozilla-community.org/c/add-ons/add-on-support\">add-on community</a> for "
|
||||
"help. </li> <li>Please keep reviews clean, avoid the use of improper language and do not post any personal information. </li> </ul> <p>Please read the <a href=\"%(guide)s\">Review Guidelines</a> "
|
||||
"for more detail about user add-on reviews.</p>"
|
||||
"Please do not post bug reports here. We do not make your email address available to add-on developers, so they can't contact you to resolve your issue. See this add-on's <a "
|
||||
"href=\"%(support)s\">support section</a> to find out if assistance is available. You can also try asking the <a href=\"https://discourse.mozilla-community.org/c/add-ons/add-on-support\">add-on "
|
||||
"community</a> for help. </li> <li>Please keep reviews clean, avoid the use of improper language and do not post any personal information. </li> </ul> <p>Please read the <a href=\"%(guide)s\">Review "
|
||||
"Guidelines</a> for more detail about user add-on reviews.</p>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/reviews/templates/reviews/reply.html
|
||||
|
@ -10307,11 +10266,11 @@ msgstr ""
|
|||
#: src/olympia/stats/templates/stats/reports/sources.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<h2>Tracking external sources</h2> <p> If you link to your add-on's details page or directly to its file from an external site, such as your blog or website, you can append a parameter to be "
|
||||
"tracked as an additional download source on this page. For example, the following links would appear as sourced by your blog: <dl> <dt>Add-on Details Page</dt> <dd>https://addons.mozilla.org/addon/"
|
||||
"%(slug)s?src=<b>external-blog</b></dd> <dt>Direct File Link</dt> <dd>https://addons.mozilla.org/downloads/latest/%(id)s/addon-%(id)s-latest.xpi?src=<b>external-blog</b></dd> </dl> <p> Only src "
|
||||
"parameters that begin with \"external-\" will be tracked, up to 61 additional characters. Any text after \"external-\" can be used to describe the source, such as \"external-blog\", \"external-"
|
||||
"sidebar\", \"external-campaign225\", etc. The following URL-safe characters are allowed: <code>a-z A-Z - . _ ~ %% +</code>"
|
||||
"<h2>Tracking external sources</h2> <p> If you link to your add-on's details page or directly to its file from an external site, such as your blog or website, you can append a parameter to be tracked"
|
||||
" as an additional download source on this page. For example, the following links would appear as sourced by your blog: <dl> <dt>Add-on Details Page</dt> "
|
||||
"<dd>https://addons.mozilla.org/addon/%(slug)s?src=<b>external-blog</b></dd> <dt>Direct File Link</dt> <dd>https://addons.mozilla.org/downloads/latest/%(id)s/addon-%(id)s-latest.xpi?src=<b>external-"
|
||||
"blog</b></dd> </dl> <p> Only src parameters that begin with \"external-\" will be tracked, up to 61 additional characters. Any text after \"external-\" can be used to describe the source, such as "
|
||||
"\"external-blog\", \"external-sidebar\", \"external-campaign225\", etc. The following URL-safe characters are allowed: <code>a-z A-Z - . _ ~ %% +</code>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/stats/templates/stats/reports/statuses.html
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT 1.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2016-11-07 14:54+0000\n"
|
||||
"PO-Revision-Date: 2017-02-16 01:59+0000\n"
|
||||
"Last-Translator: Bjørn I. <bjorn.svindseth@online.no>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: nn_NO\n"
|
||||
|
@ -144,17 +144,19 @@ msgstr "Sjekkliste for å senda inn utvidingar"
|
|||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "Please verify the following points before finalizing your submission. This will minimize delays or misunderstanding during the review process:"
|
||||
msgstr ""
|
||||
msgstr "Gjer vel og kontroller følgjande punkt før du fullfører bidraget ditt. Dette vil minimera forseinkingar eller misforståingar under vurderingsprosessen:"
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid ""
|
||||
"Compiled binaries, as well as minified or obfuscated scripts (excluding known libraries) need to have their sources submitted separately for review. Make sure that you use the source code upload "
|
||||
"field to avoid having your submission rejected."
|
||||
msgstr ""
|
||||
"Kompilerte binærfiler, så vel som forminska eller forvrengde skript (unnateke kjende bibliotek) må senda inn kjeldene sine separat for vurdering. Sjå til at du brukar opplastingsfeltet for "
|
||||
"kjeldekoden slik at du unngår at bidraget ditt vert avvist."
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "The validation process found these issues that can lead to rejections:"
|
||||
msgstr ""
|
||||
msgstr "Valideringsprosessen fann desse problema som kan føra til avslag:"
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "Sorry, no supported platform has been found."
|
||||
|
@ -815,7 +817,7 @@ msgstr "Vel ein applikasjon først"
|
|||
msgid "Set {0} add-on to a max version of {1} and email the author."
|
||||
msgid_plural "Set {0} add-ons to a max version of {1} and email the authors."
|
||||
msgstr[0] "Set utvidinga {0} til maksversjon på {1} og send e-post til utviklaren."
|
||||
msgstr[1] ""
|
||||
msgstr[1] "Set utvidingane {0} til maksversjon på {1} og send e-post til utviklaren."
|
||||
|
||||
#: static/js/zamboni/admin_validation.js
|
||||
msgid "Email author of {2} add-on which failed validation."
|
||||
|
|
|
@ -4,8 +4,8 @@ msgstr ""
|
|||
"Project-Id-Version: AMO (olympia)\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2017-02-13 15:30+0000\n"
|
||||
"Last-Translator: Alberto Castro <albertdecastro@tutanota.com>\n"
|
||||
"PO-Revision-Date: 2017-02-15 15:03+0000\n"
|
||||
"Last-Translator: Rodrigo <rodrigo.mcunha@hotmail.com>\n"
|
||||
"Language-Team: pt-PT <portuguese european>\n"
|
||||
"Language: pt_PT\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -5400,7 +5400,7 @@ msgstr "Ver todas"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
msgid "View Statistics Dashboard"
|
||||
msgstr "Ver o quadro de estatísticas"
|
||||
msgstr "Ver o painel de estatísticas"
|
||||
|
||||
# 75%
|
||||
#: src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
|
@ -10337,7 +10337,7 @@ msgstr "Exportar"
|
|||
#. {0} is an add-on name, {1} is an app name (like Firefox)
|
||||
#: src/olympia/stats/templates/stats/stats.html
|
||||
msgid "{0} :: Statistics Dashboard :: Add-ons for {1}"
|
||||
msgstr "{0} ::Quadro de estatísticas :: Extras para o {1}"
|
||||
msgstr "{0} :: Painel de estatísticas :: Extras para {1}"
|
||||
|
||||
# 77%
|
||||
#: src/olympia/stats/templates/stats/stats.html
|
||||
|
@ -10421,7 +10421,7 @@ msgstr "Sem dados disponíveis."
|
|||
|
||||
#: src/olympia/stats/templates/stats/stats.html
|
||||
msgid "This dashboard is currently <b>public</b>."
|
||||
msgstr "Este quadro de momento é <b>público</b>."
|
||||
msgstr "Este painel é atualmente <b>público</b>."
|
||||
|
||||
#: src/olympia/stats/templates/stats/stats.html
|
||||
msgid "Contribution stats are currently <b>private</b>."
|
||||
|
@ -10497,7 +10497,7 @@ msgstr "A carregar..."
|
|||
|
||||
#: src/olympia/stats/templates/stats/reports/overview.html
|
||||
msgid "<b>{0}</b> Average Daily Users"
|
||||
msgstr "<b>{0}</b> Utilizadores médios diários"
|
||||
msgstr "<b>{0}</b> utilizadores médios diários"
|
||||
|
||||
#: src/olympia/stats/templates/stats/reports/overview.html
|
||||
msgid "Top Applications"
|
||||
|
@ -10927,7 +10927,7 @@ msgstr "o meu extra baseado no sdk não pode ser atualizado"
|
|||
|
||||
#: src/olympia/users/notifications.py
|
||||
msgid "my add-on is reviewed by a reviewer"
|
||||
msgstr "o meu extra é revisto por um editor"
|
||||
msgstr "o meu extra é revisto por um revisor"
|
||||
|
||||
#: src/olympia/users/notifications.py
|
||||
msgid "Mozilla needs to contact me about my individual add-on"
|
||||
|
|
|
@ -7,7 +7,7 @@ msgstr ""
|
|||
"Project-Id-Version: addons\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2017-02-11 18:39+0000\n"
|
||||
"PO-Revision-Date: 2017-02-14 19:24+0000\n"
|
||||
"Last-Translator: Top <teerapatxtop@yahoo.com>\n"
|
||||
"Language-Team: Thai\n"
|
||||
"Language: th\n"
|
||||
|
@ -1891,7 +1891,7 @@ msgstr "ก่อนหน้า"
|
|||
|
||||
#: src/olympia/amo/templates/amo/impala/paginator.html
|
||||
msgid "Jump to last page"
|
||||
msgstr ""
|
||||
msgstr "กระโดดไปยังหน้าสุดท้าย"
|
||||
|
||||
#. First and second arguments are the result range (e.g., 1-20);
|
||||
#. third argument is the number of total results (e.g., 1,000).
|
||||
|
@ -2294,7 +2294,7 @@ msgstr[0] "<span>%(addons)s</span> ส่วนเสริม"
|
|||
#, python-format
|
||||
msgid "<span>%(followers)s</span> follower"
|
||||
msgid_plural "<span>%(followers)s</span> followers"
|
||||
msgstr[0] ""
|
||||
msgstr[0] "<span>%(followers)s</span> ผู้ติดตาม"
|
||||
|
||||
#. People "follow" collections to get notified of updates. Like
|
||||
#. Twitter followers.
|
||||
|
@ -2352,11 +2352,11 @@ msgstr "คุณแน่ใจหรือไม่?"
|
|||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/delete.html src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
msgstr "ใช่"
|
||||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/delete.html src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
msgstr "ไม่"
|
||||
|
||||
#. {0} is the name of the collection.
|
||||
#: src/olympia/bandwagon/templates/bandwagon/edit.html
|
||||
|
@ -2749,7 +2749,7 @@ msgstr "ค้นหาผู้ให้บริการใหม่สำห
|
|||
|
||||
#: src/olympia/browse/templates/browse/search_tools.html
|
||||
msgid "Additional Resources"
|
||||
msgstr ""
|
||||
msgstr "ทรัพยากรเพิ่มเติม"
|
||||
|
||||
#. {0} is an app name, like Firefox.
|
||||
#: src/olympia/browse/templates/browse/search_tools.html
|
||||
|
@ -3023,7 +3023,7 @@ msgstr "Sunbird"
|
|||
|
||||
#: src/olympia/constants/applications.py
|
||||
msgid "Mobile"
|
||||
msgstr ""
|
||||
msgstr "มือถือ"
|
||||
|
||||
#: src/olympia/constants/applications.py
|
||||
msgid "Firefox for Android"
|
||||
|
@ -3092,7 +3092,7 @@ msgstr "ชุดตกแต่งแบบสมบูรณ์"
|
|||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Search Engine"
|
||||
msgstr ""
|
||||
msgstr "เครื่องมือค้นหา"
|
||||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Language Pack (Application)"
|
||||
|
@ -3100,7 +3100,7 @@ msgstr "ชุดภาษา (แอพพลิเคชัน)"
|
|||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Language Pack (Add-on)"
|
||||
msgstr ""
|
||||
msgstr "ชุดภาษา (ส่วนเสริม)"
|
||||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Plugin"
|
||||
|
@ -3125,7 +3125,7 @@ msgstr "ชุดภาษา (แอพพลิเคชัน)"
|
|||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Language Packs (Add-on)"
|
||||
msgstr ""
|
||||
msgstr "ชุดภาษา (ส่วนเสริม)"
|
||||
|
||||
#: src/olympia/constants/base.py
|
||||
msgid "Plugins"
|
||||
|
@ -3685,7 +3685,7 @@ msgstr "ทุกแพลตฟอร์ม"
|
|||
|
||||
#: src/olympia/constants/platforms.py
|
||||
msgid "Linux"
|
||||
msgstr ""
|
||||
msgstr "Linux"
|
||||
|
||||
#: src/olympia/constants/platforms.py
|
||||
msgid "Mac OS X"
|
||||
|
@ -3697,15 +3697,15 @@ msgstr "BSD"
|
|||
|
||||
#: src/olympia/constants/platforms.py
|
||||
msgid "Windows"
|
||||
msgstr ""
|
||||
msgstr "Windows"
|
||||
|
||||
#: src/olympia/constants/platforms.py
|
||||
msgid "Solaris"
|
||||
msgstr ""
|
||||
msgstr "Solaris"
|
||||
|
||||
#: src/olympia/constants/platforms.py
|
||||
msgid "Android"
|
||||
msgstr ""
|
||||
msgstr "Android"
|
||||
|
||||
#: src/olympia/constants/webext_permissions.py
|
||||
msgid "Requests that the extension be granted permissions according to the activeTab specification."
|
||||
|
@ -4576,7 +4576,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/details.html src/olympia/users/forms.py src/olympia/users/templates/users/edit.html src/olympia/users/templates/users/vcard.html
|
||||
msgid "Homepage"
|
||||
msgstr ""
|
||||
msgstr "หน้าแรก"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/details.html
|
||||
msgid ""
|
||||
|
@ -4642,7 +4642,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/technical.html
|
||||
msgid "View Source?"
|
||||
msgstr ""
|
||||
msgstr "ดูต้นฉบับ?"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/technical.html
|
||||
msgid "Whether the source of your add-on can be displayed in our online viewer. It is only relevant for listed add-ons."
|
||||
|
@ -4674,7 +4674,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/technical.html
|
||||
msgid "Upgrade SDK?"
|
||||
msgstr ""
|
||||
msgstr "อัปเกรด SDK?"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/technical.html
|
||||
msgid "If selected, we will try to automatically upgrade your add-on when a new version of the SDK is released. It is only relevant for listed add-ons."
|
||||
|
@ -5348,7 +5348,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
msgid "View All"
|
||||
msgstr ""
|
||||
msgstr "ดูทั้งหมด"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/includes/addons_edit_nav.html
|
||||
msgid "View Statistics Dashboard"
|
||||
|
@ -5430,7 +5430,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/includes/version_file.html
|
||||
msgid "Undo"
|
||||
msgstr ""
|
||||
msgstr "เลิกทำ"
|
||||
|
||||
#. {0} is an application, like Firefox.
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/index.html src/olympia/search/views.py src/olympia/templates/base.html src/olympia/templates/impala/base.html
|
||||
|
@ -5445,11 +5445,11 @@ msgstr "รุ่นล่าสุด:"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/blog_posts.html
|
||||
msgid "Read more in our Blog"
|
||||
msgstr ""
|
||||
msgstr "อ่านเพิ่มเติมในบล็อกของเรา"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
msgid "Resources"
|
||||
msgstr ""
|
||||
msgstr "ทรัพยากร"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
|
@ -5463,15 +5463,15 @@ msgstr "ความคิดเห็น"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/templates/footer.html
|
||||
msgid "About"
|
||||
msgstr ""
|
||||
msgstr "เกี่ยวกับ"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/templates/footer.html
|
||||
msgid "Forum"
|
||||
msgstr ""
|
||||
msgstr "กระดานสนทนา"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/devhub/templates/devhub/new-landing/components/navigation.html src/olympia/templates/footer.html
|
||||
msgid "Blog"
|
||||
msgstr ""
|
||||
msgstr "บล็อก"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
|
@ -5485,7 +5485,7 @@ msgstr "บทวิจารณ์:"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html src/olympia/templates/footer.html
|
||||
msgid "FAQ"
|
||||
msgstr ""
|
||||
msgstr "คำถามที่พบบ่อย"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
|
@ -5939,11 +5939,11 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html
|
||||
msgid "Header"
|
||||
msgstr ""
|
||||
msgstr "ส่วนหัว"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html
|
||||
msgid "Footer"
|
||||
msgstr ""
|
||||
msgstr "ส่วนท้าย"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "Select colors for your Theme."
|
||||
|
@ -5959,7 +5959,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "Background"
|
||||
msgstr ""
|
||||
msgstr "พื้นหลัง"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "This is the color of the tabs."
|
||||
|
@ -6106,7 +6106,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/versions/edit.html
|
||||
msgid "Source code"
|
||||
msgstr ""
|
||||
msgstr "โค้ดต้นฉบับ"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/versions/edit.html
|
||||
msgid "If your add-on contain binary or obfuscated code, make the source available here for reviewers."
|
||||
|
|
|
@ -7,7 +7,7 @@ msgstr ""
|
|||
"Project-Id-Version: REMORA 0.1\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2017-02-04 13:45+0000\n"
|
||||
"PO-Revision-Date: 2017-02-17 18:28+0000\n"
|
||||
"Last-Translator: Selim Şumlu <selim@sum.lu>\n"
|
||||
"Language-Team: Turkish (Türkçe)\n"
|
||||
"Language: tr\n"
|
||||
|
@ -169,8 +169,8 @@ msgstr "Kullanıcılara her zaman Eklenti Yöneticisi'nde sorulacak (Firefox 4 v
|
|||
msgid "Listed"
|
||||
msgstr "Listelenen"
|
||||
|
||||
# %1 is an add-on name.
|
||||
#. l10n: {0} is the addon name
|
||||
# %1 is an add-on name.
|
||||
#: src/olympia/addons/views.py
|
||||
msgid "Contribution for {0}"
|
||||
msgstr "{0} için bağış"
|
||||
|
@ -236,9 +236,9 @@ msgstr "Bu eklentinin geliştiricisi, <a href=\"%(charity_url)s\">%(charity_name
|
|||
msgid "Contribute"
|
||||
msgstr "Bağışta Bulun"
|
||||
|
||||
#. Click Contribute button OR Install button
|
||||
# This is a separator between the graphical [contribute] button and the
|
||||
# graphical [download now] button
|
||||
#. Click Contribute button OR Install button
|
||||
#: src/olympia/addons/templates/addons/contribution.html src/olympia/addons/templates/addons/impala/contribution.html src/olympia/addons/templates/addons/report_abuse.html
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_update.html src/olympia/devhub/templates/devhub/addons/edit/admin.html src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/details.html src/olympia/devhub/templates/devhub/addons/edit/support.html src/olympia/devhub/templates/devhub/addons/edit/technical.html
|
||||
|
@ -282,17 +282,14 @@ msgstr "<strong>%(addon_name)s</strong> eklentisinin süren gelişimini destekle
|
|||
|
||||
#: src/olympia/addons/templates/addons/contributions_lightbox.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To show your support for <b>%(addon_name)s</b>, the developer asks that you make a donation to the <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgid "To show your support for <b>%(addon_name)s</b>, the developer asks that you make a donation to the <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgstr ""
|
||||
"<b>%(addon_name)s</b> eklentisine desteğinizi göstermeniz için, geliştirici, <a href=\"%(paypal_url)s\">PayPal</a> üzerinden <a href=\"%(charity_url)s\">%(charity_name)s</a> kurumuna bağışta "
|
||||
"bulunmanızı rica ediyor."
|
||||
|
||||
#: src/olympia/addons/templates/addons/contributions_lightbox.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To show your support for <b>%(addon_name)s</b>, the developer asks that you make a small contribution to <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</"
|
||||
"a>."
|
||||
msgid "To show your support for <b>%(addon_name)s</b>, the developer asks that you make a small contribution to <a href=\"%(charity_url)s\">%(charity_name)s</a> through <a href=\"%(paypal_url)s\">PayPal</a>."
|
||||
msgstr ""
|
||||
"<b>%(addon_name)s</b> eklentisine desteğinizi göstermeniz için, geliştirici, <a href=\"%(paypal_url)s\">PayPal</a> üzerinden <a href=\"%(charity_url)s\">%(charity_name)s</a> kurumuna küçük bir "
|
||||
"bağışta bulunmanızı rica ediyor."
|
||||
|
@ -487,10 +484,10 @@ msgstr "Burda bir şey yok! Geliştirici herhangi bir ayrıntı vermemiş."
|
|||
msgid "Version Notes"
|
||||
msgstr "Sürüm Notları"
|
||||
|
||||
# 76%
|
||||
# 100%
|
||||
#. {0} is the name of the add-on.
|
||||
#. {0} is the name of the add-on
|
||||
# 76%
|
||||
# 100%
|
||||
#: src/olympia/addons/templates/addons/eula.html src/olympia/legacy_discovery/templates/legacy_discovery/addons/eula.html
|
||||
msgid "End-User License Agreement for {0}"
|
||||
msgstr "{0} Son Kullanıcı Lisans Anlaşması"
|
||||
|
@ -778,8 +775,8 @@ msgstr "Bu Persona %(app)s %(new_version)s gerektiriyor. Siz şu anda %(app)s {o
|
|||
|
||||
#: src/olympia/addons/templates/addons/popups.html
|
||||
msgid ""
|
||||
"<strong>Caution:</strong> This add-on has not been reviewed by Mozilla and can't be installed on release versions of Firefox 43 and above. Be careful when installing third-party software that "
|
||||
"might harm your computer."
|
||||
"<strong>Caution:</strong> This add-on has not been reviewed by Mozilla and can't be installed on release versions of Firefox 43 and above. Be careful when installing third-party software that might"
|
||||
" harm your computer."
|
||||
msgstr ""
|
||||
"<strong>Dikkat:</strong> Bu eklenti Mozilla tarafından incelenmemiştir. Bu yüzden Firefox 43 ve üstü sürümlere yüklenemez. Bilgisayarınıza zarar verebilecek üçüncü parti yazılımları kurarken "
|
||||
"dikkatli olun."
|
||||
|
@ -1099,8 +1096,8 @@ msgstr "kapat"
|
|||
msgid "Thank you for installing {0}"
|
||||
msgstr "{0} eklentisini kurduğunuz için teşekkürler"
|
||||
|
||||
# %1 is an add-on name.
|
||||
#. {0} is an add-on name.
|
||||
# %1 is an add-on name.
|
||||
#: src/olympia/addons/templates/addons/impala/developers.html
|
||||
msgid "Meet the {0} Developer"
|
||||
msgstr "{0} Geliştiricisiyle Tanışın"
|
||||
|
@ -1802,8 +1799,8 @@ msgstr "Bulunamadı"
|
|||
#, fuzzy, python-format
|
||||
msgid ""
|
||||
"<h1>We're sorry, but we can't find what you're looking for.</h1> <p> The page or file you requested wasn't found on our site. It's possible that you clicked a link that's out of date, or typed in "
|
||||
"the address incorrectly. </p> <ul> <li>If you typed in the address, please double check the spelling.</li> <li> If you followed a link from somewhere, please <a href=\"https://github.com/mozilla/"
|
||||
"addons-server/issues/new/\">file an issue</a>. Tell us where you came from and what you were looking for, and we'll do our best to fix it. </li> </ul> <p>Or you can just jump over to some of the "
|
||||
"the address incorrectly. </p> <ul> <li>If you typed in the address, please double check the spelling.</li> <li> If you followed a link from somewhere, please <a href=\"https://github.com/mozilla"
|
||||
"/addons-server/issues/new/\">file an issue</a>. Tell us where you came from and what you were looking for, and we'll do our best to fix it. </li> </ul> <p>Or you can just jump over to some of the "
|
||||
"popular pages on our website.</p> <ul> <li>Are you interested in a <a href=\"%(rec)s\">list of featured add-ons</a>?</li> <li> Do you want to <a href=\"%(search)s\">search for add-ons</a>? You may "
|
||||
"go to the <a href=\"%(search)s\">search page</a> or just use the search field above. </li> <li> If you prefer to start over, just go to the <a href=\"%(home)s\">add-ons front page</a>. </li> </ul>"
|
||||
msgstr ""
|
||||
|
@ -2336,8 +2333,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/collection_detail.html
|
||||
msgid ""
|
||||
"Add-ons that you mark as favorites using the <b>Add to Favorites</b> feature appear below. This collection is currently <b>private</b>, which means only you can see it. If you would like everyone "
|
||||
"to be able to see your favorites, click the button below to make it public."
|
||||
"Add-ons that you mark as favorites using the <b>Add to Favorites</b> feature appear below. This collection is currently <b>private</b>, which means only you can see it. If you would like everyone to"
|
||||
" be able to see your favorites, click the button below to make it public."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/collection_detail.html
|
||||
|
@ -2565,7 +2562,7 @@ msgstr "Koleksiyon Oluştur"
|
|||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/impala/collection_sidebar.html src/olympia/bandwagon/templates/bandwagon/includes/collection_sidebar.html
|
||||
msgid "Collections make it easy to keep track of favorite add-ons and share your perfectly customized browser with others."
|
||||
msgstr ""
|
||||
msgstr "Koleksiyonlar, sevilen eklentileri takip etmenizi ve kusursuzca özelleştirdiğiniz tarayıcınızı diğer kişiler ile paylaşmanızı kolaylaştırır."
|
||||
|
||||
#: src/olympia/bandwagon/templates/bandwagon/includes/addedit.html
|
||||
msgid "Collection Icon"
|
||||
|
@ -3001,8 +2998,8 @@ msgstr "Eklenti Uyumluluk Raporları"
|
|||
#: src/olympia/compat/templates/compat/reporter.html src/olympia/compat/templates/compat/reporter_detail.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<p> Reports submitted to us through the <a href=\"%(url_)s\">Add-on Compatibility Reporter</a> are collected here for developers to view. These reports help us determine which add-ons will need "
|
||||
"help supporting an upcoming Firefox version. </p>"
|
||||
"<p> Reports submitted to us through the <a href=\"%(url_)s\">Add-on Compatibility Reporter</a> are collected here for developers to view. These reports help us determine which add-ons will need help"
|
||||
" supporting an upcoming Firefox version. </p>"
|
||||
msgstr ""
|
||||
"<p> <a href=\"%(url_)s\">Eklenti Uyumluluk Bildirici</a> aracılığıyla bize gönderilen raporlar geliştiricilerin değerlendirmesi için toplanır. Bu raporlar bize hangi eklentilerin gelecek Firefox "
|
||||
"sürümünü destekleyeceğine karar vermemize yardımcı olur. </p>"
|
||||
|
@ -3650,7 +3647,7 @@ msgstr "Fotoğraflar ve Medya"
|
|||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "RSS, News and Blogging"
|
||||
msgstr ""
|
||||
msgstr "RSS, Haberler ve Bloglar"
|
||||
|
||||
#: src/olympia/constants/categories.py
|
||||
msgid "Site-specific"
|
||||
|
@ -3818,9 +3815,8 @@ msgid "Slug incorrect."
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
#, fuzzy
|
||||
msgid "Invalid JSON object"
|
||||
msgstr "Geçersiz JWT jetonu."
|
||||
msgstr "Geçersiz JSON nesnesi"
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
msgid "Message not eligible for annotation"
|
||||
|
@ -3843,21 +3839,18 @@ msgid "License text is required when choosing Other."
|
|||
msgstr "Diğer seçeneği seçildiğinde sözleşme metni girilmesi gerekir."
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
#, fuzzy
|
||||
msgid "This add-on has an End-User License Agreement"
|
||||
msgstr "Son Kullanıcı İzin Anlaşmasına Bak"
|
||||
msgstr "Bu sözleşmenin bir Son Kullanıcı İzin Sözleşmesi var"
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
#, fuzzy
|
||||
msgid "Please specify your add-on's End-User License Agreement:"
|
||||
msgstr "Son Kullanıcı İzin Anlaşmasına Bak"
|
||||
msgstr "Eklentinizin Son Kullanıcı İzin Sözleşmesi'ni belirtin:"
|
||||
|
||||
# 89%
|
||||
# 100%
|
||||
#: src/olympia/devhub/forms.py
|
||||
#, fuzzy
|
||||
msgid "This add-on has a Privacy Policy"
|
||||
msgstr "Gizlilik Politikasını İncele"
|
||||
msgstr "Bu eklentinin Gizlilik Kuralları var"
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
msgid "Please specify your add-on's Privacy Policy:"
|
||||
|
@ -3998,8 +3991,7 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/forms.py
|
||||
msgid ""
|
||||
"On your own. <span class=\"helptext\">Your submission will be immediately signed for self-distribution. Updates should be handled by you via an updateURL or external application updates.</span>"
|
||||
msgid "On your own. <span class=\"helptext\">Your submission will be immediately signed for self-distribution. Updates should be handled by you via an updateURL or external application updates.</span>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/helpers.py
|
||||
|
@ -4100,11 +4092,11 @@ msgstr "Eklenti silindi."
|
|||
|
||||
#: src/olympia/devhub/views.py
|
||||
msgid "URL name was incorrect. Theme was not deleted."
|
||||
msgstr ""
|
||||
msgstr "URL adı yanlış. Tema silinmedi."
|
||||
|
||||
#: src/olympia/devhub/views.py
|
||||
msgid "URL name was incorrect. Add-on was not deleted."
|
||||
msgstr ""
|
||||
msgstr "URL adı yanlış. Eklenti silinmedi."
|
||||
|
||||
#: src/olympia/devhub/views.py
|
||||
msgid "An author has been added to your add-on"
|
||||
|
@ -4157,7 +4149,7 @@ msgstr "Bu isim kullanılamaz."
|
|||
#: src/olympia/devhub/views.py
|
||||
#, python-format
|
||||
msgid "Images cannot be larger than %dKB."
|
||||
msgstr ""
|
||||
msgstr "Resimler %d KB'den büyük olamaz."
|
||||
|
||||
#. L10n: {0} is an image width (in pixels), {1} is a height.
|
||||
#: src/olympia/devhub/views.py
|
||||
|
@ -4258,7 +4250,7 @@ msgstr "Arama Sonuçları"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/devhub_search.html
|
||||
msgid "Please enter some search terms."
|
||||
msgstr ""
|
||||
msgstr "Lütfen bazı arama terimleri girin."
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/devhub_search.html
|
||||
msgid "Loading results…"
|
||||
|
@ -4288,9 +4280,9 @@ msgstr "Koleksiyonlar hakkında bilgi edinin"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/index-legacy.html
|
||||
msgid ""
|
||||
"Add-ons let millions of Firefox users enhance and customize their browsing experience. If you're a Web developer and know <a href=\"https://developer.mozilla.org/docs/Web/HTML\">HTML</a>, <a href="
|
||||
"\"https://developer.mozilla.org/docs/Web/JavaScript\">JavaScript</a>, and <a href=\"https://developer.mozilla.org/docs/Web/CSS\">CSS</a>, you already have all the necessary skills to make a great "
|
||||
"add-on."
|
||||
"Add-ons let millions of Firefox users enhance and customize their browsing experience. If you're a Web developer and know <a href=\"https://developer.mozilla.org/docs/Web/HTML\">HTML</a>, <a "
|
||||
"href=\"https://developer.mozilla.org/docs/Web/JavaScript\">JavaScript</a>, and <a href=\"https://developer.mozilla.org/docs/Web/CSS\">CSS</a>, you already have all the necessary skills to make a "
|
||||
"great add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/index-legacy.html
|
||||
|
@ -4493,9 +4485,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_error.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<a href=\"#\" class=\"button compat-update\" data-updateurl=\"%(update_url)s\">Update Compatibility</a> <a href=\"%(version_url)s\" class=\"button\">Upload New Version</a> or <a href=\"#\" class="
|
||||
"\"close\">Ignore</a>"
|
||||
msgid "<a href=\"#\" class=\"button compat-update\" data-updateurl=\"%(update_url)s\">Update Compatibility</a> <a href=\"%(version_url)s\" class=\"button\">Upload New Version</a> or <a href=\"#\" class=\"close\">Ignore</a>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_status.html
|
||||
|
@ -4522,7 +4512,7 @@ msgstr "Desteklenen sürümler"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_update.html src/olympia/devhub/templates/devhub/versions/edit.html
|
||||
msgid "Add Another Application…"
|
||||
msgstr ""
|
||||
msgstr "Başka bir uygulama ekle …"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/ajax_compat_update.html src/olympia/devhub/templates/devhub/addons/listing/delete_form.html src/olympia/devhub/templates/devhub/addons/owner.html
|
||||
#: src/olympia/devhub/templates/devhub/versions/list.html src/olympia/templates/impala/base.html
|
||||
|
@ -4667,8 +4657,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Categories cannot be changed while your add-on is featured for this application. Please email <a href=\"mailto:%(email)s\">%(email)s</a> if there is a reason you need to modify your categories."
|
||||
msgid "Categories cannot be changed while your add-on is featured for this application. Please email <a href=\"mailto:%(email)s\">%(email)s</a> if there is a reason you need to modify your categories."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/basic.html
|
||||
|
@ -4740,8 +4729,8 @@ msgstr "{0} Eklenti Bilgileri"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/support.html
|
||||
msgid ""
|
||||
"If you wish to display an e-mail address for support inquiries, enter it here. If you have different addresses for each language multiple translations of this field can be added. It is only "
|
||||
"relevant for listed add-ons."
|
||||
"If you wish to display an e-mail address for support inquiries, enter it here. If you have different addresses for each language multiple translations of this field can be added. It is only relevant"
|
||||
" for listed add-ons."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/edit/support.html
|
||||
|
@ -5123,10 +5112,9 @@ msgstr "<b>Sıra:</b> %(pos)s / %(total)s"
|
|||
|
||||
#. {0} is the number of active users.
|
||||
#: src/olympia/devhub/templates/devhub/addons/listing/macros.html
|
||||
#, fuzzy
|
||||
msgid "<strong>{0}</strong> active user"
|
||||
msgid_plural "<strong>{0}</strong> active users"
|
||||
msgstr[0] "<strong>{0}</strong> kullanıcı"
|
||||
msgstr[0] "<strong>{0}</strong> etkin kullanıcı"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/base.html
|
||||
#, fuzzy
|
||||
|
@ -5172,9 +5160,8 @@ msgid "Check this option if your add-on is experimental or otherwise not ready f
|
|||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/describe.html
|
||||
#, fuzzy
|
||||
msgid "Support email:"
|
||||
msgstr "E-posta desteği"
|
||||
msgstr "Destek e-postası:"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/addons/submit/describe.html
|
||||
#, fuzzy
|
||||
|
@ -5391,8 +5378,8 @@ msgstr "JWT sırrı"
|
|||
#: src/olympia/devhub/templates/devhub/api/key.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"To make API requests, send a <a href=\"%(jwt_url)s\">JSON Web Token (JWT)</a> as the authorization header. You'll need to generate a JWT for every request as explained in the <a href=\"%(docs_url)s"
|
||||
"\">API documentation</a>."
|
||||
"To make API requests, send a <a href=\"%(jwt_url)s\">JSON Web Token (JWT)</a> as the authorization header. You'll need to generate a JWT for every request as explained in the <a "
|
||||
"href=\"%(docs_url)s\">API documentation</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/api/key.html
|
||||
|
@ -5544,9 +5531,8 @@ msgid "{0} success reports"
|
|||
msgstr "{0} başarı raporu"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/includes/blog_posts.html
|
||||
#, fuzzy
|
||||
msgid "Developer News"
|
||||
msgstr "Geliştirici"
|
||||
msgstr "Geliştirici Haberleri"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/includes/blog_posts.html
|
||||
msgid "View the blog ►"
|
||||
|
@ -5620,7 +5606,7 @@ msgstr "Eklentiler"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/blog_posts.html
|
||||
msgid "Latest News"
|
||||
msgstr ""
|
||||
msgstr "Son Haberler"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/blog_posts.html
|
||||
msgid "Read more in our Blog"
|
||||
|
@ -5656,9 +5642,8 @@ msgid "Blog"
|
|||
msgstr "Blog"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
msgid "Contact Us"
|
||||
msgstr "Kişiler"
|
||||
msgstr "Bize Ulaşın"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/footer.html
|
||||
#, fuzzy
|
||||
|
@ -5828,14 +5813,12 @@ msgid "Docs"
|
|||
msgstr "Belgeler"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/navigation.html
|
||||
#, fuzzy
|
||||
msgid "Sign Out"
|
||||
msgstr "Giriş yap"
|
||||
msgstr "Çıkış yap"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/navigation.html
|
||||
#, fuzzy
|
||||
msgid "User Photo"
|
||||
msgstr "Kullanıcı fotoğrafını sil"
|
||||
msgstr "Kullanıcı Fotoğrafı"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/navigation.html
|
||||
#, fuzzy, python-format
|
||||
|
@ -5850,8 +5833,8 @@ msgstr "Firefox için kullanımı kolay temalar"
|
|||
#: src/olympia/devhub/templates/devhub/new-landing/components/overview.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons let millions of Firefox users enhance their browsing experience. If you know <a href=\"%(html_link)s\">HTML</a>, <a href=\"%(js_link)s\">JavaScript</a>, and <a href=\"%(css_link)s\">CSS</"
|
||||
"a>, you already have all the necessary skills to make a great add-on."
|
||||
"Add-ons let millions of Firefox users enhance their browsing experience. If you know <a href=\"%(html_link)s\">HTML</a>, <a href=\"%(js_link)s\">JavaScript</a>, and <a href=\"%(css_link)s\">CSS</a>,"
|
||||
" you already have all the necessary skills to make a great add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/new-landing/components/overview.html
|
||||
|
@ -5997,7 +5980,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/payments/voluntary.html
|
||||
msgid "Sign up for PayPal"
|
||||
msgstr ""
|
||||
msgstr "PayPal'a kaydolun"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/payments/voluntary.html
|
||||
#, fuzzy
|
||||
|
@ -6006,7 +5989,7 @@ msgstr "Önerilen tek seferlik bağış miktarı: {0}"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/payments/voluntary.html
|
||||
msgid "(Example: 3.99)"
|
||||
msgstr ""
|
||||
msgstr "(Örnek: 3.99)"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/payments/voluntary.html
|
||||
msgid "When should users be asked for contributions?"
|
||||
|
@ -6102,8 +6085,8 @@ msgstr "Lisans sahibi; bu çalışmayı temel alacak çalışmaların yalnızca
|
|||
#: src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "The licensor permits others to copy, distribute and transmit only unaltered copies of the work — not derivative works based on it."
|
||||
msgstr ""
|
||||
"Lisans sahibi; bu çalışmanın yalnızca değiştirilmemiş halinin başkaları tarafından kopyalanmasına, dağıtılmasına, sergilenmesine ve uygulanmasına izin veriyor; çalışmayı temel alan başka "
|
||||
"çalışmalara izin vermiyor."
|
||||
"Lisans sahibi; bu çalışmanın yalnızca değiştirilmemiş halinin başkaları tarafından kopyalanmasına, dağıtılmasına, sergilenmesine ve uygulanmasına izin veriyor; çalışmayı temel alan başka çalışmalara"
|
||||
" izin vermiyor."
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/personas/edit.html src/olympia/devhub/templates/devhub/personas/submit.html
|
||||
msgid "Your Theme will be released under the following license:"
|
||||
|
@ -6413,7 +6396,7 @@ msgstr "Simge"
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/versions/list.html
|
||||
msgid "Leave a reply"
|
||||
msgstr ""
|
||||
msgstr "Yanıt yaz"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/versions/list.html src/olympia/reviews/templates/reviews/reply.html
|
||||
msgid "Reply"
|
||||
|
@ -6518,7 +6501,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/devhub/templates/devhub/versions/list.html
|
||||
msgid "Are you sure you wish to hide your add-on?"
|
||||
msgstr ""
|
||||
msgstr "Eklentinizi gizlemek istediğinizden emin misiniz?"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/versions/list.html
|
||||
msgid "Canceling your review request will mark your add-on incomplete, and any versions awaiting review will be disabled."
|
||||
|
@ -6711,10 +6694,9 @@ msgid "[status:%s]"
|
|||
msgstr "[durum:%s]"
|
||||
|
||||
#: src/olympia/editors/helpers.py
|
||||
#, fuzzy
|
||||
msgid "New Add-on ({0})"
|
||||
msgid_plural "New Add-ons ({0})"
|
||||
msgstr[0] "Eklenti İnceleme Süreci"
|
||||
msgstr[0] "Yeni Eklentiler ({0})"
|
||||
|
||||
#: src/olympia/editors/helpers.py
|
||||
#, fuzzy
|
||||
|
@ -8042,7 +8024,7 @@ msgstr "Video"
|
|||
|
||||
#: src/olympia/legacy_discovery/templates/legacy_discovery/pane.html
|
||||
msgid "While the video plays, the add-ons being mentioned will appear here."
|
||||
msgstr ""
|
||||
msgstr "Video oynarken ilgili eklentiler burada görünecektir."
|
||||
|
||||
#. {0} is the user's login name.
|
||||
#: src/olympia/legacy_discovery/templates/legacy_discovery/pane_account.html
|
||||
|
@ -8053,7 +8035,7 @@ msgstr "{0} koleksiyonunu düzenle"
|
|||
#: src/olympia/legacy_discovery/templates/legacy_discovery/pane_account.html
|
||||
#, python-format
|
||||
msgid "Thanks for using %(app)s and supporting <a href=\"%(url)s\">Mozilla's mission</a>!"
|
||||
msgstr ""
|
||||
msgstr "%(app)s kullanarak <a href=\"%(url)s\">Mozilla'nın misyonunu</a> desteklediğiniz için teşekkürler!"
|
||||
|
||||
#: src/olympia/legacy_discovery/templates/legacy_discovery/pane_account.html
|
||||
msgid "Add-ons downloaded:"
|
||||
|
@ -8095,7 +8077,7 @@ msgstr "Birleşik Arap Emirlikleri Dirhemi"
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Afghanistan Afghani"
|
||||
msgstr ""
|
||||
msgstr "Afganistan Afganisi"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Albania Lek"
|
||||
|
@ -8123,11 +8105,11 @@ msgstr "Avustralya Doları"
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Aruba Guilder"
|
||||
msgstr ""
|
||||
msgstr "Aruba Florini"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Azerbaijan New Manat"
|
||||
msgstr ""
|
||||
msgstr "Azerbaycan Manatı"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Bosnia and Herzegovina Convertible Marka"
|
||||
|
@ -8195,7 +8177,7 @@ msgstr "Kanada Doları"
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Congo/Kinshasa Franc"
|
||||
msgstr ""
|
||||
msgstr "Kongo/Kinşasa Frangı"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Switzerland Franc"
|
||||
|
@ -8272,15 +8254,15 @@ msgstr "Fiji Doları"
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Falkland Islands (Malvinas) Pound"
|
||||
msgstr ""
|
||||
msgstr "Falkland Adaları (Malvinas) Poundu"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "United Kingdom Pound"
|
||||
msgstr ""
|
||||
msgstr "İngiliz Sterlini"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Georgia Lari"
|
||||
msgstr ""
|
||||
msgstr "Gürcistan Larisi"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Guernsey Pound"
|
||||
|
@ -8288,15 +8270,15 @@ msgstr ""
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Ghana Cedi"
|
||||
msgstr ""
|
||||
msgstr "Gana Cedisi"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Gibraltar Pound"
|
||||
msgstr ""
|
||||
msgstr "Cebelitarık Poundu"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Gambia Dalasi"
|
||||
msgstr ""
|
||||
msgstr "Gambiya Dalasi"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Guinea Franc"
|
||||
|
@ -8336,7 +8318,7 @@ msgstr "Endonezya Rupisi"
|
|||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Israel Shekel"
|
||||
msgstr ""
|
||||
msgstr "İsrail Şekeli"
|
||||
|
||||
#: src/olympia/lib/constants.py
|
||||
msgid "Isle of Man Pound"
|
||||
|
@ -8818,8 +8800,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Help improve this website. It's open source, and you can file bugs and submit patches. <a href=\"%(url)s\"> GitHub</a> contains all of our current bugs, legacy bugs can still be found in Bugzilla."
|
||||
msgid "Help improve this website. It's open source, and you can file bugs and submit patches. <a href=\"%(url)s\"> GitHub</a> contains all of our current bugs, legacy bugs can still be found in Bugzilla."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
|
@ -8846,9 +8827,7 @@ msgstr "Geliştiriciye soru sorun"
|
|||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"A good place to start is our <a href=\"%(faq_url)s\"><abbr title=\"Frequently Asked Questions\">FAQ</abbr></a>. If you don't find an answer there, you can <a href=\"%(forum_url)s\"> ask on our "
|
||||
"forums</a>."
|
||||
msgid "A good place to start is our <a href=\"%(faq_url)s\"><abbr title=\"Frequently Asked Questions\">FAQ</abbr></a>. If you don't find an answer there, you can <a href=\"%(forum_url)s\"> ask on our forums</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
|
@ -8863,8 +8842,8 @@ msgstr "Bu sitede kim çalışıyor?"
|
|||
#: src/olympia/pages/templates/pages/about.lhtml
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Over the years, many people have contributed to this website, including both volunteers from the community and a dedicated AMO team. A list of significant contributors can be found on our <a href="
|
||||
"\"%(url)s\"> Site Credits</a> page."
|
||||
"Over the years, many people have contributed to this website, including both volunteers from the community and a dedicated AMO team. A list of significant contributors can be found on our <a "
|
||||
"href=\"%(url)s\"> Site Credits</a> page."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/acr_firstrun.html
|
||||
|
@ -9101,8 +9080,8 @@ msgstr "\"install.rdf\" dosyası ne için kullanılır?"
|
|||
#, python-format
|
||||
msgid ""
|
||||
"This file, called an <a href=\"%(url)s\">Install Manifest</a>, is used by Add-on Manager-enabled XUL applications to determine information about an add-on as it is being installed. It contains "
|
||||
"metadata identifying the add-on, providing information about who created it, where more information can be found about it, which versions of what applications it is compatible with, how it should "
|
||||
"be updated, and so on. The format of the Install Manifest is RDF/XML."
|
||||
"metadata identifying the add-on, providing information about who created it, where more information can be found about it, which versions of what applications it is compatible with, how it should be"
|
||||
" updated, and so on. The format of the Install Manifest is RDF/XML."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9150,9 +9129,9 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"To ensure compatibility with the latest Mozilla software, it's important to download updates as they become available and test your add-on to ensure that it is still functioning as expected. In "
|
||||
"many cases, the latest version of Mozilla software may be a beta release. Since these releases at times introduce architectural changes that may impact the functionality of your add-on, it's "
|
||||
"important to be actively involved in the beta process to ensure that your add-on users are not negatively impacted upon final release of Mozilla software."
|
||||
"To ensure compatibility with the latest Mozilla software, it's important to download updates as they become available and test your add-on to ensure that it is still functioning as expected. In many"
|
||||
" cases, the latest version of Mozilla software may be a beta release. Since these releases at times introduce architectural changes that may impact the functionality of your add-on, it's important "
|
||||
"to be actively involved in the beta process to ensure that your add-on users are not negatively impacted upon final release of Mozilla software."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9162,8 +9141,8 @@ msgstr "Eklentimin başarımını nasıl artırabilirim?"
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Poorly written extensions can have a severe impact on the browsing experience, including on the overall performance of Firefox itself. The following page contains many good <a href=\"%(url)s"
|
||||
"\">guides</a> that help you improve performance, whether you're developing core Mozilla code or an add-on."
|
||||
"Poorly written extensions can have a severe impact on the browsing experience, including on the overall performance of Firefox itself. The following page contains many good <a "
|
||||
"href=\"%(url)s\">guides</a> that help you improve performance, whether you're developing core Mozilla code or an add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9239,8 +9218,8 @@ msgstr "Eklentimi geliştirmek için tutabileceğim 3. şahıs geliştiriciler v
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Yes. You may find 3rd party developers via the <a href=\"%(forum_url)s\">Add-ons forum</a>, <a href=\"%(list_url)s\">mozilla.jobs list</a>, <a href=\"%(mz_url)s\">mozillaZine forums</a> or <a href="
|
||||
"\"%(wiki_url)s\">the Mozilla Wiki</a>. Please note that Mozilla does not offer developer recommendations."
|
||||
"Yes. You may find 3rd party developers via the <a href=\"%(forum_url)s\">Add-ons forum</a>, <a href=\"%(list_url)s\">mozilla.jobs list</a>, <a href=\"%(mz_url)s\">mozillaZine forums</a> or <a "
|
||||
"href=\"%(wiki_url)s\">the Mozilla Wiki</a>. Please note that Mozilla does not offer developer recommendations."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9331,8 +9310,8 @@ msgstr "Eklentim için hangi kategoriyi seçmeliyim?"
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"The choice of category is dependent on what type of audience you are targeting and the functionality of your add-on. If you're unsure of which category your add-on falls into, please choose \"Other"
|
||||
"\". The AMO team may re-categorize your add-on if it's determined that it's better suited in a different category."
|
||||
"The choice of category is dependent on what type of audience you are targeting and the functionality of your add-on. If you're unsure of which category your add-on falls into, please choose "
|
||||
"\"Other\". The AMO team may re-categorize your add-on if it's determined that it's better suited in a different category."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9371,9 +9350,9 @@ msgstr "Bu eklentinin %(cnt)s incelemesinin tümünü göster"
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons are reviewed by the Add-on Reviewers, a group of talented developers that volunteer to help the Mozilla project by reviewing add-ons to ensure a stable and safe experience for Mozilla "
|
||||
"users. When communicating with reviewer, please be courteous, patient and respectful as they are working hard to ensure that your add-on is set up correctly and follows the guidelines outlined in "
|
||||
"the <a href=\"%(url)s\">Add-on Review Guide</a>."
|
||||
"Add-ons are reviewed by the Add-on Reviewers, a group of talented developers that volunteer to help the Mozilla project by reviewing add-ons to ensure a stable and safe experience for Mozilla users."
|
||||
" When communicating with reviewer, please be courteous, patient and respectful as they are working hard to ensure that your add-on is set up correctly and follows the guidelines outlined in the <a "
|
||||
"href=\"%(url)s\">Add-on Review Guide</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9413,8 +9392,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This is why it's very important to read the <a href=\"%(g_url)s\">Add-on Review Guide</a> to ensure that your add-on is setup as expected. It's also a good idea to read the blog post, <a href="
|
||||
"\"%(blog_url)s\">Successfully Getting your Add-on Reviewed</a> which provides excellent insight into ensuring a smooth review of your add-on."
|
||||
"This is why it's very important to read the <a href=\"%(g_url)s\">Add-on Review Guide</a> to ensure that your add-on is setup as expected. It's also a good idea to read the blog post, <a "
|
||||
"href=\"%(blog_url)s\">Successfully Getting your Add-on Reviewed</a> which provides excellent insight into ensuring a smooth review of your add-on."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9502,10 +9481,10 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
msgid ""
|
||||
"Do you need more information about the various open source licenses? Are you confused as to which license you should select? What rights does a specific license grant? While nothing replaces "
|
||||
"reading the full terms of a license, below are some sites that contain information about some of the key open source licenses that may help you sort out the differences between them. These sites "
|
||||
"are being provided solely for your convenience and as a reference for your personal use. These resources do not constitute legal advice nor should they be used in lieu of such advice. Mozilla "
|
||||
"neither guarantees nor is responsible for the content of these sites or your reliance on such content."
|
||||
"Do you need more information about the various open source licenses? Are you confused as to which license you should select? What rights does a specific license grant? While nothing replaces reading"
|
||||
" the full terms of a license, below are some sites that contain information about some of the key open source licenses that may help you sort out the differences between them. These sites are being "
|
||||
"provided solely for your convenience and as a reference for your personal use. These resources do not constitute legal advice nor should they be used in lieu of such advice. Mozilla neither "
|
||||
"guarantees nor is responsible for the content of these sites or your reliance on such content."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/dev_faq.html
|
||||
|
@ -9565,9 +9544,10 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons listed in this gallery only work with Mozilla-based applications, such as <a href=\"%(getfirefox_url)s\">Firefox</a>, <a href=\"%(getmobile_url)s\">Firefox Mobile</a>, <a href="
|
||||
"\"%(getseamonkey_url)s\">SeaMonkey</a>, and <a href=\"%(getthunderbird_url)s\">Thunderbird</a>. However, not all add-ons work with each of those applications or every version of those applications. "
|
||||
"Each add-on specifies which applications and versions it works with, such as Firefox 2.0 - 3.6.*. For Firefox add-ons, the install buttons will indicate whether the add-on is compatible or not."
|
||||
"Add-ons listed in this gallery only work with Mozilla-based applications, such as <a href=\"%(getfirefox_url)s\">Firefox</a>, <a href=\"%(getmobile_url)s\">Firefox Mobile</a>, <a "
|
||||
"href=\"%(getseamonkey_url)s\">SeaMonkey</a>, and <a href=\"%(getthunderbird_url)s\">Thunderbird</a>. However, not all add-ons work with each of those applications or every version of those "
|
||||
"applications. Each add-on specifies which applications and versions it works with, such as Firefox 2.0 - 3.6.*. For Firefox add-ons, the install buttons will indicate whether the add-on is "
|
||||
"compatible or not."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9630,8 +9610,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"In Firefox, add-ons marked with \"No restart required\" can be installed without restarting. These add-ons have been created using the <a href=\"%(sdk_url)s\">Add-on SDK</a> or <a href="
|
||||
"\"%(bootstrap_url)s\">bootstrapping</a>. Other add-ons will still require a restart before you can use them."
|
||||
"In Firefox, add-ons marked with \"No restart required\" can be installed without restarting. These add-ons have been created using the <a href=\"%(sdk_url)s\">Add-on SDK</a> or <a "
|
||||
"href=\"%(bootstrap_url)s\">bootstrapping</a>. Other add-ons will still require a restart before you can use them."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9642,20 +9622,20 @@ msgstr ""
|
|||
#, python-format
|
||||
msgid ""
|
||||
"Add-ons, unlike plugins, are automatically checked for updates once every day. In Firefox, updates are automatically installed by default. Versions of Firefox prior to 4 (and other applications) "
|
||||
"will alert you that updates to your add-ons are available. <a href=\"%(plugin_url)s\">Plugins</a> are not currently automatically checked for updates, so be sure to regularly visit the <a href="
|
||||
"\"%(plugincheck_url)s\">Plugin Check</a> page to stay up-to-date."
|
||||
"will alert you that updates to your add-ons are available. <a href=\"%(plugin_url)s\">Plugins</a> are not currently automatically checked for updates, so be sure to regularly visit the <a "
|
||||
"href=\"%(plugincheck_url)s\">Plugin Check</a> page to stay up-to-date."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
msgid "Are add-ons safe to install?"
|
||||
msgstr ""
|
||||
msgstr "Eklentileri güvenle yükleyebilir miyim?"
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Unless clearly marked otherwise, add-ons available from this gallery have been checked and approved by Mozilla's team of editors and are safe to install. We recommend that you only install approved "
|
||||
"add-ons. If you wish to install unapproved add-ons or add-ons from third-party websites, use caution as these add-ons may harm your computer or violate your privacy. <a href=\"%(learnmore_url)s"
|
||||
"\">Learn more about our approval process</a>"
|
||||
"add-ons. If you wish to install unapproved add-ons or add-ons from third-party websites, use caution as these add-ons may harm your computer or violate your privacy. <a "
|
||||
"href=\"%(learnmore_url)s\">Learn more about our approval process</a>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9740,8 +9720,8 @@ msgstr ""
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"While all add-ons publicly available in our gallery are reviewed by an editor, you may receive a direct link to an add-on that hasn't yet been reviewed. Use caution when installing these add-ons, "
|
||||
"as they could harm your computer or violate your privacy. We recommend that you only install reviewed add-ons. <a href=\"%(url)s\">Learn more about our review process</a></dd>"
|
||||
"While all add-ons publicly available in our gallery are reviewed by an editor, you may receive a direct link to an add-on that hasn't yet been reviewed. Use caution when installing these add-ons, as"
|
||||
" they could harm your computer or violate your privacy. We recommend that you only install reviewed add-ons. <a href=\"%(url)s\">Learn more about our review process</a></dd>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9769,8 +9749,8 @@ msgstr "Koleksiyon nedir?"
|
|||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
msgid ""
|
||||
"Beta add-ons are unreviewed versions which represent the latest work of an add-on author. While different authors have different standards for beta code quality, you should assume that these add-"
|
||||
"ons are less stable than the general add-on releases."
|
||||
"Beta add-ons are unreviewed versions which represent the latest work of an add-on author. While different authors have different standards for beta code quality, you should assume that these add-ons"
|
||||
" are less stable than the general add-on releases."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9814,9 +9794,9 @@ msgstr "Kaynak Kodu Lisansı"
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The source code used to create an add-on is an exclusive copyright of the add-on author, unless otherwise declared in a source code license. Many add-ons on this site have <a href=\"%(url)s\" lang="
|
||||
"\"en\">open source licenses</a> that make the source code publicly available for copy and reuse under conditions determined by the author. Most authors choose widely known open source licenses like "
|
||||
"the GPL or BSD licenses instead of making up their own."
|
||||
"The source code used to create an add-on is an exclusive copyright of the add-on author, unless otherwise declared in a source code license. Many add-ons on this site have <a href=\"%(url)s\" "
|
||||
"lang=\"en\">open source licenses</a> that make the source code publicly available for copy and reuse under conditions determined by the author. Most authors choose widely known open source licenses "
|
||||
"like the GPL or BSD licenses instead of making up their own."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9863,8 +9843,8 @@ msgstr "Koleksiyon nedir?"
|
|||
#: src/olympia/pages/templates/pages/faq.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Mobile add-ons work with <a href=\"%(mobile_url)s\">Firefox for Mobile</a> and add or modify functionality just like desktop add-ons. You can find add-ons that work with Firefox for Mobile in our "
|
||||
"<a href=\"%(gallery_url)s\">gallery</a>."
|
||||
"Mobile add-ons work with <a href=\"%(mobile_url)s\">Firefox for Mobile</a> and add or modify functionality just like desktop add-ons. You can find add-ons that work with Firefox for Mobile in our <a"
|
||||
" href=\"%(gallery_url)s\">gallery</a>."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/faq.html
|
||||
|
@ -9896,8 +9876,8 @@ msgstr ""
|
|||
|
||||
#: src/olympia/pages/templates/pages/review_guide.html
|
||||
msgid ""
|
||||
"Add-on reviews are a way for you to share your opinions about the add-ons you’ve installed and used. Our review moderation team reserves the right to refuse or remove any review that does not "
|
||||
"comply with these guidelines."
|
||||
"Add-on reviews are a way for you to share your opinions about the add-ons you’ve installed and used. Our review moderation team reserves the right to refuse or remove any review that does not comply"
|
||||
" with these guidelines."
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/pages/templates/pages/review_guide.html
|
||||
|
@ -10082,7 +10062,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/reviews/forms.py
|
||||
msgid "Skip for now"
|
||||
msgstr ""
|
||||
msgstr "Şimdilik geç"
|
||||
|
||||
#: src/olympia/reviews/forms.py src/olympia/reviews/templates/reviews/review.html
|
||||
#, fuzzy
|
||||
|
@ -10091,7 +10071,7 @@ msgstr "İnceleme yazın"
|
|||
|
||||
#: src/olympia/reviews/models.py
|
||||
msgid "Other (please specify)"
|
||||
msgstr ""
|
||||
msgstr "Diğer (lütfen belirtin)"
|
||||
|
||||
#: src/olympia/reviews/views.py
|
||||
msgid "Thanks; this review has been flagged for editor approval."
|
||||
|
@ -10110,10 +10090,10 @@ msgstr "{0} Eklentileri"
|
|||
msgid ""
|
||||
"<h2>Keep these tips in mind:</h2> <ul> <li> Write like you're telling a friend about your experience with the add-on. Give specifics and helpful details, such as what features you liked and/or "
|
||||
"disliked, how easy to use it is, and any disadvantages it has. Avoid generic language such as calling it \"Great\" or \"Bad\" unless you can give reasons why you believe this is so. </li> <li> "
|
||||
"Please do not post bug reports here. We do not make your email address available to add-on developers, so they can't contact you to resolve your issue. See this add-on's <a href=\"%(support)s"
|
||||
"\">support section</a> to find out if assistance is available. You can also try asking the <a href=\"https://discourse.mozilla-community.org/c/add-ons/add-on-support\">add-on community</a> for "
|
||||
"help. </li> <li>Please keep reviews clean, avoid the use of improper language and do not post any personal information. </li> </ul> <p>Please read the <a href=\"%(guide)s\">Review Guidelines</a> "
|
||||
"for more detail about user add-on reviews.</p>"
|
||||
"Please do not post bug reports here. We do not make your email address available to add-on developers, so they can't contact you to resolve your issue. See this add-on's <a "
|
||||
"href=\"%(support)s\">support section</a> to find out if assistance is available. You can also try asking the <a href=\"https://discourse.mozilla-community.org/c/add-ons/add-on-support\">add-on "
|
||||
"community</a> for help. </li> <li>Please keep reviews clean, avoid the use of improper language and do not post any personal information. </li> </ul> <p>Please read the <a href=\"%(guide)s\">Review "
|
||||
"Guidelines</a> for more detail about user add-on reviews.</p>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/reviews/templates/reviews/reply.html
|
||||
|
@ -10391,7 +10371,7 @@ msgstr ""
|
|||
|
||||
#: src/olympia/search/templates/search/personas.html
|
||||
msgid "Themes Search Results"
|
||||
msgstr ""
|
||||
msgstr "Tema Arama Sonuçları"
|
||||
|
||||
#. {0} is a tag, such as jetpack.
|
||||
#: src/olympia/search/templates/search/results.html
|
||||
|
@ -10412,7 +10392,7 @@ msgstr[0] "<b>{0}</b> kullanıcı"
|
|||
|
||||
#: src/olympia/search/templates/search/results.html
|
||||
msgid "Filter Results"
|
||||
msgstr ""
|
||||
msgstr "Sonuçları filtrele"
|
||||
|
||||
#: src/olympia/search/templates/search/results.html
|
||||
#, fuzzy
|
||||
|
@ -10427,7 +10407,7 @@ msgstr "Etiketler"
|
|||
|
||||
#: src/olympia/search/templates/search/mobile/results.html
|
||||
msgid "Search Results <i>({num})</i>"
|
||||
msgstr ""
|
||||
msgstr "Arama Sonuçları <i>({num})</i>"
|
||||
|
||||
#: src/olympia/signing/views.py src/olympia/templates/base.html src/olympia/templates/impala/base.html
|
||||
#, fuzzy
|
||||
|
@ -10611,8 +10591,8 @@ msgstr ""
|
|||
msgid "Statistics Dashboard :: Add-ons for {0}"
|
||||
msgstr ""
|
||||
|
||||
# %1 is an add-on name.
|
||||
#. {0} is an add-on name
|
||||
# %1 is an add-on name.
|
||||
#: src/olympia/stats/templates/stats/stats.html
|
||||
#, fuzzy
|
||||
msgid "Statistics for {0}"
|
||||
|
@ -10823,11 +10803,11 @@ msgstr ""
|
|||
#: src/olympia/stats/templates/stats/reports/sources.html
|
||||
#, python-format
|
||||
msgid ""
|
||||
"<h2>Tracking external sources</h2> <p> If you link to your add-on's details page or directly to its file from an external site, such as your blog or website, you can append a parameter to be "
|
||||
"tracked as an additional download source on this page. For example, the following links would appear as sourced by your blog: <dl> <dt>Add-on Details Page</dt> <dd>https://addons.mozilla.org/addon/"
|
||||
"%(slug)s?src=<b>external-blog</b></dd> <dt>Direct File Link</dt> <dd>https://addons.mozilla.org/downloads/latest/%(id)s/addon-%(id)s-latest.xpi?src=<b>external-blog</b></dd> </dl> <p> Only src "
|
||||
"parameters that begin with \"external-\" will be tracked, up to 61 additional characters. Any text after \"external-\" can be used to describe the source, such as \"external-blog\", \"external-"
|
||||
"sidebar\", \"external-campaign225\", etc. The following URL-safe characters are allowed: <code>a-z A-Z - . _ ~ %% +</code>"
|
||||
"<h2>Tracking external sources</h2> <p> If you link to your add-on's details page or directly to its file from an external site, such as your blog or website, you can append a parameter to be tracked"
|
||||
" as an additional download source on this page. For example, the following links would appear as sourced by your blog: <dl> <dt>Add-on Details Page</dt> "
|
||||
"<dd>https://addons.mozilla.org/addon/%(slug)s?src=<b>external-blog</b></dd> <dt>Direct File Link</dt> <dd>https://addons.mozilla.org/downloads/latest/%(id)s/addon-%(id)s-latest.xpi?src=<b>external-"
|
||||
"blog</b></dd> </dl> <p> Only src parameters that begin with \"external-\" will be tracked, up to 61 additional characters. Any text after \"external-\" can be used to describe the source, such as "
|
||||
"\"external-blog\", \"external-sidebar\", \"external-campaign225\", etc. The following URL-safe characters are allowed: <code>a-z A-Z - . _ ~ %% +</code>"
|
||||
msgstr ""
|
||||
|
||||
#: src/olympia/stats/templates/stats/reports/statuses.html
|
||||
|
@ -11743,7 +11723,7 @@ msgstr "E-postaları göndermek yerine kaydet"
|
|||
|
||||
#: src/olympia/zadmin/forms.py
|
||||
msgid "Deleted versions can`t be changed."
|
||||
msgstr ""
|
||||
msgstr "Silinmiş sürümler değiştirilemez."
|
||||
|
||||
# Plural in this context means many of the add-on type
|
||||
# 75%
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2016-09-02 18:29+0000\n"
|
||||
"Last-Translator: burak <burak@buraksakalli.org>\n"
|
||||
"PO-Revision-Date: 2017-02-15 16:57+0000\n"
|
||||
"Last-Translator: Selim Şumlu <selim@sum.lu>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: tr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
@ -114,11 +114,11 @@ msgstr "Gönderiminiz otomatik olarak imzalanacak."
|
|||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "WebExtension upgrade"
|
||||
msgstr ""
|
||||
msgstr "WebExtension yükseltmesi"
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "We allow and encourage an upgrade but you cannot reverse this process. Once your users have the WebExtension installed, they will not be able to install a legacy add-on."
|
||||
msgstr ""
|
||||
msgstr "Yükseltmeye izin veriyoruz ve hatta öneriyoruz ama bu işlemi geri alamazsınız. Kullanıcılarınız WebExtension'ı yükledikten sonra eski nesil eklentiyi yükleyemezler."
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "Porting a legacy Firefox add-on on MDN"
|
||||
|
@ -145,8 +145,8 @@ msgid ""
|
|||
"Compiled binaries, as well as minified or obfuscated scripts (excluding known libraries) need to have their sources submitted separately for review. Make sure that you use the source code upload "
|
||||
"field to avoid having your submission rejected."
|
||||
msgstr ""
|
||||
"Derlenmiş ikililer, ayrıca küçültülmüş veya karartılmış betikler (bilinen kitaplıklar hariç) incelenecekse, bunların kendi kaynaklarının ayrı olarak bulunması gerekir. Başvurunuzun geri "
|
||||
"çevrilmesini önlemek adına, kaynak kodu gönderme sahasını kullandığınızdan emin olun."
|
||||
"Derlenmiş ikililer, ayrıca küçültülmüş veya karartılmış betikler (bilinen kitaplıklar hariç) incelenecekse, bunların kendi kaynaklarının ayrı olarak bulunması gerekir. Başvurunuzun geri çevrilmesini"
|
||||
" önlemek adına, kaynak kodu gönderme sahasını kullandığınızdan emin olun."
|
||||
|
||||
#: static/js/common/upload-addon.js
|
||||
msgid "The validation process found these issues that can lead to rejections:"
|
||||
|
@ -254,9 +254,8 @@ msgid "Search add-ons for <b>{0}</b>"
|
|||
msgstr "<b>{0}</b> için eklentileri ara"
|
||||
|
||||
#: static/js/impala/users.js
|
||||
#, fuzzy
|
||||
msgid "Use original"
|
||||
msgstr "orijinalini kullan"
|
||||
msgstr "Orijinalini kullan"
|
||||
|
||||
#: static/js/impala/stats/chart.js
|
||||
msgid "Week of {0}"
|
||||
|
@ -1029,11 +1028,11 @@ msgstr "Hiçbir sürüm notu bulunamadı"
|
|||
|
||||
#: static/js/zamboni/editors.js
|
||||
msgid "Review Text"
|
||||
msgstr ""
|
||||
msgstr "İnceleme Metni"
|
||||
|
||||
#: static/js/zamboni/editors.js
|
||||
msgid "Review notes found"
|
||||
msgstr ""
|
||||
msgstr "İnceleme notları bulundu"
|
||||
|
||||
#: static/js/zamboni/editors.js
|
||||
msgid "Average Reviews"
|
||||
|
@ -1041,7 +1040,7 @@ msgstr ""
|
|||
|
||||
#: static/js/zamboni/editors.js
|
||||
msgid "Number of Reviews"
|
||||
msgstr ""
|
||||
msgstr "İncelemelerin Sayısı"
|
||||
|
||||
#: static/js/zamboni/editors.js
|
||||
msgid "Error loading translation"
|
||||
|
@ -1112,7 +1111,7 @@ msgstr "Tema"
|
|||
|
||||
#: static/js/zamboni/themes_review_templates.js
|
||||
msgid "Reviewer"
|
||||
msgstr ""
|
||||
msgstr "İnceleyen"
|
||||
|
||||
#: static/js/zamboni/themes_review_templates.js
|
||||
msgid "Status"
|
||||
|
|
|
@ -4,7 +4,7 @@ msgstr ""
|
|||
"Project-Id-Version: addons-trunk // addons.mozilla.org\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2017-02-09 11:33+0000\n"
|
||||
"PO-Revision-Date: 2017-02-09 17:08+0000\n"
|
||||
"PO-Revision-Date: 2017-02-19 17:09+0000\n"
|
||||
"Last-Translator: Pin-guang Chen <petercpg@mail.moztw.org>\n"
|
||||
"Language-Team: Traditional Chinese (Taiwan) <LL@li.org>\n"
|
||||
"Language: zh_TW\n"
|
||||
|
@ -5341,7 +5341,7 @@ msgstr "移除這個應用程式"
|
|||
#: src/olympia/devhub/templates/devhub/includes/macros.html
|
||||
msgid "Select <b>up to {0}</b> {1} category for this add-on:"
|
||||
msgid_plural "Select <b>up to {0}</b> {1} categories for this add-on:"
|
||||
msgstr[0] "為這個附加元件選擇<b>最多 {0}</b> {1} 個分類:"
|
||||
msgstr[0] "為此附加元件選擇<b>最多 {0} 個</b> {1} 分類:"
|
||||
|
||||
#: src/olympia/devhub/templates/devhub/includes/policy_form.html
|
||||
msgid ""
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"dependencies": {
|
||||
"addons-linter": "0.15.15",
|
||||
"clean-css": "4.0.7",
|
||||
"clean-css-cli": "4.0.6",
|
||||
"clean-css-cli": "4.0.7",
|
||||
"less": "2.7.2",
|
||||
"stylus": "0.54.5",
|
||||
"uglify-js": "2.7.5"
|
||||
|
|
|
@ -172,9 +172,9 @@ django-waffle==0.11.1 \
|
|||
--hash=sha256:d135816e416c5846aff1928634513f89cc83af4e939e2007e4a9707ef20d7c02 \
|
||||
--hash=sha256:68d246e6f5562309f05c2743ae536b2569933e7d8ed65ecf3606e7a780968b68
|
||||
# djangorestframework is required by drf-nested-routers
|
||||
djangorestframework==3.5.3 \
|
||||
--hash=sha256:f446041a944723e14502a0a5880d0bc74a499ac1075781177f2fa6d7fe7b415d \
|
||||
--hash=sha256:7c04e2a45e6d30df7042749b9a029882c449eb2fee038f3cc14dfbc93581bfbf
|
||||
djangorestframework==3.5.4 \
|
||||
--hash=sha256:110afa12784ceadfb50808882689302d266785b51e3d13286744333ff6d78e60 \
|
||||
--hash=sha256:f995a35ae22f354d2a9a42ee6d2c059c101f826b1485ed46781677895ad25ee5
|
||||
djangorestframework-jwt==1.9.0 \
|
||||
--hash=sha256:c9fa3c1847569ac1c96d04c7fa38f8dacf894ab405d9e772f0776c4d57fa35ad \
|
||||
--hash=sha256:319fd2de82a798f46c03c0289e790f2ddbe65dbf7196ed46815225497606abb1
|
||||
|
@ -339,9 +339,9 @@ pytz==2016.10 \
|
|||
--hash=sha256:7016b2c4fa075c564b81c37a252a5fccf60d8964aa31b7f5eae59aeb594ae02b \
|
||||
--hash=sha256:9a43e20aa537cfad8fe7a1715165c91cb4a6935d40947f2d070e4c80f2dcd22b \
|
||||
--hash=sha256:aafbf066975fe217ed49d7d197b26903d3b43e9ca2aa6ba0a211081f13c41917
|
||||
raven==5.32.0 \
|
||||
--hash=sha256:a06517e9b7858ac41963f9741cc8358005d37511475aaa4c8b692d29ae0a7d94 \
|
||||
--hash=sha256:13e68bbf21d4d6f0cae4458da5be2d0d538733beabc5f93cb185048b28a77457
|
||||
raven==6.0.0 \
|
||||
--hash=sha256:c9b521eaa4f253b5ed96051ab8f7c8e61fe901f9fc18ee6d9ac99726fbcb14fe \
|
||||
--hash=sha256:cee2d745c762230383fc89365770552c93c71205ee92c6e6bbbd85fe4dbb2803
|
||||
# rdflib is required by amo-validator
|
||||
rdflib==3.4.0 \
|
||||
--hash=sha256:78d5f11a7001661d7637f9e61554a5f8971e197f3f6d17ba5e4039b0668116cf # pyup: ==3.4.0
|
||||
|
|
|
@ -109,10 +109,13 @@ class Update(object):
|
|||
sql = """SELECT id, status, addontype_id, guid FROM addons
|
||||
WHERE guid = %(guid)s AND
|
||||
inactive = 0 AND
|
||||
status != %(STATUS_DELETED)s
|
||||
status NOT IN (%(STATUS_DELETED)s, %(STATUS_DISABLED)s)
|
||||
LIMIT 1;"""
|
||||
self.cursor.execute(sql, {'guid': self.data['id'],
|
||||
'STATUS_DELETED': base.STATUS_DELETED})
|
||||
self.cursor.execute(sql, {
|
||||
'guid': self.data['id'],
|
||||
'STATUS_DELETED': base.STATUS_DELETED,
|
||||
'STATUS_DISABLED': base.STATUS_DISABLED,
|
||||
})
|
||||
result = self.cursor.fetchone()
|
||||
if result is None:
|
||||
return False
|
||||
|
@ -135,7 +138,6 @@ class Update(object):
|
|||
|
||||
data['STATUS_PUBLIC'] = base.STATUS_PUBLIC
|
||||
data['STATUS_BETA'] = base.STATUS_BETA
|
||||
data['STATUS_DISABLED'] = base.STATUS_DISABLED
|
||||
data['RELEASE_CHANNEL_LISTED'] = base.RELEASE_CHANNEL_LISTED
|
||||
|
||||
sql = ["""
|
||||
|
@ -355,7 +357,6 @@ def application(environ, start_response):
|
|||
output = force_bytes(update.get_rdf())
|
||||
start_response(status, update.get_headers(len(output)))
|
||||
except:
|
||||
#mail_exception(data)
|
||||
log_exception(data)
|
||||
raise
|
||||
return [output]
|
||||
|
|
|
@ -28,7 +28,6 @@ from olympia.lib.log_settings_base import formatters, handlers
|
|||
# remove all this.
|
||||
from olympia.constants.applications import APPS_ALL
|
||||
from olympia.constants.platforms import PLATFORMS
|
||||
from olympia.constants.base import STATUS_DISABLED
|
||||
|
||||
|
||||
# This is not DRY: it's a copy of amo.helpers.user_media_path, to avoid an
|
||||
|
|
11
settings.py
11
settings.py
|
@ -113,9 +113,18 @@ FXA_CONFIG = {
|
|||
'redirect_url': 'http://localhost:3000/fxa-authenticate',
|
||||
'scope': 'profile',
|
||||
},
|
||||
'local': {
|
||||
'client_id': '1778aef72d1adfb3',
|
||||
'client_secret':
|
||||
'3feebe3c009c1a0acdedd009f3530eae2b88859f430fa8bb951ea41f2f859b18',
|
||||
'content_host': 'https://stable.dev.lcip.org',
|
||||
'oauth_host': 'https://oauth-stable.dev.lcip.org/v1',
|
||||
'profile_host': 'https://stable.dev.lcip.org/profile/v1',
|
||||
'redirect_url': 'http://localhost:3000/api/v3/accounts/authenticate/',
|
||||
'scope': 'profile',
|
||||
},
|
||||
}
|
||||
FXA_CONFIG['amo'] = FXA_CONFIG['internal']
|
||||
FXA_CONFIG['local'] = FXA_CONFIG['internal']
|
||||
ALLOWED_FXA_CONFIGS = ['default', 'amo', 'local']
|
||||
|
||||
# CSP report endpoint which returns a 204 from addons-nginx in local dev.
|
||||
|
|
|
@ -507,6 +507,24 @@ class TestWithUser(TestCase):
|
|||
self.request, views.ERROR_STATE_MISMATCH, next_path='/next',
|
||||
format='json')
|
||||
|
||||
def test_dynamic_configuration(self):
|
||||
fxa_config = {'some': 'config'}
|
||||
|
||||
class LoginView(object):
|
||||
def get_fxa_config(self, request):
|
||||
return fxa_config
|
||||
|
||||
@views.with_user(format='json')
|
||||
def post(*args, **kwargs):
|
||||
return args, kwargs
|
||||
|
||||
identity = {'uid': '1234', 'email': 'hey@yo.it'}
|
||||
self.fxa_identify.return_value = identity
|
||||
self.find_user.return_value = self.user
|
||||
self.request.data = {'code': 'foo', 'state': 'some-blob'}
|
||||
LoginView().post(self.request)
|
||||
self.fxa_identify.assert_called_with('foo', config=fxa_config)
|
||||
|
||||
|
||||
class TestRegisterUser(TestCase):
|
||||
|
||||
|
@ -995,16 +1013,6 @@ class TestParseNextPath(TestCase):
|
|||
u'/en-US/firefox/addon/dęlîcíøùs-päñčåkę/?src=hp-dl-featured')
|
||||
|
||||
|
||||
class TestAccountViewSetGet(TestCase):
|
||||
def test_basic(self):
|
||||
self.user = user_factory()
|
||||
self.url = reverse(
|
||||
'account-detail', kwargs={'pk': self.user.pk})
|
||||
|
||||
with self.assertRaises(NotImplementedError):
|
||||
self.client.get(self.url)
|
||||
|
||||
|
||||
class TestSessionView(TestCase):
|
||||
def login_user(self, user):
|
||||
identity = {
|
||||
|
|
|
@ -1,23 +1,9 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.conf.urls import url
|
||||
|
||||
from rest_framework.routers import SimpleRouter
|
||||
from rest_framework_nested.routers import NestedSimpleRouter
|
||||
|
||||
from olympia.reviews.views import ReviewViewSet
|
||||
from . import views
|
||||
|
||||
|
||||
accounts = SimpleRouter()
|
||||
accounts.register(r'account', views.AccountViewSet, base_name='account')
|
||||
|
||||
# Router for children of /accounts/account/{account_pk}/.
|
||||
sub_accounts = NestedSimpleRouter(accounts, r'account', lookup='account')
|
||||
sub_accounts.register('reviews', ReviewViewSet, base_name='account-review')
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'', include(accounts.urls)),
|
||||
url(r'', include(sub_accounts.urls)),
|
||||
url(r'^authenticate/$', views.AuthenticateView.as_view(),
|
||||
name='accounts.authenticate'),
|
||||
url(r'^login/$', views.LoginView.as_view(), name='accounts.login'),
|
||||
|
|
|
@ -15,11 +15,9 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from rest_framework import generics
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.mixins import RetrieveModelMixin
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
from rest_framework_jwt.settings import api_settings as jwt_api_settings
|
||||
from waffle.decorators import waffle_switch
|
||||
|
||||
|
@ -162,8 +160,11 @@ def with_user(format, config=None):
|
|||
@write
|
||||
def inner(self, request):
|
||||
if config is None:
|
||||
fxa_config = (
|
||||
settings.FXA_CONFIG[settings.DEFAULT_FXA_CONFIG_NAME])
|
||||
if hasattr(self, 'get_fxa_config'):
|
||||
fxa_config = self.get_fxa_config(request)
|
||||
else:
|
||||
fxa_config = (
|
||||
settings.FXA_CONFIG[settings.DEFAULT_FXA_CONFIG_NAME])
|
||||
else:
|
||||
fxa_config = config
|
||||
|
||||
|
@ -267,20 +268,16 @@ class LoginStartView(LoginStartBaseView):
|
|||
|
||||
class LoginBaseView(FxAConfigMixin, APIView):
|
||||
|
||||
def post(self, request):
|
||||
config = self.get_fxa_config(request)
|
||||
|
||||
@with_user(format='json', config=config)
|
||||
def _post(self, request, user, identity, next_path):
|
||||
if user is None:
|
||||
return Response({'error': ERROR_NO_USER}, status=422)
|
||||
else:
|
||||
update_user(user, identity)
|
||||
response = Response({'email': identity['email']})
|
||||
add_api_token_to_response(response, user, set_cookie=False)
|
||||
log.info('Logging in user {} from FxA'.format(user))
|
||||
return response
|
||||
return _post(self, request)
|
||||
@with_user(format='json')
|
||||
def post(self, request, user, identity, next_path):
|
||||
if user is None:
|
||||
return Response({'error': ERROR_NO_USER}, status=422)
|
||||
else:
|
||||
update_user(user, identity)
|
||||
response = Response({'email': identity['email']})
|
||||
add_api_token_to_response(response, user, set_cookie=False)
|
||||
log.info('Logging in user {} from FxA'.format(user))
|
||||
return response
|
||||
|
||||
def options(self, request):
|
||||
return Response()
|
||||
|
@ -306,7 +303,10 @@ class RegisterView(APIView):
|
|||
return response
|
||||
|
||||
|
||||
class AuthenticateView(APIView):
|
||||
class AuthenticateView(FxAConfigMixin, APIView):
|
||||
DEFAULT_FXA_CONFIG_NAME = settings.DEFAULT_FXA_CONFIG_NAME
|
||||
ALLOWED_FXA_CONFIGS = settings.ALLOWED_FXA_CONFIGS
|
||||
|
||||
authentication_classes = (SessionAuthentication,)
|
||||
|
||||
@with_user(format='html')
|
||||
|
@ -344,16 +344,6 @@ class ProfileView(generics.RetrieveAPIView):
|
|||
return Response(self.get_serializer(request.user).data)
|
||||
|
||||
|
||||
class AccountViewSet(RetrieveModelMixin, GenericViewSet):
|
||||
queryset = UserProfile.objects.all()
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
# See https://github.com/mozilla/addons-server/issues/3138 ; be careful
|
||||
# when implementing it, we don't want to list users, only retrieve them
|
||||
# and eventually modify them through this ViewSet.
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class AccountSuperCreate(APIView):
|
||||
authentication_classes = [JWTKeyAuthentication]
|
||||
permission_classes = [
|
||||
|
|
|
@ -24,11 +24,7 @@ class ActivityLogSerializer(serializers.ModelSerializer):
|
|||
self.to_highlight = kwargs.get('context', []).get('to_highlight', [])
|
||||
|
||||
def get_comments(self, obj):
|
||||
# We have to do .unescape on the output of obj.to_string because the
|
||||
# 'string' it returns is supposed to be used in markup and doesn't get
|
||||
# serialized correctly unless we unescape it.
|
||||
comments = (obj.details['comments'] if obj.details
|
||||
else obj.to_string().unescape())
|
||||
comments = obj.details['comments'] if obj.details else ''
|
||||
return getattr(obj.log(), 'sanitize', comments)
|
||||
|
||||
def get_action_label(self, obj):
|
||||
|
|
|
@ -79,5 +79,5 @@ class TestReviewNotesSerializerOutput(TestCase, LogMixin):
|
|||
self.addon.find_latest_version(channel=amo.RELEASE_CHANNEL_LISTED),
|
||||
user=self.user)
|
||||
result = self.serialize()
|
||||
# Should default to the string representation of the log event.
|
||||
assert result['comments'] == self.entry.to_string()
|
||||
# Should output an empty string.
|
||||
assert result['comments'] == ''
|
||||
|
|
|
@ -274,6 +274,30 @@ class TestLogAndNotify(TestCase):
|
|||
self._check_email(send_mail_mock.call_args_list[1],
|
||||
self.addon.get_dev_url('versions'))
|
||||
|
||||
@mock.patch('olympia.activity.utils.send_mail')
|
||||
def test_log_with_no_comment(self, send_mail_mock):
|
||||
# One from the reviewer.
|
||||
self._create(amo.LOG.REJECT_VERSION, self.reviewer)
|
||||
action = amo.LOG.APPROVAL_NOTES_CHANGED
|
||||
log_and_notify(
|
||||
action=action, comments=None, note_creator=self.developer,
|
||||
version=self.version)
|
||||
|
||||
logs = ActivityLog.objects.filter(action=action.id)
|
||||
assert len(logs) == 1
|
||||
assert not logs[0].details # No details json because no comment.
|
||||
|
||||
assert send_mail_mock.call_count == 2 # One author, one reviewer.
|
||||
recipients = self._recipients(send_mail_mock)
|
||||
assert len(recipients) == 2
|
||||
assert self.reviewer.email in recipients
|
||||
assert self.developer2.email in recipients
|
||||
|
||||
assert u'Approval notes changed' in (
|
||||
send_mail_mock.call_args_list[0][0][1])
|
||||
assert u'Approval notes changed' in (
|
||||
send_mail_mock.call_args_list[1][0][1])
|
||||
|
||||
def test_staff_cc_group_is_empty_no_failure(self):
|
||||
Group.objects.create(name=ACTIVITY_MAIL_GROUP, rules='None:None')
|
||||
log_and_notify(amo.LOG.REJECT_VERSION, u'á', self.reviewer,
|
||||
|
|
|
@ -13,7 +13,7 @@ from olympia.access import acl
|
|||
from olympia.activity.models import ActivityLogToken
|
||||
from olympia.amo.helpers import absolutify
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.utils import send_mail
|
||||
from olympia.amo.utils import no_translation, send_mail
|
||||
from olympia.devhub.models import ActivityLog
|
||||
from olympia.users.models import UserProfile
|
||||
from olympia.users.utils import get_task_user
|
||||
|
@ -156,9 +156,17 @@ def log_and_notify(action, comments, note_creator, version):
|
|||
log_kwargs = {
|
||||
'user': note_creator,
|
||||
'created': datetime.datetime.now(),
|
||||
'details': {
|
||||
}
|
||||
if comments:
|
||||
log_kwargs['details'] = {
|
||||
'comments': comments,
|
||||
'version': version.version}}
|
||||
'version': version.version}
|
||||
else:
|
||||
# Just use the name of the action if no comments provided. Alas we
|
||||
# can't know the locale of recipient, and our templates are English
|
||||
# only so prevent language jumble by forcing into en-US.
|
||||
with no_translation():
|
||||
comments = '%s' % action.short
|
||||
note = amo.log(action, version.addon, version, **log_kwargs)
|
||||
|
||||
# Collect reviewers involved with this version.
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
from django.conf.urls import include, patterns, url
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from rest_framework.routers import SimpleRouter
|
||||
from rest_framework_nested.routers import NestedSimpleRouter
|
||||
|
||||
from olympia.activity.views import VersionReviewNotesViewSet
|
||||
from olympia.reviews.views import ReviewViewSet
|
||||
|
||||
from .views import (
|
||||
AddonFeaturedView, AddonSearchView, AddonVersionViewSet, AddonViewSet,
|
||||
|
@ -17,17 +16,15 @@ addons.register(r'addon', AddonViewSet)
|
|||
# Router for children of /addons/addon/{addon_pk}/.
|
||||
sub_addons = NestedSimpleRouter(addons, r'addon', lookup='addon')
|
||||
sub_addons.register('versions', AddonVersionViewSet, base_name='addon-version')
|
||||
sub_addons.register('reviews', ReviewViewSet, base_name='addon-review')
|
||||
sub_versions = NestedSimpleRouter(sub_addons, r'versions', lookup='version')
|
||||
sub_versions.register(r'reviewnotes', VersionReviewNotesViewSet,
|
||||
base_name='version-reviewnotes')
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
urlpatterns = [
|
||||
url(r'', include(addons.urls)),
|
||||
url(r'', include(sub_addons.urls)),
|
||||
url(r'', include(sub_versions.urls)),
|
||||
url(r'^search/$', AddonSearchView.as_view(), name='addon-search'),
|
||||
url(r'^featured/$', AddonFeaturedView.as_view(), name='addon-featured'),
|
||||
url(r'^categories/$', StaticCategoryView.as_view(), name='category-list'),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -49,6 +49,8 @@ class AddonIndexer(BaseSearchIndexer):
|
|||
'type': 'byte', 'index': 'no'},
|
||||
'size': {'type': 'long', 'index': 'no'},
|
||||
'status': {'type': 'byte'},
|
||||
'webext_permissions_list': {
|
||||
'type': 'string', 'index': 'no'},
|
||||
}
|
||||
},
|
||||
'version': {'type': 'string', 'index': 'no'},
|
||||
|
@ -158,6 +160,7 @@ class AddonIndexer(BaseSearchIndexer):
|
|||
'platform': file_.platform,
|
||||
'size': file_.size,
|
||||
'status': file_.status,
|
||||
'webext_permissions_list': file_.webext_permissions_list,
|
||||
} for file_ in version_obj.all_files],
|
||||
'reviewed': version_obj.reviewed,
|
||||
'version': version_obj.version,
|
||||
|
|
|
@ -1344,14 +1344,6 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
|
||||
return self.installed.filter(user=user).exists()
|
||||
|
||||
def get_latest_file(self):
|
||||
"""Get the latest file from the current version."""
|
||||
cur = self.current_version
|
||||
if cur:
|
||||
res = cur.files.order_by('-created')
|
||||
if res:
|
||||
return res[0]
|
||||
|
||||
def in_escalation_queue(self):
|
||||
return self.escalationqueue_set.exists()
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from olympia import amo
|
|||
from olympia.addons.models import (
|
||||
Addon, AddonFeatureCompatibility, attach_tags, Persona, Preview)
|
||||
from olympia.amo.helpers import absolutify
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.urlresolvers import get_outgoing_url, reverse
|
||||
from olympia.api.fields import ReverseChoiceField, TranslationSerializerField
|
||||
from olympia.api.serializers import BaseESSerializer
|
||||
from olympia.applications.models import AppVersion
|
||||
|
@ -30,10 +30,14 @@ class FileSerializer(serializers.ModelSerializer):
|
|||
url = serializers.SerializerMethodField()
|
||||
platform = ReverseChoiceField(choices=amo.PLATFORM_CHOICES_API.items())
|
||||
status = ReverseChoiceField(choices=amo.STATUS_CHOICES_API.items())
|
||||
permissions = serializers.ListField(
|
||||
source='webext_permissions_list',
|
||||
child=serializers.CharField())
|
||||
|
||||
class Meta:
|
||||
model = File
|
||||
fields = ('id', 'created', 'hash', 'platform', 'size', 'status', 'url')
|
||||
fields = ('id', 'created', 'hash', 'platform', 'size', 'status', 'url',
|
||||
'permissions')
|
||||
|
||||
def get_url(self, obj):
|
||||
# File.get_url_path() is a little different, it's already absolute, but
|
||||
|
@ -206,8 +210,21 @@ class AddonSerializer(serializers.ModelSerializer):
|
|||
|
||||
def to_representation(self, obj):
|
||||
data = super(AddonSerializer, self).to_representation(obj)
|
||||
if data['theme_data'] is None:
|
||||
if 'theme_data' in data and data['theme_data'] is None:
|
||||
data.pop('theme_data')
|
||||
if 'homepage' in data:
|
||||
data['homepage'] = self.outgoingify(data['homepage'])
|
||||
if 'support_url' in data:
|
||||
data['support_url'] = self.outgoingify(data['support_url'])
|
||||
return data
|
||||
|
||||
def outgoingify(self, data):
|
||||
if isinstance(data, basestring):
|
||||
return get_outgoing_url(data)
|
||||
elif isinstance(data, dict):
|
||||
return {key: get_outgoing_url(value) if value else None
|
||||
for key, value in data.items()}
|
||||
# Probably None... don't bother.
|
||||
return data
|
||||
|
||||
def get_categories(self, obj):
|
||||
|
@ -295,6 +312,15 @@ class ESBaseAddonSerializer(BaseESSerializer):
|
|||
translated_fields = ('name', 'description', 'homepage', 'summary',
|
||||
'support_email', 'support_url')
|
||||
|
||||
def fake_file_object(self, obj, data):
|
||||
file_ = File(
|
||||
id=data['id'], created=self.handle_date(data['created']),
|
||||
hash=data['hash'], filename=data['filename'],
|
||||
platform=data['platform'], size=data['size'],
|
||||
status=data['status'], version=obj)
|
||||
file_.webext_permissions_list = data.get('webext_permissions_list', [])
|
||||
return file_
|
||||
|
||||
def fake_version_object(self, obj, data, channel):
|
||||
if data:
|
||||
version = Version(
|
||||
|
@ -302,12 +328,8 @@ class ESBaseAddonSerializer(BaseESSerializer):
|
|||
reviewed=self.handle_date(data['reviewed']),
|
||||
version=data['version'], channel=channel)
|
||||
version.all_files = [
|
||||
File(
|
||||
id=file_['id'], created=self.handle_date(file_['created']),
|
||||
hash=file_['hash'], filename=file_['filename'],
|
||||
platform=file_['platform'], size=file_['size'],
|
||||
status=file_['status'], version=version)
|
||||
for file_ in data.get('files', [])
|
||||
self.fake_file_object(version, file_data)
|
||||
for file_data in data.get('files', [])
|
||||
]
|
||||
|
||||
# In ES we store integers for the appversion info, we need to
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
</p>
|
||||
</div> {# install #}
|
||||
|
||||
|
||||
{% if b.detailed %}
|
||||
<div class="detailed">
|
||||
{% if addon.privacy_policy %}
|
||||
<a class="privacy-policy badge" href="{{ url('addons.privacy', addon.slug) }}">
|
||||
{{ _('Privacy Policy') }}
|
||||
|
@ -48,7 +50,16 @@
|
|||
{{ _('End-User License Agreement') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if waffle.switch('webext-permissions') and version and version.all_files[0] %}
|
||||
<br>
|
||||
<a class="webext-permissions badge" href="#">
|
||||
{% if not version.all_files[0].is_webextension %}
|
||||
<img src="{{ static('img/developers/test-warning.png') }}" alt="{{ _('[Warning]') }}">
|
||||
{% endif %}
|
||||
{{ _('Permissions') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if addon.is_unreviewed() %}
|
||||
<p class="warning">
|
||||
{% trans url=url('pages.faq') + "#unreviewed" %}
|
||||
|
|
|
@ -322,6 +322,44 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if waffle.switch('webext-permissions') and addon.current_version and addon.current_version.all_files[0] %}
|
||||
<div class="modal" id="webext-permissions">
|
||||
<a href="#" class="close">{{ _('close') }}</a>
|
||||
<h2>{{ _('Permissions') }}</h2>
|
||||
{% if addon.current_version.all_files[0].is_webextension %}
|
||||
{% set permissions = addon.current_version.all_files[0].webext_permissions %}
|
||||
<div class="prose">
|
||||
<p>
|
||||
{{ _('Some add-ons ask for permissions to perform certain functions (example: a tab management add-on will ask permission to access your browser’s tab system).') }}
|
||||
</p><p>
|
||||
{{ _('Since you’re in control of your Firefox, the choice to grant or deny these requests is yours. Accepting permissions does not inherently compromise your browser’s performance or security, but in some rare cases risk may be involved.') }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
{# l10n: This is a header of a list of things the add-on can do. #}
|
||||
<h3>{{ _('It can:') }}</h3>
|
||||
<ul class="webext-permissions-list">
|
||||
{% for perm in permissions %}
|
||||
<li class="webext-permissions-list">{{ perm.description|e }}</li>
|
||||
{% else %}
|
||||
{{ ("The add-on doesn't have any special permissions.") }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="prose">
|
||||
<img src="{{ static('img/developers/test-warning.png') }}" alt="{{ _('[Warning]') }}">
|
||||
<p>
|
||||
{{ ('Some add-ons ask for permissions to perform certain functions. Since you’re in control of your Firefox, the choice to grant or deny these requests is yours.') }}
|
||||
</p><p>
|
||||
{{ ('Please note this add-on uses legacy technology, which gives it access to all browser functions and data without requesting your permission.') }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if addon.eula %}
|
||||
<div class="modal" id="eula">
|
||||
<a href="#" class="close">{{ _('close') }}</a>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import timedelta
|
||||
from itertools import chain
|
||||
|
||||
from olympia import amo
|
||||
|
@ -12,6 +11,7 @@ from olympia.addons.indexers import AddonIndexer
|
|||
from olympia.constants.applications import FIREFOX
|
||||
from olympia.constants.platforms import PLATFORM_ALL, PLATFORM_MAC
|
||||
from olympia.constants.search import SEARCH_ANALYZER_MAP
|
||||
from olympia.files.models import WebextPermission
|
||||
|
||||
|
||||
class TestAddonIndexer(TestCase):
|
||||
|
@ -116,7 +116,7 @@ class TestAddonIndexer(TestCase):
|
|||
# Make sure files mapping is set inside current_version.
|
||||
files_mapping = version_mapping['files']['properties']
|
||||
expected_file_keys = ('id', 'created', 'filename', 'hash', 'platform',
|
||||
'size', 'status')
|
||||
'size', 'status', 'webext_permissions_list')
|
||||
assert set(files_mapping.keys()) == set(expected_file_keys)
|
||||
|
||||
def _extract(self):
|
||||
|
@ -178,13 +178,15 @@ class TestAddonIndexer(TestCase):
|
|||
version = self.addon.current_version
|
||||
file_factory(version=version, platform=PLATFORM_MAC.id)
|
||||
current_beta_version = version_factory(
|
||||
addon=self.addon, file_kw={'status': amo.STATUS_BETA})
|
||||
addon=self.addon,
|
||||
file_kw={'status': amo.STATUS_BETA, 'is_webextension': True})
|
||||
# Give one of the versions some webext permissions to test that.
|
||||
WebextPermission.objects.create(
|
||||
file=current_beta_version.all_files[0],
|
||||
permissions=['bookmarks', 'random permission']
|
||||
)
|
||||
unlisted_version = version_factory(
|
||||
addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED)
|
||||
# FIXME: remove this next line once current_version is modified to only
|
||||
# return listed versions.
|
||||
unlisted_version.update(
|
||||
created=version.created - timedelta(days=42))
|
||||
extracted = self._extract()
|
||||
|
||||
assert extracted['current_version']
|
||||
|
@ -208,6 +210,7 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
assert extracted_file['webext_permissions_list'] == []
|
||||
|
||||
assert set(extracted['platforms']) == set([PLATFORM_MAC.id,
|
||||
PLATFORM_ALL.id])
|
||||
|
@ -232,6 +235,9 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
assert (extracted_file['webext_permissions_list'] ==
|
||||
file_.webext_permissions_list ==
|
||||
['bookmarks', 'random permission'])
|
||||
|
||||
version = unlisted_version
|
||||
assert extracted['latest_unlisted_version']
|
||||
|
@ -255,6 +261,7 @@ class TestAddonIndexer(TestCase):
|
|||
assert extracted_file['platform'] == file_.platform
|
||||
assert extracted_file['size'] == file_.size
|
||||
assert extracted_file['status'] == file_.status
|
||||
assert extracted_file['webext_permissions_list'] == []
|
||||
|
||||
def test_extract_translations(self):
|
||||
translations_name = {
|
||||
|
|
|
@ -2401,7 +2401,7 @@ class TestAddonFromUpload(UploadTest):
|
|||
parse_addon.return_value = {
|
||||
'default_locale': u'en',
|
||||
'e10s_compatibility': 2,
|
||||
'guid': u'notify-link-clicks-i18n@mozilla.org',
|
||||
'guid': u'notify-link-clicks-i18n@notzilla.org',
|
||||
'name': u'__MSG_extensionName__',
|
||||
'is_webextension': True,
|
||||
'type': 1,
|
||||
|
@ -2426,7 +2426,7 @@ class TestAddonFromUpload(UploadTest):
|
|||
parse_addon.return_value = {
|
||||
'default_locale': u'xxx',
|
||||
'e10s_compatibility': 2,
|
||||
'guid': u'notify-link-clicks-i18n@mozilla.org',
|
||||
'guid': u'notify-link-clicks-i18n@notzilla.org',
|
||||
'name': u'__MSG_extensionName__',
|
||||
'is_webextension': True,
|
||||
'type': 1,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.utils.translation import override
|
||||
|
||||
from elasticsearch_dsl import Search
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
|
@ -7,7 +9,7 @@ from olympia.amo.helpers import absolutify
|
|||
from olympia.amo.tests import (
|
||||
addon_factory, ESTestCase, file_factory, TestCase, version_factory,
|
||||
user_factory)
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.urlresolvers import get_outgoing_url, reverse
|
||||
from olympia.addons.indexers import AddonIndexer
|
||||
from olympia.addons.models import (
|
||||
Addon, AddonCategory, AddonUser, Category, Persona, Preview)
|
||||
|
@ -17,6 +19,7 @@ from olympia.addons.serializers import (
|
|||
VersionSerializer)
|
||||
from olympia.addons.utils import generate_addon_guid
|
||||
from olympia.constants.categories import CATEGORIES
|
||||
from olympia.files.models import WebextPermission
|
||||
from olympia.versions.models import ApplicationsVersions, AppVersion, License
|
||||
|
||||
|
||||
|
@ -51,6 +54,7 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result_file['size'] == file_.size
|
||||
assert result_file['status'] == amo.STATUS_CHOICES_API[file_.status]
|
||||
assert result_file['url'] == file_.get_url_path(src='')
|
||||
assert result_file['permissions'] == file_.webext_permissions_list
|
||||
|
||||
assert data['edit_url'] == absolutify(
|
||||
self.addon.get_dev_url(
|
||||
|
@ -159,7 +163,9 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result['guid'] == self.addon.guid
|
||||
assert result['has_eula'] is False
|
||||
assert result['has_privacy_policy'] is False
|
||||
assert result['homepage'] == {'en-US': self.addon.homepage}
|
||||
assert result['homepage'] == {
|
||||
'en-US': get_outgoing_url(unicode(self.addon.homepage))
|
||||
}
|
||||
assert result['icon_url'] == absolutify(self.addon.get_icon_url(64))
|
||||
assert result['is_disabled'] == self.addon.is_disabled
|
||||
assert result['is_experimental'] == self.addon.is_experimental is False
|
||||
|
@ -200,7 +206,9 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result['status'] == 'public'
|
||||
assert result['summary'] == {'en-US': self.addon.summary}
|
||||
assert result['support_email'] == {'en-US': self.addon.support_email}
|
||||
assert result['support_url'] == {'en-US': self.addon.support_url}
|
||||
assert result['support_url'] == {
|
||||
'en-US': get_outgoing_url(unicode(self.addon.support_url))
|
||||
}
|
||||
assert 'theme_data' not in result
|
||||
assert set(result['tags']) == set(['some_tag', 'some_other_tag'])
|
||||
assert result['type'] == 'extension'
|
||||
|
@ -334,12 +342,32 @@ class AddonSerializerOutputTestMixin(object):
|
|||
'en-US': u'My Addôn description in english',
|
||||
'fr': u'Description de mon Addôn',
|
||||
}
|
||||
translated_homepages = {
|
||||
'en-US': u'http://www.google.com/',
|
||||
'fr': u'http://www.googlé.fr/',
|
||||
}
|
||||
self.addon = addon_factory()
|
||||
self.addon.description = translated_descriptions
|
||||
self.addon.homepage = translated_homepages
|
||||
self.addon.save()
|
||||
|
||||
result = self.serialize()
|
||||
assert result['description'] == translated_descriptions
|
||||
assert result['homepage'] != translated_homepages
|
||||
assert result['homepage'] == {
|
||||
'en-US': get_outgoing_url(translated_homepages['en-US']),
|
||||
'fr': get_outgoing_url(translated_homepages['fr'])
|
||||
}
|
||||
|
||||
# Try a single translation. The locale activation is normally done by
|
||||
# LocaleAndAppURLMiddleware, but since we're directly calling the
|
||||
# serializer we need to do it ourselves.
|
||||
self.request = APIRequestFactory().get('/', {'lang': 'fr'})
|
||||
with override('fr'):
|
||||
result = self.serialize()
|
||||
assert result['description'] == translated_descriptions['fr']
|
||||
assert result['homepage'] == get_outgoing_url(
|
||||
translated_homepages['fr'])
|
||||
|
||||
def test_persona_with_persona_id(self):
|
||||
self.addon = addon_factory(persona_id=42, type=amo.ADDON_PERSONA)
|
||||
|
@ -387,6 +415,23 @@ class AddonSerializerOutputTestMixin(object):
|
|||
assert result['icon_url'] == (
|
||||
'http://testserver/static/img/addon-icons/default-64.png')
|
||||
|
||||
def test_webextension(self):
|
||||
self.addon = addon_factory(
|
||||
file_kw={'is_webextension': True})
|
||||
# Give one of the versions some webext permissions to test that.
|
||||
WebextPermission.objects.create(
|
||||
file=self.addon.current_version.all_files[0],
|
||||
permissions=['bookmarks', 'random permission']
|
||||
)
|
||||
|
||||
result = self.serialize()
|
||||
|
||||
self._test_version(
|
||||
self.addon.current_version, result['current_version'])
|
||||
# Double check the permissions got correctly set.
|
||||
assert result['current_version']['files'][0]['permissions'] == ([
|
||||
'bookmarks', 'random permission'])
|
||||
|
||||
|
||||
class TestAddonSerializerOutput(AddonSerializerOutputTestMixin, TestCase):
|
||||
serializer_class = AddonSerializer
|
||||
|
@ -538,6 +583,20 @@ class TestVersionSerializerOutput(TestCase):
|
|||
assert result['id'] == self.version.pk
|
||||
assert result['license'] is None
|
||||
|
||||
def test_file_webext_permissions(self):
|
||||
self.version = addon_factory().current_version
|
||||
result = self.serialize()
|
||||
# No permissions.
|
||||
assert result['files'][0]['permissions'] == []
|
||||
|
||||
self.version = addon_factory(
|
||||
file_kw={'is_webextension': True}).current_version
|
||||
permissions = ['dangerdanger', 'high', 'voltage']
|
||||
WebextPermission.objects.create(
|
||||
permissions=permissions, file=self.version.all_files[0])
|
||||
result = self.serialize()
|
||||
assert result['files'][0]['permissions'] == permissions
|
||||
|
||||
|
||||
class TestSimpleVersionSerializerOutput(TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -84,6 +84,13 @@ class TestDataValidate(VersionCheckMixin, TestCase):
|
|||
up = self.get(self.good_data)
|
||||
assert not up.is_valid()
|
||||
|
||||
def test_disabled(self):
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
addon.update(status=amo.STATUS_DISABLED)
|
||||
|
||||
up = self.get(self.good_data)
|
||||
assert not up.is_valid()
|
||||
|
||||
def test_no_version(self):
|
||||
data = self.good_data.copy()
|
||||
del data['version']
|
||||
|
|
|
@ -26,6 +26,7 @@ from olympia.addons.models import (
|
|||
AddonUser, Category, Charity, Persona)
|
||||
from olympia.bandwagon.models import Collection
|
||||
from olympia.constants.categories import CATEGORIES
|
||||
from olympia.files.models import WebextPermission
|
||||
from olympia.paypal.tests.test import other_error
|
||||
from olympia.stats.models import Contribution
|
||||
from olympia.users.helpers import users_list
|
||||
|
@ -733,6 +734,71 @@ class TestDetailPage(TestCase):
|
|||
privacy_url = reverse('addons.privacy', args=[self.addon.slug])
|
||||
assert doc('.privacy-policy').attr('href').endswith(privacy_url)
|
||||
|
||||
@override_switch('webext-permissions', active=False)
|
||||
def test_permissions_not_shown_without_waffle(self):
|
||||
response = self.client.get(self.url)
|
||||
doc = pq(response.content)
|
||||
assert doc('a.webext-permissions').length == 0
|
||||
assert doc('#webext-permissions').length == 0
|
||||
|
||||
@override_switch('webext-permissions', active=True)
|
||||
def test_permissions_webext(self):
|
||||
file_ = self.addon.current_version.all_files[0]
|
||||
file_.update(is_webextension=True)
|
||||
WebextPermission.objects.create(file=file_, permissions=[
|
||||
u'http://*/*', u'<all_urls>', u'bookmarks',
|
||||
u'made up permission', u'https://google.com/'])
|
||||
response = self.client.get(self.url)
|
||||
doc = pq(response.content)
|
||||
# The link next to the button
|
||||
assert doc('a.webext-permissions').length == 1
|
||||
# And the model dialog
|
||||
assert doc('#webext-permissions').length == 1
|
||||
assert u'perform certain functions (example: a tab management' in (
|
||||
doc('#webext-permissions div.prose').text())
|
||||
assert doc('ul.webext-permissions-list').length == 1
|
||||
assert doc('li.webext-permissions-list').length == 4
|
||||
# See File.webext_permissions for the order logic
|
||||
assert doc('li.webext-permissions-list').text() == (
|
||||
u'Access your data for all websites '
|
||||
u'Access bookmarks '
|
||||
u'Access your data for https://google.com/ website '
|
||||
u'made up permission')
|
||||
|
||||
@override_switch('webext-permissions', active=True)
|
||||
def test_permissions_webext_no_permissions(self):
|
||||
file_ = self.addon.current_version.all_files[0]
|
||||
file_.update(is_webextension=True)
|
||||
assert file_.webext_permissions_list == []
|
||||
response = self.client.get(self.url)
|
||||
doc = pq(response.content)
|
||||
# The link next to the button - still shown even when no permissions.
|
||||
assert doc('a.webext-permissions').length == 1
|
||||
# And the model dialog
|
||||
assert doc('#webext-permissions').length == 1
|
||||
assert u'perform certain functions (example: a tab management' in (
|
||||
doc('#webext-permissions div.prose').text())
|
||||
assert doc('ul.webext-permissions-list').length == 1
|
||||
assert doc('li.webext-permissions-list').length == 0
|
||||
assert u"doesn't have any special" in (
|
||||
doc('ul.webext-permissions-list').text())
|
||||
|
||||
@override_switch('webext-permissions', active=True)
|
||||
def test_permissions_non_webext(self):
|
||||
file_ = self.addon.current_version.all_files[0]
|
||||
file_.update(is_webextension=False)
|
||||
response = self.client.get(self.url)
|
||||
doc = pq(response.content)
|
||||
# The link next to the button
|
||||
assert doc('a.webext-permissions').length == 1
|
||||
# danger danger icon shown for oldie xul addons
|
||||
assert doc('a.webext-permissions img').length == 1
|
||||
# And the model dialog
|
||||
assert doc('#webext-permissions').length == 1
|
||||
assert u'Please note this add-on uses legacy technology' in (
|
||||
doc('#webext-permissions div.prose').text())
|
||||
assert doc('.webext-permissions-list').length == 0
|
||||
|
||||
def test_simple_html_is_rendered_in_privacy(self):
|
||||
self.addon.privacy_policy = """
|
||||
<strong> what the hell..</strong>
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from django.shortcuts import redirect
|
||||
from django.views.decorators.cache import cache_page
|
||||
|
||||
from olympia.reviews.urls import review_patterns
|
||||
from olympia.stats.urls import stats_patterns
|
||||
from . import buttons
|
||||
from . import views
|
||||
|
@ -12,8 +11,7 @@ ADDON_ID = r"""(?P<addon_id>[^/<>"']+)"""
|
|||
|
||||
|
||||
# These will all start with /addon/<addon_id>/
|
||||
detail_patterns = patterns(
|
||||
'',
|
||||
detail_patterns = [
|
||||
url('^$', views.addon_detail, name='addons.detail'),
|
||||
url('^more$', views.addon_detail, name='addons.detail_more'),
|
||||
url('^eula/(?P<file_id>\d+)?$', views.eula, name='addons.eula'),
|
||||
|
@ -39,10 +37,10 @@ detail_patterns = patterns(
|
|||
addon_id, permanent=True),
|
||||
name='addons.about'),
|
||||
|
||||
('^reviews/', include(review_patterns('addons'))),
|
||||
('^statistics/', include(stats_patterns)),
|
||||
('^versions/', include('olympia.versions.urls')),
|
||||
)
|
||||
url('^reviews/', include('olympia.reviews.urls')),
|
||||
url('^statistics/', include(stats_patterns)),
|
||||
url('^versions/', include('olympia.versions.urls')),
|
||||
]
|
||||
|
||||
|
||||
urlpatterns = patterns(
|
||||
|
|
|
@ -14,6 +14,7 @@ urlpatterns = patterns(
|
|||
url(r'^v3/addons/', include('olympia.addons.api_urls')),
|
||||
url(r'^v3/', include('olympia.discovery.api_urls')),
|
||||
url(r'^v3/internal/', include('olympia.internal_tools.urls')),
|
||||
url(r'^v3/reviews/', include('olympia.reviews.api_urls')),
|
||||
url(r'^v3/', include('olympia.signing.urls')),
|
||||
url(r'^v3/statistics/', include('olympia.stats.api_urls')),
|
||||
url(r'^v3/activity/', include('olympia.activity.urls')),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div class="barometer">
|
||||
<form method="post" class="upvote" action="{{ up_action }}">
|
||||
<form method="post" class="upvote" action="{{ up_action }}" data-no-csrf>
|
||||
<input class="{{ up_class }}" value="{{ c.upvotes }}" type="submit"
|
||||
title="{{ up_title }}">
|
||||
</form>
|
||||
<form method="post" class="downvote" action="{{ down_action }}">
|
||||
<form method="post" class="downvote" action="{{ down_action }}" data-no-csrf>
|
||||
<input class="{{ down_class }}" value="{{ c.downvotes }}" type="submit"
|
||||
title="{{ down_title }}">
|
||||
</form>
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
{{ num }} Add-ons in this Collection
|
||||
{% endtrans %}
|
||||
</h3>
|
||||
<form class="item-sort go">
|
||||
<form class="item-sort go" data-no-csrf>
|
||||
<label for="sortby">{{ _('Sort by:') }}</label>
|
||||
<select id="sortby" name="{{ filter.key }}">
|
||||
{% for value, title in filter.opts %}
|
||||
|
|
|
@ -5,19 +5,68 @@ from django.utils.translation import ugettext_lazy as _lazy
|
|||
Permission = namedtuple('Permission',
|
||||
'name, description, long_description')
|
||||
|
||||
|
||||
ALL_URLS_PERMISSION = Permission(
|
||||
u'all_urls',
|
||||
_lazy(u'Access your data for all websites'),
|
||||
'')
|
||||
|
||||
WEBEXT_PERMISSIONS = {
|
||||
u'activeTab': Permission(
|
||||
u'activeTab',
|
||||
_lazy(u'Requests that the extension be granted permissions according '
|
||||
u'to the activeTab specification.'),
|
||||
_lazy(u'Requests that the extension be granted permissions according '
|
||||
u'to the activeTab specification.')),
|
||||
u'alarms': Permission(
|
||||
u'alarms',
|
||||
_lazy(u'Gives the extension access to the chrome.alarms API.'),
|
||||
_lazy(u'Gives the extension access to the chrome.alarms API.')),
|
||||
u'<all_urls>': ALL_URLS_PERMISSION,
|
||||
u'http://*/*': ALL_URLS_PERMISSION,
|
||||
u'https://*/*': ALL_URLS_PERMISSION,
|
||||
u'*://*/*': ALL_URLS_PERMISSION,
|
||||
|
||||
u'bookmarks': Permission(
|
||||
u'bookmarks',
|
||||
_lazy(u'Read and modify bookmarks.'),
|
||||
_lazy(u'Read and modify bookmarks.')),
|
||||
_lazy(u'Access bookmarks'),
|
||||
''),
|
||||
u'clipboard': Permission(
|
||||
u'clipboard',
|
||||
_lazy(u'Access text clipboard'),
|
||||
''),
|
||||
u'downloads': Permission(
|
||||
u'downloads',
|
||||
_lazy(u"Download files and read and modify the browser's download"
|
||||
u"history"),
|
||||
''),
|
||||
u'history': Permission(
|
||||
u'history',
|
||||
_lazy(u'Access browser history'),
|
||||
''),
|
||||
u'nativeMessaging': Permission(
|
||||
u'nativeMessaging',
|
||||
_lazy(u'Exchange messages with programs other than Firefox'),
|
||||
''),
|
||||
u'notifications': Permission(
|
||||
u'notifications',
|
||||
_lazy(u'Display notifications to you'),
|
||||
''),
|
||||
u'sessions': Permission(
|
||||
u'sessions',
|
||||
_lazy(u'Access browser history to restore tabs'),
|
||||
''),
|
||||
u'tabs': Permission(
|
||||
u'tabs',
|
||||
_lazy(u'Access browser tabs'),
|
||||
''),
|
||||
u'topSites': Permission(
|
||||
u'topSites',
|
||||
_lazy(u'Access browsing history'),
|
||||
''),
|
||||
u'webNavigation': Permission(
|
||||
u'webNavigation',
|
||||
_lazy(u'Access browser activity during navigation'),
|
||||
''),
|
||||
u'unlimitedStorage': Permission(
|
||||
u'unlimitedStorage',
|
||||
_lazy(u'Provide unlimited storage of client-side data'),
|
||||
''),
|
||||
u'webRequest': Permission(
|
||||
u'webRequest',
|
||||
_lazy(u'Access browser during Web activity'),
|
||||
''),
|
||||
}
|
||||
|
||||
# webRequestBlocking has the same description as webRequest.
|
||||
WEBEXT_PERMISSIONS[u'webRequestBlocking'] = WEBEXT_PERMISSIONS[u'webRequest']
|
||||
|
|
|
@ -23,7 +23,7 @@ from olympia.amo.tests import TestCase
|
|||
from olympia.addons.models import (
|
||||
Addon, AddonFeatureCompatibility, Charity)
|
||||
from olympia.amo.helpers import url as url_reverse
|
||||
from olympia.amo.tests import addon_factory, version_factory
|
||||
from olympia.amo.tests import addon_factory, user_factory, version_factory
|
||||
from olympia.amo.tests.test_helpers import get_image_path
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.api.models import APIKey, SYMMETRIC_JWT_TYPE
|
||||
|
@ -1687,6 +1687,34 @@ class TestUploadDetail(BaseUploadTest):
|
|||
{u'tier': 1, u'message': u'You cannot submit this type of add-on',
|
||||
u'fatal': True, u'type': u'error'}]
|
||||
|
||||
@mock.patch('olympia.devhub.tasks.run_validator')
|
||||
def test_system_addon_allowed(self, mock_validator):
|
||||
user_factory(email='redpanda@mozilla.com')
|
||||
assert self.client.login(email='redpanda@mozilla.com')
|
||||
mock_validator.return_value = json.dumps(self.validation_ok())
|
||||
self.upload_file(
|
||||
'../../../files/fixtures/files/mozilla_guid.xpi')
|
||||
upload = FileUpload.objects.get()
|
||||
response = self.client.get(reverse('devhub.upload_detail',
|
||||
args=[upload.uuid.hex, 'json']))
|
||||
data = json.loads(response.content)
|
||||
assert data['validation']['messages'] == []
|
||||
|
||||
@mock.patch('olympia.devhub.tasks.run_validator')
|
||||
def test_system_addon_not_allowed_not_mozilla(self, mock_validator):
|
||||
user_factory(email='bluepanda@notzilla.com')
|
||||
assert self.client.login(email='bluepanda@notzilla.com')
|
||||
self.upload_file(
|
||||
'../../../files/fixtures/files/mozilla_guid.xpi')
|
||||
upload = FileUpload.objects.get()
|
||||
response = self.client.get(reverse('devhub.upload_detail',
|
||||
args=[upload.uuid.hex, 'json']))
|
||||
data = json.loads(response.content)
|
||||
assert data['validation']['messages'] == [
|
||||
{u'tier': 1, u'message': u'You cannot submit an add-on with a '
|
||||
u'guid ending "@mozilla.org"',
|
||||
u'fatal': True, u'type': u'error'}]
|
||||
|
||||
def test_no_redirect_for_metadata(self):
|
||||
user = UserProfile.objects.get(email='regular@mozilla.com')
|
||||
addon = addon_factory(status=amo.STATUS_NULL)
|
||||
|
|
|
@ -52,6 +52,7 @@ from olympia.lib.crypto.packaged import sign_file
|
|||
from olympia.search.views import BaseAjaxSearch
|
||||
from olympia.translations.models import delete_translation
|
||||
from olympia.users.models import UserProfile
|
||||
from olympia.users.utils import system_addon_submission_allowed
|
||||
from olympia.versions.models import Version
|
||||
from olympia.zadmin.models import get_config, ValidationResult
|
||||
|
||||
|
@ -804,6 +805,10 @@ def json_upload_detail(request, upload, addon_slug=None):
|
|||
if not acl.submission_allowed(request.user, pkg):
|
||||
raise django_forms.ValidationError(
|
||||
_(u'You cannot submit this type of add-on'))
|
||||
if not system_addon_submission_allowed(request.user, pkg):
|
||||
raise django_forms.ValidationError(
|
||||
_(u'You cannot submit an add-on with a guid ending '
|
||||
u'"@mozilla.org"'))
|
||||
except django_forms.ValidationError, exc:
|
||||
errors_before = result['validation'].get('errors', 0)
|
||||
# FIXME: This doesn't guard against client-side
|
||||
|
@ -1155,7 +1160,7 @@ def version_edit(request, addon_id, addon, version_id):
|
|||
version.update(has_info_request=False)
|
||||
if waffle.switch_is_active('activity-email'):
|
||||
log_and_notify(amo.LOG.APPROVAL_NOTES_CHANGED,
|
||||
u'Approval notes were updated.',
|
||||
None,
|
||||
request.user,
|
||||
version)
|
||||
else:
|
||||
|
@ -1172,27 +1177,15 @@ def version_edit(request, addon_id, addon, version_id):
|
|||
version.update(has_info_request=False)
|
||||
if waffle.switch_is_active('activity-email'):
|
||||
log_and_notify(amo.LOG.SOURCE_CODE_UPLOADED,
|
||||
u'Source code was uploaded.',
|
||||
None,
|
||||
request.user,
|
||||
version)
|
||||
else:
|
||||
amo.log(amo.LOG.SOURCE_CODE_UPLOADED,
|
||||
version,
|
||||
request.user,
|
||||
details={
|
||||
'comments': (u'This version has been '
|
||||
u'automatically flagged for '
|
||||
u'admin review, as source files '
|
||||
u'have been uploaded.')})
|
||||
addon, version, request.user)
|
||||
else:
|
||||
amo.log(amo.LOG.SOURCE_CODE_UPLOADED,
|
||||
version,
|
||||
request.user,
|
||||
details={
|
||||
'comments': (u'This version has been '
|
||||
u'automatically flagged for '
|
||||
u'admin review, as source files '
|
||||
u'have been uploaded.')})
|
||||
addon, version, request.user)
|
||||
|
||||
messages.success(request, _('Changes successfully saved.'))
|
||||
return redirect('devhub.versions.edit', addon.slug, version_id)
|
||||
|
@ -1688,7 +1681,7 @@ def request_review(request, addon_id, addon):
|
|||
messages.success(request, _('Review requested.'))
|
||||
else:
|
||||
messages.success(request, _(
|
||||
'Review requested. You must provide further details to proceed.'))
|
||||
'You must provide further details to proceed.'))
|
||||
amo.log(amo.LOG.CHANGE_STATUS, addon.get_status_display(), addon)
|
||||
return redirect(addon.get_dev_url('versions'))
|
||||
|
||||
|
|
Двоичный файл не отображается.
Двоичные данные
src/olympia/files/fixtures/files/notify-link-clicks-i18n.xpi
Двоичные данные
src/olympia/files/fixtures/files/notify-link-clicks-i18n.xpi
Двоичный файл не отображается.
Двоичные данные
src/olympia/files/fixtures/files/webextension_no_id.xpi
Двоичные данные
src/olympia/files/fixtures/files/webextension_no_id.xpi
Двоичный файл не отображается.
|
@ -13,7 +13,7 @@ from django.db import models
|
|||
from django.dispatch import receiver
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
import commonware
|
||||
from cache_nuggets.lib import memoize
|
||||
from django_extensions.db.fields.json import JSONField
|
||||
|
@ -377,20 +377,45 @@ class File(OnChangeMixin, ModelBase):
|
|||
statsd.timing('files.extract.localepicker', (end * 1000))
|
||||
return res
|
||||
|
||||
@amo.cached_property
|
||||
@property
|
||||
def webext_permissions(self):
|
||||
try:
|
||||
return {
|
||||
name: WEBEXT_PERMISSIONS.get(name, Permission(name, '', ''))
|
||||
for name in self._webext_permissions.permissions}
|
||||
except WebextPermission.DoesNotExist:
|
||||
return {}
|
||||
"""Return permissions with descriptions in defined order:
|
||||
1) match all urls (e.g. <all-urls>)
|
||||
2) known permissions, in constants order (alphabetically),
|
||||
3) match urls for sites
|
||||
4) unknown permissions
|
||||
"""
|
||||
out, urls, unknowns = [], [], []
|
||||
for name in self.webext_permissions_list:
|
||||
perm = WEBEXT_PERMISSIONS.get(name, None)
|
||||
if perm:
|
||||
# Add known permissions, including match-alls.
|
||||
if perm not in out:
|
||||
# We don't want duplicates.
|
||||
out.append(perm)
|
||||
elif '//' in name:
|
||||
# Filter out match urls so we can group them.
|
||||
urls.append(name)
|
||||
else:
|
||||
# Other strings are unknown permissions.
|
||||
unknowns.append(name)
|
||||
out.sort()
|
||||
# TODO: group match urls.
|
||||
out += [
|
||||
Permission(name, _(u'Access your data for {name} website').format(
|
||||
name=name), '')
|
||||
for name in urls]
|
||||
# return + other (unknown) permissions at the end.
|
||||
return out + [Permission(name, name, '') for name in unknowns]
|
||||
|
||||
@amo.cached_property
|
||||
def webext_permissions_known(self):
|
||||
return {name: perm
|
||||
for name, perm in self.webext_permissions.iteritems()
|
||||
if name in WEBEXT_PERMISSIONS}
|
||||
@amo.cached_property(writable=True)
|
||||
def webext_permissions_list(self):
|
||||
if not self.is_webextension:
|
||||
return []
|
||||
try:
|
||||
return list(self._webext_permissions.permissions)
|
||||
except WebextPermission.DoesNotExist:
|
||||
return []
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=File,
|
||||
|
|
|
@ -31,17 +31,17 @@ class TestWebextExtractPermissions(UploadTest):
|
|||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=parsed_data)
|
||||
assert WebextPermission.objects.count() == 0
|
||||
assert file_.webext_permissions == {}
|
||||
assert file_.webext_permissions_list == []
|
||||
|
||||
call_command('extract_permissions')
|
||||
|
||||
file_ = File.objects.no_cache().get(id=file_.id)
|
||||
assert WebextPermission.objects.get(file=file_)
|
||||
permissions = file_.webext_permissions
|
||||
assert len(permissions) == 3
|
||||
assert permissions['alarms']
|
||||
assert permissions[u'http://*/*']
|
||||
assert permissions[u'https://*/*']
|
||||
permissions_list = file_.webext_permissions_list
|
||||
assert len(permissions_list) == 5
|
||||
assert permissions_list == [u'http://*/*', u'https://*/*', 'bookmarks',
|
||||
'made up permission', 'https://google.com/'
|
||||
]
|
||||
|
||||
def test_force_extract(self):
|
||||
upload = self.get_upload('webextension_no_id.xpi')
|
||||
|
@ -51,11 +51,10 @@ class TestWebextExtractPermissions(UploadTest):
|
|||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=parsed_data)
|
||||
assert WebextPermission.objects.count() == 1
|
||||
assert len(file_.webext_permissions) == 2
|
||||
assert len(file_.webext_permissions_list) == 4
|
||||
|
||||
call_command('extract_permissions', force=True)
|
||||
|
||||
file_ = File.objects.no_cache().get(id=file_.id)
|
||||
assert WebextPermission.objects.get(file=file_)
|
||||
permissions = file_.webext_permissions
|
||||
assert len(permissions) == 3
|
||||
assert len(file_.webext_permissions_list) == 5
|
||||
|
|
|
@ -20,6 +20,7 @@ from olympia.amo.tests import TestCase
|
|||
from olympia.amo.utils import rm_local_tmp_dir, chunked
|
||||
from olympia.addons.models import Addon
|
||||
from olympia.applications.models import AppVersion
|
||||
from olympia.constants.webext_permissions import ALL_URLS_PERMISSION
|
||||
from olympia.files.models import (
|
||||
EXTENSIONS, File, FileUpload, FileValidation, nfd_str,
|
||||
track_file_status_change,
|
||||
|
@ -243,6 +244,32 @@ class TestFile(TestCase, amo.tests.AMOPaths):
|
|||
addon.update(status=amo.STATUS_DELETED)
|
||||
assert f.addon.id == addon_id
|
||||
|
||||
def _check_permissions_order(self, permissions):
|
||||
# We have two match-all urls - no dupes!
|
||||
assert len(permissions) == 4
|
||||
# First should be catch-all match urls, if present.
|
||||
assert permissions[0] == ALL_URLS_PERMISSION
|
||||
# Second should be known permission(s).
|
||||
assert permissions[1] == (u'bookmarks', 'Access bookmarks', '')
|
||||
# Third is match urls for specified site(s).
|
||||
assert permissions[2] == (u'https://google.com/',
|
||||
u'Access your data for https://google.com/ '
|
||||
u'website', '')
|
||||
# Lastly any unknown permission strings.
|
||||
assert permissions[3] == (u'made up permission', u'made up permission',
|
||||
'')
|
||||
|
||||
def test_webext_permissions(self):
|
||||
perm_list = [u'http://*/*', u'<all_urls>', u'bookmarks',
|
||||
u'made up permission', u'https://google.com/']
|
||||
file_ = File.objects.get(pk=67442)
|
||||
file_.webext_permissions_list = perm_list
|
||||
self._check_permissions_order(file_.webext_permissions)
|
||||
|
||||
# Check the order isn't dependent on the order in the manifest
|
||||
file_.webext_permissions_list.reverse()
|
||||
self._check_permissions_order(file_.webext_permissions)
|
||||
|
||||
|
||||
class TestTrackFileStatusChange(TestCase):
|
||||
|
||||
|
@ -332,7 +359,8 @@ class TestParseXpi(TestCase):
|
|||
parsed = self.parse(filename='webextension_no_id.xpi')
|
||||
assert len(parsed['permissions'])
|
||||
assert parsed['permissions'] == [
|
||||
u'http://*/*', u'https://*/*', u'alarms']
|
||||
u'http://*/*', u'https://*/*', u'bookmarks', u'made up permission',
|
||||
u'https://google.com/']
|
||||
|
||||
def test_parse_apps(self):
|
||||
exp = (amo.FIREFOX,
|
||||
|
@ -1086,22 +1114,16 @@ class TestFileFromUpload(UploadTest):
|
|||
|
||||
def test_permissions(self):
|
||||
upload = self.upload('webextension_no_id.xpi')
|
||||
parsed_data = parse_addon(upload)
|
||||
# 5 total permissions.
|
||||
assert len(parsed_data['permissions']) == 5
|
||||
file_ = File.from_upload(upload, self.version, self.platform,
|
||||
parsed_data=parse_addon(upload))
|
||||
permissions = file_.webext_permissions
|
||||
assert len(permissions) == 3
|
||||
# One permission is known so will have a description, etc.
|
||||
alarm = permissions['alarms']
|
||||
assert alarm.description == (
|
||||
u'Gives the extension access to the chrome.alarms API.')
|
||||
assert u'Gives the extension access to the chrome.alarms API.' in (
|
||||
alarm.long_description)
|
||||
known_permissions = file_.webext_permissions_known
|
||||
assert len(known_permissions) == 1
|
||||
known_permissions[0] = alarm
|
||||
# The other two permissions stored are just urls.
|
||||
assert permissions[u'http://*/*']
|
||||
assert permissions[u'https://*/*']
|
||||
parsed_data=parsed_data)
|
||||
permissions_list = file_.webext_permissions_list
|
||||
assert len(permissions_list) == 5
|
||||
assert permissions_list == [u'http://*/*', u'https://*/*', 'bookmarks',
|
||||
'made up permission', 'https://google.com/'
|
||||
]
|
||||
|
||||
|
||||
class TestZip(TestCase, amo.tests.AMOPaths):
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO waffle_switch (name, active, note, created, modified)
|
||||
VALUES ('webext-permissions', 0, 'Display permissions popup for webextensions on Add-on detail page.', NOW(), NOW());
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from django.conf.urls import include, url
|
||||
|
||||
from rest_framework.routers import SimpleRouter
|
||||
|
||||
from olympia.reviews.views import ReviewViewSet
|
||||
|
||||
|
||||
reviews = SimpleRouter()
|
||||
reviews.register(r'review', ReviewViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'', include(reviews.urls))
|
||||
]
|
|
@ -48,10 +48,16 @@ class BaseReviewSerializer(serializers.ModelSerializer):
|
|||
|
||||
data['user_responsible'] = request.user
|
||||
|
||||
# There are a few fields that need to be set at creation time and never
|
||||
# modified afterwards:
|
||||
if not self.partial:
|
||||
# Get the add-on pk from the URL, no need to pass it as POST data
|
||||
# since the URL is always going to have it.
|
||||
# Because we want to avoid extra queries, addon is a
|
||||
# SerializerMethodField, which means it needs to be validated
|
||||
# manually. Fortunately the view does most of the work for us.
|
||||
data['addon'] = self.context['view'].get_addon_object()
|
||||
if data['addon'] is None:
|
||||
raise serializers.ValidationError(
|
||||
{'addon': _('This field is required.')})
|
||||
|
||||
# Get the user from the request, don't allow clients to pick one
|
||||
# themselves.
|
||||
|
@ -59,6 +65,12 @@ class BaseReviewSerializer(serializers.ModelSerializer):
|
|||
|
||||
# Also include the user ip adress.
|
||||
data['ip_address'] = request.META.get('REMOTE_ADDR', '')
|
||||
else:
|
||||
# When editing, you can't change the add-on.
|
||||
if self.context['request'].data.get('addon'):
|
||||
raise serializers.ValidationError(
|
||||
{'addon': _(u"You can't change the add-on of a review once"
|
||||
u" it has been created.")})
|
||||
|
||||
# Clean up body and automatically flag the review if an URL was in it.
|
||||
body = data.get('body', '')
|
||||
|
@ -121,7 +133,6 @@ class ReviewVersionSerializer(SimpleVersionSerializer):
|
|||
class ReviewSerializer(BaseReviewSerializer):
|
||||
reply = ReviewSerializerReply(read_only=True)
|
||||
rating = serializers.IntegerField(min_value=1, max_value=5)
|
||||
|
||||
version = ReviewVersionSerializer()
|
||||
|
||||
class Meta:
|
||||
|
@ -136,6 +147,10 @@ class ReviewSerializer(BaseReviewSerializer):
|
|||
u"the review has been created."))
|
||||
|
||||
addon = self.context['view'].get_addon_object()
|
||||
if not addon:
|
||||
# BaseReviewSerializer.validate() should complain about that, not
|
||||
# this method.
|
||||
return None
|
||||
if version.addon_id != addon.pk or not version.is_public():
|
||||
raise serializers.ValidationError(
|
||||
_(u"This version of the add-on doesn't exist or isn't "
|
||||
|
|
|
@ -7,8 +7,6 @@ from django.core.urlresolvers import reverse
|
|||
|
||||
import mock
|
||||
from pyquery import PyQuery as pq
|
||||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
from olympia import amo
|
||||
from olympia.addons.utils import generate_addon_guid
|
||||
|
@ -19,7 +17,6 @@ from olympia.amo.tests import (
|
|||
from olympia.access.models import Group, GroupUser
|
||||
from olympia.addons.models import Addon, AddonUser
|
||||
from olympia.devhub.models import ActivityLog
|
||||
from olympia.reviews.views import ReviewViewSet
|
||||
from olympia.reviews.models import Review, ReviewFlag
|
||||
from olympia.users.models import UserProfile
|
||||
|
||||
|
@ -718,10 +715,9 @@ class TestReviewViewSetGet(TestCase):
|
|||
def setUp(self):
|
||||
self.addon = addon_factory(
|
||||
guid=generate_addon_guid(), name=u'My Addôn', slug='my-addon')
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.pk})
|
||||
self.url = reverse('review-list')
|
||||
|
||||
def test_list(self, **kwargs):
|
||||
def test_list_addon(self, **kwargs):
|
||||
review1 = Review.objects.create(
|
||||
addon=self.addon, body='review 1', user=user_factory(),
|
||||
rating=1)
|
||||
|
@ -755,7 +751,9 @@ class TestReviewViewSetGet(TestCase):
|
|||
|
||||
assert Review.unfiltered.count() == 6
|
||||
|
||||
response = self.client.get(self.url, kwargs)
|
||||
params = {'addon': self.addon.pk}
|
||||
params.update(kwargs)
|
||||
response = self.client.get(self.url, params)
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 2
|
||||
|
@ -765,7 +763,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
assert data['results'][1]['id'] == review1.pk
|
||||
return data
|
||||
|
||||
def test_list_queries(self):
|
||||
def test_list_addon_queries(self):
|
||||
version1 = self.addon.current_version
|
||||
version2 = version_factory(addon=self.addon)
|
||||
review1 = Review.objects.create(
|
||||
|
@ -800,7 +798,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
with mock.patch('olympia.reviews.views.ReviewViewSet'
|
||||
'.get_addon_object') as get_addon_object:
|
||||
get_addon_object.return_value = self.addon
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 3
|
||||
|
@ -810,7 +808,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
assert data['results'][1]['body'] == review2.body
|
||||
assert data['results'][2]['body'] == review1.body
|
||||
|
||||
def test_list_queries_with_replies(self):
|
||||
def test_list_addon_queries_with_replies(self):
|
||||
version1 = self.addon.current_version
|
||||
version2 = version_factory(addon=self.addon)
|
||||
review1 = Review.objects.create(
|
||||
|
@ -852,7 +850,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
with mock.patch('olympia.reviews.views.ReviewViewSet'
|
||||
'.get_addon_object') as get_addon_object:
|
||||
get_addon_object.return_value = self.addon
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 3
|
||||
|
@ -865,40 +863,34 @@ class TestReviewViewSetGet(TestCase):
|
|||
assert data['results'][2]['body'] == review1.body
|
||||
assert data['results'][2]['reply']['body'] == reply1.body
|
||||
|
||||
def test_list_grouped_ratings(self):
|
||||
data = self.test_list(show_grouped_ratings=1)
|
||||
def test_list_addon_grouped_ratings(self):
|
||||
data = self.test_list_addon(show_grouped_ratings=1)
|
||||
assert data['grouped_ratings']['1'] == 1
|
||||
assert data['grouped_ratings']['2'] == 1
|
||||
assert data['grouped_ratings']['3'] == 0
|
||||
assert data['grouped_ratings']['4'] == 0
|
||||
assert data['grouped_ratings']['5'] == 0
|
||||
|
||||
def test_list_unknown_addon(self, **kwargs):
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.pk + 42})
|
||||
response = self.client.get(self.url, kwargs)
|
||||
def test_list_addon_unknown(self, **kwargs):
|
||||
params = {'addon': self.addon.pk + 42}
|
||||
params.update(kwargs)
|
||||
response = self.client.get(self.url, params)
|
||||
assert response.status_code == 404
|
||||
data = json.loads(response.content)
|
||||
return data
|
||||
|
||||
def test_list_grouped_ratings_unknown_addon_not_present(self):
|
||||
data = self.test_list_unknown_addon(show_grouped_ratings=1)
|
||||
def test_list_addon_grouped_ratings_unknown_addon_not_present(self):
|
||||
data = self.test_list_addon_unknown(show_grouped_ratings=1)
|
||||
assert 'grouped_ratings' not in data
|
||||
|
||||
def test_list_addon_guid(self):
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.guid})
|
||||
self.test_list()
|
||||
self.test_list_addon(addon_pk=self.addon.guid)
|
||||
|
||||
def test_list_addon_slug(self):
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.slug})
|
||||
self.test_list()
|
||||
self.test_list_addon(addon_pk=self.addon.slug)
|
||||
|
||||
def test_list_user(self, **kwargs):
|
||||
self.user = user_factory()
|
||||
self.url = reverse(
|
||||
'account-review-list', kwargs={'account_pk': self.user.pk})
|
||||
review1 = Review.objects.create(
|
||||
addon=self.addon, body='review 1', user=self.user)
|
||||
review2 = Review.objects.create(
|
||||
|
@ -920,7 +912,9 @@ class TestReviewViewSetGet(TestCase):
|
|||
|
||||
assert Review.unfiltered.count() == 5
|
||||
|
||||
response = self.client.get(self.url, kwargs)
|
||||
params = {'user': self.user.pk}
|
||||
params.update(kwargs)
|
||||
response = self.client.get(self.url, params)
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 3
|
||||
|
@ -931,26 +925,55 @@ class TestReviewViewSetGet(TestCase):
|
|||
assert data['results'][2]['id'] == review2.pk
|
||||
return data
|
||||
|
||||
def test_list_addon_and_user(self):
|
||||
self.user = user_factory()
|
||||
old_review = Review.objects.create(
|
||||
addon=self.addon, body='old review', user=self.user)
|
||||
old_review.update(created=self.days_ago(42))
|
||||
recent_review = Review.objects.create(
|
||||
addon=self.addon, body='recent review', user=self.user)
|
||||
# None of those extra reviews should show up.
|
||||
review_deleted = Review.objects.create(
|
||||
addon=self.addon, body='review deleted', user=self.user)
|
||||
review_deleted.delete()
|
||||
other_review = Review.objects.create(
|
||||
addon=addon_factory(), body='review from other user',
|
||||
user=user_factory())
|
||||
Review.objects.create(
|
||||
addon=other_review.addon, body='reply to other user',
|
||||
reply_to=other_review, user=self.user) # right user, wrong addon.
|
||||
Review.objects.create(
|
||||
addon=addon_factory(), body='review from other addon',
|
||||
user=self.user)
|
||||
|
||||
assert Review.unfiltered.count() == 6
|
||||
|
||||
# Since we're filtering on both addon and user, only the most recent
|
||||
# review from self.user on self.addon should show up.
|
||||
params = {'addon': self.addon.pk, 'user': self.user.pk}
|
||||
response = self.client.get(self.url, params)
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 1
|
||||
assert data['results']
|
||||
assert len(data['results']) == 1
|
||||
assert data['results'][0]['id'] == recent_review.pk
|
||||
|
||||
def test_list_user_grouped_ratings_not_present(self):
|
||||
return
|
||||
data = self.test_list_user(show_grouped_ratings=1)
|
||||
assert 'grouped_ratings' not in data
|
||||
|
||||
def test_list_no_user_or_addon(self):
|
||||
# We have a fallback in get_queryset() to avoid listing all reviews on
|
||||
# the website if somehow we messed up the if conditions. It should not
|
||||
# be possible to reach it, but test it by forcing the instantiation of
|
||||
# the viewset with no kwargs other than action='list'.
|
||||
view = ReviewViewSet(action='list', kwargs={},
|
||||
request=APIRequestFactory().get('/'))
|
||||
with self.assertRaises(ParseError):
|
||||
view.filter_queryset(view.get_queryset())
|
||||
def test_list_no_addon_or_user_present(self):
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.content)
|
||||
assert data['detail'] == 'Need an addon or user parameter'
|
||||
|
||||
def test_detail(self):
|
||||
review = Review.objects.create(
|
||||
addon=self.addon, body='review 1', user=user_factory())
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': review.pk})
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
|
@ -963,9 +986,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
reply = Review.objects.create(
|
||||
addon=self.addon, body='reply to review', user=user_factory(),
|
||||
reply_to=review)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': reply.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': reply.pk})
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
|
@ -975,9 +996,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
def test_detail_deleted(self):
|
||||
review = Review.objects.create(
|
||||
addon=self.addon, body='review 1', user=user_factory())
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': review.pk})
|
||||
review.delete()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
|
@ -990,9 +1009,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
addon=self.addon, body='reply to review', user=user_factory(),
|
||||
reply_to=review)
|
||||
reply.delete()
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': review.pk})
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
|
@ -1011,9 +1028,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
reply_to=review)
|
||||
reply.delete()
|
||||
review.delete()
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': review.pk})
|
||||
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
|
@ -1050,7 +1065,7 @@ class TestReviewViewSetGet(TestCase):
|
|||
|
||||
assert Review.unfiltered.count() == 6
|
||||
|
||||
response = self.client.get(self.url)
|
||||
response = self.client.get(self.url, {'addon': self.addon.pk})
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 2
|
||||
|
@ -1091,7 +1106,8 @@ class TestReviewViewSetGet(TestCase):
|
|||
|
||||
assert Review.unfiltered.count() == 6
|
||||
|
||||
response = self.client.get(self.url, data={'filter': 'with_deleted'})
|
||||
response = self.client.get(
|
||||
self.url, {'addon': self.addon.pk, 'filter': 'with_deleted'})
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.content)
|
||||
assert data['count'] == 3
|
||||
|
@ -1115,9 +1131,7 @@ class TestReviewViewSetDelete(TestCase):
|
|||
self.review = Review.objects.create(
|
||||
addon=self.addon, version=self.addon.current_version, rating=1,
|
||||
body='My review', user=self.user)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': self.review.pk})
|
||||
|
||||
def test_delete_anonymous(self):
|
||||
response = self.client.delete(self.url)
|
||||
|
@ -1170,9 +1184,7 @@ class TestReviewViewSetDelete(TestCase):
|
|||
reply = Review.objects.create(
|
||||
addon=self.addon, reply_to=self.review,
|
||||
body=u'Reply that will be delêted...', user=addon_author)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': reply.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': reply.pk})
|
||||
|
||||
response = self.client.delete(self.url)
|
||||
assert response.status_code == 204
|
||||
|
@ -1181,9 +1193,7 @@ class TestReviewViewSetDelete(TestCase):
|
|||
|
||||
def test_delete_404(self):
|
||||
self.client.login_api(self.user)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk + 42})
|
||||
self.url = reverse('review-detail', kwargs={'pk': self.review.pk + 42})
|
||||
response = self.client.delete(self.url)
|
||||
assert response.status_code == 404
|
||||
assert Review.objects.count() == 1
|
||||
|
@ -1199,9 +1209,7 @@ class TestReviewViewSetEdit(TestCase):
|
|||
self.review = Review.objects.create(
|
||||
addon=self.addon, version=self.addon.current_version, rating=1,
|
||||
body=u'My revïew', title=u'Titlé', user=self.user)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': self.review.pk})
|
||||
|
||||
def test_edit_anonymous(self):
|
||||
response = self.client.patch(self.url, {'body': u'løl!'})
|
||||
|
@ -1268,6 +1276,15 @@ class TestReviewViewSetEdit(TestCase):
|
|||
u"You can't change the version of the add-on reviewed once "
|
||||
u"the review has been created."]
|
||||
|
||||
def test_edit_dont_allow_addon_to_be_edited(self):
|
||||
self.client.login_api(self.user)
|
||||
new_addon = addon_factory()
|
||||
response = self.client.patch(self.url, {'addon': new_addon.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['addon'] == [
|
||||
u"You can't change the add-on of a review once it has been "
|
||||
u"created."]
|
||||
|
||||
def test_edit_admin(self):
|
||||
original_review_user = self.review.user
|
||||
admin_user = user_factory(username='mylittleadmin')
|
||||
|
@ -1300,9 +1317,7 @@ class TestReviewViewSetEdit(TestCase):
|
|||
reply = Review.objects.create(
|
||||
reply_to=self.review, body=u'This is â reply', user=addon_author,
|
||||
addon=self.addon)
|
||||
self.url = reverse(
|
||||
'addon-review-detail',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': reply.pk})
|
||||
self.url = reverse('review-detail', kwargs={'pk': reply.pk})
|
||||
|
||||
response = self.client.patch(self.url, {'rating': 5})
|
||||
assert response.status_code == 200
|
||||
|
@ -1326,20 +1341,31 @@ class TestReviewViewSetPost(TestCase):
|
|||
def setUp(self):
|
||||
self.addon = addon_factory(
|
||||
guid=generate_addon_guid(), name=u'My Addôn', slug='my-addon')
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.pk})
|
||||
self.url = reverse('review-list')
|
||||
|
||||
def test_post_anonymous(self):
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5})
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_post_no_addon(self):
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['addon'] == [u'This field is required.']
|
||||
|
||||
def test_post_no_version(self):
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5})
|
||||
assert response.status_code == 400
|
||||
assert response.data['version'] == [u'This field is required.']
|
||||
|
||||
|
@ -1348,8 +1374,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.version})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': self.addon.current_version.version})
|
||||
assert response.status_code == 400
|
||||
assert response.data['version'] == [
|
||||
'Incorrect type. Expected pk value, received unicode.']
|
||||
|
@ -1361,8 +1387,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': u'blahé', 'rating': 5,
|
||||
'version': self.addon.current_version.pk},
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': u'blahé',
|
||||
'rating': 5, 'version': self.addon.current_version.pk},
|
||||
REMOTE_ADDR='213.225.312.5')
|
||||
assert response.status_code == 201
|
||||
review = Review.objects.latest('pk')
|
||||
|
@ -1398,8 +1424,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
body = u'Trying to spam <br> http://éxample.com'
|
||||
cleaned_body = u'Trying to spam \n http://éxample.com'
|
||||
response = self.client.post(self.url, {
|
||||
'body': body, 'title': u'blahé', 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': body, 'title': u'blahé',
|
||||
'rating': 5, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 201
|
||||
review = Review.objects.latest('pk')
|
||||
assert review.pk == response.data['id']
|
||||
|
@ -1422,8 +1448,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 4.5,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 4.5, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['rating'] == ['A valid integer is required.']
|
||||
|
||||
|
@ -1432,8 +1458,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 6,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 6, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['rating'] == [
|
||||
'Ensure this value is less than or equal to 5.']
|
||||
|
@ -1443,8 +1469,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 0,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 0, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['rating'] == [
|
||||
'Ensure this value is greater than or equal to 1.']
|
||||
|
@ -1454,8 +1480,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 201
|
||||
review = Review.objects.latest('pk')
|
||||
assert review.pk == response.data['id']
|
||||
|
@ -1477,7 +1503,7 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': None, 'title': None, 'rating': 5,
|
||||
'addon': self.addon.pk, 'body': None, 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 201
|
||||
review = Review.objects.latest('pk')
|
||||
|
@ -1501,7 +1527,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'rating': 5, 'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 201
|
||||
review = Review.objects.latest('pk')
|
||||
assert review.pk == response.data['id']
|
||||
|
@ -1524,30 +1551,26 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None,
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['rating'] == ['This field is required.']
|
||||
|
||||
def test_post_no_such_addon_id(self):
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.pk + 42})
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
response = self.client.post(self.url, {
|
||||
'body': 'test body', 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk + 42, 'body': 'test body', 'title': None,
|
||||
'rating': 5, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_post_version_not_linked_to_the_right_addon(self):
|
||||
addon2 = addon_factory()
|
||||
self.url = reverse(
|
||||
'addon-review-list', kwargs={'addon_pk': self.addon.pk})
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
response = self.client.post(self.url, {
|
||||
'body': 'test body', 'title': None, 'rating': 5,
|
||||
'version': addon2.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': 'test body', 'title': None,
|
||||
'rating': 5, 'version': addon2.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['version'] == [
|
||||
u"This version of the add-on doesn't exist or isn't public."]
|
||||
|
@ -1559,8 +1582,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': version_pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': version_pk})
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_post_deleted_version(self):
|
||||
|
@ -1577,8 +1600,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': old_version_pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': old_version_pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['version'] == [
|
||||
u"This version of the add-on doesn't exist or isn't public."]
|
||||
|
@ -1595,8 +1618,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': old_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': old_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['version'] == [
|
||||
u"This version of the add-on doesn't exist or isn't public."]
|
||||
|
@ -1608,8 +1631,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': version_pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': version_pk})
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_post_logged_in_but_is_addon_author(self):
|
||||
|
@ -1618,8 +1641,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
self.client.login_api(self.user)
|
||||
assert not Review.objects.exists()
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'test bodyé', 'title': None, 'rating': 5,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'test bodyé', 'title': None,
|
||||
'rating': 5, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['non_field_errors'] == [
|
||||
"You can't leave a review on your own add-on."]
|
||||
|
@ -1632,8 +1655,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
body='My review', user=self.user)
|
||||
second_version = version_factory(addon=self.addon)
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'My ôther review', 'title': None, 'rating': 2,
|
||||
'version': second_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'My ôther review', 'title': None,
|
||||
'rating': 2, 'version': second_version.pk})
|
||||
assert response.status_code == 201
|
||||
assert Review.objects.count() == 2
|
||||
|
||||
|
@ -1645,8 +1668,8 @@ class TestReviewViewSetPost(TestCase):
|
|||
addon=self.addon, version=self.addon.current_version, rating=1,
|
||||
body='My review', user=self.user)
|
||||
response = self.client.post(self.url, {
|
||||
'body': u'My ôther review', 'title': None, 'rating': 2,
|
||||
'version': self.addon.current_version.pk})
|
||||
'addon': self.addon.pk, 'body': u'My ôther review', 'title': None,
|
||||
'rating': 2, 'version': self.addon.current_version.pk})
|
||||
assert response.status_code == 400
|
||||
assert response.data['non_field_errors'] == [
|
||||
u"You can't leave more than one review for the same version of "
|
||||
|
@ -1663,9 +1686,11 @@ class TestReviewViewSetFlag(TestCase):
|
|||
self.review = Review.objects.create(
|
||||
addon=self.addon, version=self.addon.current_version, rating=1,
|
||||
body='My review', user=self.review_user)
|
||||
self.url = reverse(
|
||||
'addon-review-flag',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk})
|
||||
self.url = reverse('review-flag', kwargs={'pk': self.review.pk})
|
||||
|
||||
def test_url(self):
|
||||
expected_url = '/api/v3/reviews/review/%d/flag/' % self.review.pk
|
||||
assert self.url == expected_url
|
||||
|
||||
def test_flag_anonymous(self):
|
||||
response = self.client.post(self.url)
|
||||
|
@ -1797,13 +1822,10 @@ class TestReviewViewSetReply(TestCase):
|
|||
self.review = Review.objects.create(
|
||||
addon=self.addon, version=self.addon.current_version, rating=1,
|
||||
body='My review', user=self.review_user)
|
||||
self.url = reverse(
|
||||
'addon-review-reply',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk})
|
||||
self.url = reverse('review-reply', kwargs={'pk': self.review.pk})
|
||||
|
||||
def test_url(self):
|
||||
expected_url = '/api/v3/addons/addon/%d/reviews/%d/reply/' % (
|
||||
self.addon.pk, self.review.pk)
|
||||
expected_url = '/api/v3/reviews/review/%d/reply/' % self.review.pk
|
||||
assert self.url == expected_url
|
||||
|
||||
def test_get_method_not_allowed(self):
|
||||
|
@ -1826,9 +1848,7 @@ class TestReviewViewSetReply(TestCase):
|
|||
self.addon_author = user_factory()
|
||||
self.addon.addonuser_set.create(user=self.addon_author)
|
||||
self.client.login_api(self.addon_author)
|
||||
self.url = reverse(
|
||||
'addon-review-reply',
|
||||
kwargs={'addon_pk': self.addon.pk, 'pk': self.review.pk + 42})
|
||||
self.url = reverse('review-reply', kwargs={'pk': self.review.pk + 42})
|
||||
response = self.client.post(self.url, data={})
|
||||
assert response.status_code == 404
|
||||
|
||||
|
|
|
@ -1,32 +1,28 @@
|
|||
from django.conf.urls import include, patterns, url
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from olympia.reviews.feeds import ReviewsRss
|
||||
|
||||
from . import views
|
||||
|
||||
|
||||
def review_detail_patterns(prefix):
|
||||
# These all start with /addon/:id/reviews/:review_id/.
|
||||
return patterns(
|
||||
'',
|
||||
url('^$', views.review_list, name='%s.reviews.detail' % prefix),
|
||||
url('^reply$', views.reply, name='%s.reviews.reply' % prefix),
|
||||
url('^flag$', views.flag, name='%s.reviews.flag' % prefix),
|
||||
url('^delete$', views.delete, name='%s.reviews.delete' % prefix),
|
||||
url('^edit$', views.edit, name='%s.reviews.edit' % prefix),
|
||||
url('^translate/(?P<language>[a-z]{2,3}(-[A-Z]{2})?)$',
|
||||
views.translate,
|
||||
name='%s.reviews.translate' % prefix),
|
||||
)
|
||||
# These all start with /addon/:id/reviews/:review_id/.
|
||||
review_detail_patterns = [
|
||||
url('^$', views.review_list, name='addons.reviews.detail'),
|
||||
url('^reply$', views.reply, name='addons.reviews.reply'),
|
||||
url('^flag$', views.flag, name='addons.reviews.flag'),
|
||||
url('^delete$', views.delete, name='addons.reviews.delete'),
|
||||
url('^edit$', views.edit, name='addons.reviews.edit'),
|
||||
url('^translate/(?P<language>[a-z]{2,3}(-[A-Z]{2})?)$',
|
||||
views.translate,
|
||||
name='addons.reviews.translate'),
|
||||
]
|
||||
|
||||
|
||||
def review_patterns(prefix):
|
||||
return patterns(
|
||||
'',
|
||||
url('^$', views.review_list, name='%s.reviews.list' % prefix),
|
||||
url('^add$', views.add, name='%s.reviews.add' % prefix),
|
||||
url('^(?P<review_id>\d+)/', include(review_detail_patterns(prefix))),
|
||||
url('^format:rss$', ReviewsRss(), name='%s.reviews.list.rss' % prefix),
|
||||
url('^user:(?P<user_id>\d+)$', views.review_list,
|
||||
name='%s.reviews.user' % prefix),
|
||||
)
|
||||
urlpatterns = [
|
||||
url('^$', views.review_list, name='addons.reviews.list'),
|
||||
url('^add$', views.add, name='addons.reviews.add'),
|
||||
url('^(?P<review_id>\d+)/', include(review_detail_patterns)),
|
||||
url('^format:rss$', ReviewsRss(), name='addons.reviews.list.rss'),
|
||||
url('^user:(?P<user_id>\d+)$', views.review_list,
|
||||
name='addons.reviews.user'),
|
||||
]
|
||||
|
|
|
@ -327,9 +327,38 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
|
||||
queryset = Review.objects.all()
|
||||
|
||||
def set_addon_object_from_review(self, review):
|
||||
"""Set addon object on the instance from a review object."""
|
||||
# At this point it's likely we didn't have an addon in the request, so
|
||||
# if we went through get_addon_object() before it's going to be set
|
||||
# to None already. We delete the addon_object property cache and set
|
||||
# addon_pk in kwargs to force get_addon_object() to reset
|
||||
# self.addon_object.
|
||||
del self.addon_object
|
||||
self.kwargs['addon_pk'] = str(review.addon.pk)
|
||||
return self.get_addon_object()
|
||||
|
||||
def get_addon_object(self):
|
||||
"""Return addon object associated with the request, or None if not
|
||||
relevant.
|
||||
|
||||
Will also fire permission checks on the addon object when it's loaded.
|
||||
"""
|
||||
if hasattr(self, 'addon_object'):
|
||||
return self.addon_object
|
||||
|
||||
if 'addon_pk' not in self.kwargs:
|
||||
return None
|
||||
self.kwargs['addon_pk'] = (
|
||||
self.request.data.get('addon') or
|
||||
self.request.GET.get('addon'))
|
||||
if self.kwargs['addon_pk'] is None:
|
||||
# If we don't have an addon object, set it as None on the instance
|
||||
# and return immediately, that's fine.
|
||||
self.addon_object = None
|
||||
return
|
||||
else:
|
||||
# AddonViewSet.get_lookup_field() expects a string.
|
||||
self.kwargs['addon_pk'] = str(self.kwargs['addon_pk'])
|
||||
# When loading the add-on, pass a specific permission class - the
|
||||
# default from AddonViewSet is too restrictive, we are not modifying
|
||||
# the add-on itself so we don't need all the permission checks it does.
|
||||
|
@ -337,12 +366,12 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
permission_classes=[AllowIfPublic])
|
||||
|
||||
def check_permissions(self, request):
|
||||
if 'addon_pk' in self.kwargs:
|
||||
# In addition to the regular permission checks that are made, we
|
||||
# need to verify that the add-on exists, is public and listed. Just
|
||||
# loading the addon should be enough to do that, since
|
||||
# AddonChildMixin implementation calls AddonViewSet.get_object().
|
||||
self.get_addon_object()
|
||||
"""Perform permission checks.
|
||||
|
||||
The regular DRF permissions checks are made, but also, before that, if
|
||||
an addon was requested, verify that it exists, is public and listed,
|
||||
through AllowIfPublic permission, that get_addon_object() uses."""
|
||||
self.get_addon_object()
|
||||
|
||||
# Proceed with the regular permission checks.
|
||||
return super(ReviewViewSet, self).check_permissions(request)
|
||||
|
@ -357,20 +386,21 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
|
||||
def filter_queryset(self, qs):
|
||||
if self.action == 'list':
|
||||
if 'addon_pk' in self.kwargs:
|
||||
if 'addon' in self.request.GET:
|
||||
qs = qs.filter(is_latest=True, addon=self.get_addon_object())
|
||||
elif 'account_pk' in self.kwargs:
|
||||
qs = qs.filter(user=self.kwargs.get('account_pk'))
|
||||
else:
|
||||
if 'user' in self.request.GET:
|
||||
qs = qs.filter(user=self.request.GET.get('user'))
|
||||
if ('addon' not in self.request.GET and
|
||||
'user' not in self.request.GET):
|
||||
# Don't allow listing reviews without filtering by add-on or
|
||||
# user.
|
||||
raise ParseError('Need an addon or user identifier')
|
||||
raise ParseError('Need an addon or user parameter')
|
||||
return qs
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
response = super(ReviewViewSet, self).get_paginated_response(data)
|
||||
show_grouped_ratings = self.request.GET.get('show_grouped_ratings')
|
||||
if 'addon_pk' in self.kwargs and show_grouped_ratings:
|
||||
if show_grouped_ratings and self.get_addon_object():
|
||||
response.data['grouped_ratings'] = dict(GroupedRating.get(
|
||||
self.addon_object.id))
|
||||
return response
|
||||
|
@ -387,7 +417,7 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
acl.action_allowed(self.request, 'Addons', 'Edit'))
|
||||
|
||||
should_access_only_top_level_reviews = (
|
||||
self.action == 'list' and self.kwargs.get('addon_pk'))
|
||||
self.action == 'list' and self.get_addon_object())
|
||||
|
||||
if self.should_access_deleted_reviews:
|
||||
# For admins or add-on authors replying. When listing, we include
|
||||
|
@ -423,6 +453,7 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
# FK to the current review object and only allow add-on authors/admins.
|
||||
# Call get_object() to trigger 404 if it does not exist.
|
||||
self.review_object = self.get_object()
|
||||
self.set_addon_object_from_review(self.review_object)
|
||||
if Review.unfiltered.filter(reply_to=self.review_object).exists():
|
||||
# A reply already exists, just edit it.
|
||||
# We set should_access_deleted_reviews so that it works even if
|
||||
|
@ -434,14 +465,18 @@ class ReviewViewSet(AddonChildMixin, ModelViewSet):
|
|||
|
||||
@detail_route(methods=['post'])
|
||||
def flag(self, request, *args, **kwargs):
|
||||
# We load the add-on object from the review to trigger permission
|
||||
# checks.
|
||||
self.review_object = self.get_object()
|
||||
self.set_addon_object_from_review(self.review_object)
|
||||
|
||||
# Re-use flag view since it's already returning json. We just need to
|
||||
# pass it the addon slug (passing it the PK would result in a redirect)
|
||||
# and make sure request.POST is set with whatever data was sent to the
|
||||
# DRF view.
|
||||
addon = self.get_addon_object()
|
||||
request._request.POST = request.data
|
||||
request = request._request
|
||||
response = flag(request, addon.slug, kwargs.get('pk'))
|
||||
response = flag(request, self.addon_object.slug, kwargs.get('pk'))
|
||||
if response.status_code == 200:
|
||||
response.content = ''
|
||||
response.status_code = 202
|
||||
|
|
|
@ -242,6 +242,42 @@ class TestUploadVersion(BaseUploadVersionCase):
|
|||
assert response.data['error'] == (
|
||||
'You cannot submit this type of add-on')
|
||||
|
||||
def test_system_addon_allowed(self):
|
||||
guid = 'systemaddon@mozilla.org'
|
||||
self.user.update(email='redpanda@mozilla.com')
|
||||
qs = Addon.unfiltered.filter(guid=guid)
|
||||
assert not qs.exists()
|
||||
response = self.request(
|
||||
'PUT',
|
||||
addon=guid, version='0.0.1',
|
||||
filename='src/olympia/files/fixtures/files/'
|
||||
'mozilla_guid.xpi')
|
||||
assert response.status_code == 201
|
||||
assert qs.exists()
|
||||
addon = qs.get()
|
||||
assert addon.has_author(self.user)
|
||||
assert addon.status == amo.STATUS_NULL
|
||||
latest_version = addon.find_latest_version(
|
||||
channel=amo.RELEASE_CHANNEL_UNLISTED)
|
||||
assert latest_version
|
||||
assert latest_version.channel == amo.RELEASE_CHANNEL_UNLISTED
|
||||
self.auto_sign_version.assert_called_with(
|
||||
latest_version, is_beta=False)
|
||||
|
||||
def test_system_addon_not_allowed_not_mozilla(self):
|
||||
guid = 'systemaddon@mozilla.org'
|
||||
self.user.update(email='yellowpanda@notzilla.com')
|
||||
qs = Addon.unfiltered.filter(guid=guid)
|
||||
assert not qs.exists()
|
||||
response = self.request(
|
||||
'PUT',
|
||||
addon=guid, version='0.1',
|
||||
filename='src/olympia/files/fixtures/files/'
|
||||
'telemetry_experiment.xpi')
|
||||
assert response.status_code == 400
|
||||
assert response.data['error'] == (
|
||||
'You cannot submit this type of add-on')
|
||||
|
||||
def test_version_is_beta_unlisted(self):
|
||||
addon = Addon.objects.get(guid=self.guid)
|
||||
self.make_addon_unlisted(addon)
|
||||
|
|
|
@ -18,6 +18,7 @@ from olympia.api.authentication import JWTKeyAuthentication
|
|||
from olympia.devhub.views import handle_upload
|
||||
from olympia.files.models import FileUpload
|
||||
from olympia.files.utils import parse_addon
|
||||
from olympia.users.utils import system_addon_submission_allowed
|
||||
from olympia.versions import views as version_views
|
||||
from olympia.versions.models import Version
|
||||
from olympia.signing.serializers import FileUploadSerializer
|
||||
|
@ -130,6 +131,12 @@ class VersionView(APIView):
|
|||
_(u'You cannot submit this type of add-on'),
|
||||
status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not system_addon_submission_allowed(request.user, pkg):
|
||||
raise forms.ValidationError(
|
||||
_(u'You cannot submit an add-on with a guid ending '
|
||||
u'"@mozilla.org"'),
|
||||
status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if addon is not None and addon.status == amo.STATUS_DISABLED:
|
||||
raise forms.ValidationError(
|
||||
_('You cannot add versions to an addon that has status: %s.' %
|
||||
|
|
|
@ -81,3 +81,10 @@ def autocreate_username(candidate, tries=1):
|
|||
if UserProfile.objects.filter(username=adjusted_u).count():
|
||||
return autocreate_username(candidate, tries=tries + 1)
|
||||
return adjusted_u
|
||||
|
||||
|
||||
def system_addon_submission_allowed(user, parsed_addon_data):
|
||||
guid = parsed_addon_data.get('guid') or ''
|
||||
return (
|
||||
not guid.endswith(u'@mozilla.org') or
|
||||
user.email.endswith(u'@mozilla.com'))
|
||||
|
|
|
@ -1356,6 +1356,7 @@ h3.author .transfer-ownership {
|
|||
h4.author a,
|
||||
a.eula,
|
||||
a.privacy-policy,
|
||||
a.webext-permissions,
|
||||
.notice h3,
|
||||
.notice p,
|
||||
.notice p a,
|
||||
|
@ -1370,6 +1371,7 @@ h3.author .transfer-ownership {
|
|||
|
||||
h4.author a,
|
||||
a.privacy-policy,
|
||||
a.webext-permissions,
|
||||
a.eula,
|
||||
.vital a,
|
||||
.warning a,
|
||||
|
@ -2571,3 +2573,30 @@ body.windows .install-shell .platform.mac {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.webext-permissions.badge {
|
||||
img {
|
||||
height: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
#webext-permissions {
|
||||
li {
|
||||
list-style: circle;
|
||||
list-style-position: inside;
|
||||
}
|
||||
.prose {
|
||||
h3 {
|
||||
font-size: larger
|
||||
}
|
||||
img {
|
||||
float: left;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.detailed {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
|
|
@ -159,6 +159,8 @@ $(function () {
|
|||
|
||||
if ($('#privacy-policy').exists())
|
||||
$('#privacy-policy').modal('.privacy-policy', { width: '500px' });
|
||||
if ($('#webext-permissions').exists())
|
||||
$('#webext-permissions').modal('.webext-permissions', { width: '500px' });
|
||||
|
||||
// Show add-on ID when icon is clicked
|
||||
if ($("#addon[data-id], #persona[data-id]").exists()) {
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
// Update the 'Search add-ons for <b>"{addon}"</b>' text.
|
||||
settings['$results'].find('p b').html(format('"{0}"',
|
||||
settings.searchTerm));
|
||||
|
||||
// Update the .sel link.
|
||||
var searchUrl = settings['$form'].attr('action') + '?q={0}';
|
||||
settings['$results'].find('.sel').attr('href', format(searchUrl,
|
||||
settings.urlSearchTerm));
|
||||
|
||||
var li_item = template(
|
||||
'<li><a href="{url}"><span {cls} {icon}>{name}</span>{subtitle}</a></li>'
|
||||
|
|
|
@ -130,12 +130,14 @@ $.fn.searchSuggestions = function($results, processCallback, searchType) {
|
|||
$results.filter('.visible').removeClass('visible');
|
||||
return;
|
||||
}
|
||||
var urlVal = encodeURIComponent($self.val());
|
||||
|
||||
// Required data to send to the callback.
|
||||
var settings = {
|
||||
'$results': $results,
|
||||
'$form': $form,
|
||||
'searchTerm': val
|
||||
'searchTerm': val,
|
||||
'urlSearchTerm': urlVal
|
||||
};
|
||||
|
||||
// Optional data for callback.
|
||||
|
|
Загрузка…
Ссылка в новой задаче