def __call__(self, context, value): if not self.check_compatibility(context, value): raise jsonapi.InputError("%s: expected %s" % (context, self)) message = self.check(context, value) if message is not None: raise jsonapi.InputError("%s: %s" % (context, message)) if hasattr(self, "convert"): try: value = self.convert(context, value) except self.convert_exception as error: raise jsonapi.InputError("%s: %s" % (context, error.message)) if hasattr(self, "process"): self.process(context, value) return value
def convert(self, context, value): result = {} def convert_attributes(attributes): for attribute_name, attribute_value in attributes: with context.push(attribute_name): if attribute_name not in self.attributes: raise jsonapi.InputError("%s: unexpected attribute" % context) result[attribute_name] = self.attributes[attribute_name][ 2](context, attribute_value) convert_attributes( (attribute_name, attribute_value) for attribute_name, attribute_value in value.items() if attribute_name in self.prioritized) convert_attributes( (attribute_name, attribute_value) for attribute_name, attribute_value in value.items() if attribute_name not in self.prioritized) for attribute_name, (required, default, _) in self.attributes.items(): if attribute_name not in result: if required: with context.push(attribute_name): raise jsonapi.InputError("%s: missing attribute" % context) elif default: result[attribute_name] = None return result
def convert_attributes(attributes): for attribute_name, attribute_value in attributes: with context.push(attribute_name): if attribute_name not in self.attributes: raise jsonapi.InputError("%s: unexpected attribute" % context) result[attribute_name] = self.attributes[attribute_name][ 2](context, attribute_value)
def update(parameters, value, values, data): if values and len(values) != 1: raise UsageError("Updating multiple users not supported") critic = parameters.critic if values: value = values[0] converted = jsonapi.convert(parameters, {"fullname?": str}, data) with api.transaction.Transaction(critic) as transaction: if "fullname" in converted: new_fullname = converted["fullname"].strip() if not new_fullname: raise jsonapi.InputError("Empty new fullname") transaction.modifyUser(value).setFullname(new_fullname)
def ensure(data, path, ensured_value): if isinstance(path, (tuple, list)): for key in path[:-1]: data = data[key] key = path[-1] else: key = path if key not in data: data[key] = ensured_value elif data[key] != ensured_value: path_string = "data" for key in path: if isinstance(key, str): path_string += "." + key else: path_string += "[%d]" % key raise jsonapi.InputError("%s: must be %r or omitted" % (path_string, ensured_value))
def create(parameters, value, values, data): critic = parameters.critic user = parameters.context.get("users", critic.actual_user) path = parameters.subresource_path if value and path == ["replies"]: assert isinstance(value, api.comment.Comment) Comments.setAsContext(parameters, value) raise jsonapi.InternalRedirect("v1/replies") if value or values or path: raise jsonapi.UsageError("Invalid POST request") converted = jsonapi.convert( parameters, { "type": api.comment.Comment.TYPE_VALUES, "review!?": api.review.Review, "author?": api.user.User, "location?": { # Note: "general" not included here; |location| should be # omitted instead. "type": frozenset(["commit-message", "file-version"]), "first_line": int, "last_line": int, "commit?": api.commit.Commit, "file?": api.file.File, "changeset?": api.changeset.Changeset, "side?": frozenset(["old", "new"]), }, "text": str }, data) review = jsonapi.deduce("v1/reviews", parameters) if not review: if "review" not in converted: raise jsonapi.UsageError("No review specified") review = converted["review"] elif "review" in converted and review != converted["review"]: raise jsonapi.UsageError("Conflicting reviews specified") if "author" in converted: author = converted["author"] else: author = critic.actual_user if converted["type"] == "issue": expected_class = api.comment.Issue else: expected_class = api.comment.Note converted_location = converted.get("location") if converted_location: location_type = converted_location.pop("type") if location_type == "commit-message": required_fields = set(("first_line", "last_line", "commit")) optional_fields = set() else: required_fields = set(("first_line", "last_line", "file")) optional_fields = set(("commit", "changeset", "side")) accepted_fields = required_fields | optional_fields for required_field in required_fields: if required_field not in converted_location: raise jsonapi.InputError( "data.location.%s: missing attribute" % required_field) for actual_field in converted_location.keys(): if actual_field not in accepted_fields: raise jsonapi.InputError( "data.location.%s: unexpected attribute" % actual_field) if location_type == "commit-message": max_line = len( converted_location["commit"].message.splitlines()) else: if "commit" in converted_location: if "changeset" in converted_location: raise jsonapi.InputError( "data.location: only one of commit and changeset " "can be specified") changeset = None side = None commit = converted_location["commit"] elif "changeset" not in converted_location: raise jsonapi.InputError( "data.location: one of commit and changeset must be " "specified") elif "side" not in converted_location: raise jsonapi.InputError( "data.location.side: missing attribute (required when " "changeset is specified)") else: changeset = converted_location["changeset"] side = converted_location["side"] commit = None first_line = converted_location["first_line"] last_line = converted_location["last_line"] if location_type == "commit-message": location = api.comment.CommitMessageLocation.make( critic, first_line, last_line, converted_location["commit"]) else: location = api.comment.FileVersionLocation.make( critic, first_line, last_line, converted_location["file"], changeset, side, commit) else: location = None result = [] def collectComment(comment): assert isinstance(comment, expected_class), repr(comment) result.append(comment) with api.transaction.Transaction(critic) as transaction: transaction \ .modifyReview(review) \ .createComment( comment_type=converted["type"], author=author, text=converted["text"], location=location, callback=collectComment) assert len(result) == 1, repr(result) return result[0], None