vikunja-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vikunja_python/__init__.py +0 -0
- vikunja_python/cli/__init__.py +0 -0
- vikunja_python/cli/main.py +264 -0
- vikunja_python/core/__init__.py +0 -0
- vikunja_python/core/client.py +106 -0
- vikunja_python/core/models/__init__.py +377 -0
- vikunja_python/core/models/api_token.py +131 -0
- vikunja_python/core/models/auth.py +34 -0
- vikunja_python/core/models/base.py +193 -0
- vikunja_python/core/models/bulk_assignees.py +98 -0
- vikunja_python/core/models/filter.py +134 -0
- vikunja_python/core/models/label.py +230 -0
- vikunja_python/core/models/link_sharing.py +138 -0
- vikunja_python/core/models/migration.py +404 -0
- vikunja_python/core/models/phase6_medium.py +74 -0
- vikunja_python/core/models/project.py +217 -0
- vikunja_python/core/models/relation.py +199 -0
- vikunja_python/core/models/task.py +261 -0
- vikunja_python/core/models/task_expansion.py +252 -0
- vikunja_python/core/models/user.py +838 -0
- vikunja_python/core/models/webhook.py +270 -0
- vikunja_python/mcp/__init__.py +0 -0
- vikunja_python/mcp/server.py +678 -0
- vikunja_python-0.1.0.dist-info/METADATA +16 -0
- vikunja_python-0.1.0.dist-info/RECORD +28 -0
- vikunja_python-0.1.0.dist-info/WHEEL +5 -0
- vikunja_python-0.1.0.dist-info/entry_points.txt +3 -0
- vikunja_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Expansion Models for Vikunja API
|
|
3
|
+
|
|
4
|
+
Covers: models.TaskComment, models.TaskAttachment, models.TaskReminder
|
|
5
|
+
API endpoints: Part of task CRUD with expand=[comments,attachments,reminders]
|
|
6
|
+
|
|
7
|
+
These models represent the expanded data that can be fetched alongside tasks.
|
|
8
|
+
Use expand query parameter to include these in task responses.
|
|
9
|
+
|
|
10
|
+
Usage Examples:
|
|
11
|
+
# Fetch task with all expansions
|
|
12
|
+
task = client.get_task(2, expand=["comments", "attachments", "reminders"])
|
|
13
|
+
|
|
14
|
+
# Access expanded data
|
|
15
|
+
for comment in task.comments:
|
|
16
|
+
print(f"{comment.author.username}: {comment.comment}")
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from pydantic import Field, RootModel
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Optional, Dict, List, Literal
|
|
22
|
+
from .base import VikunjaBaseModel, User
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ============================================================================
|
|
26
|
+
# Task Comment Model
|
|
27
|
+
# ============================================================================
|
|
28
|
+
|
|
29
|
+
class TaskComment(VikunjaBaseModel):
|
|
30
|
+
"""
|
|
31
|
+
A comment on a task.
|
|
32
|
+
|
|
33
|
+
API endpoint: Part of task response with expand=comments
|
|
34
|
+
|
|
35
|
+
Comments support markdown formatting and reactions. Each comment has:
|
|
36
|
+
- id: Unique identifier
|
|
37
|
+
- comment: The comment text (markdown)
|
|
38
|
+
- author: User who wrote the comment
|
|
39
|
+
- created/updated: Timestamps
|
|
40
|
+
- reactions: Map of emoji reactions to users
|
|
41
|
+
|
|
42
|
+
Fields from API spec (models.TaskComment):
|
|
43
|
+
- id: Comment ID
|
|
44
|
+
- comment: Comment text content
|
|
45
|
+
- author: User object for comment author
|
|
46
|
+
- created: Creation timestamp
|
|
47
|
+
- updated: Last update timestamp
|
|
48
|
+
- reactions: Reaction map (emoji -> list of users)
|
|
49
|
+
|
|
50
|
+
Example from API response:
|
|
51
|
+
{
|
|
52
|
+
"id": 1,
|
|
53
|
+
"comment": "This needs fixing",
|
|
54
|
+
"author": {"id": 1, "username": "alice"},
|
|
55
|
+
"created": "2024-01-15T10:30:00Z",
|
|
56
|
+
"updated": "2024-01-15T10:30:00Z",
|
|
57
|
+
"reactions": {"👍": [{"id": 2, "username": "bob"}]}
|
|
58
|
+
}
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
# Core Identification (2 fields)
|
|
62
|
+
id: int = Field(..., description="Unique comment ID")
|
|
63
|
+
comment: str = Field(..., description="Comment text content (markdown)")
|
|
64
|
+
|
|
65
|
+
# Author and Timestamps (3 fields)
|
|
66
|
+
author: Optional[User] = Field(None, description="User who wrote this comment")
|
|
67
|
+
created: Optional[datetime] = Field(None, description="Creation timestamp")
|
|
68
|
+
updated: Optional[datetime] = Field(None, description="Last update timestamp")
|
|
69
|
+
|
|
70
|
+
# Reactions (1 field)
|
|
71
|
+
reactions: Optional[Dict[str, List[User]]] = Field(
|
|
72
|
+
None,
|
|
73
|
+
description="Map of emoji to list of users who reacted"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ============================================================================
|
|
78
|
+
# Task Attachment Model
|
|
79
|
+
# ============================================================================
|
|
80
|
+
|
|
81
|
+
class TaskAttachment(VikunjaBaseModel):
|
|
82
|
+
"""
|
|
83
|
+
A file attachment on a task.
|
|
84
|
+
|
|
85
|
+
API endpoint: Part of task response with expand=attachments
|
|
86
|
+
|
|
87
|
+
Attachments reference files stored in the Vikunja file system. Each has:
|
|
88
|
+
- id: Unique identifier
|
|
89
|
+
- file: File metadata (name, size, mime type)
|
|
90
|
+
- created: Upload timestamp
|
|
91
|
+
- created_by: User who uploaded it
|
|
92
|
+
- task_id: Parent task ID
|
|
93
|
+
|
|
94
|
+
Fields from API spec (models.TaskAttachment):
|
|
95
|
+
- id: Attachment ID
|
|
96
|
+
- file: File object with name, size, mime
|
|
97
|
+
- created: Upload timestamp
|
|
98
|
+
- created_by: User who uploaded
|
|
99
|
+
- task_id: Parent task ID
|
|
100
|
+
|
|
101
|
+
Example from API response:
|
|
102
|
+
{
|
|
103
|
+
"id": 1,
|
|
104
|
+
"file": {
|
|
105
|
+
"id": 100,
|
|
106
|
+
"name": "screenshot.png",
|
|
107
|
+
"size": 245760,
|
|
108
|
+
"mime": "image/png"
|
|
109
|
+
},
|
|
110
|
+
"created": "2024-01-15T10:30:00Z",
|
|
111
|
+
"created_by": {"id": 1, "username": "alice"},
|
|
112
|
+
"task_id": 5
|
|
113
|
+
}
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
# Core Identification (3 fields)
|
|
117
|
+
id: int = Field(..., description="Unique attachment ID")
|
|
118
|
+
task_id: int = Field(..., description="Parent task ID")
|
|
119
|
+
file: dict = Field(..., description="File metadata (name, size, mime)")
|
|
120
|
+
|
|
121
|
+
# Metadata (2 fields)
|
|
122
|
+
created: Optional[datetime] = Field(None, description="Upload timestamp")
|
|
123
|
+
created_by: Optional[User] = Field(None, description="User who uploaded this attachment")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ============================================================================
|
|
127
|
+
# Task Reminder Model
|
|
128
|
+
# ============================================================================
|
|
129
|
+
|
|
130
|
+
# ReminderRelation is a RootModel[str] for the date field reference
|
|
131
|
+
ReminderRelation = RootModel[str]
|
|
132
|
+
"""The date field a reminder is relative to.
|
|
133
|
+
|
|
134
|
+
API spec: models.ReminderRelation
|
|
135
|
+
|
|
136
|
+
Values:
|
|
137
|
+
- due_date: Relative to task's due date
|
|
138
|
+
- start_date: Relative to task's start date
|
|
139
|
+
- end_date: Relative to task's end date
|
|
140
|
+
|
|
141
|
+
Usage:
|
|
142
|
+
from models.task_expansion import ReminderRelation
|
|
143
|
+
|
|
144
|
+
# Create a reminder relative to due date
|
|
145
|
+
rel = ReminderRelation("due_date")
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
ReminderRelation.DUE_DATE = "due_date"
|
|
149
|
+
ReminderRelation.START_DATE = "start_date"
|
|
150
|
+
ReminderRelation.END_DATE = "end_date"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class TaskReminder(VikunjaBaseModel):
|
|
154
|
+
"""
|
|
155
|
+
A reminder for a task.
|
|
156
|
+
|
|
157
|
+
API endpoint: Part of task response with expand=reminders
|
|
158
|
+
|
|
159
|
+
Reminders can be absolute (specific datetime) or relative to task dates.
|
|
160
|
+
|
|
161
|
+
Fields from API spec (models.TaskReminder):
|
|
162
|
+
- reminder: Absolute datetime string (ISO 8601)
|
|
163
|
+
- relative_to: Date field reference (due_date, start_date, end_date)
|
|
164
|
+
- relative_period: Seconds offset from relative_to date
|
|
165
|
+
|
|
166
|
+
Examples:
|
|
167
|
+
# Absolute reminder at specific time
|
|
168
|
+
{
|
|
169
|
+
"reminder": "2024-01-20T09:00:00Z",
|
|
170
|
+
"relative_to": null,
|
|
171
|
+
"relative_period": 0
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Relative reminder (30 minutes before due date)
|
|
175
|
+
{
|
|
176
|
+
"reminder": null,
|
|
177
|
+
"relative_to": "due_date",
|
|
178
|
+
"relative_period": -1800 # -30 minutes in seconds
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Notes:
|
|
182
|
+
- If `reminder` is set, it's an absolute reminder (ignores relative fields)
|
|
183
|
+
- If `relative_to` is set, it's a relative reminder (uses relative_period offset)
|
|
184
|
+
- Negative relative_period means before the reference date
|
|
185
|
+
- Positive relative_period means after the reference date
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
# Core Reminder Definition (3 fields - one mode active at a time)
|
|
189
|
+
reminder: Optional[str] = Field(
|
|
190
|
+
None,
|
|
191
|
+
description="Absolute datetime (ISO 8601). If set, overrides relative fields."
|
|
192
|
+
)
|
|
193
|
+
relative_to: Optional[ReminderRelation] = Field(
|
|
194
|
+
None,
|
|
195
|
+
description="Date field reference (due_date, start_date, end_date)"
|
|
196
|
+
)
|
|
197
|
+
relative_period: Optional[int] = Field(
|
|
198
|
+
0,
|
|
199
|
+
description="Seconds offset from relative_to date. Negative=before, positive=after"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def is_absolute(self) -> bool:
|
|
204
|
+
"""Check if this is an absolute reminder."""
|
|
205
|
+
return self.reminder is not None
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def is_relative(self) -> bool:
|
|
209
|
+
"""Check if this is a relative reminder."""
|
|
210
|
+
return self.relative_to is not None
|
|
211
|
+
|
|
212
|
+
def get_description(self) -> str:
|
|
213
|
+
"""Human-readable description of this reminder."""
|
|
214
|
+
if self.is_absolute:
|
|
215
|
+
return f"Absolute reminder at {self.reminder}"
|
|
216
|
+
elif self.is_relative:
|
|
217
|
+
offset = self.relative_period or 0
|
|
218
|
+
direction = "before" if offset <= 0 else "after"
|
|
219
|
+
abs_offset = abs(offset)
|
|
220
|
+
if abs_offset >= 3600:
|
|
221
|
+
time_str = f"{abs_offset // 3600} hours"
|
|
222
|
+
elif abs_offset >= 60:
|
|
223
|
+
time_str = f"{abs_offset // 60} minutes"
|
|
224
|
+
else:
|
|
225
|
+
time_str = f"{abs_offset} seconds"
|
|
226
|
+
return f"Relative reminder {time_str} {direction} {self.relative_to}"
|
|
227
|
+
return "Reminder with no timing specified"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# ============================================================================
|
|
231
|
+
# Response Models for Task Expansions
|
|
232
|
+
# ============================================================================
|
|
233
|
+
|
|
234
|
+
class TaskCommentsResponse(VikunjaBaseModel):
|
|
235
|
+
"""Response containing task comments."""
|
|
236
|
+
success: bool = Field(True, description="Request succeeded")
|
|
237
|
+
comments: List[TaskComment] = Field(default_factory=list, description="List of comments")
|
|
238
|
+
error: Optional[str] = Field(None, description="Error message if failed")
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class TaskAttachmentsResponse(VikunjaBaseModel):
|
|
242
|
+
"""Response containing task attachments."""
|
|
243
|
+
success: bool = Field(True, description="Request succeeded")
|
|
244
|
+
attachments: List[TaskAttachment] = Field(default_factory=list, description="List of attachments")
|
|
245
|
+
error: Optional[str] = Field(None, description="Error message if failed")
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class TaskRemindersResponse(VikunjaBaseModel):
|
|
249
|
+
"""Response containing task reminders."""
|
|
250
|
+
success: bool = Field(True, description="Request succeeded")
|
|
251
|
+
reminders: List[TaskReminder] = Field(default_factory=list, description="List of reminders")
|
|
252
|
+
error: Optional[str] = Field(None, description="Error message if failed")
|