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
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
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
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])
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
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