def load_single_user_time(request):
    user = User.objects.get(id=request.POST.get('user_id'))
    row = {}
    rts = record_time_store()
    external_time = 0
    all_external_time = 0
    user_id = str(user.id)
    course_id = str(request.POST.get('course_id', None))
    if course_id:
        for enrollment in CourseEnrollment.enrollments_for_user(user):
            try:
                course = course_from_id(enrollment.course_id)
                all_external_time += rts.get_external_time(user_id, course.id)
            except ItemNotFoundError:
                #log.error("User {0} enrolled in non-existent course {1}".format(p.user.username, enrollment.course_id))
                pass
        all_course_time, all_discussion_time, portfolio_time = rts.get_stats_time(user_id)
        adjustment_time_totle = rts.get_adjustment_time(user_id, 'total', None)
        external_time = rts.get_external_time(user_id, course_id)
        course_time = rts.get_course_time(user_id, course_id, 'courseware')
        discussion_time = rts.get_course_time(user_id, course_id, 'discussion')
        collaboration_time = all_discussion_time + portfolio_time
        all_course_time = all_course_time + all_external_time
        total_time = all_course_time + collaboration_time + adjustment_time_totle
    else:
        for enrollment in CourseEnrollment.enrollments_for_user(user):
            try:
                course = course_from_id(enrollment.course_id)
                external_time += rts.get_external_time(user_id, course.id)
            except ItemNotFoundError:
                #log.error("User {0} enrolled in non-existent course {1}".format(p.user.username, enrollment.course_id))
                pass
        adjustment_time_totle = rts.get_adjustment_time(user_id, 'total', None)
        course_time, discussion_time, portfolio_time = rts.get_stats_time(user_id)
        all_course_time = course_time + external_time
        collaboration_time = discussion_time + portfolio_time
        total_time = all_course_time + collaboration_time + adjustment_time_totle

    row = {"id": user_id,
           "total_time": study_time_format(total_time, True),
           "collaboration_time": study_time_format(collaboration_time, True),
           "discussion_time": study_time_format(discussion_time, True),
           "portfolio_time": study_time_format(portfolio_time, True),
           "external_time": study_time_format(external_time, True),
           "course_time": study_time_format(course_time, True)
           }

    return HttpResponse(json.dumps({'row': row}), content_type="application/json")
예제 #2
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for the verification flow.
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if CourseEnrollment.enrollment_mode_for_user(request.user,
                                                 course_id) == 'verified':
        return redirect(reverse('dashboard'))

    upgrade = request.GET.get('upgrade', False)
    course = course_from_id(course_id)
    context = {
        "course_id":
        course_id.to_deprecated_string(),
        "course_modes_choose_url":
        reverse("course_modes_choose",
                kwargs={'course_id': course_id.to_deprecated_string()}),
        "verify_student_url":
        reverse('verify_student_verify',
                kwargs={'course_id': course_id.to_deprecated_string()}),
        "course_name":
        course.display_name_with_default,
        "course_org":
        course.display_org_with_default,
        "course_num":
        course.display_number_with_default,
        "is_not_active":
        not request.user.is_active,
        "upgrade":
        upgrade,
    }
    return render_to_response("verify_student/show_requirements.html", context)
def validate_adjustment_time(rts, user_id, type, adjustment_time, course_id):
    type_time = 0
    external_time = 0
    adjustment_time = int(adjustment_time)
    if adjustment_time < 0:
        if type == 'total':
            user = User.objects.get(id=user_id)
            for enrollment in CourseEnrollment.enrollments_for_user(user):
                try:
                    course = course_from_id(enrollment.course_id)
                    external_time += rts.get_external_time(user_id, course.id)
                except ItemNotFoundError:
                    log.error("User {0} enrolled in non-existent course {1}".format(user.username, enrollment.course_id))

            course_time, discussion_time, portfolio_time = rts.get_stats_time(user_id)
            adjustment_time_totle = rts.get_adjustment_time(user_id, 'total', None)
            type_time = course_time + discussion_time + portfolio_time + external_time + adjustment_time_totle
        else:
            if type == 'external':
                type_time = rts.get_external_time(user_id, course_id)
            else:
                type_time = rts.get_course_time(user_id, course_id, type)
        if type_time + adjustment_time < 0:
            return False
    return True
예제 #4
0
def midcourse_reverify_dash(request):
    """
    Shows the "course reverification dashboard", which displays the reverification status (must reverify,
    pending, approved, failed, etc) of all courses in which a student has a verified enrollment.
    """
    user = request.user
    course_enrollment_pairs = []
    for enrollment in CourseEnrollment.enrollments_for_user(user):
        try:
            course_enrollment_pairs.append((course_from_id(enrollment.course_id), enrollment))
        except ItemNotFoundError:
            log.error("User {0} enrolled in non-existent course {1}"
                      .format(user.username, enrollment.course_id))

    statuses = ["approved", "pending", "must_reverify", "denied"]

    reverifications = reverification_info(course_enrollment_pairs, user, statuses)

    context = {
        "user_full_name": user.profile.name,
        'reverifications': reverifications,
        'referer': request.META.get('HTTP_REFERER'),
        'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
    }
    return render_to_response("verify_student/midcourse_reverify_dash.html", context)
예제 #5
0
def midcourse_reverify_dash(request):
    """
    Shows the "course reverification dashboard", which displays the reverification status (must reverify,
    pending, approved, failed, etc) of all courses in which a student has a verified enrollment.
    """
    user = request.user
    course_enrollment_pairs = []
    for enrollment in CourseEnrollment.enrollments_for_user(user):
        try:
            course_enrollment_pairs.append(
                (course_from_id(enrollment.course_id), enrollment))
        except ItemNotFoundError:
            log.error("User {0} enrolled in non-existent course {1}".format(
                user.username, enrollment.course_id))

    statuses = ["approved", "pending", "must_reverify", "denied"]

    reverifications = reverification_info(course_enrollment_pairs, user,
                                          statuses)

    context = {
        "user_full_name": user.profile.name,
        'reverifications': reverifications,
        'referer': request.META.get('HTTP_REFERER'),
        'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
    }
    return render_to_response("verify_student/midcourse_reverify_dash.html",
                              context)
예제 #6
0
    def get(self, request, course_id):
        """
        Handle the case where we have a get request
        """
        upgrade = request.GET.get('upgrade', False)
        if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        verify_mode = CourseMode.mode_for_course(course_id, "verified")
        if course_id in request.session.get("donation_for_course", {}):
            chosen_price = request.session["donation_for_course"][course_id]
        else:
            chosen_price = verify_mode.min_price.format("{:g}")

        course = course_from_id(course_id)
        context = {
            "course_id": course_id,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "purchase_endpoint": get_purchase_endpoint(),
            "currency": verify_mode.currency.upper(),
            "chosen_price": chosen_price,
            "upgrade": upgrade,
        }
        return render_to_response('verify_student/verified.html', context)
예제 #7
0
    def post(self, request, course_id):
        """ Takes the form submission from the page and parses it """
        user = request.user

        # This is a bit redundant with logic in student.views.change_enrollement,
        # but I don't really have the time to refactor it more nicely and test.
        course = course_from_id(course_id)
        if not has_access(user, course, 'enroll'):
            error_msg = _("Enrollment is closed")
            return self.get(request, course_id, error=error_msg)

        upgrade = request.GET.get('upgrade', False)

        requested_mode = self.get_requested_mode(request.POST.get("mode"))
        if requested_mode == "verified" and request.POST.get("honor-code"):
            requested_mode = "honor"

        allowed_modes = CourseMode.modes_for_course_dict(course_id)
        if requested_mode not in allowed_modes:
            return HttpResponseBadRequest(_("Enrollment mode not supported"))

        if requested_mode in ("audit", "honor"):
            CourseEnrollment.enroll(user, course_id, requested_mode)
            return redirect('dashboard')

        mode_info = allowed_modes[requested_mode]

        if requested_mode == "verified":
            amount = request.POST.get("contribution") or \
                request.POST.get("contribution-other-amt") or 0

            try:
                # validate the amount passed in and force it into two digits
                amount_value = decimal.Decimal(amount).quantize(
                    decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN)
            except decimal.InvalidOperation:
                error_msg = _("Invalid amount selected.")
                return self.get(request, course_id, error=error_msg)

            # Check for minimum pricing
            if amount_value < mode_info.min_price:
                error_msg = _(
                    "No selected price or selected price is too low.")
                return self.get(request, course_id, error=error_msg)

            donation_for_course = request.session.get("donation_for_course",
                                                      {})
            donation_for_course[course_id] = amount_value
            request.session["donation_for_course"] = donation_for_course
            if SoftwareSecurePhotoVerification.user_has_valid_or_pending(
                    request.user):
                return redirect(
                    reverse('verify_student_verified',
                            kwargs={'course_id': course_id}) +
                    "?upgrade={}".format(upgrade))

            return redirect(
                reverse('verify_student_show_requirements',
                        kwargs={'course_id': course_id}) +
                "?upgrade={}".format(upgrade))
예제 #8
0
    def get(self, request, course_id, error=None):
        """ Displays the course mode choice page """
        if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        modes = CourseMode.modes_for_course_dict(course_id)

        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(course_id, None)

        course = course_from_id(course_id)
        context = {
            "course_id": course_id,
            "modes": modes,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "chosen_price": chosen_price,
            "error": error,
        }
        if "verified" in modes:
            context["suggested_prices"] = modes["verified"].suggested_prices.split(",")
            context["currency"] = modes["verified"].currency.upper()
            context["min_price"] = modes["verified"].min_price

        return render_to_response("course_modes/choose.html", context)
예제 #9
0
    def get(self, request, course_id, error=None):
        """ Displays the course mode choice page """

        enrollment_mode = CourseEnrollment.enrollment_mode_for_user(request.user, course_id)
        upgrade = request.GET.get('upgrade', False)

        # verified users do not need to register or upgrade
        if enrollment_mode == 'verified':
            return redirect(reverse('dashboard'))

        # registered users who are not trying to upgrade do not need to re-register
        if enrollment_mode is not None and upgrade is False:
            return redirect(reverse('dashboard'))

        modes = CourseMode.modes_for_course_dict(course_id)
        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(course_id, None)

        course = course_from_id(course_id)
        context = {
            "course_id": course_id,
            "modes": modes,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "chosen_price": chosen_price,
            "error": error,
            "upgrade": upgrade,
        }
        if "verified" in modes:
            context["suggested_prices"] = [decimal.Decimal(x) for x in modes["verified"].suggested_prices.split(",")]
            context["currency"] = modes["verified"].currency.upper()
            context["min_price"] = modes["verified"].min_price

        return render_to_response("course_modes/choose.html", context)
예제 #10
0
    def get(self, request, course_id, error=None):
        """ Displays the course mode choice page """

        enrollment_mode = CourseEnrollment.enrollment_mode_for_user(request.user, course_id)
        upgrade = request.GET.get('upgrade', False)

        # verified users do not need to register or upgrade
        if enrollment_mode == 'verified':
            return redirect(reverse('dashboard'))

        # registered users who are not trying to upgrade do not need to re-register
        if enrollment_mode is not None and upgrade is False:
            return redirect(reverse('dashboard'))

        modes = CourseMode.modes_for_course_dict(course_id)
        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(course_id, None)

        course = course_from_id(course_id)
        context = {
            "course_id": course_id,
            "modes": modes,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "chosen_price": chosen_price,
            "error": error,
            "upgrade": upgrade,
        }
        if "verified" in modes:
            context["suggested_prices"] = [decimal.Decimal(x) for x in modes["verified"].suggested_prices.split(",")]
            context["currency"] = modes["verified"].currency.upper()
            context["min_price"] = modes["verified"].min_price

        return render_to_response("course_modes/choose.html", context)
예제 #11
0
    def get(self, request, course_id):
        """
        Handle the case where we have a get request
        """
        upgrade = request.GET.get('upgrade', False)
        course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        verify_mode = CourseMode.mode_for_course(course_id, "verified")

        if verify_mode is None:
            return redirect(reverse('dashboard'))

        chosen_price = request.session.get(
            "donation_for_course",
            {}
        ).get(
            course_id.to_deprecated_string(),
            verify_mode.min_price
        )

        course = course_from_id(course_id)
        context = {
            "course_id": course_id.to_deprecated_string(),
            "course_modes_choose_url": reverse('course_modes_choose', kwargs={'course_id': course_id.to_deprecated_string()}),
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "purchase_endpoint": get_purchase_endpoint(),
            "currency": verify_mode.currency.upper(),
            "chosen_price": chosen_price,
            "create_order_url": reverse("verify_student_create_order"),
            "upgrade": upgrade,
        }
        return render_to_response('verify_student/verified.html', context)
def drop_courses(request):
    r = list()
    courses = get_courses(None)
    for course in courses:
        course = course_from_id(course.id)
        r.append({"id": course.id, "name": str(course.display_coursenumber) + ' ' + course.display_name})
    r.sort(key=lambda x: x['name'], reverse=False)
    return HttpResponse(json.dumps(r), content_type="application/json")
