Example #1
0
def page(request, slug=u'key-to-the-families'):
    if slug != slug.lower():
        raise Http404
    title = models.slug_to_title(slug)
    if title.startswith('Section '):
        title = title.title()
    page = get_object_or_404(models.Page, title=title)
    if page.rank == 'species':
        raise Http404
    proxy = _Proxy(page)
    return render(request, 'dkey/page.html', {
            'partner_site': partner_short_name(request),
            'groups': get_groups,
            'leads': (lambda: proxy.leads),
            'lead_hierarchy': (lambda: proxy.lead_hierarchy),
            'page': (lambda: proxy.page),
            'rank_beneath': (lambda: proxy.rank_beneath),
            'taxa_beneath': (lambda: proxy.taxa_beneath),
            'next_page': (lambda: proxy.next() or proxy.page),
            })
Example #2
0
def page(request, slug='key-to-the-families'):
    if slug != slug.lower():
        raise Http404
    title = models.slug_to_title(slug)
    if title.startswith('Section '):
        title = title.title()
    page = get_object_or_404(models.Page, title=title)
    if page.rank == 'species':
        raise Http404
    proxy = _Proxy(page)
    return render(
        request, 'dkey/page.html', {
            'partner_site': partner_short_name(request),
            'groups': get_groups,
            'leads': (lambda: proxy.leads),
            'lead_hierarchy': (lambda: proxy.lead_hierarchy),
            'page': (lambda: proxy.page),
            'rank_beneath': (lambda: proxy.rank_beneath),
            'taxa_beneath': (lambda: proxy.taxa_beneath),
            'next_page': (lambda: next(proxy) or proxy.page),
        })
Example #3
0
def dkey_images(request, slug):

    if slug == 'key-to-the-families':
        return jsonify({})

    # Whether a dkey page displays groups of families, genera, or taxa,
    # we need to pull exactly one species to stand as the representative
    # for each taxon, and then grab all of the rank=1 content images for
    # those species.

    title = dkey_models.slug_to_title(slug)
    page = get_object_or_404(dkey_models.Page, title=title)

    taxa = None
    rank = None
    taxa_names = []
    for lead in page.leads.all():
        if lead.taxa_cache:
            rank, comma_list = lead.taxa_cache.split(':')
            taxa_names.extend(comma_list.split(','))
    if rank is None:
        return jsonify({})

    group_title = None

    if page.rank == 'group':
        group_title = page.title
    else:
        for ancestor in page.breadcrumb_cache.all():
            if ancestor.rank == 'group':
                group_title = ancestor.title

    image_types_allowed = ['plant form']
    image_types_allowed.extend(extra_image_types.get(group_title, ()))

    if rank == u'family':

        # See https://github.com/newfs/gobotany-app/issues/302
        # and https://github.com/newfs/gobotany-app/issues/304

        group_number = title.split()[-1] if page.rank == u'group' else u''

        cursor = connection.cursor()
        cursor.execute(
            """
            SELECT f.name, t.id,
              (SELECT id FROM core_taxon WHERE family_id = f.id LIMIT 1)
              FROM core_family f
              LEFT JOIN dkey_illustrativespecies i
                ON (i.group_number = %s AND f.name = i.family_name)
              LEFT JOIN core_taxon t
                ON (i.species_name = t.scientific_name)
              WHERE f.name IN %s""", (
                group_number,
                tuple(taxa_names),
            ))

        rows = cursor.fetchall()
        family_map = {}
        for family_name, illustrative_taxon_id, random_taxon_id in rows:
            taxon_id = illustrative_taxon_id
            if taxon_id is None:
                taxon_id = random_taxon_id
            family_map[taxon_id] = family_name

        taxon_ids = family_map.keys()

    elif rank == u'genus':

        cursor = connection.cursor()
        cursor.execute(
            """
            SELECT
              (SELECT id FROM core_taxon WHERE genus_id = g.id LIMIT 1)
              FROM core_genus g
              WHERE g.name IN %s""", (tuple(taxa_names), ))
        taxon_ids = [id for (id, ) in cursor.fetchall()]

    elif rank == u'species':

        taxa = Taxon.objects.filter(scientific_name__in=taxa_names)
        taxon_ids = [taxon.id for taxon in taxa]

    else:
        return jsonify({})

    if taxa is None:
        taxa = Taxon.objects.filter(id__in=taxon_ids)

    ctype = ContentType.objects.get_for_model(Taxon)
    query = (ContentImage.objects.filter(
        content_type=ctype, object_id__in=taxon_ids, rank=1).filter(
            image_type__name__in=image_types_allowed).select_related(
                'image_type'))

    image_map = {(image.object_id, image.image_type.name): image.thumb_small()
                 for image in query}

    image_types = sorted(set(key[1] for key in image_map))
    image_lists = []

    for taxon in taxa:

        if rank == u'family':
            name = family_map[taxon.id]
            title = u'{}<br><i>({})</i>'.format(name, taxon.scientific_name)
        else:
            if rank == u'genus':
                name = taxon.genus_name()
            else:
                name = taxon.scientific_name
            title = u'<i>{}</i>'.format(taxon.scientific_name)

        image_list = []
        for image_type in image_types:
            image = image_map.get((taxon.id, image_type))
            if image is not None:
                image_list.append({
                    'image_type':
                    image_type,
                    'image_url':
                    secure_url(image_map.get((taxon.id, image_type))),
                })

        image_lists.append({
            'name': name,
            'scientific_name': taxon.scientific_name,
            'title': title,
            'image_list': image_list,
        })

    image_lists.sort(key=itemgetter('title'))

    return jsonify({
        'image_types': image_types,
        'image_lists': image_lists,
    })
