<commit_before>from datetime import datetime, date

from django.contrib.contenttypes.models import ContentType
from django.template import RequestContext
from django.core.paginator import Paginator
from django.conf import settings
from django.template.defaultfilters import slugify
from django.db import models
from django.http import Http404

from ella.core.models import Listing, Category, Placement
from ella.core.cache import get_cached_object_or_404, cache_this
from ella.core import custom_urls
from ella.core.cache.template_loader import render_to_response

__docformat__ = "restructuredtext en"

# local cache for get_content_type()
CONTENT_TYPE_MAPPING = {}
CACHE_TIMEOUT_LONG = getattr(settings, 'CACHE_TIMEOUT_LONG', 60 * 60)

def get_content_type(ct_name):
    """
    A helper function that returns ContentType object based on its slugified verbose_name_plural.

    Results of this function is cached to improve performance.

    :Parameters: 
        - `ct_name`:  Slugified verbose_name_plural of the target model.

    :Exceptions: 
        - `Http404`: if no matching ContentType is found
    """
    try:
        ct = CONTENT_TYPE_MAPPING[ct_name]
    except KeyError:
        for model in models.get_models():
            if ct_name == slugify(model._meta.verbose_name_plural):
                ct = ContentType.objects.get_for_model(model)
                CONTENT_TYPE_MAPPING[ct_name] = ct
                break
        else:
            raise Http404
    return ct

def object_detail(request, category, content_type, slug, year=None, month=None, day=None, url_remainder=None):
    """
    Renders a page for placement. All the data fetching and context creation is done in `_object_detail`.
    If `url_remainder` is specified, tries to locate custom view via `custom_urls.dispatcher`. Renders a template 
    returned by `get_template` with context returned by `_object_detail`.

    :Parameters:
        - `request`: `HttpRequest` from Django
        - `category, content_type, slug, year, month, day`: parameters passed on to `_object_detail`
        - `url_remainder`: url after the object's url, used to locate custom views in `custom_urls.dispatcher`

    :Exceptions: 
        - `Http404`: if the URL is not valid and/or doesn't correspond to any valid `Placement`
    """
    context = _object_detail(request.user, category, content_type, slug, year, month, day)

    obj = context['object']
    # check for custom actions
    if url_remainder:
        bits = url_remainder.split('/')
        return custom_urls.dispatcher.call_view(request, bits, context)
    elif custom_urls.dispatcher.has_custom_detail(obj):
        return custom_urls.dispatcher.call_custom_detail(request, context)

    return render_to_response(
        get_templates('object.html', slug, context['category'], context['content_type'].app_label, context['content_type'].model),
        context,
        context_instance=RequestContext(request)
    )

def category_detail(request, category):
    context = _category_detail(category)
    return render_to_response(
            (
            'page/category/%s/category.html' % (context["category"].path),
            'page/category.html',
            ),
            context,
            context_instance=RequestContext(request)
        )

def list_content_type(request, category=None, year=None, month=None, day=None, content_type=None, paginate_by=20):
    # pagination
    if 'p' in request.GET and request.GET['p'].isdigit():
        page_no = int(request.GET['p'])
    else:
        page_no = 1

    context = _list_content_type(category, year, month, day, content_type, page_no, paginate_by)
    if content_type:
        ct = get_content_type(content_type)
    else:
        ct = False
    template_list = []
    if ct:
        template_list.append('page/category/%s/content_type/%s.%s/listing.html' % (context["cat"].path, ct.app_label, ct.model))
    template_list.append('page/category/%s/listing.html' % (context["cat"].path))
    if ct:
        template_list.append('page/content_type/%s.%s/listing.html' % (ct.app_label, ct.model))
    template_list.append('page/listing.html')
    return render_to_response(
            template_list,
            context,
            context_instance=RequestContext(request)
        )

def home(request):
    """
    Homepage of the actual site.

    :Parameters: 
        - `request`: `HttpRequest` from Django

    :Exceptions: 
        - `Http404`: if there is no base category
    """
    context = _category_detail()
    return render_to_response(
            (
            'page/category/%s/category.html' % (context['category'].path),
            'page/category.html',
            ),
            context,
            context_instance=RequestContext(request)
        )