예제 #13
0
    def get(self, request, course_id):
        """
        Displays the main verification view, which contains three separate steps:
            - Taking the standard face photo
            - Taking the id photo
            - Confirming that the photos and payment price are correct
              before proceeding to payment
        """
        upgrade = request.GET.get('upgrade', False)

        course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        # If the user has already been verified within the given time period,
        # redirect straight to the payment -- no need to verify again.
        if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
            return redirect(
                reverse('verify_student_verified',
                        kwargs={'course_id': course_id.to_deprecated_string()}) + "?upgrade={}".format(upgrade)
            )
        elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        else:
            # If they haven't completed a verification attempt, we have to
            # restart with a new one. We can't reuse an older one because we
            # won't be able to show them their encrypted photo_id -- it's easier
            # bookkeeping-wise just to start over.
            progress_state = "start"

        verify_mode = CourseMode.mode_for_course(course_id, "verified")
        # if the course doesn't have a verified mode, we want to kick them
        # from the flow
        if not verify_mode:
            return redirect(reverse('dashboard'))
        if course_id.to_deprecated_string() in request.session.get("donation_for_course", {}):
            chosen_price = request.session["donation_for_course"][course_id.to_deprecated_string()]
        else:
            chosen_price = verify_mode.min_price

        course = course_from_id(course_id)
        context = {
            "progress_state": progress_state,
            "user_full_name": request.user.profile.name,
            "course_id": course_id.to_deprecated_string(),
            "course_modes_choose_url": reverse('course_modes_choose', kwargs={'course_id': course_id.to_deprecated_string()}),
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "purchase_endpoint": get_purchase_endpoint(),
            "suggested_prices": [
                decimal.Decimal(price)
                for price in verify_mode.suggested_prices.split(",")
            ],
            "currency": verify_mode.currency.upper(),
            "chosen_price": chosen_price,
            "min_price": verify_mode.min_price,
            "upgrade": upgrade,
        }

        return render_to_response('verify_student/photo_verification.html', context)
예제 #14
0
    def add_to_order(cls, order, course_id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, cost=None, currency=None):
        """
        A standardized way to create these objects, with sensible defaults filled in.
        Will update the cost if called on an order that already carries the course.

        Returns the order item
        """
        # First a bunch of sanity checks
        try:
            course = course_from_id(course_id)  # actually fetch the course to make sure it exists, use this to
                                                # throw errors if it doesn't
        except ItemNotFoundError:
            log.error("User {} tried to add non-existent course {} to cart id {}"
                      .format(order.user.email, course_id, order.id))
            raise CourseDoesNotExistException

        if cls.contained_in_order(order, course_id):
            log.warning("User {} tried to add PaidCourseRegistration for course {}, already in cart id {}"
                        .format(order.user.email, course_id, order.id))
            raise ItemAlreadyInCartException

        if CourseEnrollment.is_enrolled(user=order.user, course_id=course_id):
            log.warning("User {} trying to add course {} to cart id {}, already registered"
                        .format(order.user.email, course_id, order.id))
            raise AlreadyEnrolledInCourseException

        ### Validations done, now proceed
        ### handle default arguments for mode_slug, cost, currency
        ## Se corrigio la llamada a CourseMode, para que lea la forma
        ## de pago que esta ligada a este curso
        course_list = CourseMode.modes_for_course(course_id)
        course_mode = course_list and course_list[0] or []
        if not course_mode:
            # user could have specified a mode that's not set, in that case return the DEFAULT_MODE
            course_mode = CourseMode.DEFAULT_MODE
        if not cost:
            cost = course_mode.min_price
        if not currency:
            currency = course_mode.currency

        super(PaidCourseRegistration, cls).add_to_order(order, course_id, cost, currency=currency)

        item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id)
        item.status = order.status
        item.mode = course_mode.slug
        item.qty = 1
        item.unit_cost = cost
        item.line_desc = _(u'Registration for Course: {course_name}').format(
            course_name=course.display_name_with_default)
        item.currency = currency
        order.currency = currency
        item.report_comments = item.csv_report_comments
        order.save()
        item.save()
        log.info("User {} added course registration {} to cart: order {}"
                 .format(order.user.email, course_id, order.id))
        return item
예제 #15
0
    def get(self, request, course_id):
        """
        """
        # If the user has already been verified within the given time period,
        # redirect straight to the payment -- no need to verify again.
        if SoftwareSecurePhotoVerification.user_has_valid_or_pending(
                request.user):
            return redirect(
                reverse('verify_student_verified',
                        kwargs={'course_id': course_id}))
        elif CourseEnrollment.enrollment_mode_for_user(
                request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        else:
            # If they haven't completed a verification attempt, we have to
            # restart with a new one. We can't reuse an older one because we
            # won't be able to show them their encrypted photo_id -- it's easier
            # bookkeeping-wise just to start over.
            progress_state = "start"

        verify_mode = CourseMode.mode_for_course(course_id, "verified")
        if course_id in request.session.get("donation_for_course", {}):
            chosen_price = request.session["donation_for_course"][course_id]
        else:
            chosen_price = verify_mode.min_price

        course = course_from_id(course_id)
        context = {
            "progress_state":
            progress_state,
            "user_full_name":
            request.user.profile.name,
            "course_id":
            course_id,
            "course_name":
            course.display_name_with_default,
            "course_org":
            course.display_org_with_default,
            "course_num":
            course.display_number_with_default,
            "purchase_endpoint":
            get_purchase_endpoint(),
            "suggested_prices": [
                decimal.Decimal(price)
                for price in verify_mode.suggested_prices.split(",")
            ],
            "currency":
            verify_mode.currency.upper(),
            "chosen_price":
            chosen_price,
            "min_price":
            verify_mode.min_price,
        }

        return render_to_response('verify_student/photo_verification.html',
                                  context)
예제 #16
0
    def get(self, request, course_id):
        """
        Displays the main verification view, which contains three separate steps:
            - Taking the standard face photo
            - Taking the id photo
            - Confirming that the photos and payment price are correct
              before proceeding to payment
        """
        upgrade = request.GET.get('upgrade', False)

        # If the user has already been verified within the given time period,
        # redirect straight to the payment -- no need to verify again.
        if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
            return redirect(
                reverse('verify_student_verified',
                        kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade)
            )
        elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        else:
            # If they haven't completed a verification attempt, we have to
            # restart with a new one. We can't reuse an older one because we
            # won't be able to show them their encrypted photo_id -- it's easier
            # bookkeeping-wise just to start over.
            progress_state = "start"

        verify_mode = CourseMode.mode_for_course(course_id, "verified")
        # if the course doesn't have a verified mode, we want to kick them
        # from the flow
        if not verify_mode:
            return redirect(reverse('dashboard'))
        if course_id in request.session.get("donation_for_course", {}):
            chosen_price = request.session["donation_for_course"][course_id]
        else:
            chosen_price = verify_mode.min_price

        course = course_from_id(course_id)
        context = {
            "progress_state": progress_state,
            "user_full_name": request.user.profile.name,
            "course_id": course_id,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "purchase_endpoint": get_purchase_endpoint(),
            "suggested_prices": [
                decimal.Decimal(price)
                for price in verify_mode.suggested_prices.split(",")
            ],
            "currency": verify_mode.currency.upper(),
            "chosen_price": chosen_price,
            "min_price": verify_mode.min_price,
            "upgrade": upgrade,
        }

        return render_to_response('verify_student/photo_verification.html', context)
예제 #17
0
 def single_item_receipt_context(self):
     course = course_from_id(self.course_id)
     return {
         "course_id" : self.course_id,
         "course_name": course.display_name_with_default,
         "course_org": course.display_org_with_default,
         "course_num": course.display_number_with_default,
         "course_start_date_text": course.start_date_text,
         "course_has_started": course.start > datetime.today().replace(tzinfo=pytz.utc),
     }
예제 #18
0
def piazza_discussion(request, course_id):
    '''
    Shows the page under the Discussion tab with an iframe containing Piazza
    '''
    # Create a new tool configuration
    config = ToolConfig(title = 'Piazza',
            launch_url = LTI_LAUNCH_URL)

    # Create tool consumer using LTI!
    consumer = ToolConsumer(LTI_CONSUMER_KEY,
            LTI_CONSUMER_SECRET)
    consumer.set_config(config)

    
    #retrieve user and course models
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    userProfile = UserProfile.objects.get(user_id=user.id)
    course = course_from_id(course_id)

    #check for permissions to determine what role to pass to Piazza.com through 
    piazza_role = ''
    if user.groups.filter(name=('instructor_'+course_id)).count() != 0 or request.user.is_staff:
        piazza_role = 'Instructor'
    elif user.groups.filter(name=('staff_'+course_id)).count() != 0:
        piazza_role = 'Staff'
    else:
        piazza_role = 'Learner'

    # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
    consumer.resource_link_id = course_id
    consumer.lis_person_contact_email_primary = user.email
    consumer.lis_person_name_full = str(userProfile.name)
    hash = hashlib.md5()
    hash.update(str(userProfile.user_id))
    consumer.user_id = hash.hexdigest()

    #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately
    consumer.roles = piazza_role
    consumer.context_id = course_id
    consumer.context_title = course.display_name_with_default
    consumer.context_label = course.number.replace('_', ' ')
    consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu'
    consumer.tool_consumer_instance_description = 'Columbia University'
 

    launch_data = consumer.generate_launch_data()
    launch_url = consumer.launch_url


    course = get_course_with_access(request.user, course_id, 'load')
    staff_access = has_access(request.user, course, 'staff')
    masq = setup_masquerade(request, staff_access)    # allow staff to toggle masquerade on info page

    return render_to_response('courseware/piazza_discussion.html', {'request': request, 'course_id': course_id, 'cache': None,
            'course': course, 'staff_access': staff_access, 'masquerade': masq, 'launch_url':launch_url, 'launch_data':launch_data})
예제 #19
0
    def post(self, request, course_id):
        """ Takes the form submission from the page and parses it """
        user = request.user

        # This is a bit redundant with logic in student.views.change_enrollement,
        # but I don't really have the time to refactor it more nicely and test.
        course = course_from_id(course_id)
        if not has_access(user, course, 'enroll'):
            error_msg = _("Enrollment is closed")
            return self.get(request, course_id, error=error_msg)

        upgrade = request.GET.get('upgrade', False)

        requested_mode = self.get_requested_mode(request.POST.get("mode"))
        if requested_mode == "verified" and request.POST.get("honor-code"):
            requested_mode = "honor"

        allowed_modes = CourseMode.modes_for_course_dict(course_id)
        if requested_mode not in allowed_modes:
            return HttpResponseBadRequest(_("Enrollment mode not supported"))

        if requested_mode in ("audit", "honor"):
            CourseEnrollment.enroll(user, course_id, requested_mode)
            return redirect('dashboard')

        mode_info = allowed_modes[requested_mode]

        if requested_mode == "verified":
            amount = request.POST.get("contribution") or \
                request.POST.get("contribution-other-amt") or 0

            try:
                # validate the amount passed in and force it into two digits
                amount_value = decimal.Decimal(amount).quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_DOWN)
            except decimal.InvalidOperation:
                error_msg = _("Invalid amount selected.")
                return self.get(request, course_id, error=error_msg)

            # Check for minimum pricing
            if amount_value < mode_info.min_price:
                error_msg = _("No selected price or selected price is too low.")
                return self.get(request, course_id, error=error_msg)

            donation_for_course = request.session.get("donation_for_course", {})
            donation_for_course[course_id] = amount_value
            request.session["donation_for_course"] = donation_for_course
            if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
                return redirect(
                    reverse('verify_student_verified',
                            kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade)
                )

            return redirect(
                reverse('verify_student_show_requirements',
                        kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade))
def drop_enroll_courses(request):
    r = list()
    user = User.objects.get(id=request.GET.get('user_id'))
    for enrollment in CourseEnrollment.enrollments_for_user(user):
        try:
            course = course_from_id(enrollment.course_id)
            r.append({"id": course.id, "name": str(course.display_coursenumber) + ' ' + course.display_name})
        except ItemNotFoundError:
            log.error("User {0} enrolled in non-existent course {1}".format(user.username, enrollment.course_id))
    r.sort(key=lambda x: x['name'], reverse=False)
    return HttpResponse(json.dumps(r), content_type="application/json")
예제 #21
0
    def add_to_order(cls, order, course_id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, cost=None, currency=None):
        """
        A standardized way to create these objects, with sensible defaults filled in.
        Will update the cost if called on an order that already carries the course.

        Returns the order item
        """
        # First a bunch of sanity checks
        try:
            course = course_from_id(course_id)  # actually fetch the course to make sure it exists, use this to
                                                # throw errors if it doesn't
        except ItemNotFoundError:
            log.error("User {} tried to add non-existent course {} to cart id {}"
                      .format(order.user.email, course_id, order.id))
            raise CourseDoesNotExistException

        if cls.contained_in_order(order, course_id):
            log.warning("User {} tried to add PaidCourseRegistration for course {}, already in cart id {}"
                        .format(order.user.email, course_id, order.id))
            raise ItemAlreadyInCartException

        if CourseEnrollment.is_enrolled(user=order.user, course_id=course_id):
            log.warning("User {} trying to add course {} to cart id {}, already registered"
                        .format(order.user.email, course_id, order.id))
            raise AlreadyEnrolledInCourseException

        ### Validations done, now proceed
        ### handle default arguments for mode_slug, cost, currency
        course_mode = CourseMode.mode_for_course(course_id, mode_slug)
        if not course_mode:
            # user could have specified a mode that's not set, in that case return the DEFAULT_MODE
            course_mode = CourseMode.DEFAULT_MODE
        if not cost:
            cost = course_mode.min_price
        if not currency:
            currency = course_mode.currency

        super(PaidCourseRegistration, cls).add_to_order(order, course_id, cost, currency=currency)

        item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id)
        item.status = order.status
        item.mode = course_mode.slug
        item.qty = 1
        item.unit_cost = cost
        item.line_desc = _(u'Registration for Course: {course_name}').format(
            course_name=course.display_name_with_default)
        item.currency = currency
        order.currency = currency
        item.report_comments = item.csv_report_comments
        order.save()
        item.save()
        log.info("User {} added course registration {} to cart: order {}"
                 .format(order.user.email, course_id, order.id))
        return item