Example #4
0
def dkey(request, slug=u'key-to-the-families'):
    if request.method == 'GET':
        # For showing the D. Key Editor page
        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)
        families = models.Family.objects.all()
        genera = models.Genus.objects.all()
        sections = list(dkey_models.Page.objects.filter(
            rank='section').order_by('title').values_list('title', flat=True))
        carex_sections = [(section.replace('Section ', ''),
            section.lower().replace(' ', '-')) for section in sections]
        return render(request, 'gobotany/edit_dkey.html', {
                'families': families,
                'genera': genera,
                'carex_sections': carex_sections,
                'groups': get_groups,
                'leads': (lambda: proxy.leads),
                'lead_hierarchy': (lambda: proxy.lead_hierarchy),
                'page': (lambda: proxy.page),
                'rank_beneath': (lambda: proxy.rank_beneath),
                'taxa_beneath': (lambda: proxy.taxa_beneath),
                'next_page': (lambda: proxy.next() or proxy.page),
                'messages': get_messages(request),
            })
    elif request.method == 'POST':
        # Add or delete a couplet.
        command = request.POST['command']
        lead_id = request.POST['lead-id']
        added_leads = []
        deleted_leads = []
        last_number = 0

        this_lead = dkey_models.Lead.objects.get(id=lead_id)
        if command == 'add':
            # Add a couplet.
            # Create a temporary sequence number for the new leads far above
            # the likely highest on the page, to be renumbered later.
            temp_seq_number = this_lead.letter.replace('a', '').replace(
                'b', '') + '500'
            a_lead = dkey_models.Lead()
            a_lead.page = this_lead.page
            a_lead.parent = this_lead
            a_lead.letter = temp_seq_number + 'a'
            a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper()
            a_lead.save()
            b_lead = dkey_models.Lead()
            b_lead.page = this_lead.page
            b_lead.parent = this_lead
            b_lead.letter = temp_seq_number + 'b'
            b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper()
            b_lead.save()
            added_leads = dkey_models.Lead.objects.filter(parent=lead_id)
        elif command == 'delete':
            # Delete a couplet.
            leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id)
            # Be careful about deleting lead records:
            # verify that there are two, and delete no more than two.
            if leads_to_delete.count() == 2:
                deleted_leads.append(leads_to_delete[0].id)
                deleted_leads.append(leads_to_delete[1].id)
                leads_to_delete.delete()
        elif command == 'promote':
            print('command: promote')
            # Determine the new parent of the leads that will be promoted.
            promoted_leads_parent = this_lead.parent
            print('promoted_leads_parent:', promoted_leads_parent)

            # Disconnect the leads that are being replaced rather than fully
            # delete them. This way the records stay around for future use.
            #
            # Query the leads whose parent equals the promoted_leads_parent.
            # This should return just the two leads to be disconnected.
            leads_to_disconnect = dkey_models.Lead.objects.filter(
                parent=this_lead.parent)
            print('leads to disconnect:', leads_to_disconnect)
            # Be careful about disconnecting old leads: verify there are two.
            if leads_to_disconnect.count() == 2:
                print('leads_to_disconnect[0].parent (set to None):',
                    leads_to_disconnect[0].parent)
                leads_to_disconnect[0].parent = None
                leads_to_disconnect[0].save()
                print('leads_to_disconnect[0].parent:', leads_to_disconnect[0].parent)
                print('leads_to_disconnect[1].parent (set to None):',
                    leads_to_disconnect[1].parent)
                leads_to_disconnect[1].parent = None
                leads_to_disconnect[1].save()
                print('leads_to_disconnect[1].parent:', leads_to_disconnect[1].parent)

            # Query the leads that are to be promoted.
            leads_to_promote = dkey_models.Lead.objects.filter(parent=lead_id)
            # Be careful about promoting lead records: verify there are two.
            if leads_to_promote.count() == 2:
                print('leads_to_promote[0]: %s - current parent is %s, set to %s' % (
                    leads_to_promote[0], leads_to_promote[0].parent,
                    promoted_leads_parent))
                leads_to_promote[0].parent = promoted_leads_parent
                leads_to_promote[0].save()
                print('leads_to_promote[0].parent:', leads_to_promote[0].parent)
                print('leads_to_promote[1]: %s - current parent is %s, set to %s' % (
                    leads_to_promote[1], leads_to_promote[1].parent,
                    promoted_leads_parent))
                leads_to_promote[1].parent = promoted_leads_parent
                leads_to_promote[1].save()
                print('leads_to_promote[1].parent:', leads_to_promote[1].parent)

        last_number = _renumber_page(this_lead.page)

        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)

        return redirect(request.path)
