<commit_before>"""
Project: META-SHARE prototype implementation
 Author: Christian Federmann <cfedermann@dfki.de>
"""

import logging

from datetime import datetime
from os.path import split
from urllib import urlopen

from django.contrib.auth.decorators import login_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404, HttpResponseForbidden
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext

from haystack.views import FacetedSearchView

from metashare.repo2.forms import LicenseSelectionForm, LicenseAgreementForm
from metashare.repo2.models import licenceInfoType_model, resourceInfoType_model
from metashare.settings import LOG_LEVEL, LOG_HANDLER
from metashare.stats.model_utils import getLRStats, saveLRStats, \
    saveQueryStats, VIEW_STAT, DOWNLOAD_STAT

MAXIMUM_READ_BLOCK_SIZE = 4096

# Setup logging support.
logging.basicConfig(level=LOG_LEVEL)
LOGGER = logging.getLogger('metashare.repo2.views')
LOGGER.addHandler(LOG_HANDLER)

def _convert_to_template_tuples(element_tree):
    """
    Converts the given ElementTree instance to template tuples.

    A template tuple contains:
    - a two-tuple (component, values) for complex nodes, and
    - a one-tuple ((key, value),) for simple tags.

    The length distinction allows for recursive rendering in the template.
    See repo2/detail.html and repo2/detail_view.html for more information.

    Rendering recursively inside the Django template system needs this trick:
    - http://blog.elsdoerfer.name/2008/01/22/recursion-in-django-templates/

    """
    # If we are dealing with a complex node containing children nodes, we have
    # to first recursively collect the data values from the sub components.
    if len(element_tree.getchildren()):
        values = []
        for child in element_tree.getchildren():
            values.append(_convert_to_template_tuples(child))
        return (element_tree.tag, values)

    # Otherwise, we return a tuple containg (key, value), i.e., (tag, text).
    else:
        return ((element_tree.tag, element_tree.text),)

# The following most be kept here, rather than in models.py,
# because models.py is automatically generated from the XML Schema.
LICENCEINFOTYPE_URLS_LICENCE_CHOICES = {
  'AGPL': ('/site_media/licences/GNU_agpl-3.0.htm', False),
  'LGPL': ('/site_media/licences/GNU_lgpl-2.0.htm', False),
  'LGPLv3': ('/site_media/licences/GNU_lgpl-3.0.htm', False),
  'CC': ('/site_media/licences/CC0v1.0.htm', False),
  'CC_BY-SA_3.0': ('/site_media/licences/CC-BYSAv3.0.htm', False),
  'CC_BY-NC-ND': ('/site_media/licences/CC-BYNCNDv3.0.htm', False),
  'CC_BY-NC-SA': ('/site_media/licences/CC-BYNCSAv2.5.pdf', False),
  'CC_BY-NC': ('/site_media/licences/CC-BYNCv3.0.htm', False),
  'CC_BY-ND': ('/site_media/licences/CC-BYNDv3.0.htm', False),
  'CC_BY-SA': ('/site_media/licences/CC-BYSAv2.5.pdf', False),
  'CC_BY': ('/site_media/licences/CC-BYv3.0.htm', False),
  'CC_BY-NC-SA_3.0': ('/site_media/licences/CC-BYNCSAv3.0.htm', False),
  'MSCommons_BY': \
    ('/site_media/licences/META-SHARE_COMMONS_BY_v1.0.htm', False),
  'MSCommons_BY-NC': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNC_v1.0.htm', False),
  'MSCommons_BY-NC-ND': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNCND_v1.0.htm', False),
  'MSCommons_BY-NC-SA': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNCSA_v1.0.htm', False),
  'MSCommons_BY-ND': \
    ('/site_media/licences/META-SHARE_COMMONS_BYND_v1.0.htm', False),
  'MSCommons_BY-SA': \
    ('/site_media/licences/META-SHARE_COMMONS_BYSA_v1.0.htm', False),
  'MSCommons_COM-NR-FF': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_For-a-Fee' \
     '_v0.7.htm', True),
  'MSCommons_COM-NR': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_v0.7.htm',
     False),
  'MSCommons_COM-NR-ND-FF': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives_For-a-fee-v1.0.htm', True),
  'MSCommons_COM-NR-ND': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives-v1.0.htm', False),
  'MSCommons_NoCOM-NC-NR-ND-FF': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution_' \
     'NoDerivatives_For-a-fee-v1.0.htm', True),
  'MSCommons_NoCOM-NC-NR-ND': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives-v1.0.htm', False),
  'MSCommons_NoCOM-NC-NR-FF': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution_' \
     'For-a-Fee-v1.0.htm', True),
  'MSCommons_NoCOM-NC-NR': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution-v1.0.htm',
     False),
  'ELRA_EVALUATION': \
    ('/site_media/licences/EVALUATION.pdf', True),
  'ELRA_VAR': ('/site_media/licences/VAR-v3_2007.pdf', True),
  'ELRA_END_USER': \
    ('/site_media/licences/ENDUSER-v3_2007.pdf', True),
  'ELRA_LIMITED': ('/site_media/licences/Var-E-v2.pdf', True),
  'proprietary': ('', True),
  'CLARIN_PUB': ('', True),
  'CLARIN_ACA-NC': ('', True),
  'CLARIN_ACA': ('', True),
  'CLARIN_RES': ('', True),
  'Princeton_Wordnet': ('/site_media/licences/WordNet-3.0.pdf', False),
  'GPL': ('/site_media/licences/GNU_gpl-3.0.pdf', False),
  'GeneralLicenceGrant': ('', True),
  'GFDL': ('/site_media/licences/GNU_fdl-1.3.pdf', False),
  'ApacheLicence_V2.0': ('/site_media/licences/Apache-2.0.htm', False),
  'BSD-style': ('/site_media/licences/BSD_license.pdf', False),
  'underNegotiation': ('', True),
  'other': ('', True)
}

@login_required
def download(request, object_id):
    """
    Renders the resource download view including license selection, etc.
    """
    if not request.user.is_active:
        return HttpResponseForbidden()

    # here we are only interested in licenses (or their names) of the specified
    # resource that allow a download
    resource = get_object_or_404(resourceInfoType_model, pk=object_id)
    licence_infos = tuple(licenceInfoType_model.objects \
        .filter(back_to_distributioninfotype_model__id=object_id))
    licences = dict([(l_name, l_info) for l_info in licence_infos
        if u'downloadable' in l_info.get_distributionAccessMedium_display_list()
        for l_name in l_info.get_licence_display_list()])

    licence_choice = None
    if request.method == "POST":
        licence_choice = request.POST.get('licence', None)
        if licence_choice and 'in_licence_agree_form' in request.POST:
            la_form = LicenseAgreementForm(licence_choice, data=request.POST)
            if la_form.is_valid():
                return _provide_download(request, resource,
                                    licences[licence_choice].downloadLocation)
            else:
                return render_to_response('repo2/licence_agreement.html',
                    { 'form': la_form, 'resource': resource,
                      'licence_path': \
                      LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][0],
                      'requires_sig': \
                      LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][1] })
        elif licence_choice and not licence_choice in licences:
            licence_choice = None

    if len(licences) == 1:
        # no need to manually choose amongst 1 license ...
        licence_choice = licences.iterkeys().next()

    if licence_choice:
        return render_to_response('repo2/licence_agreement.html',
            { 'form': LicenseAgreementForm(licence_choice),
              'resource': resource,
              'licence_path': \
                LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][0],
              'requires_sig': \
                LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][1] })
    elif len(licences) > 1:
        return render_to_response('repo2/licence_selection.html',
            { 'form': LicenseSelectionForm([(name, name) for name in licences]),
              'resource': resource })
    else:
        return render_to_response('repo2/lr_not_downloadable.html',
                                  { 'resource': resource })

def _provide_download(request, resource, download_urls):
    """
    Returns an HTTP response with a download of the given resource.
    """
    sessionid = ""
    if request.COOKIES:
        sessionid = request.COOKIES.get('sessionid', '')

    if resource.storage_object.has_local_download_copy():
        try:
            _binary_data = resource.storage_object.get_download()

            # We use a generic, binary mime type here for version v1.
            response = HttpResponse(mimetype="application/octet-stream")
            response['Content-Disposition'] = 'attachment; filename={0}' \
                                                .format(split(_binary_data)[1])
            with open(_binary_data, 'rb') as _local_data:
                _chunk = _local_data.read(MAXIMUM_READ_BLOCK_SIZE)
                while _chunk:
                    response.write(_chunk)
                    _chunk = _local_data.read(MAXIMUM_READ_BLOCK_SIZE)

            saveLRStats(request.user.username,
                        resource.storage_object.identifier, sessionid,
                        DOWNLOAD_STAT)
            return response
        except:
            raise Http404
    # redirect to download location, if available
    else:
        for url in download_urls:
            if (urlopen(url).code / 100 < 4):
                saveLRStats(request.user.username,
                            resource.storage_object.identifier,
                            sessionid, DOWNLOAD_STAT)
                return redirect(url)
        LOGGER.info("No download could be offered for resource #{0}." \
                    .format(resource.id))
    raise Http404

