src/catedit/views/categories.py
author durandn
Fri, 17 Apr 2015 10:45:30 +0200
changeset 131 7684ea24c330
parent 121 70b206790ef6
child 132 04de6a298527
permissions -rw-r--r--
started refactoring viewe + fix bug with corrupted properties

"""
categories.py:
The views functions that handle category management and editing
"""

from catedit import app
from catedit.models import Category
from catedit.resources import CategoryAPI, CategoryChangesAPI
from catedit.views.utils import check_user_status_and_repo_access, \
                                get_current_category_list, get_commits, \
                                get_issues
from catedit.utils import get_property_list
from io import StringIO

from flask import render_template, request, redirect, url_for, abort, Blueprint
from rdflib import Graph

from catedit.views.forms import CommitForm, CategoryForm


module = Blueprint('categories', __name__)
logger = app.logger


@module.route(
    '/<string:repository>/workshop', methods=['GET']
)
def workshop(repository):
    """
        View that has a list of all categories available. Template is
        categories/workshop.html, located in src/templates/
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)
    
    cat_list = get_current_category_list(repository=repository)
    cat_list = sorted(cat_list, key=lambda cat: cat['cat_id'])
    changeset_list = get_commits(repository, 5, 1)[0]
    discussion_list = get_issues(repository, 5, 1)[0]
    return render_template(
        'categories/workshop.html',
        cat_list=cat_list,
        changeset_list=changeset_list,
        discussion_list=discussion_list,
        current_repository=repository
    )


@module.route(
    '/<string:repository>/delete-modifs-<deleted_changes_id>&redirect_to=<redirect_to>',
    methods=['POST']
)
def delete_changes(repository, deleted_changes_id, redirect_to):
    """
        View that handles deleting changes for a given repo. If no deleted_changes_id is
        given, it will delete every change
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)
    
    cat_changes_api_instance = CategoryChangesAPI()
    if deleted_changes_id is None:
        cat_changes_api_instance.delete(repository=repository)
    else:
        cat_changes_api_instance.delete(
            repository=repository,
            modified_cat_id=deleted_changes_id
        )
    return redirect(url_for('categories.'+redirect_to, repository=repository))


@module.route(
    '/<string:repository>/delete-<deleted_cat_id>&redirect_to=<redirect_to>',
    methods=['POST']
)
def delete_category(repository, deleted_cat_id, redirect_to):
    """
        View that handles deleting a given category for a given repo
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)
    
    cat_api_instance = CategoryAPI()
    if deleted_cat_id is not None:
        cat_api_instance.delete(
            repository=repository,
            deleted_cat_id=deleted_cat_id
        )
    return redirect(url_for('categories.'+redirect_to, repository=repository))


@module.route(
    '/<string:repository>/submit', methods=['GET']
)
def submit(repository):
    """
        View that handles all the visualisation of changes for a user's
        session, links to the editor forms, allows the users to cancel their
        own changes and submits all their changes.

        Template is categories/submit.html, located in src/templates/
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)

    commit_form = CommitForm(request.form)
    
    cat_list = get_current_category_list(repository=repository)
    original_cat_list = get_current_category_list(
        repository=repository,
        with_local_changes=False
    )

    created_cat_count = len([
        created_cat for created_cat in cat_list
        if created_cat["state"] == "created"
    ])
    edited_cat_count = len([
        edited_cat for edited_cat in cat_list
        if edited_cat["state"] == "modified"
    ])
    deleted_cat_count = len([
        deleted_cat for deleted_cat in cat_list
        if deleted_cat["state"] == "deleted"
    ])

    return render_template('categories/submit.html',
                           cat_list=cat_list,
                           original_cat_list=original_cat_list,
                           original_cat_count=len(original_cat_list),
                           created_cat_count=created_cat_count,
                           edited_cat_count=edited_cat_count,
                           deleted_cat_count=deleted_cat_count,
                           commit_form=commit_form,
                           current_repository=repository)


