Ejemplo n.º 1
0
def create_annotation_set(request,cid):
    '''create_annotation_set will allow the user to create a custom annotation set
    (stored as ReportSet) for making annotations.
    :param cid: the collection id to use
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        users = get_collection_annotators(collection)
        allowed_annotations = get_allowed_annotations(collection,return_objects=False)

        # Only allow generation of a set if minimum of 25 reports (for gold standard)
        count = get_annotation_counts(collection)['total']
        if count < GOLD_STANDARD_MIN_ANNOTS:
            messages.info(request,'''You must have a minimum of 25 annotations to create an annotation set. 
                                     A collection owner or contributor can annotate random reports to generate 
                                     this gold standard.''')
            return HttpResponseRedirect(collection.get_absolute_url())


        context = {"users": users,
                   "collection": collection,
                   "allowed_annotations": allowed_annotations}
        return render(request, "reports/create_annotation_set.html", context)

    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 2
0
def save_annotation_session(request,cid):
    '''save_annotation_session will save the annotation set, meaning creation of 
    a session with the queryset. (not in use)
    :param cid: the collection id to use
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        if request.method == "POST":

            # What user does the request want to see annotations by?
            user_id = request.POST.get('user')
            user = get_user(request,user_id)

            # What annotation (name and label) do we filter to?
            selection_keys = [x for x in request.POST.keys() if re.search("^whatisit[||]", x)]
            selections = []
            seen_annotations = []
            for selection_key in selection_keys:
                name,label = selection_key.replace("whatisit||","").split("||")
                annotation_object = AllowedAnnotation.objects.get(name=name,
                                                                      label=label)

                # Query to select the reports of interest
                selection = Annotation.objects.filter(annotator=user,
                                                      annotation=annotation_object,
                                                      reports__collection=collection)
                for annotation in selection:
                    if annotation not in seen_annotations:
                        selections = list(chain(selections,annotation.reports.all()))
                        seen_annotations.append(annotation)

            request.session['reports'] = selections
            return annotate_session(request,cid)

    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 3
0
def annotate_session(request,cid):
    '''annotate_custom will allow the user to annotate a custom selected set (saved in a session)
    if not defined, the user is redirected to create one, with a message
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        report_set = request.session.get('reports', None)

        # Undefined session means the user hasn't created a set yet
        if report_set == None:
            messages.info(request, 'You need to create an annotation set first.')   
            return create_annotation_set(request,cid)

        # The user has finished annotating all reports, time to move on.      
        elif len(report_set) == 0:
            return create_annotation_set(request,cid)
      
        # The user has reports left to annotate
        else:
            next_report = report_set.pop(0)
            request.session['reports'] = report_set
            return annotate_report(request,
                                   rid=next_report.id,
                                   report=next_report,
                                   next="set")

    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 4
0
def approve_annotate_permission(request,cid,uid):
    '''a user must first get approved for annotate permission before being
    added to an annotation set
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        requester = get_user(request,uid)
        permission_request = RequestMembership.objects.get(collection=collection,
                                                           requester=requester)
        if permission_request.status not in ["APPROVED","DENIED"]:

            # Update the collection
            collection.annotators.add(requester)
            collection.save()

            # Update the permission request
            permission_request.status = "APPROVED"
            permission_request.save()

            # Send a notification to the user
            message = """Your request to annotate sets in the collection %s 
                         has been approved!""" %(collection.name)
            notify.send(collection.owner, recipient=requester, verb=message)
            messages.success(request, 'Annotators approved.')
    
    return view_report_collection(request,cid)
