Esempio n. 1
0
def create_project(request):
    """Create a new project.

    HTTP POST
        Request body - should contain json params:
            name: Project name
            description: Project description

        Response body - will be json with the following structure, representing the created project:
            {
                'projectsByGuid':  { <projectGuid1> : { ... <project key-value pairs> ... } }
            }

    """

    request_json = json.loads(request.body)
    if 'form' not in request_json:
        return create_json_response(
            {},
            status=400,
            reason="Invalid request: 'form' not in request_json")

    form_data = request_json['form']

    name = form_data.get('name')
    if not name:
        return create_json_response({},
                                    status=400,
                                    reason="'Name' cannot be blank")

    description = form_data.get('description')

    project = Project.objects.create(created_by=request.user,
                                     name=name,
                                     description=description)

    # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
    try:
        base_project, created = BaseProject.objects.get_or_create(
            project_id=_slugify(name))
        if created:
            print("Created project %s" % base_project)
        base_project.project_name = name
        base_project.description = description
        base_project.save()

        project.deprecated_project_id = base_project.project_id
        project.save()
    except:
        raise

    projects_by_guid = {
        project.guid: _get_json_for_project(project, request.user)
    }

    return create_json_response({
        'projectsByGuid': projects_by_guid,
    })
Esempio n. 2
0
def login_required_error(request):
    """Returns an HttpResponse with a 401 UNAUTHORIZED error message.

    This is used to redirect AJAX HTTP handlers to the login page.
    """
    assert not request.user.is_authenticated()

    return create_json_response({}, status=401, reason="login required")
Esempio n. 3
0
def case_review_page_data(request, project_guid):
    """Returns a JSON object containing information used by the case review page:
    ::

      json_response = {
         'user': {..},
         'project': {..},
         'familiesByGuid': {..},
         'individualsByGuid': {..},
         'familyGuidToIndivGuids': {..},
       }
    Args:
        project_guid (string): GUID of the project being case-reviewed.
    """

    # get all families in this project
    project = Project.objects.filter(guid=project_guid)
    if not project:
        raise ValueError("Invalid project id: %s" % project_guid)

    project = project[0]
    json_response = {
        'user': _get_json_for_user(request.user),
        'project': _get_json_for_project(project, request.user),
        'familiesByGuid': {},
        'individualsByGuid': {},
        'familyGuidToIndivGuids': {},
    }

    for i in Individual.objects.filter(family__project=project).select_related('family'):

        # filter out individuals that were never in case review (or where case review status is set to -- )
        if not i.case_review_status:
            continue

        # process family record if it hasn't been added already
        family = i.family
        if str(family.guid) not in json_response['familiesByGuid']:
            json_response['familiesByGuid'][family.guid] = _get_json_for_family(family)
            json_response['familyGuidToIndivGuids'][family.guid] = []

        json_response['familyGuidToIndivGuids'][family.guid].append(i.guid)
        json_response['individualsByGuid'][i.guid] = _get_json_for_individual(i)

    return create_json_response(json_response)
Esempio n. 4
0
def awesomebar_autocomplete(request):
    """Accepts HTTP GET request with q=.. url arg, and returns suggestions"""

    query = request.GET.get('q', None)

    results = {}
    if len(query) > 0:
        projects = _get_matching_projects(request.user, query)
        if projects:
            results['projects'] = {'name': 'Projects', 'results': projects}

        families = _get_matching_families(request.user, query)
        if families:
            results['families'] = {'name': 'Families', 'results': families}

        genes = _get_matching_genes(request.user, query)
        if genes:
            results['genes'] = {'name': 'Genes', 'results': genes}

    #from pprint import pprint
    #pprint(results)
    return create_json_response({'matches': results})
Esempio n. 5
0
def delete_project(request, project_guid):
    """Update project metadata - including one or more of these fields: name, description

    Args:
        project_guid (string): GUID of the project that should be updated

    HTTP POST
        Response body - will be json with the delete projectGuid mapped to the special 'DELETE' keyword:
            {
                'projectsByGuid':  { <projectGuid1> : 'DELETE' }
            }

    """

    project = Project.objects.get(guid=project_guid)

    # check permissions
    if not request.user.has_perm(IS_OWNER,
                                 project) and not request.user.is_staff:
        raise PermissionDenied

    project.delete()

    # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
    try:
        base_project = BaseProject.objects.filter(
            project_id=project.deprecated_project_id)
        if base_project:
            base_project = base_project[0]
            base_project.delete()
    except:
        raise

    # TODO delete Family, Individual, and other objects under this project
    return create_json_response({
        'projectsByGuid': {
            project.guid: 'DELETE'
        },
    })
