Example #1
0
def create(request):
    """Creates a collection."""
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(
        collection_ids=course_collections,
        can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket,
                                                **collection_filters)

    if request.method == 'POST':
        lti_req = LTIService(request)
        published = not lti_req.isTeacher()
        request.POST = request.POST.copy()
        request.POST['published'] = published
        collection_form = CollectionForm(request.POST)

        card_template_id = collection_form.data['card_template']
        if collection_form.is_valid():
            collection = collection_form.save()
            lti_req.associateCourse(collection.id)
            services.add_user_to_collection(
                user=request.user,
                collection=collection,
                role=Users_Collections.ADMINISTRATOR)
            #update role_bucket to add admin permission to the user for this newly created collection
            services.get_or_update_role_bucket(
                request, collection.id,
                Users_Collections.role_map[Users_Collections.ADMINISTRATOR])
            log.info('Collection %s created.' % collection.id,
                     extra={'user': request.user})
            analytics.track(actor=request.user,
                            verb=analytics.VERBS.created,
                            object=analytics.OBJECTS.collection,
                            context={"custom": False})
            return redirect(collection)
    else:
        rel_templates = CardTemplate.objects.filter(
            Q(owner__isnull=True) | Q(owner=request.user))
        initial = {'card_template': '1'}
        card_template_id = initial['card_template']
        collection_form = CollectionForm(query_set=rel_templates,
                                         initial=initial)

    # Pre-populate the "preview" of the card template
    # This view is also called via AJAX on the page.
    prev_request = HttpRequest()
    prev_request.method = 'GET'
    prev_request.GET['card_template_id'] = card_template_id
    prev_response = card_template.preview(prev_request)
    card_template_preview_html = prev_response.content

    context = {
        "nav_collections": collection_list,
        "active_collection": None,
        "collection_form": collection_form,
        "card_template_preview_html": card_template_preview_html
    }

    return render(request, 'collections/create.html', context)
Example #2
0
def delete(request, deck_id=None):
    """Deletes a deck."""
    d = {'user': request.user}

    collection_id = queries.getDeckCollectionId(deck_id)
    success = services.delete_deck(deck_id)
    if success:
        log.info('Deck %(d)s deleted from collection %(c)s' % {
            'd': deck_id,
            'c': collection_id
        },
                 extra=d)
    else:
        log.info('Deck %(d)s could not be deleted from collection %(c)s' % {
            'd': deck_id,
            'c': collection_id
        },
                 extra=d)

    response = redirect('collectionIndex', collection_id)
    response['Location'] += '?instructor=edit'

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.deleted,
        object=analytics.OBJECTS.deck,
        context={"deck_id": deck_id},
    )

    return response
Example #3
0
def all_cards(request, collection_id):
    collection_id = int(collection_id)
    decks = queries.getDecksByCollection(collection_ids=[collection_id])
    decks = decks[collection_id]
    current_collection = Collection.objects.get(id=collection_id)

    deck_cards = []
    for deck in decks:
        deck_cards += Decks_Cards.objects.filter(deck=deck).order_by(
            'sort_order').prefetch_related('card__cards_fields_set__field')
    [cards, collection_list, is_quiz_mode, is_deck_admin,
     card_id] = deck_view_helper(request, current_collection, deck_cards)
    context = {
        "collection": current_collection,
        "nav_collections": collection_list,
        "deck": {
            'id': -collection_id,
            'title': 'All Cards'
        },
        "cards": cards,
        "is_quiz_mode": is_quiz_mode,
        "is_deck_admin": is_deck_admin,
        "card_id": card_id,
    }
    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.viewed,
        object=analytics.OBJECTS.deck,
        context={
            "collection_id": collection_id,
            'type': 'All Cards Deck'
        },
    )
    return render(request, "deck_view.html", context)
Example #4
0
def index(request, deck_id=None):
    """Displays the deck of cards for review/quiz."""

    deck = Deck.objects.get(id=deck_id)
    deck_cards = Decks_Cards.objects.filter(deck=deck).order_by(
        'sort_order').prefetch_related('card__cards_fields_set__field')
    current_collection = deck.collection
    [cards, collection_list, is_quiz_mode, is_deck_admin,
     card_id] = deck_view_helper(request, current_collection, deck_cards)

    context = {
        "collection": current_collection,
        "nav_collections": collection_list,
        "deck": deck,
        "cards": cards,
        "is_quiz_mode": is_quiz_mode,
        "is_deck_admin": is_deck_admin,
        "card_id": card_id,
    }

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.viewed,
        object=analytics.OBJECTS.deck,
        context={"deck_id": deck_id},
    )
    return render(request, "deck_view.html", context)
