Esempio n. 1
0
def category(label):
    ''' list of entries for a label
    :param label: the type of data to list out
    :return: rendered list page
    '''
    label = helpers.sanitize(label)
    if not graph.validate_label(label):
        labels = graph.get_labels()
        return render_template(request.url, '404.html', labels=labels)

    filtered = None
    try:
        item1 = helpers.sanitize(request.values['i'])
    except KeyError:
        data = graph.get_all(label)
    else:
        try:
            item2 = helpers.sanitize(request.values['j'])
            operator = helpers.sanitize(request.values['op'])
            if operator not in ['and', 'not']:
                raise BadRequestKeyError
        except (KeyError, BadRequestKeyError):
            data = graph.get_filtered(label, item1)
            filtered = {
                'item1': graph.get_node(item1)['nodes'][0],
            }
        else:
            data = graph.get_filtered(label, item1, item2, operator)
            filtered = {
                'operator': operator,
                'item1': graph.get_node(item1)['nodes'][0],
                'item2': graph.get_node(item2)['nodes'][0]
            }

    items = data['nodes']

    template = 'list.html'
    title = 'List of %s' % helpers.capitalize_filter(helpers.pluralize(label))

    grimoires = []
    if label in entities:
        template = 'entity-list.html'
        grimoires = graph.get_all('grimoire',
                                  with_connection_label=label)['nodes']
        if len(grimoires) < 2:
            grimoires = None

    return render_template(request.url,
                           template,
                           items=items,
                           title=title,
                           label=label,
                           grimoires=grimoires,
                           filtered=filtered)
Esempio n. 2
0
def category(label):
    ''' list of entries for a label
    :param label: the type of data to list out
    :return: rendered list page
    '''
    label = helpers.sanitize(label)
    if not graph.validate_label(label):
        labels = graph.get_labels()
        return render_template(request.url, 'label-404.html', labels=labels)

    filtered = None
    try:
        item1 = helpers.sanitize(request.values['i'])
    except KeyError:
        data = graph.get_all(label)
    else:
        try:
            item2 = helpers.sanitize(request.values['j'])
            operator = helpers.sanitize(request.values['op'])
            if operator not in ['and', 'not']:
                raise BadRequestKeyError
        except (KeyError, BadRequestKeyError):
            data = graph.get_filtered(label, item1)
            filtered = {
                'item1': graph.get_node(item1)['nodes'][0],
            }
        else:
            data = graph.get_filtered(label, item1, item2, operator)
            filtered = {
                'operator': operator,
                'item1': graph.get_node(item1)['nodes'][0],
                'item2': graph.get_node(item2)['nodes'][0]
            }

    items = data['nodes']

    template = 'list.html'
    title = 'List of %s' % helpers.capitalize_filter(helpers.pluralize(label))

    grimoires = []
    if label in entities:
        template = 'entity-list.html'
        grimoires = graph.get_all('grimoire',
                                  with_connection_label=label)['nodes']
        if len(grimoires) < 2:
            grimoires = None

    return render_template(request.url, template, items=items,
                           title=title, label=label,
                           grimoires=grimoires, filtered=filtered)
Esempio n. 3
0
def spell():
    ''' custom page for spells
    :return: rendered spell page template '''
    sort = 'outcome'
    try:
        sort = helpers.sanitize(request.values['sort'], allow_spaces=True)
    except BadRequestKeyError:
        pass

    if sort == 'outcome':
        data = graph.get_spells_by_outcome()
    elif sort == 'grimoire':
        data = graph.get_spells_by_grimoire()
    else:
        return redirect('/spell')

    spells = {
        k['props']['identifier']: v
        for k, v in zip(data['nodes'], data['lists'])
    }
    return render_template(request.url,
                           'spells.html',
                           spells=spells,
                           sort=sort,
                           title='List of Spells')