Ejemplo n.º 5
0
def bulk_annotate(request,cid,sid=None):
    '''bulk annotate will allow a user to apply annotations, in masse, to a collection or set
    :param cid: the collection id to use
    :param sid: the report set id, if a subset of reports is being used
    '''
    if sid !=None:
        report_set = get_report_set(sid)
        collection = report_set.collection
        reports = report_set.reports.all()
    else:
        collection = get_report_collection(cid)
        reports = collection.report_set.all()
   
    if has_collection_edit_permission(request,collection):

        # POST indicates creating a bulk annotation
        if request.method == "POST":

            # Does the user want to bulk annotate only unlabeled sets?
            unlabeled_only = request.POST.get('unlabeled_only',None)

            # What annotations does the user want to do in bulk?
            selection_keys = [x for x in request.POST.keys() if re.search("^whatisit[||]", x)]
            selections = []
            seen_annotations = []
            for selection_key in selection_keys:
                name = selection_key.replace("whatisit||","")
                label = request.POST.get(selection_key,"")
                if label != "":
                    
                    allowed_annotation = AllowedAnnotation.objects.get(name=name,
                                                                       label=label)

                    # If the user doesn't want to include already labeled reports, exclude
                    if unlabeled_only != None:
                        reports = reports.exclude(reports_annotated__annotator=request.user).distinct()

                    for report in reports:
                        # Update user annotation sent to celery to run async
                        update_user_annotation.apply_async(kwargs={'user':request.user.id, 
                                                                   'allowed_annotation':allowed_annotation.id,
                                                                   'report':report.id})

                    messages.info(request,"Annotation %s:%s task running for %s reports" %(name,label,reports.count()))
        
                return view_report_collection(request,cid)

        # Otherwise just render the form
        else:

            allowed_annotations = get_allowed_annotations(collection,return_objects=False)

            context = {"collection": collection,
                       "allowed_annotations": allowed_annotations}

            if sid != None:
                context['sid'] = sid

            return render(request, "annotate/bulk_annotate.html", context)
    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 6
