def get_queryset(self): """ List one course run --- parameters: - name: include_deleted_programs description: Will include deleted programs in the associated programs array required: false type: integer paramType: query multiple: false """ q = self.request.query_params.get('q') partner = self.request.site.partner edit_mode = get_query_param(self.request, 'editable') or self.request.method not in SAFE_METHODS if edit_mode and q: raise EditableAndQUnsupported() if edit_mode: queryset = CourseRun.objects.filter_drafts() queryset = CourseEditor.editable_course_runs(self.request.user, queryset) else: queryset = self.queryset if q: queryset = CourseRun.search(q, queryset=queryset) queryset = queryset.filter(course__partner=partner) return self.get_serializer_class().prefetch_queryset(queryset=queryset)
def get_queryset(self): """ List one course run --- parameters: - name: include_deleted_programs description: Will include deleted programs in the associated programs array required: false type: integer paramType: query multiple: false """ q = self.request.query_params.get('q') partner = self.request.site.partner edit_mode = get_query_param(self.request, 'editable') or self.request.method not in SAFE_METHODS if edit_mode and q: raise EditableAndQUnsupported() if edit_mode and (not self.request.user.is_staff and not is_publisher_user(self.request.user)): raise PermissionDenied if edit_mode: queryset = CourseRun.objects.filter_drafts() queryset = CourseEditor.editable_course_runs(self.request.user, queryset) else: queryset = self.queryset if q: qs = SearchQuerySetWrapper(CourseRun.search(q).filter(partner=partner.short_code)) # This is necessary to avoid issues with the filter backend. qs.model = self.queryset.model return qs queryset = queryset.filter(course__partner=partner) return self.get_serializer_class().prefetch_queryset(queryset=queryset)
def create(self, request): comment_creation_fields = { 'course_uuid': request.data.get('course_uuid'), 'comment': request.data.get('comment'), } missing_values = [k for k, v in comment_creation_fields.items() if v is None] error_message = '' if missing_values: error_message += ''.join([_('Missing value for: [{name}]. ').format(name=name) for name in missing_values]) if error_message: return Response((_('Incorrect data sent. ') + error_message).strip(), status=status.HTTP_400_BAD_REQUEST) partner = self.request.site.partner course = self._get_course_or_404(partner, comment_creation_fields.get('course_uuid')) if not CourseEditor.is_course_editable(request.user, course): raise PermissionDenied util = self._get_salesforce_util_or_404(partner) try: comment = util.create_comment_for_course_case( course, request.user, comment_creation_fields.get('comment'), course_run_key=request.data.get('course_run_key') ) send_email_for_comment(comment, course, request.user) return Response(comment, status=status.HTTP_201_CREATED) except SalesforceMissingCaseException as ex: return Response(ex.message, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def get_queryset(self): partner = self.request.site.partner q = self.request.query_params.get('q') # We don't want to create an additional elasticsearch index right now for draft courses, so we # try to implement a basic search behavior with this pubq parameter here against key and name. pub_q = self.request.query_params.get('pubq') edit_method = self.request.method not in SAFE_METHODS edit_mode = get_query_param(self.request, 'editable') or edit_method if edit_mode and q: raise EditableAndQUnsupported() if edit_mode and (not self.request.user.is_staff and not is_publisher_user(self.request.user)): raise PermissionDenied if edit_mode: # Start with either draft versions or real versions of the courses queryset = Course.objects.filter_drafts() queryset = CourseEditor.editable_courses(self.request.user, queryset, check_editors=edit_method) else: queryset = self.queryset if q: queryset = Course.search(q, queryset=queryset) queryset = self.get_serializer_class().prefetch_queryset(queryset=queryset, partner=partner) else: if edit_mode: course_runs = CourseRun.objects.filter_drafts(course__partner=partner) else: course_runs = CourseRun.objects.filter(course__partner=partner) if not get_query_param(self.request, 'include_hidden_course_runs'): course_runs = course_runs.exclude(hidden=True) if get_query_param(self.request, 'marketable_course_runs_only'): course_runs = course_runs.marketable().active() if get_query_param(self.request, 'marketable_enrollable_course_runs_with_archived'): course_runs = course_runs.marketable().enrollable() if get_query_param(self.request, 'published_course_runs_only'): course_runs = course_runs.filter(status=CourseRunStatus.Published) if get_query_param(self.request, 'include_deleted_programs'): programs = Program.objects.all() else: programs = Program.objects.exclude(status=ProgramStatus.Deleted) queryset = self.get_serializer_class().prefetch_queryset( queryset=queryset, course_runs=course_runs, partner=partner, programs=programs, ) if pub_q and edit_mode: return queryset.filter(Q(key__icontains=pub_q) | Q(title__icontains=pub_q)).order_by(Lower('key')) return queryset.order_by(Lower('key'))
def has_permission(self, request, view): if request.method == 'POST': org = request.data.get('org') if not org: # Fail happily because OPTIONS goes down this path too with a fake POST. # If this is a real POST, we'll complain about the missing org in the view. return True return CourseEditor.can_create_course(request.user, org) else: return True # other write access attempts will be caught by object permissions below
def has_permission(self, request, view): if request.method in SAFE_METHODS: return True else: org = request.data.get('org') if not org: # Fail happily because OPTIONS goes down this path too with a fake POST. # If this is a real POST, we'll complain about the missing org in the view. return True return CourseEditor.can_create_course(request.user, org)
def has_permission(self, request, view): if self.django_perms.has_permission(request, view): return True elif request.user.is_staff: return True elif request.method == 'POST': course = request.data.get('course') if not course: return False org, _ = parse_course_key_fragment(course) return org and CourseEditor.can_create_course(request.user, org) else: return True # other write access attempts will be caught by object permissions below
def has_permission(self, request, view): if request.method in SAFE_METHODS: return True else: course = request.data.get('course') if not course: # Fail happily because OPTIONS goes down this path too with a fake POST. # If this is a real POST, we'll complain about the missing course in the view. return True # We could do a lookup on the course from the request above, but the logic already exists in the view so we # use that to avoid writing it twice return CourseEditor.is_course_editable(request.user, view.course)
def send_email_to_editors(course_run, template_name, subject, context=None): """ Send a specific email template to all editors for a course run. Arguments: course_run (Object): CourseRun object template_name (str): path to template without filename extension subject (str): subject line for the email context (dict): additional context for the template """ # Model imports here to avoid a circular import from course_discovery.apps.course_metadata.models import CourseEditor # pylint: disable=import-outside-toplevel editors = CourseEditor.course_editors(course_run.course) send_email(template_name, subject, editors, _('course team'), context=context, course_run=course_run)
def get_queryset(self): partner = self.request.site.partner q = self.request.query_params.get('q') edit_mode = get_query_param( self.request, 'editable') or self.request.method not in SAFE_METHODS if edit_mode and q: raise EditableAndQUnsupported() # Start with either draft versions or real versions of the courses if edit_mode: # TODO: For now hardcode in draft=True until we choose to roll this out live, DISCO-818 queryset = Course.objects.filter_drafts(draft=True) queryset = CourseEditor.editable_courses(self.request.user, queryset) else: queryset = self.queryset if q: queryset = Course.search(q, queryset=queryset) queryset = self.get_serializer_class().prefetch_queryset( queryset=queryset, partner=partner) else: if edit_mode: course_runs = CourseRun.objects.filter_drafts( course__partner=partner) else: course_runs = CourseRun.objects.filter(course__partner=partner) if not get_query_param(self.request, 'include_hidden_course_runs'): course_runs = course_runs.exclude(hidden=True) if get_query_param(self.request, 'marketable_course_runs_only'): course_runs = course_runs.marketable().active() if get_query_param( self.request, 'marketable_enrollable_course_runs_with_archived'): course_runs = course_runs.marketable().enrollable() if get_query_param(self.request, 'published_course_runs_only'): course_runs = course_runs.filter( status=CourseRunStatus.Published) queryset = self.get_serializer_class().prefetch_queryset( queryset=queryset, course_runs=course_runs, partner=partner) return queryset.order_by(Lower('key'))
def has_permission(self, request, view): if self.django_perms.has_permission(request, view): return True elif request.user.is_staff: return True elif request.method == 'POST': course = request.data.get('course') if not course: # Fail happily because OPTIONS goes down this path too with a fake POST. # If this is a real POST, we'll complain about the missing course in the view. return True org, _ = parse_course_key_fragment(course) return org and CourseEditor.can_create_course(request.user, org) else: return True # other write access attempts will be caught by object permissions below
def send_email_for_comment(comment, course, author): """ Send the emails for a comment. Arguments: comment (Dict): Comment dict returned from salesforce.py course (Course): Course object for the comment author (User): User object who made the post request """ # Model imports here to avoid a circular import from course_discovery.apps.course_metadata.models import CourseEditor subject = _('Comment added: {title}').format(title=course.title) org = course.authoring_organizations.first() project_coordinator = get_project_coordinator(org) recipients = list(CourseEditor.course_editors(course)) if project_coordinator: recipients.append(project_coordinator) # remove email of comment owner if exists recipients = filter(lambda x: x.email != author.email, recipients) context = { 'comment_message': comment.get('comment'), 'user_name': author.username, 'course_name': course.title, 'comment_date': dateutil.parser.parse(comment.get('created')), 'page_url': '{url}/courses/{path}'.format( url=course.partner.publisher_url.strip('/'), path=course.uuid) } try: send_email('course_metadata/email/comment', subject, recipients, '', course=course, context=context, project_coordinator=project_coordinator) except Exception: # pylint: disable=broad-except logger.exception( 'Failed to send email notifications for comment on course %s', course.uuid)
def has_object_permission(self, request, view, obj): if request.method in SAFE_METHODS: return True else: return CourseEditor.is_course_editable(request.user, obj.course)
def has_permission(self, request, view): if request.method == 'POST': org = request.data.get('org') return org and CourseEditor.can_create_course(request.user, org) else: return True # other write access attempts will be caught by object permissions below
def get_queryset(self): return CourseEditor.editors_for_user(self.request.user)