Esempio n. 4
0
def table(entity='demon'):
    ''' a comparison table for grimoires and entities
    :param entity: the type of creature (default is demon)
    :return: the rendered table page
    '''
    if entity not in entities + ['spell']:
        return redirect('/table')

    data = graph.get_grimoire_entities(entity)
    entity_list = data['nodes']

    all_grimoires = []
    for i, grimoire_list in enumerate(data['lists']):
        entity_list[i]['grimoires'] = \
                {g['props']['uid']: g for g in grimoire_list}
        all_grimoires.append(entity_list[i]['grimoires'])

    grimoires = {}
    for d in all_grimoires:
        for key, value in d.items():
            grimoires[key] = value
    grimoires = grimoires.values()
    grimoires = sorted(grimoires, key=lambda g: g['props']['date'])

    isolates_data = graph.get_single_grimoire_entities(entity)
    isolates = zip(isolates_data['nodes'], isolates_data['lists'])

    return render_template(request.url, 'table.html', entity=entity,
                           grimoires=grimoires, entities=entity_list,
                           isolates=isolates, table=True)
Esempio n. 5
0
def table(entity='demon'):
    ''' a comparison table for grimoires and entities
    :param entity: the type of creature (default is demon)
    :return: the rendered table page
    '''
    if entity not in entities + ['spell']:
        return redirect('/table')

    data = graph.get_grimoire_entities(entity)
    entity_list = data['nodes']

    all_grimoires = []
    for i, grimoire_list in enumerate(data['lists']):
        entity_list[i]['grimoires'] = \
                {g['props']['uid']: g for g in grimoire_list}
        all_grimoires.append(entity_list[i]['grimoires'])

    grimoires = {}
    for d in all_grimoires:
        for key, value in d.items():
            grimoires[key] = value
    grimoires = grimoires.values()
    grimoires = sorted(grimoires, key=lambda g: g['props']['date'])

    isolates_data = graph.get_single_grimoire_entities(entity)
    isolates = zip(isolates_data['nodes'], isolates_data['lists'])

    return render_template(request.url,
                           'table.html',
                           entity=entity,
                           grimoires=grimoires,
                           entities=entity_list,
                           isolates=isolates,
                           table=True)
Esempio n. 6
0
def timeline_page():
    ''' timeline data display
    :return: rendered timeline page
    '''
    events = graph.get_all('event')['nodes']
    for event in events:
        if event['props']['type'] == 'grimoire':
            event['props']['relevant'] = True

    timeline, start, end = build_timeline(events)
    return render_template(request.url,
                           'timeline.html',
                           data=timeline,
                           start=start,
                           end=end)
Esempio n. 7
0
def redirect_excerpts(uid):
    ''' Re-route anyone who lands on an excerpt page to the proper node
    :param uid: the excerpt's identifier
    :return: a redirect to the linked content node
    '''

    data = graph.get_node(uid)
    source = extract_rel_list_by_type(data['rels'], 'event', 'start') + \
             extract_rel_list_by_type(data['rels'], 'excerpt', 'start') + \
             extract_rel_list_by_type(data['rels'], 'image', 'start')
    try:
        source = source[0]
    except IndexError:
        return render_template(request.url, 'label-404.html',
                               labels=graph.get_labels())

    return redirect(source['link'])
Esempio n. 8
0
def search():
    ''' look up a term '''
    try:
        term = helpers.sanitize(request.values['term'], allow_spaces=True)
    except BadRequestKeyError:
        return redirect('/')

    if not term:
        return redirect('/')
    data = graph.search(term)

    # if there's only one result, redirect
    if len(data['nodes']) == 1:
        item = data['nodes'][0]
        return redirect('/%s/%s' % (item['label'], item['props']['uid']))
    template_data = {'results': data['nodes'], 'term': term}
    return render_template(request.url, 'search.html', **template_data)
Esempio n. 9
0
def redirect_excerpts(uid):
    ''' Re-route anyone who lands on an excerpt page to the proper node
    :param uid: the excerpt's identifier
    :return: a redirect to the linked content node
    '''

    data = graph.get_node(uid)
    source = extract_rel_list_by_type(data['rels'], 'event', 'start') + \
             extract_rel_list_by_type(data['rels'], 'excerpt', 'start') + \
             extract_rel_list_by_type(data['rels'], 'image', 'start')
    try:
        source = source[0]
    except IndexError:
        return render_template(request.url,
                               '404.html',
                               labels=graph.get_labels())

    return redirect(source['link'])