@login_required
def create(request):
    """
    Redirects to the Django admin backend editor for resources.
    """
    return redirect(reverse('admin:repo2_resourceinfotype_model_add'))

def view(request, object_id=None):
    """
    Render browse or detail view for the repo2 application.
    """
    # If an object id is given, try to look up the corresponding resource in
    # the Django database, raising HTTP 404 if it cannot be found.
    if object_id:

        resource = get_object_or_404(resourceInfoType_model, pk=object_id)

        # Convert resource to ElementTree and then to template tuples.
        resource_tree = resource.export_to_elementtree()
        lr_content = _convert_to_template_tuples(resource_tree)

        # we need to know if the resource is published or not
        resource_published = resource.storage_object.published

        # Define context for template rendering.
        context = {'resource': resource, 'lr_content': lr_content,
                   'RESOURCE_PUBLISHED': resource_published}
        template = 'repo2/lr_view.html'

        # For staff users, we have to add LR_EDIT which contains the URL of
        # the Django admin backend page for this resource.
        if request.user.is_staff:
            context['LR_EDIT'] = reverse(
                'admin:repo2_resourceinfotype_model_change', args=(object_id,))

        context['LR_DOWNLOAD'] = ""
        try:
            licences = licenceInfoType_model.objects \
                .values("downloadLocation") \
                .filter(back_to_distributioninfotype_model__id=object_id)
            if resource.storage_object.has_download() \
                    or resource.storage_object.has_local_download_copy() \
                    or len(licences) > 0:
                context['LR_DOWNLOAD'] = reverse(download, args=(object_id,))
                if (not request.user.is_active):
                    context['LR_DOWNLOAD'] = "restricted"
        except ObjectDoesNotExist:
            print "Info about licence doesn't exist."

        # Update statistics and create a report about the user actions on LR
        if hasattr(resource.storage_object, 'identifier'):
            sessionid = ""
            if request.COOKIES:
                sessionid = request.COOKIES.get('sessionid', '')
            saveLRStats(request.user.username,
              resource.storage_object.identifier, sessionid, VIEW_STAT)
            context['LR_STATS'] = getLRStats(resource.storage_object.identifier)

    # Otherwise, we just collect all resources from the Django database.
    else:
        resources = resourceInfoType_model.objects.all()

        # Define context for template rendering.
        context = {'resources': resources}
        template = 'repo2/resources.html'

    # Render and return template with the defined context.
    ctx = RequestContext(request)
    return render_to_response(template, context, context_instance=ctx)

class MetashareFacetedSearchView(FacetedSearchView):
    """
    A modified `FacetedSearchView` which makes sure that only such results will
    be returned that are accessible by the current user.
    """
    def get_results(self):
        sqs = super(MetashareFacetedSearchView, self).get_results()
        if not self.request.user.is_staff:
            sqs = sqs.filter(published=True)

        # collect statistics about the query
        starttime = datetime.now()
        results_count = sqs.count()
        if results_count and self.query:
            saveQueryStats(self.request.user.username, '', self.query,
                results_count, (datetime.now() - starttime).microseconds)

        return sqs
<commit_msg>factored out session ID retrieval into its own method<commit_after>"""
Project: META-SHARE prototype implementation
 Author: Christian Federmann <cfedermann@dfki.de>
"""

import logging

from datetime import datetime
from os.path import split
from urllib import urlopen

from django.contrib.auth.decorators import login_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404, HttpResponseForbidden
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext

from haystack.views import FacetedSearchView

from metashare.repo2.forms import LicenseSelectionForm, LicenseAgreementForm
from metashare.repo2.models import licenceInfoType_model, resourceInfoType_model
from metashare.settings import LOG_LEVEL, LOG_HANDLER
from metashare.stats.model_utils import getLRStats, saveLRStats, \
    saveQueryStats, VIEW_STAT, DOWNLOAD_STAT

MAXIMUM_READ_BLOCK_SIZE = 4096

# Setup logging support.
logging.basicConfig(level=LOG_LEVEL)
LOGGER = logging.getLogger('metashare.repo2.views')
LOGGER.addHandler(LOG_HANDLER)

def _convert_to_template_tuples(element_tree):
    """
    Converts the given ElementTree instance to template tuples.

    A template tuple contains:
    - a two-tuple (component, values) for complex nodes, and
    - a one-tuple ((key, value),) for simple tags.

    The length distinction allows for recursive rendering in the template.
    See repo2/detail.html and repo2/detail_view.html for more information.

    Rendering recursively inside the Django template system needs this trick:
    - http://blog.elsdoerfer.name/2008/01/22/recursion-in-django-templates/

    """
    # If we are dealing with a complex node containing children nodes, we have
    # to first recursively collect the data values from the sub components.
    if len(element_tree.getchildren()):
        values = []
        for child in element_tree.getchildren():
            values.append(_convert_to_template_tuples(child))
        return (element_tree.tag, values)

    # Otherwise, we return a tuple containg (key, value), i.e., (tag, text).
    else:
        return ((element_tree.tag, element_tree.text),)

# The following most be kept here, rather than in models.py,
# because models.py is automatically generated from the XML Schema.
LICENCEINFOTYPE_URLS_LICENCE_CHOICES = {
  'AGPL': ('/site_media/licences/GNU_agpl-3.0.htm', False),
  'LGPL': ('/site_media/licences/GNU_lgpl-2.0.htm', False),
  'LGPLv3': ('/site_media/licences/GNU_lgpl-3.0.htm', False),
  'CC': ('/site_media/licences/CC0v1.0.htm', False),
  'CC_BY-SA_3.0': ('/site_media/licences/CC-BYSAv3.0.htm', False),
  'CC_BY-NC-ND': ('/site_media/licences/CC-BYNCNDv3.0.htm', False),
  'CC_BY-NC-SA': ('/site_media/licences/CC-BYNCSAv2.5.pdf', False),
  'CC_BY-NC': ('/site_media/licences/CC-BYNCv3.0.htm', False),
  'CC_BY-ND': ('/site_media/licences/CC-BYNDv3.0.htm', False),
  'CC_BY-SA': ('/site_media/licences/CC-BYSAv2.5.pdf', False),
  'CC_BY': ('/site_media/licences/CC-BYv3.0.htm', False),
  'CC_BY-NC-SA_3.0': ('/site_media/licences/CC-BYNCSAv3.0.htm', False),
  'MSCommons_BY': \
    ('/site_media/licences/META-SHARE_COMMONS_BY_v1.0.htm', False),
  'MSCommons_BY-NC': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNC_v1.0.htm', False),
  'MSCommons_BY-NC-ND': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNCND_v1.0.htm', False),
  'MSCommons_BY-NC-SA': \
    ('/site_media/licences/META-SHARE_COMMONS_BYNCSA_v1.0.htm', False),
  'MSCommons_BY-ND': \
    ('/site_media/licences/META-SHARE_COMMONS_BYND_v1.0.htm', False),
  'MSCommons_BY-SA': \
    ('/site_media/licences/META-SHARE_COMMONS_BYSA_v1.0.htm', False),
  'MSCommons_COM-NR-FF': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_For-a-Fee' \
     '_v0.7.htm', True),
  'MSCommons_COM-NR': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_v0.7.htm',
     False),
  'MSCommons_COM-NR-ND-FF': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives_For-a-fee-v1.0.htm', True),
  'MSCommons_COM-NR-ND': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives-v1.0.htm', False),
  'MSCommons_NoCOM-NC-NR-ND-FF': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution_' \
     'NoDerivatives_For-a-fee-v1.0.htm', True),
  'MSCommons_NoCOM-NC-NR-ND': \
    ('/site_media/licences/META-SHARE_Commercial_NoRedistribution_' \
     'NoDerivatives-v1.0.htm', False),
  'MSCommons_NoCOM-NC-NR-FF': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution_' \
     'For-a-Fee-v1.0.htm', True),
  'MSCommons_NoCOM-NC-NR': \
    ('/site_media/licences/META-SHARE_NonCommercial_NoRedistribution-v1.0.htm',
     False),
  'ELRA_EVALUATION': \
    ('/site_media/licences/EVALUATION.pdf', True),
  'ELRA_VAR': ('/site_media/licences/VAR-v3_2007.pdf', True),
  'ELRA_END_USER': \
    ('/site_media/licences/ENDUSER-v3_2007.pdf', True),
  'ELRA_LIMITED': ('/site_media/licences/Var-E-v2.pdf', True),
  'proprietary': ('', True),
  'CLARIN_PUB': ('', True),
  'CLARIN_ACA-NC': ('', True),
  'CLARIN_ACA': ('', True),
  'CLARIN_RES': ('', True),
  'Princeton_Wordnet': ('/site_media/licences/WordNet-3.0.pdf', False),
  'GPL': ('/site_media/licences/GNU_gpl-3.0.pdf', False),
  'GeneralLicenceGrant': ('', True),
  'GFDL': ('/site_media/licences/GNU_fdl-1.3.pdf', False),
  'ApacheLicence_V2.0': ('/site_media/licences/Apache-2.0.htm', False),
  'BSD-style': ('/site_media/licences/BSD_license.pdf', False),
  'underNegotiation': ('', True),
  'other': ('', True)
}