@module.route(
    '/<string:repository>/push_changes', methods=['POST']
)
def push_changes(repository):
    """
        View that handles POST from the submit page
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)
    
    cat_api_instance = CategoryAPI()
    cat_changes_api_instance = CategoryChangesAPI()
    
    commit_form = CommitForm(request.form)
    
    if commit_form.validate_on_submit():
        cat_api_instance.put(repository=repository, message=commit_form.commit_message.data)
        cat_changes_api_instance.delete(repository=repository)
        return redirect(url_for('categories.workshop', repository=repository))
    else:
        return redirect(url_for('categories.submit', repository=repository))


@module.route('/<string:repository>/editor',
              defaults={'cat_id': None},
              methods=['GET', 'POST'])
@module.route('/<string:repository>/editor/<string:cat_id>',
              methods=['GET', 'POST'])
def editor(repository, cat_id):
    """
        View that handles creation and edition of categories. Template is
        categories/editor.html, located in src/templates
    """
    if repository not in app.config["PERSISTENCE_CONFIG"]["REPOSITORY_LIST"]:
        abort(404)

    check_user_status_and_repo_access(repository)

    cat_api_instance = CategoryAPI()
    cat_changes_api_instance = CategoryChangesAPI()

    specific_serialized_cat = ""
    # Serialization of the category of id cat_id, either from
    # CategoryChangesAPI (if it was modified) or from CategoryAPI (if it
    # was not)

    changes_response = None
    # Changes on the category cat_id we get from CategoryChangesAPI

    current_cat = None
    current_cat_id = None
    current_cat_properties = []
    # Args for the template, if we create a new category they are not used

    cat_list = []
    # Category list that will be used by the template
    deleted_cat_dict = {}
    # Deleted categories we won't append to cat_list
    modified_cat_dict = {}
    # Modified categories to append to cat_list in case label changed
    serialized_cat_list = []
    # Existing categories we get from CategoryAPI
    cat_changes = {}
    # Changes list we get from CategoryChangesAPI

    if cat_id is not None:
        changes_response = cat_changes_api_instance.get(
            repository=repository,
            modified_cat_id=cat_id
        )
        if changes_response[0]["type"] is "deleted":
            abort(404)
        elif changes_response[0]["type"] is "modified":
            specific_serialized_cat = changes_response[0] \
                                                      ["category"] \
                                                      [cat_id]
        elif changes_response[0]["type"] is "untouched":
            category_api_response = cat_api_instance.get(
                repository=repository,
                cat_id=cat_id
            )
            if category_api_response == 404:
                abort(404)
            else:
                specific_serialized_cat = category_api_response[0]
        #TODO: vérifier encoding - logger.debug(specific_serialized_cat)

        cat_rdf_graph = Graph()
        cat_rdf_graph.parse(source=StringIO(specific_serialized_cat),
                            format='turtle')

        current_cat = Category(graph=cat_rdf_graph)
        current_cat_id = current_cat.cat_id
        current_cat_properties = current_cat.properties

    serialized_cat_list = cat_api_instance.get(repository)[0]
    cat_changes = cat_changes_api_instance.get(repository)[0]
    deleted_cat_dict = cat_changes["deleted_categories"]
    modified_cat_dict = cat_changes["modified_categories"]
    #TODO: vérifier encoding - logger.debug(changes_response)

    for modified_cat_name in modified_cat_dict.keys():
        modified_cat_rdf_graph = Graph()
        modified_cat_rdf_graph.parse(
            source=StringIO(modified_cat_dict[modified_cat_name]),
            format='turtle'
        )
        modified_cat = Category(graph=modified_cat_rdf_graph)
        cat_list.append({"cat_label": modified_cat.label,
                         "cat_description": modified_cat.description,
                         "cat_id": modified_cat.cat_id,
                         "cat_properties": modified_cat.properties})

    for serialized_cat in serialized_cat_list:
        cat_rdf_graph = Graph()
        cat_rdf_graph.parse(source=StringIO(serialized_cat),
                            format='turtle')
        cat = Category(graph=cat_rdf_graph)
        if cat.cat_id not in deleted_cat_dict.keys() and \
           cat.cat_id not in modified_cat_dict.keys():
            cat_list.append({"cat_label": cat.label,
                             "cat_description": cat.description,
                             "cat_id": cat.cat_id,
                             "cat_properties": cat.properties})

    cat_form = CategoryForm(request.form)

    if request.method == "GET":
        """
            GET Method means we will display the editor
        """
        if current_cat is not None:
            cat_form.label.data = current_cat.label
            cat_form.description.data = current_cat.description
            for (cat_predicate, cat_object) in current_cat_properties:
                can_append = True
                if get_property_list()[repository][cat_predicate.toPython()]["object_type"] == "uriref-category":             
                    if "#" in cat_object:
                        namespace, object_id = cat_object.split("#", 1)
                    else:
                        can_append = False
                else:
                    object_id = cat_object
                if can_append:
                    cat_form.properties.append_entry({
                        "property_predicate": cat_predicate.toPython(),
                        "property_object": object_id
                    })
        # list of category that will be used in property editor, list of dict
        # {"cat_id": cat.cat_id,
        #  "cat_label": cat.label,
        #  "cat_description": cat.description,
        #  "cat_properties": cat.properties}
        return render_template('categories/editor.html',
                               cat_id=current_cat_id,
                               cat_properties=current_cat_properties,
                               form=cat_form,
                               cat_list=cat_list,
                               deleted_cat_list=list(deleted_cat_dict.keys()),
                               current_repository=repository)
    elif request.method == "POST":
        """
            POST Method means we will compute the form data, call the relevant
            "POST" and "PUT" method on CategoryAPI, and return to a display
            page (workshop for now, ideally the one from whence we came)
        """
        if cat_form.validate_on_submit():
            cat_data = {}
            cat_data["label"] = cat_form.label.data
            cat_data["description"] = cat_form.description.data
            cat_data["properties"] = [
                (cat_property["property_predicate"],
                 cat_property["property_object"])
                for cat_property in cat_form.properties.data
            ]
            if cat_id is not None:
                #TODO: vérifier encoding - logger.debug(str(cat_data))
                cat_api_instance.put(
                    repository=repository,
                    cat_id=cat_id,
                    cat_data=cat_data
                )
            else:
                #TODO: vérifier encoding - logger.debug(str(cat_data))
                cat_api_instance.post(
                    repository=repository,
                    cat_data=cat_data
                )
            return redirect(url_for('categories.workshop', repository=repository))
        else:
            # if form doesn't validate we don't want to delete whatever
            # changes the user did
            return render_template('categories/editor.html',
                                   cat_id=cat_id,
                                   cat_properties=current_cat_properties,
                                   form=cat_form,
                                   cat_list=cat_list,
                                   deleted_cat_list=list(
                                       deleted_cat_dict.keys()
                                   ),
                                   current_repository=repository)