<commit_before>from django.shortcuts import render_to_response
from django.http import Http404
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.template import RequestContext
from eulcore.existdb.exceptions import DoesNotExist # ReturnedMultiple needed also ?
from findingaids.fa.models import FindingAid, Series, Subseries, Subsubseries, title_letters, Index
from findingaids.fa.forms import KeywordSearchForm
from findingaids.fa.utils import render_to_pdf

def site_index(request):
    "Site home page"
    first_letters = title_letters()
    return render_to_response('findingaids/index.html', { 'letters' : first_letters,
                                                          'querytime': [first_letters.queryTime()]},
                                                          context_instance=RequestContext(request)
                                                          )

def browse_titles(request):
    "List all first letters in finding aid list title, link to browse by letter."
    first_letters = title_letters()
    return render_to_response('findingaids/browse_letters.html', { 'letters' : first_letters,
                                                           'querytime': [first_letters.queryTime()]},
                                                          context_instance=RequestContext(request))

def titles_by_letter(request, letter):
    "Paginated list of finding aids by first letter in list title"
    first_letters = title_letters()

    fa = FindingAid.objects.filter(list_title__startswith=letter).order_by('list_title').only(*_fa_listfields())   
    fa_subset = _paginate_queryset(request, fa)
    query_times = [first_letters.queryTime(), fa.queryTime()]

    return render_to_response('findingaids/titles_list.html',
        {'findingaids' : fa_subset,
         'querytime': query_times,
         'letters': first_letters,
         'current_letter': letter},
         context_instance=RequestContext(request))

# object pagination - adapted directly from django paginator documentation
def _paginate_queryset(request, qs, per_page=10):
    # FIXME: should num-per-page be configurable via local settings?
    paginator = Paginator(qs, per_page)
     # Make sure page request is an int. If not, deliver first page.
    try:
        page = int(request.GET.get('page', '1'))
    except ValueError:
        page = 1

    # If page request (9999) is out of range, deliver last page of results.
    try:
        paginated_qs = paginator.page(page)
    except (EmptyPage, InvalidPage):
        paginated_qs = paginator.page(paginator.num_pages)

    return paginated_qs


def view_fa(request, id):
    "View a single finding aid"
    try:
        fa = FindingAid.objects.get(eadid=id)
    except DoesNotExist:   
        raise Http404
    # FIXME: handle other exceptions 
    series = _subseries_links(fa.dsc, url_ids=[fa.eadid])    
    return render_to_response('findingaids/view.html', { 'findingaid' : fa,
                                                         'series' : series,
                                                         'all_indexes' : fa.archdesc.index },
                                                         context_instance=RequestContext(request))

def series_or_index(request, id, series_id):
    "View a single series (c01) or index from a finding aid"
    return _view_series(request, id, series_id)

def view_subseries(request, id, series_id, subseries_id):
    "View a single subseries (c02) from a finding aid"   
    return _view_series(request, id, series_id, subseries_id)

def view_subsubseries(request, id, series_id, subseries_id, subsubseries_id):
    "View a single subseries (c03) from a finding aid"
    return _view_series(request, id, series_id, subseries_id, subsubseries_id)

def _view_series(request, eadid, *series_ids):
    # get the item to be displayed (series, subseries, index)
    result = _get_series_or_index(eadid, *series_ids)
    # info needed to construct navigation links within this ead
    # - summary info for all top-level series in this finding aid
    all_series = Series.objects.only('id', 'level', 'did__unitid', 'did__unittitle').filter(ead__eadid=eadid).all()
    # - summary info for any indexes
    all_indexes = Index.objects.only('id', 'head').filter(ead__eadid=eadid).all()

    render_opts = { 'ead': result.ead,
                    'all_series' : all_series,
                    'all_indexes' : all_indexes,
                    "querytime" : [result.queryTime(), all_series.queryTime(), all_indexes.queryTime()]}

    if (isinstance(result, Index)):
        render_opts['index'] = result
    else:
        render_opts['series'] = result
        render_opts['subseries'] = _subseries_links(result)

    return render_to_response('findingaids/series_or_index.html',
                            render_opts, context_instance=RequestContext(request))

def _get_series_or_index(eadid, *series_ids):
    # additional fields to be returned
    return_fields = ['ead__eadid', 'ead__title', 'ead__archdesc__controlaccess__head',
        'ead__dsc__head']
    # common search parameters - last series id should be requested series, of whatever type
    search_fields = {'ead__eadid' : eadid, 'id': series_ids[-1]}
    try:
        if len(series_ids) == 1:
            try:
                record = Series.objects.also(*return_fields).get(**search_fields)
            except DoesNotExist:
                record = Index.objects.also(*return_fields).get(**search_fields)                
        elif len(series_ids) == 2:
            return_fields.append('series__id')
            search_fields["series__id"] = series_ids[0]
            record = Subseries.objects.also(*return_fields).get(**search_fields)
        elif len(series_ids) == 3:
            return_fields.extend(['series__id', 'subseries__id'])
            search_fields.update({"series__id": series_ids[0], "subseries__id" : series_ids[1]})
            record = Subsubseries.objects.also(*return_fields).get(**search_fields)
    except DoesNotExist:
        raise Http404
    return record