Example #5
0
def add_deck(request, collection_id=None):
    """Adds a deck."""
    deck_title = 'Untitled Deck'
    action = 1
    if request.method == 'POST':
        deck_title_submitted = request.POST.get('deck_title', deck_title)
        deck_title = deck_title_submitted if deck_title_submitted != "" else deck_title
        action = int(request.POST.get('action', action))

    deck = services.create_deck(collection_id=collection_id, deck_title=deck_title)
    log.info('Deck %(d)s added to the collection %(c)s.' %{'d': deck.id, 'c': str(collection_id)}, extra={'user': request.user})
    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.created,
        object=analytics.OBJECTS.deck,
        context={"collection_id": collection_id, "deck_id": deck.id}
    )

    actions = {2: 'deckCreateCard', 3: 'deckUpload'}
    if action  in actions.keys():
        response = redirect(actions[action], deck.id)
        response['Location'] += '?deck_id='+str(deck.id)
        return response
    else:
        return redirect(deck)
Example #6
0
def share_collection(request, collection_id=None):
    """
    Share a collection with users by creating a temporary url for authorized
    users to use in order to add themselves into the collection's authorized
    users list
    """
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_list = queries.getCollectionList(
        role_bucket, collection_ids=course_collections)

    collection = Collection.objects.get(id=collection_id)
    collection_share_form = CollectionShareForm()
    context = {
        'share_form': collection_share_form,
        'nav_collections': collection_list,
        'collection': collection,
    }

    if request.POST:
        collection_share_form = CollectionShareForm(request.POST)
        if collection_share_form.is_valid():
            expired_in = str(collection_share_form.cleaned_data['expired_in'])

            # This creates an array of the share data (collection id and expiration data
            # for the url).  Random data is appended/prepended to "obfuscate" the url.
            # This isn't intended to be secure by any means, just make it harder to guess.
            # The assumption is that a share URL will only grant a user student-level
            # access, so they can't do any damage if they "guess" the URL. If that
            # assumption changes, then this implementation should be revisited to make it
            # more secure and tamper-proof.
            share_data = [collection_id, expired_in]
            share_data.insert(0, utils.generate_random_id(3))
            share_data.append(utils.generate_random_id(3))
            share_key = '!!'.join(share_data)

            # This pads the share key so that the base64 encoded string doesn't include
            # base64 padding, which is typically the equals sign ("=").  The equals sign
            # must be percent encoded as %3D which looks bad.  Since 3 ascii characters (8
            # bits) are encoded with 4 base64 characters (6 bits each) this should ensure
            # that the share_key is always a multiple of 3.
            if (len(share_key) % 3) > 0:
                share_key = share_key + utils.generate_random_id(
                    3 - (len(share_key) % 3))

            secret_share_key = base64.urlsafe_b64encode(
                share_key.encode("ascii", "ignore"))

            context['share_form'] = collection_share_form
            context['secret_share_key'] = secret_share_key
            log.info('URL generated to share collection %s.' % collection_id,
                     extra={'user': request.user})
            analytics.track(actor=request.user,
                            verb=analytics.VERBS.shared,
                            object=analytics.OBJECTS.collection,
                            context={"collection_id": collection_id})
        else:
            context['share_form'] = collection_share_form

    return render(request, 'collections/share.html', context)
Example #7
0
def add_deck(request, collection_id=None):
    """Adds a deck."""
    deck_title = 'Untitled Deck'
    action = 1
    if request.method == 'POST':
        deck_title_submitted = request.POST.get('deck_title', deck_title)
        deck_title = deck_title_submitted if deck_title_submitted != "" else deck_title
        action = int(request.POST.get('action', action))

    deck = services.create_deck(collection_id=collection_id,
                                deck_title=deck_title)
    log.info('Deck %(d)s added to the collection %(c)s.' % {
        'd': deck.id,
        'c': str(collection_id)
    },
             extra={'user': request.user})
    analytics.track(actor=request.user,
                    verb=analytics.VERBS.created,
                    object=analytics.OBJECTS.deck,
                    context={
                        "collection_id": collection_id,
                        "deck_id": deck.id
                    })

    actions = {2: 'deckCreateCard', 3: 'deckUpload'}
    if action in actions.keys():
        response = redirect(actions[action], deck.id)
        response['Location'] += '?deck_id=' + str(deck.id)
        return response
    else:
        return redirect(deck)
Example #8
0
def download_template(request, collection_id=None):
    '''
    Downloads an excel spreadsheet that may be used as a template for uploading
    a deck of cards.
    '''
    collection = Collection.objects.get(id=collection_id)

    response = HttpResponse(content_type='application/vnd.ms-excel')
    response[
        'Content-Disposition'] = 'attachment; filename=flashcards_template.xls'

    file_output = utils.create_deck_template_file(collection.card_template)
    response.write(file_output)
    log.info('Template for the collection %(c)s downloaded by the user.' %
             {'c': str(collection_id)},
             extra={'user': request.user})

    analytics.track(actor=request.user,
                    verb=analytics.VERBS.downloaded,
                    object=analytics.OBJECTS.template,
                    context={
                        "collection_id": collection_id,
                        "custom": False
                    })

    return response
