Roles
`roles.list`, `list_all`, `iterate`, `get`, `create`, `update`, `delete` y `list_permissions`.
Todos los métodos
page = client.roles.listputs page.items.size role = client.roles.get("role_8b1f4c2e9a7d3b60e5f1a2c4")puts role[:name] support = client.roles.create( name: "Support", description: "Answers the shared inboxes and nothing else.", permissions: ["emails:send", "threads:write", "labels:write"]) p support[:permissions] client.roles.update(support[:id], permissions: [*support[:permissions], "templates:read"]) client.roles.delete(support[:id], reassign_to: role[:id]) vocabulary = client.roles.list_permissionsp vocabulary.map { |permission| permission[:id] }support[:permissions] contiene seis entradas, no tres: emails:send arrastra emails:read, threads:write arrastra threads:read y labels:write arrastra labels:read. Lee la lista devuelta en lugar de darla por supuesta.
list devuelve una OpenEmail::Page, list_all devuelve todos los roles en un solo Array, e iterate pasa cada rol a un bloque o devuelve un Enumerator sin bloque. Un rol vuelve como un Hash con claves Symbol, así que role[:permissions] lee la lista. create y update aceptan los campos del cuerpo como argumentos nombrados o como un solo Hash, mientras que delete acepta reassign_to:, un argumento nombrado en snake_case que la gema renombra para la API.
Un rol dice lo que alguien PUEDE HACER. A qué DIRECCIONES puede hacérselo es el otro eje y vive en client.members: consulta grant_address y revoke_address en la página Miembros. «Puede enviar correo» y «puede enviar como invoices@» son frases distintas, y un espacio de trabajo que contrata a un segundo agente de soporte cambia la segunda sin tocar la primera. Un permiso responde a las dos: un rol con addresses:all llega a todas las direcciones, incluidas las que se añadan más tarde, sin ninguna concesión, y solo una persona en la app puede asignarlo a un rol.
Ramifica según editable y deletable, no según builtin ni según el nombre. Ambos son false solo para el rol de propietario, cuya lista es «todos los permisos, incluidos los que se inventen el año que viene» y se calcula en lugar de almacenarse. Cualquier otro rol responde true a los dos, incluidos los cinco con los que se inicializa un espacio de trabajo. Un rol al que alguien haya cambiado el nombre sigue respondiendo correctamente a los dos, y su nombre ya no te dice nada.
update REEMPLAZA la lista de permisos. No existe una llamada para conceder uno solo, así que lee el rol, cambia la entrada que querías y envíalos todos de vuelta, como hace [*support[:permissions], "templates:read"] arriba. Enviar un único permiso deja al rol con exactamente ese, más lo que implique.
delete necesita reassign_to: en cuanto alguien tiene el rol. La gema lo envía como parámetro de consulta reassignTo, porque varios entornos de ejecución y no pocos proxies descartan el cuerpo de un DELETE, y omite el parámetro cuando no pasas nada. El resultado informa de reassigned y keysReassigned por separado, de modo que un script puede registrar lo que hizo y no lo que pidió.
list_permissions es GET /roles/permissions, una ruta fija situada justo donde iría un id de rol. La gema llama a esa ruta directamente en lugar de pasar la palabra por get, y devuelve un Array simple, no una OpenEmail::Page: un Hash por permiso, con id, label, group y scope. scope: false marca las entradas que ninguna clave puede tener nunca. No pases tú la palabra a get. client.roles.get("permissions") construye la misma ruta, así que envía la misma solicitud y recibe el vocabulario en lugar de un rol o un 404.
Un rol es el techo de una clave
Una clave emitida contra un rol puede ejercer sus propios ámbitos INTERSECADOS con los permisos de ese rol, resueltos por solicitud en el límite del sistema. Por tanto, restringir un rol revoca sus claves en vivo, sin que ninguna se rote. Una clave sin rol no tiene techo alguno, lo que convierte un roleId nil en el estado más amplio en el que puede estar una clave, no en el más estrecho.
Por eso también roles.delete exige un destino al que mover las claves. Dejarlas huérfanas eliminaría su techo por completo, promoviendo en silencio todas las credenciales que el rol limitaba.
GET /keys/self y GET /ping informan de roleId y grantedScopes junto a los scopes efectivos. Así se responde a «mi clave tiene emails:send y recibo insufficient_scope»: todo lo que esté en grantedScopes y falte en scopes lo quitó el rol. client.me.get y client.me.ping devuelven ambos en su Hash, así que key[:grantedScopes] - key[:scopes] lista lo que quitó el rol. El propio rechazo es un OpenEmail::PermissionError cuyo scope_missing? es true.
Parámetros
nameStringobligatorio- Cómo llama el espacio de trabajo al rol: de 1 a 48 caracteres, recortado antes de almacenarse. Los nombres son únicos por espacio de trabajo sin distinguir mayúsculas, así que un segundo «Support» se rechaza con `role_name_taken` (409), lanzado como `OpenEmail::ConflictError`, en lugar de crearse junto al primero.
descriptionString- Una frase que explica para qué sirve el rol, recortada y de 240 caracteres como máximo. Una cadena que queda en blanco tras recortarla se almacena como nil, de modo que una descripción de espacios vuelve como nil y no como lo que enviaste. En `create`, omítela en lugar de pasar nil: la gema envía un nil tal cual, y `create` lo rechaza con un 422. En `update`, `description: nil` la borra.
permissionsArray<String>obligatorio- Lo que concede el rol, tomado del vocabulario que sirve `list_permissions`. Una cadena que no esté en él es un 422 sobre `permissions`, lanzado como `OpenEmail::ValidationError` con `param` igual a `permissions`, en vez de descartarse en silencio, así que una errata se informa en lugar de costarte una tarde. La lista se EXPANDE a la entrada (`templates:write` almacena `templates:read` junto a él), se deduplica y se devuelve al orden canónico, así que lee la lista almacenada en la respuesta en lugar de suponer que es la que enviaste.
Respuesta
objectString- Siempre `role`. La lápida de borrado responde con el mismo valor, el `id` del rol, `deleted: true` y los dos recuentos de reasignación, y ninguno de los demás campos que siguen.
idString- El id del rol, que se lee con `role[:id]`. Es lo que nombra el `roleId` de un miembro, aquello a lo que apunta el techo de una clave de API y lo que recibe `reassign_to:` cuando se elimina otro rol y sus titulares pasan a este.
nameString- El nombre que el espacio de trabajo da al rol, recortado y único sin distinguir mayúsculas. Todos los roles salvo el de propietario pueden renombrarse, incluidos los sembrados (`builtin` dice de dónde vino una fila, no cómo tiene que seguir llamándose), así que no leas «Admin» como una promesa sobre lo que el rol contiene. Un nombre al que ya responde otro rol es `role_name_taken` (409, con `param` igual a `name`). Renombrar el de propietario es `role_immutable` (409), como cualquier otra modificación suya.
descriptionString or nil- La frase que describe el rol, o nil cuando no se dio ninguna. Una entrada en blanco se almacena como nil tanto al crear como al actualizar, así que esto nunca es una cadena vacía.
permissionsArray<String>- Todo lo que concede el rol, ya expandido y en orden canónico, no en el orden en que alguien lo escribió. Ese orden es estructural: dos roles con los mismos permisos contienen Arrays iguales, que es lo que permite a una pantalla de ajustes compararlos con `==` para decidir si Guardar está habilitado.
builtinString or nil- De cuál de los seis roles sembrados procede esta fila, `owner`, `admin`, `member`, `viewer`, `developer` o `billing`, o nil si el espacio de trabajo la escribió él mismo. Registra el origen sembrado y no un estado: un rol sembrado se renombra, se le cambian los permisos y se elimina como cualquier otro. Ramifica según `editable` y `deletable`, no según esto. Un rol al que alguien llamó «Admin» no tiene por qué ser el sembrado, y el sembrado puede que ya no se llame así.
editableBoolean- Se calcula como `builtin != "owner"`, así que es false solo para el rol de propietario, y todo `update` de ese rol se rechaza con `role_immutable` (409). Cualquier otro rol es editable por completo (nombre, descripción y permisos), incluidos los cinco con los que se inicializa un espacio de trabajo.
deletableBoolean- Se calcula como `builtin != "owner"`: false solo para el rol de propietario, que devuelve `role_undeletable` (409), y true para cualquier otro rol, incluidos los sembrados. Compruébalo antes de ofrecer el botón y no después del rechazo. Un rol que alguien todavía tiene necesita además `reassign_to:`, o el borrado es `role_in_use` (409). Ambos rechazos se lanzan como `OpenEmail::ConflictError`, y `code` los distingue.
membersInteger- Cuántas personas tienen este rol, contadas a partir de las filas de miembros del espacio de trabajo. El propietario no está entre ellas: no tiene fila de miembro y no se le puede asignar un rol, así que el rol de propietario informa de cero titulares aunque la lista de miembros lo muestre.
apiKeysInteger- Cuántas claves de API activas están limitadas por este rol. Las claves revocadas quedan fuera del recuento, aunque un borrado reapunta todas las filas de claves que apuntan al rol, las revocadas incluidas. Es la segunda población que hay que mover antes de poder eliminar el rol, y la que nadie advierte: las claves son programas, y un programa no se queja.
createdAtString- Cuándo se escribió la fila del rol, como String ISO 8601. Las filas integradas se siembran de forma diferida la primera vez que algo las necesita, como una lectura de la lista de roles, la creación de un rol o la pantalla de claves de API, y no al crear el espacio de trabajo. Así que la marca de tiempo de un rol integrado indica cuándo llegó esa primera solicitud y no cuándo se creó el espacio de trabajo.
updatedAtString- Cuándo cambió el rol por última vez, como String ISO 8601. Cada `update` aceptado la actualiza, incluido uno que asigne a un campo el valor que ya tenía.