def test_server_track_with_middleware(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'accept_language': '',
                'referer': '',
                'username': '******',
                'ip': '127.0.0.1',
                'event_source': 'server',
                'event_type': str(sentinel.event_type),
                'event': '{}',
                'agent': '',
                'page': None,
                'time': FROZEN_TIME,
                'host': 'testserver',
                'context': {
                    'user_id': '',
                    'course_id': u'foo/bar/baz',
                    'org_id': 'foo',
                    'path': u'/courses/foo/bar/baz/xmod/'
                },
            }
        finally:
            middleware.process_response(request, None)

        self.assert_mock_tracker_call_matches(expected_event)
    def process_response(self, request, response):
        """Exit the context if it exists."""
        try:
            tracker.get_tracker().exit_context(CONTEXT_NAME)
        except Exception:  # pylint: disable=broad-except
            pass

        # Set spam query string into cookie
        spam = request.GET.get('spam')
        if spam:
            response.set_cookie('spam', spam)

        # track session changed 
        try:
            origin_session = request.COOKIES.get('sessionid')
            if origin_session and request.session.session_key and request.session.session_key != origin_session:
                session_md5 = hashlib.md5()
                session_md5.update(request.session.session_key)
                origin_session_md5 = hashlib.md5()
                origin_session_md5.update(origin_session)
                event = {
                    'changed_session': session_md5.hexdigest(),
                    'origin_session': origin_session_md5.hexdigest(),
                }
                views.server_track(request, request.META['PATH_INFO'], event)
        except Exception, e:
            pass
Exemple #3
0
    def test_server_track_with_middleware_and_google_analytics_cookie(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899'
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'accept_language': '',
                'referer': '',
                'username': '******',
                'ip': '127.0.0.1',
                'event_source': 'server',
                'event_type': str(sentinel.event_type),
                'event': '{}',
                'agent': '',
                'page': None,
                'time': FROZEN_TIME,
                'host': 'testserver',
                'context': {
                    'user_id': '',
                    'course_id': u'foo/bar/baz',
                    'org_id': 'foo',
                    'path': u'/courses/foo/bar/baz/xmod/'
                },
            }
        finally:
            middleware.process_response(request, None)

        self.assert_mock_tracker_call_matches(expected_event)