Esempio n. 6
0
def save_internal_case_review_summary(request, project_guid, family_guid):
    """Updates the `internal_case_review_summary` field for the given family.

    Args:
        project_guid (string): GUID of the project.
        family_guid  (string): GUID of the family.
    """

    family = Family.objects.get(guid=family_guid)
    requestJSON = json.loads(request.body)

    family.internal_case_review_brief_summary = requestJSON['form']
    family.save()

    # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
    try:
        base_f = BaseFamily.objects.get(project__project_id=family.project.deprecated_project_id, family_id=family.family_id)
        base_f.internal_case_review_brief_summary = requestJSON['form']
        base_f.save()
    except:
        raise

    return create_json_response({family.guid: _get_json_for_family(family)})
Esempio n. 7
0
def save_case_review_status(request, project_guid):
    """Updates the `case_review_status`, with initial case_review_page_data json embedded.

    Args:
        project_guid (string): GUID of the Project under case review.
    """

    project = Project.objects.get(guid=project_guid)

    # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
    base_project = BaseProject.objects.filter(project_id=project.deprecated_project_id)
    if base_project:
        base_project = base_project[0]

    requestJSON = json.loads(request.body)
    responseJSON = {}
    for individual_guid, new_case_review_status in requestJSON['form'].items():
        i = Individual.objects.get(family__project=project, guid=individual_guid)
        if i.case_review_status == new_case_review_status:
            continue
        i.case_review_status = new_case_review_status
        i.case_review_status_last_modified_by = request.user
        i.case_review_status_last_modified_date = timezone.now()
        i.save()

        responseJSON[i.guid] = _get_json_for_individual(i)

        # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
        try:
            if base_project:
                base_i = BaseIndividual.objects.get(family__project=base_project, indiv_id=i.individual_id)
                base_i.case_review_status = new_case_review_status
                base_i.save()
        except:
            raise

    return create_json_response(responseJSON)
Esempio n. 8
0
def update_project(request, project_guid):
    """Update project metadata - including one or more of these fields: name, description

    Args:
        project_guid (string): GUID of the project that should be updated

    HTTP POST
        Request body - should contain one or more json params:
            name: Project name
            description: Project description

        Response body - will be json with the following structure, representing the updated project:
            {
                'projectsByGuid':  { <projectGuid1> : { ... <project key-value pairs> ... } }
            }

    """

    project = Project.objects.get(guid=project_guid)

    # check permissions
    if not request.user.has_perm(CAN_EDIT,
                                 project) and not request.user.is_staff:
        raise PermissionDenied

    request_json = json.loads(request.body)
    if 'form' not in request_json:
        return create_json_response(
            {},
            status=400,
            reason="Invalid request: 'form' not in request_json")

    form_data = request_json['form']

    if 'name' in form_data:
        project.name = form_data.get('name')
        project.save()
    elif 'description' in form_data:
        project.description = form_data.get('description')
        project.save()

    # keep new seqr.Project model in sync with existing xbrowse_server.base.models - TODO remove this code after transition to new schema is finished
    try:
        base_project = BaseProject.objects.filter(
            project_id=project.deprecated_project_id)
        if base_project:
            base_project = base_project[0]
            if 'name' in form_data:
                base_project.project_name = form_data.get('name')
                base_project.save()
            elif 'description' in form_data:
                base_project.description = form_data.get('description')
                base_project.save()
    except:
        raise

    projects_by_guid = {
        project.guid: _get_json_for_project(project, request.user)
    }

    return create_json_response({
        'projectsByGuid': projects_by_guid,
    })
