This commit is contained in:
Andrew Williamson 2019-04-01 11:02:38 +01:00 коммит произвёл GitHub
Родитель 4e2e5d4368
Коммит 01f267050b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
42 изменённых файлов: 33 добавлений и 2801 удалений

Просмотреть файл

@ -664,13 +664,11 @@ class Addon(OnChangeMixin, ModelBase):
return data
def get_url_path(self, more=False, add_prefix=True):
def get_url_path(self, add_prefix=True):
if not self.current_version:
return ''
# If more=True you get the link to the ajax'd middle chunk of the
# detail page.
view = 'addons.detail_more' if more else 'addons.detail'
return reverse(view, args=[self.slug], add_prefix=add_prefix)
return reverse(
'addons.detail', args=[self.slug], add_prefix=add_prefix)
def get_dev_url(self, action='edit', args=None, prefix_only=False):
args = args or []
@ -687,9 +685,6 @@ class Addon(OnChangeMixin, ModelBase):
args = []
return reverse('addons.%s' % action, args=[self.slug] + args)
def meet_the_dev_url(self):
return reverse('addons.meet', args=[self.slug])
@property
def ratings_url(self):
return reverse('addons.ratings.list', args=[self.slug])

Просмотреть файл

@ -5,7 +5,6 @@
<div class="install {{ button.install_class|join(' ') }}"
data-addon="{{ addon.id }}"
data-icon="{{ addon.get_icon_url(32) }}"
data-developers="{{ addon.meet_the_dev_url() }}"
data-versions="{{ url('addons.versions', addon.id) }}"
data-name="{{ addon.name }}"
{{ button.attrs()|xmlattr }}
@ -54,16 +53,6 @@
</div> {# install #}
{% if button.detailed %}
{% if addon.privacy_policy %}
<a class="privacy-policy" href="{{ url('addons.privacy', addon.slug) }}">
<strong>{{ _('View privacy policy') }}</strong>
</a>
{% endif %}
{% if addon.eula %}
<a class="eula" href="{{ url('addons.eula', addon.slug) }}">
<strong>{{ _('View End-User License Agreement') }}</strong>
</a>
{% endif %}
{% if addon.is_unreviewed() %}
<p class="warning">{% trans %}

Просмотреть файл

@ -1,35 +0,0 @@
{% extends "impala/base_side_categories.html" %}
{% from "addons/macros.html" import addon_heading %}
{% block title %}
{# L10n: {0} is the name of the add-on. #}
{{ page_title(_('End-User License Agreement for {0}')|format_html(addon.name)) }}
{% endblock %}
{% set addon_type = addon.type %}
{% set detail_url = addon.get_url_path() %}
{% block primary %}
<section class="primary" id="eula">
<hgroup class="hero">
{{ addon_heading(addon, version) }}
</hgroup>
<div class="prose">
<h2>{{ _('End-User License Agreement') }}</h2>
<p>
{% trans addon_name = addon.name %}
{{ addon_name }} requires that you accept the following
End-User License Agreement before installation can proceed:
{% endtrans %}
</p>
<div class="policy-statement">{{ addon.eula|nl2br }}</div>
<div class="policy-install">
{{ install_button(addon, version=version,
show_warning=False, impala=True) }}
</div>
<p class="policy-back">
<a href="{{ detail_url }}">{{ _('Back to {0}…')|format_html(addon.name) }}</a>
</p>
</div>
</section>
{% endblock %}

Просмотреть файл

@ -22,16 +22,6 @@
{% if button.detailed %}
<div class="detailed">
{% if addon.privacy_policy %}
<a class="privacy-policy badge" href="{{ url('addons.privacy', addon.slug) }}">
{{ _('Privacy Policy') }}
</a>
{% endif %}
{% if addon.eula %}
<a class="eula badge" href="{{ url('addons.eula', addon.slug) }}">
{{ _('End-User License Agreement') }}
</a>
{% endif %}
{% if addon.should_show_permissions(version) %}
<a class="webext-permissions badge" href="#">
{% if not version.all_files[0].is_webextension %}

Просмотреть файл

@ -1,67 +0,0 @@
{# The front of the detail page content is in details.html.
We want the above-the-fold portion to return and render really fast
so we pull in reviews and links to other add-ons with js.
This view returns a chunk of HTML that's injected into the DOM. #}
{% set version = addon.current_version %}
{% set reviews = reviews[:3] %}
<aside class="secondary addon-reviews c">
{% if reviews %}
<div>
{{ addon.average_rating|stars }}
{{ _('Average') }}
</div>
{% endif %}
{% include "ratings/grouped_ratings.html" %}
{% if addon.can_review(user) %}
<div>
<a class="button" id="add-review" href="{{ url('addons.ratings.add', addon.slug) }}">{{ _('Write a review') }}</a>
</div>
{% endif %}
<a id="report-abuse" href="{{ url('addons.abuse', addon.pk) }}"
class="abuse-image">{{ _('Report Abuse') }}</a>
</aside>
<section id="reviews" class="primary island c">
<h2>{{ _('Reviews') }}</h2>
{{ impala_review_list_box(addon=addon, reviews=reviews) }}
</section>
<aside id="related" class="secondary metadata c">
{% with categories = addon.categories.filter(application=APP.id) %}
{% if categories %}
<h3>{{ _('Related Categories') }}</h3>
<ul>
{% for category in categories %}
<li>
<a href="{{ category.get_url_path() }}">
{{ category }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{{ tags_box(addon=addon, tags=tags) }}
</aside>
{% if author_addons %}
<section class="primary island c">
{% if author_addons %}
<section id="author-addons">
<h2>
{% with count=addon.listed_authors|length,
author=users_list(addon.listed_authors) %}
{% trans count=count %}
Other add-ons by {{ author }}
{% pluralize %}
Other add-ons by these authors
{% endtrans %}
{% endwith %}
</h2>
{{ author_addons|addon_grid(cols=3, src='dp-hc-othersby',
dl_src='dp-dl-othersby') }}
</section>
{% endif %}
</section>
{% endif %}

Просмотреть файл

@ -1,329 +0,0 @@
{% extends "impala/base_shared.html" %}
{% from "addons/macros.html" import addon_flags %}
{% set is_author = request.check_ownership(addon, require_owner=False) %}
{% set is_reviewer = action_allowed(amo.permissions.ADDONS_REVIEW) %}
{% set is_admin = action_allowed(amo.permissions.REVIEWS_ADMIN) %}
{% block title %}{{ page_title(addon.name) }}{% endblock %}
{% block bodyclass %}gutter addon-details {{ super() }}{% endblock %}
{% block extrahead %}
{% if settings.ENGAGE_ROBOTS and addon.status == amo.STATUS_NOMINATED %}
<meta name="robots" content="noindex">
{% endif %}
<meta property="og:title" content="{{ addon.name }}">
<meta property="og:type" content="website">
<meta property="og:image" content="{{ addon.get_icon_url(64)|absolutify }}">
<meta property="og:url" content="{{ addon.get_url_path()|absolutify }}">
<meta property="og:description" content="{{ addon.summary|striptags }}">
{% endblock %}
{% block header_content %}
<div itemscope itemtype="http://schema.org/WebApplication">
<link itemprop="SoftwareApplicationCategory" href="http://schema.org/OtherApplication" />
<aside class="secondary addon-vitals">
{# This assumes we'll never charge for add-ons. Ha. #}
<span itemprop="offers" itemscope itemtype="http://schema.org/Offer">
<meta itemprop="price" content="$0" />
<meta itemprop="priceCurrency" content="USD" />
<link itemprop="availability" href="http://schema.org/InStock" />
</span>
<div itemprop="aggregateRating" itemscope="" itemtype="http://schema.org/AggregateRating">
<meta content="{{ addon.average_rating }}" itemprop="ratingValue">
{{ addon.average_rating|stars(large=True) }}
<div>
<a id="reviews-link" href="{{ addon.ratings_url }}">
{% trans cnt=addon.total_ratings, num=addon.total_ratings|numberfmt %}
<span itemprop="ratingCount">{{ num }}</span> user review
{% pluralize %}
<span itemprop="ratingCount">{{ num }}</span> user reviews
{% endtrans %}
</a>
</div>
</div>
{% if addon.show_adu() %}
{% set cnt = addon.average_daily_users %}
{% if cnt %}
{% set cnt_id = 'daily-users' %}
{% set cnt_pretty = ngettext(
'{0} user', '{0} users', cnt)|format_html(cnt|numberfmt) %}
{% endif %}
{% else %}
{% set cnt = addon.weekly_downloads %}
{% if cnt %}
{% set cnt_id = 'weekly-downloads' %}
{% set cnt_pretty = ngettext('{0} weekly download',
'{0} weekly downloads', cnt)|format_html(cnt|numberfmt) %}
{% endif %}
{% endif %}
{% if cnt %}
<div id="{{ cnt_id }}">
{% if addon.public_stats or is_author %}
<a class="stats" title="{{ _('View statistics') }}"
href="{{ url('stats.overview', addon.slug) }}">{{ cnt_pretty }}</a>
{% else %}
{{ cnt_pretty }}
{% endif %}
<meta itemprop="interactionCount" content="UserDownloads:{{ addon.total_downloads }}" />
</div>
{% endif %}
{% if is_author %}
<p class="manage-button"><a href="{{ addon.get_dev_url() }}" class="button developer prominent"><span>{{ _('Manage') }}</span></a></p>
{% endif %}
{% if is_reviewer %}
<p class="manage-button"><a href="{{ url('reviewers.review', addon.slug) }}" class="button"><span>{{ _('Add-on Review') }}</span></a></p>
{% endif %}
{% if is_admin %}
<p class="manage-button"><a href="{{ url('zadmin.addon_manage', addon.slug) }}" class="button"><span>{{ _('Admin Manage') }}</span></a></p>
{% endif %}
</aside>
{% set version = addon.current_version %}
{# All this depends on the addon or version, and nothing needs the user,
so we can cache it all against the addon. #}
<section class="primary addon-description-header">
<div id="addon" class="island c" role="main" data-id="{{ addon.id }}">
<hgroup>
{# L10n: {0} is an add-on name. #}
<img id="addon-icon" itemprop="image" src="{{ addon.get_icon_url(64) }}" class="icon" alt="{{ _('Icon of {0}')|format_html(addon.name) }}">
<h1 class="addon"{{ addon.name|locale_html }}>
<span itemprop="name">{{ addon.name }}</span>
{% if version %}
<span class="version-number" itemprop="version">{{ version.version }}</span>
{{ addon_flags(addon, version) }}
{% endif %}
</h1>
<h4 class="author">{{ _('by') }} {{ users_list(addon.listed_authors) }}</h4>
</hgroup>
<p id="addon-summary" itemprop="description" {{ addon.summary|locale_html }}>{{ addon.summary|nl2br }}</p>
{% if version %}
{{ big_install_button(addon, show_warning=False, impala=True) }}
{% endif %}
{% if addon.is_featured(APP, LANG) %}
<div class="banner-box">
<div class="banner featured">{{ _('Featured') }}</div>
</div>
{% endif %}
</div>
{% if addon.contributions %}
<div class="notice c author">
<div class="button-wrapper">
<a class="button contribute prominent" id="contribution-url-button"
target="_blank" rel="noopener"
href="{{ addon.contributions|external_url }}">
<b></b>{{ _('Contribute') }}
</a>
</div>
<h3>{{ _('Enjoy this add-on?') }}</h3>
<p>
{% trans %}
The developer of this add-on asks that you help support its
continued development by making a small contribution.
{% endtrans %}
</p>
</div>
{% endif %}
</section>
</div>
{% endblock header_content %}
{% block content %}
{% set version = addon.current_version %}
{% if addon.type != amo.ADDON_PERSONA %}
{% if addon.current_previews|length > 0 %}
<section class="previews">
<div class="carousel">
<a href="#" class="control prev">&laquo;</a>
<a href="#" class="control next">&raquo;</a>
<ul id="preview" class="slider">
{%- for preview in addon.current_previews -%}
<li class="panel">
<a class="screenshot thumbnail" rel="jquery-lightbox"
href="{{ preview.image_url }}" title="{{ preview.caption }}">
{# L10n: {0} is an index. #}
<img src="{{ preview.thumbnail_url }}" alt="{{ _('Add-on screenshot #{0}')|format_html(loop.index) }}">
</a>
</li>
{%- endfor -%}
</ul>
</div>
</section>
<div id="lightbox">
<section>
<div class="content">
<a class="close" href="#">Close</a>
</div>
<div class="controls">
<a href="#" class="control next">&raquo;</a>
<a href="#" class="control prev">&laquo;</a>
<div class="caption"><span></span></div>
</div>
</section>
</div>
{% endif %}
{% endif %}
<aside class="secondary metadata c">
<ul class="links">
{% if addon.homepage %}
<li><a class="home" href="{{ addon.homepage|external_url }}">
{{ _('Add-on home page') }}</a></li>
{% endif %}
{% if addon.support_url %}
<li><a class="support" href="{{ addon.support_url|external_url }}">{{ _('Support site') }}</a></li>
{% endif %}
{% if addon.support_email %}
<li>{{ emaillink(addon.support_email.localized_string,
_('Support E-mail')) }}</li>
{% endif %}
</ul>
{% if version %}
<ul>
<li>{{ _('Version {0}')|format_html(version.version) }} <a class="scrollto" href="#detail-relnotes">{{ _('Info') }}</a></li>
<li>{% trans %}Last Updated:{% endtrans %} {{ version.created|date }}</li>
<li class="source-license">
{% set license = version.license %}
{% if license %}
{% if license.url %}
{% trans url = license.url,
name = license if license.builtin else _('Custom License') %}
Released under <a href="{{ url }}">{{ name }}</a>
{% endtrans %}
{% else %}
{% trans url = version.license_url(),
name = license if license.builtin else _('Custom License') %}
Released under <a href="{{ url }}">{{ name }}</a>
{% endtrans %}
{% endif %}
{% endif %}
</li>
</ul>
{% endif %}
</aside>
<section class="primary island c">
<h2>{{ _('About this Add-on') }}</h2>
<div class="prose">
{% if addon.description %}
<div id="addon-description" class="prose" {{ addon.description|locale_html }}>{{ addon.description|nl2br }}</div>
{% else %}
<div id="addon-description" class="prose" {{ addon.description|locale_html }}>{{ addon.summary|nl2br }}</div>
{% endif %}
</div>
</section>
<div id="more-webpage" class="primary c" data-more-url="{{ addon.get_url_path(more=True) }}"></div>
{% if version or addon.developer_comments %}
<section class="primary island more-island">
{% if addon.developer_comments %}
<section class="expando" id="developer-comments">
<h2>{{ _('Developers Comments') }}<a class="toggle" href="#developer-comments"><b></b></a></h2>
<div class="content prose">
<p{{ addon.developer_comments|locale_html }}>
{{ addon.developer_comments|nl2br }}</p>
</div>
</section>
{% endif %}
{% if version %}
<section id="detail-relnotes" class="expando">
<h2>{{ _('Version Information') }}<a class="toggle" href="#detail-relnotes"><b></b></a></h2>
<div class="content listing">
<div class="items">
{{ version_detail(addon, version, src=version_src, impala=True) }}
</div>
<p class="more c">
<a class="more-info" href="{{ url('addons.versions', addon.slug) }}">
{{ _('See complete version history') }}
</a>
</p>
</div>
</section>
{% endif %}
</section>
{% endif %}
</div>
{# The rest of the detail page content is in details-more.html.
We want above-the-fold to return and render really fast so we pull
in reviews and links to other add-ons with js. #}
{% endblock content %}
{% block popups %}
{% if addon.privacy_policy %}
<div class="modal" id="privacy-policy">
<a href="#" class="close">{{ _('close') }}</a>
<h2>{{ _('Privacy Policy') }}</h2>
<div class="prose">
{{ addon.privacy_policy|nl2br }}
</div>
</div>
{% endif %}
{% if addon.should_show_permissions() %}
<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_list %}
<div class="prose">
<p>
{{ _('Some add-ons ask for permission to perform certain functions (example: a tab management add-on will ask permission to access your browsers tab system).') }}
</p><p>
{{ _('Since youre in control of your Firefox, the choice to grant or deny these requests is yours. Accepting permissions does not inherently compromise your browsers 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>{{ _('This add-on can:') }}</h3>
<ul class="webext-permissions-list">
{% for perm in permissions %}
<li class="webext-permissions-list">{{ perm|e }}</li>
{% endfor %}
</ul>
</p>
</div>
{% else %}
<div class="prose">
<img src="{{ static('img/developers/test-warning.png') }}" alt="{{ _('[Warning]') }}">
<p>
{{ _('Some add-ons ask for permission to perform certain functions. Since youre 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>
<h2>{{ _('End-User License Agreement') }}</h2>
<div class="prose">
{{ addon.eula|nl2br }}
</div>
</div>
{% endif %}
{% if review_form and request.user.is_authenticated %}
{{ impala_review_add_box(addon=addon) }}
{% endif %}
{% if abuse_form %}
<div id="abuse-modal" class="modal">
<a href="#" class="close">{{ _('close') }}</a>
<h2>{{ _('Report Abuse') }}</h2>
{{ addon_report_abuse(hide=False, addon=addon) }}
</div>
{% endif %}
{% endblock %}

Просмотреть файл

@ -1,20 +0,0 @@
{% extends "impala/base_shared.html" %}
{% block title %}{{ page_title(addon.name) }}{% endblock %}
{% block bodyclass %}gutter{% endblock %}
{% block content %}
<aside class="secondary">
{{ addon|sidebar_listing }}
</aside>
<div class="primary">
<div class="notification-box error {{ 'removed' if addon.disabled_by_user else 'disabled' }}">
{% if addon.disabled_by_user %}
{{ _('This add-on has been removed by its author.') }}
{% elif addon.status == amo.STATUS_DISABLED %}
{{ _('This add-on has been disabled by an administrator.') }}
{% endif %}
</div>
</div>
{% endblock content %}

Просмотреть файл

@ -1,27 +0,0 @@
{% extends "impala/base_side_categories.html" %}
{% from "addons/macros.html" import addon_heading %}
{% block title %}
{{ page_title(_('Source Code License for {addon}'))|format_html(addon=addon.name) }}
{% endblock %}
{% set addon_type = addon.type %}
{% set license = version.license %}
{% block primary %}
<section class="primary">
<hgroup class="hero">
{# L10n: The License for this add-on. #}
{{ addon_heading(addon, version) }}
</hgroup>
<div class="prose">
<h2>{{ _('Source Code License') }}</h2>
{% if license.url %}
<p><a href="{{ license.url }}">{{ license }}</a></p>
{% else %}
<h3>{{ license }}</h3>
<pre class="license">{{ license.text|nl2br }}</pre>
{% endif %}
</div>
</section>
{% endblock %}

Просмотреть файл

@ -1,47 +0,0 @@
<div id="review-add-box" class="modal">
{% if addon.can_review(user) %}
<a class="close" href="#">{{ _('close') }}</a>
<h2>{{ _('What do you think?') }}</h2>
<div id="review-box" class="c">
{% if not user.is_authenticated %}
<p>
{% trans login=login_link() %}
Please <a href="{{ login }}">log in</a> to submit a review
{% endtrans %}
</p>
{% endif %}
<form method="post" action="{{ url('addons.ratings.add', addon.slug) }}">
{% set attrs = {} if user.is_authenticated else {'disabled': 'disabled'} %}
{% csrf_token %}
{{ field(review_form.body, _('Review:'), **attrs) }}
{{ field(review_form.rating, _('Rating:'), **attrs) }}
<p><input type="submit" value="{{ _('Submit review') }}" {{ attrs|xmlattr }}></p>
</form>
<div>
<p>
{% trans %}
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.
{% endtrans %}
</p>
{% if addon.support_url or addon.support_email %}
<p>
See this add-on's
{% if addon.support_url %}
<a class="support" href="{{ addon.support_url|external_url }}">{{ _('support section') }}</a>
{% elif addon.support_email %}
{{ emaillink(addon.support_email.localized_string, _('support email')) }}
{% endif %}
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.
</p>
{% endif %}
<p><a href="{{ url('pages.review_guide') }}">{{ _('Review Guidelines') }}</a></p>
</div>
</div>{# /#review-box #}
{% endif %}{# /is_author #}
</div>

Просмотреть файл

@ -1,46 +0,0 @@
{% set reviews = reviews[:3] %}
{% if reviews %}
{% set replies = get_replies(reviews) %}
{% for review in reviews %}
<div class="review">
<h3>
{{ review.rating|stars }}
</h3>
<p class="byline">
{% trans user=review.user|user_link, date=review.created|date %}
by {{ user }} on {{ date }}
{% endtrans %}
&middot;
<a class="permalink"
href="{{ url('addons.ratings.detail', addon.slug, review.id) }}">{{ _('permalink') }}</a>
</p>
<p class="description">{{ review.body|nl2br }}</p>
{% if replies[review.id] %}
<a class="more-info" href="{{ replies[review.id].get_url_path() }}">
{{ _("Show the developer's reply to this review") }}</a>
{% endif %}
</div>
{% endfor %}
{% if addon %}
<p>
<a class="more-info" href="{{ addon.ratings_url }}">
{% trans num=addon.total_ratings, cnt=addon.total_ratings|numberfmt %}
See all user reviews
{% pluralize %}
See all {{ cnt }} user reviews
{% endtrans %}
</a>
</p>
{% endif %}
{% else %}
<div class="review no-reviews">
<h3>
{{ _('This add-on has not yet been reviewed.') }}
{% if addon.can_review(user) %}
<a id="add-first-review" href="{{ url('addons.ratings.add', addon.slug) }}">
{{ _('Be the first!') }}
</a>
{% endif %}
</h3>
</div>
{% endif %}

Просмотреть файл

@ -1,7 +1,6 @@
{# these are custom attributes on <div class="install ..."> found in src/olympia/addons/templates/addons/impala/button.html #}
data-addon="{{ addon.id }}"
data-icon="{{ addon.get_icon_url(32) }}"
data-developers="{{ addon.meet_the_dev_url() }}"
data-versions="{{ url('addons.versions', addon.id) }}"
data-name="{{ addon.name }}"
{{ button.attrs()|xmlattr }}

Просмотреть файл

@ -1,31 +0,0 @@
<div class="featured">
<div class="featured-inner object-lead">
<div id="addon-summary-wrapper">
<div id="persona-summary" class="{{ addon|statusflags }}">
{{ persona_preview(persona, linked=False) }}
<table itemscope itemtype="http://data-vocabulary.org/Review-aggregate">
{% with addon_name='<span itemprop="itemreviewed">{0}</span>'|format_html(addon.name) %}
{# L10n: This is a caption for a table. {0} is an add-on name. #}
<caption>{{ _('Add-on Information for {0}')|format_html(addon_name) }}</caption>
{% endwith %}
{% include "addons/persona_detail_table.html" %}
</table>
<p{{ addon.description|locale_html }}>{{ addon.description|nl2br }}</p>
{{ big_install_button(addon, show_warning=False) }}
{% if is_artist %}
<p><a href="{{ addon.get_dev_url() }}" class="button developer prominent">{{ _('Edit Theme') }}</a></p>
{% endif %}
{% if is_reviewer %}
{# TODO: Move Reviewer Tools to AMO so we don't need to hack. #}
<p><a href="{{ url('reviewers.themes.single', addon.slug) }}" class="button prominent">
{{ _('Approve / Reject') if addon.is_pending() else _('Review History') }}</a>
{% endif %}
</div>
</div>{# /addon-summary and -wrapper #}
</div>
</div>{# /featured-inner and featured #}

Просмотреть файл

@ -1,11 +0,0 @@
{% if persona.addon.is_pending() and not is_artist %}
<div class="persona featured pending-notice">
<strong>{{ _('Sorry, this theme is pending. Please come back later.') }}</strong>
</div>
{% else %}
{% if persona.addon.is_pending() and is_artist %}
<div class="persona featured pending-notice">
<strong>{{ _('This theme is pending. It is invisible to everyone but you.') }}</strong>
</div>
{% endif %}
{% endif %}

Просмотреть файл

@ -1,85 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ page_title(addon.name) }}{% endblock %}
{% block bodyclass %}inverse{% endblock %}
{% block content %}
{% set is_artist = request.check_ownership(addon, require_owner=False) %}
<hgroup>
<h2 class="addon"{{ addon.name|locale_html }}>
<img src="{{ addon.get_icon_url(32) }}" class="icon" alt="" />
<span>
{{ addon.name }}
</span>
</h2>
<h4 class="author">{{ _('by') }} {{ users_list(addon.listed_authors) or persona.display_username }}</h4>
</hgroup>
{% include "addons/includes/persona_pending_notice.html" %}
<div id="persona" class="primary" role="main" data-id="{{ addon.id }}">
{% if not persona.addon.is_pending() or request.check_ownership(addon, require_owner=False) %}
{# If theme is pending, only artist should see theme listing. #}
{% include "addons/includes/persona.html" %}
{% endif %}
<div id="more-personas">
{% if category_personas %}
<div id="more-category" class="persona-list {{ 'persona-list-3col' if not author_personas else 'persona-list-2col' }}">
{# L10n: {0} is a category name, such as Nature #}
<h3>{{ _('More {0} Themes')|format_html(categories[0].name) }}</h3>
<div class="article">
{% for other in category_personas %}
{{ persona_preview(other.persona, size='small') }}
{% endfor %}
</div>
{# L10n: {0} is a category name, such as Nature #}
<a href="{{ categories[0].get_url_path() }}" class="more-link">{{ _('See all {0} Themes')|format_html(categories[0].name) }}</a>
</div>
{% endif %}
{% if author_personas %}
<div id="more-artist">
<h3>{{ _('More by this Artist') }}</h3>
<div class="article">
{% for other in author_personas %}
{{ persona_preview(other.persona, size='small') }}
{% endfor %}
</div>
{% if author_gallery %}
<a href="{{ author_gallery }}" class="more-link">{{ _('See all Themes by this Artist') }}</a>
{% endif %}
</div>
{% endif %}
</div>{# /more-personas #}
{{ review_list_box(addon=addon, reviews=reviews) }}
{% if request.user.is_authenticated %}
{{ review_add_box(addon=addon) }}
{% endif %}
{% if abuse_form %}
{{ addon_report_abuse(hide=True, addon=addon) }}
{% endif %}
</div>{# /primary #}
<div id="persona-side" class="secondary" role="navigation">
{% if categories %}
<div class="category-list">
<h3 class="compact-bottom">{{ _('Categories') }}</h3>
<ul>
{# TODO reverse URL #}
{% for category in categories %}
<li>
<a href="{{ category.get_url_path() }}" class="category">{{ category }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{{ tags_box(addon=addon, tags=user_tags) }}
</div>{# /secondary #}
{% endblock content %}

Просмотреть файл

@ -1,30 +0,0 @@
<tbody>
<tr>
<th>{{ _('Updated') }}</th>
<td>
<time datetime="{{ addon.modified|isotime }}">{{
addon.modified|date }}</time>
</td>
</tr>
<tr class="artist">
<th>{{ _('Artist') }}</th>
<td>{{ users_list(addon.listed_authors, max_text_length=20) or
persona.display_username }}</td>
</tr>
<tr>
<th>{{ _('Rating') }}</th>
<td>{{ reviews_link(addon) }}</td>
</tr>
<tr class="meta-stats">
<th>{{ _('Daily Users') }}</th>
<td>
<strong class="downloads">{{ persona.popularity|numberfmt }}</strong>
</td>
</tr>
{% if persona.license %}
<tr>
<th>{{ _('License') }}</th>
<td>{{ license_link(amo.PERSONA_LICENSES_IDS[persona.license]) }}</td>
</tr>
{% endif %}
</tbody>

Просмотреть файл

@ -1,27 +0,0 @@
{% extends "impala/base_side_categories.html" %}
{% from "addons/macros.html" import addon_heading %}
{% block title %}
{# L10n: {0} is the name of the add-on. #}
{{ page_title(_('Privacy Policy for {0}')|format_html(addon.name)) }}
{% endblock %}
{% set addon_type = addon.type %}
{% set version = addon.current_version %}
{% set detail_url = addon.get_url_path() %}
{% block primary %}
<section class="primary">
<hgroup class="hero">
{# L10n: The Privacy Policy for this add-on. #}
{{ addon_heading(addon, version) }}
</hgroup>
<div class="prose">
<h2>{{ _('Privacy Policy') }}</h2>
<div class="policy-statement">{{ addon.privacy_policy|nl2br }}</div>
<p class="policy-back">
<a href="{{ detail_url }}">{{ _('Back to {0}…')|format_html(addon.name) }}</a>
</p>
</div>
</section>
{% endblock %}

Просмотреть файл

@ -1,34 +0,0 @@
<form method="post" action="{{ url('addons.abuse', addon.slug) }}" data-no-csrf="anon-only">
{% csrf_token %}
<fieldset class="abuse">
{% if hide %}
<legend><a href="{{ url('devhub.docs', 'policies/contact') }}"
class="abuse-image">{{ _('Report Abuse') }}</a></legend>
{% endif %}
<ol {% if hide %}style="display: none"{% endif %}>
<li>
<p>{% trans amo_policy_link_open='<a href="https://developer.mozilla.org/en-US/Add-ons/AMO/Policy">'|safe,
link_close='</a>'|safe %}
If you suspect this add-on violates {{ amo_policy_link_open }}our policies{{ link_close }} or
has security or privacy issues, please use the form below to describe your
concerns. Please do not use this form for any other reason.
{% endtrans %}
</p>
</li>
<li>
{{ abuse_form.text }}
{{ abuse_form.text.errors }}
</li>
{% if abuse_form.has_recaptcha %}
{{ abuse_form.recaptcha }}
{{ abuse_form.recaptcha.errors }}
{% endif %}
<li class="footer-submit">
<button type="submit">{{ _('Send Report') }}</button>
{% if hide %}
{{ _('or') }} <a href="#" class="cancel">{{ _('Cancel') }}</a>
{% endif %}
</li>
</ol>
</fieldset>
</form>

Просмотреть файл

@ -1,13 +0,0 @@
{% extends "impala/base_shared.html" %}
{% set title = 'Report abuse for {0}'|format_html(addon.name) %}
{% block bodyclass %}gutter abuse{% endblock %}
{% block title %}{{ page_title(title) }}{% endblock %}
{% block content %}
<header>
<h1>{{ title }}</h1>
</header>
<section class="primary island c prettyform">
{{ addon_report_abuse(hide=False, addon=addon) }}
</section>
{% endblock %}

Просмотреть файл

@ -1,40 +0,0 @@
{% if not addon.has_author(user) %}
<h3>{{ _('What do you think?') }}</h3>
<div id="review-box" class="highlight">
{% if not user.is_authenticated %}
<p>
{% trans login=login_link() %}
Please <a href="{{ login }}">log in</a> to submit a review
{% endtrans %}
</p>
{% endif %}
<form disabled method="post" action="{{ url('addons.ratings.add', addon.slug) }}">
{% set attrs = {} if user.is_authenticated else {'disabled': 'disabled'} %}
{% csrf_token %}
{{ field(review_form.body, _('Review:'), **attrs) }}
{{ field(review_form.rating, _('Rating:'), **attrs) }}
<input type="submit" value="{{ _('Submit review') }}" {{ attrs|xmlattr }}>
</form>
<div>
<p>
{% trans %}
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.
{% endtrans %}
</p>
{% if addon.support_url or addon.support_email %}
<p>
{% trans support='#support' %}
See this add-on's <a href="{{ support }}">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.
{% endtrans %}
</p>
{% endif %}
<p><a href="{{ url('pages.review_guide') }}">{{ _('Review Guidelines') }}</a></p>
</div>
</div>{# /#review-box #}
{% endif %}{# /is_author #}

Просмотреть файл

@ -1,32 +0,0 @@
{% set reviews = reviews[:3] %}
{% set replies = get_replies(reviews) %}
{% if reviews %}
<h3 id="reviews">{{ _('Reviews') }}</h3>
<div class="article">
{% for review in reviews %}
<div class="review-detail">
<p class="description">{{ review.body|nl2br }}</p>
<p>{{ review.rating|stars }}
{% trans user=review.user|user_link, date=review.created|date %}
by {{ user }} on {{ date }}
{% endtrans %}
{% if replies[review.id] %}
<a class="show-more" href="{{ replies[review.id].get_url_path() }}">
{{ _("Show the developer's reply to this review") }}</a>
{% endif %}
</p>
</div>
{% endfor %}
{% if addon %}
<p>
<a class="more-info" href="{{ url('addons.ratings.list', addon.slug) }}">
{% trans num=addon.total_ratings, cnt=addon.total_ratings|numberfmt %}
See all reviews of this add-on
{% pluralize %}
See all {{ cnt }} reviews of this add-on
{% endtrans %}
</a>
</p>
{% endif %}
</div>
{% endif %}

Просмотреть файл

@ -1,9 +0,0 @@
{% if tags %}
<div class="clearboth">
<h3 class="compact-bottom">{{ _('Tags') }}</h3>
<div id="tagbox">
{{ tag_list(addon, tags=tags) }}
</div>
</div>
{% endif %}

Просмотреть файл

@ -41,60 +41,6 @@ def flag(context, addon):
return ''
@library.global_function
@library.render_with('addons/review_list_box.html')
@jinja2.contextfunction
def review_list_box(context, addon, reviews):
"""Details page: Show a box with three add-on reviews."""
c = dict(context.items())
c.update(addon=addon, reviews=reviews)
return c
@library.global_function
@library.render_with('addons/impala/review_list_box.html')
@jinja2.contextfunction
def impala_review_list_box(context, addon, reviews):
"""Details page: Show a box with three add-on reviews."""
c = dict(context.items())
c.update(addon=addon, reviews=reviews)
return c
@library.global_function
@library.render_with('addons/review_add_box.html')
@jinja2.contextfunction
def review_add_box(context, addon):
"""Details page: Show a box for the user to post a review."""
c = dict(context.items())
c['addon'] = addon
return c
@library.global_function
@library.render_with('addons/impala/review_add_box.html')
@jinja2.contextfunction
def impala_review_add_box(context, addon):
"""Details page: Show a box for the user to post a review."""
c = dict(context.items())
c['addon'] = addon
return c
@library.global_function
@library.render_with('addons/tags_box.html')
@jinja2.contextfunction
def tags_box(context, addon, tags=None):
"""
Details page: Show a box with existing tags along with a form to add new
ones.
"""
c = dict(context.items())
c.update({'addon': addon,
'tags': tags})
return c
@library.global_function
@library.render_with('addons/listing/items.html')
@jinja2.contextfunction
@ -264,10 +210,3 @@ def theme_grid(context, themes, src=None, dl_src=None):
if not dl_src:
dl_src = context.get('dl_src', src)
return new_context(**locals())
@library.global_function
@library.render_with('addons/report_abuse.html')
@jinja2.contextfunction
def addon_report_abuse(context, hide, addon):
return new_context(**locals())

Просмотреть файл

@ -223,7 +223,6 @@ class TestButton(ButtonTest):
def test_file_details(self):
file = self.get_file(amo.PLATFORM_ALL.id)
self.addon.meet_the_dev_url.return_value = 'meet.dev'
b = self.get_button()
# Normal.
@ -314,7 +313,6 @@ class TestButtonHtml(ButtonTest):
a = self.addon
a.id = '12345'
a.get_icon_url.return_value = 'icon url'
a.meet_the_dev_url.return_value = 'meet.dev'
a.name = 'addon name'
self.file.hash = 'file hash'
@ -328,7 +326,6 @@ class TestButtonHtml(ButtonTest):
install = doc('.install')
assert '12345' == install.attr('data-addon')
assert 'icon url' == install.attr('data-icon')
assert 'meet.dev' == install.attr('data-developers')
assert reverse('addons.versions', args=[a.id]) == (
install.attr('data-versions'))
assert 'addon name' == install.attr('data-name')
@ -348,14 +345,6 @@ class TestButtonHtml(ButtonTest):
doc('.install').attr('class').split())
assert 'Featured' == doc('.install strong:last-child').text()
def test_detailed_privacy_policy(self):
policy = self.render(detailed=True)('.install-shell .privacy-policy')
assert policy.length == 0
self.addon.privacy_policy = 'privacy!'
policy = self.render(detailed=True)('.install-shell .privacy-policy')
assert policy.text() == 'View privacy policy'
def test_experimental_detailed_warning(self):
self.addon.status = amo.STATUS_PUBLIC
self.addon.is_experimental = True
@ -467,16 +456,3 @@ class TestButtonHtml(ButtonTest):
doc = self.render(impala=True, show_download_anyway=True)
assert doc('.download-anyway')
@pytest.mark.skipif(
django.VERSION[0] >= 2,
reason='Legacy UI tests')
class TestViews(TestCase):
fixtures = ['addons/eula+contrib-addon']
def test_eula_with_contrib_roadblock(self):
url = reverse('addons.eula', args=[11730, 53612])
response = self.client.get(url, follow=True)
doc = PyQuery(response.content)
assert doc('[data-search]').attr('class') == 'install '

Просмотреть файл

@ -1867,11 +1867,6 @@ class TestAddonGetURLPath(TestCase):
addon = addon_factory(slug='woo')
assert addon.get_url_path() == '/en-US/firefox/addon/woo/'
def test_get_url_path_more(self):
addon = addon_factory(slug='yeah')
assert addon.get_url_path(more=True) == (
'/en-US/firefox/addon/yeah/more')
def test_unlisted_addon_get_url_path(self):
addon = addon_factory(
slug='woo', version_kw={'channel': amo.RELEASE_CHANNEL_UNLISTED})

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,6 +1,6 @@
from django.conf.urls import include, url
from django.shortcuts import redirect
from olympia.amo.views import frontend_view
from olympia.stats.urls import stats_patterns
from . import views
@ -11,46 +11,12 @@ ADDON_ID = r"""(?P<addon_id>[^/<>"']+)"""
# These will all start with /addon/<addon_id>/
detail_patterns = [
url(r'^$', views.addon_detail, name='addons.detail'),
url(r'^more$', views.addon_detail, name='addons.detail_more'),
url(r'^eula/(?P<file_id>\d+)?$', views.eula, name='addons.eula'),
url(r'^license/(?P<version>[^/]+)?', views.license, name='addons.license'),
url(r'^privacy/', views.privacy, name='addons.privacy'),
url(r'^abuse/', views.report_abuse, name='addons.abuse'),
url(r'^$', frontend_view, name='addons.detail'),
url(r'^license/(?P<version>[^/]+)?', frontend_view, name='addons.license'),
url(r'^reviews/', include('olympia.ratings.urls')),
url(r'^statistics/', include(stats_patterns)),
url(r'^versions/', include('olympia.versions.urls')),
# Old contribution urls
url(r'^developers$',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.meet'),
url(r'^contribute/roadblock/',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.roadblock'),
url(r'^contribute/installed/',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.installed'),
url(r'^contribute/thanks',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.thanks'),
url(r'^contribute/$',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.contribute'),
url(r'^contribute/(?P<status>cancel|complete)$',
lambda r, addon_id, status: redirect('addons.detail',
addon_id, permanent=True),
name='addons.contribute_status'),
url(r'^about$',
lambda r, addon_id: redirect('addons.detail',
addon_id, permanent=True),
name='addons.about'),
]
@ -58,25 +24,9 @@ urlpatterns = [
# Promo modules for the homepage
url(r'^i/promos$', views.homepage_promos, name='addons.homepage_promos'),
# See https://github.com/mozilla/addons-server/issues/3130
# Hardcode because there is no relation from blocklist items and the
# add-on they block :-(
url(r'^addon/icloud-bookmarks/$', views.icloud_bookmarks_redirect,
name='addons.icloudbookmarksredirect'),
# URLs for a single add-on.
url(r'^addon/%s/' % ADDON_ID, include(detail_patterns)),
# Remora EULA and Privacy policy URLS
url(r'^addons/policy/0/(?P<addon_id>\d+)/(?P<file_id>\d+)',
lambda r, addon_id, file_id: redirect(
'addons.eula', addon_id, file_id, permanent=True)),
url(r'^addons/policy/0/(?P<addon_id>\d+)/',
lambda r, addon_id: redirect(
'addons.privacy', addon_id, permanent=True)),
url(r'^versions/license/(\d+)$', views.license_redirect),
url(r'^find-replacement/$', views.find_replacement_addon,
name='addons.find_replacement'),
]

Просмотреть файл

@ -3,14 +3,10 @@ from collections import OrderedDict
from django import http
from django.db.models import Prefetch
from django.db.transaction import non_atomic_requests
from django.shortcuts import get_list_or_404, get_object_or_404, redirect
from django.shortcuts import redirect
from django.utils.cache import patch_cache_control
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext
from django.views.decorators.cache import cache_control, cache_page
from django.views.decorators.vary import vary_on_headers
import waffle
from django.views.decorators.cache import cache_page
from elasticsearch_dsl import Q, query, Search
from rest_framework import exceptions, serializers
@ -24,20 +20,15 @@ from rest_framework.viewsets import GenericViewSet
import olympia.core.logger
from olympia import amo
from olympia.abuse.models import send_abuse_report
from olympia.access import acl
from olympia.amo import messages
from olympia.amo.forms import AbuseForm
from olympia.amo.models import manual_order
from olympia.amo.urlresolvers import get_outgoing_url, get_url_prefix, reverse
from olympia.amo.utils import randslice, render
from olympia.amo.urlresolvers import get_outgoing_url
from olympia.amo.utils import render
from olympia.api.pagination import ESPageNumberPagination
from olympia.api.permissions import (
AllowAddonAuthor, AllowReadOnlyIfPublic, AllowRelatedObjectPermissions,
AllowReviewer, AllowReviewerUnlisted, AnyOf, GroupPermission)
from olympia.constants.categories import CATEGORIES_BY_ID
from olympia.ratings.forms import RatingForm
from olympia.ratings.models import GroupedRating, Rating
from olympia.search.filters import (
AddonAppQueryParam, AddonAppVersionQueryParam, AddonAuthorQueryParam,
AddonCategoryQueryParam, AddonGuidQueryParam, AddonTypeQueryParam,
@ -45,12 +36,11 @@ from olympia.search.filters import (
SortingFilter)
from olympia.translations.query import order_by_translation
from olympia.versions.models import Version
from olympia.lib.cache import make_key, cache_get_or_set
from .decorators import addon_view_factory
from .indexers import AddonIndexer
from .models import (
Addon, CompatOverride, FrozenAddon, Persona, ReplacementAddon)
Addon, CompatOverride, FrozenAddon, ReplacementAddon)
from .serializers import (
AddonEulaPolicySerializer,
AddonSerializer, AddonSerializerWithUnlistedData, CompatOverrideSerializer,
@ -67,129 +57,6 @@ addon_valid_disabled_pending_view = addon_view_factory(
qs=Addon.objects.valid_and_disabled_and_pending)
@addon_valid_disabled_pending_view
@non_atomic_requests
def addon_detail(request, addon):
"""Add-ons details page dispatcher."""
if addon.is_deleted or (addon.is_pending() and not addon.is_persona()):
# Allow pending themes to be listed.
raise http.Http404
if addon.is_disabled:
return render(request, 'addons/impala/disabled.html',
{'addon': addon}, status=404)
# addon needs to have a version and be valid for this app.
if addon.type in request.APP.types:
if addon.type == amo.ADDON_PERSONA:
return persona_detail(request, addon)
else:
if not addon.current_version:
raise http.Http404
return extension_detail(request, addon)
else:
# Redirect to an app that supports this type.
try:
new_app = [a for a in amo.APP_USAGE if addon.type
in a.types][0]
except IndexError:
raise http.Http404
else:
prefixer = get_url_prefix()
prefixer.app = new_app.short
return http.HttpResponsePermanentRedirect(reverse(
'addons.detail', args=[addon.slug]))
@vary_on_headers('X-Requested-With')
@non_atomic_requests
def extension_detail(request, addon):
"""Extensions details page."""
# If current version is incompatible with this app, redirect.
comp_apps = addon.compatible_apps
if comp_apps and request.APP not in comp_apps:
prefixer = get_url_prefix()
prefixer.app = list(comp_apps.keys())[0].short
return redirect('addons.detail', addon.slug, permanent=True)
ctx = {
'addon': addon,
'src': request.GET.get('src', 'dp-btn-primary'),
'version_src': request.GET.get('src', 'dp-btn-version'),
'tags': addon.tags.not_denied(),
'grouped_ratings': GroupedRating.get(addon.id),
'review_form': RatingForm(),
'reviews': Rating.without_replies.all().filter(
addon=addon, is_latest=True).exclude(body=None),
'get_replies': Rating.get_replies,
'abuse_form': AbuseForm(request=request),
}
# details.html just returns the top half of the page for speed. The bottom
# does a lot more queries we don't want on the initial page load.
if request.is_ajax():
# Other add-ons/apps from the same author(s).
ctx['author_addons'] = addon.authors_other_addons(app=request.APP)[:6]
return render(request, 'addons/impala/details-more.html', ctx)
else:
return render(request, 'addons/impala/details.html', ctx)
def _category_personas(qs, limit):
def fetch_personas():
return randslice(qs, limit=limit)
key = make_key('cat-personas:' + str(qs.query), normalize=True)
return cache_get_or_set(key, fetch_personas)
@non_atomic_requests
def persona_detail(request, addon):
"""Details page for Personas."""
if not (addon.is_public() or addon.is_pending()):
raise http.Http404
try:
persona = addon.persona
except Persona.DoesNotExist:
raise http.Http404
# This persona's categories.
categories = addon.categories.all()
category_personas = None
if categories.exists():
qs = Addon.objects.public().filter(categories=categories[0])
category_personas = _category_personas(qs, limit=6)
data = {
'addon': addon,
'persona': persona,
'categories': categories,
'author_personas': persona.authors_other_addons()[:3],
'category_personas': category_personas,
}
try:
author = addon.authors.all()[0]
except IndexError:
author = None
else:
author = author.get_url_path(src='addon-detail')
data['author_gallery'] = author
dev_tags, user_tags = addon.tags_partitioned_by_developer
data.update({
'dev_tags': dev_tags,
'user_tags': user_tags,
'review_form': RatingForm(),
'reviews': Rating.without_replies.all().filter(
addon=addon, is_latest=True),
'get_replies': Rating.get_replies,
'search_cat': 'themes',
'abuse_form': AbuseForm(request=request),
})
return render(request, 'addons/persona_detail.html', data)
class BaseFilter(object):
"""
Filters help generate querysets for add-on listings.
@ -311,88 +178,6 @@ def homepage_promos(request):
return promos(request, 'home', version, platform)
@addon_view
@non_atomic_requests
def eula(request, addon, file_id=None):
if not addon.eula:
return http.HttpResponseRedirect(addon.get_url_path())
if file_id:
version = get_object_or_404(addon.versions, files__id=file_id)
else:
version = addon.current_version
return render(request, 'addons/eula.html',
{'addon': addon, 'version': version})
@addon_view
@non_atomic_requests
def privacy(request, addon):
if not addon.privacy_policy:
return http.HttpResponseRedirect(addon.get_url_path())
return render(request, 'addons/privacy.html', {'addon': addon})
@addon_view
@non_atomic_requests
def license(request, addon, version=None):
if version is not None:
qs = addon.versions.filter(channel=amo.RELEASE_CHANNEL_LISTED,
files__status__in=amo.VALID_FILE_STATUSES)
version = get_list_or_404(qs, version=version)[0]
else:
version = addon.current_version
if not (version and version.license):
raise http.Http404
return render(request, 'addons/impala/license.html',
dict(addon=addon, version=version))
@non_atomic_requests
def license_redirect(request, version):
version = get_object_or_404(Version.objects, pk=version)
return redirect(version.license_url(), permanent=True)
@addon_view
@non_atomic_requests
def report_abuse(request, addon):
form = AbuseForm(request.POST or None, request=request)
if request.method == "POST" and form.is_valid():
send_abuse_report(request, addon, form.cleaned_data['text'])
messages.success(request, ugettext('Abuse reported.'))
return http.HttpResponseRedirect(addon.get_url_path())
else:
return render(request, 'addons/report_abuse_full.html',
{'addon': addon, 'abuse_form': form})
@cache_control(max_age=60 * 60 * 24)
@non_atomic_requests
def persona_redirect(request, persona_id):
if persona_id == 0:
# Newer themes have persona_id == 0, doesn't mean anything.
return http.HttpResponseNotFound()
persona = get_object_or_404(Persona.objects, persona_id=persona_id)
try:
to = reverse('addons.detail', args=[persona.addon.slug])
except Addon.DoesNotExist:
# Would otherwise throw 500. Something funky happened during GP
# migration which caused some Personas to be without Addons (problem
# with cascading deletes?). Tell GoogleBot these are dead with a 404.
return http.HttpResponseNotFound()
return http.HttpResponsePermanentRedirect(to)
@non_atomic_requests
def icloud_bookmarks_redirect(request):
if (waffle.switch_is_active('icloud_bookmarks_redirect')):
return redirect('/blocked/i1214/', permanent=False)
else:
return addon_detail(request, 'icloud-bookmarks')
DEFAULT_FIND_REPLACEMENT_PATH = '/collections/mozilla/featured-add-ons/'
FIND_REPLACEMENT_SRC = 'find-replacement'

Просмотреть файл

@ -1,29 +1,9 @@
from django import forms
from django.conf import settings
from olympia.amo.fields import ReCaptchaField
from olympia.translations.fields import TranslatedField
from django.utils.functional import cached_property
class AbuseForm(forms.Form):
recaptcha = ReCaptchaField(label='')
text = forms.CharField(required=True,
label='',
widget=forms.Textarea())
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.has_recaptcha = True
super(AbuseForm, self).__init__(*args, **kwargs)
if (not self.request.user.is_anonymous or
not settings.NOBOT_RECAPTCHA_PRIVATE_KEY):
del self.fields['recaptcha']
self.has_recaptcha = False
class AMOModelForm(forms.ModelForm):
@cached_property

Просмотреть файл

@ -2,9 +2,6 @@
User-agent: *
Allow: /
{# Due to URL changes we have to use * here and hope most crawlers respect it #}
Disallow: /*{{ url('addons.contribute', 0, add_prefix=False)|replace('0', '*') }}
{# The downloads live at locale-agnostic URLs now. #}
{% for app in apps -%}
Disallow: /{{ app.short }}/downloads/

Просмотреть файл

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
"""Check all our redirects from remora to zamboni."""
from django.db import connection
from olympia import amo
from olympia.addons.models import Category
@ -16,20 +15,6 @@ class TestRedirects(TestCase):
assert r.redirect_chain[-1][0].endswith(
'/en-US/firefox/themes/film-and-tv/')
def test_contribute_installed(self):
r"""`/addon/\d+/about` should go to
`/addon/\d+/contribute/installed`."""
r = self.client.get(u'/addon/5326/about', follow=True)
redirect = r.redirect_chain[-1][0]
assert redirect.endswith(
'/en-US/firefox/addon/5326/')
def test_contribute(self):
"""`/addons/contribute/$id` should go to `/addon/$id/contribute`."""
response = self.client.get(u'/addon/5326/contribute', follow=True)
redirect = response.redirect_chain[-1][0]
assert redirect.endswith('/en-US/firefox/addon/5326/')
def test_reviews(self):
response = self.client.get('/reviews/display/4', follow=True)
self.assert3xx(response, '/en-US/firefox/addon/a4/reviews/',
@ -137,32 +122,3 @@ class TestRedirects(TestCase):
r = self.client.get('/addons/reviews/4/format:rss', follow=True)
self.assert3xx(r, '/en-US/firefox/addon/4/reviews/format:rss',
status_code=302)
class TestPersonaRedirect(TestCase):
fixtures = ['addons/persona']
def test_persona_redirect(self):
r"""`/persona/\d+` should go to `/addon/\d+`."""
r = self.client.get('/persona/813', follow=True)
self.assert3xx(r, '/en-US/firefox/addon/a15663/', status_code=302)
def test_persona_redirect_addon_no_exist(self):
"""When the persona exists but not its addon, throw a 404."""
# Got get shady to separate Persona/Addons.
try:
with connection.cursor() as cursor:
cursor.execute("""
SET FOREIGN_KEY_CHECKS = 0;
UPDATE personas SET addon_id=123 WHERE persona_id=813;
SET FOREIGN_KEY_CHECKS = 1;
""")
r = self.client.get('/persona/813', follow=True)
assert r.status_code == 404
finally:
with connection.cursor() as cursor:
cursor.execute("""
SET FOREIGN_KEY_CHECKS = 0;
UPDATE personas SET addon_id=15663 WHERE persona_id=813;
SET FOREIGN_KEY_CHECKS = 1;
""")

Просмотреть файл

@ -147,13 +147,6 @@ class TestVersion(TestCase):
assert ActivityLog.objects.filter(
action=amo.LOG.DELETE_VERSION.id).count() == 1
def test_delete_version_then_detail(self):
version, file = self._extra_version_and_file(amo.STATUS_PUBLIC)
self.client.post(self.delete_url, self.delete_data)
response = self.client.get(
reverse('addons.detail', args=[self.addon.slug]))
assert response.status_code == 200
def test_version_delete_version_deleted(self):
self.version.delete()
response = self.client.post(self.delete_url, self.delete_data)

Просмотреть файл

@ -243,9 +243,6 @@ class File(OnChangeMixin, ModelBase):
return os.path.join(reverse('downloads.latest', kwargs=kw),
'addon-%s-latest%s' % (addon.pk, self.extension))
def eula_url(self):
return reverse('addons.eula', args=[self.version.addon_id, self.id])
@property
def file_path(self):
return os.path.join(user_media_path('addons'),

Просмотреть файл

@ -194,10 +194,6 @@ class TestFile(TestCase, amo.tests.AMOPaths):
'/firefox/downloads/latest/a3615/type:attachment/'
'addon-3615-latest.xpi')
def test_eula_url(self):
f = File.objects.get(id=67442)
assert f.eula_url() == '/en-US/firefox/addon/3615/eula/67442'
def test_generate_filename(self):
f = File.objects.get(id=67442)
assert f.generate_filename() == 'delicious_bookmarks-2.1.072-fx.xpi'

Просмотреть файл

@ -395,7 +395,6 @@ class TestCreate(ReviewTest):
self.addon = Addon.objects.get(pk=1865)
self.user = UserProfile.objects.get(email='root_x@ukr.net')
self.qs = Rating.objects.filter(addon=self.addon)
self.more_url = self.addon.get_url_path(more=True)
self.list_url = jinja_helpers.url(
'addons.ratings.list', self.addon.slug)
@ -496,40 +495,6 @@ class TestCreate(ReviewTest):
review = Rating.objects.latest('pk')
assert six.text_type(review.body) == "foo\nbar"
def test_add_link_visitor(self):
"""
Ensure non-logged user can see Add Review links on details page
and Reviews listing page.
"""
self.client.logout()
r = self.client.get_ajax(self.more_url)
assert pq(r.content)('#add-review').length == 1
r = self.client.get(jinja_helpers.url(
'addons.ratings.list', self.addon.slug))
doc = pq(r.content)
assert doc('#add-review').length == 1
assert doc('#add-first-review').length == 0
def test_add_link_logged(self):
"""Ensure logged user can see Add Review links."""
r = self.client.get_ajax(self.more_url)
assert pq(r.content)('#add-review').length == 1
r = self.client.get(self.list_url)
doc = pq(r.content)
assert doc('#add-review').length == 1
assert doc('#add-first-review').length == 0
def test_add_link_dev(self):
"""Ensure developer cannot see Add Review links."""
self.login_dev()
r = self.client.get_ajax(self.more_url)
assert pq(r.content)('#add-review').length == 0
r = self.client.get(jinja_helpers.url(
'addons.ratings.list', self.addon.slug))
doc = pq(r.content)
assert doc('#add-review').length == 0
assert doc('#add-first-review').length == 0
def test_list_none_add_review_link_visitor(self):
"""If no reviews, ensure visitor user cannot see Add Review link."""
Rating.objects.all().delete()

Просмотреть файл

@ -1,19 +0,0 @@
{% macro tag_li(tag, addon=None, css_class='') -%}
<li id="taglink-{{ tag.id }}" class="{{ css_class }}">
{% if tag.can_reverse() %}
<a href="{{ url('tags.detail', tag.tag_text) }}" class="tagitem">
{{ tag.tag_text }}
</a>
{% else %}
<span class="tagitem">{{ tag.tag_text }}</span>
{% endif %}
</li>
{%- endmacro %}
{% if tags %}
<ul class="addon-tags nojs" id="addonid-{{ addon.id }}">
{% for tag in tags %}
{{ tag_li(tag, addon=addon, css_class='tag') }}
{% endfor %}
</ul>
{% endif %}

Просмотреть файл

Просмотреть файл

@ -1,17 +0,0 @@
import jinja2
from django_jinja import library
@library.global_function
@library.render_with('tags/tag_list.html')
@jinja2.contextfunction
def tag_list(context, addon, tags=None):
"""Display list of tags, with delete buttons."""
if tags is None:
tags = []
c = dict(context.items())
c.update({'addon': addon,
'tags': tags})
return c

Просмотреть файл

@ -1,42 +0,0 @@
from mock import Mock
from pyquery import PyQuery as pq
from olympia import amo
from olympia.addons.models import Addon
def render(s, context=None):
"""Taken from jingo.tests.utils, previously jingo.tests.test_helpers."""
if context is None:
context = {}
t = amo.utils.from_string(s)
return t.render(context)
class TestHelpers(amo.tests.TestCase):
fixtures = ('base/addon_3615', 'base/user_2519', 'base/user_4043307',
'tags/tags')
def test_tag_list(self):
addon = Addon.objects.get(id=3615)
request = Mock()
request.user = addon.authors.all()[0]
tags = addon.tags.not_denied()
ctx = {
'APP': amo.FIREFOX,
'LANG': 'en-us',
'request': request,
'addon': addon,
'tags': tags}
# no tags, no list
s = render('{{ tag_list(addon) }}', ctx)
assert s.strip() == ""
s = render('{{ tag_list(addon, tags=tags) }}', ctx)
assert s, "Non-empty tags must return tag list."
doc = pq(s)
assert doc('li').length == len(tags)

Просмотреть файл

@ -1,84 +0,0 @@
from django.urls import NoReverseMatch, reverse
from pyquery import PyQuery as pq
from olympia.addons.models import Addon
from olympia.amo.tests import TestCase
class TestManagement(TestCase):
fixtures = ['base/addon_3615',
'tags/tags.json']
def test_tags_details_view(self):
"""Test that there are some tags being shown on the details page."""
url = reverse('addons.detail_more', args=['a3615'])
response = self.client.get_ajax(url, follow=True)
doc = pq(response.content)
assert len(doc('li.tag')) == 4
assert 'Tags' in [d.text for d in doc('h3')]
class TestXSS(TestCase):
fixtures = ['base/addon_3615',
'tags/tags.json']
xss = "<script src='foo.bar'>"
escaped = "&lt;script src=&#39;foo.bar&#39;&gt;"
def setUp(self):
self.addon = Addon.objects.get(pk=3615)
self.tag = self.addon.tags.all()[0]
self.tag.tag_text = self.xss
self.tag.num_addons = 1
self.tag.save()
def test_tags_xss_detail(self):
"""Test xss tag detail."""
url = reverse('addons.detail_more', args=['a3615'])
response = self.client.get_ajax(url, follow=True)
content = response.content.decode('utf-8')
assert self.escaped in content
assert self.xss not in content
class TestXSSURLFail(TestCase):
fixtures = ['base/addon_3615',
'tags/tags.json']
xss = "<script>alert('xss')</script>"
escaped = "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"
def setUp(self):
self.addon = Addon.objects.get(pk=3615)
self.tag = self.addon.tags.all()[0]
self.tag.tag_text = self.xss
self.tag.num_addons = 1
self.tag.save()
def test_tags_xss(self):
"""Test xss tag detail."""
url = reverse('addons.detail_more', args=['a3615'])
response = self.client.get_ajax(url, follow=True)
content = response.content.decode('utf-8')
assert self.escaped in content
assert self.xss not in content
def test_tags_xss_home(self):
"""Test xss tag home."""
self.assertRaises(NoReverseMatch, reverse,
'tags.detail', args=[self.xss])
def test_no_reverse(self):
assert not self.tag.can_reverse()
class TestNoTags(TestCase):
fixtures = ['base/addon_3615']
def test_tags_no_details_view(self):
"""Test that there is no tag header tags being shown."""
url = reverse('addons.detail', args=['a3615'])
response = self.client.get(url, follow=True)
doc = pq(response.content)
assert 'Tags' not in [d.text for d in doc('h3')]

Просмотреть файл

@ -100,14 +100,6 @@ urlpatterns = [
url(r'^pages/about$',
lambda r: redirect('pages.about', permanent=True)),
# Redirect persona/xxx
url(r'^getpersonas$',
lambda r: redirect('http://www.getpersonas.com/gallery/All/Popular',
permanent=True)),
url(r'^persona/(?P<persona_id>\d+)',
addons_views.persona_redirect, name='persona'),
url(r'^personas/film and tv/?$',
lambda r: redirect('browse.personas', 'film-and-tv', permanent=True)),

Просмотреть файл

@ -84,16 +84,6 @@ def _user_link(user, max_text_length=None):
jinja2.escape(force_text(name)))
@library.global_function
@library.render_with('users/report_abuse.html')
@jinja2.contextfunction
def user_report_abuse(context, hide, profile):
new = dict(context.items())
new.update({'hide': hide, 'profile': profile,
'abuse_form': context['abuse_form']})
return new
@library.global_function
@jinja2.contextfunction
def manage_fxa_link(context):

Просмотреть файл

@ -9,8 +9,7 @@ from pyquery import PyQuery as pq
from six.moves.urllib_parse import parse_qs, urlparse
from olympia import amo
from olympia.addons.models import Addon
from olympia.addons.tests.test_views import TestPersonas
from olympia.addons.models import Addon, AddonUser
from olympia.amo.tests import TestCase
from olympia.users.models import UserProfile
from olympia.users.templatetags.jinja_helpers import (
@ -110,7 +109,8 @@ def test_user_link_unicode():
u.display_name))
class TestAddonUsersList(TestPersonas, TestCase):
class TestAddonUsersList(TestCase):
fixtures = ['addons/persona', 'base/users']
def setUp(self):
super(TestAddonUsersList, self).setUp()
@ -118,6 +118,9 @@ class TestAddonUsersList(TestPersonas, TestCase):
self.persona = self.addon.persona
self.create_addon_user(self.addon)
def create_addon_user(self, addon):
return AddonUser.objects.create(addon=addon, user_id=999)
def test_by(self):
"""Test that the by... bit works."""
# Need to re-fetch the add-on since the user was attached after the