@login_required
def download(request, object_id):
    """
    Renders the resource download view including license selection, etc.
    """
    if not request.user.is_active:
        return HttpResponseForbidden()

    # here we are only interested in licenses (or their names) of the specified
    # resource that allow a download
    resource = get_object_or_404(resourceInfoType_model, pk=object_id)
    licence_infos = tuple(licenceInfoType_model.objects \
        .filter(back_to_distributioninfotype_model__id=object_id))
    licences = dict([(l_name, l_info) for l_info in licence_infos
        if u'downloadable' in l_info.get_distributionAccessMedium_display_list()
        for l_name in l_info.get_licence_display_list()])

    licence_choice = None
    if request.method == "POST":
        licence_choice = request.POST.get('licence', None)
        if licence_choice and 'in_licence_agree_form' in request.POST:
            la_form = LicenseAgreementForm(licence_choice, data=request.POST)
            if la_form.is_valid():
                return _provide_download(request, resource,
                                    licences[licence_choice].downloadLocation)
            else:
                return render_to_response('repo2/licence_agreement.html',
                    { 'form': la_form, 'resource': resource,
                      'licence_path': \
                      LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][0],
                      'requires_sig': \
                      LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][1] })
        elif licence_choice and not licence_choice in licences:
            licence_choice = None

    if len(licences) == 1:
        # no need to manually choose amongst 1 license ...
        licence_choice = licences.iterkeys().next()

    if licence_choice:
        return render_to_response('repo2/licence_agreement.html',
            { 'form': LicenseAgreementForm(licence_choice),
              'resource': resource,
              'licence_path': \
                LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][0],
              'requires_sig': \
                LICENCEINFOTYPE_URLS_LICENCE_CHOICES[licence_choice][1] })
    elif len(licences) > 1:
        return render_to_response('repo2/licence_selection.html',
            { 'form': LicenseSelectionForm([(name, name) for name in licences]),
              'resource': resource })
    else:
        return render_to_response('repo2/lr_not_downloadable.html',
                                  { 'resource': resource })

def _provide_download(request, resource, download_urls):
    """
    Returns an HTTP response with a download of the given resource.
    """
    if resource.storage_object.has_local_download_copy():
        try:
            _binary_data = resource.storage_object.get_download()

            # We use a generic, binary mime type here for version v1.
            response = HttpResponse(mimetype="application/octet-stream")
            response['Content-Disposition'] = 'attachment; filename={0}' \
                                                .format(split(_binary_data)[1])
            with open(_binary_data, 'rb') as _local_data:
                _chunk = _local_data.read(MAXIMUM_READ_BLOCK_SIZE)
                while _chunk:
                    response.write(_chunk)
                    _chunk = _local_data.read(MAXIMUM_READ_BLOCK_SIZE)

            saveLRStats(request.user.username,
                        resource.storage_object.identifier,
                        _get_sessionid(request), DOWNLOAD_STAT)
            return response
        except:
            raise Http404
    # redirect to download location, if available
    else:
        for url in download_urls:
            if (urlopen(url).code / 100 < 4):
                saveLRStats(request.user.username,
                            resource.storage_object.identifier,
                            _get_sessionid(request), DOWNLOAD_STAT)
                return redirect(url)
        LOGGER.info("No download could be offered for resource #{0}." \
                    .format(resource.id))
    raise Http404

def _get_sessionid(request):
    """
    Returns the session ID stored in the cookies of the given request.

    The empty string is returned, if there is no session ID available.
    """
    if request.COOKIES:
        return request.COOKIES.get('sessionid', '')
    return ''

@login_required
def create(request):
    """
    Redirects to the Django admin backend editor for resources.
    """
    return redirect(reverse('admin:repo2_resourceinfotype_model_add'))

def view(request, object_id=None):
    """
    Render browse or detail view for the repo2 application.
    """
    # If an object id is given, try to look up the corresponding resource in
    # the Django database, raising HTTP 404 if it cannot be found.
    if object_id:

        resource = get_object_or_404(resourceInfoType_model, pk=object_id)

        # Convert resource to ElementTree and then to template tuples.
        resource_tree = resource.export_to_elementtree()
        lr_content = _convert_to_template_tuples(resource_tree)

        # we need to know if the resource is published or not
        resource_published = resource.storage_object.published

        # Define context for template rendering.
        context = {'resource': resource, 'lr_content': lr_content,
                   'RESOURCE_PUBLISHED': resource_published}
        template = 'repo2/lr_view.html'

        # For staff users, we have to add LR_EDIT which contains the URL of
        # the Django admin backend page for this resource.
        if request.user.is_staff:
            context['LR_EDIT'] = reverse(
                'admin:repo2_resourceinfotype_model_change', args=(object_id,))

        context['LR_DOWNLOAD'] = ""
        try:
            licences = licenceInfoType_model.objects \
                .values("downloadLocation") \
                .filter(back_to_distributioninfotype_model__id=object_id)
            if resource.storage_object.has_download() \
                    or resource.storage_object.has_local_download_copy() \
                    or len(licences) > 0:
                context['LR_DOWNLOAD'] = reverse(download, args=(object_id,))
                if (not request.user.is_active):
                    context['LR_DOWNLOAD'] = "restricted"
        except ObjectDoesNotExist:
            print "Info about licence doesn't exist."

        # Update statistics and create a report about the user actions on LR
        if hasattr(resource.storage_object, 'identifier'):
            sessionid = ""
            if request.COOKIES:
                sessionid = request.COOKIES.get('sessionid', '')
            saveLRStats(request.user.username,
              resource.storage_object.identifier, sessionid, VIEW_STAT)
            context['LR_STATS'] = getLRStats(resource.storage_object.identifier)

    # Otherwise, we just collect all resources from the Django database.
    else:
        resources = resourceInfoType_model.objects.all()

        # Define context for template rendering.
        context = {'resources': resources}
        template = 'repo2/resources.html'

    # Render and return template with the defined context.
    ctx = RequestContext(request)
    return render_to_response(template, context, context_instance=ctx)

class MetashareFacetedSearchView(FacetedSearchView):
    """
    A modified `FacetedSearchView` which makes sure that only such results will
    be returned that are accessible by the current user.
    """
    def get_results(self):
        sqs = super(MetashareFacetedSearchView, self).get_results()
        if not self.request.user.is_staff:
            sqs = sqs.filter(published=True)

        # collect statistics about the query
        starttime = datetime.now()
        results_count = sqs.count()
        if results_count and self.query:
            saveQueryStats(self.request.user.username, '', self.query,
                results_count, (datetime.now() - starttime).microseconds)

        return sqs
<|endoftext|>


<commit_before>import unittest
from method_forwarder import MethodForwarder
try:
  from mock import Mock
except ImportError:
  print "You don't have mock installed. On Unixy systems, run as superuser:"
  print "S apt-get install python-pip # Or the equivalent for your distro"
  print "$ pip install mock"
  print "On Windows, download from http://www.voidspace.org.uk/python/mock/"
  import sys
  sys.exit(1)

class MethodForwarderTest(unittest.TestCase):

  def setUp(self):
    self.mock_forwardee = Mock()

  def test_method_forwarding(self):
    class TestMethodForwarder(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarder, self).__init__()

    self.mock_forwardee.foo_method.return_value = 'a return value'

    test_obj = TestMethodForwarder()
    test_obj.add_forwardee(self.mock_forwardee)

    result = test_obj.foo_method()
    self.assertEquals('a return value', result,
        'method should be forwarded')

  def test_method_forwarding_with_arguments(self):
    class TestMethodForwarderWithArgs(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarderWithArgs, self).__init__()

    def mock_forwardee_method(self, *args, **kwargs):
      return (args[0], kwargs['number'])
    self.mock_forwardee.foo_method = mock_forwardee_method

    test_obj = TestMethodForwarderWithArgs()
    test_obj.add_forwardee(self.mock_forwardee)

    result = test_obj.foo_method('foo', number=5)
    self.assertEquals(('foo', 5), result,
        'arguments should be passed through')

  def test_method_forwarding_with_multiple_forwardees(self):
    class TestMethodForwarderWithMultipleForwardees(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarderWithMultipleForwardees, self).__init__()

    first_forwardee = Mock(['foo_method'])
    second_forwardee = Mock(['bar_method'])

    test_obj = TestMethodForwarderWithMultipleForwardees()
    test_obj.add_forwardee(first_forwardee)
    test_obj.add_forwardee(second_forwardee)

    first_forwardee.foo_method.return_value = 'foo'
    second_forwardee.bar_method.return_value = 'bar'

    first_result = test_obj.foo_method()
    second_result = test_obj.bar_method()

    self.assertEquals('foo', first_result, 'should forward to first_forwardee')
    self.assertEquals('bar', second_result,
      "should forward to second_forwardee as first_forwardee doesn't respond")

  def test_method_forwarding_when_method_missing_from_all_forwardees(self):
    class TestForwardingMethodMissing(MethodForwarder):
      def __init__(self):
        super(TestForwardingMethodMissing, self).__init__()

    first_forwardee = Mock(['foo_method'])
    test_obj = TestForwardingMethodMissing()
    test_obj.add_forwardee(first_forwardee)
    self.assertRaises(NotImplementedError, test_obj.bar_method)