Example #9
0
def index(request, deck_id=None):
    """Displays the deck of cards for review/quiz."""

    deck = Deck.objects.get(id=deck_id)
    deck_cards = Decks_Cards.objects.filter(deck=deck).order_by('sort_order').prefetch_related('card__cards_fields_set__field')
    current_collection = deck.collection
    [cards, collection_list, is_quiz_mode, is_deck_admin, card_id] = deck_view_helper(request, current_collection, deck_cards)

    context = {
        "collection": current_collection,
        "nav_collections": collection_list,
        "deck": deck,
        "cards": cards,
        "is_quiz_mode": is_quiz_mode,
        "is_deck_admin": is_deck_admin,
        "card_id": card_id,
    }

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.viewed,
        object=analytics.OBJECTS.deck,
        context={"deck_id": deck_id},
    )
    return render(request, "deck_view.html", context)
Example #10
0
def all_cards(request, collection_id):
    collection_id = int(collection_id)
    decks = queries.getDecksByCollection(collection_ids = [collection_id])
    decks = decks[collection_id]
    current_collection = Collection.objects.get(id=collection_id)

    deck_cards = []
    for deck in decks:
        deck_cards += Decks_Cards.objects.filter(deck=deck).order_by('sort_order').prefetch_related('card__cards_fields_set__field')
    [cards, collection_list, is_quiz_mode, is_deck_admin, card_id] = deck_view_helper(request, current_collection, deck_cards)
    context = {
        "collection": current_collection,
        "nav_collections": collection_list,
        "deck": {'id': -collection_id, 'title': 'All Cards'},
        "cards": cards,
        "is_quiz_mode": is_quiz_mode,
        "is_deck_admin": is_deck_admin,
        "card_id": card_id,
    }
    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.viewed,
        object=analytics.OBJECTS.deck,
        context={"collection_id": collection_id, 'type': 'All Cards Deck'},
    )
    return render(request, "deck_view.html", context)
Example #11
0
def edit(request):
    """Add/edit card."""
    result = {"success": False}
    card_id = request.POST.get('card_id', '')
    deck_id = request.POST.get('deck_id', '')
    add_another = int(request.POST.get('add_another_val', 0))
    # fetch the fields being edited; new cards must be created from the card template
    if card_id == '':
        deck = Deck.objects.get(id=deck_id)
        card_fields = deck.collection.card_template.fields.all()
    else:
        card = Card.objects.get(id=card_id)
        card_fields = [cfield.field for cfield in card.cards_fields_set.all()]

    for k, v in request.POST.iteritems():
        if k.endswith('_image_url') and v:
            field_name = k.replace('_image_url', '')
            request.FILES[field_name] = services.fetch_image_from_url(v)
        elif k.endswith('_audio_url') and v:
            field_name = k.replace('_audio_url', '')
            request.FILES[field_name] = services.fetch_audio_from_url(v)

    # attempted to validate and save the form data
    card_edit_form = CardEditForm(request.POST,
                                  request.FILES,
                                  card_fields=card_fields)
    if card_edit_form.is_valid():
        card_edit_form.save()
        card = card_edit_form.get_card()
        deck = card_edit_form.get_deck()
        result['success'] = True
        is_all_cards = request.GET.get('is_all_cards', 0)

        if add_another:
            base_url = deck.get_add_card_url()
            goto_url = "{0}?deck_id={1}".format(base_url, deck.id)
        else:
            if int(is_all_cards):
                base_url = deck.collection.get_all_cards_url()
            else:
                base_url = deck.get_absolute_url()
            goto_url = "{0}?card_id={1}".format(base_url, card.id)

        result['data'] = {"card_id": card.id, "card_url": goto_url}
    else:
        card_edit_form.get_card().delete()
        result['errors'] = card_edit_form.errors

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.modified,
        object=analytics.OBJECTS.card,
        context={
            "deck_id": deck_id,
            "card_id": card_id
        },
    )

    return HttpResponse(json.dumps(result), content_type="application/json")
Example #12
0
def edit(request):
    """Add/edit card."""
    result = {"success":False}
    card_id = request.POST.get('card_id', '')
    deck_id = request.POST.get('deck_id', '')
    add_another =  int(request.POST.get('add_another_val', 0))
    # fetch the fields being edited; new cards must be created from the card template
    if card_id == '':
        deck = Deck.objects.get(id=deck_id)
        card_fields = deck.collection.card_template.fields.all()
    else:
        card = Card.objects.get(id=card_id)
        card_fields = [cfield.field for cfield in card.cards_fields_set.all()]

    for k, v in request.POST.iteritems():
        if k.endswith('_image_url') and v:
            field_name = k.replace('_image_url', '')
            request.FILES[field_name] = services.fetch_image_from_url(v)
        elif k.endswith('_audio_url') and v:
            field_name = k.replace('_audio_url', '')
            request.FILES[field_name] = services.fetch_audio_from_url(v)

    # attempted to validate and save the form data
    card_edit_form = CardEditForm(request.POST, request.FILES, card_fields=card_fields)
    if card_edit_form.is_valid():
        card_edit_form.save()
        card = card_edit_form.get_card()
        deck = card_edit_form.get_deck()
        result['success'] = True
        is_all_cards = request.GET.get('is_all_cards', 0)


        if add_another:
            base_url = deck.get_add_card_url()
            goto_url = "{0}?deck_id={1}".format(base_url, deck.id)
        else:
            if int(is_all_cards):
                base_url = deck.collection.get_all_cards_url()
            else:
                base_url = deck.get_absolute_url()
            goto_url = "{0}?card_id={1}".format(base_url, card.id)

        result['data'] = {
            "card_id": card.id,
            "card_url": goto_url
        }
    else:
        card_edit_form.get_card().delete()
        result['errors'] = card_edit_form.errors

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.modified,
        object=analytics.OBJECTS.card,
        context={"deck_id": deck_id, "card_id": card_id},
    )

    return HttpResponse(json.dumps(result), content_type="application/json")
