Beispiel #1
0
def _collect_stats(project_id):
    """
    Synopsis:
        Collects all the data neccessary to render stats pngs for a given project.
    :param project_id: ID of the project for which the stats are to be collected
    :returns stats: dictionary of stats
    """
    stats = {
        'nodes_over_time': list(),
        'edges_over_time': list(),
        'most_connected_obj': None,
        'least_connected_obj': None,
        'model_complexity_over_time': list(),
        'class_data_complexity': list(),
        'class_function_complexity': list()
    }

    mdjs = db.get_project_models(project_id=project_id)
    if not mdjs:
        return stats

    parsed, timeslice_array = _collect_quantity_stats(mdjs, stats)
    _collect_connectivity_stats(parsed, stats)
    _collect_complexity_stats(stats, timeslice_array)

    os.remove('degree_script.gvpr')
    os.remove('temp.dot')

    return stats
Beispiel #2
0
def get_diagrams(project_id, token):
    """
    Synopsis:
        Collects and returns the diagram IDs contained in a project.
    Status Codes:
        200: successful
        400: password or token count not found in request
        403: password invalid
        404: project not found in database
        410: project is empty
    :param project_id: unique project ID
    :param token: user authentification token
    :returns response: JSON-object containing
        1. list of (name, ID) tuples
    """
    if not is_int_castable(project_id):
        abort(400)  # Bad request

    if not token_is_valid(project_id, token):
        abort(403)  # Forbidden

    if not db.check_project_exists(project_id=project_id):
        abort(404)  # Not found

    mdjs = db.get_project_models(project_id=project_id)
    if len(mdjs) < 1:
        abort(410)  # Gone

    parsed = parser.parse_models(mdj_array=mdjs)

    return jsonify({
        'dia_name_id_pairs':
        list(set(anal.get_diagram_names_and_ids(parsed)))
    }), 200  # OK
Beispiel #3
0
def get_recent_changes(project_id, from_rev, to_rev, token, diagram_id):
    """
    Synopsis:
        Returns a textual diff-log of the given project, restricted to objects in the given diagram.
        This function claims the *db.lock* system lock.
    Status Codes:
        400: invalid project ID
        403: password invalid
        404: project not found in database OR diagram ID not found in project
        410: project is empty
    :param project_id: unique project ID
    :param from_rev: revision index to start changelog
    :param to_rev: revision index to end changelog
    :param token: user authentification token
    :param diagram_id: ID of diagram restricting which objects are to be rendered
    :returns log: string
    """
    if not is_int_castable(project_id):
        abort(400)  # Bad request

    if not token_is_valid(project_id, token):
        abort(403)  # Forbidden

    if not db.check_project_exists(project_id=project_id):
        abort(404)  # Not found

    mdjs = db.get_project_models(project_id=project_id)
    if not mdjs:
        abort(410)  # Gone

    parsed = parser.parse_models(mdj_array=mdjs)
    if not parsed:
        abort(500)  # Internal Server Error

    diagram_name_id_pairs = list(set(anal.get_diagram_names_and_ids(parsed)))
    if diagram_id not in map(lambda x: x[1], diagram_name_id_pairs):
        abort(404)  # Not found

    timeslice_array, error_flag = anal.get_timeslices(parsed=parsed,
                                                      diagram_id=diagram_id)

    if error_flag:
        abort(500)  # Internal Server Error

    log = gen.generate_log(timeslice_array=timeslice_array,
                           from_version=from_rev,
                           to_version=to_rev)

    return log
Beispiel #4
0
def download_revision(project_id, revision_id, token):
    """
    Synopsis:
        Provides an uploaded revision as download.
        This function claims the *db.lock* system lock.
    Status Codes:
        400: invalid project ID
        403: password invalid
        404: project not found in database OR revision not found in database
    :param project_id: unique project ID
    :param revision_id: ID of the revision to be downloaded
    :param token: user authentification token
    :returns file: file
    """
    if not is_int_castable(project_id):
        abort(400)  # Bad request

    if not token_is_valid(project_id, token):
        abort(403)  # Forbidden

    if not db.check_project_exists(project_id):
        abort(404)  # Not found

    mdjs = db.get_project_models(project_id=project_id)
    if not mdjs:
        abort(404)  # Not found

    for path in mdjs:
        if 'v' + str(revision_id) in path:
            break
    else:
        abort(404)  # Not found

    return send_file(path,
                     as_attachment=True,
                     attachment_filename=path.split(os.path.sep)[-1])