예제 #22
0
파일: views.py 프로젝트: idefs/edx-platform
    def get(self, request, course_id, error=None):
        if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'pay_with_coupon':
            return redirect(reverse('dashboard'))
        price = get_base_price_for_course_id(course_id)

        context = {
            "course_id": course_id,
            "price": price,
            "course_name": course_from_id(course_id).display_name,
            "error": error,
        }
        return render_to_response("coupons/pay_with_coupon.html", context)
예제 #23
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for
    """
    if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
        return redirect(reverse('dashboard'))
    context = {
        "course_id": course_id,
        "is_not_active": not request.user.is_active,
        "course_name": course_from_id(course_id).display_name,
    }
    return render_to_response("verify_student/show_requirements.html", context)
예제 #24
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for
    """
    if CourseEnrollment.enrollment_mode_for_user(request.user,
                                                 course_id) == 'verified':
        return redirect(reverse('dashboard'))
    context = {
        "course_id": course_id,
        "is_not_active": not request.user.is_active,
        "course_name": course_from_id(course_id).display_name,
    }
    return render_to_response("verify_student/show_requirements.html", context)
예제 #25
0
def piazza_test(request, course_id):
    # Create a new tool configuration
    config = ToolConfig(title = 'Piazza',
            launch_url = LTI_LAUNCH_URL)

    # Create tool consumer using LTI!
    consumer = ToolConsumer(LTI_CONSUMER_KEY,
            LTI_CONSUMER_SECRET)
    consumer.set_config(config)

    #retrieve user and course models
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    userProfile = UserProfile.objects.get(user_id=user.id)
    course = course_from_id(course_id)

    #check for permissions to determine what role to pass to Piazza.com through 
    piazza_role = ''
    if user.groups.filter(name=('instructor_'+course_id)).count() != 0 or request.user.is_staff:
        piazza_role = 'Instructor'
    elif user.groups.filter(name=('staff_'+course_id)).count() != 0:
        piazza_role = 'Staff'
    else:
        piazza_role = 'Learner'

    # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
    consumer.resource_link_id = course_id
    consumer.lis_person_contact_email_primary = user.email
    consumer.lis_person_name_full = str(userProfile.name)
    hash = hashlib.md5()
    hash.update(str(userProfile.user_id))
    consumer.user_id = hash.hexdigest()
    #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately
    #consumer.roles = 'Learner'
    consumer.roles = piazza_role
    consumer.context_id = course_id
    consumer.context_title = course.display_name_with_default
    consumer.context_label = course.number.replace('_', ' ')
    consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu'
    consumer.tool_consumer_instance_description = 'Columbia University'

    launch_data = consumer.generate_launch_data()
    launch_url = consumer.launch_url

    #render a self-submitting form that sends all data to Piazza.com via the LTI standard
    returnable = '<form id="ltiLaunchFormSubmitArea" action="' + launch_url + '" name="ltiLaunchForm" id="ltiLaunchForm" method="post" encType="application/x-www-form-urlencoded">'
    for key in launch_data:
        returnable += '<input type="hidden" name="'+ key +'" value="'+ str(launch_data[key]) + '"/>'
    returnable += '<input type="submit" value="Go to Piazza"></input>'
    returnable += '</form>'
    returnable += '<script language="javascript">document.getElementById("ltiLaunchFormSubmitArea").style.display = "none";document.ltiLaunchForm.submit();</script>'
    return HttpResponse(returnable)
예제 #26
0
def piazza_test(request, course_id):
    # Create a new tool configuration
    config = ToolConfig(title='Piazza', launch_url=LTI_LAUNCH_URL)

    # Create tool consumer using LTI!
    consumer = ToolConsumer(LTI_CONSUMER_KEY, LTI_CONSUMER_SECRET)
    consumer.set_config(config)

    #retrieve user and course models
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    userProfile = UserProfile.objects.get(user_id=user.id)
    course = course_from_id(course_id)

    #check for permissions to determine what role to pass to Piazza.com through
    piazza_role = ''
    if user.groups.filter(name=(
            'instructor_' + course_id)).count() != 0 or request.user.is_staff:
        piazza_role = 'Instructor'
    elif user.groups.filter(name=('staff_' + course_id)).count() != 0:
        piazza_role = 'Staff'
    else:
        piazza_role = 'Learner'

    # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
    consumer.resource_link_id = course_id
    consumer.lis_person_contact_email_primary = user.email
    consumer.lis_person_name_full = str(userProfile.name)
    hash = hashlib.md5()
    hash.update(str(userProfile.user_id))
    consumer.user_id = hash.hexdigest()
    #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately
    #consumer.roles = 'Learner'
    consumer.roles = piazza_role
    consumer.context_id = course_id
    consumer.context_title = course.display_name_with_default
    consumer.context_label = course.number.replace('_', ' ')
    consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu'
    consumer.tool_consumer_instance_description = 'Columbia University'

    launch_data = consumer.generate_launch_data()
    launch_url = consumer.launch_url

    #render a self-submitting form that sends all data to Piazza.com via the LTI standard
    returnable = '<form id="ltiLaunchFormSubmitArea" action="' + launch_url + '" name="ltiLaunchForm" id="ltiLaunchForm" method="post" encType="application/x-www-form-urlencoded">'
    for key in launch_data:
        returnable += '<input type="hidden" name="' + key + '" value="' + str(
            launch_data[key]) + '"/>'
    returnable += '<input type="submit" value="Go to Piazza"></input>'
    returnable += '</form>'
    returnable += '<script language="javascript">document.getElementById("ltiLaunchFormSubmitArea").style.display = "none";document.ltiLaunchForm.submit();</script>'
    return HttpResponse(returnable)
예제 #27
0
def fetch_reverify_banner_info(request, course_id):
    """
    Fetches needed context variable to display reverification banner in courseware
    """
    reverifications = defaultdict(list)
    user = request.user
    if not user.id:
        return reverifications
    enrollment = CourseEnrollment.get_or_create_enrollment(request.user, course_id)
    course = course_from_id(course_id)
    info = single_course_reverification_info(user, course, enrollment)
    if info:
        reverifications[info.status].append(info)
    return reverifications
예제 #28
0
def fetch_reverify_banner_info(request, course_id):
    """
    Fetches needed context variable to display reverification banner in courseware
    """
    reverifications = defaultdict(list)
    user = request.user
    if not user.id:
        return reverifications
    enrollment = CourseEnrollment.get_or_create_enrollment(request.user, course_id)
    course = course_from_id(course_id)
    info = single_course_reverification_info(user, course, enrollment)
    if info:
        reverifications[info.status].append(info)
    return reverifications
예제 #29
0
def tnl_table_data():
    """
    Returns the data needed to build the tables on the config page
    """
    # Get the Domains.
    domains = tnl_get_domain()
    # Get the districts.
    districts = tnl_get_district()
    # Get the list of course ids.
    courses = tnl_get_course()
    # Load the courses and add the name to the objects.
    for x in range(0, len(courses)):
        course = course_from_id(courses[x].course)
        courses[x].name = course.display_name_with_default
    return domains, districts, courses
예제 #30
0
파일: models.py 프로젝트: Bvic/edx-platform
 def single_item_receipt_context(self):
     course = course_from_id(self.course_id)
     return {
         "course_id": self.course_id,
         "course_name": course.display_name_with_default,
         "course_org": course.display_org_with_default,
         "course_num": course.display_number_with_default,
         "course_start_date_text": course.start_date_text,
         "course_has_started": course.start > datetime.today().replace(tzinfo=pytz.utc),
         "course_root_url": reverse(
             'course_root',
             kwargs={'course_id': self.course_id.to_deprecated_string()}  # pylint: disable=no-member
         ),
         "dashboard_url": reverse('dashboard'),
     }
예제 #31
0
    def add_to_order(cls, order, course_id, cost, mode, currency='usd'):
        """
        Add a CertificateItem to an order

        Returns the CertificateItem object after saving

        `order` - an order that this item should be added to, generally the cart order
        `course_id` - the course that we would like to purchase as a CertificateItem
        `cost` - the amount the user will be paying for this CertificateItem
        `mode` - the course mode that this certificate is going to be issued for

        This item also creates a new enrollment if none exists for this user and this course.

        Example Usage:
            cart = Order.get_cart_for_user(user)
            CertificateItem.add_to_order(cart, 'edX/Test101/2013_Fall', 30, 'verified')

        """
        super(CertificateItem, cls).add_to_order(order, course_id, cost, currency=currency)
        try:
            course_enrollment = CourseEnrollment.objects.get(user=order.user, course_id=course_id)
        except ObjectDoesNotExist:
            course_enrollment = CourseEnrollment.create_enrollment(order.user, course_id, mode=mode)

        # do some validation on the enrollment mode
        valid_modes = CourseMode.modes_for_course_dict(course_id)
        if mode in valid_modes:
            mode_info = valid_modes[mode]
        else:
            raise InvalidCartItem(_("Mode {mode} does not exist for {course_id}").format(mode=mode, course_id=course_id))
        item, _created = cls.objects.get_or_create(
            order=order,
            user=order.user,
            course_id=course_id,
            course_enrollment=course_enrollment,
            mode=mode
        )
        item.status = order.status
        item.qty = 1
        item.unit_cost = cost
        course_name = course_from_id(course_id).display_name
        item.line_desc = _("Certificate of Achievement, {mode_name} for course {course}").format(mode_name=mode_info.name,
                                                                                                 course=course_name)
        item.currency = currency
        order.currency = currency
        order.save()
        item.save()
        return item
예제 #32
0
    def add_to_order(cls,
                     order,
                     course_id,
                     mode_slug=CourseMode.DEFAULT_MODE_SLUG,
                     cost=None,
                     currency=None):
        """
        A standardized way to create these objects, with sensible defaults filled in.
        Will update the cost if called on an order that already carries the course.

        Returns the order item
        """
        # TODO: Possibly add checking for whether student is already enrolled in course
        course = course_from_id(
            course_id
        )  # actually fetch the course to make sure it exists, use this to
        # throw errors if it doesn't

        ### handle default arguments for mode_slug, cost, currency
        course_mode = CourseMode.mode_for_course(course_id, mode_slug)
        if not course_mode:
            # user could have specified a mode that's not set, in that case return the DEFAULT_MODE
            course_mode = CourseMode.DEFAULT_MODE
        if not cost:
            cost = course_mode.min_price
        if not currency:
            currency = course_mode.currency

        super(PaidCourseRegistration, cls).add_to_order(order,
                                                        course_id,
                                                        cost,
                                                        currency=currency)

        item, created = cls.objects.get_or_create(order=order,
                                                  user=order.user,
                                                  course_id=course_id)
        item.status = order.status

        item.mode = course_mode.slug
        item.qty = 1
        item.unit_cost = cost
        item.line_desc = 'Registration for Course: {0}. Mode: {1}'.format(
            get_course_about_section(course, "title"), course_mode.name)
        item.currency = currency
        order.currency = currency
        order.save()
        item.save()
        return item
예제 #33
0
def tnl_course_add(request):
    """
    Adds the requested course to the TNL enabled courses and registers it with TNL.
    """
    try:
        # Load the selected course.
        course = course_from_id(request.POST.get('course'))
        # Load the selected Domain.
        domain = request.POST.get('domain')
        # Create a TNL Instance.
        tnl_instance = TNLInstance(domain)
        # Register the course with TNL.
        tnl_instance.register_course(course)
        return HttpResponse(json.dumps({'success': True}), mimetype='application/json')
    except:
        return HttpResponse(json.dumps({'success': False}), mimetype='application/json')
예제 #34
0
    def get(self, request, course_id):
        """
        """
        # If the user has already been verified within the given time period,
        # redirect straight to the payment -- no need to verify again.
        if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
            return redirect(
                reverse('verify_student_verified',
                        kwargs={'course_id': course_id}))
        elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        else:
            # If they haven't completed a verification attempt, we have to
            # restart with a new one. We can't reuse an older one because we
            # won't be able to show them their encrypted photo_id -- it's easier
            # bookkeeping-wise just to start over.
            progress_state = "start"

        verify_mode = CourseMode.mode_for_course(course_id, "verified")
        # if the course doesn't have a verified mode, we want to kick them
        # from the flow
        if not verify_mode:
            return redirect(reverse('dashboard'))
        if course_id in request.session.get("donation_for_course", {}):
            chosen_price = request.session["donation_for_course"][course_id]
        else:
            chosen_price = verify_mode.min_price

        course = course_from_id(course_id)
        context = {
            "progress_state": progress_state,
            "user_full_name": request.user.profile.name,
            "course_id": course_id,
            "course_name": course.display_name_with_default,
            "course_org" : course.display_org_with_default,
            "course_num" : course.display_number_with_default,
            "purchase_endpoint": get_purchase_endpoint(),
            "suggested_prices": [
                decimal.Decimal(price)
                for price in verify_mode.suggested_prices.split(",")
            ],
            "currency": verify_mode.currency.upper(),
            "chosen_price": chosen_price,
            "min_price": verify_mode.min_price,
        }

        return render_to_response('verify_student/photo_verification.html', context)