Example #13
0
def share_collection(request, collection_id=None):
    """
    Share a collection with users by creating a temporary url for authorized
    users to use in order to add themselves into the collection's authorized
    users list
    """
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_list = queries.getCollectionList(role_bucket, collection_ids=course_collections)

    collection = Collection.objects.get(id=collection_id)
    collection_share_form = CollectionShareForm()
    context = {
            'share_form': collection_share_form,
            'nav_collections': collection_list,
            'collection': collection,
             }

    if request.POST:
        collection_share_form = CollectionShareForm(request.POST)
        if collection_share_form.is_valid():
            expired_in = str(collection_share_form.cleaned_data['expired_in'])

            # This creates an array of the share data (collection id and expiration data
            # for the url).  Random data is appended/prepended to "obfuscate" the url.
            # This isn't intended to be secure by any means, just make it harder to guess.
            # The assumption is that a share URL will only grant a user student-level
            # access, so they can't do any damage if they "guess" the URL. If that
            # assumption changes, then this implementation should be revisited to make it
            # more secure and tamper-proof.
            share_data = [collection_id, expired_in]
            share_data.insert(0, utils.generate_random_id(3))
            share_data.append(utils.generate_random_id(3))
            share_key = '!!'.join(share_data)

            # This pads the share key so that the base64 encoded string doesn't include
            # base64 padding, which is typically the equals sign ("=").  The equals sign
            # must be percent encoded as %3D which looks bad.  Since 3 ascii characters (8
            # bits) are encoded with 4 base64 characters (6 bits each) this should ensure
            # that the share_key is always a multiple of 3.
            if (len(share_key) % 3) > 0:
                share_key = share_key + utils.generate_random_id(3 - (len(share_key) % 3))

            secret_share_key = base64.urlsafe_b64encode(share_key.encode("ascii", "ignore"))

            context['share_form'] = collection_share_form
            context['secret_share_key'] = secret_share_key
            log.info('URL generated to share collection %s.' %collection_id, extra={'user': request.user})
            analytics.track(
                actor=request.user,
                verb=analytics.VERBS.shared,
                object=analytics.OBJECTS.collection,
                context={"collection_id": collection_id}
            )
        else:
            context['share_form'] = collection_share_form

    return render(request, 'collections/share.html', context)
Example #14
0
def index(request, collection_id=None):
    """Displays a set of collections to the user depending on whether
    or not the collections are private or public and whether or not the
    user has permission."""

    if collection_id is not None:
        collection_id = int(collection_id)

    role_bucket = services.get_or_update_role_bucket(request)
    lti_req = LTIService(request)
    course_collections = lti_req.getCourseCollections()

    is_teacher = lti_req.isTeacher() or queries.is_superuser_or_staff(
        request.user)
    collection_admin_perms = []
    for r in (Users_Collections.ADMINISTRATOR, Users_Collections.INSTRUCTOR):
        role_name = Users_Collections.role_map[r]
        collection_admin_perms.extend(role_bucket[role_name])

    copy_collections = queries.getCopyCollectionList(request.user)
    collection_filters = dict(
        collection_ids=course_collections,
        can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket,
                                                **collection_filters)
    display_collections = queries.groupCollectionsByList(collection_list)

    context = {
        "nav_collections": collection_list,
        "display_collections": display_collections,
        "copy_collections": copy_collections,
        "active_collection": None,
        "user_collection_role": role_bucket,
        "collection_admin_perms": collection_admin_perms,
        "is_teacher": is_teacher,
    }

    if collection_id:
        try:
            cur_collection = Collection.objects.get(id=collection_id)
        except Collection.DoesNotExist:
            raise Http404
        filtered_collection_list = [
            c for c in collection_list if c['id'] == cur_collection.id
        ]
        if len(filtered_collection_list) == 0:
            raise Http404
        context['active_collection'] = filtered_collection_list[0]

    analytics.track(actor=request.user,
                    verb=analytics.VERBS.viewed,
                    object=analytics.OBJECTS.collection,
                    context={"collection_id": collection_id})

    return render(request, 'collections/index.html', context)
