class CreateGroupMembership(JSONAPIData): """The data to add a user to a group.""" validator = Schema.get_validator( "bulk_api/command/create_group_membership.json") @classmethod def create(cls, user_ref, group_ref): """ Create a create group membership body for adding users to groups. :param user_ref: Custom user reference :param group_ref: Custom group reference :return: """ return super().create( DataType.GROUP_MEMBERSHIP, relationships={ "member": { "data": { "type": DataType.USER.value, "id": { "$ref": user_ref } } }, "group": { "data": { "type": DataType.GROUP.value, "id": { "$ref": group_ref } } }, }, ) @property def member(self): """The user which is a member of this group. :return: A value object with `id` and `ref` properties. """ return _IdRef(self.relationships["member"]["data"]["id"]) @property def group(self): """The group which this user is a member of. :return: A value object with `id` and `ref` properties. """ return _IdRef(self.relationships["group"]["data"]["id"])
class UpsertUser(JSONAPIData): """The data to upsert a user.""" validator = Schema.get_validator("bulk_api/command/upsert_user.json") @classmethod def create(cls, _id, attributes): """ Create an upsert user body. :param _id: User id :param attributes: User attributes :return: """ return super().create(DataType.USER, _id=_id, attributes=attributes)
class Command(Model): """A single abstract command provided to the API.""" validator = Schema.get_validator("bulk_api/wrapper.json") validation_error_title = "Cannot interpret command as the wrapper is malformed" def validate(self): super().validate() if isinstance(self.body, Model): self.body.validate() @classmethod def create(cls, type_, body): """ Create a command. :param type_: The CommandType of the command :param body: The payload for the command :return: An instance of Command """ return cls([CommandType(type_).value, cls.extract_raw(body)]) @property def type(self): """ Get the command type. :return: The CommandType of this command """ return CommandType(self.raw[0]) @property def body(self): """ Get the body of this command. :return: The raw body """ return self.raw[1] def __repr__(self): return f"<{self.__class__.__name__} {self.body}>"
class Configuration(Model): validator = Schema.get_validator("bulk_api/command/configuration.json") WILD_CARD = "*" @classmethod def create(cls, effective_user, total_instructions): """ Create a configuration object. :param effective_user: User to execute the command as :param total_instructions: Number of instructions (including this) """ return cls({ "view": None, "user": { "effective": effective_user }, "instructions": { "total": int(total_instructions) }, "defaults": [ ["create", "*", { "on_duplicate": "continue" }], ["upsert", "*", { "merge_query": True }], ], }) @property def view(self): """The return type of view requested by the user.""" return self.raw["view"] @property def effective_user(self): """The user to execute the request as.""" return self.raw["user"]["effective"] @property def total_instructions(self): """ The number of instructions in the request. This count includes configuration commands. """ return self.raw["instructions"]["total"] def defaults_for(self, command_type, data_type): """ Provide default configuration for the given command and data type. This will use any wild card options first, overlaying more specific defaults as they are found. :param command_type: Type of modification (e.g. Types.UPSERT) :param data_type: Data type being modified :return: A dict of config """ defaults = self._command_defaults config = {} wild = defaults.get(self.WILD_CARD, {}) specific = defaults.get(CommandType(command_type), {}) data_type = DataType(data_type) for container in (wild, specific): if self.WILD_CARD in container: config.update(container[self.WILD_CARD]) if data_type in container: config.update(container[data_type]) return config @property @lru_cache(1) def _command_defaults(self): config = defaultdict(dict) for command_type, data_type, defaults in self.raw["defaults"]: if command_type != self.WILD_CARD: command_type = CommandType(command_type) if data_type != self.WILD_CARD: data_type = DataType(data_type) config[command_type][data_type] = defaults return config
class CreateGroupMembership(JSONAPIData): """The data to add a user to a group.""" validator = Schema.get_validator( "bulk_api/command/create_group_membership.json") @classmethod def create(cls, user_id, group_ref): """ Create a create group membership body for adding users to groups. :param user_id: User id :param group_ref: Custom group reference :return: """ return super().create( DataType.GROUP_MEMBERSHIP, relationships={ "member": { "data": { "type": DataType.USER.value, "id": user_id } }, "group": { "data": { "type": DataType.GROUP.value, "id": { "$ref": group_ref } } }, }, ) @property def member_id(self): """The user which is a member of this group.""" return self.relationships["member"]["data"]["id"] @property def group_id(self): """The group the user is a member of.""" _group_id = self._group_id if "$ref" in _group_id: return None return _group_id @property def group_ref(self): """ A client provided reference for this group. If you don't know the group id yet, you can use your own reference. """ return self._group_id.get("$ref") @property def _group_id(self): return self.relationships["group"]["data"]["id"]
class UpsertGroup(UpsertBody): """The data to upsert a group.""" validator = Schema.get_validator("bulk_api/command/upsert_group.json") data_type = DataType.GROUP query_fields = ["authority", "authority_provided_id"]
class UpsertUser(UpsertBody): """The data to upsert a user.""" validator = Schema.get_validator("bulk_api/command/upsert_user.json") data_type = DataType.USER query_fields = ["authority", "username"]