Esempio n. 10
0
def search():
    ''' look up a term '''
    try:
        term = helpers.sanitize(request.values['term'], allow_spaces=True)
    except BadRequestKeyError:
        return redirect('/')

    if not term:
        return redirect('/')
    data = graph.search(term)

    # if there's only one result, redirect
    if len(data['nodes']) == 1:
        item = data['nodes'][0]
        return redirect('/%s/%s' % (item['label'], item['props']['uid']))
    template_data = {
        'results': data['nodes'],
        'term': term
    }
    return render_template(request.url, 'search.html', **template_data)
Esempio n. 11
0
def spell():
    ''' custom page for spells
    :return: rendered spell page template '''
    sort = 'outcome'
    try:
        sort = helpers.sanitize(request.values['sort'], allow_spaces=True)
    except BadRequestKeyError:
        pass

    if sort == 'outcome':
        data = graph.get_spells_by_outcome()
    elif sort == 'grimoire':
        data = graph.get_spells_by_grimoire()
    else:
        return redirect('/spell')

    spells = {k['props']['identifier']: v
              for k, v in zip(data['nodes'], data['lists'])}
    return render_template(request.url, 'spells.html',
                           spells=spells, sort=sort,
                           title='List of Spells')
Esempio n. 12
0
def timeline_page():
    ''' timeline data display
    :return: rendered timeline page
    '''

    nodes = graph.timeline()['nodes']
    if not graph.timeline_labels:
        graph.timeline_labels = set([n['label'] for n in nodes])

    show = [l for l in graph.timeline_labels
            if l in request.args and request.values[l] == 'on']

    if show:
        nodes = [n for n in nodes if n['label'] in show]
    else:
        show = graph.timeline_labels

    timeline = {}
    for node in nodes:
        for event in date_params:
            if event not in node['props']:
                continue
            try:
                year = int(node['props'][event])
            except ValueError:
                continue

            date_precision = node['props'].get('date_precision', 'year')

            note = event if event not in ['year', 'date'] else None
            timeline = helpers.add_to_timeline(timeline, node, year,
                                               date_precision, note=note)

    end = date.today().year
    return render_template(request.url, 'timeline.html', data=timeline, end=end,
                           labels=graph.timeline_labels, show=show)
Esempio n. 13
0
def teacups():
    data = graph.get_all('teacup')['nodes']
    return render_template(request.url, 'teacups.html', cups=data)