if __name__ == '__main__':
  unittest.main()
<commit_msg>Fixed a typo<commit_after>import unittest
from method_forwarder import MethodForwarder
try:
  from mock import Mock
except ImportError:
  print "You don't have mock installed. On Unixy systems, run as superuser:"
  print "$ apt-get install python-pip # Or the equivalent for your distro"
  print "$ pip install mock"
  print "On Windows, download from http://www.voidspace.org.uk/python/mock/"
  import sys
  sys.exit(1)

class MethodForwarderTest(unittest.TestCase):

  def setUp(self):
    self.mock_forwardee = Mock()

  def test_method_forwarding(self):
    class TestMethodForwarder(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarder, self).__init__()

    self.mock_forwardee.foo_method.return_value = 'a return value'

    test_obj = TestMethodForwarder()
    test_obj.add_forwardee(self.mock_forwardee)

    result = test_obj.foo_method()
    self.assertEquals('a return value', result,
        'method should be forwarded')

  def test_method_forwarding_with_arguments(self):
    class TestMethodForwarderWithArgs(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarderWithArgs, self).__init__()

    def mock_forwardee_method(self, *args, **kwargs):
      return (args[0], kwargs['number'])
    self.mock_forwardee.foo_method = mock_forwardee_method

    test_obj = TestMethodForwarderWithArgs()
    test_obj.add_forwardee(self.mock_forwardee)

    result = test_obj.foo_method('foo', number=5)
    self.assertEquals(('foo', 5), result,
        'arguments should be passed through')

  def test_method_forwarding_with_multiple_forwardees(self):
    class TestMethodForwarderWithMultipleForwardees(MethodForwarder):
      def __init__(self):
        super(TestMethodForwarderWithMultipleForwardees, self).__init__()

    first_forwardee = Mock(['foo_method'])
    second_forwardee = Mock(['bar_method'])

    test_obj = TestMethodForwarderWithMultipleForwardees()
    test_obj.add_forwardee(first_forwardee)
    test_obj.add_forwardee(second_forwardee)

    first_forwardee.foo_method.return_value = 'foo'
    second_forwardee.bar_method.return_value = 'bar'

    first_result = test_obj.foo_method()
    second_result = test_obj.bar_method()

    self.assertEquals('foo', first_result, 'should forward to first_forwardee')
    self.assertEquals('bar', second_result,
      "should forward to second_forwardee as first_forwardee doesn't respond")

  def test_method_forwarding_when_method_missing_from_all_forwardees(self):
    class TestForwardingMethodMissing(MethodForwarder):
      def __init__(self):
        super(TestForwardingMethodMissing, self).__init__()

    first_forwardee = Mock(['foo_method'])
    test_obj = TestForwardingMethodMissing()
    test_obj.add_forwardee(first_forwardee)
    self.assertRaises(NotImplementedError, test_obj.bar_method)

if __name__ == '__main__':
  unittest.main()
<|endoftext|>


<commit_before>from __future__ import unicode_literals
from future.builtins import str
from future.utils import with_metaclass

from bleach import clean

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
from django.forms import MultipleChoiceField
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _

from mezzanine.utils.importing import import_dotted_path

# Tags and attributes added to richtext filtering whitelist when the
# RICHTEXT_FILTER_LEVEL is set to low. General use-case for these is
# allowing embedded video, but we will add to this fixed list over
# time as more use-cases come up. We won't ever add script tags or
# events (onclick etc) to this list. To enable those, filtering can
# be turned off in the settings admin.
LOW_FILTER_TAGS = ("iframe", "embed", "video", "param", "source", "object")
LOW_FILTER_ATTRS = ("allowfullscreen", "autostart", "loop", "hidden",
                    "playcount", "volume", "controls", "data", "classid")

class RichTextField(models.TextField):
    """
    TextField that stores HTML.
    """

    def formfield(self, **kwargs):
        """
        Apply the widget class defined by the
        ``RICHTEXT_WIDGET_CLASS`` setting.
        """
        from mezzanine.conf import settings
        try:
            widget_class = import_dotted_path(settings.RICHTEXT_WIDGET_CLASS)
        except ImportError:
            raise ImproperlyConfigured(_("Could not import the value of "
                                         "settings.RICHTEXT_WIDGET_CLASS: %s"
                                         % settings.RICHTEXT_WIDGET_CLASS))
        kwargs["widget"] = widget_class()
        formfield = super(RichTextField, self).formfield(**kwargs)
        return formfield

    def clean(self, value, model_instance):
        """
        Remove potentially dangerous HTML tags and attributes.
        """
        from mezzanine.conf import settings
        from mezzanine.core.defaults import (RICHTEXT_FILTER_LEVEL_NONE,
                                             RICHTEXT_FILTER_LEVEL_LOW)
        settings.use_editable()
        if settings.RICHTEXT_FILTER_LEVEL == RICHTEXT_FILTER_LEVEL_NONE:
            return value
        tags = settings.RICHTEXT_ALLOWED_TAGS
        attrs = settings.RICHTEXT_ALLOWED_ATTRIBUTES
        styles = settings.RICHTEXT_ALLOWED_STYLES
        if settings.RICHTEXT_FILTER_LEVEL == RICHTEXT_FILTER_LEVEL_LOW:
            tags += LOW_FILTER_TAGS
            attrs += LOW_FILTER_ATTRS
        return clean(value, tags=tags, attributes=attrs, strip=True,
                     strip_comments=False, styles=styles)

class MultiChoiceField(with_metaclass(models.SubfieldBase, models.CharField)):
    """
    Charfield that stores multiple choices selected as a comma
    separated string. Based on http://djangosnippets.org/snippets/2753/
    """

    def formfield(self, *args, **kwargs):
        from mezzanine.core.forms import CheckboxSelectMultiple
        defaults = {
            "required": not self.blank,
            "label": capfirst(self.verbose_name),
            "help_text": self.help_text,
            "choices": self.choices,
            "widget": CheckboxSelectMultiple,
            "initial": self.get_default() if self.has_default() else None,
        }
        defaults.update(kwargs)
        return MultipleChoiceField(**defaults)

    def get_db_prep_value(self, value, **kwargs):
        if isinstance(value, (tuple, list)):
            value = ",".join([str(i) for i in value])
        return value

    def to_python(self, value):
        if isinstance(value, str):
            value = value.split(",")
        return value

    def validate(self, value, instance):
        choices = [str(choice[0]) for choice in self.choices]
        if set(value) - set(choices):
            error = self.error_messages["invalid_choice"] % value
            raise ValidationError(error)

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return ",".join(value)

# Define a ``FileField`` that maps to filebrowser's ``FileBrowseField``
# if available, falling back to Django's ``FileField`` otherwise.
try:
    FileBrowseField = import_dotted_path("%s.fields.FileBrowseField" %
                                         settings.PACKAGE_NAME_FILEBROWSER)
except ImportError:
    class FileField(models.FileField):
        def __init__(self, *args, **kwargs):
            for fb_arg in ("format", "extensions"):
                kwargs.pop(fb_arg, None)
            super(FileField, self).__init__(*args, **kwargs)
else:
    class FileField(FileBrowseField):
        def __init__(self, *args, **kwargs):
            kwargs.setdefault("directory", kwargs.pop("upload_to", None))
            kwargs.setdefault("max_length", 255)
            super(FileField, self).__init__(*args, **kwargs)

HtmlField = RichTextField  # For backward compatibility in south migrations.

# South requires custom fields to be given "rules".
# See http://south.aeracode.org/docs/customfields.html
if "south" in settings.INSTALLED_APPS:
    try:
        from south.modelsinspector import add_introspection_rules
        add_introspection_rules(patterns=["mezzanine\.core\.fields\."],
            rules=[((FileField, RichTextField, MultiChoiceField), [], {})])
    except ImportError:
        pass