Example #15
0
def create(request):
    """Creates a collection."""
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(collection_ids=course_collections, can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket, **collection_filters)

    if request.method == 'POST':
        lti_req = LTIService(request)
        published = not lti_req.isTeacher()
        request.POST = request.POST.copy()
        request.POST['published'] = published
        collection_form = CollectionForm(request.POST)

        card_template_id = collection_form.data['card_template']
        if collection_form.is_valid():
            collection = collection_form.save()
            lti_req.associateCourse(collection.id)
            services.add_user_to_collection(user=request.user, collection=collection, role=Users_Collections.ADMINISTRATOR)
            #update role_bucket to add admin permission to the user for this newly created collection
            services.get_or_update_role_bucket(request, collection.id, Users_Collections.role_map[Users_Collections.ADMINISTRATOR])
            log.info('Collection %s created.' %collection.id, extra={'user': request.user})
            analytics.track(
                actor=request.user,
                verb=analytics.VERBS.created,
                object=analytics.OBJECTS.collection,
                context={"custom": False}
            )
            return redirect(collection)
    else:
        rel_templates = CardTemplate.objects.filter(Q(owner__isnull=True) | Q(owner=request.user))
        initial = {'card_template': '1'}
        card_template_id = initial['card_template']
        collection_form = CollectionForm(query_set=rel_templates,initial=initial)


    # Pre-populate the "preview" of the card template
    # This view is also called via AJAX on the page.
    prev_request = HttpRequest()
    prev_request.method = 'GET'
    prev_request.GET['card_template_id'] = card_template_id
    prev_response = card_template.preview(prev_request)
    card_template_preview_html = prev_response.content

    context = {
        "nav_collections": collection_list,
        "active_collection": None,
        "collection_form": collection_form,
        "card_template_preview_html": card_template_preview_html
    }

    return render(request, 'collections/create.html', context)
Example #16
0
def delete(request, collection_id=None):
    """Deletes a collection."""

    services.delete_collection(collection_id)
    response = redirect('collectionIndex')
    response['Location'] += '?instructor=edit'
    log.info('Collection %(c)s deleted.' % {'c': str(collection_id)},
             extra={'user': request.user})
    analytics.track(actor=request.user,
                    verb=analytics.VERBS.deleted,
                    object=analytics.OBJECTS.collection,
                    context={"collection_id": collection_id})
    return response
Example #17
0
def log_analytics_delete(success, entity_type, entity_id, card_id, user):
    d = {'user': user}
    if success:
        log.info('Card deleted from the %(t) %(id)s' %{'t': entity_type, 'id': str(entity_id)}, extra=d)
    else:
        log.error('Card could not be deleted from the %(t) %(id)s' %{'t': entity_type, 'id': str(entity_id)}, extra=d)

    analytics.track(
        actor=user,
        verb=analytics.VERBS.deleted,
        object=analytics.OBJECTS.card,
        context={entity_type+"_id": entity_id, "card_id": card_id}
    )
Example #18
0
def index(request, collection_id=None):
    """Displays a set of collections to the user depending on whether
    or not the collections are private or public and whether or not the
    user has permission."""

    if collection_id is not None:
        collection_id = int(collection_id)

    role_bucket = services.get_or_update_role_bucket(request)
    lti_req = LTIService(request)
    course_collections = lti_req.getCourseCollections()

    is_teacher = lti_req.isTeacher() or queries.is_superuser_or_staff(request.user)
    collection_admin_perms = []
    for r in (Users_Collections.ADMINISTRATOR, Users_Collections.INSTRUCTOR):
        role_name = Users_Collections.role_map[r]
        collection_admin_perms.extend(role_bucket[role_name])

    copy_collections = queries.getCopyCollectionList(request.user)
    collection_filters = dict(collection_ids=course_collections, can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket, **collection_filters)
    display_collections = queries.groupCollectionsByList(collection_list)

    context = {
        "nav_collections": collection_list,
        "display_collections": display_collections,
        "copy_collections": copy_collections,
        "active_collection": None,
        "user_collection_role": role_bucket,
        "collection_admin_perms": collection_admin_perms,
        "is_teacher": is_teacher,
    }

    if collection_id:
        try:
            cur_collection = Collection.objects.get(id=collection_id)
        except Collection.DoesNotExist:
            raise Http404
        filtered_collection_list = [c for c in collection_list if c['id'] == cur_collection.id]
        if len(filtered_collection_list) == 0:
            raise Http404
        context['active_collection'] = filtered_collection_list[0]

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.viewed,
        object=analytics.OBJECTS.collection,
        context={"collection_id": collection_id}
    )

    return render(request, 'collections/index.html', context)
Example #19
0
 def post(self, request, *args, **kwargs):
     '''
     Handles the LTI launch request and redirects to the main page.
     '''
     lti_launch_json = json.dumps(request.session['LTI_LAUNCH'], sort_keys=True, indent=4, separators=(',',': '))
     log.debug("LTI launch parameters: %s" % lti_launch_json)
     LTIService(request).subscribeToCourseCollections()
     analytics.track(
         actor=request.user, 
         verb=analytics.VERBS.launched, 
         object=analytics.OBJECTS.application,
         context={"lti_launch": request.session['LTI_LAUNCH']}
     )
     return redirect(self.url)