Esempio n. 14
0
def compare_grimoires(uid_1, uid_2):
    ''' compare two items of the same type '''
    try:
        data = (helpers.get_node(uid_1), helpers.get_node(uid_2))
    except NameError:
        return redirect('/compare')

    nodes = [d['node'] for d in data]
    rels = [d['rels'] for d in data]

    data = {'item_1': nodes[0], 'item_2': nodes[1]}

    # ----- check that item 1 and item 2 are both grimoires
    if nodes[0]['parent_label'] != 'parent:book' or \
            nodes[1]['parent_label'] != 'parent:book':
        return redirect(nodes[0]['link'])

    # ----- get all shared items to list out
    max_list_size = 0
    # keeps track of the biggest list
    data['shared_list'] = {}
    for entity in entities + ['spell']:
        entity_lists = [
            extract_rel_list_by_type(rel_list, 'lists', 'end', label=entity)
            for rel_list in rels
        ]
        data['shared_list'][entity] = intersection(entity_lists[0],
                                                   entity_lists[1])
        max_list_size = max_list_size \
                        if len(data['shared_list'][entity]) < max_list_size \
                        else len(data['shared_list'][entity])
    data['default_collapse'] = max_list_size > 20

    data['title'] = '"%s" vs "%s"' % (nodes[0]['props']['identifier'],
                                      nodes[1]['props']['identifier'])

    # ----- Properties table
    grim_items = [grimoire_item(nodes[i], rels[i]) for i in range(2)]
    details = [g['details'] for g in grim_items]
    for d in details:
        d['author'] = d.get('author', [{'text': 'Unknown'}])
    keys = list(set(details[0].keys()) & set(details[1].keys()))
    keys = [k for k in keys if k not in ['Name', 'online_edition']]
    data['props'] = {k: [details[0][k], details[1][k]] for k in keys}

    # ----- compare remaining rels
    rels = [helpers.exclude_rels(rel_list, ['lists']) for rel_list in rels]

    # pull out rels between the two grimoires
    data['self_rels'] = []
    for rel in rels[0]:
        if rel['start']['props']['uid'] in [uid_1, uid_2] and \
           rel['end']['props']['uid'] in [uid_1, uid_2]:
            data['self_rels'].append(rel)

    exclude_ids = [r['id'] for r in data['self_rels']]
    rels[0] = [r for r in rels[0] if not r['id'] in exclude_ids]
    rels[1] = [r for r in rels[1] if not r['id'] in exclude_ids]

    # make a dictionary for each relationship type with an empty array value
    # ie: {'wrote': [[], []], 'influenced': [[], []]}
    types = {t: [[], []] for t in \
             list(set([r['type'] for r in rels[0] + rels[1]]))}

    # populate types dictionary with every relationship of that type
    for (i, rel_list) in enumerate(rels):
        for rel in rel_list:
            types[rel['type']][i] += [rel]

    # remove types that only exist for one item or the other
    types = {k: v for (k, v) in types.items() if v[0] and v[1]}

    data['same'] = {'start': [], 'end': []}
    for rel_type in types:
        relset = types[rel_type]
        direction = 'end' if \
                    relset[0][0]['start']['props']['uid'] == uid_1 \
                    else 'start'

        subjects = [[rel[direction] for rel in r] for r in relset]
        same_uids = [
            i['props']['uid'] for i in intersection(subjects[0], subjects[1])
        ]
        same_rels = [rel for rel in relset[0] if \
                     rel[direction]['props']['uid'] in same_uids]

        data['same']['start' if direction == 'end' else 'end'] += same_rels

    data['same'] = {
        'start': helpers.combine_rels(data['same']['start']),
        'end': helpers.combine_rels(data['same']['end'])
    }

    data['grimoires'] = graph.get_all('grimoire')['nodes']

    return render_template(request.url, 'compare.html', **data)
Esempio n. 15
0
def compare_start():
    ''' load form for comparing grimoires '''
    grimoires = graph.get_all('grimoire')['nodes']
    return render_template(request.url, 'compare.html', grimoires=grimoires)
Esempio n. 16
0
def item(label, uid):
    ''' generic page for an item
    :param label: the desired neo4j label
    :param uid: the human-readable uid of the node
    :return: customized data for this label rendered item page template
    '''

    # load and validate url data
    label = helpers.sanitize(label)
    if not graph.validate_label(label):
        logging.error('Invalid label %s', label)
        return render_template(request.url,
                               '404.html',
                               labels=graph.get_labels())

    try:
        data = helpers.get_node(uid)
    except NameError:
        items = graph.get_all(label)
        return render_template(request.url,
                               '404.html',
                               items=items['nodes'],
                               search=graph.search(uid)['nodes'],
                               label=label)

    node = data['node']
    rels = data['rels']

    # ----- page header/metadata
    title = node['props']['identifier']

    # ----- formatted data
    switch = {
        'parent:book': grimoire_item,
        'parent:entity': entity_item,
        'art': art_item,
        'language': language_item,
        'edition': edition_item,
        'publisher': publisher_item,
        'editor': editor_item,
        'default': generic_item,
        'spell': spell_item,
        'talisman': spell_item,
        'parent:ingredient': ingredient_item,
        'outcome': outcome_item
    }

    key = node['parent_label'] if node['parent_label'] in switch else \
          (label if label in switch else 'default')
    item_data = switch[key](node, rels)

    item_data['rels'] = helpers.combine_rels(item_data['rels'])

    # ----- sidebar
    sidebar = []
    related = graph.related(uid, label)
    if related['nodes']:
        sidebar = [{'title': 'Similar %s' % \
                    helpers.capitalize_filter(helpers.pluralize(label)),
                    'data': related['nodes']}]
    sidebar += get_others(data['rels'], node)

    if not item_data['content'] and not item_data['excerpts']:
        item_data['content'] = 'The %s "%s."' % \
                               (helpers.format_filter(label),
                                helpers.unthe(title))

    max_main_length = max([len(i['data']) for i in item_data['main']] + [0])
    default_collapse = len(item_data['main']) > 2 or max_main_length > 30

    return render_template(request.url,
                           'item.html',
                           data=item_data,
                           title=title,
                           label=label,
                           sidebar=sidebar,
                           default_collapse=default_collapse)
