<s> """<STR_LIT>""" <EOL> import hashlib <EOL> import itertools <EOL> import json <EOL> import random <EOL> import urllib <EOL> from datetime import date , timedelta <EOL> from django . core . cache import cache <EOL> from django . db . transaction import non_atomic_requests <EOL> from django . http import HttpResponse , HttpResponsePermanentRedirect <EOL> from django . template . context import get_standard_processors <EOL> from django . utils . decorators import method_decorator <EOL> from django . utils . translation import ugettext as _ , ugettext_lazy , get_language <EOL> from django . utils . encoding import smart_str <EOL> import commonware . log <EOL> import jingo <EOL> import waffle <EOL> from caching . base import cached_with <EOL> from olympia import amo , legacy_api <EOL> from olympia . addons . models import Addon , CompatOverride <EOL> from olympia . amo . decorators import ( <EOL> allow_cross_site_request , json_view ) <EOL> from olympia . amo . models import manual_order <EOL> from olympia . amo . urlresolvers import get_url_prefix <EOL> from olympia . amo . utils import JSONEncoder <EOL> from olympia . legacy_api . utils import addon_to_dict , extract_filters <EOL> from olympia . search . views import ( <EOL> AddonSuggestionsAjax , PersonaSuggestionsAjax , name_query ) <EOL> from olympia . versions . compare import version_int <EOL> ERROR = '<STR_LIT:error>' <EOL> OUT_OF_DATE = ugettext_lazy ( <EOL> u"<STR_LIT>" <EOL> u"<STR_LIT>" ) <EOL> SEARCHABLE_STATUSES = ( amo . STATUS_PUBLIC , amo . STATUS_LITE , <EOL> amo . STATUS_LITE_AND_NOMINATED ) <EOL> xml_env = jingo . get_env ( ) . overlay ( ) <EOL> old_finalize = xml_env . finalize <EOL> xml_env . finalize = lambda x : amo . helpers . strip_controls ( old_finalize ( x ) ) <EOL> MAX_LIMIT , BUFFER = <NUM_LIT:30> , <NUM_LIT:10> <EOL> NEW_DAYS = <NUM_LIT:10> <EOL> log = commonware . log . getLogger ( '<STR_LIT>' ) <EOL> def partition ( seq , key ) : <EOL> """<STR_LIT>""" <EOL> groups = itertools . groupby ( sorted ( seq , key = key ) , key = key ) <EOL> return ( ( k , list ( v ) ) for k , v in groups ) <EOL> def render_xml_to_string ( request , template , context = { } ) : <EOL> if not jingo . _helpers_loaded : <EOL> jingo . load_helpers ( ) <EOL> for processor in get_standard_processors ( ) : <EOL> context . update ( processor ( request ) ) <EOL> template = xml_env . get_template ( template ) <EOL> return template . render ( context ) <EOL> @ non_atomic_requests <EOL> def render_xml ( request , template , context = { } , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> rendered = render_xml_to_string ( request , template , context ) <EOL> if '<STR_LIT>' not in kwargs : <EOL> kwargs [ '<STR_LIT>' ] = '<STR_LIT>' <EOL> return HttpResponse ( rendered , ** kwargs ) <EOL> @ non_atomic_requests <EOL> def handler403 ( request ) : <EOL> context = { '<STR_LIT>' : ERROR , '<STR_LIT>' : '<STR_LIT>' } <EOL> return render_xml ( request , '<STR_LIT>' , context , status = <NUM_LIT> ) <EOL> @ non_atomic_requests <EOL> def handler404 ( request ) : <EOL> context = { '<STR_LIT>' : ERROR , '<STR_LIT>' : '<STR_LIT>' } <EOL> return render_xml ( request , '<STR_LIT>' , context , status = <NUM_LIT> ) <EOL> @ non_atomic_requests <EOL> def handler500 ( request ) : <EOL> context = { '<STR_LIT>' : ERROR , '<STR_LIT>' : '<STR_LIT>' } <EOL> return render_xml ( request , '<STR_LIT>' , context , status = <NUM_LIT> ) <EOL> def validate_api_version ( version ) : <EOL> """<STR_LIT>""" <EOL> if float ( version ) < legacy_api . MIN_VERSION : <EOL> return False <EOL> if float ( version ) > legacy_api . MAX_VERSION : <EOL> return False <EOL> return True <EOL> def addon_filter ( addons , addon_type , limit , app , platform , version , <EOL> compat_mode = '<STR_LIT:strict>' , shuffle = True ) : <EOL> """<STR_LIT>""" <EOL> APP = app <EOL> if addon_type . upper ( ) != '<STR_LIT>' : <EOL> try : <EOL> addon_type = int ( addon_type ) <EOL> if addon_type : <EOL> addons = [ a for a in addons if a . type == addon_type ] <EOL> except ValueError : <EOL> pass <EOL> groups = dict ( partition ( addons , <EOL> lambda x : x . type == amo . ADDON_PERSONA ) ) <EOL> personas , addons = groups . get ( True , [ ] ) , groups . get ( False , [ ] ) <EOL> platform = platform . lower ( ) <EOL> if platform != '<STR_LIT:all>' and platform in amo . PLATFORM_DICT : <EOL> def f ( ps ) : <EOL> return pid in ps or amo . PLATFORM_ALL in ps <EOL> pid = amo . PLATFORM_DICT [ platform ] <EOL> addons = [ a for a in addons <EOL> if f ( a . current_version . supported_platforms ) ] <EOL> if version is not None : <EOL> vint = version_int ( version ) <EOL> def f_strict ( app ) : <EOL> return app . min . version_int <= vint <= app . max . version_int <EOL> def f_ignore ( app ) : <EOL> return app . min . version_int <= vint <EOL> xs = [ ( a , a . compatible_apps ) for a in addons ] <EOL> addons = [ ] <EOL> for addon , apps in xs : <EOL> app = apps . get ( APP ) <EOL> if compat_mode == '<STR_LIT:strict>' : <EOL> if app and f_strict ( app ) : <EOL> addons . append ( addon ) <EOL> elif compat_mode == '<STR_LIT:ignore>' : <EOL> if app and f_ignore ( app ) : <EOL> addons . append ( addon ) <EOL> elif compat_mode == '<STR_LIT>' : <EOL> v = addon . compatible_version ( APP . id , version , platform , <EOL> compat_mode ) <EOL> if v : <EOL> addons . append ( addon ) <EOL> addons . extend ( personas ) <EOL> lang = get_language ( ) <EOL> def partitioner ( x ) : <EOL> return x . description is not None and ( x . description . locale == lang ) <EOL> groups = dict ( partition ( addons , partitioner ) ) <EOL> good , others = groups . get ( True , [ ] ) , groups . get ( False , [ ] ) <EOL> if shuffle : <EOL> random . shuffle ( good ) <EOL> random . shuffle ( others ) <EOL> if limit > <NUM_LIT:0> : <EOL> if len ( good ) < limit : <EOL> good . extend ( others [ : limit - len ( good ) ] ) <EOL> return good [ : limit ] <EOL> else : <EOL> good . extend ( others ) <EOL> return good <EOL> class APIView ( object ) : <EOL> """<STR_LIT>""" <EOL> @ method_decorator ( non_atomic_requests ) <EOL> def __call__ ( self , request , api_version , * args , ** kwargs ) : <EOL> self . version = float ( api_version ) <EOL> self . format = request . REQUEST . get ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> self . content_type = ( '<STR_LIT>' if self . format == '<STR_LIT>' <EOL> else '<STR_LIT:application/json>' ) <EOL> self . request = request <EOL> if not validate_api_version ( api_version ) : <EOL> msg = OUT_OF_DATE . format ( self . version , legacy_api . CURRENT_VERSION ) <EOL> return self . render_msg ( msg , ERROR , status = <NUM_LIT> , <EOL> content_type = self . content_type ) <EOL> return self . process_request ( * args , ** kwargs ) <EOL> def render_msg ( self , msg , error_level = None , * args , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> if self . format == '<STR_LIT>' : <EOL> return render_xml ( <EOL> self . request , '<STR_LIT>' , <EOL> { '<STR_LIT>' : error_level , '<STR_LIT>' : msg } , * args , ** kwargs ) <EOL> else : <EOL> return HttpResponse ( json . dumps ( { '<STR_LIT>' : _ ( msg ) } ) , * args , ** kwargs ) <EOL> def render ( self , template , context ) : <EOL> context [ '<STR_LIT>' ] = self . version <EOL> context [ '<STR_LIT>' ] = legacy_api <EOL> if self . format == '<STR_LIT>' : <EOL> return render_xml ( self . request , template , context , <EOL> content_type = self . content_type ) <EOL> else : <EOL> return HttpResponse ( self . render_json ( context ) , <EOL> content_type = self . content_type ) <EOL> def render_json ( self , context ) : <EOL> return json . dumps ( { '<STR_LIT>' : _ ( '<STR_LIT>' ) } ) <EOL> class AddonDetailView ( APIView ) : <EOL> @ allow_cross_site_request <EOL> def process_request ( self , addon_id ) : <EOL> try : <EOL> addon = Addon . objects . id_or_slug ( addon_id ) . get ( ) <EOL> except Addon . DoesNotExist : <EOL> return self . render_msg ( <EOL> '<STR_LIT>' , ERROR , status = <NUM_LIT> , <EOL> content_type = self . content_type <EOL> ) <EOL> if addon . is_disabled : <EOL> return self . render_msg ( '<STR_LIT>' , ERROR , status = <NUM_LIT> , <EOL> content_type = self . content_type ) <EOL> return self . render_addon ( addon ) <EOL> def render_addon ( self , addon ) : <EOL> return self . render ( '<STR_LIT>' , { '<STR_LIT>' : addon } ) <EOL> def render_json ( self , context ) : <EOL> return json . dumps ( addon_to_dict ( context [ '<STR_LIT>' ] ) , cls = JSONEncoder ) <EOL> @ non_atomic_requests <EOL> def guid_search ( request , api_version , guids ) : <EOL> lang = request . LANG <EOL> def guid_search_cache_key ( guid ) : <EOL> key = '<STR_LIT>' % ( api_version , lang , guid ) <EOL> return hashlib . md5 ( smart_str ( key ) ) . hexdigest ( ) <EOL> guids = [ g . strip ( ) for g in guids . split ( '<STR_LIT:U+002C>' ) ] if guids else [ ] <EOL> addons_xml = cache . get_many ( [ guid_search_cache_key ( g ) for g in guids ] ) <EOL> dirty_keys = set ( ) <EOL> for g in guids : <EOL> key = guid_search_cache_key ( g ) <EOL> if key not in addons_xml : <EOL> dirty_keys . add ( key ) <EOL> try : <EOL> addon = Addon . objects . get ( guid = g , disabled_by_user = False , <EOL> status__in = SEARCHABLE_STATUSES ) <EOL> except Addon . DoesNotExist : <EOL> addons_xml [ key ] = '<STR_LIT>' <EOL> else : <EOL> addon_xml = render_xml_to_string ( <EOL> request , '<STR_LIT>' , { <EOL> '<STR_LIT>' : addon , <EOL> '<STR_LIT>' : api_version , <EOL> '<STR_LIT>' : legacy_api <EOL> } ) <EOL> addons_xml [ key ] = addon_xml <EOL> cache . set_many ( dict ( ( k , v ) for k , v in addons_xml . iteritems ( ) <EOL> if k in dirty_keys ) ) <EOL> compat = ( CompatOverride . objects . filter ( guid__in = guids ) <EOL> . transform ( CompatOverride . transformer ) ) <EOL> addons_xml = [ v for v in addons_xml . values ( ) if v ] <EOL> return render_xml ( request , '<STR_LIT>' , { <EOL> '<STR_LIT>' : addons_xml , <EOL> '<STR_LIT>' : len ( addons_xml ) , <EOL> '<STR_LIT>' : compat , <EOL> '<STR_LIT>' : api_version , '<STR_LIT>' : legacy_api <EOL> } ) <EOL> class SearchView ( APIView ) : <EOL> def process_request ( self , query , addon_type = '<STR_LIT>' , limit = <NUM_LIT:10> , <EOL> platform = '<STR_LIT>' , version = None , compat_mode = '<STR_LIT:strict>' ) : <EOL> """<STR_LIT>""" <EOL> limit = min ( MAX_LIMIT , int ( limit ) ) <EOL> app_id = self . request . APP . id <EOL> filters = { <EOL> '<STR_LIT>' : app_id , <EOL> '<STR_LIT:status>' : amo . STATUS_PUBLIC , <EOL> '<STR_LIT>' : True , <EOL> '<STR_LIT>' : False , <EOL> '<STR_LIT>' : True , <EOL> } <EOL> opts = { <EOL> '<STR_LIT>' : addon_type , <EOL> '<STR_LIT:version>' : version , <EOL> } <EOL> if addon_type != '<STR_LIT>' : <EOL> opts [ '<STR_LIT>' ] = platform <EOL> if self . version < <NUM_LIT> : <EOL> try : <EOL> query = urllib . unquote ( query . encode ( '<STR_LIT:ascii>' ) ) <EOL> except UnicodeEncodeError : <EOL> pass <EOL> query , qs_filters , params = extract_filters ( query , opts ) <EOL> qs = Addon . search ( ) . query ( or_ = name_query ( query ) ) <EOL> filters . update ( qs_filters ) <EOL> if '<STR_LIT:type>' not in filters : <EOL> filters [ '<STR_LIT>' ] = list ( amo . ADDON_SEARCH_TYPES ) <EOL> qs = qs . filter ( ** filters ) <EOL> qs = qs [ : limit ] <EOL> total = qs . count ( ) <EOL> results = [ ] <EOL> for addon in qs : <EOL> compat_version = addon . compatible_version ( app_id , <EOL> params [ '<STR_LIT:version>' ] , <EOL> params [ '<STR_LIT>' ] , <EOL> compat_mode ) <EOL> if compat_version or addon_type == '<STR_LIT>' : <EOL> addon . compat_version = compat_version <EOL> results . append ( addon ) <EOL> if len ( results ) == limit : <EOL> break <EOL> else : <EOL> total -= <NUM_LIT:1> <EOL> return self . render ( '<STR_LIT>' , { <EOL> '<STR_LIT>' : results , <EOL> '<STR_LIT>' : total , <EOL> '<STR_LIT:version>' : version , <EOL> '<STR_LIT>' : compat_mode , <EOL> } ) <EOL> @ json_view <EOL> @ non_atomic_requests <EOL> def search_suggestions ( request ) : <EOL> if waffle . sample_is_active ( '<STR_LIT>' ) : <EOL> return HttpResponse ( status = <NUM_LIT> ) <EOL> cat = request . GET . get ( '<STR_LIT>' , '<STR_LIT:all>' ) <EOL> suggesterClass = { <EOL> '<STR_LIT:all>' : AddonSuggestionsAjax , <EOL> '<STR_LIT>' : PersonaSuggestionsAjax , <EOL> } . get ( cat , AddonSuggestionsAjax ) <EOL> items = suggesterClass ( request , ratings = True ) . items <EOL> for s in items : <EOL> s [ '<STR_LIT>' ] = float ( s [ '<STR_LIT>' ] ) <EOL> return { '<STR_LIT>' : items } <EOL> class ListView ( APIView ) : <EOL> def process_request ( self , list_type = '<STR_LIT>' , addon_type = '<STR_LIT>' , <EOL> limit = <NUM_LIT:10> , platform = '<STR_LIT>' , version = None , <EOL> compat_mode = '<STR_LIT:strict>' ) : <EOL> """<STR_LIT>""" <EOL> limit = min ( MAX_LIMIT , int ( limit ) ) <EOL> APP , platform = self . request . APP , platform . lower ( ) <EOL> qs = Addon . objects . listed ( APP ) <EOL> shuffle = True <EOL> if list_type in ( '<STR_LIT>' , '<STR_LIT>' ) : <EOL> qs = qs . exclude ( type = amo . ADDON_PERSONA ) <EOL> if list_type == '<STR_LIT>' : <EOL> new = date . today ( ) - timedelta ( days = NEW_DAYS ) <EOL> addons = ( qs . filter ( created__gte = new ) <EOL> . order_by ( '<STR_LIT>' ) ) [ : limit + BUFFER ] <EOL> elif list_type == '<STR_LIT>' : <EOL> addons = qs . order_by ( '<STR_LIT>' ) [ : limit + BUFFER ] <EOL> shuffle = False <EOL> elif list_type == '<STR_LIT>' : <EOL> addons = ( qs . filter ( type = amo . ADDON_EXTENSION ) <EOL> . order_by ( '<STR_LIT>' ) ) [ : limit + BUFFER ] <EOL> shuffle = False <EOL> else : <EOL> ids = Addon . featured_random ( APP , self . request . LANG ) <EOL> addons = manual_order ( qs , ids [ : limit + BUFFER ] , '<STR_LIT>' ) <EOL> shuffle = False <EOL> args = ( addon_type , limit , APP , platform , version , compat_mode , <EOL> shuffle ) <EOL> def f ( ) : <EOL> return self . _process ( addons , * args ) <EOL> return cached_with ( addons , f , map ( smart_str , args ) ) <EOL> def _process ( self , addons , * args ) : <EOL> return self . render ( '<STR_LIT>' , <EOL> { '<STR_LIT>' : addon_filter ( addons , * args ) } ) <EOL> def render_json ( self , context ) : <EOL> return json . dumps ( [ addon_to_dict ( a ) for a in context [ '<STR_LIT>' ] ] , <EOL> cls = JSONEncoder ) <EOL> class LanguageView ( APIView ) : <EOL> def process_request ( self ) : <EOL> addons = Addon . objects . filter ( status = amo . STATUS_PUBLIC , <EOL> type = amo . ADDON_LPAPP , <EOL> appsupport__app = self . request . APP . id , <EOL> disabled_by_user = False ) . order_by ( '<STR_LIT>' ) <EOL> return self . render ( '<STR_LIT>' , { '<STR_LIT>' : addons , <EOL> '<STR_LIT>' : True } ) <EOL> @ non_atomic_requests <EOL> def redirect_view ( request , url ) : <EOL> """<STR_LIT>""" <EOL> dest = '<STR_LIT>' % ( legacy_api . CURRENT_VERSION , <EOL> urllib . quote ( url . encode ( '<STR_LIT:utf-8>' ) ) ) <EOL> dest = get_url_prefix ( ) . fix ( dest ) <EOL> return HttpResponsePermanentRedirect ( dest ) </s>
