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")
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
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)
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)
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)
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 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)
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)
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")
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)
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
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)
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)
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), }
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})
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")
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
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)
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)
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)
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)
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
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
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'), }
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
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 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')
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)
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)
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)
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)
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)
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 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> \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> 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> \';\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()
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 })
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)
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!")
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"))