Exemple #4
0
    def test_server_track_with_middleware_and_google_analytics_cookie(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899'
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'username': '******',
                'ip': '127.0.0.1',
                'event_source': 'server',
                'event_type': str(sentinel.event_type),
                'event': '{}',
                'agent': '',
                'page': None,
                'time': expected_time,
                'host': 'testserver',
                'context': {
                    'user_id': '',
                    'course_id': u'foo/bar/baz',
                    'org_id': 'foo',
                    'path': u'/courses/foo/bar/baz/xmod/'
                },
            }
        finally:
            middleware.process_response(request, None)

        self.mock_tracker.send.assert_called_once_with(expected_event)
    def post(self, request, format=None):
        file_obj = request.FILES.get('file')
        now = timezone.now().strftime('%Y%m%d')
        log_root = os.path.join(LOG_BASE_ROOT, now)
        if not os.path.exists(log_root):
            os.mkdir(log_root)
        uid = request.user.id
        platform = None
        http_uuid = request.META.get('HTTP_UUID')
        user_agent = request.META.get('HTTP_USER_AGENT', '').lower()
        if 'ios' in user_agent:
            platform = 'ios'
        elif 'android' in user_agent:
            platform = 'android'

        log_path = os.path.join(log_root, '{}_{}_{}_{}.zip'.format(http_uuid,
            uid, platform, uuid.uuid4().hex[:10]))
        with open(log_path, 'wb+') as destination:
            for chunk in file_obj.chunks():
                destination.write(chunk)
        server_track(request, 'api.user.upload_log', {
            'uid': uid,
            'uuid': http_uuid,
            'sid': request.META.get('HTTP_SID'),
            'log_path': log_path,
        })
        return Response({'success': True}, status.HTTP_200_OK)
    def test_server_track_with_middleware(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'username': '******',
                'ip': '127.0.0.1',
                'event_source': 'server',
                'event_type': str(sentinel.event_type),
                'event': '{}',
                'agent': '',
                'page': None,
                'time': expected_time,
                'host': 'testserver',
                'context': {
                    'user_id': '',
                    'course_id': u'foo/bar/baz',
                    'org_id': 'foo',
                    'path': u'/courses/foo/bar/baz/xmod/'
                },
            }
        finally:
            middleware.process_response(request, None)

        self.mock_tracker.send.assert_called_once_with(expected_event)
    def process_request(self, request):
        try:
            self.enter_request_context(request)

            if not self.should_process_request(request):
                return

            # Set sessionid and referer if there comes a new user
            if not request.COOKIES.get('sessionid'):
                request.session.cycle_key()
            referer = _get_request_header(request, 'HTTP_REFERER')
            if request.session.get('referer') is None:
                request.session['referer'] = referer
            else:
                host = _get_request_header(request, 'HTTP_HOST')
                if host and referer and not re.match('https?://%s\/?' % request.META['HTTP_HOST'], request.META['HTTP_REFERER']):
                    request.session['referer'] = referer

            # Removes passwords from the tracking logs
            # WARNING: This list needs to be changed whenever we change
            # password handling functionality.
            #
            # As of the time of this comment, only 'password' is used
            # The rest are there for future extension.
            #
            # Passwords should never be sent as GET requests, but
            # this can happen due to older browser bugs. We censor
            # this too.
            #
            # We should manually confirm no passwords make it into log
            # files when we change this.

            censored_strings = ['password', 'newpassword', 'new_password', 'repassword',
                                'oldpassword', 'old_password', 'new_password1', 'new_password2']
            post_dict = dict(request.POST)
            get_dict = dict(request.GET)
            for string in censored_strings:
                if string in post_dict:
                    post_dict[string] = '*' * 8
                if string in get_dict:
                    get_dict[string] = '*' * 8

            event = {'GET': dict(get_dict), 'POST': dict(post_dict)}
            # EDXMERGE: 可能会对数据团队造成影响
            # TODO: Confirm no large file uploads
            #event = json.dumps(event)
            #event = event[:512]

            views.server_track(request,  request.META['PATH_INFO'], event)
        except Exception, e:
            pass
    def post(self, request):
        """Modify user's setting for receiving emails from a course."""
        username = request.DATA.get('username')
        try:
            user = User.objects.get(username=username)
        except ObjectDoesNotExist:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={"message": u"User {username} does not exist".format(username=username)}
            )

        course_id = request.DATA.get('course_id')
        if not course_id:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={"message": u"Course ID must be specified."}
            )

        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": u"No course '{course_id}' found".format(course_id=course_id)
                }
            )

        receive_emails = request.DATA.get("subscribe")
        if receive_emails:
            optout_object = Optout.objects.filter(user=user, course_id=course_key)
            if optout_object:
                optout_object.delete()
            log.info(
                u"User %s (%s) opted in to receive emails from course %s",
                user.username,
                user.email,
                course_id
            )
            track_views.server_track(request, "change-email-settings", {"receive_emails": "no", "course": course_id})
        else:
            Optout.objects.get_or_create(user=user, course_id=course_key)
            log.info(
                u"User %s (%s) opted out of receiving emails from course %s",
                user.username,
                user.email,
                course_id
            )
            track_views.server_track(request, "change-email-settings", {"receive_emails": "yes", "course": course_id})
        return Response(status=status.HTTP_200_OK)
    def post(self, request):
        """Modify user's setting for receiving emails from a course."""
        username = request.data.get('username')
        try:
            user = User.objects.get(username=username)
        except ObjectDoesNotExist:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={"message": u"User {username} does not exist".format(username=username)}
            )

        course_id = request.data.get('course_id')
        if not course_id:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={"message": u"Course ID must be specified."}
            )

        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    "message": u"No course '{course_id}' found".format(course_id=course_id)
                }
            )

        receive_emails = request.data.get("subscribe")
        if receive_emails:
            optout_object = Optout.objects.filter(user=user, course_id=course_key)
            if optout_object:
                optout_object.delete()
            log.info(
                u"User %s (%s) opted in to receive emails from course %s",
                user.username,
                user.email,
                course_id
            )
            track_views.server_track(request, "change-email-settings", {"receive_emails": "no", "course": course_id})
        else:
            Optout.objects.get_or_create(user=user, course_id=course_key)
            log.info(
                u"User %s (%s) opted out of receiving emails from course %s",
                user.username,
                user.email,
                course_id
            )
            track_views.server_track(request, "change-email-settings", {"receive_emails": "yes", "course": course_id})
        return Response(status=status.HTTP_200_OK)
    def post(self, request, course_id, format=None):
        """ Enroll in Course """
        user = request.user
        err = {}
        try:
            course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)

            course = course_from_key(course_key)
        except ItemNotFoundError:
            err['err_type'] = 'InvalidCourseId'
            err['err_msg'] = _("Course id is invalid")
            return Response(err, status=status.HTTP_400_BAD_REQUEST)

        if not has_access(user, 'enroll', course):
            err['err_type'] = 'InvalidEnrollment'
            err['err_msg'] = _("Enrollment is closed")
            return Response(err, status=status.HTTP_400_BAD_REQUEST)

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

        if is_course_full:
            err['err_type'] = 'InvalidEnrollment'
            err['err_msg'] = _("Course is full")
            return Response(err, status=status.HTTP_400_BAD_REQUEST)

        # 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)
        available_modes_dict = CourseMode.modes_for_course_dict(course_id, available_modes)
        if CourseMode.has_verified_mode(available_modes_dict):
            err['err_type'] = 'InvalidEnrollment'
            err['err_msg'] = _("Missing course mode")
            return Response(err, status=status.HTTP_400_BAD_REQUEST)

        current_mode = available_modes[0]
        course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        dog_stats_api.increment(
            "common.student.enrollment",
            tags=[u"org:{0}".format(course_key.org),
                  u"course:{0}".format(course_key.course),
                  u"run:{0}".format(course_key.run)]
        )
        server_track(request, 'api.course.enrollment', {
            'username': user.username,
            'course_id': course_id,
        })

        CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
        return Response()
    def post(self, request, provider):
        data = request.DATA
        uid = data.get('uid')
        access_token = data.get('access_token')
        strategy = get_strategy(provider)
        social_response = {
            'access_token': access_token,
            'uid': uid,
            'openid': uid,
            'provider': provider,
        }
        log.info('api.oauth.bind.outer.login\n{}'.format(social_response))
        if provider == 'qq':
            social_response.update({
                'SOCIAL_AUTH_QQ_KEY': settings.SOCIAL_AUTH_MOBILE_QQ_OAUTH_CONSUMER_KEY
            })
        try:
            # 请求三方接口获得用户信息
            detail = strategy.backend.user_data(access_token, response=social_response)
            log.info('api.user.bind.oauth.login.response\n{}'.format(detail))
            if 'errcode' in detail:
                server_track(request, 'api.user.oauth.bind_failure', {
                    'bind_type': 'social_oauth',
                    'provider': provider,
                    'uid': request.user.id,
                    'error': {
                        'msg': u'三方登录失败',
                        'detail': detail,
                    },
                })
                raise error.Error(error.SOCIAL_OAUTH_LOGIN_FAILED, u'三分登陆失败')
        except Exception as ex:
            server_track(request, 'api.user.oauth.bind_failure', {
                'bind_type': 'social_oauth',
                'provider': provider,
                'uid': request.user.id,
                'error': {
                    'msg': ex.__class__.__name__,
                }
            })
            raise error.Error(error.SOCIAL_OAUTH_LOGIN_FAILED, u'三分登陆失败')

        try:
            _new_association(strategy, detail, request.user, created_on='mobile_bind')
            server_track(request, 'api.user.oauth.bind_success', {
                'unbind_type': 'social_oauth',
                'provider': provider,
                'uid': request.user.id
            })
        except AuthAlreadyAssociated as ex:
            server_track(request, 'api.user.oauth.bind_failure', {
                'bind_type': 'social_oauth',
                'provider': provider,
                'uid': request.user.id,
                'error': {
                    'msg': ex.__class__.__name__,
                }
            })
            raise error.Error(error.SOCIAL_OAUTH_AUTH_ALREADY_ASSOCIATED, u'该账号已被其它账号绑定')
        return Response(status=status.HTTP_201_CREATED)
