async-vikunja 1.0.0
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.
- checksums.yaml +7 -0
- data/README.md +362 -0
- data/lib/async/vikunja/admin.rb +97 -0
- data/lib/async/vikunja/assignees.rb +20 -0
- data/lib/async/vikunja/attachments.rb +51 -0
- data/lib/async/vikunja/auth.rb +52 -0
- data/lib/async/vikunja/bots.rb +43 -0
- data/lib/async/vikunja/buckets.rb +51 -0
- data/lib/async/vikunja/client.rb +76 -0
- data/lib/async/vikunja/comments.rb +31 -0
- data/lib/async/vikunja/error.rb +52 -0
- data/lib/async/vikunja/escape.rb +9 -0
- data/lib/async/vikunja/filters.rb +39 -0
- data/lib/async/vikunja/labels.rb +71 -0
- data/lib/async/vikunja/migration.rb +89 -0
- data/lib/async/vikunja/notifications.rb +45 -0
- data/lib/async/vikunja/page.rb +112 -0
- data/lib/async/vikunja/projects.rb +133 -0
- data/lib/async/vikunja/reactions.rb +19 -0
- data/lib/async/vikunja/redacted.rb +37 -0
- data/lib/async/vikunja/representation.rb +73 -0
- data/lib/async/vikunja/service.rb +137 -0
- data/lib/async/vikunja/sessions.rb +29 -0
- data/lib/async/vikunja/settings.rb +67 -0
- data/lib/async/vikunja/sharing.rb +131 -0
- data/lib/async/vikunja/submit.rb +97 -0
- data/lib/async/vikunja/subscriptions.rb +21 -0
- data/lib/async/vikunja/tasks.rb +207 -0
- data/lib/async/vikunja/teams.rb +85 -0
- data/lib/async/vikunja/time_entries.rb +55 -0
- data/lib/async/vikunja/tokens.rb +59 -0
- data/lib/async/vikunja/users.rb +107 -0
- data/lib/async/vikunja/version.rb +10 -0
- data/lib/async/vikunja/views.rb +75 -0
- data/lib/async/vikunja/webhooks.rb +55 -0
- data/lib/async/vikunja/wrapper.rb +75 -0
- data/lib/async/vikunja.rb +2 -0
- data/license.md +21 -0
- metadata +105 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "async/rest/resource"
|
|
2
|
+
|
|
3
|
+
require_relative "admin"
|
|
4
|
+
require_relative "assignees"
|
|
5
|
+
require_relative "attachments"
|
|
6
|
+
require_relative "auth"
|
|
7
|
+
require_relative "bots"
|
|
8
|
+
require_relative "buckets"
|
|
9
|
+
require_relative "comments"
|
|
10
|
+
require_relative "error"
|
|
11
|
+
require_relative "filters"
|
|
12
|
+
require_relative "labels"
|
|
13
|
+
require_relative "migration"
|
|
14
|
+
require_relative "notifications"
|
|
15
|
+
require_relative "page"
|
|
16
|
+
require_relative "projects"
|
|
17
|
+
require_relative "reactions"
|
|
18
|
+
require_relative "service"
|
|
19
|
+
require_relative "sessions"
|
|
20
|
+
require_relative "settings"
|
|
21
|
+
require_relative "sharing"
|
|
22
|
+
require_relative "subscriptions"
|
|
23
|
+
require_relative "submit"
|
|
24
|
+
require_relative "tasks"
|
|
25
|
+
require_relative "teams"
|
|
26
|
+
require_relative "time_entries"
|
|
27
|
+
require_relative "tokens"
|
|
28
|
+
require_relative "users"
|
|
29
|
+
require_relative "version"
|
|
30
|
+
require_relative "views"
|
|
31
|
+
require_relative "webhooks"
|
|
32
|
+
|
|
33
|
+
module Async
|
|
34
|
+
module Vikunja
|
|
35
|
+
class Client < Async::REST::Resource
|
|
36
|
+
ENDPOINT = Async::HTTP::Endpoint.parse(ENV.fetch("VIKUNJA_URL", "http://localhost:3456/api/v2/"))
|
|
37
|
+
|
|
38
|
+
USER_AGENT = "async-vikunja (https://github.com/n-at-han-k/async-vikunja, v" + VERSION + ")"
|
|
39
|
+
|
|
40
|
+
include Submit
|
|
41
|
+
|
|
42
|
+
include Admin
|
|
43
|
+
include Auth
|
|
44
|
+
include Bots
|
|
45
|
+
include Filters
|
|
46
|
+
include Labels
|
|
47
|
+
include Migration
|
|
48
|
+
include Notifications
|
|
49
|
+
include Projects
|
|
50
|
+
include Reactions
|
|
51
|
+
include Service
|
|
52
|
+
include Sessions
|
|
53
|
+
include Settings
|
|
54
|
+
include Sharing
|
|
55
|
+
include Subscriptions
|
|
56
|
+
include Tasks
|
|
57
|
+
include Teams
|
|
58
|
+
include TimeEntries
|
|
59
|
+
include Tokens
|
|
60
|
+
include Users
|
|
61
|
+
include Webhooks
|
|
62
|
+
|
|
63
|
+
def initialize(delegate, reference = ::Protocol::URL::Reference.parse, headers = ::Protocol::HTTP::Headers.new)
|
|
64
|
+
super
|
|
65
|
+
|
|
66
|
+
unless @headers["user-agent"]
|
|
67
|
+
@headers = @headers.merge("user-agent" => USER_AGENT)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def authenticated(token)
|
|
72
|
+
self.with(headers: {"authorization" => "Bearer " + token})
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class TaskComment < Representation
|
|
6
|
+
def id = self.value[:id]
|
|
7
|
+
|
|
8
|
+
def comment = self.value[:comment]
|
|
9
|
+
|
|
10
|
+
def created = self.value[:created]
|
|
11
|
+
|
|
12
|
+
def updated = self.value[:updated]
|
|
13
|
+
|
|
14
|
+
def reactions = self.value[:reactions]
|
|
15
|
+
|
|
16
|
+
def author = self.nested(User, self.value[:author])
|
|
17
|
+
|
|
18
|
+
def max_permission = self.value[:max_permission]
|
|
19
|
+
|
|
20
|
+
def update(payload) = self.submit(TaskComment, @resource, payload, method: :put)
|
|
21
|
+
|
|
22
|
+
def patch(payload) = self.merge_patch(TaskComment, @resource, payload)
|
|
23
|
+
|
|
24
|
+
def delete = self.discard(@resource)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class TaskCommentPage < Page
|
|
28
|
+
MEMBER = TaskComment
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Async
|
|
2
|
+
module Vikunja
|
|
3
|
+
class Error < StandardError
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
class Failure < Error
|
|
7
|
+
def self.for(response)
|
|
8
|
+
problem = self.problem_for(response.read)
|
|
9
|
+
|
|
10
|
+
self.new(
|
|
11
|
+
response.status.to_s + ": " + self.summary_of(problem),
|
|
12
|
+
status: response.status,
|
|
13
|
+
problem: problem,
|
|
14
|
+
retry_after: response.headers["retry-after"],
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.problem_for(payload)
|
|
19
|
+
case payload
|
|
20
|
+
in Hash => problem
|
|
21
|
+
problem
|
|
22
|
+
else
|
|
23
|
+
{detail: payload.to_s}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.summary_of(problem)
|
|
28
|
+
problem[:title] || problem[:detail] || problem.inspect
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def initialize(message, status:, problem: {}, retry_after: nil)
|
|
32
|
+
super(message)
|
|
33
|
+
|
|
34
|
+
@status = status
|
|
35
|
+
@problem = problem
|
|
36
|
+
@retry_after = retry_after
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr :status
|
|
40
|
+
attr :problem
|
|
41
|
+
attr :retry_after
|
|
42
|
+
|
|
43
|
+
def code = @problem[:code]
|
|
44
|
+
|
|
45
|
+
def title = @problem[:title]
|
|
46
|
+
|
|
47
|
+
def detail = @problem[:detail]
|
|
48
|
+
|
|
49
|
+
def errors = Array(@problem[:errors])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class SavedFilter < Representation
|
|
6
|
+
def id = self.value[:id]
|
|
7
|
+
|
|
8
|
+
def title = self.value[:title]
|
|
9
|
+
|
|
10
|
+
def description = self.value[:description]
|
|
11
|
+
|
|
12
|
+
def is_favorite = self.value[:is_favorite]
|
|
13
|
+
|
|
14
|
+
def max_permission = self.value[:max_permission]
|
|
15
|
+
|
|
16
|
+
def created = self.value[:created]
|
|
17
|
+
|
|
18
|
+
def updated = self.value[:updated]
|
|
19
|
+
|
|
20
|
+
def owner = self.nested(User, self.value[:owner])
|
|
21
|
+
|
|
22
|
+
def filters = self.nested(TaskCollection, self.value[:filters])
|
|
23
|
+
|
|
24
|
+
def favorite? = self.is_favorite == true
|
|
25
|
+
|
|
26
|
+
def update(payload) = self.submit(SavedFilter, @resource, payload, method: :put)
|
|
27
|
+
|
|
28
|
+
def patch(payload) = self.merge_patch(SavedFilter, @resource, payload)
|
|
29
|
+
|
|
30
|
+
def delete = self.discard(@resource)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
module Filters
|
|
34
|
+
def filter(id) = SavedFilter.new(self.with(path: "filters/" + Vikunja.escape(id)))
|
|
35
|
+
|
|
36
|
+
def create_filter(payload) = self.submit(SavedFilter, self.with(path: "filters"), payload, identify: true)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class Label < Representation
|
|
6
|
+
def id = self.value[:id]
|
|
7
|
+
|
|
8
|
+
def title = self.value[:title]
|
|
9
|
+
|
|
10
|
+
def description = self.value[:description]
|
|
11
|
+
|
|
12
|
+
def hex_color = self.value[:hex_color]
|
|
13
|
+
|
|
14
|
+
def created = self.value[:created]
|
|
15
|
+
|
|
16
|
+
def updated = self.value[:updated]
|
|
17
|
+
|
|
18
|
+
def created_by = self.nested(User, self.value[:created_by])
|
|
19
|
+
|
|
20
|
+
def max_permission = self.value[:max_permission]
|
|
21
|
+
|
|
22
|
+
def update(payload) = self.submit(Label, @resource, payload, method: :put)
|
|
23
|
+
|
|
24
|
+
def patch(payload) = self.merge_patch(Label, @resource, payload)
|
|
25
|
+
|
|
26
|
+
def delete = self.discard(@resource)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class LabelWithTaskID < Representation
|
|
30
|
+
def id = self.value[:id]
|
|
31
|
+
|
|
32
|
+
def title = self.value[:title]
|
|
33
|
+
|
|
34
|
+
def description = self.value[:description]
|
|
35
|
+
|
|
36
|
+
def hex_color = self.value[:hex_color]
|
|
37
|
+
|
|
38
|
+
def created = self.value[:created]
|
|
39
|
+
|
|
40
|
+
def updated = self.value[:updated]
|
|
41
|
+
|
|
42
|
+
def created_by = self.nested(User, self.value[:created_by])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class LabelTask < Representation
|
|
46
|
+
def label_id = self.value[:label_id]
|
|
47
|
+
|
|
48
|
+
def created = self.value[:created]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class LabelTaskBulk < Representation
|
|
52
|
+
def labels = self.nested_list(Label, self.value[:labels])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class LabelPage < Page
|
|
56
|
+
MEMBER = LabelWithTaskID
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class TaskLabelPage < Page
|
|
60
|
+
MEMBER = LabelWithTaskID
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module Labels
|
|
64
|
+
def labels(**parameters) = Collection.for(self, "labels", LabelPage, **parameters)
|
|
65
|
+
|
|
66
|
+
def label(id) = Label.new(self.with(path: "labels/" + Vikunja.escape(id)))
|
|
67
|
+
|
|
68
|
+
def create_label(payload) = self.submit(Label, self.with(path: "labels"), payload, identify: true)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class ColumnMapping < Representation
|
|
6
|
+
def attribute = self.value[:attribute]
|
|
7
|
+
|
|
8
|
+
def column_index = self.value[:column_index]
|
|
9
|
+
|
|
10
|
+
def column_name = self.value[:column_name]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class DetectionResult < Representation
|
|
14
|
+
def columns = self.value[:columns]
|
|
15
|
+
|
|
16
|
+
def date_format = self.value[:date_format]
|
|
17
|
+
|
|
18
|
+
def delimiter = self.value[:delimiter]
|
|
19
|
+
|
|
20
|
+
def preview_rows = self.value[:preview_rows]
|
|
21
|
+
|
|
22
|
+
def quote_char = self.value[:quote_char]
|
|
23
|
+
|
|
24
|
+
def suggested_mapping = self.nested_list(ColumnMapping, self.value[:suggested_mapping])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class PreviewTask < Representation
|
|
28
|
+
def title = self.value[:title]
|
|
29
|
+
|
|
30
|
+
def description = self.value[:description]
|
|
31
|
+
|
|
32
|
+
def done = self.value[:done]
|
|
33
|
+
|
|
34
|
+
def due_date = self.value[:due_date]
|
|
35
|
+
|
|
36
|
+
def start_date = self.value[:start_date]
|
|
37
|
+
|
|
38
|
+
def end_date = self.value[:end_date]
|
|
39
|
+
|
|
40
|
+
def labels = self.value[:labels]
|
|
41
|
+
|
|
42
|
+
def priority = self.value[:priority]
|
|
43
|
+
|
|
44
|
+
def project = self.value[:project]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class PreviewResult < Representation
|
|
48
|
+
def tasks = self.nested_list(PreviewTask, self.value[:tasks])
|
|
49
|
+
|
|
50
|
+
def total_rows = self.value[:total_rows]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class Status < Representation
|
|
54
|
+
def id = self.value[:id]
|
|
55
|
+
|
|
56
|
+
def migrator_name = self.value[:migrator_name]
|
|
57
|
+
|
|
58
|
+
def started_at = self.value[:started_at]
|
|
59
|
+
|
|
60
|
+
def finished_at = self.value[:finished_at]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module Migration
|
|
64
|
+
def csv_detect(part) = self.upload(DetectionResult, self.with(path: "migration/csv/detect"), [part])
|
|
65
|
+
|
|
66
|
+
def csv_preview(parts) = self.upload(PreviewResult, self.with(path: "migration/csv/preview"), parts)
|
|
67
|
+
|
|
68
|
+
def csv_migrate(parts) = self.upload(Message, self.with(path: "migration/csv/migrate"), parts)
|
|
69
|
+
|
|
70
|
+
def csv_status = Status.new(self.with(path: "migration/csv/status"))
|
|
71
|
+
|
|
72
|
+
def planka_migrate(payload) = self.submit(Message, self.with(path: "migration/planka/migrate"), payload)
|
|
73
|
+
|
|
74
|
+
def planka_status = Status.new(self.with(path: "migration/planka/status"))
|
|
75
|
+
|
|
76
|
+
def ticktick_migrate(part) = self.upload(Message, self.with(path: "migration/ticktick/migrate"), [part])
|
|
77
|
+
|
|
78
|
+
def ticktick_status = Status.new(self.with(path: "migration/ticktick/status"))
|
|
79
|
+
|
|
80
|
+
def vikunja_file_migrate(part) = self.upload(Message, self.with(path: "migration/vikunja-file/migrate"), [part])
|
|
81
|
+
|
|
82
|
+
def vikunja_file_status = Status.new(self.with(path: "migration/vikunja-file/status"))
|
|
83
|
+
|
|
84
|
+
def wekan_migrate(part) = self.upload(Message, self.with(path: "migration/wekan/migrate"), [part])
|
|
85
|
+
|
|
86
|
+
def wekan_status = Status.new(self.with(path: "migration/wekan/status"))
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class DatabaseNotification < Representation
|
|
6
|
+
def id = self.value[:id]
|
|
7
|
+
|
|
8
|
+
def name = self.value[:name]
|
|
9
|
+
|
|
10
|
+
def notification = self.value[:notification]
|
|
11
|
+
|
|
12
|
+
def read_at = self.value[:read_at]
|
|
13
|
+
|
|
14
|
+
def created = self.value[:created]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class DatabaseNotifications < Representation
|
|
18
|
+
def id = self.value[:id]
|
|
19
|
+
|
|
20
|
+
def name = self.value[:name]
|
|
21
|
+
|
|
22
|
+
def notification = self.value[:notification]
|
|
23
|
+
|
|
24
|
+
def read = self.value[:read]
|
|
25
|
+
|
|
26
|
+
def read_at = self.value[:read_at]
|
|
27
|
+
|
|
28
|
+
def created = self.value[:created]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class NotificationPage < Page
|
|
32
|
+
MEMBER = DatabaseNotification
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module Notifications
|
|
36
|
+
def notifications(**parameters) = Collection.for(self, "notifications", NotificationPage, **parameters)
|
|
37
|
+
|
|
38
|
+
def mark_notifications_read = self.submit(Message, self.with(path: "notifications"), nil)
|
|
39
|
+
|
|
40
|
+
def clear_notifications = self.discard(self.with(path: "notifications"))
|
|
41
|
+
|
|
42
|
+
def update_notification(id, payload) = self.submit(DatabaseNotifications, self.with(path: "notifications/" + Vikunja.escape(id)), payload, method: :put)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require_relative "representation"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class Page < Representation
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
MEMBER = Representation
|
|
9
|
+
|
|
10
|
+
def items = Array(self.value[:items])
|
|
11
|
+
|
|
12
|
+
def page = self.value[:page].to_i
|
|
13
|
+
|
|
14
|
+
def per_page = self.value[:per_page].to_i
|
|
15
|
+
|
|
16
|
+
def total = self.value[:total].to_i
|
|
17
|
+
|
|
18
|
+
def total_pages = self.value[:total_pages].to_i
|
|
19
|
+
|
|
20
|
+
def last? = self.page >= [self.total_pages, 1].max
|
|
21
|
+
|
|
22
|
+
def empty? = self.items.empty?
|
|
23
|
+
|
|
24
|
+
def each(&block)
|
|
25
|
+
if block
|
|
26
|
+
self.items.each do |record|
|
|
27
|
+
block.call(self.member_for(record))
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
self.to_enum(:each)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def member_class = self.class::MEMBER
|
|
35
|
+
|
|
36
|
+
def member_path(record) = Vikunja.escape(record[:id])
|
|
37
|
+
|
|
38
|
+
def member_resource(record)
|
|
39
|
+
@resource.with(path: self.member_path(record), parameters: nil, merge: false)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def member_for(record)
|
|
43
|
+
self.member_class.new(self.member_resource(record), value: record, metadata: self.metadata)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Collection
|
|
48
|
+
include Enumerable
|
|
49
|
+
|
|
50
|
+
DEFAULT_PER_PAGE = 50
|
|
51
|
+
|
|
52
|
+
def self.for(parent, path, page_class, **parameters)
|
|
53
|
+
self.new(parent.with(path: path, parameters: parameters), page_class)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def initialize(resource, page_class)
|
|
57
|
+
@resource = resource
|
|
58
|
+
@page_class = page_class
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
attr :resource
|
|
62
|
+
|
|
63
|
+
attr :page_class
|
|
64
|
+
|
|
65
|
+
def each_page(per_page: DEFAULT_PER_PAGE, &block)
|
|
66
|
+
if block
|
|
67
|
+
self.walk(per_page, &block)
|
|
68
|
+
else
|
|
69
|
+
self.to_enum(:each_page, per_page: per_page)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def each(**options, &block)
|
|
74
|
+
if block
|
|
75
|
+
self.each_page(**options) do |page|
|
|
76
|
+
page.each(&block)
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
self.to_enum(:each, **options)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def page(number, per_page: DEFAULT_PER_PAGE)
|
|
84
|
+
@page_class.new(@resource.with(parameters: {page: number, per_page: per_page}))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def total
|
|
88
|
+
self.page(1, per_page: 1).total
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def walk(per_page, &block)
|
|
92
|
+
number = 1
|
|
93
|
+
|
|
94
|
+
while true
|
|
95
|
+
page = self.page(number, per_page: per_page)
|
|
96
|
+
|
|
97
|
+
if page.empty?
|
|
98
|
+
break
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
block.call(page)
|
|
102
|
+
|
|
103
|
+
if page.last?
|
|
104
|
+
break
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
number += 1
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class Project < Representation
|
|
6
|
+
def id = self.value[:id]
|
|
7
|
+
|
|
8
|
+
def title = self.value[:title]
|
|
9
|
+
|
|
10
|
+
def description = self.value[:description]
|
|
11
|
+
|
|
12
|
+
def identifier = self.value[:identifier]
|
|
13
|
+
|
|
14
|
+
def hex_color = self.value[:hex_color]
|
|
15
|
+
|
|
16
|
+
def position = self.value[:position]
|
|
17
|
+
|
|
18
|
+
def parent_project_id = self.value[:parent_project_id]
|
|
19
|
+
|
|
20
|
+
def is_archived = self.value[:is_archived]
|
|
21
|
+
|
|
22
|
+
def is_favorite = self.value[:is_favorite]
|
|
23
|
+
|
|
24
|
+
def max_permission = self.value[:max_permission]
|
|
25
|
+
|
|
26
|
+
def background_blur_hash = self.value[:background_blur_hash]
|
|
27
|
+
|
|
28
|
+
def background_information = self.value[:background_information]
|
|
29
|
+
|
|
30
|
+
def created = self.value[:created]
|
|
31
|
+
|
|
32
|
+
def updated = self.value[:updated]
|
|
33
|
+
|
|
34
|
+
def owner = self.nested(User, self.value[:owner])
|
|
35
|
+
|
|
36
|
+
def subscription = self.nested(Subscription, self.value[:subscription])
|
|
37
|
+
|
|
38
|
+
def views = self.nested_list(ProjectView, self.value[:views])
|
|
39
|
+
|
|
40
|
+
def archived? = self.is_archived == true
|
|
41
|
+
|
|
42
|
+
def favorite? = self.is_favorite == true
|
|
43
|
+
|
|
44
|
+
def tasks(**parameters) = Collection.for(@resource, "tasks", ProjectTaskPage, **parameters)
|
|
45
|
+
|
|
46
|
+
def project_views(**parameters) = Collection.for(@resource, "views", ProjectViewPage, **parameters)
|
|
47
|
+
|
|
48
|
+
def shares(**parameters) = Collection.for(@resource, "shares", LinkSharingPage, **parameters)
|
|
49
|
+
|
|
50
|
+
def teams(**parameters) = Collection.for(@resource, "teams", TeamWithPermissionPage, **parameters)
|
|
51
|
+
|
|
52
|
+
def users(**parameters) = Collection.for(@resource, "users", ProjectUserPage, **parameters)
|
|
53
|
+
|
|
54
|
+
def webhooks(**parameters) = Collection.for(@resource, "webhooks", ProjectWebhookPage, **parameters)
|
|
55
|
+
|
|
56
|
+
def time_entries(**parameters) = Collection.for(@resource, "time-entries", ProjectTimeEntryPage, **parameters)
|
|
57
|
+
|
|
58
|
+
def view(id) = ProjectView.new(@resource.with(path: "views/" + Vikunja.escape(id)))
|
|
59
|
+
|
|
60
|
+
def share(id) = LinkSharing.new(@resource.with(path: "shares/" + Vikunja.escape(id)))
|
|
61
|
+
|
|
62
|
+
def task_by_index(index) = TaskReadOneBody.new(@resource.with(path: "tasks/by-index/" + Vikunja.escape(index)))
|
|
63
|
+
|
|
64
|
+
def background = Download.new(@resource.with(path: "background"))
|
|
65
|
+
|
|
66
|
+
def search_users(query) = UserSearchPage.new(@resource.with(path: "users/search", parameters: {q: query}))
|
|
67
|
+
|
|
68
|
+
def create_task(payload) = self.submit(Task, @resource.with(path: "tasks"), payload, identify: "../../../tasks/")
|
|
69
|
+
|
|
70
|
+
def create_tasks(titles) = self.submit(BulkTaskCreation, @resource.with(path: "tasks/bulk"), {tasks: titles}, identify: nil)
|
|
71
|
+
|
|
72
|
+
def create_view(payload) = self.submit(ProjectView, @resource.with(path: "views"), payload, identify: true)
|
|
73
|
+
|
|
74
|
+
def create_share(payload) = self.submit(LinkSharing, @resource.with(path: "shares"), payload, identify: true)
|
|
75
|
+
|
|
76
|
+
def create_webhook(payload) = self.submit(Webhook, @resource.with(path: "webhooks"), payload, identify: true)
|
|
77
|
+
|
|
78
|
+
def add_team(payload) = self.submit(TeamProject, @resource.with(path: "teams"), payload)
|
|
79
|
+
|
|
80
|
+
def add_user(payload) = self.submit(ProjectUser, @resource.with(path: "users"), payload)
|
|
81
|
+
|
|
82
|
+
def update_team(team, payload) = self.submit(TeamProject, @resource.with(path: "teams/" + Vikunja.escape(team)), payload, method: :put)
|
|
83
|
+
|
|
84
|
+
def update_user(user, payload) = self.submit(ProjectUser, @resource.with(path: "users/" + Vikunja.escape(user)), payload, method: :put)
|
|
85
|
+
|
|
86
|
+
def update_webhook(webhook, payload) = self.submit(Webhook, @resource.with(path: "webhooks/" + Vikunja.escape(webhook)), payload, method: :put)
|
|
87
|
+
|
|
88
|
+
def remove_team(team) = self.discard(@resource.with(path: "teams/" + Vikunja.escape(team)))
|
|
89
|
+
|
|
90
|
+
def remove_user(user) = self.discard(@resource.with(path: "users/" + Vikunja.escape(user)))
|
|
91
|
+
|
|
92
|
+
def remove_webhook(webhook) = self.discard(@resource.with(path: "webhooks/" + Vikunja.escape(webhook)))
|
|
93
|
+
|
|
94
|
+
def remove_share(id) = self.discard(@resource.with(path: "shares/" + Vikunja.escape(id)))
|
|
95
|
+
|
|
96
|
+
def duplicate(payload = {}) = self.submit(ProjectDuplicate, @resource.with(path: "duplicate"), payload)
|
|
97
|
+
|
|
98
|
+
def upload_background(part) = self.upload(Project, @resource.with(path: "backgrounds/upload"), [part], method: :put)
|
|
99
|
+
|
|
100
|
+
def remove_background = self.submit(Project, @resource.with(path: "background"), nil, method: :delete)
|
|
101
|
+
|
|
102
|
+
def update(payload) = self.submit(Project, @resource, payload, method: :put)
|
|
103
|
+
|
|
104
|
+
def patch(payload) = self.merge_patch(Project, @resource, payload)
|
|
105
|
+
|
|
106
|
+
def delete = self.discard(@resource)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class ProjectDuplicate < Representation
|
|
110
|
+
def parent_project_id = self.value[:parent_project_id]
|
|
111
|
+
|
|
112
|
+
def duplicate_shares = self.value[:duplicate_shares]
|
|
113
|
+
|
|
114
|
+
def duplicated_project = self.nested(Project, self.value[:duplicated_project])
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
class ProjectPage < Page
|
|
118
|
+
MEMBER = Project
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class AdminProjectPage < ProjectPage
|
|
122
|
+
def member_path(record) = "../../projects/" + Vikunja.escape(record[:id])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
module Projects
|
|
126
|
+
def projects(**parameters) = Collection.for(self, "projects", ProjectPage, **parameters)
|
|
127
|
+
|
|
128
|
+
def project(id) = Project.new(self.with(path: "projects/" + Vikunja.escape(id)))
|
|
129
|
+
|
|
130
|
+
def create_project(payload) = self.submit(Project, self.with(path: "projects"), payload, identify: true)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative "page"
|
|
2
|
+
|
|
3
|
+
module Async
|
|
4
|
+
module Vikunja
|
|
5
|
+
class Reaction < Representation
|
|
6
|
+
def created = self.value[:created]
|
|
7
|
+
|
|
8
|
+
def user = self.nested(User, self.value[:user])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Reactions
|
|
12
|
+
def reactions(entitykind, entityid) = Representation.new(self.with(path: Vikunja.escape(entitykind) + "/" + Vikunja.escape(entityid) + "/reactions"))
|
|
13
|
+
|
|
14
|
+
def add_reaction(entitykind, entityid, payload) = self.submit(Reaction, self.with(path: Vikunja.escape(entitykind) + "/" + Vikunja.escape(entityid) + "/reactions"), payload)
|
|
15
|
+
|
|
16
|
+
def remove_reaction(entitykind, entityid, payload) = self.submit(Representation, self.with(path: Vikunja.escape(entitykind) + "/" + Vikunja.escape(entityid) + "/reactions/delete"), payload)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|