def del_calc(db, job_id, user):
    """
    Delete a calculation and all associated outputs, if possible.

    :param db: a :class:`openquake.server.dbapi.Db` instance
    :param job_id: job ID, can be an integer or a string
    :param user: username
    :returns: None if everything went fine or an error message
    """
    job_id = int(job_id)
    dependent = db(
        'SELECT id FROM job WHERE hazard_calculation_id=?x', job_id)
    if dependent:
        return {"error": 'Cannot delete calculation %d: there '
                'are calculations '
                'dependent from it: %s' % (job_id, [j.id for j in dependent])}
    try:
        owner, path = db('SELECT user_name, ds_calc_dir FROM job WHERE id=?x',
                         job_id, one=True)
    except NotFound:
        return {"error": 'Cannot delete calculation %d:'
                ' ID does not exist' % job_id}

    deleted = db('DELETE FROM job WHERE id=?x AND user_name=?x',
                 job_id, user).rowcount
    if not deleted:
        return {"error": 'Cannot delete calculation %d: it belongs to '
                '%s and you are %s' % (job_id, owner, user)}

    # try to delete datastore and associated file
    # path has typically the form /home/user/oqdata/calc_XXX
    fname = path + ".hdf5"
    try:
        os.remove(fname)
    except OSError as exc:  # permission error
        return {"error": 'Could not remove %s: %s' % (fname, exc)}
    return {"success": fname}
Delete a calculation and all associated outputs, if possible.

    :param db: a :class:`openquake.server.dbapi.Db` instance
    :param job_id: job ID, can be an integer or a string
    :param user: username
    :returns: None if everything went fine or an error message