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
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)
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)
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 )
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)
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)
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': expected_time, 'host': '', 'context': {}, } self.mock_tracker.send.assert_called_once_with(expected_event)
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)
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)
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)
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)
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 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
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)
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)
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