<commit_msg>Fixed regression when validating displayable content field against published status<commit_after>from __future__ import unicode_literals
from future.builtins import str
from future.utils import with_metaclass

from bleach import clean

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
from django.forms import MultipleChoiceField
from django.utils.text import capfirst
from django.utils.translation import ugettext_lazy as _

from mezzanine.utils.importing import import_dotted_path

# Tags and attributes added to richtext filtering whitelist when the
# RICHTEXT_FILTER_LEVEL is set to low. General use-case for these is
# allowing embedded video, but we will add to this fixed list over
# time as more use-cases come up. We won't ever add script tags or
# events (onclick etc) to this list. To enable those, filtering can
# be turned off in the settings admin.
LOW_FILTER_TAGS = ("iframe", "embed", "video", "param", "source", "object")
LOW_FILTER_ATTRS = ("allowfullscreen", "autostart", "loop", "hidden",
                    "playcount", "volume", "controls", "data", "classid")

class RichTextField(models.TextField):
    """
    TextField that stores HTML.
    """

    def formfield(self, **kwargs):
        """
        Apply the widget class defined by the
        ``RICHTEXT_WIDGET_CLASS`` setting.
        """
        from mezzanine.conf import settings
        try:
            widget_class = import_dotted_path(settings.RICHTEXT_WIDGET_CLASS)
        except ImportError:
            raise ImproperlyConfigured(_("Could not import the value of "
                                         "settings.RICHTEXT_WIDGET_CLASS: %s"
                                         % settings.RICHTEXT_WIDGET_CLASS))
        kwargs["widget"] = widget_class()
        kwargs.setdefault("required", False)
        formfield = super(RichTextField, self).formfield(**kwargs)
        return formfield

    def clean(self, value, model_instance):
        """
        Remove potentially dangerous HTML tags and attributes.
        """
        from mezzanine.conf import settings
        from mezzanine.core.defaults import (RICHTEXT_FILTER_LEVEL_NONE,
                                             RICHTEXT_FILTER_LEVEL_LOW)
        settings.use_editable()
        if settings.RICHTEXT_FILTER_LEVEL == RICHTEXT_FILTER_LEVEL_NONE:
            return value
        tags = settings.RICHTEXT_ALLOWED_TAGS
        attrs = settings.RICHTEXT_ALLOWED_ATTRIBUTES
        styles = settings.RICHTEXT_ALLOWED_STYLES
        if settings.RICHTEXT_FILTER_LEVEL == RICHTEXT_FILTER_LEVEL_LOW:
            tags += LOW_FILTER_TAGS
            attrs += LOW_FILTER_ATTRS
        return clean(value, tags=tags, attributes=attrs, strip=True,
                     strip_comments=False, styles=styles)

class MultiChoiceField(with_metaclass(models.SubfieldBase, models.CharField)):
    """
    Charfield that stores multiple choices selected as a comma
    separated string. Based on http://djangosnippets.org/snippets/2753/
    """

    def formfield(self, *args, **kwargs):
        from mezzanine.core.forms import CheckboxSelectMultiple
        defaults = {
            "required": not self.blank,
            "label": capfirst(self.verbose_name),
            "help_text": self.help_text,
            "choices": self.choices,
            "widget": CheckboxSelectMultiple,
            "initial": self.get_default() if self.has_default() else None,
        }
        defaults.update(kwargs)
        return MultipleChoiceField(**defaults)

    def get_db_prep_value(self, value, **kwargs):
        if isinstance(value, (tuple, list)):
            value = ",".join([str(i) for i in value])
        return value

    def to_python(self, value):
        if isinstance(value, str):
            value = value.split(",")
        return value

    def validate(self, value, instance):
        choices = [str(choice[0]) for choice in self.choices]
        if set(value) - set(choices):
            error = self.error_messages["invalid_choice"] % value
            raise ValidationError(error)

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return ",".join(value)

# Define a ``FileField`` that maps to filebrowser's ``FileBrowseField``
# if available, falling back to Django's ``FileField`` otherwise.
try:
    FileBrowseField = import_dotted_path("%s.fields.FileBrowseField" %
                                         settings.PACKAGE_NAME_FILEBROWSER)
except ImportError:
    class FileField(models.FileField):
        def __init__(self, *args, **kwargs):
            for fb_arg in ("format", "extensions"):
                kwargs.pop(fb_arg, None)
            super(FileField, self).__init__(*args, **kwargs)
else:
    class FileField(FileBrowseField):
        def __init__(self, *args, **kwargs):
            kwargs.setdefault("directory", kwargs.pop("upload_to", None))
            kwargs.setdefault("max_length", 255)
            super(FileField, self).__init__(*args, **kwargs)

HtmlField = RichTextField  # For backward compatibility in south migrations.

# South requires custom fields to be given "rules".
# See http://south.aeracode.org/docs/customfields.html
if "south" in settings.INSTALLED_APPS:
    try:
        from south.modelsinspector import add_introspection_rules
        add_introspection_rules(patterns=["mezzanine\.core\.fields\."],
            rules=[((FileField, RichTextField, MultiChoiceField), [], {})])
    except ImportError:
        pass
<|endoftext|>


<commit_before>from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import six
import numpy as np
import uuid
import mongoengine
import mongoengine.connection
from nose.tools import make_decorator
from mongoengine.context_managers import switch_db

import fileStore.commands as fc
import fileStore.retrieve as fsr
from fileStore.database.file_base import FileBase
from fileStore.database.file_event_link import FileEventLink
from numpy.testing import assert_array_equal

from .t_utils import SynHandlerMod, SynHandlerEcho

db_name = str(uuid.uuid4())
dummy_db_name = str(uuid.uuid4())

def setup():
    # need to make 'default' connection to point to no-where, just to be safe
    mongoengine.connect(dummy_db_name)
    # connect to the db we are actually going to use
    mongoengine.connect(db_name, alias='test_db')
    # register the dummy handler to use
    fsr.register_handler('syn-mod', SynHandlerMod)

def teardown():
    conn = mongoengine.connection.get_connection('test_db')
    conn.drop_database(db_name)
    conn.drop_database(dummy_db_name)
    del fsr._h_registry['syn-mod']

def context_decorator(func):
    def inner():
        with switch_db(FileBase, 'test_db'), \
          switch_db(FileEventLink, 'test_db'):
            func()

    return make_decorator(func)(inner)

def _insert_syn_data(f_type, shape, count):
    fb = fc.save_file_base(f_type, '',
                           {'shape': shape})
    ret = []
    for k in range(count):
        r_id = str(uuid.uuid4())
        fc.save_file_event_link(fb, r_id, {'n': k + 1})
        ret.append(r_id)
    return ret

@context_decorator
def test_round_trip():
    shape = (25, 32)
    mod_ids = _insert_syn_data('syn-mod', shape, 10)

    for j, r_id in enumerate(mod_ids):
        data = fc.retrieve_data(r_id)
        known_data = np.mod(np.arange(np.prod(shape)), j + 1).reshape(shape)
        assert_array_equal(data, known_data)
<commit_msg>TST : add test for failed find<commit_after>from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import six
import numpy as np
import uuid
import mongoengine
import mongoengine.connection
from nose.tools import make_decorator
from mongoengine.context_managers import switch_db

import fileStore.commands as fc
import fileStore.retrieve as fsr
from fileStore.database.file_base import FileBase
from fileStore.database.file_event_link import FileEventLink
from numpy.testing import assert_array_equal
from nose.tools import assert_raises

from .t_utils import SynHandlerMod

db_name = str(uuid.uuid4())
dummy_db_name = str(uuid.uuid4())

def setup():
    # need to make 'default' connection to point to no-where, just to be safe
    mongoengine.connect(dummy_db_name)
    # connect to the db we are actually going to use
    mongoengine.connect(db_name, alias='test_db')
    # register the dummy handler to use
    fsr.register_handler('syn-mod', SynHandlerMod)

def teardown():
    conn = mongoengine.connection.get_connection('test_db')
    conn.drop_database(db_name)
    conn.drop_database(dummy_db_name)
    del fsr._h_registry['syn-mod']

def context_decorator(func):
    def inner():
        with switch_db(FileBase, 'test_db'), \
          switch_db(FileEventLink, 'test_db'):
            func()

    return make_decorator(func)(inner)

def _insert_syn_data(f_type, shape, count):
    fb = fc.save_file_base(f_type, '',
                           {'shape': shape})
    ret = []
    for k in range(count):
        r_id = str(uuid.uuid4())
        fc.save_file_event_link(fb, r_id, {'n': k + 1})
        ret.append(r_id)
    return ret

@context_decorator
def test_round_trip():
    shape = (25, 32)
    mod_ids = _insert_syn_data('syn-mod', shape, 10)

    for j, r_id in enumerate(mod_ids):
        data = fc.retrieve_data(r_id)
        known_data = np.mod(np.arange(np.prod(shape)), j + 1).reshape(shape)
        assert_array_equal(data, known_data)