Example #5
0
def dkey_images(request, slug):

    if slug == 'key-to-the-families':
        return jsonify({})

    # Whether a dkey page displays groups of families, genera, or taxa,
    # we need to pull exactly one species to stand as the representative
    # for each taxon, and then grab all of the rank=1 content images for
    # those species.

    title = dkey_models.slug_to_title(slug)
    page = get_object_or_404(dkey_models.Page, title=title)

    taxa = None
    rank = None
    taxa_names = []
    for lead in page.leads.all():
        if lead.taxa_cache:
            rank, comma_list = lead.taxa_cache.split(':')
            taxa_names.extend(comma_list.split(','))
    if rank is None:
        return jsonify({})

    group_title = None

    if page.rank == 'group':
        group_title = page.title
    else:
        for ancestor in page.breadcrumb_cache.all():
            if ancestor.rank == 'group':
                group_title = ancestor.title

    image_types_allowed = ['plant form']
    image_types_allowed.extend(extra_image_types.get(group_title, ()))

    if rank == u'family':

        # See https://github.com/newfs/gobotany-app/issues/302
        # and https://github.com/newfs/gobotany-app/issues/304

        group_number = title.split()[-1] if page.rank == u'group' else u''

        cursor = connection.cursor()
        cursor.execute("""
            SELECT f.name, t.id,
              (SELECT id FROM core_taxon WHERE family_id = f.id LIMIT 1)
              FROM core_family f
              LEFT JOIN dkey_illustrativespecies i
                ON (i.group_number = %s AND f.name = i.family_name)
              LEFT JOIN core_taxon t
                ON (i.species_name = t.scientific_name)
              WHERE f.name IN %s""", (group_number, tuple(taxa_names),))

        rows = cursor.fetchall()
        family_map = {}
        for family_name, illustrative_taxon_id, random_taxon_id in rows:
            taxon_id = illustrative_taxon_id
            if taxon_id is None:
                taxon_id = random_taxon_id
            family_map[taxon_id] = family_name

        taxon_ids = family_map.keys()

    elif rank == u'genus':

        cursor = connection.cursor()
        cursor.execute("""
            SELECT
              (SELECT id FROM core_taxon WHERE genus_id = g.id LIMIT 1)
              FROM core_genus g
              WHERE g.name IN %s""", (tuple(taxa_names),))
        taxon_ids = [ id for (id,) in cursor.fetchall() ]

    elif rank == u'species':

        taxa = Taxon.objects.filter(scientific_name__in=taxa_names)
        taxon_ids = [ taxon.id for taxon in taxa ]

    else:
        return jsonify({})

    if taxa is None:
        taxa = Taxon.objects.filter(id__in=taxon_ids)

    ctype = ContentType.objects.get_for_model(Taxon)
    query = (ContentImage.objects
             .filter(content_type=ctype, object_id__in=taxon_ids, rank=1)
             .filter(image_type__name__in=image_types_allowed)
             .select_related('image_type')
             )

    image_map = {
        (image.object_id, image.image_type.name): image.thumb_small()
        for image in query
        }

    image_types = sorted(set(key[1] for key in image_map))
    image_lists = []

    for taxon in taxa:

        if rank == u'family':
            name = family_map[taxon.id]
            title = u'{}<br><i>({})</i>'.format(name, taxon.scientific_name)
        else:
            if rank == u'genus':
                name = taxon.genus_name()
            else:
                name = taxon.scientific_name
            title = u'<i>{}</i>'.format(taxon.scientific_name)

        image_list = []
        for image_type in image_types:
            image = image_map.get((taxon.id, image_type))
            if image is not None:
                image_list.append({
                    'image_type': image_type,
                    'image_url': image_map.get((taxon.id, image_type)),
                    })

        image_lists.append({
            'name': name,
            'scientific_name': taxon.scientific_name,
            'title': title,
            'image_list': image_list,
            })

    image_lists.sort(key=itemgetter('title'))

    return jsonify({
            'image_types': image_types,
            'image_lists': image_lists,
            })