def keyword_search(request):
    "Simple keyword search - runs exist full-text terms query on all terms included."
    form = KeywordSearchForm(request.GET)
    if form.is_valid():
        # not yet implemented - if no search terms, display search form
        search_terms = request.GET.get('keywords')
        # common ead fields for list display, plus full-text relevance score
        return_fields = _fa_listfields()
        return_fields.append('fulltext_score')
        results = FindingAid.objects.filter(fulltext_terms=search_terms).order_by('fulltext_score').only(*return_fields)
        result_subset = _paginate_queryset(request, results)

        query_times = results.queryTime()
        # FIXME: does not currently include keyword param in generated urls
        # create a better browse view - display search terms, etc.

        return render_to_response('findingaids/search_results.html',
                {'findingaids' : result_subset,
                 'keywords'  : search_terms,
                 'querytime': [query_times]},
                 context_instance=RequestContext(request))
    else:
        form = KeywordSearchForm()
            
    return render_to_response('findingaids/search_form.html',
                    {'form' : form, 'request': request },
                    context_instance=RequestContext(request))

def full_fa(request, id, mode):
    "View the full contents of a single finding aid as PDF or plain html"
    try:
        fa = FindingAid.objects.get(eadid=id)
    except DoesNotExist:
        raise Http404
    # FIXME: other exceptions?

    series = _subseries_links(fa.dsc, url_ids=[fa.eadid], url_callback=_series_anchor)

    template = 'findingaids/full.html'<commit_msg>add last-modified header to full ead / pdf<commit_after>import datetime

from django.http import Http404
from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.decorators.http import condition

from eulcore.django.existdb.db import ExistDB
from eulcore.existdb.exceptions import DoesNotExist # ReturnedMultiple needed also ?

from findingaids.fa.models import FindingAid, Series, Subseries, Subsubseries, title_letters, Index
from findingaids.fa.forms import KeywordSearchForm
from findingaids.fa.utils import render_to_pdf

def site_index(request):
    "Site home page"
    first_letters = title_letters()
    return render_to_response('findingaids/index.html', { 'letters' : first_letters,
                                                          'querytime': [first_letters.queryTime()]},
                                                          context_instance=RequestContext(request)
                                                          )

def browse_titles(request):
    "List all first letters in finding aid list title, link to browse by letter."
    first_letters = title_letters()
    return render_to_response('findingaids/browse_letters.html', { 'letters' : first_letters,
                                                           'querytime': [first_letters.queryTime()]},
                                                          context_instance=RequestContext(request))

def titles_by_letter(request, letter):
    "Paginated list of finding aids by first letter in list title"
    first_letters = title_letters()

    fa = FindingAid.objects.filter(list_title__startswith=letter).order_by('list_title').only(*_fa_listfields())   
    fa_subset = _paginate_queryset(request, fa)
    query_times = [first_letters.queryTime(), fa.queryTime()]

    return render_to_response('findingaids/titles_list.html',
        {'findingaids' : fa_subset,
         'querytime': query_times,
         'letters': first_letters,
         'current_letter': letter},
         context_instance=RequestContext(request))

# object pagination - adapted directly from django paginator documentation
def _paginate_queryset(request, qs, per_page=10):
    # FIXME: should num-per-page be configurable via local settings?
    paginator = Paginator(qs, per_page)
     # Make sure page request is an int. If not, deliver first page.
    try:
        page = int(request.GET.get('page', '1'))
    except ValueError:
        page = 1

    # If page request (9999) is out of range, deliver last page of results.
    try:
        paginated_qs = paginator.page(page)
    except (EmptyPage, InvalidPage):
        paginated_qs = paginator.page(paginator.num_pages)

    return paginated_qs


def view_fa(request, id):
    "View a single finding aid"
    try:
        fa = FindingAid.objects.get(eadid=id)
    except DoesNotExist:   
        raise Http404
    # FIXME: handle other exceptions 
    series = _subseries_links(fa.dsc, url_ids=[fa.eadid])    
    return render_to_response('findingaids/view.html', { 'findingaid' : fa,
                                                         'series' : series,
                                                         'all_indexes' : fa.archdesc.index },
                                                         context_instance=RequestContext(request))

def series_or_index(request, id, series_id):
    "View a single series (c01) or index from a finding aid"
    return _view_series(request, id, series_id)

def view_subseries(request, id, series_id, subseries_id):
    "View a single subseries (c02) from a finding aid"   
    return _view_series(request, id, series_id, subseries_id)