Esempio n. 17
0
def compare_grimoires(uid_1, uid_2):
    ''' compare two items of the same type '''
    try:
        data = (helpers.get_node(uid_1), helpers.get_node(uid_2))
    except NameError:
        return redirect('/compare')

    nodes = [d['node'] for d in data]
    rels = [d['rels'] for d in data]

    data = {
        'item_1': nodes[0],
        'item_2': nodes[1]
    }

    # ----- check that item 1 and item 2 are both grimoires
    if nodes[0]['parent_label'] != 'parent:book' or nodes[1]['parent_label'] != 'parent:book':
        return redirect(nodes[0]['link'])

    # ----- get all shared items to list out
    max_list_size = 0
    # keeps track of the biggest list
    data['shared_list'] = {}
    for entity in entities + ['spell']:
        entity_lists = [
            extract_rel_list_by_type(rel_list, 'lists', 'end', label=entity)
            for rel_list in rels]
        data['shared_list'][entity] = intersection(entity_lists[0],
                                                   entity_lists[1])
        max_list_size = max_list_size \
                        if len(data['shared_list'][entity]) < max_list_size \
                        else len(data['shared_list'][entity])
    data['default_collapse'] = max_list_size > 20

    data['title'] = '"%s" vs "%s"' % (nodes[0]['props']['identifier'],
                                      nodes[1]['props']['identifier'])

    # ----- Properties table
    grim_items = [grimoire_item(nodes[i], rels[i]) for i in range(2)]
    details = [g['details'] for g in grim_items]
    for d in details:
        d['author'] = d.get('author', [{'text': 'Unknown'}])
    keys = list(set(details[0].keys()) & set(details[1].keys()))
    keys = [k for k in keys if k not in ['Name', 'online_edition']]
    data['props'] = {k: [details[0][k], details[1][k]] for k in keys}

    # ----- compare remaining rels
    rels = [helpers.exclude_rels(rel_list, ['lists']) for rel_list in rels]

    # pull out rels between the two grimoires
    data['self_rels'] = []
    for rel in rels[0]:
        if rel['start']['props']['uid'] in [uid_1, uid_2] and \
           rel['end']['props']['uid'] in [uid_1, uid_2]:
            data['self_rels'].append(rel)

    exclude_ids = [r['id'] for r in data['self_rels']]
    rels[0] = [r for r in rels[0] if not r['id'] in exclude_ids]
    rels[1] = [r for r in rels[1] if not r['id'] in exclude_ids]

    # make a dictionary for each relationship type with an empty array value
    # ie: {'wrote': [[], []], 'influenced': [[], []]}
    types = {t: [[], []] for t in \
             list(set([r['type'] for r in rels[0] + rels[1]]))}

    # populate types dictionary with every relationship of that type
    for (i, rel_list) in enumerate(rels):
        for rel in rel_list:
            types[rel['type']][i] += [rel]

    # remove types that only exist for one item or the other
    types = {k: v for (k, v) in types.items() if v[0] and v[1]}

    data['same'] = {'start': [], 'end': []}
    for rel_type in types:
        relset = types[rel_type]
        direction = 'end' if \
                    relset[0][0]['start']['props']['uid'] == uid_1 \
                    else 'start'

        subjects = [[rel[direction] for rel in r] for r in relset]
        same_uids = [
            i['props']['uid'] for i in intersection(subjects[0], subjects[1])
        ]
        same_rels = [rel for rel in relset[0] if \
                     rel[direction]['props']['uid'] in same_uids]

        data['same']['start' if direction == 'end' else 'end'] += same_rels

    data['same'] = {
        'start': helpers.combine_rels(data['same']['start']),
        'end': helpers.combine_rels(data['same']['end'])
    }

    data['grimoires'] = graph.get_all('grimoire')['nodes']

    return render_template(request.url, 'compare.html', **data)