@context_decorator
def test_non_exist():
    assert_raises(ValueError, fc.retrieve_data, 'aardvark')
<|endoftext|>


<commit_before>from __future__ import unicode_literals

import os
import sys

from django.contrib.sites.models import Site

from mezzanine.conf import settings
from mezzanine.core.request import current_request

def current_site_id():
    """
    Responsible for determining the current ``Site`` instance to use
    when retrieving data for any ``SiteRelated`` models. If a request
    is available, and the site can be determined from it, we store the
    site against the request for subsequent retrievals. Otherwise the
    order of checks is as follows:

      - ``site_id`` in session. Used in the admin so that admin users
        can switch sites and stay on the same domain for the admin.
      - host for the current request matched to the domain of the site
        instance.
      - ``MEZZANINE_SITE_ID`` environment variable, so management
        commands or anything else outside of a request can specify a
        site.
      - ``SITE_ID`` setting.

    """
    from mezzanine.utils.cache import cache_installed, cache_get, cache_set
    request = current_request()
    site_id = getattr(request, "site_id", None)
    if request and not site_id:
        site_id = request.session.get("site_id", None)
        if not site_id:
            domain = request.get_host().lower()
            if cache_installed():
                # Don't use Mezzanine's cache_key_prefix here, since it
                # uses this very function we're in right now to create a
                # per-site cache key.
                bits = (settings.CACHE_MIDDLEWARE_KEY_PREFIX, domain)
                cache_key = "%s.site_id.%s" % bits
                site_id = cache_get(cache_key)
            if not site_id:
                try:
                    site = Site.objects.get(domain__iexact=domain)
                except Site.DoesNotExist:
                    pass
                else:
                    site_id = site.id
                    if cache_installed():
                        cache_set(cache_key, site_id)
            if request and site_id:
                request.site_id = site_id
    if not site_id:
        site_id = os.environ.get("MEZZANINE_SITE_ID", settings.SITE_ID)
    if request and site_id and not getattr(settings, "TESTING", False):
        request.site_id = site_id
    return site_id

def has_site_permission(user):
    """
    Checks if a staff user has staff-level access for the current site.
    The actual permission lookup occurs in ``SitePermissionMiddleware``
    which then marks the request with the ``has_site_permission`` flag,
    so that we only query the db once per request, so this function
    serves as the entry point for everything else to check access. We
    also fall back to an ``is_staff`` check if the middleware is not
    installed, to ease migration.
    """
    mw = "mezzanine.core.middleware.SitePermissionMiddleware"
    if mw not in settings.MIDDLEWARE_CLASSES:
        from warnings import warn
        warn(mw + " missing from settings.MIDDLEWARE_CLASSES - per site"
             "permissions not applied")
        return user.is_staff and user.is_active
    return getattr(user, "has_site_permission", False)

def host_theme_path():
    """
    Returns the directory of the theme associated with the given host.
    """
    domain = None  # Set domain to None, which we'll then query for in
                   # the first iteration of HOST_THEMES. We use the
                   # current site_id rather than a request object here,
                   # as it may differ for admin users.
    for (host, theme) in settings.HOST_THEMES:
        if domain is None:
            domain = Site.objects.get(id=current_site_id()).domain
        if host.lower() == domain.lower():
            try:
                __import__(theme)
                module = sys.modules[theme]
            except ImportError:
                pass
            else:
                return os.path.dirname(os.path.abspath(module.__file__))
    return ""

def templates_for_host(templates):
    """
    Given a template name (or list of them), returns the template names
    as a list, with each name prefixed with the device directory
    inserted into the front of the list.
    """
    if not isinstance(templates, (list, tuple)):
        templates = [templates]
    theme_dir = host_theme_path()
    host_templates = []
    if theme_dir:
        for template in templates:
            host_templates.append("%s/templates/%s" % (theme_dir, template))
            host_templates.append(template)
        return host_templates
    return templates
<commit_msg>Fix comment formatting<commit_after>from __future__ import unicode_literals

import os
import sys

from django.contrib.sites.models import Site

from mezzanine.conf import settings
from mezzanine.core.request import current_request

def current_site_id():
    """
    Responsible for determining the current ``Site`` instance to use
    when retrieving data for any ``SiteRelated`` models. If a request
    is available, and the site can be determined from it, we store the
    site against the request for subsequent retrievals. Otherwise the
    order of checks is as follows:

      - ``site_id`` in session. Used in the admin so that admin users
        can switch sites and stay on the same domain for the admin.
      - host for the current request matched to the domain of the site
        instance.
      - ``MEZZANINE_SITE_ID`` environment variable, so management
        commands or anything else outside of a request can specify a
        site.
      - ``SITE_ID`` setting.

    """
    from mezzanine.utils.cache import cache_installed, cache_get, cache_set
    request = current_request()
    site_id = getattr(request, "site_id", None)
    if request and not site_id:
        site_id = request.session.get("site_id", None)
        if not site_id:
            domain = request.get_host().lower()
            if cache_installed():
                # Don't use Mezzanine's cache_key_prefix here, since it
                # uses this very function we're in right now to create a
                # per-site cache key.
                bits = (settings.CACHE_MIDDLEWARE_KEY_PREFIX, domain)
                cache_key = "%s.site_id.%s" % bits
                site_id = cache_get(cache_key)
            if not site_id:
                try:
                    site = Site.objects.get(domain__iexact=domain)
                except Site.DoesNotExist:
                    pass
                else:
                    site_id = site.id
                    if cache_installed():
                        cache_set(cache_key, site_id)
            if request and site_id:
                request.site_id = site_id
    if not site_id:
        site_id = os.environ.get("MEZZANINE_SITE_ID", settings.SITE_ID)
    if request and site_id and not getattr(settings, "TESTING", False):
        request.site_id = site_id
    return site_id

def has_site_permission(user):
    """
    Checks if a staff user has staff-level access for the current site.
    The actual permission lookup occurs in ``SitePermissionMiddleware``
    which then marks the request with the ``has_site_permission`` flag,
    so that we only query the db once per request, so this function
    serves as the entry point for everything else to check access. We
    also fall back to an ``is_staff`` check if the middleware is not
    installed, to ease migration.
    """
    mw = "mezzanine.core.middleware.SitePermissionMiddleware"
    if mw not in settings.MIDDLEWARE_CLASSES:
        from warnings import warn
        warn(mw + " missing from settings.MIDDLEWARE_CLASSES - per site"
             "permissions not applied")
        return user.is_staff and user.is_active
    return getattr(user, "has_site_permission", False)

def host_theme_path():
    """
    Returns the directory of the theme associated with the given host.
    """

    # Set domain to None, which we'll then query for in the first
    # iteration of HOST_THEMES. We use the current site_id rather
    # than a request object here, as it may differ for admin users.
    domain = None

    for (host, theme) in settings.HOST_THEMES:
        if domain is None:
            domain = Site.objects.get(id=current_site_id()).domain
        if host.lower() == domain.lower():
            try:
                __import__(theme)
                module = sys.modules[theme]
            except ImportError:
                pass
            else:
                return os.path.dirname(os.path.abspath(module.__file__))
    return ""

def templates_for_host(templates):
    """
    Given a template name (or list of them), returns the template names
    as a list, with each name prefixed with the device directory
    inserted into the front of the list.
    """
    if not isinstance(templates, (list, tuple)):
        templates = [templates]
    theme_dir = host_theme_path()
    host_templates = []
    if theme_dir:
        for template in templates:
            host_templates.append("%s/templates/%s" % (theme_dir, template))
            host_templates.append(template)
        return host_templates
    return templates
<|endoftext|>


<commit_before>class YQLV(object) :
    RSS_NEWS_URL = 'http://finance.yahoo.com/rss/headline?s='
    YAHOO_URL = 'http://query.yahooapis.com/v1/public/yql'
    DATATABLES_URL = 'store://datatables.org/alltableswithkeys'
    quotes = 'yahoo.finance.quotes'
    options = 'yahoo.finance.options'
    quoteslist = 'yahoo.finance.quoteslist'
    sectors = 'yahoo.finance.sectors'
    industry = 'yahoo.finance.industry'
