def create(self, request, *args, **kwargs): try: tel = request.data['tel'] code = request.data['code'] data = request.data.copy() if is_tel(tel): check_sms_verify(tel, 1, code) # 以手机号码注册 serializer = UserCreateSerializer(data=data) else: return error_response(3, '请输入合法的手机号码') if serializer.is_valid(): # 注册一个真实用户 user = serializer.create(serializer.validated_data) user.refresh_im_token() data = { 'id': user.id, 'token': user.get_token(), 'im_token': user.get_im_token(), 'name': user.get_full_name(), 'portal': request.build_absolute_uri(user.get_portrait()) } return success_response(data) else: return error_response(1, self.humanize_errors(serializer)) except VerifyError as e: return error_response(2, e.message) except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def verify_phone_number(request): """ Given a phone number (e.164 format) and an active verification code, this endpoint generates a new user account capable of owning access and refresh tokens. An initial set of refresh and access tokens for the new account are returned on success. """ request_data = get_request_data(request.body) if request_data is None: return error_response("Missing or invalid data") current_time = get_current_utc_time() active_codes = get_active_verification_codes_for_phone_number( request_data.phone_number, current_time) is_valid_code = request_data.verification_code in active_codes if not is_valid_code: return error_response("Invalid verification code") invalidate_verification_code(request_data.verification_code) user, created = get_or_create_user(phone_number=request_data.phone_number) if not created: logger.info( f"Generating refresh token for existing user {user.user_id}") refresh_token = generate_and_record_refresh_token(user, current_time) access_token, token_payload = generate_access_token_for_user( user.user_id, current_time) expiry_time = from_timestamp(token_payload["exp"]) response_data = ResponseData(refresh_token=refresh_token, access_token=access_token, expiry_time=expiry_time) return success_response(response_data)
def send_verification_code(request) -> HttpResponse: request_data = get_request_data(request.body) if request_data is None: return error_response() phone_number = get_e164_phone_number(request_data.phone_number, request_data.region) if phone_number is None: return error_response("invalid phone_number") current_time = get_current_utc_time() verification_code_expiry_time = current_time + timedelta( seconds=VERIFICATION_CODE_LIFETIME_SECONDS ) provider = get_communication_provider() message_status_callback = settings.TWILIO_MESSAGE_STATUS_CALLBACK success, verification_code = send_verification_code_sms( provider=provider, phone_number=phone_number, verification_code_population=VERIFICATION_CODE_ALPHABET, verification_code_length=VERIFICATION_CODE_LENGTH, verification_code_expiry_time=verification_code_expiry_time, callback=message_status_callback, max_retries=3, ) if success is False: invalidate_verification_code(verification_code) return error_response("failed to send verification token", status=503) return success_response({"phone_number": phone_number})
def send_verification_code(request) -> HttpResponse: """ Validates, formats and requests an SMS from the configured provider. The requested phone_number received a temporary verification code which should be supplied to the verify_phone_number endpoint. """ request_data = get_request_data(request.body) if request_data is None: return error_response() phone_number = get_e164_phone_number(request_data.phone_number, request_data.region) if phone_number is None: return error_response("Invalid phone_number") current_time = get_current_utc_time() verification_code_expiry_time = current_time + timedelta( seconds=VERIFICATION_CODE_LIFETIME_SECONDS) provider = get_communication_provider() message_status_callback = settings.TWILIO_MESSAGE_STATUS_CALLBACK success, verification_code = send_verification_code_sms( provider=provider, phone_number=phone_number, verification_code_population=VERIFICATION_CODE_ALPHABET, verification_code_length=VERIFICATION_CODE_LENGTH, verification_code_expiry_time=verification_code_expiry_time, callback=message_status_callback, ) if success is False: invalidate_verification_code(verification_code.code) return error_response("Failed to send verification SMS", status=503) return success_response({"phone_number": phone_number})
def verify_phone_number(request): request_data = get_request_data(request.body) if request_data is None: return error_response("missing or invalid data") current_time = get_current_utc_time() active_codes = get_active_verification_codes_for_phone_number( request_data.phone_number, current_time ) is_valid_code = request_data.verification_code in active_codes if not is_valid_code: return error_response("invalid verification code") current_time = get_current_utc_time() user, created = get_or_create_user(phone_number=request_data.phone_number) if not created: return error_response("phone number has already been verified") refresh_token = generate_and_record_refresh_token(user, current_time) access_token, token_payload = generate_access_token_for_user( user.user_id, current_time ) expiry_time = from_timestamp(token_payload["exp"]) response_data = ResponseData( refresh_token=refresh_token, access_token=access_token, expiry_time=expiry_time ) return success_response(response_data)
def wrapper(request, *args, **kwargs): if settings.IS_TEST_ENVIRONMENT: user = get_user_from_test_user_header(request.META) if user is not None: request.user = user return func(request, *args, **kwargs) auth_header = get_authorization_header(request.META) if auth_header is None: return error_response(status=401, message="Missing authorization header") token = get_token_from_authorization_header(auth_header) try: claims = decode(token, public_key, algorithms="RS256", audience=AUDIENCE_NAME) user, created = get_or_create_user(claims["sub"]) except (InvalidTokenError, KeyError) as e: logger.info("Failed to decode authorization token: %s", e) return error_response(status=401, message="Invalid authorization token") if created: logger.info( "First time user with external_id '%s' has authenticated", claims["sub"], ) request.user = user return func(request, *args, **kwargs)
def create(self, request, *args, **kwargs): try: to_user = User.objects.get(id=request.data['to_user']) # 我->他人 关系处理 friend_from, is_created_from = self.get_queryset().get_or_create( from_user=request.user, to_user=to_user) if not is_created_from: if friend_from.is_block: # 若已拉黑则解除拉黑 friend_from.is_block = False else: if friend_from.state == FriendState.Agree: return error_response(3, '不可重复添加好友') friend_from.state = 1 friend_from.say_hi = request.data['say_hi'] if 'remark' in request.data: friend_from.remark = request.data['remark'] else: friend_from.remark = to_user.get_full_name() friend_from.save() # TODO 向他人推送我请求加他为好友 try: jpush.audience( to_user.id, '好友请求', '用户{}请求添加您为好友'.format(request.user.get_full_name()), {'operation': 'friend_add'}) except PushError as e: logging.error('{} {}'.format(e.code, e.message)) return success_response('请求已发送') except User.DoesNotExist: return error_response(2, '该用户不存在') except Exception as e: return error_response(1, str(e))
def delete_move_handler(request, move_id): uuid_move_id = parse_move_id_as_uuid(move_id) if uuid_move_id is None: return error_response(status=404) move = get_move_by_move_id(request.user, uuid_move_id) if move is None: return error_response(status=404) delete_move(move) return success_response(status=204)
def check(self, request): try: instance = self.get_queryset().get(user=self.request.user, version=request.data['version']) return success_response(instance.is_agree) except ObjectDoesNotExist: return success_response(False) except MultipleObjectsReturned: return success_response(False) except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def update_trip_handler(request, trip_id): db_trip = get_trip_by_id(request.user, trip_id) if not db_trip: return error_response(status=404) parsed_body = safe_parse_json(request.body) if parsed_body is None: return error_response(message="Could not parse JSON body") try: updated_trip = update_trip(request.user, db_trip, **parsed_body) except UpdateNotAllowed: return validation_error_response( ["Cannot update one or more requested fields"]) return success_response(data=Trip.from_db_model(updated_trip))
def find_pwd(self, request): try: tel = request.data['tel'] code = request.data['code'] # 防止输入空用户名试图登陆 if not tel or tel == '': return error_response(2, '无此用户') if is_tel(tel): check_sms_verify(tel, 2, code) user = User.objects.get(tel=tel) else: return error_response(4, '请使用合法号码找回密码') if user.is_active: user.set_password(request.data['pwd_new']) user.save() return success_response('找回密码成功。') else: return error_response(6, '该账号未激活') except VerifyError as e: return error_response(3, e.message) except User.DoesNotExist: return error_response(2, '无此用户') except User.MultipleObjectsReturned: return error_response(5, '用户登陆凭证冲突') except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def exist(self, request): try: username = request.data['username'] User.objects.get( Q(username=username) | Q(tel=username) | Q(email=username)) return success_response(True) except ObjectDoesNotExist: return success_response(False) except MultipleObjectsReturned: return success_response(False) except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def trip_id_endpoint(request, *args, **kwargs): if request.method == "GET": return get_trip_handler(request, *args, **kwargs) if request.method == "PATCH": return update_trip_handler(request, *args, **kwargs) return error_response(status=404)
def get_trip_handler(request, trip_id): db_trip = get_trip_by_id(request.user, trip_id) if not db_trip: return error_response(status=404) trip = get_response_trip(db_trip) return success_response(data=trip)
def revoke_refresh_token(request): request_data = get_request_data(request.body) if request_data is None: return error_response("Invalid or malformed request data") payload = get_refresh_token_payload_if_active(request_data.refresh_token) if payload is None: return error_response("Refresh token is invalid") success = delete_refresh_token(token_id=payload["jti"]) if not success: logger.info( f"Attempt to delete non-existent token: sub={payload['sub']}, jti={payload['jti']}" ) return success_response(status=204)
def root_endpoint(request, *args, **kwargs): if request.method == "GET": return list_trips_handler(request, *args, **kwargs) if request.method == "POST": return create_trip_handler(request, *args, **kwargs) return error_response(status=404)
def nearby_posts(self, request, *args, **kwargs): serializer = PostNearBySerializer(data=request.data) if serializer.is_valid(): data = serializer.validated_data longitude = float(data['longitude']) latitude = float(data['latitude']) distance = float(data['distance']) lon_min, lon_max, lat_min, lat_max = bounding_box(longitude, latitude, distance) # 正方形内帖子 box_queryset = self.get_queryset().filter(longitude__gte=lon_min, longitude__lte=lon_max, latitude__gte=lat_min, latitude__lte=lat_max) # 正方形内筛选圆形区域 ids = [] for x in box_queryset: if haversine(longitude, latitude, x.longitude, x.latitude) <= distance: ids.append(x.id) queryset = box_queryset.filter(id__in=ids) # list部分 queryset = self.filter_queryset(queryset) context = self.get_serializer_context() context.update({'longitude': longitude, 'latitude': latitude}) page = self.paginate_queryset(queryset) if page is not None: serializer = PostDistanceListSerializer(page, context=context, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, context=context, many=True) return success_response(serializer.data) else: return error_response(1, self.humanize_errors(serializer))
def destroy(self, request, *args, **kwargs): instance = self.get_object() if request.user == instance.from_user: self.perform_destroy(instance) return success_response('删除成功') else: return error_response(1, '无此权限')
def push(self, request): try: jpush.audience(request.user.id, 'Hello', 'hello python jpush api', {}) return success_response('推送成功') except PushError as e: return error_response(e.code, e.message)
def login(self, request): try: username = request.data['username'] try: instance = User.objects.get( Q(username=username) | Q(tel=username)) except ObjectDoesNotExist: return error_response(2, '用户名或密码错误') except MultipleObjectsReturned: return error_response(3, '用户登陆凭证冲突') if 'password' in request.data: # 密码登陆 user = authenticate(username=instance.username, password=request.data['password']) elif 'code' in request.data: # 验证码登陆 if is_tel(username): try: check_sms_verify(username, 4, request.data['code']) user = instance except VerifyError as e: return error_response(5, e.message) else: return error_response(6, '请输入合法号码') else: return error_response(5, '未提供登陆凭证') if user is not None: if user.is_active: # 登陆系统 login(request, user) # 更新登陆时间 user.last_login = timezone.now() user.save() data = { 'id': user.id, 'token': user.get_token(), 'im_token': user.get_im_token(), 'name': user.get_full_name(), 'portal': request.build_absolute_uri(user.get_portrait()) } return success_response(data) else: return error_response(4, '该账号未激活') else: return error_response(2, '用户名或密码错误') except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def message_status_webhook(request): request_data = get_request_data(request.POST) if request_data is None: logger.error("got invalid webhook request") return error_response() logger.info(f"message status updated: {request_data}") return success_response()
def change_pwd(self, request): try: user = authenticate(username=request.user.username, password=request.data['pwd_old']) if user is not None: if user.is_active: user.set_password(request.data['pwd_new']) user.save() return success_response('修改成功。') else: return error_response(3, '该账号未激活') else: return error_response(2, '旧密码错误') except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def create(self, request, *args, **kwargs): data = request.data.copy() data['user'] = request.user.id serializer = self.get_serializer(data=data) if serializer.is_valid(): serializer.save() return success_response('设置成功') else: return error_response(1, self.humanize_errors(serializer))
def create(self, request, *args, **kwargs): self.before_create() serializer = self.get_serializer(data=request.data) if serializer.is_valid(): instance = self.perform_create(serializer) return success_response(self.serializer_classes['retrieve']( instance, context=self.get_serializer_context()).data) else: return error_response(1, self.humanize_errors(serializer))
def create_location_handler(request, trip_id): db_trip = get_trip_by_id(request.user, trip_id) if not db_trip: return error_response(status=404) event = parse_location_from_request_body(request.body) if not event.is_valid: return validation_error_response(event.validation_errors) location = persist_location(db_trip, event) return success_response(status=201, data=location)
def retrieve_access_token(request): request_data = get_request_data(request.body) if request_data is None: return error_response("Invalid or missing fields in request body") refresh_token_payload = get_refresh_token_payload_if_active( request_data.refresh_token ) if refresh_token_payload is None: return error_response("Refresh token is invalid") current_time = get_current_utc_time() access_token, access_token_payload = generate_access_token_for_user( refresh_token_payload["sub"], current_time ) response_data = ResponseData( access_token=access_token, expiry_time=from_timestamp(access_token_payload["exp"]), ) return success_response(response_data)
def send_verify(self, request): try: purpose = int(request.data['purpose']) tel = request.data['tel'] if is_tel(tel): if purpose == 1 and User.objects.filter(tel=tel).exists(): return error_response(2, '该用户已注册,请直接登陆') elif purpose == 2 and not User.objects.filter( tel=tel).exists(): return error_response(3, '该用户未注册,无法找回密码') # 发送短信验证码 tel_verify, create = TelVerify.objects.get_or_create( tel=tel, purpose=purpose) # 未创建则更新 if not create: tel_verify.update() # 更新发送时间 tel_verify.send_time = timezone.now() tel_verify.save() # 发送短信 is_success, message = tel_verify.send_sms() if is_success: return success_response('发送成功') else: logger.error('短信发送失败 原因:{}'.format(message)) return error_response(5, message) else: return error_response(4, '请输入合法号码') except KeyError as e: return error_response(1, '获取参数{}失败'.format(e.__context__)) except Exception as e: return error_response(1, str(e))
def operate(self, request): serializer = FavoritesOperateSerializer( data=request.data, context=self.get_serializer_context()) if serializer.is_valid(): data = serializer.validated_data if data['operate'] == 0: data['favorites'].posts.add(data['post']) return success_response('收藏成功') else: # 取消收藏 data['favorites'].posts.remove(data['post']) return success_response('取消收藏成功') else: return error_response(1, self.humanize_errors(serializer))
def revoke_refresh_token(request): """ Revokes a refresh token. This revokes the tokens ability to generate new access tokens. Note: Existing access tokens generated by the revoked refresh token will continue to be valid until they expire. """ request_data = get_request_data(request.body) if request_data is None: return error_response("Invalid or malformed request data") payload = get_refresh_token_payload_if_active(request_data.refresh_token) if payload is None: return error_response("Refresh token is invalid") success = delete_refresh_token(token_id=payload["jti"]) if not success: logger.info( f"Attempt to delete non-existent token: sub={payload['sub']}, jti={payload['jti']}" ) return success_response(status=204)
def itinerary_handler(request, trip_id): trip = get_trip_by_id(request.user, trip_id) if trip is None: return error_response(status=404) locations = get_locations_for_trip(trip) logger.info( "constructing itinerary for trip '%s' with %d locations", trip.trip_id, len(locations), ) itinerary = get_itinerary_events_by_day_for_locations(locations) return success_response(data={"itinerary": to_response_shape(itinerary)})