Esempio n. 9
0
def update_project_categories(request, project_guid):
    """Update ProjectCategories for the given project.

    Args:
        project_guid (string): GUID of the project that should be updated

    HTTP POST
        Request body - should contain one or more json params:
            categories: a list of category GUIDs for the categories assigned to the given project

        Response body - will be json with the following structure, representing the updated project,
            as well all categories in seqr:
            {
                'projectsByGuid':  {
                    <projectGuid1> : { ... <project key-value pairs> ... }
                }
                'projectCategoriesByGuid':  {
                    <projectCategoryGuid1> : { ... <category key-value pairs> ... }
                    <projectCategoryGuid2> : { ... <category key-value pairs> ... }
                }
            }
    """
    project = Project.objects.get(guid=project_guid)

    # check permissions
    if not request.user.has_perm(CAN_EDIT,
                                 project) and not request.user.is_staff:
        raise PermissionDenied

    request_json = json.loads(request.body)

    if 'form' not in request_json:
        return create_json_response(
            {},
            status=400,
            reason="Invalid request: 'form' not in request_json")

    form_data = request_json['form']

    # categories currently assigned to this project
    current_categories = set(form_data['categories'])

    # remove ProjectCategory mappings for categories the user wants to remove from this project
    project_categories_already_assigned = set()
    for project_category in project.projectcategory_set.all():
        if project_category.guid not in current_categories:
            project_category.projects.remove(project)
            if project_category.projects.count() == 0:
                project_category.delete()
        else:
            # also record the project_category guids for which there's already a ProjectCategory
            # object mapped to this project and doesn't need to be added or removed
            project_categories_already_assigned.add(project_category.guid)

    # add mappings for ProjectCategory objects that are mapped to other projects, and that the user now wants to add to this project also
    project_categories_to_create = set(current_categories)
    for project_category in ProjectCategory.objects.filter(
            guid__in=current_categories):
        if project_category.guid not in project_categories_already_assigned:
            project_category.projects.add(project)

        project_categories_to_create.remove(project_category.guid)

    # create ProjectCategory objects for new categories, and add mappings for them to this project
    project_categories_by_guid = {}
    for category_name in project_categories_to_create:
        project_category = ProjectCategory.objects.create(
            name=category_name, created_by=request.user)
        project_category.projects.add(project)

        project_categories_by_guid[
            project_category.guid] = project_category.json()

    projects_by_guid = {
        project.guid: _get_json_for_project(project, request.user)
    }

    return create_json_response({
        'projectsByGuid':
        projects_by_guid,
        'projectCategoriesByGuid':
        project_categories_by_guid,
    })