class YQLBase(object) :
    class Query(object):
        def __call__(self, yql):
            import urllib.parse, json
            queryString = urllib.parse.urlencode({'q': yql, 'format': 'json', 'env': YQLV.DATATABLES_URL})
            url = YQLV.YAHOO_URL + '?' + queryString
            ret = WebUtils.invoke_url(url)
            ret = json.loads(ret)
            return ret
        def __is_valid_response(self, response, field):
            return 'query' in response and 'results' in response['query'] and field in response['query']['results']
        def validate_response(self, response, tagToCheck):
            if self.__is_valid_response(response, tagToCheck):
                ret = response['query']['results'][tagToCheck]
            else:
                if 'error' in response:
                    raise IOError('YQL query failed with error: "%s".' % response['error']['description'])
                else:
                    raise IOError('YQL response malformed.')
            return ret
    class Stock(object) :
        def __init__(self,query,table,tag) :
            self.query = query
            self.table = table
            self.tag = tag
        def __call__(self,symbol, columns='*') :
            yql = 'select %s from %s where symbol in (\'%s\')' %(columns, self.table, symbol)
            print(yql)
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
class YQL(object) :
    class StockQuote(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.quotes,'quote')
    class StockOptions(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.options,'optionsChain')
    class StockQuoteSummary(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.quoteslist,'quote')
    class StockNameBySector(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.sectors,'sector')
        def __call__(self) :
            yql = 'select * from %s' % self.table
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
    class StockByIndustry(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.industry,'industry')
        def __call__(self,id) :
            yql = 'select * from %s where id =\'%s\'' % (self.table, id)
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
    class NewsFeed(object) :
        def __init__(self,query=YQLBase.Query()) :
            self.query = query
        def __call__(self,symbol) :
            if '^' in symbol : return None
            yql = 'select title,link, pubDate from rss where url=\'%s%s\'' % (YQLV.RSS_NEWS_URL,symbol)
            ret = self.query(yql)
            if ret is None  :return None
            if 'query' in ret : ret = ret['query']
            if ret is None  :return None
            if 'results' in ret : ret = ret['results']
            if ret is None  :return None
            if 'item' in ret : ret = ret['item']
            if ret is None  :return None
            print (type(ret))
            if isinstance(ret,list) :
                if 'title' in ret[0] and ret[0]['title'].find('not found') > 0:
                    raise IOError('Feed for %s does not exist.' % symbol)
            elif isinstance(ret,dict) :
                if 'error' in ret :
                    raise IOError('Failed to read feed for %s : %s ' % (symbol,ret['error']))
                else :
                    print(ret.keys())
            else :
                print(type(ret))
            return ret
    class NewsFeedList(object) :
        def __init__(self,query) :
            self.query = query
            self.fresh = {}
            self.cache = {}
        def __call__(self,stock) :
            if stock not in self.cache.keys() or not self.fresh[stock]():
                ret = self.query(stock)
                self.fresh[stock] = TimeUtil.ExpireTimer(24*60)
                self.cache[stock] = self.__transform(ret)
            return self.cache[stock]
        def __transform(self,rss) :
            if rss is None : return rss
            for item in rss :
                del (item['title'])
                url = item['link'].split('*')[1]
                soup = WebUtils.format_noodle(url)
                if soup is None : soup = WebUtils.format_yahoo_finance(url)
                if soup is None : soup = WebUtils.format_biz_yahoo(url)
                if soup is None : soup = WebUtils.format_investopedia(url)
                if soup is None : soup = WebUtils.format_generic(url)
                item['link'] = soup
            return rss
<commit_msg>Update YqlUtils.py<commit_after>class YQLV(object) :
    RSS_NEWS_URL = 'http://finance.yahoo.com/rss/headline?s='
    YAHOO_URL = 'http://query.yahooapis.com/v1/public/yql'
    DATATABLES_URL = 'store://datatables.org/alltableswithkeys'
    quotes = 'yahoo.finance.quotes'
    options = 'yahoo.finance.options'
    quoteslist = 'yahoo.finance.quoteslist'
    sectors = 'yahoo.finance.sectors'
    industry = 'yahoo.finance.industry'
class YQLBase(object) :
    class Query(object):
        def __call__(self, yql):
            import urllib.parse, json
            queryString = urllib.parse.urlencode({'q': yql, 'format': 'json', 'env': YQLV.DATATABLES_URL})
            url = YQLV.YAHOO_URL + '?' + queryString
            ret = WebUtils.invoke_url(url)
            ret = json.loads(ret)
            return ret
        def __is_valid_response(self, response, field):
            return 'query' in response and 'results' in response['query'] and field in response['query']['results']
        def validate_response(self, response, tagToCheck):
            if self.__is_valid_response(response, tagToCheck):
                ret = response['query']['results'][tagToCheck]
            else:
                if 'error' in response:
                    raise IOError('YQL query failed with error: "%s".' % response['error']['description'])
                else:
                    raise IOError('YQL response malformed.')
            return ret
    class Stock(object) :
        def __init__(self,query,table,tag) :
            self.query = query
            self.table = table
            self.tag = tag
        def __call__(self,symbol, columns='*') :
            #yql = 'select title, link, description, pubDate from rss where url=\'%s%s\'' % (YQLNews.RSS_URL,symbol)
            yql = 'select %s from %s where symbol in (\'%s\')' %(columns, self.table, symbol)
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
class YQL(object) :
    class StockQuote(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.quotes,'quote')
    class StockOptions(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.options,'optionsChain')
    class StockQuoteSummary(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.quoteslist,'quote')
    class StockNameBySector(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.sectors,'sector')
        def __call__(self) :
            yql = 'select * from %s' % self.table
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
    class StockByIndustry(YQLBase.Stock) :
        def __init__(self) :
            Stock.__init__(self,Query(),YQLV.industry,'industry')
        def __call__(self,id) :
            yql = 'select * from %s where id =\'%s\'' % (self.table, id)
            ret = self.query(yql)
            return self.query.validate_response(ret, self.tag)
    class NewsFeed(object) :
        def __init__(self,query=YQLBase.Query()) :
            self.query = query
        def __call__(self,symbol) :
            if '^' in symbol : return None
            yql = 'select title,link, pubDate from rss where url=\'%s%s\'' % (YQLV.RSS_NEWS_URL,symbol)
            ret = self.query(yql)
            if ret is None  :return None
            if 'query' in ret : ret = ret['query']
            if ret is None  :return None
            if 'results' in ret : ret = ret['results']
            if ret is None  :return None
            if 'item' in ret : ret = ret['item']
            if ret is None  :return None
            print (type(ret))
            if isinstance(ret,list) :
                if 'title' in ret[0] and ret[0]['title'].find('not found') > 0:
                    raise IOError('Feed for %s does not exist.' % symbol)
            elif isinstance(ret,dict) :
                if 'error' in ret :
                    raise IOError('Failed to read feed for %s : %s ' % (symbol,ret['error']))
                else :
                    print(ret.keys())
            else :
                print(type(ret))
            return ret
    class NewsFeedList(object) :
        def __init__(self,query) :
            self.query = query
            self.fresh = {}
            self.cache = {}
        def __call__(self,stock) :
            if stock not in self.cache.keys() or not self.fresh[stock]():
                ret = self.query(stock)
                self.fresh[stock] = TimeUtil.ExpireTimer(24*60)
                self.cache[stock] = self.__transform(ret)
            return self.cache[stock]
        def __transform(self,rss) :
            if rss is None : return rss
            for item in rss :
                del (item['title'])
                url = item['link'].split('*')[1]
                soup = WebUtils.format_noodle(url)
                if soup is None : soup = WebUtils.format_yahoo_finance(url)
                if soup is None : soup = WebUtils.format_biz_yahoo(url)
                if soup is None : soup = WebUtils.format_investopedia(url)
                if soup is None : soup = WebUtils.format_generic(url)
                item['link'] = soup
            return rss
<|endoftext|>


<commit_before>from stationspinner.celery import app
from stationspinner.libs.eveapihandler import EveAPIHandler
from stationspinner.accounting.models import APIKey, APIUpdate
from stationspinner.corporation.models import CorporationSheet, AssetList, \
    MarketOrder, Medal, MemberMedal, MemberSecurity, MemberSecurityLog, \
    MemberTitle, MemberTracking, ContractItem, AccountBalance, Contact, \
    ContainerLog, Contract, ContractBid, NPCStanding, Facilities, \
    OutpostService, Shareholder, Starbase, StarbaseFuel, IndustryJob, \
    IndustryJobHistory, Outpost, WalletTransaction, WalletJournal, Asset, \
    Blueprint

from stationspinner.libs.eveapi.eveapi import AuthenticationError

from celery.utils.log import get_task_logger

log = get_task_logger(__name__)