Example #6
0
def dkey(request, slug='key-to-the-families'):
    if request.method == 'GET':
        # For showing the D. Key Editor page
        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)
        families = models.Family.objects.all()
        genera = models.Genus.objects.all()
        sections = list(
            dkey_models.Page.objects.filter(
                rank='section').order_by('title').values_list('title',
                                                              flat=True))
        carex_sections = [(section.replace('Section ', ''),
                           section.lower().replace(' ', '-'))
                          for section in sections]
        return render(
            request, 'gobotany/edit_dkey.html', {
                'families': families,
                'genera': genera,
                'carex_sections': carex_sections,
                'groups': get_groups,
                'leads': (lambda: proxy.leads),
                'lead_hierarchy': (lambda: proxy.lead_hierarchy),
                'page': (lambda: proxy.page),
                'rank_beneath': (lambda: proxy.rank_beneath),
                'taxa_beneath': (lambda: proxy.taxa_beneath),
                'next_page': (lambda: next(proxy) or proxy.page),
                'messages': get_messages(request),
            })
    elif request.method == 'POST':
        # Add or delete a couplet.
        command = request.POST['command']
        lead_id = request.POST['lead-id']
        added_leads = []
        deleted_leads = []
        last_number = 0

        this_lead = dkey_models.Lead.objects.get(id=lead_id)
        if command == 'add':
            # Add a couplet.
            # Create a temporary sequence number for the new leads far above
            # the likely highest on the page, to be renumbered later.
            temp_seq_number = this_lead.letter.replace('a', '').replace(
                'b', '') + '500'
            a_lead = dkey_models.Lead()
            a_lead.page = this_lead.page
            a_lead.parent = this_lead
            a_lead.letter = temp_seq_number + 'a'
            a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper()
            a_lead.save()
            b_lead = dkey_models.Lead()
            b_lead.page = this_lead.page
            b_lead.parent = this_lead
            b_lead.letter = temp_seq_number + 'b'
            b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper()
            b_lead.save()
            added_leads = dkey_models.Lead.objects.filter(parent=lead_id)
        elif command == 'delete':
            # Delete a couplet.
            leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id)
            # Be careful about deleting lead records:
            # verify that there are two, and delete no more than two.
            if leads_to_delete.count() == 2:
                deleted_leads.append(leads_to_delete[0].id)
                deleted_leads.append(leads_to_delete[1].id)
                leads_to_delete.delete()
        elif command == 'promote':
            # Determine the new parent of the leads that will be promoted.
            promoted_leads_parent = this_lead.parent

            # Disconnect the leads that are being replaced.

            # Query the leads whose parent equals the promoted_leads_parent.
            # This should return just the two leads to be disconnected.
            leads_to_disconnect = dkey_models.Lead.objects.filter(
                parent=this_lead.parent).order_by('letter')

            # Be careful about disconnecting leads: verify there are two.
            if leads_to_disconnect.count() == 2:
                first_removed_lead = leads_to_disconnect[0]
                second_removed_lead = leads_to_disconnect[1]

                # Disconnect the first lead.
                first_removed_lead.parent = None
                try:
                    first_removed_lead.save()
                except ValidationError as e:
                    print(('ValidationError when disconnecting first lead:',
                           e.message_dict))

                # Disconnect the second lead.
                second_removed_lead.parent = None
                try:
                    second_removed_lead.save()
                except ValidationError as e:
                    print(('ValidationError when disconnecting second lead:',
                           e.message_dict))

            # Query the leads that are to be promoted, i.e. moved up,
            # to replace the leads that have just been removed.
            leads_to_promote = dkey_models.Lead.objects.filter(
                parent=lead_id).order_by('letter')

            # Be careful about promoting lead records: verify there are two.
            if leads_to_promote.count() == 2:
                first_lead = leads_to_promote[0]
                second_lead = leads_to_promote[1]

                # Set a new parent for the first lead.
                first_lead.parent = promoted_leads_parent
                try:
                    first_lead.save()
                except ValidationError as e:
                    print(('ValidationError:', e.message_dict))

                # Set a new parent for the second lead.
                second_lead.parent = promoted_leads_parent
                try:
                    second_lead.save()
                except ValidationError as e:
                    print(('ValidationError:', e.message_dict))

                # Delete the two disconnected leads, which should also
                # delete any child leads that one of them may have had.
                # This deletion was mentioned to the user in a confirmation
                # message to let them know that this would happen.
                try:
                    first_removed_lead.delete()
                except ValidationError as e:
                    print(('ValidationError when deleting first lead:',
                           e.message_dict))
                try:
                    second_removed_lead.delete()
                except ValidationError as e:
                    print(('ValidationError when deleting second lead:',
                           e.message_dict))

        last_number = _renumber_page(this_lead.page)

        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)

        return redirect(request.path)