예제 #35
0
    def get(self, request, course_id, error=None):
        if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
            return redirect(reverse('dashboard'))
        modes = CourseMode.modes_for_course_dict(course_id)
        context = {
            "course_id": course_id,
            "modes": modes,
            "course_name": course_from_id(course_id).display_name,
            "chosen_price": None,
            "error": error,
        }
        if "verified" in modes:
            context["suggested_prices"] = modes["verified"].suggested_prices.split(",")
            context["currency"] = modes["verified"].currency.upper()
            context["min_price"] = modes["verified"].min_price

        return render_to_response("course_modes/choose.html", context)
예제 #36
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for the verification flow.
    """
    if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
        return redirect(reverse('dashboard'))

    upgrade = request.GET.get('upgrade', False)
    course = course_from_id(course_id)
    context = {
        "course_id": course_id,
        "course_name": course.display_name_with_default,
        "course_org": course.display_org_with_default,
        "course_num": course.display_number_with_default,
        "is_not_active": not request.user.is_active,
        "upgrade": upgrade,
    }
    return render_to_response("verify_student/show_requirements.html", context)
예제 #37
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for the verification flow.
    """
    if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
        return redirect(reverse('dashboard'))

    upgrade = request.GET.get('upgrade', False)
    course = course_from_id(course_id)
    context = {
        "course_id": course_id,
        "course_name": course.display_name_with_default,
        "course_org": course.display_org_with_default,
        "course_num": course.display_number_with_default,
        "is_not_active": not request.user.is_active,
        "upgrade": upgrade,
    }
    return render_to_response("verify_student/show_requirements.html", context)
예제 #38
0
    def get(self, request, course_id, error=None):
        if CourseEnrollment.enrollment_mode_for_user(request.user,
                                                     course_id) == 'verified':
            return redirect(reverse('dashboard'))
        modes = CourseMode.modes_for_course_dict(course_id)
        context = {
            "course_id": course_id,
            "modes": modes,
            "course_name": course_from_id(course_id).display_name,
            "chosen_price": None,
            "error": error,
        }
        if "verified" in modes:
            context["suggested_prices"] = modes[
                "verified"].suggested_prices.split(",")
            context["currency"] = modes["verified"].currency.upper()
            context["min_price"] = modes["verified"].min_price

        return render_to_response("course_modes/choose.html", context)
예제 #39
0
    def get(self, request, course_id):
        """
        display this view
        """
        course = course_from_id(course_id)
        course_enrollment = CourseEnrollment.get_or_create_enrollment(request.user, course_id)
        course_enrollment.update_enrollment(mode="verified")
        course_enrollment.emit_event(EVENT_NAME_USER_ENTERED_MIDCOURSE_REVERIFY_VIEW)
        context = {
            "user_full_name": request.user.profile.name,
            "error": False,
            "course_id": course_id,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "reverify": True,
        }

        return render_to_response("verify_student/midcourse_photo_reverification.html", context)
예제 #40
0
    def get(self, request, course_id):
        """
        display this view
        """
        course = course_from_id(course_id)
        course_enrollment = CourseEnrollment.get_or_create_enrollment(request.user, course_id)
        course_enrollment.update_enrollment(mode="verified")
        course_enrollment.emit_event(EVENT_NAME_USER_ENTERED_MIDCOURSE_REVERIFY_VIEW)
        context = {
            "user_full_name": request.user.profile.name,
            "error": False,
            "course_id": course_id,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "reverify": True,
        }

        return render_to_response("verify_student/midcourse_photo_reverification.html", context)
예제 #41
0
    def get(self, request, course_id):
        """
        Handle the case where we have a get request
        """
        upgrade = request.GET.get('upgrade', False)
        course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        if CourseEnrollment.enrollment_mode_for_user(request.user,
                                                     course_id) == 'verified':
            return redirect(reverse('dashboard'))
        verify_mode = CourseMode.mode_for_course(course_id, "verified")

        if verify_mode is None:
            return redirect(reverse('dashboard'))

        chosen_price = request.session.get("donation_for_course", {}).get(
            course_id.to_deprecated_string(), verify_mode.min_price)

        course = course_from_id(course_id)
        context = {
            "course_id":
            course_id.to_deprecated_string(),
            "course_modes_choose_url":
            reverse('course_modes_choose',
                    kwargs={'course_id': course_id.to_deprecated_string()}),
            "course_name":
            course.display_name_with_default,
            "course_org":
            course.display_org_with_default,
            "course_num":
            course.display_number_with_default,
            "purchase_endpoint":
            get_purchase_endpoint(),
            "currency":
            verify_mode.currency.upper(),
            "chosen_price":
            chosen_price,
            "create_order_url":
            reverse("verify_student_create_order"),
            "upgrade":
            upgrade,
        }
        return render_to_response('verify_student/verified.html', context)
예제 #42
0
def show_requirements(request, course_id):
    """
    Show the requirements necessary for the verification flow.
    """
    course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
        return redirect(reverse('dashboard'))

    upgrade = request.GET.get('upgrade', False)
    course = course_from_id(course_id)
    context = {
        "course_id": course_id.to_deprecated_string(),
        "course_modes_choose_url": reverse("course_modes_choose", kwargs={'course_id': course_id.to_deprecated_string()}),
        "verify_student_url": reverse('verify_student_verify', kwargs={'course_id': course_id.to_deprecated_string()}),
        "course_name": course.display_name_with_default,
        "course_org": course.display_org_with_default,
        "course_num": course.display_number_with_default,
        "is_not_active": not request.user.is_active,
        "upgrade": upgrade,
    }
    return render_to_response("verify_student/show_requirements.html", context)
예제 #43
0
 def single_item_receipt_context(self):
     course = course_from_id(self.course_id)
     return {
         "course_id":
         self.course_id,
         "course_name":
         course.display_name_with_default,
         "course_org":
         course.display_org_with_default,
         "course_num":
         course.display_number_with_default,
         "course_start_date_text":
         course.start_date_text,
         "course_has_started":
         course.start > datetime.today().replace(tzinfo=pytz.utc),
         "course_root_url":
         reverse(
             'course_root',
             kwargs={'course_id': self.course_id.to_deprecated_string()}  # pylint: disable=no-member
         ),
         "dashboard_url":
         reverse('dashboard'),
     }
예제 #44
0
    def add_to_order(cls, order, course_id, mode_slug=CourseMode.DEFAULT_MODE_SLUG, cost=None, currency=None):
        """
        A standardized way to create these objects, with sensible defaults filled in.
        Will update the cost if called on an order that already carries the course.

        Returns the order item
        """
        # TODO: Possibly add checking for whether student is already enrolled in course
        course = course_from_id(course_id)  # actually fetch the course to make sure it exists, use this to
        # throw errors if it doesn't

        ### handle default arguments for mode_slug, cost, currency
        course_mode = CourseMode.mode_for_course(course_id, mode_slug)
        if not course_mode:
            # user could have specified a mode that's not set, in that case return the DEFAULT_MODE
            course_mode = CourseMode.DEFAULT_MODE
        if not cost:
            cost = course_mode.min_price
        if not currency:
            currency = course_mode.currency

        super(PaidCourseRegistration, cls).add_to_order(order, course_id, cost, currency=currency)

        item, created = cls.objects.get_or_create(order=order, user=order.user, course_id=course_id)
        item.status = order.status

        item.mode = course_mode.slug
        item.qty = 1
        item.unit_cost = cost
        item.line_desc = "Registration for Course: {0}. Mode: {1}".format(
            get_course_about_section(course, "title"), course_mode.name
        )
        item.currency = currency
        order.currency = currency
        order.save()
        item.save()
        return item
def load_enrollment_courses(request):
    r = list()
    complete_course = list()
    current_course = list()
    user = User.objects.get(id=request.POST.get('user_id'))
    enrollment_type = request.POST.get('type')
    for enrollment in CourseEnrollment.enrollments_for_user(user):
        try:
            course = course_from_id(enrollment.course_id)
            field_data_cache = FieldDataCache([course], course.id, user)
            course_instance = get_module(user, request, course.location, field_data_cache, course.id, grade_bucket_type='ajax')
            item = {'name': str(course.display_coursenumber) + ' ' + course.display_name}
            if course_instance.complete_course:
                complete_course.append(item)
            else:
                current_course.append(item)
        except ItemNotFoundError:
            log.error("User {0} enrolled in non-existent course {1}".format(user.username, enrollment.course_id))
    if enrollment_type == 'complete':
        r = complete_course
    else:
        r = current_course
    r.sort(key=lambda x: x['name'], reverse=False)
    return HttpResponse(json.dumps(r), content_type="application/json")