Example #20
0
def delete(request, collection_id=None):
    """Deletes a collection."""

    services.delete_collection(collection_id)
    response = redirect('collectionIndex')
    response['Location'] += '?instructor=edit'
    log.info('Collection %(c)s deleted.' %{'c': str(collection_id)}, extra={'user': request.user})
    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.deleted,
        object=analytics.OBJECTS.collection,
        context={"collection_id": collection_id}
    )
    return response
Example #21
0
 def post(self, request, *args, **kwargs):
     '''
     Handles the LTI launch request and redirects to the main page.
     '''
     lti_launch_json = json.dumps(request.session['LTI_LAUNCH'],
                                  sort_keys=True,
                                  indent=4,
                                  separators=(',', ': '))
     log.debug("LTI launch parameters: %s" % lti_launch_json)
     LTIService(request).subscribeToCourseCollections()
     analytics.track(actor=request.user,
                     verb=analytics.VERBS.launched,
                     object=analytics.OBJECTS.application,
                     context={"lti_launch": request.session['LTI_LAUNCH']})
     return redirect(self.url)
Example #22
0
def track(request):
    actor = request.user
    statements_json = request.POST.get('statements', '')
    statements = json.loads(statements_json)
    num_statements = len(statements)
    results = []

    for s in statements:
        verb = s.get('verb', '')
        object = s.get('object', '')
        context = s.get('context', '')
        if context == '':
            context = None
        timestamp = s.get('timestamp', '')
        if timestamp == '':
            timestamp = None

        result = {"success": False, "data": s}

        if verb != '' and object != '':
            statement = analytics.track(
                actor=actor,
                verb=verb,
                object=object,
                timestamp=timestamp,
                context=context,
            )
            result['success'] = True
            result['data'] = statement.as_dict()

        results.append(result)

    return HttpResponse(json.dumps({"statements": results}), content_type="application/json")
Example #23
0
def track(request):
    actor = request.user
    statements_json = request.POST.get('statements', '')
    statements = json.loads(statements_json)
    num_statements = len(statements)
    results = []

    for s in statements:
        verb = s.get('verb', '')
        object = s.get('object', '')
        context = s.get('context', '')
        if context == '':
            context = None
        timestamp = s.get('timestamp', '')
        if timestamp == '':
            timestamp = None

        result = {"success": False, "data": s}

        if verb != '' and object != '':
            statement = analytics.track(
                actor=actor,
                verb=verb,
                object=object,
                timestamp=timestamp,
                context=context,
            )
            result['success'] = True
            result['data'] = statement.as_dict()

        results.append(result)

    return HttpResponse(json.dumps({"statements": results}),
                        content_type="application/json")
Example #24
0
 def test_track_anonymous_user(self):
     stmt_args = {
         "actor": "anonymous",
         "verb": "did",
         "object": "that"
     }
     statement = analytics.track(**stmt_args)
     self.assertTrue(statement.model.stmt_actor_user is None)
     self.assertEqual(statement.model.stmt_actor_desc, stmt_args['actor'])
Example #25
0
def edit(request, collection_id=None):
    """Edits a collection."""

    collection = Collection.objects.get(id=collection_id)

    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(
        collection_ids=course_collections,
        can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket,
                                                **collection_filters)

    if request.method == 'POST':
        collection_form = CollectionForm(request.POST, instance=collection)
        if collection_form.is_valid():
            collection = collection_form.save()
            response = redirect(collection)
            response['Location'] += '?instructor=edit'
            analytics.track(actor=request.user,
                            verb=analytics.VERBS.modified,
                            object=analytics.OBJECTS.collection,
                            context={"collection_id": collection_id})
            return response
    else:
        collection_form = CollectionForm(instance=collection)

    collection_decks = []
    for c in collection_list:
        if c['id'] == collection.id:
            collection_decks = c['decks']
            break

    print collection_decks

    context = {
        "collection_form": collection_form,
        "nav_collections": collection_list,
        "collection": collection,
        "collection_decks": collection_decks,
    }

    return render(request, 'collections/edit.html', context)
Example #26
0
def edit(request, collection_id=None):
    """Edits a collection."""

    collection = Collection.objects.get(id=collection_id)

    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(collection_ids=course_collections, can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket, **collection_filters)

    if request.method == 'POST':
        collection_form = CollectionForm(request.POST, instance=collection)
        if collection_form.is_valid():
            collection = collection_form.save()
            response = redirect(collection)
            response['Location'] += '?instructor=edit'
            analytics.track(
                actor=request.user,
                verb=analytics.VERBS.modified,
                object=analytics.OBJECTS.collection,
                context={"collection_id": collection_id}
            )
            return response
    else:
        collection_form = CollectionForm(instance=collection)

    collection_decks = []
    for c in collection_list:
        if c['id'] == collection.id:
            collection_decks = c['decks']
            break

    print collection_decks

    context = {
        "collection_form": collection_form,
        "nav_collections": collection_list,
        "collection": collection,
        "collection_decks": collection_decks,
    }

    return render(request, 'collections/edit.html', context)