def _object_detail(user, category, content_type, slug, year=None, month=None, day=None):
    """
    Helper function that does all the data fetching for `object_detail` view. It
    returns a dictionary containing:

        - `placement`: `Placement` instance representing the URL accessed
        - `object`: `Publishable` instance bound to the `placement`
        - `category`: `Category` of the `placement`
        - `content_type_name`: slugified plural verbose name of the publishable's content type
        - `content_type`: `ContentType` of the publishable

    :Parameters: 
        - `user`: django `User` instance
        - `category`: `Category.tree_path` (empty if home category)
        - `year`, `month`, `day`: date matching the `publish_from` field of the `Placement` object
        - `content_type`: slugified `verbose_name_plural` of the target model
        - `slug`: slug of the `Placement`

    :Exceptions:
        - `Http404`: if object or placement doesn't exist or dates don't match
    """
    ct = get_content_type(content_type)

    if category:
        cat = get_cached_object_or_404(Category, tree_path=category, site__id=settings.SITE_ID)
    else:
        cat = get_cached_object_or_404(Category, tree_parent__isnull=True, site__id=settings.SITE_ID)

    if year:
        placement = get_cached_object_or_404(Placement,
                    publish_from__year=year,
                    publish_from__month=month,
                    publish_from__day=day,
                    publishable__content_type=ct,
                    category=cat,
                    slug=slug,
                    static=False
                )
    else:
        placement = get_cached_object_or_404(Placement, category=cat, publishable__content_type=ct, slug=slug, static=True)

    if not (placement.is_active() or user.is_staff):
        # future placement, render if accessed by logged in staff member
        raise Http404

    obj = placement.publishable.target

    context = {
            'placement' : placement,
            'object' : obj,
            'category' : cat,
            'content_type_name' : content_type,
            'content_type' : ct,
        }

    return context


def get_templates(name, slug=None, category=None, app_label=None, model_label=None):
    """
    Returns templates in following format and order:

        - 'page/category/%s/content_type/%s.%s/%s/%s' % ( category.path, app_label, model_label, slug, name ),
        - 'page/category/%s/content_type/%s.%s/%s' % ( category.path, app_label, model_label, name ),
        - 'page/category/%s/%s' % ( category.path, name ),
        - 'page/content_type/%s.%s/%s' % ( app_label, model_label, name ),
        - 'page/%s' % name,
    """<commit_msg>Migrated ella.core.views to use class based views<commit_after>from datetime import datetime, date

from django.contrib.contenttypes.models import ContentType
from django.template import RequestContext
from django.core.paginator import Paginator
from django.conf import settings
from django.template.defaultfilters import slugify
from django.db import models
from django.http import Http404

from ella.core.models import Listing, Category, Placement
from ella.core.cache import get_cached_object_or_404, cache_this
from ella.core import custom_urls
from ella.core.cache.template_loader import render_to_response

__docformat__ = "restructuredtext en"

# local cache for get_content_type()
CONTENT_TYPE_MAPPING = {}
CACHE_TIMEOUT_LONG = getattr(settings, 'CACHE_TIMEOUT_LONG', 60 * 60)

class EllaCoreView(object):
    ' Base class for class-based views used in ella.core.views. '

    # name of the template to be passed into get_templates
    template_name = 'TEMPLATE'

    def get_context(self, request, **kwargs):
        """
        Return a dictionary that will be then passed into the template as context.

        :Parameters:
            - `request`: current request

        :Returns:
            Dictionary with all the data
        """
        raise NotImplementedError()

    def get_templates(self, context):
        " Extract parameters for `get_templates` from the context. "
        kw = {}
        if 'object' in context:
            o = context['object']
            kw['slug'] = o.slug

        if 'content_type' in context:
            ct = context['content_type']
            kw['app_label'] = ct.app_label
            kw['model_label'] = ct.model

        return get_templates(self.template_name, category=context['category'], **kw)

    def render(self, request, context, template):
        return render_to_response(template, context,
            context_instance=RequestContext(request))

    def __call__(self, request, **kwargs):
        context = self.get_context(request, **kwargs)
        return self.render(request, context, self.get_templates(context))

class CategoryDetail(EllaCoreView):
    """
    Homepage of a category the actual site.

    :Parameters: 
        - `request`: `HttpRequest` from Django
        - `category`: optional - `tree_path` of the `Category` to render
          home page is used if this parameter is omitted

    :Exceptions: 
        - `Http404`: if there is no category
    """
    template_name = 'category.html'
    def get_context(self, request, category=None):
        return _category_detail(category)