def render_body(context,**pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs)
        total_discussions = context.get('total_discussions', UNDEFINED)
        csrf_token = context.get('csrf_token', UNDEFINED)
        trending = context.get('trending', UNDEFINED)
        users = context.get('users', UNDEFINED)
        def title():
            return render_title(context.locals_(__M_locals))
        request = context.get('request', UNDEFINED)
        facilitator = context.get('facilitator', UNDEFINED)
        community = context.get('community', UNDEFINED)
        courses = context.get('courses', UNDEFINED)
        enumerate = context.get('enumerate', UNDEFINED)
        discussions = context.get('discussions', UNDEFINED)
        pager = context.get('pager', UNDEFINED)
        resources = context.get('resources', UNDEFINED)
        __M_writer = context.writer()
        # SOURCE LINE 1
        __M_writer(u'\r\n')
        # SOURCE LINE 11
        __M_writer(u'\r\n')
        # SOURCE LINE 12
        __M_writer(u'\r\n')
        if 'parent' not in context._data or not hasattr(context._data['parent'], 'title'):
            context['self'].title(**pageargs)
        

        # SOURCE LINE 15
        __M_writer(u'\r\n<script type="text/javascript" src="/static/js/admin_ui_controls.js"></script>\r\n<script type="text/javascript" src="https://secure.skypeassets.com/i/scom/js/skype-uri.js"></script>\r\n<script type="text/javascript" src="/static/js/ckeditor/ckeditor.js" charset="utf-8"></script>\r\n<style type="text/css" media="screen">\r\n    #community-main {\r\n        width: 1185px;\r\n        margin: 30px auto;\r\n        text-align: left;\r\n    }\r\n    #community-main-content {\r\n        width: 880px;\r\n        float: left;\r\n    }\r\n    #community-main-sidebar {\r\n        width: 266px;\r\n        float: right;\r\n        top: 0;\r\n        text-align: center;\r\n    }\r\n    #community-sidebar-header {\r\n        border: 2px solid #ddd;\r\n        height: 53px;\r\n        text-align: center;\r\n        vertical-align: middle;\r\n        font: 700 1.2em/2.4em "Open Sans",Verdana,Geneva,sans-serif;\r\n    }\r\n    #community-sidebar {\r\n        width: 208px;\r\n        padding: 20px 20px 0 20px;\r\n        border: 2px solid #ddd;\r\n        margin: auto;\r\n        border-top: 0;\r\n        text-align: left;\r\n    }\r\n    .sidebar-section {\r\n        margin: 0 0 20px 0;\r\n    }\r\n    #community-member {\r\n        margin-top: 10px;\r\n    }\r\n    .sidebar-section h2 {\r\n        border-bottom: 2px solid #90BF70;\r\n        padding-bottom: 5px;\r\n        margin: 0 0 10px 0;\r\n        color: #006EBF;\r\n        font-weight: bold;\r\n        text-transform: none;\r\n        font-size: 1em;\r\n        line-height: 1em;\r\n    }\r\n    .sidebar-sub-section {\r\n        margin: 0 10px;\r\n    }\r\n    .trending-title {\r\n        display: block;\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n    }\r\n    .trending-name {\r\n        font-size: 80%;\r\n        display: block;\r\n        margin-bottom: 5px;\r\n    }\r\n    .trending-name span {\r\n        font-weight: bold;\r\n    }\r\n    .status-name {\r\n        display: block;\r\n        margin-bottom: 5px;\r\n    }\r\n    #community-header {\r\n        border: 2px solid #ddd;\r\n        width: 100%;\r\n        position: relative;\r\n        min-height: 260px;\r\n    }\r\n    #community-header h1 {\r\n        text-align: left;\r\n        color: #006EBF;\r\n        margin: 15px 0 0 20px;\r\n        font-weight: bold;\r\n        font-size: 160%;\r\n    }\r\n    #community-header h2 {\r\n        margin: 15px 0 0 20px;\r\n        text-transform: none;\r\n        font-weight: bold;\r\n    }\r\n    #community-header h3 {\r\n        color: #006EBF;\r\n        padding: 10px 0;\r\n    }\r\n    #community-header h4 {\r\n        font-weight: bold;\r\n    }\r\n    #community-avatar {\r\n        width: 100px;\r\n        float: left;\r\n        margin: 0 15px 0 0;\r\n    }\r\n    #community-logo {\r\n        float: right;\r\n        width: 380px;\r\n        height: 260px;\r\n        overflow: hidden;\r\n        margin: 15px;\r\n        text-align: center;\r\n        background-color: white;\r\n    }\r\n    #community-logo img {\r\n        height: 260px;\r\n    }\r\n    .facilitator-wrap {\r\n        position: absolute;\r\n        width: 450px;\r\n        bottom: 20px;\r\n        left: 20px;\r\n    }\r\n    #community-content-area h1 {\r\n        color: #006EBF;\r\n        padding: 20px 3px;\r\n        font-size: 20px;\r\n        font-weight: bold;\r\n        text-align: left;\r\n        border-bottom: 2px solid #90BF70;\r\n        display: inline-block;\r\n    }\r\n    #community-content h1 {\r\n        width: 100%;\r\n    }\r\n    #community-content, #community-discussions {\r\n        color: #000;\r\n        padding: 20px 3px;\r\n    }\r\n    #community-content-area label {\r\n        font-style: normal;\r\n        display: inline-block;\r\n        width: 3.5em;\r\n        text-align: left;\r\n        font-weight: bold;\r\n    }\r\n    #community-content-area span {\r\n        /*font-size: 12px;*/\r\n    }\r\n    #community-content {\r\n        width: 270px;\r\n        height: 700px;\r\n        float: left;\r\n    }\r\n    #community-content-scroller {\r\n        width: 270px;\r\n        height: 640px;\r\n        overflow-y: scroll;\r\n        overflow-x: hidden;\r\n    }\r\n    #community-discussions {\r\n        width: 578px;\r\n        margin-right: 20px;\r\n        float: left;\r\n    }\r\n    .discussion {\r\n        clear: both;\r\n        position: relative;\r\n        border: 2px solid #ddd;\r\n        border-radius: 10px;\r\n        padding: 15px 20px 15px 94px;\r\n        background-color: #fff;\r\n        margin-bottom: 15px;\r\n    }\r\n    .discussion h2 {\r\n        margin-bottom: 5px;\r\n        width: 370px;\r\n        white-space: nowrap;\r\n        overflow: hidden;\r\n        text-overflow: ellipsis;\r\n    }\r\n    .discussion-post-info-header {\r\n        float: left;\r\n        width: 463px;\r\n    }\r\n    .discussion-post-info div {\r\n        display: inline-block;\r\n    }\r\n    .discussion-post-info span {\r\n        font-weight: bold;\r\n    }\r\n    .discussion-byline {\r\n        overflow: hidden;\r\n        height: 1.5em;\r\n        width: 370px;\r\n        white-space: nowrap;\r\n        text-overflow: ellipsis;\r\n    }\r\n    .discussion-stats-header {\r\n        float: left;\r\n        width: 100px;\r\n    }\r\n    .discussion-stats {\r\n        float: right;\r\n        width: 80px;\r\n    }\r\n    .discussion-stats span {\r\n        display: block;\r\n    }\r\n    .discussion-avatar {\r\n        position: absolute;\r\n        width: 64px;\r\n        display: block;\r\n        top: 15px;\r\n        left: 20px;\r\n    }\r\n    .community-clear {\r\n        clear: both;\r\n        height: 1px;\r\n        margin-top: -1px;\r\n    }\r\n    #discussion-pager {\r\n        text-align: center;\r\n        line-height: 24px;\r\n        clear: both;\r\n        margin: 20px 0;\r\n    }\r\n    #discussion-pager a {\r\n        width: auto;\r\n        line-height: 24px;\r\n        padding: 2px 5px;\r\n        color: #333;\r\n        border: 1px solid #ccc;\r\n        margin-left: 3px;\r\n    }\r\n    #discussion-pager a:hover {\r\n        color: #ff6600;\r\n    }\r\n    #discussion-pager .up_page {\r\n        display: inline-block;\r\n        width: 17px !important;\r\n        line-height: 24px;\r\n        height: 20px;\r\n        background: url(/static/tmp-resource/image/up_page.png) no-repeat;\r\n        border: none;\r\n        vertical-align: middle;\r\n    }\r\n    #discussion-pager .next_page {\r\n        display: inline-block;\r\n        width: 17px !important;\r\n        height: 20px;\r\n        background: url(/static/tmp-resource/image/next_page.png) no-repeat;\r\n        border: none;\r\n        margin-left: 13px;\r\n        vertical-align: middle;\r\n    }\r\n    #discussion-pager .page_active {\r\n        color: #ff6600 !important;\r\n    }\r\n    #discussion-pager .page_active:hover {\r\n        color: #ff9933 !important;\r\n    }\r\n    #discussion-pager .page_num {\r\n        display: inline-block;\r\n        padding: 2px 5px;\r\n    }\r\n    div.cke{\r\n        width:580px;\r\n    }\r\n    .community-resource {\r\n        display: block;\r\n        clear: both;\r\n        margin-bottom: 20px;\r\n        border: 0 solid #f0870c;\r\n        height: 160px;\r\n        width: 242px;\r\n        box-shadow: rgba(0, 0, 0, 0.1) 3px 7px 7px 0;\r\n        border-radius: 6px;\r\n        overflow: hidden;\r\n        position: relative;\r\n    }\r\n    .community-resource img {\r\n        display: block;\r\n        width: 242px;\r\n        border-radius: 6px;\r\n    }\r\n    .community-resource a {\r\n        display: block;\r\n        position: absolute;\r\n        bottom: 0;\r\n        left: 0;\r\n        height: 60px;\r\n        background: #f0870c;\r\n        color: #fff;\r\n        font-size: 14px;\r\n        border-radius: 0 0 6px 6px;\r\n    }\r\n    .community-resource div {\r\n        display: table-cell;\r\n        height: 60px;\r\n        vertical-align: middle;\r\n        width: 242px;\r\n        text-align: center;\r\n    }\r\n    #table-members th {\r\n        color: #006EBF;\r\n        padding: 20px 3px;\r\n        font-size: 20px;\r\n    }\r\n    .card-link span {\r\n        color: #FFFFFF;\r\n    }\r\n    .course-card {\r\n        margin: 0 0 20px 0 !important\r\n    }\r\n    div.card-bottom table tr:nth-child(2) {\r\n        display: none;\r\n    }\r\n    #members {\r\n        display: inline-block;\r\n        overflow-x: hidden;\r\n        padding: 10px 0;\r\n        width: 100%;\r\n        position: relative;\r\n    }\r\n    #members a {\r\n        margin-right: 5px;\r\n        display: inline-block;\r\n    }\r\n    #members a img {\r\n        vertical-align: middle;\r\n    }\r\n    .modal {\r\n        position: absolute;\r\n        opacity: 1;\r\n        z-index: 101;\r\n        left: 50%;\r\n        margin-left: -349px;\r\n        top: 40px;\r\n        background: none repeat scroll 0 0 rgba(255, 255, 255, 1);\r\n        border-radius: 5px;\r\n        box-shadow: 0px 15px 80px 15px rgba(0, 0, 0, 0.5);\r\n        padding: 0 0 8px 0;\r\n        width: 680px;\r\n        display: none;\r\n    }\r\n    #fixed-dialog, #skype-dialog {\r\n        position: fixed;\r\n    }\r\n    .modal .close-modal {\r\n        border-radius: 2px;\r\n        cursor: pointer;\r\n        display: inline-block;\r\n        vertical-align: baseline;\r\n        padding: 10px;\r\n        position: absolute;\r\n        right: 2px;\r\n        top: 0;\r\n        z-index: 3;\r\n        color: #333;\r\n    }\r\n    .modal .titlebar {\r\n        height: 70px;\r\n        background: #ccc;\r\n    }\r\n    .modal .dialog-title {\r\n        margin: 0;\r\n        padding: 20px 0 0 30px;\r\n        color: #666;\r\n    }\r\n    .modal .content {\r\n        color: #333;\r\n        text-align: left;\r\n        font-size: 16px;\r\n        padding: 20px 10px;\r\n        line-height: 20px;\r\n    }\r\n    .modal .discussion-error {\r\n        color: #f00;\r\n        font-weight: bold;\r\n        font-size: 120%;\r\n        line-height: 120%;\r\n    }\r\n    .modal .inner-wrapper form textarea {\r\n        height: 100px;\r\n    }\r\n    .hangout_container {\r\n        text-align: center;\r\n        padding-top: 20px;\r\n    }\r\n    .hangout_container img {\r\n        width: 120px;\r\n        vertical-align: top;\r\n    }\r\n    .hangout_container .side-button {\r\n        background: #8cbe41 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAAJdnBBZwAAABQAAAAUAKM7KtEAAAB2SURBVCjPY/zPQBxgIlIdTRReYfiPFZ5HUsXNMJ/hP24A06P9/8r//4QVpvz/CuHgU8jzfzGCgxvo/b+O4DD+xx3iPxg4iAue38SGoynDZSQeXs9w/p9NjGcgwRPz/zNxChn+a0IC/AoOZVeR4pP7/3zGIZAeAdFoNZxQb6AuAAAAAElFTkSuQmCC) no-repeat 10px 10px;\r\n        height: 20px;\r\n    }\r\n    .side-button {\r\n        color: white !important;\r\n        display: block;\r\n        padding: 10px;\r\n        border-width: 1px;\r\n        border-style: solid;\r\n        text-align: center;\r\n        margin-top: 5px;\r\n    }\r\n    .blue-button {\r\n        border-color: #45719E;\r\n        background: #5A9BD5;\r\n    }\r\n    .green-button {\r\n        border-color: #595;\r\n        background: #8cbe41;\r\n    }\r\n    .red-button {\r\n        border-color: #df0000;\r\n        background: #ED2828;\r\n    }\r\n    #poll-form {\r\n        display: none;\r\n        margin-top: 15px;\r\n        clear: both;\r\n    }\r\n    .poll-answer-input {\r\n        width: 80% !important;\r\n        display: inline !important;\r\n    }\r\n    .discussion-attachment {\r\n        float: left;\r\n        padding-top: 16px;\r\n    }\r\n    .discussion-poll {\r\n        float: right;\r\n        display: block;\r\n        vertical-align: middle;\r\n        padding-top: 16px;\r\n    }\r\n    #members-title {\r\n        border-bottom: 2px solid #90BF70;\r\n        color: #006EBF;\r\n        font-size: 20px;\r\n        padding: 20px 3px;\r\n        font-weight: bold;\r\n        clear: both;\r\n    }\r\n    #table-members {\r\n        width: 100%;\r\n        table-layout: fixed;\r\n        margin-bottom: 20px;\r\n    }\r\n    #table-members tr {\r\n        border-bottom: 2px solid #90BF70;\r\n    }\r\n    .member-arrows {\r\n        width: 20px;\r\n        vertical-align: middle;\r\n    }\r\n    .member-arrows div {\r\n        cursor: pointer;\r\n        width: 17px;\r\n        height: 20px;\r\n    }\r\n    .member-arrow-left {\r\n        background: url(/static/tmp-resource/image/up_page.png);\r\n    }\r\n    .member-arrow-right {\r\n        background: url(/static/tmp-resource/image/next_page.png);\r\n    }\r\n    .member-column {\r\n        white-space: nowrap;\r\n    }\r\n    .discussion-error-box {\r\n        border-color: red !important;\r\n    }\r\n    #create-skype {\r\n        float: left;\r\n        margin: 0 20px 0 0;\r\n    }\r\n    .skype-container {\r\n        float: left;\r\n    }\r\n    .skype-button .side-button {\r\n        background: #5A9BD5 url(https://swx.cdn.skype.com/skypewebsdk/shareButton/v/latest/assets/images/s_logo.svg) no-repeat 10px 10px/20px 20px;\r\n        height: 20px;\r\n    }\r\n</style>\r\n<link rel="stylesheet" type="text/css"  href="static/tmp-resource/css/ppd-general01.css"/>\r\n<body style="text-align:center">\r\n<div id="community-main" class="clearfix">\r\n    <section id="community-main-content">\r\n        <div id="community-header">\r\n')
        # SOURCE LINE 504
        if community.logo:
            # SOURCE LINE 505
            __M_writer(u'                <div id="community-logo"><img src="')
            __M_writer(filters.decode.utf8(get_file_url(community.logo)))
            __M_writer(u'" alt="Community Logo"/></div>\r\n')
        # SOURCE LINE 507
        __M_writer(u'            <h1>')
        __M_writer(filters.decode.utf8(community.name))
        __M_writer(u'</h1>\r\n            <h2>')
        # SOURCE LINE 508
        __M_writer(filters.decode.utf8(community.motto))
        __M_writer(u'</h2>\r\n')
        # SOURCE LINE 509
        if facilitator:
            # SOURCE LINE 510
            __M_writer(u'                <div class="facilitator-wrap">\r\n                    <img src="')
            # SOURCE LINE 511
            __M_writer(filters.decode.utf8(reverse('user_photo', args=[facilitator.user.id])))
            __M_writer(u'" id="community-avatar" alt="Facilitator Avatar" />\r\n                    <h3>')
            # SOURCE LINE 512
            __M_writer(filters.decode.utf8(facilitator.user.first_name))
            __M_writer(u' ')
            __M_writer(filters.decode.utf8(facilitator.user.last_name))
            __M_writer(u'</h3>\r\n                    <h4>Community Facilitator</h4>\r\n                </div>\r\n')
        # SOURCE LINE 516
        __M_writer(u'            <div class="community-clear"></div>\r\n        </div>\r\n\r\n        <div id="community-content-area">\r\n            <div id="community-discussions">\r\n                <a name="discussions"></a>\r\n                <h1 class="discussion-post-info-header">Community Discussion</h1>\r\n                <h1 class="discussion-stats-header">Activity</h1>\r\n                <div class="discussions">\r\n')
        # SOURCE LINE 525
        for i,d in enumerate(discussions):
            # SOURCE LINE 526
            __M_writer(u'                    <div class="discussion">\r\n                        <img class="discussion-avatar" src="')
            # SOURCE LINE 527
            __M_writer(filters.decode.utf8(reverse('user_photo', args=[d.user.id])))
            __M_writer(u'">\r\n                        <div class="discussion-stats">\r\n                            <span>Replies: ')
            # SOURCE LINE 529
            __M_writer(filters.decode.utf8(d.replies))
            __M_writer(u'</span>\r\n                            <span>Views: ')
            # SOURCE LINE 530
            __M_writer(filters.decode.utf8(d.views))
            __M_writer(u'</span>\r\n                        </div>\r\n                        <h2><a href="')
            # SOURCE LINE 532
            __M_writer(filters.decode.utf8(reverse('community_discussion_view', args=[d.id])))
            __M_writer(u'">')
            __M_writer(filters.decode.utf8(d.subject))
            __M_writer(u'</a></h2>\r\n                        <div class="discussion-post-info">\r\n                            <div class="discussion-byline"><span>Posted By: </span>')
            # SOURCE LINE 534
            __M_writer(filters.decode.utf8(d.user.first_name))
            __M_writer(u' ')
            __M_writer(filters.decode.utf8(d.user.last_name))
            __M_writer(u'</div>\r\n                            <div class="discussion-date"><span> On: </span>')
            # SOURCE LINE 535
            __M_writer(filters.decode.utf8('{dt:%b}. {dt.day}, {dt.year}'.format(dt=d.date_create)))
            __M_writer(u'</div>\r\n                        </div>\r\n                        <div class="community-clear"></div>\r\n                    </div>\r\n')
        # SOURCE LINE 540
        __M_writer(u'                </div>\r\n                <div id="discussion-pager">\r\n                    <span>Total Discussions: ')
        # SOURCE LINE 542
        __M_writer(filters.decode.utf8(pager['total']))
        __M_writer(u'</span>&nbsp;&nbsp;&nbsp;\r\n')
        # SOURCE LINE 543
        if pager['page'] > 1:
            # SOURCE LINE 544
            __M_writer(u'                        <a href="#discussions" onclick="replaceDiscussions(')
            __M_writer(filters.decode.utf8(pager['page']-1))
            __M_writer(u')" class="up_page"></a>\r\n')
        # SOURCE LINE 546
        for p in pager['jumps']:
            # SOURCE LINE 547
            if p=='c':
                # SOURCE LINE 548
                __M_writer(u'                            <a href="#discussions" onclick="replaceDiscussions(')
                __M_writer(filters.decode.utf8(pager['page']))
                __M_writer(u')" class="page_active">')
                __M_writer(filters.decode.utf8(pager['page']))
                __M_writer(u'</a>\r\n')
                # SOURCE LINE 549
            else:
                # SOURCE LINE 550
                __M_writer(u'                            <a href="#discussions" onclick="replaceDiscussions(')
                __M_writer(filters.decode.utf8(p))
                __M_writer(u')">')
                __M_writer(filters.decode.utf8(p))
                __M_writer(u'</a>\r\n')
        # SOURCE LINE 553
        if pager['pages'] > pager['page']:
            # SOURCE LINE 554
            __M_writer(u'                        <a href="#discussions" onclick="replaceDiscussions(')
            __M_writer(filters.decode.utf8(pager['page']+1))
            __M_writer(u')" class="next_page"></a>\r\n')
        # SOURCE LINE 556
        __M_writer(u'                </div>\r\n            </div>\r\n            <div id="community-content">\r\n                <h1>Content Collections</h1>\r\n                <div id="community-content-scroller">\r\n')
        # SOURCE LINE 561
        for i,cc in enumerate(courses):
            # SOURCE LINE 562
            __M_writer(u'                        ')
            c=course_from_id(cc.course) 
            
            __M_locals_builtin_stored = __M_locals_builtin()
            __M_locals.update(__M_dict_builtin([(__M_key, __M_locals_builtin_stored[__M_key]) for __M_key in ['c'] if __M_key in __M_locals_builtin_stored]))
            __M_writer(u'\r\n                        ')
            # SOURCE LINE 563
            runtime._include_file(context, u'../course.html', _template_uri, course=c)
            __M_writer(u'\r\n')
        # SOURCE LINE 565
        for i,r in enumerate(resources):
            # SOURCE LINE 566
            __M_writer(u'                        <div class="community-resource">\r\n                            <img src="')
            # SOURCE LINE 567
            __M_writer(filters.decode.utf8(get_file_url(r.logo)))
            __M_writer(u'" alt="')
            __M_writer(filters.decode.utf8(r.name))
            __M_writer(u'" />\r\n                            <a href="')
            # SOURCE LINE 568
            __M_writer(filters.decode.utf8(r.link))
            __M_writer(u'" target="_blank">\r\n                                <div>\r\n                                    ')
            # SOURCE LINE 570
            __M_writer(filters.decode.utf8(r.name))
            __M_writer(u'\r\n                                </div>\r\n                            </a>\r\n                        </div>\r\n')
        # SOURCE LINE 575
        __M_writer(u'                </div>\r\n            </div>\r\n        </div>\r\n        \r\n        <div id="members-title">Members</div>\r\n        <table id="table-members" cellspacing="" cellpadding="" border="0">\r\n            <tr>\r\n                <td class="member-arrows">\r\n                    <div class="member-arrow-left" onclick="left()"> </div>\r\n                </td>\r\n                <td class="member-column">\r\n                    <div id="members">\r\n')
        # SOURCE LINE 587
        for u in users:
            # SOURCE LINE 588
            __M_writer(u'                            <a href="')
            __M_writer(filters.decode.utf8(reverse('dashboard',args=[u.user.id])))
            __M_writer(u'" target="_blank">\r\n                                <img src="')
            # SOURCE LINE 589
            __M_writer(filters.decode.utf8(reverse('user_photo',args=[u.user.id])))
            __M_writer(u'" alt="')
            __M_writer(filters.decode.utf8(u.user.first_name))
            __M_writer(u'" />\r\n                            </a>\r\n')
        # SOURCE LINE 592
        __M_writer(u'                    </div>\r\n                </td>\r\n                <td class="member-arrows">\r\n                    <div class="member-arrow-right" onclick="right()"></div>\r\n                </td>\r\n            </tr>\r\n        </table>\r\n    </section>\r\n    <section id="community-main-sidebar">\r\n        <div id="community-sidebar-header">\r\n            ')
        # SOURCE LINE 602
        __M_writer(filters.decode.utf8(request.user.username))
        __M_writer(u'\r\n        </div>\r\n        <div id="community-sidebar">\r\n            <div class="sidebar-section" style="text-align: center;">\r\n                <img src="/static/images/pcg_columns_transparent.png" alt="PCG Logo" />\r\n')
        # SOURCE LINE 607
        if is_member(request.user, community):
            # SOURCE LINE 608
            __M_writer(u'                    <div id="community-member">MEMBER</div>\r\n')
            # SOURCE LINE 609
        else:
            # SOURCE LINE 610
            __M_writer(u'                    <a href="#" class="side-button green-button" onclick="joinMe()">Add Me</a>\r\n')
        # SOURCE LINE 612
        __M_writer(u'            </div>\r\n            <div class="sidebar-section">\r\n                <h2>Community Status</h2>\r\n                <div class="sidebar-sub-section">\r\n                    <span class="status-name">Discussions: ')
        # SOURCE LINE 616
        __M_writer(filters.decode.utf8(total_discussions))
        __M_writer(u'</span>\r\n                    <!--<span class="trending-name">Messages: </span>-->\r\n                    <span class="status-name">Members: ')
        # SOURCE LINE 618
        __M_writer(filters.decode.utf8(users.count()))
        __M_writer(u'</span>\r\n                </div>\r\n            </div>\r\n            <div class="sidebar-section">\r\n                <h2>Trending</h2>\r\n                <div class="sidebar-sub-section">\r\n')
        # SOURCE LINE 624
        for i, d in enumerate(trending):
            # SOURCE LINE 625
            __M_writer(u'                        <span class="trending-title"><a href="')
            __M_writer(filters.decode.utf8(reverse('community_discussion_view', args=[d.id])))
            __M_writer(u'">')
            __M_writer(filters.decode.utf8(d.subject))
            __M_writer(u'</a></span>\r\n                        <span class="trending-name"><span>Posted: </span>')
            # SOURCE LINE 626
            __M_writer(filters.decode.utf8('{dt:%b}. {dt.day}, {dt.year}'.format(dt=d.date_create)))
            __M_writer(u'</span>\r\n')
        # SOURCE LINE 628
        __M_writer(u'                </div>\r\n            </div>\r\n            <div class="sidebar-section">\r\n                <a href="')
        # SOURCE LINE 631
        __M_writer(filters.decode.utf8(reverse('communities')))
        __M_writer(u'" class="blue-button side-button">My Communities</a>\r\n')
        # SOURCE LINE 632
        if is_member(request.user, community) or request.user.is_superuser:
            # SOURCE LINE 633
            __M_writer(u'                    <a href="#" class="blue-button side-button" id="newDiscussionButton" onclick="newDiscussion()">Start a New Discussion</a>\r\n')
        # SOURCE LINE 635
        if is_facilitator(request.user, community) or request.user.is_superuser:
            # SOURCE LINE 636
            __M_writer(u'                    <a href="')
            __M_writer(filters.decode.utf8(reverse('community_edit',args=[community.id])))
            __M_writer(u'" class="green-button side-button">Edit</a>\r\n                    <a href="')
            # SOURCE LINE 637
            __M_writer(filters.decode.utf8(reverse('community_delete',args=[community.id])))
            __M_writer(u'" class="red-button side-button delete-icon">Delete</a>\r\n                    <a href="')
            # SOURCE LINE 638
            __M_writer(filters.decode.utf8(reverse('community_mange_member',args=[community.id])))
            __M_writer(u'" class="blue-button side-button">Manage Members</a>\r\n')
        # SOURCE LINE 640
        if has_hangout_perms(request.user) and community.hangout:
            # SOURCE LINE 641
            __M_writer(u'                    <div class="hangout_container" id="hangout_div">\r\n                        <img src="/static/images/community_google_hangouts.png" class="" alt="" />\r\n                        <a class="side-button green-button" href="')
            # SOURCE LINE 643
            __M_writer(filters.decode.utf8(community.hangout))
            __M_writer(u'" target="_blank">Join Hangout</a>\r\n                    </div>\r\n')
        # SOURCE LINE 646
        if request.user.is_superuser:
            # SOURCE LINE 647
            __M_writer(u'                    <div class="skype-button">\r\n                        <a href="#" id="skype-start" class="side-button blue-button">Start Skype Call</a>\r\n                    </div>\r\n')
        # SOURCE LINE 651
        __M_writer(u'            </div>\r\n        </div>\r\n    </section>\r\n</div>\r\n<div style="" id="dialog" class="modal">\r\n    <div class="inner-wrapper" style="border:0;border-radius:5px;padding:0">\r\n        <div class="titlebar">\r\n            <h3 class="dialog-title"></h3>\r\n            <div class="close-modal" id="dialog_close">\u2715</div>\r\n        </div>\r\n        <div class="content"></div>\r\n    </div>\r\n</div>\r\n<div style="" id="fixed-dialog" class="modal">\r\n    <div class="inner-wrapper" style="border:0;border-radius:5px;padding:0">\r\n        <div class="titlebar">\r\n            <h3 class="dialog-title"></h3>\r\n            <div class="close-modal" id="dialog_close">\u2715</div>\r\n        </div>\r\n        <div class="content"></div>\r\n    </div>\r\n</div>\r\n<div style="" id="skype-dialog" class="modal">\r\n    <div class="inner-wrapper" style="border:0;border-radius:5px;padding:0">\r\n        <div class="titlebar">\r\n            <h3 class="dialog-title">Start Skype Call</h3>\r\n            <div class="close-modal" id="dialog_close">\u2715</div>\r\n        </div>\r\n        <div class="content">\r\n            <form>\r\n                <label>Participants (comma separated):<input type="text" name="skype-participants"></label>\r\n                <label>Topic (optional):<input type="text" name="skype-topic"></label>\r\n                <input type="button" value="Create" id="create-skype">\r\n                <div class="skype-container">\r\n                    <script type="text/javascript">\r\n                        function startSkype(params) {\r\n                            var skype_button = Skype.ui(params);\r\n                            if (skype_button) {\r\n                                var id = $(\'.skype-container\').attr(\'id\');\r\n                                $(\'#\' + id + \'_paraElement img\').css({\'margin\': \'0\', \'vertical-align\': \'0\'});\r\n                            }\r\n                        }\r\n                    </script>\r\n                </div>\r\n            </form>\r\n            <div class="community-clear"></div>\r\n        </div>\r\n    </div>\r\n</div>\r\n<script type="text/javascript">\r\n    function joinMe(){\r\n        var user_id = "')
        # SOURCE LINE 702
        __M_writer(filters.decode.utf8(request.user.id))
        __M_writer(u'";\r\n        $.post("')
        # SOURCE LINE 703
        __M_writer(filters.decode.utf8(reverse('community_join', args=[community.id])))
        __M_writer(u'",{user_ids:user_id}, function(r){\r\n            if(r.success)\r\n                window.location.reload();\r\n        });\r\n    }\r\n    function validateDiscussionForm() {\r\n        $(\'.discussion-error-box\').removeClass(\'discussion-error-box\');\r\n        var valid = true;\r\n        var errors = [\'The following errors occurred:\\n\'];\r\n        if (!/[A-Za-z]/.test($(\'.discussion-subject input\').val())) {\r\n            valid = false;\r\n            errors.push(\'Subject is required.\');\r\n            $(\'.discussion-subject input\').addClass(\'discussion-error-box\');\r\n        }\r\n        if (!/[A-Za-z]/.test($(\'.discussion-post textarea\').val())) {\r\n            valid = false;\r\n            errors.push(\'Discussion is required.\');\r\n            $(\'.discussion-post textarea\').addClass(\'discussion-error-box\');\r\n        }\r\n        if ($(\'#new-discussion-submit .poll-add\').is(\':checked\')) {\r\n            if (!/[A-Za-z]/.test($(\'.poll-question\').val())) {\r\n                valid = false;\r\n                errors.push(\'Question is required.\');\r\n                $(\'.poll-question\').addClass(\'discussion-error-box\');\r\n            }\r\n            if ($(\'.poll-answer-input\').length < 2) {\r\n                valid = false;\r\n                errors.push(\'You need at least two answers to choose from.\');\r\n            }\r\n            $(\'.poll-answer-input\').each(function() {\r\n                if (!/[A-Za-z]/.test($(this).val())) {\r\n                    valid = false;\r\n                    errors.push(\'Answers must be filled out.\');\r\n                    $(this).addClass(\'discussion-error-box\');\r\n                    return false;\r\n                }\r\n            });\r\n            if ($(\'.poll-expiration\').val() != \'\' && !/^\\d?\\d\\/\\d?\\d\\/\\d\\d\\d\\d$/.test($(\'.poll-expiration\').val())) {\r\n                valid = false;\r\n                errors.push(\'Expiration date must be in the format mm/dd/yyyy.\');\r\n                $(\'.poll-expiration\').addClass(\'discussion-error-box\');\r\n            }\r\n        }\r\n        if (!valid) {\r\n            var error = errors.join(\'\\n\');\r\n            alert(error);\r\n        }\r\n        return valid;\r\n    }\r\n    function newDiscussion() {\r\n        var content = \'<form id="new-discussion-submit" action="')
        # SOURCE LINE 753
        __M_writer(filters.decode.utf8(reverse('community_discussion_add')))
        __M_writer(u'" method="post" enctype="multipart/form-data">\';\r\n        content += \'<label class="discussion-subject">Subject:<input type="text" name="subject"></label>\';\r\n        content += \'<label class="discussion-post">Discussion:<textarea name="post" id="post"></textarea></label>\';\r\n        content += \'<label class="discussion-attachment">Attachment:<input type="file" name="attachment"></label>\';\r\n        content += \'<label class="discussion-poll"><img src="/static/images/poll-icon.png" alt="Add Poll"> <input type="checkbox" class="poll-add"> Add Poll</label>\';\r\n        content += \'<div id="poll-form">\';\r\n        content += \'<label>Question: <input class="poll-question" type="text" name="question"></label>\';\r\n        content += \'<label>Answers: <ol id="poll-answers">\';\r\n        content += \'<li class="poll-answer">\';\r\n        content += \'<input class="poll-answer-input" type="text" name="answers[0]">\';\r\n        content += \'</li>\';\r\n        content += \'<li class="poll-answer">\';\r\n        content += \'<input class="poll-answer-input" type="text" name="answers[1]"> <input type="button" class="add operation" value="+">\';\r\n        content += \'</li>\';\r\n        content += \'</ol></label>\';\r\n        content += \'<label>Expiration Date: <input class="poll-expiration" type="text" name="expiration" placeholder="mm/dd/yyyy"></label>\';\r\n        content += \'</div>\';\r\n        content += \'<input type="hidden" value="')
        # SOURCE LINE 770
        __M_writer(filters.decode.utf8(community.id))
        __M_writer(u'" name="community_id">\';\r\n        content += \'<input type="hidden" name="csrfmiddlewaretoken" value="')
        # SOURCE LINE 771
        __M_writer(filters.decode.utf8(csrf_token))
        __M_writer(u'"/>\';\r\n        content += \'<div class="community-clear"></div><br/>\';\r\n        content += \'<input type="submit" name="submit" value="Add">\';\r\n        content += \'</form><div class="discussion-error"></div>\';\r\n        var discussion_dialog = new Dialog($(\'#dialog\'));\r\n        discussion_dialog.show(\'New Discussion\', content);\r\n        CKEDITOR.replace(\'post\');\r\n\r\n        $(\'#new-discussion-submit\').submit(function(event) {\r\n            event.preventDefault();\r\n            for (var instanceName in CKEDITOR.instances) {\r\n                CKEDITOR.instances[instanceName].updateElement();\r\n            }\r\n            if (validateDiscussionForm()) {\r\n                var formData = new FormData($(this)[0]);\r\n                var formSelector = $(this);\r\n                $.ajax({\r\n                    url: \'')
        # SOURCE LINE 788
        __M_writer(filters.decode.utf8(reverse('community_discussion_add')))
        __M_writer(u"',\r\n                    type: 'POST',\r\n                    data: formData,\r\n                    async: false,\r\n                    cache: false,\r\n                    contentType: false,\r\n                    processData: false,\r\n                    success: function (data) {\r\n                        if (data.Success) {\r\n                            if ($('#new-discussion-submit .poll-add').is(':checked')) {\r\n                                var pollData = formSelector.serializeArray();\r\n                                pollData[pollData.length] = {name: 'poll_id', 'value': data.DiscussionID};\r\n                                $.post('")
        # SOURCE LINE 800
        __M_writer(filters.decode.utf8(reverse('poll_form_submit', args=['discussion'])))
        __M_writer(u"', pollData, function (data) {\r\n                                    if (data.Success) {\r\n                                        discussion_dialog.hide();\r\n                                        replaceDiscussions(1);\r\n                                    } else {\r\n                                        $('.discussion-error').append('There was an error adding your discussion. Please try again later.')\r\n                                    }\r\n                                });\r\n                            } else {\r\n                                discussion_dialog.hide();\r\n                                replaceDiscussions(1);\r\n                            }\r\n\r\n                        } else {\r\n                            $('.discussion-error').append('There was an error adding your discussion. Please try again later.')\r\n                        }\r\n                    }\r\n                });\r\n            }\r\n        });\r\n\r\n        $('.poll-add').click(function() {\r\n            $('#poll-form').toggle();\r\n        });\r\n        $('.poll-answer .add').click(function() {\r\n            newAnswer();\r\n        });\r\n    }\r\n    function replaceDiscussions(page) {\r\n        $.get('")
        # SOURCE LINE 829
        __M_writer(filters.decode.utf8(reverse('community_discussion_list', args=[community.id])))
        __M_writer(u'\', {\'page\': page}, function(data) {\r\n            var content = \'<div class="discussions">\';\r\n            for (var x = 0; x < data.discussions.length; x++) {\r\n                content += \'<div class="discussion">\';\r\n                content += \'<img class="discussion-avatar" src="\' + data.discussions[x].avatar + \'">\';\r\n                content += \'<div class="discussion-stats">\';\r\n                content += \'<span>Replies: \' + data.discussions[x].replies + \'</span>\';\r\n                content += \'<span>Views: \' + data.discussions[x].views + \'</span>\';\r\n                content += \'</div>\';\r\n                content += \'<h2><a href="\' + data.discussions[x].url + \'">\' + data.discussions[x].subject + \'</a></h2>\';\r\n                content += \'<div class="discussion-post-info">\';\r\n                content += \'<div class="discussion-byline"><span>Posted By: </span>\' + data.discussions[x].first_name + \' \' + data.discussions[x].last_name + \'</div>\';\r\n                content += \'<div class="discussion-date"><span>&nbsp;On: </span>\' + data.discussions[x].date_create + \'</div>\';\r\n                content += \'</div><div class="community-clear"></div></div>\';\r\n            }\r\n            content += \'</div>\';\r\n            $(\'#community-discussions .discussions\').replaceWith(content);\r\n\r\n            content = \'<div id="discussion-pager">\';\r\n            content += \'<span>Total Discussions: \' + data.pager.total + \'</span>&nbsp;&nbsp;&nbsp;\';\r\n            if (data.pager.page > 1) {\r\n                content += \'<a href="#discussions" onclick="replaceDiscussions(\' + (data.pager.page - 1) + \')" class="up_page"></a>\';\r\n            }\r\n            for (var p = 0; p < data.pager.jumps.length; p++) {\r\n                if (data.pager.jumps[p] == \'c\') {\r\n                    content += \'<a href="#discussions" onclick="replaceDiscussions(\' + data.pager.page + \')" class="page_active">\' + data.pager.page + \'</a>\';\r\n                } else {\r\n                    content += \'<a href="#discussions" onclick="replaceDiscussions(\' + data.pager.jumps[p] + \')">\' + data.pager.jumps[p] + \'</a>\';\r\n                }\r\n            }\r\n            if (data.pager.pages > data.pager.page) {\r\n                content += \'<a href="#discussions" onclick="replaceDiscussions(\' + (data.pager.page + 1) + \')" class="next_page"></a>\';\r\n            }\r\n            content += \'</div>\';\r\n            $(\'#discussion-pager\').replaceWith(content);\r\n\r\n            window.history.pushState(page, "')
        # SOURCE LINE 865
        __M_writer(filters.decode.utf8(community.name))
        __M_writer(u'", "')
        __M_writer(filters.decode.utf8(reverse('community_view', args=[community.id])))
        __M_writer(u'?page=" + page);\r\n        });\r\n    }\r\n    function newAnswer() {\r\n        var answer_num = $(\'.poll-answer\').length;\r\n        $(\'.poll-answer\').each(function(index) {\r\n            $(this).find(\'.operation\').replaceWith(\'<input type="button" class="minus operation" value="-" onclick="removeAnswer(\' + index + \')">\');\r\n        });\r\n        var entry = \'<li class="poll-answer">\';\r\n        entry += \'<input class="poll-answer-input" type="text" name="answers[\' + answer_num + \']"> <input type="button" class="add operation" value="+">\';\r\n        entry += \'</li>\';\r\n        $(\'#poll-answers\').append(entry);\r\n        $(\'.poll-answer .add\').click(function() {\r\n            newAnswer();\r\n        });\r\n    }\r\n    function removeAnswer(index) {\r\n        $(\'.poll-answer\').each(function(i) {\r\n            if (i == index) {\r\n                $(this).remove();\r\n            } else {\r\n                var num = 0;\r\n                if (i < index) {\r\n                    num = i;\r\n                }\r\n                if (i > index) {\r\n                    num = i - 1;\r\n                }\r\n                $(this).children(\'.poll-answer-input\').attr(\'name\', \'answers[\' + num + \']\');\r\n            }\r\n        });\r\n        $(\'.poll-answer .minus\').each(function(index) {\r\n            $(this).replaceWith(\'<input type="button" class="minus operation" value="-" onclick="removeAnswer(\' + index + \')">\');\r\n        });\r\n    }\r\n    function isScrolledIntoView(elem, view) {\r\n        var $elem = $(elem);\r\n        var $view = $(view);\r\n        var docViewLeft = $view.offset().left;\r\n        var docViewRight = docViewLeft + $view.width();\r\n        var elLeft = $elem.offset().left;\r\n        var elRight = elLeft + $elem.width();\r\n        // return ((elemRight <= docViewRight) && (elemLeft >= docViewLeft)); // partly visible\r\n        return ((docViewLeft < elLeft) && (docViewRight > elRight));\r\n    }\r\n    function left(){\r\n        var lastHideLeft = null;\r\n        var n=-1;\r\n        $("#members").find("a").each(function(i){\r\n            if(!isScrolledIntoView(this, $("#members"))){\r\n                lastHideLeft=this;\r\n                n=i;\r\n            }else{\r\n                return false;\r\n            }\r\n        });\r\n        if(lastHideLeft) {\r\n            //$(lastHideLeft).css(\'border\',"1px solid #f00");\r\n            $("#members").scrollLeft($("#members").scrollLeft()  + $(lastHideLeft).position().left-1);\r\n        }\r\n    }\r\n    function right(){\r\n        var firstHideRight=null;\r\n        var foundVisible=false;\r\n        var n=-1;\r\n        $("#members").find("a").each(function(i){\r\n            if(!isScrolledIntoView(this, $("#members"))){\r\n                if(foundVisible){\r\n                    firstHideRight=this;\r\n                    n=i;\r\n                    return false;\r\n                }\r\n            }else{\r\n                foundVisible=true;\r\n            }\r\n        });\r\n        if(firstHideRight) {\r\n            $("#members").scrollLeft($("#members").scrollLeft()\r\n                    + $(firstHideRight).position().left\r\n                    - $("#members").width() + $(firstHideRight).width() + 1);\r\n        }\r\n    }\r\n    $(document).ready(function() {\r\n        $("#members").scrollLeft(0);\r\n        $(\'.card-link\').attr(\'target\', \'_blank\');\r\n        $(\'.delete-icon\').click(function(event) {\r\n            event.preventDefault();\r\n            var title = \'Really Delete This Community?\';\r\n            var content = \'If you delete this community, all discussions, memberships and resources will be removed as well. This operation cannot be undone\';\r\n            var continue_url = $(this).attr(\'href\');\r\n            new Dialog($(\'#fixed-dialog\')).showYesNo(title, content, function(ans) {\r\n                this.hide();\r\n                if (!ans) return;\r\n                window.location.href = continue_url;\r\n            });\r\n        });\r\n        $("#newDiscussionButton").click(function(e){\r\n            e.preventDefault();\r\n            scroll(0,0)\r\n        });\r\n        $(\'#skype-start\').click(function(e) {\r\n            e.preventDefault();\r\n            $(\'.skype-container\').attr(\'id\', \'\');\r\n            $(\'.skype-container\').children(\'p\').remove();\r\n            $(\'#create-skype\').off(\'click\');\r\n            var dialog = new Dialog(\'#skype-dialog\');\r\n            dialog.showOverlay();\r\n            dialog.$ei.fadeIn(200);\r\n            $(\'#create-skype\').click(function() {\r\n                var participants = $("input[name=\'skype-participants\']").val().split(/, ?/);\r\n                var topic = $("input[name=\'skype-topic\']").val();\r\n                var skype_params = {\r\n                    name: "call",\r\n                    element: "SkypeButton_Call_" + participants[0] + "_1",\r\n                    participants: participants,\r\n                    imageSize: 24,\r\n                    imageColor: "skype",\r\n                    video: "true",\r\n                    topic: topic\r\n                };\r\n                $(\'.skype-container\').attr(\'id\', \'\');\r\n                $(\'.skype-container\').attr(\'id\', "SkypeButton_Call_" + participants[0] + "_1");\r\n                $(\'.skype-container\').children(\'p\').remove();\r\n                startSkype(skype_params);\r\n            });\r\n        });\r\n    });\r\n</script>\r\n</body>\r\n')
        return ''
    finally:
        context.caller_stack._pop_frame()