Esempio n. 10
0
def dashboard_page_data(request):
    """Returns a JSON object containing information used by the case review page:
    ::

      json_response = {
         'user': {..},
         'familiesByGuid': {..},
         'individualsByGuid': {..},
         'familyGuidToIndivGuids': {..},
       }
    Args:
        project_guid (string): GUID of the Project under case review.
    """

    # get all projects this user has permissions to view
    if request.user.is_staff:
        projects = projects_user_can_edit = Project.objects.all()
        projects_WHERE_clause = ''
    else:
        projects = Project.objects.filter(can_view_group__user=request.user)
        projects_WHERE_clause = 'WHERE p.guid in (%s)' % (','.join(
            "'%s'" % p.guid for p in projects))
        projects_user_can_edit = Project.objects.filter(
            can_edit_group__user=request.user)

    # use raw SQL to avoid making N+1 queries.
    num_families_subquery = """
      SELECT count(*) FROM seqr_family
        WHERE project_id=p.id
    """.strip()

    num_variant_tags_subquery = """
      SELECT count(*) FROM seqr_varianttag AS v
        JOIN seqr_varianttagtype AS t ON v.variant_tag_type_id=t.id
        WHERE project_id=p.id
    """.strip()

    num_individuals_subquery = """
      SELECT count(*) FROM seqr_individual AS i
        JOIN seqr_family AS f ON i.family_id=f.id
        WHERE f.project_id=p.id
    """.strip()

    projects_query = """
      SELECT
        guid AS project_guid,
        p.name AS name,
        description,
        deprecated_project_id,
        created_date,
        deprecated_last_accessed_date,
        (%(num_variant_tags_subquery)s) AS num_variant_tags,
        (%(num_families_subquery)s) AS num_families,
        (%(num_individuals_subquery)s) AS num_individuals
      FROM seqr_project AS p
      %(projects_WHERE_clause)s
    """.strip() % locals()

    cursor = connection.cursor()
    cursor.execute(projects_query)

    key_map = {'deprecated_last_accessed_date': 'last_accessed_date'}
    columns = [
        _to_camel_case(_remap_key(col[0], key_map))
        for col in cursor.description
    ]

    projects_by_guid = {
        r['projectGuid']: r
        for r in (dict(zip(columns, row)) for row in cursor.fetchall())
    }

    # retrieve solve counts for each project
    ANALYSIS_STATUS_CATEGORIES = {
        'S': 'Solved',
        'S_kgfp': 'Solved',
        'S_kgdp': 'solved',
        'S_ng': 'Solved',
        'Sc_kgfp': 'Strong candidate',
        'Sc_kgdp': 'Strong candidate',
        'Sc_ng': 'Strong candidate',
        'Rncc': 'Reviewed, no candidate',
        'Rcpc': 'Analysis in progress',
        'I': 'Analysis in progress',
        'Q': 'Waiting for data',
    }

    analysis_status_query = """
      SELECT
        p.guid AS project_guid,
        f.analysis_status AS analysis_status,
        count(*) as analysis_status_count
      FROM seqr_family AS f
      JOIN seqr_project AS p
       ON f.project_id = p.id
      GROUP BY p.guid, f.analysis_status
    """.strip() % locals()

    cursor.execute(analysis_status_query)

    columns = [col[0] for col in cursor.description]
    for row in cursor.fetchall():
        analysis_status_record = dict(zip(columns, row))
        project_guid = analysis_status_record['project_guid']
        analysis_status_count = analysis_status_record['analysis_status_count']
        analysis_status_category = ANALYSIS_STATUS_CATEGORIES[
            analysis_status_record['analysis_status']]

        if 'analysisStatusCounts' not in projects_by_guid[project_guid]:
            projects_by_guid[project_guid]['analysisStatusCounts'] = {}
        analysis_status_counts_dict = projects_by_guid[project_guid][
            'analysisStatusCounts']

        analysis_status_counts_dict[
            analysis_status_category] = analysis_status_counts_dict.get(
                analysis_status_category, 0) + analysis_status_count

    # retrieve all project categories
    for project_guid in projects_by_guid:
        projects_by_guid[project_guid]['projectCategoryGuids'] = []

    project_categories_by_guid = {}
    for project_category in ProjectCategory.objects.all():
        project_category_guid = project_category.guid

        for p in project_category.projects.all():
            projects_by_guid[p.guid]['projectCategoryGuids'].append(
                project_category_guid)

        project_categories_by_guid[
            project_category_guid] = project_category.json()

    # do a separate query to get details on all datasets in these projects
    num_samples_subquery = """
      SELECT COUNT(*) FROM seqr_sequencingsample AS subquery_s
        WHERE subquery_s.dataset_id=d.id
    """
    datasets_query = """
        SELECT
          p.guid AS project_guid,
          d.guid AS dataset_guid,
          d.id AS dataset_id,
          d.sequencing_type AS sequencing_type,
          d.is_loaded AS is_loaded,
          (%(num_samples_subquery)s) AS num_samples
        FROM seqr_dataset AS d
          JOIN seqr_sequencingsample AS s ON d.id=s.dataset_id
          JOIN seqr_individual_sequencing_samples AS iss ON iss.sequencingsample_id=s.id
          JOIN seqr_individual AS i ON iss.individual_id=i.id
          JOIN seqr_family AS f ON i.family_id=f.id
          JOIN seqr_project AS p ON f.project_id=p.id %(projects_WHERE_clause)s
        GROUP BY p.guid, d.guid, d.id, d.sequencing_type, d.is_loaded
    """.strip() % locals()

    cursor.execute(datasets_query)

    columns = [_to_camel_case(col[0]) for col in cursor.description]
    datasets_by_guid = {}
    for row in cursor.fetchall():
        dataset_project_record = dict(zip(columns, row))
        project_guid = dataset_project_record['projectGuid']
        dataset_guid = dataset_project_record['datasetGuid']
        del dataset_project_record['projectGuid']
        del dataset_project_record['datasetGuid']

        project_record = projects_by_guid[project_guid]
        if 'datasets' not in project_record:
            project_record['datasetGuids'] = []
        project_record['datasetGuids'].append(dataset_guid)

        datasets_by_guid[dataset_guid] = dataset_project_record

    cursor.close()

    # mark all projects where this user has edit permissions
    for project in projects_user_can_edit:
        projects_by_guid[project.guid]['canEdit'] = True

    json_response = {
        'user': _get_json_for_user(request.user),
        'projectsByGuid': projects_by_guid,
        'projectCategoriesByGuid': project_categories_by_guid,
        'datasetsByGuid': datasets_by_guid,
    }

    return create_json_response(json_response)