Exemple #12
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            data = {"user_id": self.user.id, "course_id": self.course_id, "mode": self.mode}

            with tracker.get_tracker().context(event_name, context):
                server_track(crum.get_current_request(), event_name, data)
        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception(
                    "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id
                )
Exemple #13
0
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'timestamp': FROZEN_TIME,
            'data': '{}',
            'name': str(sentinel.event_type),
            'context': {
                'username': '******',
                'page': None,
                'event_source': 'server'
            }
        }
        actual_event = self.get_event()
        assert_event_matches(expected_event, actual_event)
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'username': '******',
            'ip': '',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': expected_time,
            'host': '',
            'context': {},
        }
    def test_server_track(self):
        request = self.request_factory.get(self.path_with_course)
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'username': '******',
            'ip': '127.0.0.1',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': expected_time,
            'host': 'testserver',
            'context': {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'username': '******',
            'ip': '',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': self._expected_timestamp,
            'host': '',
            'context': {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #17
0
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), "{}")

        expected_event = {
            "username": "******",
            "ip": "",
            "event_source": "server",
            "event_type": str(sentinel.event_type),
            "event": "{}",
            "agent": "",
            "page": None,
            "time": expected_time,
            "host": "",
            "context": {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #18
0
    def test_server_track(self):
        request = self.request_factory.get(self.path_with_course)
        views.server_track(request, str(sentinel.event_type), "{}")

        expected_event = {
            "username": "******",
            "ip": "127.0.0.1",
            "event_source": "server",
            "event_type": str(sentinel.event_type),
            "event": "{}",
            "agent": "",
            "page": None,
            "time": expected_time,
            "host": "testserver",
            "context": {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #19
0
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'username': '******',
            'ip': '',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': expected_time,
            'host': '',
            'context': {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #20
0
    def test_server_track(self):
        request = self.request_factory.get(self.path_with_course)
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'username': '******',
            'ip': '127.0.0.1',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': expected_time,
            'host': 'testserver',
            'context': {},
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #21
0
 def post(self, request):
     post_vars = request.DATA
     check_phone_number(post_vars)
     check_validate_used(post_vars)
     user = request.user
     phone_number = post_vars.get('phone')
     password = post_vars.get('password')
     if password:
         if user.password != '!':
             server_track(request, 'api.user.phone.bind_failure', {
                 'bind_type': 'phone',
                 'provider': '',
                 'uid': request.user.id,
                 'error': {
                     'msg': 'PASSWORD_ALREADY_BIND',
                     'detail': phone_number,
                 }
             })
             raise error.Error(error.PASSWORD_ALREADY_BIND, u'之前已绑定密码')
         user.set_password(password)
     profile = user.profile
     if profile.phone_number:
         server_track(request, 'api.user.phone.bind_failure', {
             'bind_type': 'phone',
             'provider': '',
             'uid': request.user.id,
             'error': {
                 'msg': 'PASSWORD_ALREADY_BIND',
                 'detail': phone_number,
             }
         })
         raise error.Error(error.PASSWORD_ALREADY_BIND, u'该手机已被注册或绑定')
     check_validate_used(post_vars)
     profile.phone_number = phone_number
     try:
         profile.save()
     except IntegrityError:
         server_track(request, 'api.user.phone.bind_failure', {
             'bind_type': 'phone',
             'provider': '',
             'uid': request.user.id,
             'error': {
                 'msg': 'PHONE_NUMBER_EXIST',
                 'detail': phone_number,
             }
         })
         raise error.Error(error.PHONE_NUMBER_EXIST, u'该手机已被注册或绑定')
     user.save()
     server_track(request, 'api.user.phone.bind_success', {
         'bind_type': 'phone',
         'provider': '',
         'uid': user.id,
         'phone_number': phone_number
     })
     return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #22
0
    def process_request(self, request):
        try:
            self.enter_request_context(request)

            if not self.should_process_request(request):
                return

            # Removes passwords from the tracking logs
            # WARNING: This list needs to be changed whenever we change
            # password handling functionality.
            #
            # As of the time of this comment, only 'password' is used
            # The rest are there for future extension.
            #
            # Passwords should never be sent as GET requests, but
            # this can happen due to older browser bugs. We censor
            # this too.
            #
            # We should manually confirm no passwords make it into log
            # files when we change this.

            censored_strings = [
                'password', 'newpassword', 'new_password', 'oldpassword',
                'old_password'
            ]
            post_dict = dict(request.POST)
            get_dict = dict(request.GET)
            for string in censored_strings:
                if string in post_dict:
                    post_dict[string] = '*' * 8
                if string in get_dict:
                    get_dict[string] = '*' * 8

            event = {
                'GET': dict(get_dict),
                'POST': dict(post_dict),
            }

            # TODO: Confirm no large file uploads
            event = json.dumps(event)
            event = event[:512]

            views.server_track(request, request.META['PATH_INFO'], event)
        except:
            pass
 def delete(self, request, course_id, format=None):
     """ Unenroll the current course. """
     user = request.user
     if not CourseEnrollment.is_enrolled(user, course_id):
         return error.ErrorResponse(error.USER_NOT_ENROLLED, "Course id is invalid", status=status.HTTP_404_NOT_FOUND)
     course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
     CourseEnrollment.unenroll(user, course_key)
     dog_stats_api.increment(
         "common.student.unenrollment",
         tags=["org:{0}".format(course_key.org),
               "course:{0}".format(course_key.course),
               "run:{0}".format(course_key.run)]
     )
     server_track(request, 'api.course.unenrollment', {
         'username': user.username,
         'course_id': course_id,
     })
     return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #24
0
    def emit_event(self, event_name):
        """
        Emits an event to explicitly track course enrollment and unenrollment.
        """

        try:
            context = contexts.course_context_from_course_id(self.course_id)
            data = {
                'user_id': self.user.id,
                'course_id': self.course_id,
                'mode': self.mode,
            }

            with tracker.get_tracker().context(event_name, context):
                server_track(crum.get_current_request(), event_name, data)
        except:  # pylint: disable=bare-except
            if event_name and self.course_id:
                log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
Exemple #25
0
    def post(self, request, format=None):
        #  url(r'^s_log/?$', tv.SimpleLogView.as_view(), name='v2_simple_log')

        log_content = request.DATA['log_content']

        log_arrays = log_content.split('\n')
        for log_content in log_arrays:
            s_content = strip(log_content)
            if s_content:
                server_track(request, 'api.user.simple_log', {
                    'uid': request.user.id,
                    'uuid': request.META.get('HTTP_UUID'),
                    'sid': request.META.get('HTTP_SID'),
                    'log_content': s_content,
                    'log_content_format': 'json',
                })

        return Response(status=status.HTTP_201_CREATED)
 def post(self, request, provider):
     try:
         _unbind_social(request.user, provider)
         server_track(request, 'api.user.oauth.unbind_success', {
             'unbind_type': 'social_oauth',
             'provider': provider,
             'uid': request.user.id
         })
     except NotAllowedToDisconnect as ex:
         server_track(request, 'api.user.oauth.unbind_failure', {
             'unbind_type': 'social_oauth',
             'provider': provider,
             'uid': request.user.id,
             'error': {
                 'msg': ex.__class__.__name__,
             }
         })
         raise error.Error(error.SOCIAL_OAUTH_NOT_ALLOWED_TO_DISCONNECT, u'您未绑定过其他联系方式或者{}账号,不能解绑'.format(provider))
     return Response(status=status.HTTP_204_NO_CONTENT)
Exemple #27
0
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'accept_language': '',
            'referer': '',
            'username': '******',
            'ip': '',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': FROZEN_TIME,
            'host': '',
            'context': {},
        }
        self.assert_mock_tracker_call_matches(expected_event)
    def test_server_track_with_no_request(self):
        request = None
        views.server_track(request, str(sentinel.event_type), '{}')

        expected_event = {
            'accept_language': '',
            'referer': '',
            'username': '******',
            'ip': '',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': FROZEN_TIME,
            'host': '',
            'context': {},
        }
        self.assert_mock_tracker_call_matches(expected_event)
Exemple #29
0
    def process_request(self, request):
        try:
            self.enter_course_context(request)

            if not self.should_process_request(request):
                return

            # Removes passwords from the tracking logs
            # WARNING: This list needs to be changed whenever we change
            # password handling functionality.
            #
            # As of the time of this comment, only 'password' is used
            # The rest are there for future extension.
            #
            # Passwords should never be sent as GET requests, but
            # this can happen due to older browser bugs. We censor
            # this too.
            #
            # We should manually confirm no passwords make it into log
            # files when we change this.

            censored_strings = ['password', 'newpassword', 'new_password',
                                'oldpassword', 'old_password']
            post_dict = dict(request.POST)
            get_dict = dict(request.GET)
            for string in censored_strings:
                if string in post_dict:
                    post_dict[string] = '*' * 8
                if string in get_dict:
                    get_dict[string] = '*' * 8

            event = {'GET': dict(get_dict),
                      'POST': dict(post_dict)}

            # TODO: Confirm no large file uploads
            event = json.dumps(event)
            event = event[:512]

            views.server_track(request, request.META['PATH_INFO'], event)
        except:
            pass
Exemple #30
0
    def test_server_track_with_middleware_and_google_analytics_cookie(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899'
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'timestamp': FROZEN_TIME,
                'data': '{"GET": {}, "POST": {}}',
                'name': self.path_with_course,
                'context': {
                    'username': '******',
                    'user_id': '',
                    'accept_language': '',
                    'ip': '127.0.0.1',
                    'org_id': 'foo',
                    'agent': '',
                    'event_source': 'server',
                    'host': 'testserver',
                    'session': '',
                    'referer': '',
                    'client_id': '1033501218.1368477899',
                    'course_id': 'foo/bar/baz',
                    'path': self.path_with_course,
                    'page': None
                }
            }

        finally:
            middleware.process_response(request, None)

        actual_event = self.get_event()
        assert_event_matches(expected_event,
                             actual_event,
                             tolerate={
                                 'string_payload',
                             })
    def password(self, request, data, client):
        """
        Handle ``grant_type=password`` requests as defined in :draft:`4.3`.
        """

        data = self.get_password_grant(request, data, client)
        user = data.get('user')
        scope = data.get('scope')

        if constants.SINGLE_ACCESS_TOKEN:
            at = self.get_access_token(request, user, scope, client)
        else:
            at = self.create_access_token(request, user, scope, client)
            rt = self.create_refresh_token(request, user, scope, at, client)

        # track user login ip
        # TODO: track in authorization grant typer last login ip in auth_userprofile
        user_profile = UserProfile.objects.get(user=user)
        user_profile.last_login_ip = request.META.get('REMOTE_ADDR', None)
        user_profile.save()

        sid = request.META.get('HTTP_SID')
        uid = user.id
        uuid = request.META.get('HTTP_UUID')
        if uuid:
            device, _ = DeviceInfo.objects.get_or_create(uuid=uuid)
            device.uid = uid
            device.save()
        if sid:
            timestamp = time.time()
            IDsInfo.new(sid, uid, uuid, timestamp)

        response = self.access_token_response(at)
        set_login_response_header(request, response)
        login_type = response.get('login_type', '')
        server_track(request, 'api.user.login_success', {
            'uid': user.id,
            'username': user.username,
            'login_type': login_type,
        })
        return response
 def error_response(self, error, mimetype='application/json', status=400,
         **kwargs):
     """
     Return an error response to the client with default status code of
     *400* stating the error as outlined in :draft:`5.2`.
     """
     request = kwargs.get('request')
     if request:
         del kwargs['request']
     response = HttpResponse(json.dumps(error), mimetype=mimetype,
             status=status, **kwargs)
     if request:
         set_login_response_header(request, response)
         login_type = response.get('login_type', '')
         error_dict = {
             'login_type': login_type,
             'error': error
         }
         error_dict['error'].update({'msg': error.get('error', u'登录失败')})
         server_track(request, 'api.user.login_failure', error)
     return response
 def delete(self, request, course_id, format=None):
     """ Unenroll in Course """
     user = request.user
     err = {}
     if not CourseEnrollment.is_enrolled(user, course_id):
         err['err_type'] = 'UserNotEnrolled'
         err['err_msg'] = _("You are not enrolled in this course")
         return Response(err, status=status.HTTP_400_BAD_REQUEST)
     course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
     CourseEnrollment.unenroll(user, course_key)
     dog_stats_api.increment(
         "common.student.unenrollment",
         tags=[u"org:{0}".format(course_key.org),
               u"course:{0}".format(course_key.course),
               u"run:{0}".format(course_key.run)]
     )
     server_track(request, 'api.course.unenrollment', {
         'username': user.username,
         'course_id': course_id,
     })
     return Response()
    def test_server_track(self):
        request = self.request_factory.get(self.path_with_course)
        request.user = self.user
        request.session = {"referer": "www.baidu.com"}
        views.server_track(request, str(sentinel.event_type), '{}')

        '''
        expected_event = {
            'username': '******',
            'ip': '127.0.0.1',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': expected_time,
            'host': 'testserver',
            'context': {},
        }
        '''
        expected_event = {
            'username': '',
            'ip': '127.0.0.1',
            'event_source': 'server',
            'event_type': str(sentinel.event_type),
            'event': '{}',
            'agent': '',
            'page': None,
            'time': '2013/10/03 16:24:55',
            'host': 'testserver',
            'context': {},
            'method': "GET",
            'session': None,
            'referer': '',
            'origin_referer':'www.baidu.com',
            'event_source': 'server',
            'spam':None
        }
        self.mock_tracker.send.assert_called_once_with(expected_event)
    def test_server_track_with_middleware_and_google_analytics_cookie(self):
        middleware = TrackMiddleware()
        request = self.request_factory.get(self.path_with_course)
        request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899'
        request.user = self.user
        request.session = {"referer": "www.baidu.com"}
        middleware.process_request(request)
        # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature.
        self.mock_tracker.reset_mock()
        try:
            views.server_track(request, str(sentinel.event_type), '{}')

            expected_event = {
                'username': '',
                'ip': '127.0.0.1',
                'event_source': 'server',
                'event_type': str(sentinel.event_type),
                'event': '{}',
                'agent': '',
                'page': None,
                'time': '2013/10/03 16:24:55',
                'host': 'testserver',
                'session': None,
                'referer': '',
                'origin_referer': 'www.baidu.com',
                'spam': None,
                'method': 'GET',
                'context': {
                    'user_id': '',
                    'course_id': u'foo/bar/baz',
                    'org_id': 'foo',
                    'path': u'/courses/foo/bar/baz/xmod/'
                },
            }
        finally:
            middleware.process_response(request, None)

        self.mock_tracker.send.assert_called_once_with(expected_event)
Exemple #36
0
    def post(self, request, format=None):
        """ Register a new user. """
        post_vars = request.DATA.copy()
        if 'email' in post_vars:
            register_type = 'email'
        else:
            register_type = 'phone'

        if post_vars.get('register_type', '') == 'auto':
            register_type = 'auto'

        try:
            if 'email' == register_type:
                user, profile, registration = self.create_user_with_email(post_vars, request=request)
            elif 'auto' == register_type:
                user, profile, registration = self.create_tv_user(post_vars, request=request)
            else:  # phone
                user, profile, registration = self.create_user_with_phone(post_vars, request=request)
        except error.Error as ex:
            server_track(request, 'api.user.register_failure', {
                'msg': u'注册失败',
                'register_type': register_type,
                'error': {
                    'msg': ex.err_message,
                    'error_code': ex.err_code,
                },
            })
            raise ex

        result = get_user_info(user)
        response = Response(result, status.HTTP_201_CREATED)
        response['register_type'] = register_type
        server_track(request, 'api.user.register_success', {
            'uid': user.id,
            'username': user.username,
            'register_type': register_type,
        })
        return response
    def post(self, request, course_id, format=None):
        """ Get Enroll the current course. The new version edX has lot of enroll modes. """
        course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
    
        user = request.user
        try:
            course = course_from_key(course_key)
        except ItemNotFoundError:
            return error.ErrorResponse(error.INVALID_PARAMETER, "Course id is invalid", status=status.HTTP_404_NOT_FOUND)

        if not has_access(user, 'enroll', course):
            return error.ErrorResponse(error.INVALID_ENROLLMENT, "Enrollment is closed", status=status.HTTP_400_BAD_REQUEST)

        if CourseEnrollment.is_course_full(course):
            return error.ErrorResponse(error.INVALID_ENROLLMENT, "Course is full", status=status.HTTP_400_BAD_REQUEST)

        available_modes = CourseMode.modes_for_course(course_id)
        available_modes_dict = CourseMode.modes_for_course_dict(course_id, available_modes)
        if CourseMode.has_verified_mode(available_modes_dict):
            return error.ErrorResponse(error.INVALID_ENROLLMENT, "付费课程请在网站加入", status=status.HTTP_400_BAD_REQUEST)
        current_mode = available_modes[0]

        course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
        dog_stats_api.increment(
            "common.student.enrollment",
            tags=["org:{0}".format(course_key.org),
                  "course:{0}".format(course_key.course),
                  "run:{0}".format(course_key.run)]
        )
        server_track(request, 'api.course.enrollment', {
            'username': user.username,
            'course_id': course_id,
        })

        CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
        return Response(status=status.HTTP_201_CREATED)
Exemple #38
0
 def post(self, request, format=None):
     """ Forgot password and send the email. """
     if request.DATA.get('email'):
         try:
             self.reset_password_with_email(request)
             response = Response(status=status.HTTP_204_NO_CONTENT)
             response['reset_type'] = 'email'
             server_track(request, 'api.user.password_reset_success', {
                 'email': request.DATA.get('email'),
                 'reset_type': 'email',
             })
         except error.Error as ex:
             server_track(request, 'api.user.password_reset_failure', {
                 'email': request.DATA.get('email'),
                 'reset_type': 'email',
                 'error': {
                     'msg': ex.err_message,
                     'error_code': ex.err_code,
                 }
             })
             raise ex
     else:
         try:
             self.reset_password_with_phone(request)
             response = Response(status=status.HTTP_204_NO_CONTENT)
             response['reset_type'] = 'phone'
             server_track(request, 'api.user.password_reset_success', {
                 'phone': request.DATA.get('phone'),
                 'reset_type': 'phone',
             })
         except error.Error as ex:
             server_track(request, 'api.user.password_reset_failure', {
                 'phone': request.DATA.get('phone'),
                 'reset_type': 'phone',
                 'error': {
                     'msg': ex.err_message,
                     'error_code': ex.err_code,
                 }
             })
             raise ex
     return response
    def process_request(self, request):
        try:
            self.enter_request_context(request)

            if not self.should_process_request(request):
                return

            # Removes passwords from the tracking logs
            # WARNING: This list needs to be changed whenever we change
            # password handling functionality.
            #
            # As of the time of this comment, only 'password' is used
            # The rest are there for future extension.
            #
            # Passwords should never be sent as GET requests, but
            # this can happen due to older browser bugs. We censor
            # this too.
            #
            # We should manually confirm no passwords make it into log
            # files when we change this.

            censored_strings = ['password', 'newpassword', 'new_password',
                                'oldpassword', 'old_password', 'new_password1', 'new_password2']
            post_dict = dict(request.POST)
            get_dict = dict(request.GET)
            for string in censored_strings:
                if string in post_dict:
                    post_dict[string] = '*' * 8
                if string in get_dict:
                    get_dict[string] = '*' * 8

            event = {
                'GET': dict(get_dict),
                'POST': dict(post_dict),
            }

            # TODO: Confirm no large file uploads
            event = json.dumps(event)
            event = event[:512]

            views.server_track(request, request.META['PATH_INFO'], event)
        except:
            ## Why do we have the overly broad except?
            ##
            ## I added instrumentation so if we drop events on the
            ## floor, we at least know about it. However, we really
            ## should just return a 500 here: (1) This will translate
            ## to much more insidious user-facing bugs if we make any
            ## decisions based on incorrect data.  (2) If the system
            ## is down, we should fail and fix it.
            event = {'event-type': 'exception', 'exception': repr(sys.exc_info()[0])}
            try:
                views.server_track(request, request.META['PATH_INFO'], event)
            except:
                # At this point, things are really broken. We really
                # should fail return a 500 to the user here.  However,
                # the interim decision is to just fail in order to be
                # consistent with current policy, and expedite the PR.
                # This version of the code makes no compromises
                # relative to the code before, while a proper failure
                # here would involve shifting compromises and
                # discussion.
                pass
    def process_request(self, request):
        try:
            self.enter_request_context(request)

            if not self.should_process_request(request):
                return

            # Removes passwords from the tracking logs
            # WARNING: This list needs to be changed whenever we change
            # password handling functionality.
            #
            # As of the time of this comment, only 'password' is used
            # The rest are there for future extension.
            #
            # Passwords should never be sent as GET requests, but
            # this can happen due to older browser bugs. We censor
            # this too.
            #
            # We should manually confirm no passwords make it into log
            # files when we change this.

            censored_strings = ['password', 'newpassword', 'new_password',
                                'oldpassword', 'old_password', 'new_password1', 'new_password2']
            post_dict = dict(request.POST)
            get_dict = dict(request.GET)
            for string in censored_strings:
                if string in post_dict:
                    post_dict[string] = '*' * 8
                if string in get_dict:
                    get_dict[string] = '*' * 8

            event = {
                'GET': dict(get_dict),
                'POST': dict(post_dict),
            }

            # TODO: Confirm no large file uploads
            event = json.dumps(event)
            event = self.truncate_openended_responses(event)

            views.server_track(request, request.META['PATH_INFO'], event)
        except:
            ## Why do we have the overly broad except?
            ##
            ## I added instrumentation so if we drop events on the
            ## floor, we at least know about it. However, we really
            ## should just return a 500 here: (1) This will translate
            ## to much more insidious user-facing bugs if we make any
            ## decisions based on incorrect data.  (2) If the system
            ## is down, we should fail and fix it.
            event = {'event-type': 'exception', 'exception': repr(sys.exc_info()[0])}
            try:
                views.server_track(request, request.META['PATH_INFO'], event)
            except:
                # At this point, things are really broken. We really
                # should fail return a 500 to the user here.  However,
                # the interim decision is to just fail in order to be
                # consistent with current policy, and expedite the PR.
                # This version of the code makes no compromises
                # relative to the code before, while a proper failure
                # here would involve shifting compromises and
                # discussion.
                pass
    def social_oauth(self, request, data, client):
        """
        Handle ``grant_type=social_oauth`` requests as defined in :draft:`4.3`.
        """

        data = self.get_social_oauth_grant(request, data, client)
        uid = data.get('uid')
        access_token = data.get('access_token')
        provider = data.get('provider')
        scope = data.get('scope')
        strategy = get_strategy(provider)
        social_response = {
            'access_token': access_token,
            'uid': uid,
            'openid': uid,
            'provider': provider,
        }
        logging.info('api.oauth.outer.login\n{}'.format(social_response))
        if provider == 'qq':
            social_response.update({
                'SOCIAL_AUTH_QQ_KEY': settings.SOCIAL_AUTH_MOBILE_QQ_OAUTH_CONSUMER_KEY
            })
        user = _created = detail = None
        try:
            # 请求三方接口获得用户信息
            detail = strategy.backend.user_data(access_token, response=social_response)
            logging.info('api.user.oauth.login.response\n{}'.format(detail))
            if 'errcode' in detail:
                server_track(request, 'api.user.oauth.login_failure', {
                    'login_type': 'social_oauth',
                    'error': {
                        'msg': u'三方登录失败',
                        'detail': detail,
                    },
                })
                return self.error_response({
                    'error': u'三方登录失败',
                    'error_description': u"三方登录失败"
                }, request=request)
        except Exception as ex:
            server_track(request, 'api.user.oauth.login_failure', {
                'login_type': 'social_oauth',
                'error': {
                    'msg': ex.__class__.__name__,
                }
            })
            return self.error_response({
                'error': u'三方登录失败',
                'error_description': u"三方登录失败"
            }, request=request)

        try:
            # 创建用户: TODO: 异常处理
            user, _created = _get_or_create_oauth_user(strategy, detail,
                    request, mobile_client=True, created_on='mobile')
            if _created:
                server_track(request, 'api.user.oauth.register_success', {
                    'uid': user.id,
                    'username': user.username,
                    'provider': strategy.backend.name,
                })
        except Exception as ex:
            if not user and (_created is None):
                server_track(request, 'api.user.oauth.register_failure', {
                    'register_type': 'social_oauth',
                    'error': {
                        'msg': ex.__class__.__name__,
                    },
                })
            return self.error_response({
                'error': u'三方登录失败',
                'error_description': u"三方登录失败"
            }, request=request)

        if constants.SINGLE_ACCESS_TOKEN:
            at = self.get_access_token(request, user, scope, client)
        else:
            at = self.create_access_token(request, user, scope, client)
            rt = self.create_refresh_token(request, user, scope, at, client)

        # track user login ip
        # TODO: track in authorization grant typer last login ip in auth_userprofile
        user_profile = UserProfile.objects.get(user=user)
        user_profile.last_login_ip = request.META.get('REMOTE_ADDR', None)
        user_profile.save()

        sid = request.META.get('HTTP_SID')
        uid = user.id
        uuid = request.META.get('HTTP_UUID')
        if uuid:
            device, _ = DeviceInfo.objects.get_or_create(uuid=uuid)
            device.uid = uid
            device.save()
        if sid:
            timestamp = time.time()
            IDsInfo.new(sid, uid, uuid, timestamp)
        uuid = request.META.get('HTTP_UUID')

        response = self.access_token_response(at)
        set_login_response_header(request, response)
        login_type = response.get('login_type', '')
        server_track(request, 'api.user.oauth.login_success', {
            'uid': user.id,
            'username': user.username,
            'provider': strategy.backend.name,
            'login_type': login_type,
        })
        if _created:
            response['register_type'] = 'social_oauth'
        return response