예제 #47
0
def piazza_discussion(request, course_id):
    '''
    Shows the page under the Discussion tab with an iframe containing Piazza
    '''
    # Create a new tool configuration
    config = ToolConfig(title='Piazza', launch_url=LTI_LAUNCH_URL)

    # Create tool consumer using LTI!
    consumer = ToolConsumer(LTI_CONSUMER_KEY, LTI_CONSUMER_SECRET)
    consumer.set_config(config)

    #retrieve user and course models
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    userProfile = UserProfile.objects.get(user_id=user.id)
    course = course_from_id(course_id)

    #check for permissions to determine what role to pass to Piazza.com through
    piazza_role = ''
    if user.groups.filter(name=(
            'instructor_' + course_id)).count() != 0 or request.user.is_staff:
        piazza_role = 'Instructor'
    elif user.groups.filter(name=('staff_' + course_id)).count() != 0:
        piazza_role = 'Staff'
    else:
        piazza_role = 'Learner'

    # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
    consumer.resource_link_id = course_id
    consumer.lis_person_contact_email_primary = user.email
    consumer.lis_person_name_full = str(userProfile.name)
    hash = hashlib.md5()
    hash.update(str(userProfile.user_id))
    consumer.user_id = hash.hexdigest()

    #TODO: check if user is is_staff, student, professor, or staff and set the role appropriately
    consumer.roles = piazza_role
    consumer.context_id = course_id
    consumer.context_title = course.display_name_with_default
    consumer.context_label = course.number.replace('_', ' ')
    consumer.tool_consumer_instance_guid = 'lms.cvn.columbia.edu'
    consumer.tool_consumer_instance_description = 'Columbia University'

    launch_data = consumer.generate_launch_data()
    launch_url = consumer.launch_url

    course = get_course_with_access(request.user, course_id, 'load')
    staff_access = has_access(request.user, course, 'staff')
    masq = setup_masquerade(
        request, staff_access)  # allow staff to toggle masquerade on info page

    return render_to_response(
        'courseware/piazza_discussion.html', {
            'request': request,
            'course_id': course_id,
            'cache': None,
            'course': course,
            'staff_access': staff_access,
            'masquerade': masq,
            'launch_url': launch_url,
            'launch_data': launch_data
        })