Example #27
0
def upload_deck(request, deck_id=None):
    '''
    Imports a deck of cards from an excel spreadsheet.
    '''
    upload_error = ''
    deck = Deck.objects.get(id=deck_id)
    current_collection = deck.collection

    role_bucket = services.get_or_update_role_bucket(request)
    canvas_course_collections = LTIService(request).getCourseCollections()
    collection_list = queries.getCollectionList(
        role_bucket, collection_ids=canvas_course_collections)

    if request.method == 'POST':
        d = {'user': request.user}
        log.info('The user is uploading a new deck.', extra=d)
        deck_form = DeckImportForm(request.POST, request.FILES)
        if deck_form.is_valid():
            if 'file' in request.FILES:
                try:
                    services.handle_uploaded_deck_file(deck,
                                                       request.FILES['file'])
                    log.info(
                        'New deck successfully added to the collection %(c)s.'
                        % {'c': str(deck.collection.id)},
                        extra=d)
                    analytics.track(
                        actor=request.user,
                        verb=analytics.VERBS.uploaded,
                        object=analytics.OBJECTS.deck,
                        context={"deck_id": deck_id},
                    )
                    return redirect(deck)
                except Exception, e:
                    upload_error = str(e)
                    msg = 'The following error occurred when the user tried uploading a deck: '
                    log.error(msg + upload_error, extra=d)
            else:
                log.info('No file selected.', extra=d)
        else:
            log.error('Deck Form is not valid.', extra=d)
Example #28
0
def download_custom_template(request, collection_id=None):
    '''
    Downloads an excel spreadsheet that may be used as a template for uploading
    a deck of cards.
    '''

    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = 'attachment; filename=flashcards_template.xls'

    file_output = utils.create_custom_template_file()
    response.write(file_output)
    log.info('Custom template downloaded.', extra={'user': request.user})

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.downloaded,
        object=analytics.OBJECTS.template,
        context={"collection_id": collection_id, "custom": True}
    )

    return response
Example #29
0
def download_deck(request, deck_id=None):
    '''
    Downloads a ZIP containing the excel spreadsheet of the deck of cards
    along with any associated media files like images or audio.
    '''

    deck =  Deck.objects.get(id=deck_id)
    zfile_output = services.create_zip_deck_file(deck)
    log.info('Deck %(d)s from the collection %(c)s downloaded by the user.'
            %{'d': str(deck.id), 'c': str(deck.collection.id)}, extra={'user': request.user})

    response = HttpResponse(zfile_output, content_type='application/x-zip-compressed')
    response['Content-Disposition'] = 'attachment; filename=deck.zip'

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.downloaded,
        object=analytics.OBJECTS.deck,
        context={"deck_id": deck_id}
    )

    return response
Example #30
0
def delete(request, deck_id=None):
    """Deletes a deck."""
    d = {'user': request.user}

    collection_id = queries.getDeckCollectionId(deck_id)
    success = services.delete_deck(deck_id)
    if success:
        log.info('Deck %(d)s deleted from collection %(c)s' %{'d':deck_id, 'c':collection_id}, extra=d)
    else:
        log.info('Deck %(d)s could not be deleted from collection %(c)s' %{'d':deck_id, 'c':collection_id}, extra=d)

    response =  redirect('collectionIndex', collection_id)
    response['Location'] += '?instructor=edit'

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.deleted,
        object=analytics.OBJECTS.deck,
        context={"deck_id": deck_id},
    )

    return response
Example #31
0
def log_analytics_delete(success, entity_type, entity_id, card_id, user):
    d = {'user': user}
    if success:
        log.info('Card deleted from the %(t) %(id)s' % {
            't': entity_type,
            'id': str(entity_id)
        },
                 extra=d)
    else:
        log.error('Card could not be deleted from the %(t) %(id)s' % {
            't': entity_type,
            'id': str(entity_id)
        },
                  extra=d)

    analytics.track(actor=user,
                    verb=analytics.VERBS.deleted,
                    object=analytics.OBJECTS.card,
                    context={
                        entity_type + "_id": entity_id,
                        "card_id": card_id
                    })
Example #32
0
def download_template(request, collection_id=None):
    '''
    Downloads an excel spreadsheet that may be used as a template for uploading
    a deck of cards.
    '''
    collection = Collection.objects.get(id=collection_id)

    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = 'attachment; filename=flashcards_template.xls'

    file_output = utils.create_deck_template_file(collection.card_template)
    response.write(file_output)
    log.info('Template for the collection %(c)s downloaded by the user.'
            %{'c': str(collection_id)}, extra={'user': request.user})

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.downloaded,
        object=analytics.OBJECTS.template,
        context={"collection_id": collection_id, "custom": False}
    )

    return response
Example #33
0
def download_custom_template(request, collection_id=None):
    '''
    Downloads an excel spreadsheet that may be used as a template for uploading
    a deck of cards.
    '''

    response = HttpResponse(content_type='application/vnd.ms-excel')
    response[
        'Content-Disposition'] = 'attachment; filename=flashcards_template.xls'

    file_output = utils.create_custom_template_file()
    response.write(file_output)
    log.info('Custom template downloaded.', extra={'user': request.user})

    analytics.track(actor=request.user,
                    verb=analytics.VERBS.downloaded,
                    object=analytics.OBJECTS.template,
                    context={
                        "collection_id": collection_id,
                        "custom": True
                    })

    return response