Esempio n. 18
0
def compare_start():
    ''' load form for comparing grimoires '''
    grimoires = graph.get_all('grimoire')['nodes']
    return render_template(request.url, 'compare.html', grimoires=grimoires)
Esempio n. 19
0
def item(label, uid):
    ''' generic page for an item
    :param label: the desired neo4j label
    :param uid: the human-readable uid of the node
    :return: customized data for this label rendered item page template
    '''

    # load and validate url data
    label = helpers.sanitize(label)
    if not graph.validate_label(label):
        logging.error('Invalid label %s', label)
        return render_template(request.url,
                               'label-404.html',
                               labels=graph.get_labels())

    try:
        data = helpers.get_node(uid)
    except NameError:
        items = graph.get_all(label)
        return render_template(request.url, 'item-404.html',
                               items=items['nodes'],
                               search=graph.search(uid)['nodes'],
                               label=label)

    node = data['node']
    rels = data['rels']

    # ----- page header/metadata
    title = node['props']['identifier']

    # ----- formatted data
    switch = {
        'parent:book': grimoire_item,
        'parent:entity': entity_item,
        'art': art_item,
        'language': language_item,
        'edition': edition_item,
        'publisher': publisher_item,
        'editor': editor_item,
        'default': generic_item,
        'spell': spell_item,
        'talisman': spell_item,
        'parent:ingredient': ingredient_item,
        'outcome': outcome_item
    }

    key = node['parent_label'] if node['parent_label'] in switch else \
          (label if label in switch else 'default')
    item_data = switch[key](node, rels)

    item_data['rels'] = helpers.combine_rels(item_data['rels'])

    # ----- sidebar
    sidebar = []
    related = graph.related(uid, label)
    if related['nodes']:
        sidebar = [{'title': 'Similar %s' % \
                    helpers.capitalize_filter(helpers.pluralize(label)),
                    'data': related['nodes']}]
    sidebar += get_others(data['rels'], node)

    if not item_data['content'] and not item_data['excerpts']:
        item_data['content'] = 'The %s "%s."' % \
                               (helpers.format_filter(label),
                                helpers.unthe(title))

    max_main_length = max([len(i['data']) for i in item_data['main']] + [0])
    default_collapse = len(item_data['main']) > 2 or max_main_length > 30

    return render_template(request.url, 'item.html',
                           data=item_data,
                           title=title,
                           label=label,
                           sidebar=sidebar,
                           default_collapse=default_collapse)
Esempio n. 20
0
def updates():
    ''' Simple page of updates I've posted '''
    return render_template(request.url, 'updates.html', title='News & Updates')
Esempio n. 21
0
def support():
    ''' the "give me money" page '''
    return render_template(request.url, 'support.html',
                           title='Support Grimoire dot org')
Esempio n. 22
0
def updates():
    ''' Simple page of updates I've posted '''
    return render_template(request.url, 'updates.html', title='News & Updates')
Esempio n. 23
0
def api_docs():
    ''' API documentation page '''
    return render_template(request.url, 'api.html', title='API Documentation')
Esempio n. 24
0
def support():
    ''' the "give me money" page '''
    return render_template(request.url,
                           'support.html',
                           title='Support Grimoire dot org')
Esempio n. 25
0
def api_docs():
    ''' API documentation page '''
    return render_template(request.url, 'api.html', title='API Documentation')