0
def save_annotation_set(request,cid):
    '''save_annotation_set will save the annotation set, meaning creation of 
    a ReportSet with the queryset.
    :param cid: the collection id to use
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        if request.method == "POST":
            
            # What does the user want to name the set?
            set_name = request.POST.get('setname').lower().replace(" ","_")

            # What user should be used as gold standard?
            gold_standard = request.POST.get('gold_standard')

            # How many reports in the set?
            request,N = parse_numeric_input(request=request,
                                            value=request.POST.get('N'),
                                            default=100,
                                            description="the number of reports")
            
            # How many tests should be given and passing?
            request,testing_set = parse_numeric_input(request=request,
                                                      value=request.POST.get('testing_set'),
                                                      default=25,
                                                      description="the number of testing reports")

            request,testing_set_correct = parse_numeric_input(request=request,
                                                              value=request.POST.get('testing_set_correct'),
                                                              default=20,
                                                              description="the number reports correct to pass")

            # Required number correct must be less than total
            if testing_set_correct > testing_set:
                messages.info(request,"The required number of passing questions must be less than or equal to the number of testing questions.")
                return create_annotation_set(request,cid)

            # What users does the request want to see annotations by?
            user_id = request.POST.get('user')
            if user_id == 'all':
                user = [u.id for u in get_collection_users(collection)]
            else:
                user = [get_user(request,user_id).id]

            # What annotation (name and label) do we filter to?
            selection_keys = [x for x in request.POST.keys() if re.search("^whatisit[||]", x)]
            generate_annotation_set.apply_async(kwargs={'uid':request.user.id,
                                                        'user_ids':user,
                                                        'selection_keys':selection_keys,
                                                        'cid':collection.id,
                                                        'N':N,
                                                        'testing_set':testing_set,
                                                        'testing_set_correct':testing_set_correct,
                                                        'gid':gold_standard,
                                                        'set_name':set_name})

            messages.info(request,"""Your set is being created. It's status will be sent via notification. Once it is created, you should add annotators to it.""")

    return redirect('report_collection_details',cid=collection.id)
Ejemplo n.º 7
0
def summarize_reports(request,cid):
    collection = get_report_collection(cid)
    # Get a count of annotations by label in the collection
    annotation_counts = get_annotation_counts(collection)
    report_count = Report.objects.filter(collection=collection).count()
    context = {"collection":collection,
               "annotation_counts":annotation_counts,
               "report_count":report_count}
    return render(request, 'reports/report_collection_summary.html', context)
Ejemplo n.º 8
0
def create_label(request,cid,lid=None):
    '''create_label will allow a user to create a new label to be associated with a collection. The user
    will be able to select from other collection labels
    :param cid: the collection id to associate the label with (not required, but no url accessible for it) 
    :param lid: if provided on a post, the label will be added to the collection as an allowed annotation
    '''
    collection = get_report_collection(cid)

    if request.user == collection.owner:

        if request.method == "POST":

            # If lid is defined, we are adding an already existing annotation label to collection
            if lid != None:
                try:
                    allowed_annotation = AllowedAnnotation.objects.get(id=lid)
                    collection.allowed_annotations.add(allowed_annotation)
                    collection.save()
                    label_name = "%s:%s" %(allowed_annotation.name,
                                           allowed_annotation.label)
                    response_text = {"result": "New annotation label %s added successfully." %(label_name)}

                except BaseException as e:
                    response_text = {"error": "Error retrieving allowed annotation %s, %s" %(lid,e.message)}

            # Otherwise, the user wants a new one
            else:

                name = request.POST.get('annotation_name', None)
                if name != None:
                    for key in request.POST.keys():
                        if re.search('annotation_label',key):
                            new_label = request.POST.get(key)
                            allowed_annot,created = AllowedAnnotation.objects.get_or_create(name=name,
                                                                                         label=new_label)                       
                            if created == True:
                                allowed_annot.save()
                            collection.allowed_annotations.add(allowed_annot)

                    messages.info(request,"Label generation successful.")
                else:
                    messages.info(request,"An annotation name is required.")
                
                return view_label(request,cid)

        else:

            return view_label(request,cid)

        return JsonResponse(response_text)

    else:
        # Does not have permission, return to collection
        messages.info(request, "You do not have permission to perform this action.")
    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 9
0
def save_collection_markup(request,cid):
    collection = get_report_collection(cid)
    edit_permission = has_collection_edit_permission(request,collection)
    if request.method == "POST":
        if edit_permission:
            markup = request.POST.get('markup',None)
            if markup:
                collection.markup = markup
                collection.save()
                messages.success(request, 'Collection markup saved.')

    return view_report_collection(request,cid)
Ejemplo n.º 10
0
def request_annotate_permission(request,cid):    
    '''request_annotate_permission will allow a user to request addition to
    a collection (as an annotator) via a RequestMembership object. This does not
    give full access to annotate, they must then be added to specific annotation sets
    '''
    collection = get_report_collection(cid)
    previous_request,created = RequestMembership.objects.get_or_create(requester=request.user,
                                                                       collection=collection)
    if created == True:
        previous_request.save()

    # redirect back to collection with message
    messages.success(request, 'Request sent.')
    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 11
0
def remove_contributor(request,cid,uid):
    '''remove a contributor from a collection
    :param cid: the collection id
    :param uid: the contributor (user) id
    '''
    collection = get_report_collection(cid)
    user = get_user(request,uid)
    contributors = collection.contributors.all()
    if request.user == collection.owner:
        if user in contributors:    
            collection.contributors = [x for x in contributors if x != user]
            collection.save()
            messages.success(request, 'User %s is no longer a contributor to the collection.' %(contributor))

    return edit_contributors(request,cid)
Ejemplo n.º 12
0
def view_label(request,cid,template=None):
    '''view_label is a general template to return a view of labels
    '''
    collection = get_report_collection(cid)
    if template==None:
        template = 'labels/new_collection_label.html'

    # Labels associated with collection
    collection_labels = collection.allowed_annotations.all()
    labels = [x for x in AllowedAnnotation.objects.all() if x not in collection_labels]

    context = {'labels':labels,
               'collection':collection,
               'collection_labels':collection_labels}

    # send back json response success
    return render(request, template, context)
Ejemplo n.º 13
0
def add_contributor(request,cid):
    '''add a new contributor to a collection
    :param cid: the collection id
    '''
    collection = get_report_collection(cid)
    if request.user == collection.owner:
        if request.method == "POST":
            user_id = request.POST.get('user',None)
            if user_id:
                user = get_user(request,user_id)
                collection.contributors.add(user)
                collection.save()

                # Alert the user of the status change
                message = """You have been added as a contributor to the %s.""" %(collection.name)
                notify.send(collection.owner, recipient=user, verb=message)

                messages.success(request, 'User %s added as contributor to collection.' %(user))

    return edit_contributors(request,cid)
Ejemplo n.º 14
0
def annotate_testing(request,cid,rid=None,sid=None,reports=None):
    '''annotate_testing will select a random record from a collection, and render a page for
    the user to annotate
    :param cid: the collection id to select from
    :param rid: a report id, if provided, to annotate
    :param sid: the set id of a report, if provided, will be sent in with the next url param
    :param reports: a pre selected subset to select randomly from
    '''
    collection = get_report_collection(cid)
    if reports == None:
        reports = Report.objects.filter(collection=collection)

    # Get a random report (if gets slow, change to get_random_report
    report = select_random_reports(reports)[0]

    # Ensure url returned is for report
    if sid != None:
        return HttpResponseRedirect(reverse('annotate_report_testing',  kwargs={'rid': report.id,
                                                                                'sid': sid}))
    return HttpResponseRedirect(reverse('annotate_report_testing',  kwargs={'rid': report.id}))
Ejemplo n.º 15
0
def create_annotation_session(request,cid):
    '''create_annotation_session will allow the user to create a custom annotation set
    (stored in a session) for making annotations. (not currently in use)
    :param cid: the collection id to use
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        report_set = request.session.get('reports', None) 
        if report_set != None:
            if len(report_set) != 0:
                messages.warning(request, 'You have an annotation session in progress. Creating a new set will override it.')

        # Get collection annotators
        users = get_collection_users(collection)

        allowed_annotations = get_allowed_annotations(collection,return_objects=False)
        context = {"users": users,
                   "collection": collection,
                   "allowed_annotations": allowed_annotations}
        return render(request, "reports/create_annotation_set_local.html", context)
    return HttpResponseRedirect(collection.get_absolute_url())