Example #34
0
def download_deck(request, deck_id=None):
    '''
    Downloads a ZIP containing the excel spreadsheet of the deck of cards
    along with any associated media files like images or audio.
    '''

    deck = Deck.objects.get(id=deck_id)
    zfile_output = services.create_zip_deck_file(deck)
    log.info('Deck %(d)s from the collection %(c)s downloaded by the user.' % {
        'd': str(deck.id),
        'c': str(deck.collection.id)
    },
             extra={'user': request.user})

    response = HttpResponse(zfile_output,
                            content_type='application/x-zip-compressed')
    response['Content-Disposition'] = 'attachment; filename=deck.zip'

    analytics.track(actor=request.user,
                    verb=analytics.VERBS.downloaded,
                    object=analytics.OBJECTS.deck,
                    context={"deck_id": deck_id})

    return response
Example #35
0
def upload_deck(request, deck_id=None):
    '''
    Imports a deck of cards from an excel spreadsheet.
    '''
    upload_error = ''
    deck = Deck.objects.get(id=deck_id)
    current_collection = deck.collection

    role_bucket = services.get_or_update_role_bucket(request)
    canvas_course_collections = LTIService(request).getCourseCollections()
    collection_list = queries.getCollectionList(role_bucket, collection_ids=canvas_course_collections)

    if request.method == 'POST':
        d = {'user': request.user}
        log.info('The user is uploading a new deck.', extra=d)
        deck_form = DeckImportForm(request.POST, request.FILES)
        if deck_form.is_valid():
            if 'file' in request.FILES:
                try:
                    services.handle_uploaded_deck_file(deck, request.FILES['file'])
                    log.info('New deck successfully added to the collection %(c)s.' %{'c': str(deck.collection.id)}, extra=d)
                    analytics.track(
                        actor=request.user,
                        verb=analytics.VERBS.uploaded,
                        object=analytics.OBJECTS.deck,
                        context={"deck_id": deck_id},
                    )
                    return redirect(deck)
                except Exception, e:
                    upload_error = str(e)
                    msg = 'The following error occurred when the user tried uploading a deck: '
                    log.error(msg + upload_error, extra=d)
            else:
                log.info('No file selected.', extra=d)
        else:
            log.error('Deck Form is not valid.', extra=d)
Example #36
0
 def test_track_anonymous_user(self):
     stmt_args = {"actor": "anonymous", "verb": "did", "object": "that"}
     statement = analytics.track(**stmt_args)
     self.assertTrue(statement.model.stmt_actor_user is None)
     self.assertEqual(statement.model.stmt_actor_desc, stmt_args['actor'])
Example #37
0
 def test_track_user(self):
     statement = analytics.track(**self.test_stmt_args)
     exists = Analytics.objects.filter(pk=statement.model.pk).exists()
     self.assertTrue(exists)
Example #38
0
                return redirect(deck)
            except Exception, e:
                    upload_error = str(e)
        msg = 'The following error occurred when the user tried uploading a deck: '
        log.error(msg + upload_error , extra=d)

    context = {
        "nav_collections": collection_list,
        "active_collection": None,
        'upload_error': upload_error,
        "course_name": course_name or ''
    }

    analytics.track(
        actor=request.user,
        verb=analytics.VERBS.created,
        object=analytics.OBJECTS.collection,
        context={"custom": True}
    )

    return render(request, 'collections/custom.html', context)

#should only check on collections? allow any registered user to create their own?
@login_required
def create(request):
    """Creates a collection."""
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(collection_ids=course_collections, can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket, **collection_filters)

    if request.method == 'POST':
Example #39
0
 def test_track_user(self):
     statement = analytics.track(**self.test_stmt_args)
     exists = Analytics.objects.filter(pk=statement.model.pk).exists()
     self.assertTrue(exists)
Example #40
0
                    extra=d)
                return redirect(deck)
            except Exception, e:
                upload_error = str(e)
        msg = 'The following error occurred when the user tried uploading a deck: '
        log.error(msg + upload_error, extra=d)

    context = {
        "nav_collections": collection_list,
        "active_collection": None,
        'upload_error': upload_error,
        "course_name": course_name or ''
    }

    analytics.track(actor=request.user,
                    verb=analytics.VERBS.created,
                    object=analytics.OBJECTS.collection,
                    context={"custom": True})

    return render(request, 'collections/custom.html', context)


#should only check on collections? allow any registered user to create their own?
@login_required
def create(request):
    """Creates a collection."""
    role_bucket = services.get_or_update_role_bucket(request)
    course_collections = LTIService(request).getCourseCollections()
    collection_filters = dict(
        collection_ids=course_collections,
        can_filter=not queries.is_superuser_or_staff(request.user))
    collection_list = queries.getCollectionList(role_bucket,