feat(api): endpoint fea/v1/crear-autor para alta de autores (#166)
POST /wp-json/fea/v1/crear-autor — permite a Mixbot/Inma dar de alta autores nuevos sin depender de intervención manual, sin necesitar el permiso sensible create_users de WP. Rol 'author' fijo en el código (no lo decide quien llama). Auth: is_user_logged_in() + edit_others_posts (nivel Editor+, ya lo cumple su cuenta actual). Idempotente por slug: si ya existe, devuelve el usuario existente en vez de duplicar/errorar. Ver gitea.feadulta.com#166 (protocolo entre Claudes, opción B elegida sobre A porque WP no permite nativamente restringir create_users a un solo rol, y sobre C porque evita el salto humano/agente en el bucle). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — API crear-autor
|
||||
* Description: Endpoint REST acotado para que Mixbot (Inma) dé de alta autores
|
||||
* nuevos sin depender de que Rafa esté disponible, sin necesitar
|
||||
* el permiso sensible create_users de WP. El rol siempre es
|
||||
* 'author' (fijo en el código, no lo decide quien llama).
|
||||
* Idempotente: si el slug ya existe, devuelve el usuario existente.
|
||||
* Version: 1.0
|
||||
*
|
||||
* Ver issue gitea.feadulta.com/rafa/feadulta#166.
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
add_action('rest_api_init', function () {
|
||||
register_rest_route('fea/v1', '/crear-autor', [
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => 'fea_crear_autor_handle',
|
||||
'permission_callback' => 'fea_crear_autor_can_call',
|
||||
'args' => [
|
||||
'nombre' => ['required' => true],
|
||||
'slug' => ['required' => false],
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
/** Editor o superior (mismo nivel que ya usan Inma/Mixbot para editar posts). */
|
||||
function fea_crear_autor_can_call(WP_REST_Request $request) {
|
||||
if (!is_user_logged_in()) {
|
||||
return new WP_Error(
|
||||
'fea_crear_autor_not_authenticated',
|
||||
'Debes autenticarte para crear un autor.',
|
||||
['status' => 401]
|
||||
);
|
||||
}
|
||||
if (!current_user_can('edit_others_posts')) {
|
||||
return new WP_Error(
|
||||
'fea_crear_autor_forbidden',
|
||||
'No tienes permiso para crear autores.',
|
||||
['status' => 403]
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function fea_crear_autor_handle(WP_REST_Request $request) {
|
||||
$nombre = trim((string) $request->get_param('nombre'));
|
||||
if ($nombre === '') {
|
||||
return new WP_Error(
|
||||
'fea_crear_autor_invalid',
|
||||
'nombre es obligatorio.',
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$slug_input = trim((string) $request->get_param('slug'));
|
||||
$login = sanitize_user(sanitize_title($slug_input !== '' ? $slug_input : $nombre), true);
|
||||
if ($login === '') {
|
||||
return new WP_Error(
|
||||
'fea_crear_autor_invalid',
|
||||
'No se pudo derivar un slug válido de nombre/slug.',
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
// Idempotencia: si el login/slug ya existe, se devuelve tal cual (created=false).
|
||||
$existing = get_user_by('login', $login);
|
||||
if ($existing) {
|
||||
return fea_crear_autor_response($existing, false);
|
||||
}
|
||||
|
||||
$email = $login . '@feadulta.com';
|
||||
$i = 2;
|
||||
while (email_exists($email)) {
|
||||
$email = $login . $i . '@feadulta.com';
|
||||
$i++;
|
||||
}
|
||||
|
||||
$user_id = wp_insert_user([
|
||||
'user_login' => $login,
|
||||
'user_pass' => wp_generate_password(20),
|
||||
'user_email' => $email,
|
||||
'display_name' => $nombre,
|
||||
'nickname' => $nombre,
|
||||
'role' => 'author', // fijo: este endpoint nunca crea otro rol.
|
||||
]);
|
||||
|
||||
if (is_wp_error($user_id)) {
|
||||
return new WP_Error(
|
||||
'fea_crear_autor_failed',
|
||||
'No se pudo crear el usuario: ' . $user_id->get_error_message(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
return fea_crear_autor_response(get_userdata($user_id), true);
|
||||
}
|
||||
|
||||
function fea_crear_autor_response(WP_User $user, bool $created) {
|
||||
return rest_ensure_response([
|
||||
'id' => $user->ID,
|
||||
'login' => $user->user_login,
|
||||
'slug' => $user->user_nicename,
|
||||
'display_name' => $user->display_name,
|
||||
'role' => 'author',
|
||||
'created' => $created,
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user