Example #7
0
def dkey(request, slug=u'key-to-the-families'):
    if request.method == 'GET':
        # For showing the D. Key Editor page
        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)
        return render(
            request, 'gobotany/edit_dkey.html', {
                'groups': get_groups,
                'leads': (lambda: proxy.leads),
                'lead_hierarchy': (lambda: proxy.lead_hierarchy),
                'page': (lambda: proxy.page),
                'rank_beneath': (lambda: proxy.rank_beneath),
                'taxa_beneath': (lambda: proxy.taxa_beneath),
                'next_page': (lambda: proxy.next() or proxy.page),
            })
    elif request.method == 'POST':
        # Add or delete a couplet.
        command = request.POST['command']
        lead_id = request.POST['lead-id']
        added_leads = []
        deleted_leads = []
        last_number = 0

        this_lead = dkey_models.Lead.objects.get(id=lead_id)
        if command == 'add':
            # Add a couplet.
            # Create a temporary sequence number for the new leads far above
            # the likely highest on the page, to be renumbered later.
            temp_seq_number = this_lead.letter.replace('a', '').replace(
                'b', '') + '500'
            a_lead = dkey_models.Lead()
            a_lead.page = this_lead.page
            a_lead.parent = this_lead
            a_lead.letter = temp_seq_number + 'a'
            a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper()
            a_lead.save()
            b_lead = dkey_models.Lead()
            b_lead.page = this_lead.page
            b_lead.parent = this_lead
            b_lead.letter = temp_seq_number + 'b'
            b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper()
            b_lead.save()
            added_leads = dkey_models.Lead.objects.filter(parent=lead_id)
        elif command == 'delete':
            # Delete a couplet.
            leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id)
            # Be careful about deleting lead records:
            # verify that there are two, and delete no more than two.
            if leads_to_delete.count() == 2:
                deleted_leads.append(leads_to_delete[0].id)
                deleted_leads.append(leads_to_delete[1].id)
                leads_to_delete.delete()

        last_number = _renumber_page(this_lead.page)

        if slug != slug.lower():
            raise Http404
        title = dkey_models.slug_to_title(slug)
        if title.startswith('Section '):
            title = title.title()
        page = get_object_or_404(dkey_models.Page, title=title)
        if page.rank == 'species':
            raise Http404
        proxy = _Proxy(page)

        return redirect(request.path)