docs: 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}