def view_subsubseries(request, id, series_id, subseries_id, subsubseries_id):
    "View a single subseries (c03) from a finding aid"
    return _view_series(request, id, series_id, subseries_id, subsubseries_id)

def _view_series(request, eadid, *series_ids):
    # get the item to be displayed (series, subseries, index)
    result = _get_series_or_index(eadid, *series_ids)
    # info needed to construct navigation links within this ead
    # - summary info for all top-level series in this finding aid
    all_series = Series.objects.only('id', 'level', 'did__unitid', 'did__unittitle').filter(ead__eadid=eadid).all()
    # - summary info for any indexes
    all_indexes = Index.objects.only('id', 'head').filter(ead__eadid=eadid).all()

    render_opts = { 'ead': result.ead,
                    'all_series' : all_series,
                    'all_indexes' : all_indexes,
                    "querytime" : [result.queryTime(), all_series.queryTime(), all_indexes.queryTime()]}

    if (isinstance(result, Index)):
        render_opts['index'] = result
    else:
        render_opts['series'] = result
        render_opts['subseries'] = _subseries_links(result)

    return render_to_response('findingaids/series_or_index.html',
                            render_opts, context_instance=RequestContext(request))

def _get_series_or_index(eadid, *series_ids):
    # additional fields to be returned
    return_fields = ['ead__eadid', 'ead__title', 'ead__archdesc__controlaccess__head',
        'ead__dsc__head']
    # common search parameters - last series id should be requested series, of whatever type
    search_fields = {'ead__eadid' : eadid, 'id': series_ids[-1]}
    try:
        if len(series_ids) == 1:
            try:
                record = Series.objects.also(*return_fields).get(**search_fields)
            except DoesNotExist:
                record = Index.objects.also(*return_fields).get(**search_fields)                
        elif len(series_ids) == 2:
            return_fields.append('series__id')
            search_fields["series__id"] = series_ids[0]
            record = Subseries.objects.also(*return_fields).get(**search_fields)
        elif len(series_ids) == 3:
            return_fields.extend(['series__id', 'subseries__id'])
            search_fields.update({"series__id": series_ids[0], "subseries__id" : series_ids[1]})
            record = Subsubseries.objects.also(*return_fields).get(**search_fields)
    except DoesNotExist:
        raise Http404
    return record

def keyword_search(request):
    "Simple keyword search - runs exist full-text terms query on all terms included."
    form = KeywordSearchForm(request.GET)
    if form.is_valid():
        # not yet implemented - if no search terms, display search form
        search_terms = request.GET.get('keywords')
        # common ead fields for list display, plus full-text relevance score
        return_fields = _fa_listfields()
        return_fields.append('fulltext_score')
        results = FindingAid.objects.filter(fulltext_terms=search_terms).order_by('fulltext_score').only(*return_fields)
        result_subset = _paginate_queryset(request, results)

        query_times = results.queryTime()
        # FIXME: does not currently include keyword param in generated urls
        # create a better browse view - display search terms, etc.

        return render_to_response('findingaids/search_results.html',
                {'findingaids' : result_subset,
                 'keywords'  : search_terms,
                 'querytime': [query_times]},
                 context_instance=RequestContext(request))
    else:
        form = KeywordSearchForm()
            
    return render_to_response('findingaids/search_form.html',
                    {'form' : form, 'request': request },
                    context_instance=RequestContext(request))

def _ead_lastmodified(request, id, mode):
    db = ExistDB()
    if '.xml' in id:	# TEMPORARY (we hope)
        id = id.replace('.xml', '')
    info = db.describeDocument("%s/%s.xml" % (settings.EXISTDB_ROOT_COLLECTION, id))
    # returns an xmlrpc DateTime object - convert into datetime format required by django
    mod_time = info['modified'].timetuple()
    modified = datetime.datetime(mod_time.tm_year, mod_time.tm_mon, mod_time.tm_mday,
                                 mod_time.tm_hour, mod_time.tm_min, mod_time.tm_sec)
    return modified

#FIXME/TODO: also generate an etag ?

@condition(last_modified_func=_ead_lastmodified)
def full_fa(request, id, mode):
    "View the full contents of a single finding aid as PDF or plain html"
    try:
        fa = FindingAid.objects.get(eadid=id)
    except DoesNotExist:
        raise Http404
    # FIXME: other exceptions?

    series = _subseries_links(fa.dsc, url_ids=[fa.eadid], url_callback=_series_anchor)

    template = 'findingaids/full.html'
{'fraction_non_alphanumeric': 0.09320599613152805, 'fraction_numerical': 0.003989361702127659, 'mean_word_length': 2.7713699566902212, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 33, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4191197', 'n_tokens_mistral': 4732, 'n_tokens_neox': 4572, 'n_words': 1143}