Beispiel #5
0
def get_history(project_id, frame, token, diagram_id):
    """
    Synopsis:
        Returns a frame of the visualized diagram history of the given project.
        The frame is taken from the project cache. If no cache exists for the given diagram,
        all frames of the history are rendered and composed into a new cache.
        This function claims the *db.lock* and *cache.lock* system locks.
    Status Codes:
        400: invalid project ID
        403: password invalid
        404: project not found in database OR diagram ID not found in project
        410: project is empty
        416: frame index out of bounds
    :param project_id: unique project ID
    :param frame: index of frame to be returned. range: [0 - #revisions]
    :param token: user authentification token
    :param diagram_id: ID of diagram restricting which objects are to be rendered
    :returns file: file, mimetype = image/png
    """
    if not is_int_castable(project_id):
        abort(400)  # Bad request

    if not token_is_valid(project_id, token):
        abort(403)  # Forbidden

    if not db.check_project_exists(project_id=project_id):
        abort(404)  # Not found

    with open('cache.lock', 'a', 0) as cache_lock:
        plocker.lock(cache_lock, plocker.LOCK_EX)
        frame_path = db.get_cache_filepath(frame, project_id, diagram_id)
        if frame_path:
            return send_file(frame_path, mimetype='image/png')

        mdjs = db.get_project_models(project_id=project_id)
        if len(mdjs) == 0:
            abort(410)  # Gone
        if len(mdjs) < frame or frame < 0:
            abort(416)  # Range not acceptable

        parsed = parser.parse_models(mdj_array=mdjs)
        if not parsed:
            abort(500)  # Internal Server Error

        diagram_name_id_pairs = list(
            set(anal.get_diagram_names_and_ids(parsed)))
        if diagram_id not in map(lambda x: x[1], diagram_name_id_pairs):
            abort(404)  # Not found

        timeslice_array, error_flag = anal.get_timeslices(
            parsed=parsed, diagram_id=diagram_id)
        if error_flag:
            abort(500)  # Internal Server Error

        anim.render_timeslices(timeslice_array=timeslice_array)

        db.build_cache(project_id, diagram_id)

        frame_path = db.get_cache_filepath(frame, project_id, diagram_id)
        if frame_path:
            return send_file(frame_path, mimetype='image/png')
        else:
            abort(500)  # Internal Server Error
Beispiel #6
0
def create_new_revision(project_id, token):
    """
    Synopsis:
        Checks in a new model revision into a given project.
        The model is saved as new file in the database.
        The project statistics are updated.
        This operation invalidates the project cache.
        This function claims the *db.lock* and *cache.lock* system locks.
    Status Codes:
        201: successful
        400: password or token count not found in request
        403: password invalid
        413: provided model file too large
        415: provided file has unsupported type
        422: model does not contain any parsable information
    :param project_id: unique project ID
    :param token: user authentification token
    :returns response: JSON-object containing
        1. new revision ID
        2. project ID
        3. return message
    """
    if request.content_length > MDJ_MAX_SIZE:
        abort(413)  # Payload Too Large

    if not is_int_castable(project_id):
        abort(400)  # Bad request

    if not token_is_valid(project_id, token):
        abort(403)  # Forbidden

    model_file = None
    unicode_filename = ''

    if request.files and request.files['file'] and request.form['filename']:
        model_file = list()
        for line in request.files['file'].stream:
            model_file.append(line)
        escaped_filename = request.form['filename'].encode('utf-8')
        unescaped_filename = escaped_filename.decode('string-escape')
        unicode_filename = unescaped_filename.decode('utf-8')
    else:
        abort(400)  # Bad request

    if model_file is None or not allowed_file(unicode_filename):
        abort(415)  # Unsupported Media Type

    db.invalidate_cache(project_id)

    db.add_revision(project_id='temp',
                    model_file=model_file,
                    filename=unicode_filename)
    new_version_number = -1
    mdjs = db.get_project_models(project_id='temp')

    parsed = parser.parse_models(mdj_array=mdjs)
    db.delete_project('temp')
    if len(anal.get_diagram_names_and_ids(parsed)) == 0:
        abort(422)  # Unprocessable Entity

    else:
        new_version_number = db.add_revision(project_id=project_id,
                                             model_file=model_file,
                                             filename=unicode_filename)

    generate_statistics(project_id)

    return jsonify({
        'new_revision_id':
        new_version_number,
        'project_id':
        project_id,
        'return_msg':
        'The new revision numbered %i has successfully been added to the project '
        'with the ID %s' % (new_version_number, project_id)
    }), 201  # Created