Ejemplo n.º 16
0
def deny_annotate_permission(request,cid,uid):
    '''a user can be denied annotate permission at the onset (being asked) or
    have it taken away, given asking --> pending --> does not pass test
    '''
    collection = get_report_collection(cid)
    if has_collection_edit_permission(request,collection):
        requester = get_user(request,uid)
        permission_request = RequestMembership.objects.get(collection=collection,
                                                           requester=requester)
        if permission_request.status != "DENIED":
            permission_request.status = "DENIED"
            permission_request.save()

            # Send a notification to the user
            message = """Your request to annotate sets in the collection %s 
                         has been denied""" %(collection.name)
            notify.send(collection.owner, recipient=requester, verb=message)


            messages.success(request, 'Annotators updated.')    
    return view_report_collection(request,cid)
Ejemplo n.º 17
0
def download_data(request, cid):
    '''download data returns a general view for a collection to download data,
    meaning all reports, reports for a set, or annotations for a set
    :param cid: the collection id
    '''
    collection = get_report_collection(cid)

    # Does the user have permission to edit?
    requester = request.user
    if requester == collection.owner or requester in collection.contributors.all(
    ):
        context = {
            "collection": collection,
            "annotators": get_collection_annotators(collection),
            "report_sets": ReportSet.objects.filter(collection=collection)
        }
        return render(request, 'export/download_data.html', context)

    messages.info(request,
                  "You do not have permission to perform this action.")
    return redirect('report_collection_details', cid=collection.id)
