<commit_before>import datetime
import difflib
from flask import redirect, render_template, render_template_string, Blueprint, flash
from flask import request, url_for, jsonify
from flask_user import current_user, login_required, roles_accepted
from flask_login.mixins import AnonymousUserMixin
from flask_mail import Mail, Message

from werkzeug.datastructures import CombinedMultiDict
import json, random
import cPickle as pickle
import os
import uuid
import datetime

from app.init_app import app, db
from app.models import (UserProfileForm, FriendForm, Graph, GraphRevision, User,
                        Friendship, GraphViewRevision, FriendshipInvite)
from app.images import process_profile_picture
from app.utils import (subjective_graph_nodes, subjective_graph_edges,
                       objective_graph_nodes, objective_graph_edges)

# set up Flask Mail
mail = Mail(app)

# The Home page is accessible to anyone
@app.route('/home')
@login_required
def home_page():
    return render_template('pages/home_page.html')

@app.route('/landing')
def landing_page():
    return render_template('pages/landing_page.html')

@app.route('/')
def index():
    if current_user.is_anonymous:
        return render_template('pages/landing_page.html')
    else:
        return redirect(url_for('home_page'))

@app.route('/graphs')
@login_required  # Limits access to authenticated users
def graph_list_page():
    graphs = []
    for g in current_user.graphs_owned:
        graphs.append(g)
    for g in current_user.graphs_helping:
        graphs.append(g)

    return render_template('pages/graph_list_page.html', graphs=graphs)

@app.route('/graph/<id>')
@login_required  # Limits access to authenticated users
def graph_page(id):
    graph = Graph.query.get(id)
    revision = graph.current_revision

    if current_user not in graph.owners and current_user not in graph.helpers:
        return redirect(url_for('graph_list_page'))

    nodes = pickle.loads(str(revision.nodes))
    edges = pickle.loads(str(revision.edges))
    helpers = []
    default_helper = None
    owner_helper = None
    for u in graph.owners + graph.helpers:
        views = GraphViewRevision.query.filter(
            (GraphViewRevision.graph_id == graph.id)
            & (GraphViewRevision.author_id == u.id)).order_by(
                'timestamp').all()

        # construct helper dict to pass into JS
        h = dict(id=u.id,
                 name=" ".join([u.first_name, u.last_name]),
                 photo=os.path.join('/static/images/users/',
                                    u.photo_file_name))

        if len(views) > 0:
            view = views[-1]
            h['view_nodes'] = pickle.loads(str(view.nodes))
            h['view_edges'] = pickle.loads(str(view.edges))
        else:
            # if no views from this helper, use empty lists
            h['view_nodes'] = []
            h['view_edges'] = []

        helpers.append(h)

        if u == current_user:
            default_helper = h
        if u in graph.owners:
            owner_helper = h

    if default_helper is None:
        default_helper = owner_helper

    assert default_helper is not None

    return render_template('pages/graph_page.html', save_id=id,
                           graph_name=graph.name,
                           nodes=json.dumps(nodes), edges=json.dumps(edges),
                           helpers=json.dumps(helpers),
                           default_helper=json.dumps(default_helper))

@app.route('/graph_diff/<id>')
@login_required
def graph_diff(id):
    new_revision = GraphRevision.query.get(id)

    if new_revision.previous_revision_id is None:
        diff = difflib.HtmlDiff().make_table([''],<commit_msg>Added graph JSON endpoint<commit_after>import datetime
import difflib
from flask import redirect, render_template, render_template_string, Blueprint, flash
from flask import request, url_for, jsonify
from flask_user import current_user, login_required, roles_accepted
from flask_login.mixins import AnonymousUserMixin
from flask_mail import Mail, Message

from werkzeug.datastructures import CombinedMultiDict
import json, random
import cPickle as pickle
import os
import uuid
import datetime

from app.init_app import app, db
from app.models import (UserProfileForm, FriendForm, Graph, GraphRevision, User,
                        Friendship, GraphViewRevision, FriendshipInvite)
from app.images import process_profile_picture
from app.utils import (subjective_graph_nodes, subjective_graph_edges,
                       objective_graph_nodes, objective_graph_edges)

# set up Flask Mail
mail = Mail(app)

# The Home page is accessible to anyone
@app.route('/home')
@login_required
def home_page():
    return render_template('pages/home_page.html')

@app.route('/landing')
def landing_page():
    return render_template('pages/landing_page.html')

@app.route('/')
def index():
    if current_user.is_anonymous:
        return render_template('pages/landing_page.html')
    else:
        return redirect(url_for('home_page'))

@app.route('/graphs')
@login_required  # Limits access to authenticated users
def graph_list_page():
    graphs = []
    for g in current_user.graphs_owned:
        graphs.append(g)
    for g in current_user.graphs_helping:
        graphs.append(g)

    return render_template('pages/graph_list_page.html', graphs=graphs)

def get_graph_data(graph):
    revision = graph.current_revision

    nodes = pickle.loads(str(revision.nodes))
    edges = pickle.loads(str(revision.edges))
    helpers = []
    default_helper = None
    owner_helper = None
    for u in graph.owners + graph.helpers:
        views = GraphViewRevision.query.filter(
            (GraphViewRevision.graph_id == graph.id)
            & (GraphViewRevision.author_id == u.id)).order_by(
                'timestamp').all()

        # construct helper dict to pass into JS
        h = dict(id=u.id,
                 name=" ".join([u.first_name, u.last_name]),
                 photo=os.path.join('/static/images/users/',
                                    u.photo_file_name))

        if len(views) > 0:
            view = views[-1]
            h['view_nodes'] = pickle.loads(str(view.nodes))
            h['view_edges'] = pickle.loads(str(view.edges))
        else:
            # if no views from this helper, use empty lists
            h['view_nodes'] = []
            h['view_edges'] = []

        helpers.append(h)

        if u == current_user:
            default_helper = h
        if u in graph.owners:
            owner_helper = h

    if default_helper is None:
        default_helper = owner_helper

    assert default_helper is not None

    return nodes, edges, helpers, default_helper
    
@app.route('/graph/<id>')
@login_required  # Limits access to authenticated users
def graph_page(id):
    graph = Graph.query.get(id)

    if current_user not in graph.owners and current_user not in graph.helpers:
        return redirect(url_for('graph_list_page'))

    nodes, edges, helpers, default_helper = get_graph_data(graph)

    return render_template('pages/graph_page.html', save_id=id,
                           graph_name=graph.name,
                           nodes=json.dumps(nodes), edges=json.dumps(edges),
                           helpers=json.dumps(helpers),
                           default_helper=json.dumps(default_helper))

@app.route('/_graph/<id>')
@login_required  # Limits access to authenticated users
def graph_json(id):
    graph = Graph.query.get(id)

    if current_user not in graph.owners and current_user not in graph.helpers:
        return redirect(url_for('graph_list_page'))

    nodes, edges, helpers, default_helper = get_graph_data(graph)
    graph_data = dict(nodes=nodes,
                      edges=edges,
                      helpers=helpers,
                      default_helper=default_helper)
    
    return jsonify(graph=graph_data)


@app.route('/graph_diff/<id>')
@login_required
def graph_diff(id):
    new_revision = GraphRevision.query.get(id)

    if new_revision.previous_revision_id is None:
        diff = difflib.HtmlDiff().make_table([''],
{'fraction_non_alphanumeric': 0.09712806606680637, 'fraction_numerical': 0.0004930358683594232, 'mean_word_length': 2.834593572778828, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3770021', 'n_tokens_mistral': 2421, 'n_tokens_neox': 2361, 'n_words': 565}