def parse_json_request(self) -> Any: """Parse the request body as JSON. Raise UnsupportedMediaType if the content type does not indicate a JSON request or if it contains invalid JSON. """ if self.request.mimetype != "application/json": raise UnsupportedMediaType() try: j = self.request.data.decode(self._charset) return json_loads(j) except (LookupError, JSONDecodeError) as exc: raise UnsupportedMediaType(str(exc)) from exc
def post(self): args = post_parser.parse_args() json_data = dict() json_data['_id'] = ObjectId() json_data['title'] = args['title'] json_data['subtitles'] = args['subtitles'] json_data['contents'] = args['contents'] json_data["writer_id"] = ObjectId(get_jwt_identity()) json_data["created_date"] = time.mktime(datetime.datetime.utcnow().timetuple()) sound_file = args['sound'] extension = os.path.splitext(sound_file.filename)[1] sound_file.filename = str(json_data['_id']) + extension if not allowed_file(sound_file.filename, SOUND_ALLOWED_EXTENSIONS): raise UnsupportedMediaType(errors.UNSUPPORT_MEDIA_TYPE) json_data["sound_url"] = os.path.join(request.url, 'sound', sound_file.filename) storage.upload_file(SOUND_RESOURCE, sound_file) mongo.db.questions.insert(json_data) json_data['writer'] = get_user(ObjectId(get_jwt_identity())) return json_data, 201
def validate_message(request): """ Validates message is well formed and has valid signature """ if request.method != 'POST': raise MethodNotAllowed(valid_methods="POST") content_type = request.headers['content-type'] if content_type != 'application/json': raise UnsupportedMediaType( description="Unknown content type: {}".format(content_type)) # parse the content as JSON request_json = request.get_json(silent=False) if not request_json or request_json.keys() < { "merchant_id", "location_id", "event_type", "entity_id" }: raise BadRequest( description="JSON is invalid, or missing required property") # ensure the request is signed as coming from Square try: validate_square_signature(request) except ValueError: raise BadRequest(description="Signature could not be validated") return request_json
def acceptOffer(): """ This method is used to accept offer input: job id, offer id return: boolean """ if session.get('user') is None: raise Unauthorized() if not request.is_json: raise UnsupportedMediaType() body = request.get_json() if body.get('job_id') is None: raise BadRequest('missing jobID property') if body.get('offerID') is None: raise BadRequest('missing offerID property') jobID = body.get('job_id') job = jobs.find_one({"_id":ObjectId.ObjectId(jobID)}) if job is None: raise BadRequest("Invalid Job ID") if job["user"] != ObjectId.ObjectId(session.get('user')["$oid"]): raise Unauthorized() if job["job_status"] != "Open": raise BadRequest("Job already taken") jobs.update_one({'_id':ObjectId.ObjectId(body.get('job_id'))},{'$set':{"job_status":"Closed"}}) return Response(status=200)
def decorated_function(*args, **kwargs): """ Checks that the media type is correct """ pattern = re.compile(content_type + '.*') if 'Content-Type' in request.headers: if pattern.match(request.headers['Content-Type']): return f(*args, **kwargs) else: app.logger.error('Invalid Content-Type: %s', request.headers['Content-Type']) raise UnsupportedMediaType( ' Content-Type must be {}'.format(content_type)) else: # provide no content type app.logger.error('Provide No Content-Type') raise UnsupportedMediaType( ' Content-Type must be {}'.format(content_type))
def review(): """ This method is used to give mover_reviews input: rating return: """ # Bounce any requests that are not JSON type requests if session.get('user') is None: raise Unauthorized() if not request.is_json: raise UnsupportedMediaType() body = request.get_json() if body.get('rating') is None: raise BadRequest('missing rating property') review_score = body.get('rating') userId = body.get('moverID') if users.find({'_id':ObjectId.ObjectId(userId)}) is None: raise BadRequest("invalid User ID") rev = {'userId': userId, 'review_score':review_score} moverReviews.insert_one(rev) return Response(status=201)
def add_new_user(): """ This method is used to register a new user. :return: """ # Bounce any requests that are not JSON type requests if not request.is_json: raise UnsupportedMediaType() # Check that the request body has `username` and `password` properties body = request.get_json() if body.get('username') is None: raise BadRequest('missing username property') if body.get('password') is None: raise BadRequest('missing password property') password_hash = security.generate_password_hash(body.get('password')) try: mongo.db.users.insert_one({ 'username': body.get('username'), 'password_hash': password_hash }) except DuplicateKeyError: raise NotFound('User already exists') # check that mongo didn't fail return Response(status=201)
def add_metadata(self, circuit_id): """Add metadata to an EVC.""" try: metadata = request.get_json() content_type = request.content_type except BadRequest as error: result = "The request body is not a well-formed JSON." raise BadRequest(result) from error if content_type is None: result = "The request body is empty." raise BadRequest(result) if metadata is None: if content_type != "application/json": result = ( "The content type must be application/json " f"(received {content_type})." ) else: result = "Metadata is empty." raise UnsupportedMediaType(result) try: evc = self.circuits[circuit_id] except KeyError as error: raise NotFound(f"circuit_id {circuit_id} not found.") from error evc.extend_metadata(metadata) evc.sync() return jsonify("Operation successful"), 201
def item_error(self): """Raise an error.""" error_code = resource_requestctx.route["error_code"] if error_code == 415: raise UnsupportedMediaType() elif error_code == 400: raise BadRequest()
def put(self, nickname): ''' Adds a new user in the database. :param str nickname: Nickname of the required user. ENTITY BODY INPUT FORMAT: { 'public_profile':{'signature': <signature>,'avatar': <avatar>}, 'restricted_profile':{'firstname': <name>, 'lastname': <surname>, 'email': <email address>, 'website': <webpage url> (optional attribute), 'mobile': <mobile phone number> (optional), 'skype': <skype nickname> (optional), 'birtday': <birthday>, 'residence': <address>, 'gender': <gender>, 'picture': <picture file name> (optional) } } OUTPUT: * Returns 201 + the url of the new resource in the Location header * Return 409 Conflict if there is another user with the same nickname * Return 400 if the body is not well formed * Return 415 if it receives a media type != application/json ''' # PERFORM INITAL CHECKING: # Check that there is no other user with the same nickname if g.con.contains_user(nickname): abort(409, message="There is already a user with same nickname %s.\ Try another user " % nickname, resource_type="User", resource_url=request.path, resource_id=nickname) # PARSE THE REQUEST: user = request.get_json() if not user: raise UnsupportedMediaType() # Get the request body and serialize it to object # We should check that the format of the request body is correct. Check # That mandatory attributes are there. if not all(attr in user['public_profile'] for attr in ('signature', 'avatar')): abort(400) if not all(attr in user['restricted_profile'] for attr in ('firstname', 'lastname', 'birthday', 'residence', 'gender', 'email')): abort(400) # But we are not going to do this exercise nickname = g.con.append_user(nickname, user) # CREATE RESPONSE AND RENDER return Response( status=201, headers={"Location": api.url_for(User, nickname=nickname)})
def create_job(): """ Create a record in the jobs collection. Only possible if the user is logged in!! """ # Bounce any requests that are not JSON type requests if not request.is_json: raise UnsupportedMediaType() if session.get('user') is None: raise Unauthorized() # Check that the JSON request has the fields you expect body = request.get_json() if body.get('start_time') is None: raise BadRequest('missing start_time property') if body.get('end_time') is None: raise BadRequest('missing end_time property') # ... obviously you'll want to have many more fields # Create a dictionary that will be inserted into Mongo job_record = {'start_time': body.get('start_time'), 'end_time': body.get('end_time')} job_record.update({'user': session['user']['_id']['$oid']}) # Insert into the mongo collection res = mongo.db.jobs.insert_one(job_record) return Response(str(res.inserted_id), 200)
def put(self, request, response, key): # Limit charset of keys. if re.match("^[A-Za-z0-9_]+$", key) is None: return Forbidden() if not self.authorized(request): logger.warning("Unauthorized request.", extra={'location': request.url, 'details': repr(request.authorization)}) raise CustomUnauthorized(self.realm_name) if request.mimetype != "application/json": logger.warning("Unsupported MIME type.", extra={'location': request.url, 'details': request.mimetype}) raise UnsupportedMediaType() try: data = json.load(request.stream) except (TypeError, ValueError): logger.warning("Wrong JSON.", extra={'location': request.url}) raise BadRequest() try: if key not in self.store: self.store.create(key, data) else: self.store.update(key, data) except InvalidData: logger.warning("Invalid data.", exc_info=True, extra={'location': request.url, 'details': pprint.pformat(data)}) raise BadRequest() response.status_code = 204
def login(): """ This method logs the user in by checking username + password against the mongo database :return: """ # Bounce any requests that are not JSON type requests if not request.is_json: raise UnsupportedMediaType() # Check that the request body has `username` and `password` properties body = request.get_json() if body.get('username') is None: raise BadRequest('missing username property') if body.get('password') is None: raise BadRequest('missing password property') user = mongo.db.users.find_one({'username': body.get('username')}) if user is None: session.clear() raise BadRequest('User not found') if not bcrypt.check_password_hash(user['password_hash'], body.get('password')): session.clear() raise BadRequest('Password does not match') # this little trick is necessary because MongoDb sends back objects that are # CLOSE to json, but not actually JSON (principally the ObjectId is not JSON serializable) # so we just convert to json and use `loads` to get a dict serializable_user_obj = json.loads(json_util.dumps(user)) session['user'] = serializable_user_obj return Response(status=200)
def decorated(*args, **kwargs): if request.mimetype not in ('application/json',): raise UnsupportedMediaType( "You must send a raw body in JSON format with the Content-Type" " header properly set to application/json.") return f(*args, **kwargs)
def check_content_type(content_type): """ Validate the content type of request """ if (request.headers['Content-Type'] == content_type): return app.logger.error('Invalid Content_Type: %s', request.headers['Content-Type']) raise UnsupportedMediaType('Content-Type must be {}'.format(content_type))
def upload_poster_img(file): """Uploads a file to the server's filesystem. Takes the file as an argument.""" # TODO: optimum size for the page is 540x816. if the pic is larger, # resize before saving if file and allowed_file(file.filename): filename = secure_filename(file.filename.replace(" ", "_")) full_filename = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(full_filename) # create a thumbnail image for search displays size = (200, 325) thumbnail = os.path.splitext(full_filename)[0] + ".thumbnail" try: im = Image.open(full_filename) img_copy = im.copy() img_copy.thumbnail(size) img_copy.save(thumbnail, "JPEG") except IOError: raise IOError( "Couldn't create a thumbnail of your image. Please try again." ) return filename else: raise UnsupportedMediaType( "Couldn't save your image. " + "Please make sure to upload a .jpg, .jpeg, .png, or .gif file.")
def put_list(self, request, response): if not self.authorized(request): logger.info("Unauthorized request.", extra={'location': request.url, 'details': repr(request.authorization)}) raise CustomUnauthorized(self.realm_name) if request.mimetype != "application/json": logger.warning("Unsupported MIME type.", extra={'location': request.url, 'details': request.mimetype}) raise UnsupportedMediaType() try: data = json.load(request.stream) except (TypeError, ValueError): logger.warning("Wrong JSON.", extra={'location': request.url}) raise BadRequest() try: self.store.merge_list(data) except InvalidData: logger.warning("Invalid data.", exc_info=True, extra={'location': request.url, 'details': pprint.pformat(data)}) raise BadRequest() response.status_code = 204
def create_job(): """ Create a record in the jobs collection. Only possible if the user is logged in!! """ # Bounce any requests that are not JSON type requests if not request.is_json: raise UnsupportedMediaType() if session.get('user') is None: raise Unauthorized() # Check that the JSON request has the fields you expect body = request.get_json() if body.get('start_time') is None: raise BadRequest('missing start_time property') if body.get('end_time') is None: raise BadRequest('missing end_time property') if body.get('start_address') is None: raise BadRequest("missing start address property") if body.get('end_address') is None: raise BadRequest("missing end address property") if body.get("description") is None: raise BadRequest("missing description property") if body.get("max_price") is None: raise BadRequest("missing max price property") else: try: max_price = float(body.get("max_price")) except Exception,e: raise BadRequest("Invalid max price property")
def upload_postprocessing_stack(): # TODO document returns """ API endpoint for uploading the given postprocessing stack to the Postprocessing server This request must contain the scripts in the 'files[]' field and the corresponding metadata in the 'fileMeta[]' field. The metadata object should contain the 'name' and the 'description' of the corresponding script. The order of the files represents the order in which the scripts will be executed in a postprocessing task. The form part of the multipart-form request should contain the following fields: 'name', 'description' and 'author' """ if request.mimetype == 'multipart/form-data': identity = get_jwt_identity() username = identity.get('username') meta_list = request.form.getlist('fileMeta[]') scripts = [] for index, entry in enumerate(request.files.getlist('files[]')): print(entry.filename) print(meta_list[index]) meta = json.loads(meta_list[index]) script = PostprocessingScript(name=meta['name'], description=meta['description'], index=index, file=entry.stream.read()) scripts.append(script) stack = PostprocessingStack(name=request.form['name'], description=request.form['description'], author=username, scripts=scripts) upload_stack(stack) return jsonify({'msg': 'Uploaded stack successfully'}), 201 else: raise UnsupportedMediaType( "Media type has to be 'multipart/form-data'")
def add_new_user(): """ This method is used to register a new user. """ # Bounce any requests that are not JSON type requests if not request.is_json: raise UnsupportedMediaType() # Check that the request body has required properties body = request.get_json() if body.get('name') is None: raise BadRequest('missing name property') if body.get('password') is None: raise BadRequest('missing password property') if body.get('email') is None: raise BadRequest('missing email property') if body.get('phone_number') is None: raise BadRequest('missing phone_number property') password_hash = bcrypt.generate_password_hash(body.get('password')) try: mongo.db.users.insert_one({ '_id': body.get('email'), 'password_hash': password_hash, 'name': body.get('name'), 'phone_number': body.get('phone_number') }) except DuplicateKeyError: raise NotFound('User already exists') # check that mongo didn't fail return Response(status=201)
def wsgi_app(self, environ, start_response): """Execute this instance as a WSGI application. See the PEP for the meaning of parameters. The separation of __call__ and wsgi_app eases the insertion of middlewares. """ urls = self._url_map.bind_to_environ(environ) try: endpoint, args = urls.match() except HTTPException as exc: return exc assert endpoint == "rpc" remote_service = ServiceCoord(args['service'], args['shard']) if remote_service not in self._service.remote_services: return NotFound() if self._auth is not None and not self._auth( args['service'], args['shard'], args['method']): return Forbidden() request = Request(environ) request.encoding_errors = "strict" # TODO Check content_encoding and content_md5. if request.mimetype != "application/json": return UnsupportedMediaType() if request.accept_mimetypes.quality("application/json") <= 0: return NotAcceptable() try: data = json.load(request.stream) except ValueError: return BadRequest() if not self._service.remote_services[remote_service].connected: return ServiceUnavailable() result = self._service.remote_services[remote_service].execute_rpc( args['method'], data) result.wait(timeout=60) response = Response() response.status_code = 200 response.mimetype = "application/json" response.data = json.dumps({ "data": result.value, "error": None if result.successful() else "%s" % result.exception }) return response
def post(self, messageid): ''' Adds a response to a message with id <messageid>. INPUT PARAMETERS: :param str messageid: The id of the message to be deleted ENTITY BODY INPUT FORMAT: The entity body is a JSON representation with the following format: {'title': <newTitle>,'body': <newBody>, 'sender': <sender user>} Use 'Anonymous' is 'sender' field does not exist. OUTPUT: * Returns 201 if the message has been added correctly. The Location header contains the path of the new message * Returns 400 if the message is not well formed or the entity body is empty. * Returns 404 if there is no message with messageid * Returns 415 if the format of the response is not json * Returns 500 if the message could not be added to database. ''' # CHECK THAT MESSAGE EXISTS # If the message with messageid does not exist return status code 404 if not g.con.contains_message(messageid): raise NotFound() # Extract the request body. In general would be request.data # Since the request is JSON I use request.get_json # get_json returns a python dictionary after serializing the request body # get_json returns None if the body of the request is not formatted # using JSON data = request.get_json() if not data: raise UnsupportedMediaType() # It throws a BadRequest exception, and hence a 400 code if the JSON is #not wellformed try: title = data['title'] body = data['body'] sender = data.get('sender', 'Anonymous') ipaddress = request.remote_addr except: # This is launched if either title or body does not exist. abort(400) # Create the new message and build the response code' newmessageid = g.con.append_answer(messageid, title, body, sender, ipaddress) if not newmessageid: abort(500) # Create the Location header with the id of the message created url = api.url_for(Message, messageid=newmessageid) # RENDER # Return the response return Response(status=201, headers={'Location': url})
def validate_input_file(handle, mimetype): """Validate that an input file is a known text encoding if text or a readable Excel spreadsheet. Raise UnsupportedMediaType error if not.""" handle.seek(0) if mimetype in ("text/plain", "text/csv"): buf = handle.read(512) if len(buf) > 0: merlin = magic.Magic(mime_encoding=True) encoding = merlin.from_buffer(buf) if encoding == "binary": raise UnsupportedMediaType() else: try: xlrd.open_workbook(file_contents=handle.read()) except AssertionError: # This is the error created if we can't open the spreadsheet raise UnsupportedMediaType() handle.seek(0)
def monzo_hook(): if not request.is_json: logger.info( f"Monzo hook called with unsupported mimetype: {request.mimetype}") raise UnsupportedMediaType() logger.info(f"Monzo hook called with request body: {request.json}") status_code = webhook.handle_incoming_transaction(request.json) return ("", status_code)
def edit_profile(): form = generate_edit_user_public_profile_form(current_user) if form.validate_on_submit(): display_name = form.display_name.data if form.display_name.data != '' \ else current_user.display_name current_user.display_name = display_name current_user.description = form.description.data if form.university_check.data: current_user.educational_institution = None \ if form.university.data == '' else form.university.data else: current_user.educational_institution = None if form.display_image.data: try: current_user.display_image = form.display_image.data except PIL.UnidentifiedImageError: raise UnsupportedMediaType( \ description="Uploaded file is not an image") db.session.add(current_user) db.session.commit() return redirect(url_for('profile.edit_profile')) # Generate sidebar organisations = {} if current_user.departments: for department in current_user.departments: try: display_name = department.organisation.display_name organisations[display_name] except AttributeError: if department.temp_organisation is None: # We have a consistency error! continue display_name = department.temp_organisation organisations[display_name] = { # TODO: make this the pending organisation page 'link': None, 'departments': {} } except KeyError: organisations[display_name] = { 'link': url_for('profile.edit_organisation', id=department.organisation.id), 'departments': {} } organisations[display_name]['departments']\ [department.display_name] = { 'link': url_for('organisations.edit_department', department_id=department.id) } return render_template('profile/profile.html', user=current_user, organisations=organisations, form=form)
def list_error(self): """Raise an error.""" # TODO: Make it easier to get request.args into resource_requestctx by default error_code = request.args["error_code"] if error_code == "415": raise UnsupportedMediaType() elif error_code == "400": raise BadRequest() return ([],)
def wrapped_route(*args, **kwargs): if missing_ok and request.content_length is None and not request.mimetype: pass elif request.mimetype not in allowed: raise UnsupportedMediaType( f"Body data Content-Type must be {prose_list(allowed)}{' when a body is sent' if missing_ok else ''}" ) return route(*args, **kwargs)
def wrapper(request, *args, **kwargs): try: data = str(request.data, "utf-8").strip() except UnicodeDecodeError: raise UnsupportedMediaType( "Cannot parse request body: invalid UTF-8 data") if not data: raise UnsupportedMediaType( "Cannot parse request body: no data supplied") try: data = json.loads(data) except json.decoder.JSONDecodeError: raise UnsupportedMediaType( "Cannot parse request body: invalid JSON") if not isinstance(data, body_type): raise UnprocessableEntity( f"Invalid data format: {body_type.__name__} expected") if body_type == dict and content_types: too_many = data.keys() - sig.parameters.keys() if too_many: raise UnprocessableEntity( f"Key not allowed: {', '.join(too_many)}") kwargs.update(data) bound = sig.bind_partial(request, *args, **kwargs) bound.apply_defaults() missing = sig.parameters.keys() - bound.arguments.keys() if missing: raise UnprocessableEntity(f"Key missing: {', '.join(missing)}") for key, data_type in content_types.items(): if not isinstance(bound.arguments[key], data_type): raise UnprocessableEntity( f"Invalid format: '{key}' must be of type {data_type.__name__}." ) else: kwargs["data"] = data return func(request, *args, **kwargs)
def update(self, circuit_id): """Update a circuit based on payload. The EVC required attributes (name, uni_a, uni_z) can't be updated. """ log.debug("update /v2/evc/%s", circuit_id) try: evc = self.circuits[circuit_id] except KeyError: result = f"circuit_id {circuit_id} not found" log.debug("update result %s %s", result, 404) raise NotFound(result) from NotFound if evc.archived: result = "Can't update archived EVC" log.debug("update result %s %s", result, 405) raise MethodNotAllowed(["GET"], result) try: data = request.get_json() except BadRequest: result = "The request body is not a well-formed JSON." log.debug("update result %s %s", result, 400) raise BadRequest(result) from BadRequest if data is None: result = "The request body mimetype is not application/json." log.debug("update result %s %s", result, 415) raise UnsupportedMediaType(result) from UnsupportedMediaType try: enable, redeploy = evc.update( **self._evc_dict_with_instances(data) ) except ValueError as exception: log.error(exception) log.debug("update result %s %s", exception, 400) raise BadRequest(str(exception)) from BadRequest if evc.is_active(): if enable is False: # disable if active with evc.lock: evc.remove() elif redeploy is not None: # redeploy if active with evc.lock: evc.remove() evc.deploy() else: if enable is True: # enable if inactive with evc.lock: evc.deploy() result = {evc.id: evc.as_dict()} status = 200 log.debug("update result %s %s", result, status) emit_event(self.controller, "updated", evc_id=evc.id, data=data) return jsonify(result), status
def get_jobs(): """ Return the records in the job collection for which the hauler field is null """ if not request.is_json: raise UnsupportedMediaType() if session.get('user') is None: raise Unauthorized() result = jsonify(dumps(list(mongo.db.jobs.find({'hauler': None})))) return result