Ejemplo n.º 18
0
def edit_contributors(request,cid):
    '''edit_contributors is the view to see, add, and delete contributors for a set.
    '''
    collection = get_report_collection(cid)
    if request.user == collection.owner:

        # Who are current contributors?
        contributors = collection.contributors.all()

        # Any user that isn't the owner or already a contributor can be added
        invalid_users = [x.id for x in contributors] + [request.user.id]
        contenders = [x for x in User.objects.all() if x.username != 'AnonymousUser']
        contenders = [x for x in contenders if x.id not in invalid_users]

        context = {'contributors':contributors,
                   'collection':collection,
                   'contenders':contenders}
        
        return render(request, 'reports/edit_collection_contributors.html', context)

    # Does not have permission, return to collection
    messages.info(request, "You do not have permission to perform this action.")
    return view_report_collection(request,cid)
Ejemplo n.º 19
0
def view_report_collection(request,cid):
    collection = get_report_collection(cid)
    report_count = collection.report_set.count()
    annotation_count = count_user_annotations(collection.annotators.all())
    context = {"collection":collection,
               "report_count":report_count,
               "annotation_count":annotation_count}

    # Get all permissions, context must have collection as key
    context = get_permissions(request,context)

    # If the user has edit_permissions, we want to show him/her users that can be added
    if context["edit_permission"] == True:
        context["requesters"] = RequestMembership.objects.filter(collection=collection)
        context["requesters_pending"] = len([x for x in context["requesters"] if x.status == "PENDING"])

    # Show report Sets allowed to annotate
    context["report_sets"] = ReportSet.objects.filter(annotators__in=[request.user],
                                                      collection=collection)
    context['report_set_testers'] = get_user_report_sets(collection,
                                                         user=request.user) # status="TESTING"

    return render(request, 'reports/report_collection_details.html', context)
Ejemplo n.º 20
0
def edit_report_collection(request, cid=None):

    if cid:
        collection = get_report_collection(cid)
    else:
        collection = ReportCollection(owner=request.user)
        if has_collection_edit_permission(request,collection):

            if request.method == "POST":
                form = ReportCollectionForm(request.POST,instance=collection)
                if form.is_valid():
 
                    # Update annotators and contributors
                    previous_contribs = set()
                    previous_annots = set()
                    if form.instance.id is not None:
                        previous_contribs = set(form.instance.contributors.all())
                        previous_annots = set(form.instance.annotators.all())

                    collection = form.save(commit=False)
                    collection.save()

                    form.save_m2m()  # save contributors

                return HttpResponseRedirect(collection.get_absolute_url())
        else:
            form = ReportCollectionForm(instance=collection)

        edit_permission = has_collection_edit_permission(request,collection)
        context = {"form": form,
                   "edit_oermission": edit_permission}

        return render(request, "reports/edit_report_collection.html", context)

    # If user makes it down here, does not have permission
    messages.info(request, "You don't have permission to edit this collection.")
    return redirect("report_collections")
Ejemplo n.º 21
0
def download_reports(request, cid, sid=None, return_json=False):
    '''download reports returns a tsv download for an entire collection of reports (not recommended)
    or for reports within a collection (recommended)
    :param cid: the collection id
    :param sid: the report set if, if provided use that report set.
    :param return_json: return a Json response instead (default is False)
    '''
    if sid != None:
        report_set = get_report_set(sid)
        collection = report_set.collection
        reports = report_set.reports.all()
        export_name = "%s_reports_set.tsv" % (report_set.id)
    else:
        collection = get_report_collection(cid)
        reports = collection.report_set.all()
        export_name = "%s_reports.tsv" % (collection.id)

    # Does the user have permission to edit?
    requester = request.user
    if requester == collection.owner or requester in collection.contributors.all(
    ):
        df = pandas.DataFrame(columns=["report_id", "report_text"])
        df["report_id"] = [r.report_id for r in reports]
        df["report_text"] = [r.report_text for r in reports]
        if not return_json:
            response = HttpResponse(df.to_csv(sep="\t"),
                                    content_type='text/csv')
            response['Content-Disposition'] = 'attachment; filename="%s"' % (
                export_name)
            return response
        else:
            return JsonResponse(df.to_json(orient="records"))

    messages.info(request,
                  "You do not have permission to perform this action.")
    return redirect('report_collection_details', cid=collection.id)