예제 #48
0
def cvn_lms_dashboard(request):
    user = request.user

    # This view was copy-pasted from student.views
    # We should figure out a way to not do that. --mjg
    courses = []
    for enrollment in CourseEnrollment.enrollments_for_user(user):
        try:
            courses.append((course_from_id(enrollment.course_id), enrollment))
        except ItemNotFoundError:
            log.error("User {0} enrolled in non-existent course {1}".format(
                user.username, enrollment.course_id))

    course_optouts = Optout.objects.filter(user=user).values_list('course_id',
                                                                  flat=True)

    message = ""
    if not user.is_active:
        message = render_to_string('registration/activate_account_notice.html',
                                   {'email': user.email})

    # Global staff can see what courses errored on their dashboard
    staff_access = False
    errored_courses = {}

    # FIXME: in the copy-paste where this page of code came from, the following
    # lines were not taken into consideration, so they cause this page to break
    # for admin users:
    ## if has_access(user, 'global', 'staff'):
    ##     # Show any courses that errored on load
    ##     staff_access = True
    ##     errored_courses = modulestore().get_errored_courses()

    show_courseware_links_for = frozenset(
        course.id for course, _enrollment in courses
        if has_access(request.user, course, 'load'))

    cert_statuses = {
        course.id: cert_info(request.user, course)
        for course, _enrollment in courses
    }

    # get info w.r.t ExternalAuthMap
    external_auth_map = None
    try:
        external_auth_map = ExternalAuthMap.objects.get(user=user)
    except ExternalAuthMap.DoesNotExist:
        pass

    try:
        theProctor = Proctor.objects.get(user=user)
    except:
        theProctor = Proctor(user=user)
        theProctor.save()
    proct_form = ProctorForm(instance=theProctor)

    context = {
        'courses': courses,
        'course_optouts': course_optouts,
        'message': message,
        'external_auth_map': external_auth_map,
        'staff_access': staff_access,
        'errored_courses': errored_courses,
        'show_courseware_links_for': show_courseware_links_for,
        'cert_statuses': cert_statuses,
        'form': proct_form,
    }

    return render_to_response('cvn_dashboard.html', context)