def _get_corporation_auth(apiupdate_pk):
    try:
        target = APIUpdate.objects.get(pk=apiupdate_pk)
    except APIUpdate.DoesNotExist, dne:
        log.error('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        raise dne

    corporation = CorporationSheet.objects.get(pk=target.owner)

    return target, corporation

@app.task(name='corporation.fetch_corporationsheet', max_retries=0)
def fetch_corporationsheet(apiupdate_pk):
    try:
        target = APIUpdate.objects.get(pk=apiupdate_pk)
    except APIUpdate.DoesNotExist, dne:
        log.error('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        raise dne

    apikey = target.apikey

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(apikey)
    try:
        sheet = auth.corp.CorporationSheet(characterID=apikey.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    try:
        corporation = CorporationSheet.objects.get(corporationID=sheet.corporationID)

        # As long as the apikey can get a valid character sheet back from the
        # eveapi, we'll allow the CS model to change owner and/or key
        if corporation.owner_key != apikey:
            log.warning('Corporation {0} "{1}" changed APIKey to keyID={2}.'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                apikey.keyID))
        if corporation.owner != apikey.owner:
            log.warning('Corporation {0} "{1}" changed owner from "{2}" to "{3}".'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                corporation.owner,
                                                                                apikey.owner))
    except CorporationSheet.DoesNotExist:
        corporation = CorporationSheet(corporationID=sheet.corporationID)
    except Exception, ex:
        log.warning('Corporation {0} "{1}" could not be updated with APIKey {2}.'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                apikey.keyID))
        raise ex

    corporation.owner_key = apikey
    corporation.owner = apikey.owner
    corporation.update_from_api(sheet, handler)

    log.info('Corporation {0} "{1}" updated.'.format(sheet.corporationID,
                                                      sheet.corporationName))
    target.updated(sheet)
    return corporation.pk

@app.task(name='corporation.fetch_assetlist', max_retries=0)
def fetch_assetlist(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.AssetList(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    assetlist = AssetList(owner=corporation,
                          retrieved=api_data._meta.currentTime)

    assetlist.items = handler.asset_parser(api_data.assets,
                                           Asset,
                                           corporation)
    assetlist.save()
    target.updated(api_data)

@app.task(name='corporation.fetch_membertracking', max_retries=0)
def fetch_membertracking(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.MemberTracking(characterID=corporation.owner_key.characterID,
                                        extended=1)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return
    handler.autoparse_list(api_data.members,
                          MemberTracking,
                          unique_together=('characterID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    target.updated(api_data)

@app.task(name='corporation.fetch_startbaselist', max_retries=0)
def fetch_starbaselist(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.StarbaseList(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    handler.autoparse_list(api_data.starbases,
                          Starbase,
                          unique_together=('itemID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    target.updated(api_data)

@app.task(name='corporation.fetch_blueprints', max_retries=0)
def fetch_blueprints(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)

    try:
        api_data = auth.corp.Blueprints(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    blueprintsIDs = handler.autoparse_list(api_data.blueprints,
                          Blueprint,
                          unique_together=('itemID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)

    Blueprint.objects.filter(owner=corporation) \
        .exclude(pk__in=blueprintsIDs).delete()
    target.updated(api_data)

@app.task(name='corporation.fetch_accountbalance', max_retries=0)
def fetch_accountbalance(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.AccountBalance(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return
    handler.autoparse_list(api_data.accounts,
                          AccountBalance,
                          unique_together=('accountKey',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    target.updated(api_data)

API_MAP = {
        'AssetList': (fetch_assetlist, fetch_blueprints),
        'AccountBalance': (fetch_accountbalance,),
        'MemberTrackingExtended': (fetch_membertracking,),
        'StarbaseList': (fetch_starbaselist,),
    }<commit_msg>Add purging of poses and members<commit_after>from stationspinner.celery import app
from stationspinner.libs.eveapihandler import EveAPIHandler
from stationspinner.accounting.models import APIKey, APIUpdate
from stationspinner.corporation.models import CorporationSheet, AssetList, \
    MarketOrder, Medal, MemberMedal, MemberSecurity, MemberSecurityLog, \
    MemberTitle, MemberTracking, ContractItem, AccountBalance, Contact, \
    ContainerLog, Contract, ContractBid, NPCStanding, Facilities, \
    OutpostService, Shareholder, Starbase, StarbaseFuel, IndustryJob, \
    IndustryJobHistory, Outpost, WalletTransaction, WalletJournal, Asset, \
    Blueprint

from stationspinner.libs.eveapi.eveapi import AuthenticationError

from celery.utils.log import get_task_logger

log = get_task_logger(__name__)

def _get_corporation_auth(apiupdate_pk):
    try:
        target = APIUpdate.objects.get(pk=apiupdate_pk)
    except APIUpdate.DoesNotExist, dne:
        log.error('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        raise dne

    corporation = CorporationSheet.objects.get(pk=target.owner)

    return target, corporation

@app.task(name='corporation.fetch_corporationsheet', max_retries=0)
def fetch_corporationsheet(apiupdate_pk):
    try:
        target = APIUpdate.objects.get(pk=apiupdate_pk)
    except APIUpdate.DoesNotExist, dne:
        log.error('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        raise dne

    apikey = target.apikey

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(apikey)
    try:
        sheet = auth.corp.CorporationSheet(characterID=apikey.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    try:
        corporation = CorporationSheet.objects.get(corporationID=sheet.corporationID)

        # As long as the apikey can get a valid character sheet back from the
        # eveapi, we'll allow the CS model to change owner and/or key
        if corporation.owner_key != apikey:
            log.warning('Corporation {0} "{1}" changed APIKey to keyID={2}.'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                apikey.keyID))
        if corporation.owner != apikey.owner:
            log.warning('Corporation {0} "{1}" changed owner from "{2}" to "{3}".'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                corporation.owner,
                                                                                apikey.owner))
    except CorporationSheet.DoesNotExist:
        corporation = CorporationSheet(corporationID=sheet.corporationID)
    except Exception, ex:
        log.warning('Corporation {0} "{1}" could not be updated with APIKey {2}.'.format(sheet.corporationID,
                                                                                sheet.corporationName,
                                                                                apikey.keyID))
        raise ex

    corporation.owner_key = apikey
    corporation.owner = apikey.owner
    corporation.update_from_api(sheet, handler)

    log.info('Corporation {0} "{1}" updated.'.format(sheet.corporationID,
                                                      sheet.corporationName))
    target.updated(sheet)
    return corporation.pk

@app.task(name='corporation.fetch_assetlist', max_retries=0)
def fetch_assetlist(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.AssetList(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    assetlist = AssetList(owner=corporation,
                          retrieved=api_data._meta.currentTime)

    assetlist.items = handler.asset_parser(api_data.assets,
                                           Asset,
                                           corporation)
    assetlist.save()
    target.updated(api_data)

@app.task(name='corporation.fetch_membertracking', max_retries=0)
def fetch_membertracking(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.MemberTracking(characterID=corporation.owner_key.characterID,
                                        extended=1)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return
    memberIDs = handler.autoparse_list(api_data.members,
                          MemberTracking,
                          unique_together=('characterID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    MemberTracking.objects.filter(owner=corporation) \
        .exclude(pk_in=memberIDs).delete()

    target.updated(api_data)

@app.task(name='corporation.fetch_startbaselist', max_retries=0)
def fetch_starbaselist(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.StarbaseList(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    posIDs = handler.autoparse_list(api_data.starbases,
                          Starbase,
                          unique_together=('itemID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    Starbase.objects.filter(owner=corporation) \
        .exclude(pk_in=posIDs).delete()
    target.updated(api_data)

@app.task(name='corporation.fetch_blueprints', max_retries=0)
def fetch_blueprints(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)

    try:
        api_data = auth.corp.Blueprints(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return

    blueprintsIDs = handler.autoparse_list(api_data.blueprints,
                          Blueprint,
                          unique_together=('itemID',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)

    Blueprint.objects.filter(owner=corporation) \
        .exclude(pk__in=blueprintsIDs).delete()
    target.updated(api_data)

@app.task(name='corporation.fetch_accountbalance', max_retries=0)
def fetch_accountbalance(apiupdate_pk):
    try:
        target, corporation = _get_corporation_auth(apiupdate_pk)
    except CorporationSheet.DoesNotExist:
        log.debug('CorporationSheet for APIUpdate {0} not indexed yet.'.format(apiupdate_pk))
        return
    except APIUpdate.DoesNotExist:
        log.warning('Target APIUpdate {0} was deleted mid-flight.'.format(apiupdate_pk))
        return

    handler = EveAPIHandler()
    auth = handler.get_authed_eveapi(corporation.owner_key)
    try:
        api_data = auth.corp.AccountBalance(characterID=corporation.owner_key.characterID)
    except AuthenticationError:
        log.error('AuthenticationError for key "{0}" owned by "{1}"'.format(
            target.apikey.keyID,
            target.apikey.owner
        ))
        target.delete()
        return
    handler.autoparse_list(api_data.accounts,
                          AccountBalance,
                          unique_together=('accountKey',),
                          extra_selectors={'owner': corporation},
                          owner=corporation,
                          pre_save=True)
    target.updated(api_data)

API_MAP = {
        'AssetList': (fetch_assetlist, fetch_blueprints),
        'AccountBalance': (fetch_accountbalance,),
        'MemberTrackingExtended': (fetch_membertracking,),
        'StarbaseList': (fetch_starbaselist,),
    }<|endoftext|>