Ejemplo n.º 22
0
def generate_annotation_set(uid,user_ids,selection_keys,cid,N,testing_set,testing_set_correct,set_name,gid):
    '''generate annotation set is a task to select reports and generate an annotation set.
    If failed, will send a message to the user
    :param uid: the user id requesting, in case failed
    :param users: the (list, one or more) of user ids to include
    :param selection_keys: the list of selection keys
    :param cid: the id of the collection to generate a set for
    :param N: the number to include in the report set
    :param testing_set: the number to include in the testing set
    :param testing_set_correct: the total correct
    :param set_name: the name for the new report set
    :param gid: the unique id for the gold standard user
    '''
    collection = get_report_collection(cid)

    # Try to get requester and gold standard annotator users
    try:
        requester = User.objects.get(id=uid)
        gold_standard = User.objects.get(id=gid)
    except:
        raise

    user = []
    for uid in user_ids:
        try:     
            add_user = User.objects.get(id=uid)
            user.append(add_user)
        except:
            pass

    if requester in collection.contributors.all() or requester == collection.owner:
        selections = []
        seen_annotations = []
        allowed_annotations = []
        for selection_key in selection_keys:
            name,label = selection_key.replace("whatisit||","").split("||")
            annotation_object = AllowedAnnotation.objects.get(name=name,
                                                              label=label)
            # We save the allowed annotation as a label to use for testing
            allowed_annotations.append(annotation_object)

            # Query to select the reports of interest
            selection = Annotation.objects.filter(annotator__in=user,
                                                  annotation=annotation_object,
                                                  reports__collection=collection)

            for annotation in selection:
                if annotation not in seen_annotations:
                    selections = list(chain(selections,annotation.reports.filter(collection=collection)))
                    seen_annotations.append(annotation)

        # Remove reports that are already in sets
        existing = []
        existing_sets = ReportSet.objects.filter(collection=collection)
        for existing_set in existing_sets:
            existing = list(chain(existing,existing_set.reports.all()))
        selections = [report for report in selections if report not in existing]

        # If we have fewer selections left than options, no go
        if len(selections) < N:
            message = """You requested a new report set with %s reports for the %s collection. 
                         There are %s reports (not in a set) that match this criteria, and so we cannot
                         create new set.""" %(N,collection.name,len(selections))
            notify.send(requester, recipient=requester, verb=message)
            return False

        # Otherwise, save the new report set
        selections = selections[0:N]
        report_set = ReportSet.objects.create(collection=collection,
                                              number_tests=testing_set,
                                              number_reports=N,
                                              name=set_name,
                                              passing_tests=testing_set_correct,
                                              gold_standard=gold_standard)
        report_set.save()

        # Set creator should be allowed to see it
        report_set.annotators.add(requester)            
        report_set.reports = selections
        report_set.testing_annotations = allowed_annotations
        report_set.save()   

        # If we are successful, return a message to tell the admin to add annotators.
        add_annotators_link = "/collections/%s/sets/annotators" %(report_set.id)
        message = """Report set %s (N=%s reports) for the %s collection 
                     has been successfully created.""" %(set_name,N,collection.name)
        notify.send(requester, recipient=requester, verb=message)
Ejemplo n.º 23
0
def upload_reports(request,cid):
    '''upload_reports to a collection (currently not implemented)
    '''
    collection = get_report_collection(cid)
    messages.info(request,"Upload of reports in the interface is not currently supported.")    
    return view_report_collection(request,cid)