예제 #49
0
def results_callback(request):
    """
    Software Secure will call this callback to tell us whether a user is
    verified to be who they said they are.
    """
    body = request.body

    try:
        body_dict = json.loads(body)
    except ValueError:
        log.exception(
            "Invalid JSON received from Software Secure:\n\n{}\n".format(body))
        return HttpResponseBadRequest(
            "Invalid JSON. Received:\n\n{}".format(body))

    if not isinstance(body_dict, dict):
        log.error(
            "Reply from Software Secure is not a dict:\n\n{}\n".format(body))
        return HttpResponseBadRequest(
            "JSON should be dict. Received:\n\n{}".format(body))

    headers = {
        "Authorization": request.META.get("HTTP_AUTHORIZATION", ""),
        "Date": request.META.get("HTTP_DATE", "")
    }

    sig_valid = ssencrypt.has_valid_signature(
        "POST", headers, body_dict,
        settings.VERIFY_STUDENT["SOFTWARE_SECURE"]["API_ACCESS_KEY"],
        settings.VERIFY_STUDENT["SOFTWARE_SECURE"]["API_SECRET_KEY"])

    _response, access_key_and_sig = headers["Authorization"].split(" ")
    access_key = access_key_and_sig.split(":")[0]

    # This is what we should be doing...
    #if not sig_valid:
    #    return HttpResponseBadRequest("Signature is invalid")

    # This is what we're doing until we can figure out why we disagree on sigs
    if access_key != settings.VERIFY_STUDENT["SOFTWARE_SECURE"][
            "API_ACCESS_KEY"]:
        return HttpResponseBadRequest("Access key invalid")

    receipt_id = body_dict.get("EdX-ID")
    result = body_dict.get("Result")
    reason = body_dict.get("Reason", "")
    error_code = body_dict.get("MessageType", "")

    try:
        attempt = SoftwareSecurePhotoVerification.objects.get(
            receipt_id=receipt_id)
    except SoftwareSecurePhotoVerification.DoesNotExist:
        log.error(
            "Software Secure posted back for receipt_id {}, but not found".
            format(receipt_id))
        return HttpResponseBadRequest("edX ID {} not found".format(receipt_id))

    if result == "PASS":
        log.debug("Approving verification for {}".format(receipt_id))
        attempt.approve()
    elif result == "FAIL":
        log.debug("Denying verification for {}".format(receipt_id))
        attempt.deny(json.dumps(reason), error_code=error_code)
    elif result == "SYSTEM FAIL":
        log.debug("System failure for {} -- resetting to must_retry".format(
            receipt_id))
        attempt.system_error(json.dumps(reason), error_code=error_code)
        log.error("Software Secure callback attempt for %s failed: %s",
                  receipt_id, reason)
    else:
        log.error("Software Secure returned unknown result {}".format(result))
        return HttpResponseBadRequest(
            "Result {} not understood. Known results: PASS, FAIL, SYSTEM FAIL".
            format(result))

    # If this is a reverification, log an event
    if attempt.window:
        course_id = attempt.window.course_id
        course = course_from_id(course_id)
        course_enrollment = CourseEnrollment.get_or_create_enrollment(
            attempt.user, course_id)
        course_enrollment.emit_event(
            EVENT_NAME_USER_REVERIFICATION_REVIEWED_BY_SOFTWARESECURE)

    return HttpResponse("OK!")
예제 #50
0
def mobile_change_enrollment(request):
    """
    Modify the enrollment status for the logged-in user.

    The request parameter must be a POST request (other methods return 405)
    that specifies course_id and enrollment_action parameters. If course_id or
    enrollment_action is not specified, if course_id is not valid, if
    enrollment_action is something other than "enroll" or "unenroll", if
    enrollment_action is "enroll" and enrollment is closed for the course, or
    if enrollment_action is "unenroll" and the user is not enrolled in the
    course, a 400 error will be returned. If the user is not logged in, 403
    will be returned; it is important that only this case return 403 so the
    front end can redirect the user to a registration or login page when this
    happens. This function should only be called from an AJAX request or
    as a post-login/registration helper, so the error messages in the responses
    should never actually be user-visible.
    """
    user = request.user

    action = request.POST.get("enrollment_action")
    course_id = request.POST.get("course_id")
    if course_id is None:
        return HttpResponseBadRequest(_("Course id not specified"))

    if not user.is_authenticated():
        return HttpResponseForbidden()

    if action == "enroll":
        # Make sure the course exists
        # We don't do this check on unenroll, or a bad course id can't be unenrolled from
        try:
            course = course_from_id(course_id)
        except ItemNotFoundError:
            log.warning("User {0} tried to enroll in non-existent course {1}"
                        .format(user.username, course_id))
            return HttpResponseBadRequest(_("Course id is invalid"))

        if not has_access(user, course, 'enroll'):
            return HttpResponseBadRequest(_("Enrollment is closed"))

        # see if we have already filled up all allowed enrollments
        is_course_full = CourseEnrollment.is_course_full(course)

        if is_course_full:
            return HttpResponseBadRequest(_("Course is full"))

        # If this course is available in multiple modes, redirect them to a page
        # where they can choose which mode they want.
        available_modes = CourseMode.modes_for_course(course_id)
        if len(available_modes) > 1:
            return HttpResponse(
                reverse("course_modes_choose", kwargs={'course_id': course_id})
            )

        current_mode = available_modes[0]

        course_id_dict = Location.parse_course_id(course_id)
        dog_stats_api.increment(
            "common.student.enrollment",
            tags=[u"org:{org}".format(**course_id_dict),
                  u"course:{course}".format(**course_id_dict),
                  u"run:{name}".format(**course_id_dict)]
        )

        CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)

        return HttpResponse('about')

    elif action == "add_to_cart":
        # Pass the request handling to shoppingcart.views
        # The view in shoppingcart.views performs error handling and logs different errors.  But this elif clause
        # is only used in the "auto-add after user reg/login" case, i.e. it's always wrapped in try_change_enrollment.
        # This means there's no good way to display error messages to the user.  So we log the errors and send
        # the user to the shopping cart page always, where they can reasonably discern the status of their cart,
        # whether things got added, etc

        shoppingcart.views.add_course_to_cart(request, course_id)
        return HttpResponse(
            reverse("shoppingcart.views.show_cart")
        )

    elif action == "unenroll":
        if not CourseEnrollment.is_enrolled(user, course_id):
            return HttpResponseBadRequest(_("You are not enrolled in this course"))
        CourseEnrollment.unenroll(user, course_id)
        course_id_dict = Location.parse_course_id(course_id)
        dog_stats_api.increment(
            "common.student.unenrollment",
            tags=[u"org:{org}".format(**course_id_dict),
                  u"course:{course}".format(**course_id_dict),
                  u"run:{name}".format(**course_id_dict)]
        )
        return HttpResponse()
    else:
        return HttpResponseBadRequest(_("Enrollment action is invalid"))