class ObjectDetail(EllaCoreView):
    """
    Renders a page for placement. All the data fetching and context creation is done in `_object_detail`.
    If `url_remainder` is specified, tries to locate custom view via `custom_urls.dispatcher`. Renders a template 
    returned by `get_template` with context returned by `_object_detail`.

    :Parameters:
        - `request`: `HttpRequest` from Django
        - `category, content_type, slug, year, month, day`: parameters passed on to `_object_detail`
        - `url_remainder`: url after the object's url, used to locate custom views in `custom_urls.dispatcher`

    :Exceptions: 
        - `Http404`: if the URL is not valid and/or doesn't correspond to any valid `Placement`
    """
    template_name = 'object.html'
    def __call__(self, request, category, content_type, slug, year=None, month=None, day=None, url_remainder=None):
        context = self.get_context(request, category, content_type, slug, year, month, day)

        obj = context['object']
        # check for custom actions
        if url_remainder:
            bits = url_remainder.split('/')
            return custom_urls.dispatcher.call_view(request, bits, context)
        elif custom_urls.dispatcher.has_custom_detail(obj):
            return custom_urls.dispatcher.call_custom_detail(request, context)

        return self.render(request, context, self.get_templates(context))

    def get_context(self, request, category, content_type, slug, year, month, day):
        return _object_detail(request.user, category, content_type, slug, year, month, day)

class ListContentType(EllaCoreView):
    template_name = 'listing.html'
    def get_context(self, request, category=None, year=None, month=None, day=None, content_type=None, paginate_by=20):
        # pagination
        if 'p' in request.GET and request.GET['p'].isdigit():
            page_no = int(request.GET['p'])
        else:
            page_no = 1

        return  _list_content_type(category, year, month, day, content_type, page_no, paginate_by)

# backwards compatibility
object_detail = ObjectDetail()
home = category_detail = CategoryDetail()
list_content_type = ListContentType()

def get_content_type(ct_name):
    """
    A helper function that returns ContentType object based on its slugified verbose_name_plural.

    Results of this function is cached to improve performance.

    :Parameters: 
        - `ct_name`:  Slugified verbose_name_plural of the target model.

    :Exceptions: 
        - `Http404`: if no matching ContentType is found
    """
    try:
        ct = CONTENT_TYPE_MAPPING[ct_name]
    except KeyError:
        for model in models.get_models():
            if ct_name == slugify(model._meta.verbose_name_plural):
                ct = ContentType.objects.get_for_model(model)
                CONTENT_TYPE_MAPPING[ct_name] = ct
                break
        else:
            raise Http404
    return ct


def _object_detail(user, category, content_type, slug, year, month, day):
    """
    Helper function that does all the data fetching for `object_detail` view. It
    returns a dictionary containing:

        - `placement`: `Placement` instance representing the URL accessed
        - `object`: `Publishable` instance bound to the `placement`
        - `category`: `Category` of the `placement`
        - `content_type_name`: slugified plural verbose name of the publishable's content type
        - `content_type`: `ContentType` of the publishable

    :Parameters: 
        - `user`: django `User` instance
        - `category`: `Category.tree_path` (empty if home category)
        - `year`, `month`, `day`: date matching the `publish_from` field of the `Placement` object
        - `content_type`: slugified `verbose_name_plural` of the target model
        - `slug`: slug of the `Placement`

    :Exceptions:
        - `Http404`: if object or placement doesn't exist or dates don't match
    """
    ct = get_content_type(content_type)

    if category:
        cat = get_cached_object_or_404(Category, tree_path=category, site__id=settings.SITE_ID)
    else:
        cat = get_cached_object_or_404(Category, tree_parent__isnull=True, site__id=settings.SITE_ID)

    if year:
        placement = get_cached_object_or_404(Placement,
                    publish_from__year=year,
                    publish_from__month=month,
                    publish_from__day=day,
                    publishable__content_type=ct,
                    category=cat,
                    slug=slug,
                    static=False
                )
    else:
        placement = get_cached_object_or_404(Placement, category=cat, publishable__content_type=ct, slug=slug, static=True)


    if not (placement.is_active() or user.is_staff):
        # future placement, render if accessed by logged in staff member
        raise Http404

    obj = placement.publishable.target

    context = {
            'placement' : placement,
            'object' : obj,
            'category' : cat,
            'content_type_name' : content_type,
            'content_type' : ct,
        }

    return context


def get_templates(name, slug=None, category=None, app_label=None, model_label=None):
    """
    Returns templates in following format and order:

        - 'page/category/%s/content_type/%s.%s/%s/%s' % ( category.path, app_label, model_label, slug, name ),
        - 'page/category/%s/content_type/%s.%s/%s' % ( category.path, app_label, model_label, name ),
        - 'page/category/%s/%s' % ( category.path, name ),
        - 'page/content_type/%s.%s/%s' % ( app_label, model_label, name ),
        - 'page/%s' % name,
    """
{'fraction_non_alphanumeric': 0.09717808567433583, 'fraction_numerical': 0.005465870090250413, 'mean_word_length': 2.8784816366773476, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2531883', 'n_tokens_mistral': 4703, 'n_tokens_neox': 4436, 'n_words': 1218}