llamadas a la api creadas

This commit is contained in:
2025-10-21 20:38:36 +02:00
parent 659715c4a4
commit b1992c0753
3 changed files with 936 additions and 0 deletions
@@ -0,0 +1,281 @@
{
"version": "1",
"metadata": {
"marimo_version": "0.17.0"
},
"cells": [
{
"id": "Hbol",
"code_hash": "1d0db38904205bec4d6f6f6a1f6cec3e",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": []
},
{
"id": "mmzP",
"code_hash": "e53b82f6768020aad4940c56dd2fae07",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"listar-proyectos\">Listar Proyectos</h2></span>"
}
}
],
"console": []
},
{
"id": "soEq",
"code_hash": "35bcfe34cc3625a28a154254259b76de",
"outputs": [
{
"type": "data",
"data": {
"application/json": "{\"jsonrpc\": \"2.0\", \"result\": [{\"id\": 1, \"name\": \"CodeProyects\", \"is_active\": true, \"token\": \"\", \"last_modified\": 1761063849, \"is_public\": false, \"is_private\": false, \"description\": null, \"identifier\": \"\", \"start_date\": \"\", \"end_date\": \"\", \"owner_id\": 2, \"priority_default\": 0, \"priority_start\": 0, \"priority_end\": 3, \"email\": null, \"predefined_email_subjects\": null, \"per_swimlane_task_limits\": false, \"task_limit\": 0, \"enable_global_tags\": true, \"url\": {\"board\": \"http://localhost/board/1\", \"list\": \"http://localhost/list/1\"}}], \"id\": 1}"
}
}
],
"console": []
},
{
"id": "COzz",
"code_hash": "8593497dfb93ffdc4d481231f22ff886",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"listar-usuarios\">Listar usuarios</h2></span>"
}
}
],
"console": []
},
{
"id": "fRcd",
"code_hash": "036c95a347f6de634be1a5277fc99daa",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "\u2705 Usuarios encontrados:\nID 1 | Usuario: admin | Nombre: None\nID 2 | Usuario: Egutierrez | Nombre: Enmanuel\n"
}
]
},
{
"id": "ucix",
"code_hash": "80ced1b6d20bb63695c909cca312c33c",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"listar-tareas\">Listar tareas</h2></span>"
}
}
],
"console": []
},
{
"id": "fRXL",
"code_hash": "18ea3c992e655e4fb8f64b7d24a41bbb",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "Tarea ID 5: Otra tarea autom\u00e1tica con etiquetas\nTarea ID 6: Otra tarea autom\u00e1tica con etiquetas\nTarea ID 7: Otra tarea autom\u00e1tica con etiquetas\nTarea ID 8: Otra tarea autom\u00e1tica con etiquetas\nTarea ID 9: Tarea con maxima prioridad\nTarea ID 10: Tarea con maxima prioridad\n"
}
]
},
{
"id": "jMzO",
"code_hash": "808fe59b3702664ab0b7e4e4a920629a",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h3 id=\"listar-subtareas\">Listar subtareas</h3></span>"
}
}
],
"console": []
},
{
"id": "qrHy",
"code_hash": "7a03102141b244eb5054544c39ec0feb",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": []
},
{
"id": "rkGP",
"code_hash": "ed4d72d20e904f8baad87c095b3d3471",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"listar-tareas-columnas\">Listar tareas columnas</h2></span>"
}
}
],
"console": []
},
{
"id": "HTUm",
"code_hash": "f8d752251cf677e701b0a7b1ed2cc1cc",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "\n\ud83d\udce6 Backlog (4 tareas):\n \u251c\u2500 [5] Otra tarea autom\u00e1tica con etiquetas\n \u251c\u2500 [8] Otra tarea autom\u00e1tica con etiquetas\n \u251c\u2500 [9] Tarea con maxima prioridad\n \u251c\u2500 [10] Tarea con maxima prioridad\n\n\ud83d\udce6 Ready (1 tareas):\n \u251c\u2500 [7] Otra tarea autom\u00e1tica con etiquetas\n\n\ud83d\udce6 Work in progress (1 tareas):\n \u251c\u2500 [6] Otra tarea autom\u00e1tica con etiquetas\n\n\ud83d\udce6 Done (0 tareas):\n"
}
]
},
{
"id": "DHdl",
"code_hash": "557d1157ae68f568602eeb5e5ed09c76",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"mover-tareas-entre-columnas\">Mover tareas entre columnas</h2></span>"
}
}
],
"console": []
},
{
"id": "WhTX",
"code_hash": "f88d3bdcbdaf4bbbf6f070b536cd24d6",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "\u26a0\ufe0f No se pudo mover la tarea 6.\n"
}
]
},
{
"id": "DBDn",
"code_hash": null,
"outputs": [],
"console": []
},
{
"id": "LoIk",
"code_hash": "7590f79b2fa20f3da53fcbbaf31c3e70",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"crear-tarea\">Crear tarea</h2></span>"
}
}
],
"console": []
},
{
"id": "dbns",
"code_hash": "c3260268117f17ff51af0ebe7c5c413b",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "\u2705 Tarea creada correctamente (ID 10) en el proyecto 1\n"
},
{
"type": "stream",
"name": "stdout",
"text": "\ud83c\udff7\ufe0f Etiquetas a\u00f1adidas: etl, prioridad-alta\n"
}
]
},
{
"id": "HDME",
"code_hash": "8c2e1134753947cea243b3a8e020383d",
"outputs": [
{
"type": "data",
"data": {
"text/html": "<span class=\"markdown prose dark:prose-invert\"><h2 id=\"editar-tarea\">Editar tarea</h2></span>"
}
}
],
"console": []
},
{
"id": "NQhy",
"code_hash": "29ac83f0938d9e28f09291ac8e870ad7",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": [
{
"type": "stream",
"name": "stdout",
"text": "\u2705 Tarea 8 actualizada correctamente en Kanboard.\n"
},
{
"type": "stream",
"name": "stdout",
"text": "\ud83c\udff7\ufe0f Etiquetas actualizadas: automatizada, revisi\u00f3n, python\n"
}
]
}
]
}
@@ -0,0 +1,77 @@
{
"version": "1",
"metadata": {
"marimo_version": "0.17.0"
},
"cells": [
{
"id": "Hbol",
"code_hash": "1d0db38904205bec4d6f6f6a1f6cec3e",
"outputs": [
{
"type": "data",
"data": {
"text/plain": ""
}
}
],
"console": []
},
{
"id": "MJUe",
"code_hash": "30549382a489a6758d4eda0a633ecec7",
"outputs": [
{
"type": "error",
"ename": "exception",
"evalue": "401 Client Error: Unauthorized for url: http://127.0.0.1:8080/jsonrpc.php",
"traceback": []
}
],
"console": [
{
"type": "stream",
"name": "stderr",
"text": "<span class=\"codehilite\"><div class=\"highlight\"><pre><span></span><span class=\"gt\">Traceback (most recent call last):</span>\n File <span class=\"nb\">&quot;/tmp/marimo_86378/__marimo__cell_MJUe_.py&quot;</span>, line <span class=\"m\">67</span>, in <span class=\"n\">&lt;module&gt;</span>\n<span class=\"w\"> </span><span class=\"n\">projects</span> <span class=\"o\">=</span> <span class=\"n\">get_all_projects_with_tasks</span><span class=\"p\">(</span><span class=\"n\">API_URL</span><span class=\"p\">,</span> <span class=\"n\">USERNAME</span><span class=\"p\">,</span> <span class=\"n\">API_TOKEN</span><span class=\"p\">)</span>\n File <span class=\"nb\">&quot;/tmp/marimo_86378/__marimo__cell_MJUe_.py&quot;</span>, line <span class=\"m\">33</span>, in <span class=\"n\">get_all_projects_with_tasks</span>\n<span class=\"w\"> </span><span class=\"n\">projects</span> <span class=\"o\">=</span> <span class=\"n\">rpc</span><span class=\"p\">(</span><span class=\"s2\">&quot;getAllProjects&quot;</span><span class=\"p\">)</span>\n File <span class=\"nb\">&quot;/tmp/marimo_86378/__marimo__cell_MJUe_.py&quot;</span>, line <span class=\"m\">27</span>, in <span class=\"n\">rpc</span>\n<span class=\"w\"> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n<span class=\"w\"> </span><span class=\"pm\">~~~~~~~~~~~~~~~~~~^^</span>\n File <span class=\"nb\">&quot;/home/lucas/DataProyects/kanboard/.venv/lib/python3.13/site-packages/requests/models.py&quot;</span>, line <span class=\"m\">1026</span>, in <span class=\"n\">raise_for_status</span>\n<span class=\"w\"> </span><span class=\"k\">raise</span> <span class=\"n\">HTTPError</span><span class=\"p\">(</span><span class=\"n\">http_error_msg</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"p\">)</span>\n<span class=\"gr\">requests.exceptions.HTTPError</span>: <span class=\"n\">401 Client Error: Unauthorized for url: http://127.0.0.1:8080/jsonrpc.php</span>\n</pre></div>\n</span>"
}
]
},
{
"id": "LMtK",
"code_hash": "b150d3f7475c3d17e5c1bffbdbc6d5fe",
"outputs": [
{
"type": "error",
"ename": "multiple-defs",
"evalue": "The variable 'API_TOKEN' was defined by another cell",
"traceback": []
},
{
"type": "error",
"ename": "multiple-defs",
"evalue": "The variable 'API_URL' was defined by another cell",
"traceback": []
},
{
"type": "error",
"ename": "multiple-defs",
"evalue": "The variable 'HTTPBasicAuth' was defined by another cell",
"traceback": []
},
{
"type": "error",
"ename": "multiple-defs",
"evalue": "The variable 'USERNAME' was defined by another cell",
"traceback": []
},
{
"type": "error",
"ename": "multiple-defs",
"evalue": "The variable 'requests' was defined by another cell",
"traceback": []
}
],
"console": []
}
]
}
+578
View File
@@ -0,0 +1,578 @@
import marimo
__generated_with = "0.17.0"
app = marimo.App(width="columns")
@app.cell(column=0)
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
mo.md(r"""## Listar Proyectos""")
return
@app.cell
def _():
import requests
from requests.auth import HTTPBasicAuth
import json
url = "http://localhost:8080/jsonrpc.php" # o http://host.docker.internal:8080/jsonrpc.php desde WSL
auth = HTTPBasicAuth("jsonrpc", "792d8fdd6cbf69b3a32d800beaf48b958e4490dd9185c72c06c56061a591")
payload = {
"jsonrpc": "2.0",
"method": "getAllProjects",
"id": 1
}
response = requests.post(
url,
json=payload,
auth=auth,
headers={"Content-Type": "application/json"},
timeout=10
)
# 👇 Convierte el cuerpo en JSON (Python dict)
resultado = response.json()
# Muestra el JSON bonito
resultado
return HTTPBasicAuth, requests
@app.cell
def _(mo):
mo.md(r"""## Listar usuarios""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, TOKEN, USER, requests):
def obtener_usuarios(api_url, usuario, token):
"""
Devuelve la lista completa de usuarios disponibles en Kanboard.
Parámetros:
api_url (str): URL del endpoint JSON-RPC (por ejemplo, http://host.docker.internal:8080/jsonrpc.php)
usuario (str): Usuario con permisos API (ej. 'jsonrpc' o 'admin')
token (str): Token de autenticación del usuario
Retorna:
list[dict]: Lista de usuarios, cada uno con su 'id', 'username', 'name', etc.
"""
auth = HTTPBasicAuth(usuario, token)
payload = {
"jsonrpc": "2.0",
"method": "getAllUsers",
"id": 1
}
response = requests.post(
api_url,
json=payload,
auth=auth,
headers={"Content-Type": "application/json"},
timeout=10
)
data = response.json()
if "error" in data:
raise Exception(f"❌ Error al obtener usuarios: {data['error']}")
return data.get("result", [])
# 🧪 Ejemplo de uso
if __name__ == "__main__":
usuarios = obtener_usuarios(API_URL, USER, TOKEN)
print("✅ Usuarios encontrados:")
for u in usuarios:
print(f"ID {u['id']:>2} | Usuario: {u['username']:<15} | Nombre: {u.get('name', '')}")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""## Listar tareas""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, PROJECT_ID, TOKEN, USER, requests):
def listar_tareas(api_url, usuario, token, project_id):
"""
Lista todas las tareas de un proyecto en Kanboard.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API
token (str): Token del usuario
project_id (int): ID del proyecto donde obtener las tareas
Retorna:
list[dict]: Lista de tareas en el proyecto
"""
auth = HTTPBasicAuth(usuario, token)
payload = {
"jsonrpc": "2.0",
"method": "getAllTasks",
"id": 1,
"params": {
"project_id": project_id
}
}
response = requests.post(api_url, json=payload, auth=auth, headers={"Content-Type": "application/json"})
data = response.json()
if "error" in data:
print("❌ Error al obtener tareas:", data["error"])
return []
return data.get("result", [])
# 🧪 Ejemplo de uso:
tareas = listar_tareas(API_URL, USER, TOKEN, PROJECT_ID)
for tarea in tareas:
print(f"Tarea ID {tarea['id']}: {tarea['title']}")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""### Listar subtareas""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, TOKEN, USER, requests):
def listar_subtareas(api_url, usuario, token, task_id):
"""
Lista todas las subtareas de una tarea.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API
token (str): Token del usuario
task_id (int): ID de la tarea principal para obtener sus subtareas
Retorna:
list[dict]: Lista de subtareas asociadas
"""
auth = HTTPBasicAuth(usuario, token)
payload = {
"jsonrpc": "2.0",
"method": "getAllSubtasks",
"id": 1,
"params": {
"task_id": task_id
}
}
response = requests.post(api_url, json=payload, auth=auth, headers={"Content-Type": "application/json"})
data = response.json()
if "error" in data:
print("❌ Error al obtener subtareas:", data["error"])
return []
return data.get("result", [])
# 🧪 Ejemplo de uso:
task_id = 10 # ID de la tarea principal
subtareas = listar_subtareas(API_URL, USER, TOKEN, task_id)
for sub in subtareas:
print(f"Subtarea ID {sub['id']}: {sub['title']}")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""## Listar tareas columnas""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, PROJECT_ID, TOKEN, USER, requests):
def listar_tareas_por_columna(api_url, usuario, token, project_id):
"""
Devuelve todas las _tareas agrupadas por columna dentro de un proyecto Kanboard.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API
token (str): Token del usuario
project_id (int): ID del proyecto
Retorna:
dict: { 'columna': [ {_tarea}, {_tarea} ] }
"""
auth = HTTPBasicAuth(usuario, token)
payload = {
"jsonrpc": "2.0",
"method": "getBoard",
"id": 1,
"params": {
"project_id": project_id
}
}
response = requests.post(api_url, json=payload, auth=auth, headers={"Content-Type": "application/json"})
data = response.json()
if "error" in data:
print("❌ Error al obtener el tablero:", data["error"])
return {}
board = data.get("result", [])
tareas_por_columna = {}
for swimlane in board:
for columna in swimlane.get("columns", []):
nombre_columna = columna["title"]
tareas_por_columna[nombre_columna] = columna.get("tasks", [])
return tareas_por_columna
# 🧪 Ejemplo de uso
if __name__ == "__main__":
tareas_columna = listar_tareas_por_columna(API_URL, USER, TOKEN, PROJECT_ID)
for columna, _tareas in tareas_columna.items():
print(f"\n📦 {columna} ({len(_tareas)} tareas):")
for _tarea in _tareas:
print(f" ├─ [{_tarea['id']}] {_tarea['title']}")
return
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""## Mover tareas entre columnas""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, PROJECT_ID, TOKEN, USER, requests):
def mover_tarea_columna(api_url, usuario, token, project_id, task_id, column_id, position=1, swimlane_id=0):
"""
Mueve una tarea a otra columna dentro de un proyecto Kanboard.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API (por ejemplo 'jsonrpc' o tu bot)
token (str): Token de autenticación
project_id (int): ID del proyecto
task_id (int): ID de la tarea a mover
column_id (int): ID de la columna destino
position (int): Posición dentro de la columna (por defecto 1)
swimlane_id (int): ID de la swimlane (0 = principal)
Retorna:
bool: True si el movimiento fue exitoso, False en caso de error.
"""
auth = HTTPBasicAuth(usuario, token)
payload = {
"jsonrpc": "2.0",
"method": "moveTaskPosition",
"id": 1,
"params": {
"project_id": project_id,
"task_id": task_id,
"column_id": column_id,
"position": position,
"swimlane_id": swimlane_id
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(api_url, json=payload, auth=auth, headers=headers, timeout=10)
data = response.json()
if "error" in data:
print("❌ Error al mover tarea:", data["error"])
return False
result = data.get("result", False)
if result:
print(f"✅ Tarea {task_id} movida correctamente a la columna {column_id}.")
else:
print(f"⚠️ No se pudo mover la tarea {task_id}.")
return result
# 🧪 Ejemplo de uso
if __name__ == "__main__":
# API_URL = "http://host.docker.internal:8080/jsonrpc.php"
# USER = "jsonrpc"
# TOKEN = "792d8fdd6cbf69b3a32d800beaf48b958e4490dd9185c72c06c56061a591"
# PROJECT_ID = 1
TASK_ID = 6 # ID de la tarea a mover
COLUMN_ID = 3 # Nueva columna (por ejemplo "En progreso")
mover_tarea_columna(API_URL, USER, TOKEN, PROJECT_ID, TASK_ID, COLUMN_ID)
return
@app.cell(column=1)
def _():
return
@app.cell
def _(mo):
mo.md(r"""## Crear tarea""")
return
@app.cell
def _(HTTPBasicAuth, requests):
import random
def crear_tarea(api_url, usuario, token, project_id, titulo, descripcion="", swimlane_id=None, assignee_id=None, tags=None, priority=None):
"""
Crea una tarea en el backlog del proyecto indicado en Kanboard,
con un color aleatorio, etiquetas (tags), prioridad
y (opcionalmente) asignada a un usuario.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API
token (str): Token del usuario
project_id (int): ID del proyecto donde crear la tarea
titulo (str): Título de la tarea
descripcion (str): Descripción de la tarea
swimlane_id (int): ID de la swimlane (opcional)
assignee_id (int): ID del usuario a quien se asignará la tarea (opcional)
tags (list[str]): Lista de etiquetas a añadir (opcional)
priority (int): Prioridad numérica de la tarea (opcional)
Retorna:
dict: Respuesta completa de la API
"""
auth = HTTPBasicAuth(usuario, token)
# 🎨 Colores disponibles
colores = [
"yellow", "blue", "green", "purple",
"red", "orange", "grey", "brown",
"deep_orange", "dark_grey", "lime", "cyan"
]
color_aleatorio = random.choice(colores)
# 🧩 Payload principal
payload = {
"jsonrpc": "2.0",
"method": "createTask",
"id": 1,
"params": {
"title": titulo,
"description": descripcion,
"project_id": project_id,
"color_id": color_aleatorio
}
}
if swimlane_id is not None:
payload["params"]["swimlane_id"] = swimlane_id
if assignee_id is not None:
payload["params"]["owner_id"] = assignee_id
if priority is not None:
payload["params"]["priority"] = priority
headers = {"Content-Type": "application/json"}
# 🚀 Crear la tarea
response = requests.post(api_url, json=payload, auth=auth, headers=headers, timeout=10)
data = response.json()
if "error" in data:
print("❌ Error al crear tarea:", data["error"])
return data
task_id = data.get("result")
print(f"✅ Tarea creada correctamente (ID {task_id}) en el proyecto {project_id}")
# 🏷️ Añadir etiquetas (si se proporcionaron)
if tags:
tag_payload = {
"jsonrpc": "2.0",
"method": "setTaskTags",
"id": 1,
"params": {
"project_id": project_id,
"task_id": task_id,
"tags": tags
}
}
tag_response = requests.post(api_url, json=tag_payload, auth=auth, headers=headers, timeout=10)
tag_data = tag_response.json()
if "error" in tag_data:
print("⚠️ Error al añadir etiquetas:", tag_data["error"])
else:
print(f"🏷️ Etiquetas añadidas: {', '.join(tags)}")
return data
# 🧪 Ejemplo de uso:
if __name__ == "__main__":
API_URL = "http://localhost:8080/jsonrpc.php" # desde WSL
USER = "jsonrpc"
TOKEN = "792d8fdd6cbf69b3a32d800beaf48b958e4490dd9185c72c06c56061a591"
PROJECT_ID = 1
ASSIGNEE_ID = 2 # ID de Egutierrez
crear_tarea(
api_url=API_URL,
usuario=USER,
token=TOKEN,
project_id=PROJECT_ID,
titulo="Tarea con maxima prioridad",
descripcion="Esta tarea tiene prioridad 3 y etiquetas automáticas.",
assignee_id=ASSIGNEE_ID,
tags=["etl", "prioridad-alta"],
priority=3
)
return API_URL, PROJECT_ID, TOKEN, USER
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""## Editar tarea""")
return
@app.cell
def _(API_URL, HTTPBasicAuth, TOKEN, USER, requests):
def editar_tarea(api_url, usuario, token, task_id, titulo=None, descripcion=None,
swimlane_id=None, assignee_id=None, tags=None, priority=None):
"""
Edita una tarea existente en Kanboard.
Solo se envían los parámetros que se indiquen explícitamente.
Parámetros:
api_url (str): URL del endpoint JSON-RPC
usuario (str): Usuario con permisos API
token (str): Token del usuario
task_id (int): ID de la tarea a editar
titulo (str): Nuevo título (opcional)
descripcion (str): Nueva descripción (opcional)
swimlane_id (int): Nueva swimlane (opcional)
assignee_id (int): Nuevo responsable (opcional)
tags (list[str]): Lista de etiquetas (opcional)
priority (int): Nueva prioridad (opcional)
Retorna:
dict: Respuesta completa de la API
"""
auth = HTTPBasicAuth(usuario, token)
headers = {"Content-Type": "application/json"}
# 🧩 Construir payload con solo los campos que se quieren cambiar
params = {"id": task_id}
if titulo is not None:
params["title"] = titulo
if descripcion is not None:
params["description"] = descripcion
if swimlane_id is not None:
params["swimlane_id"] = swimlane_id
if assignee_id is not None:
params["owner_id"] = assignee_id
if priority is not None:
params["priority"] = priority
# Si no hay cambios, no se hace nada
if len(params) == 1:
print("⚠️ No se proporcionaron campos a modificar.")
return {"warning": "sin cambios"}
payload = {
"jsonrpc": "2.0",
"method": "updateTask",
"id": 1,
"params": params
}
# 🚀 Ejecutar la actualización
response = requests.post(api_url, json=payload, auth=auth, headers=headers, timeout=10)
data = response.json()
if "error" in data:
print("❌ Error al editar tarea:", data["error"])
return data
print(f"✅ Tarea {task_id} actualizada correctamente en Kanboard.")
# 🏷️ Actualizar etiquetas si se proporcionan
if tags:
# Para setTaskTags se requiere el project_id, lo obtenemos antes
get_task_payload = {
"jsonrpc": "2.0",
"method": "getTask",
"id": 1,
"params": {"task_id": task_id}
}
task_response = requests.post(api_url, json=get_task_payload, auth=auth, headers=headers, timeout=10)
project_id = task_response.json().get("result", {}).get("project_id")
if project_id:
tag_payload = {
"jsonrpc": "2.0",
"method": "setTaskTags",
"id": 1,
"params": {
"project_id": project_id,
"task_id": task_id,
"tags": tags
}
}
tag_response = requests.post(api_url, json=tag_payload, auth=auth, headers=headers, timeout=10)
tag_data = tag_response.json()
if "error" in tag_data:
print("⚠️ Error al actualizar etiquetas:", tag_data["error"])
else:
print(f"🏷️ Etiquetas actualizadas: {', '.join(tags)}")
return data
# 🧪 Ejemplo de uso:
if __name__ == "__main__":
_TASK_ID = 8 # ID de la tarea existente
editar_tarea(
api_url=API_URL,
usuario=USER,
token=TOKEN,
task_id=_TASK_ID,
titulo="🔥 Actualización directa desde Python",
descripcion="Descripción actualizada sin afectar otros campos.",
assignee_id=2,
tags=["automatizada", "revisión", "python"],
priority=2
)
return
if __name__ == "__main__":
app.run()