mural-ruby 0.1.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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +28 -0
  3. data/.ruby-version +1 -0
  4. data/README.md +126 -0
  5. data/Rakefile +16 -0
  6. data/UNLICENSE +24 -0
  7. data/img/draw-widget.png +0 -0
  8. data/img/inking-widget.png +0 -0
  9. data/img/mind-map.png +0 -0
  10. data/img/smart-planner.png +0 -0
  11. data/lib/mural/asset.rb +26 -0
  12. data/lib/mural/client/authentication.rb +75 -0
  13. data/lib/mural/client/mural_content/files.rb +40 -0
  14. data/lib/mural/client/mural_content/sticky_notes.rb +30 -0
  15. data/lib/mural/client/mural_content/tags.rb +48 -0
  16. data/lib/mural/client/mural_content/widgets.rb +33 -0
  17. data/lib/mural/client/mural_content.rb +30 -0
  18. data/lib/mural/client/murals.rb +138 -0
  19. data/lib/mural/client/rooms.rb +92 -0
  20. data/lib/mural/client/search.rb +55 -0
  21. data/lib/mural/client/templates.rb +77 -0
  22. data/lib/mural/client/users/mural_users.rb +67 -0
  23. data/lib/mural/client/users/room_users.rb +62 -0
  24. data/lib/mural/client/users.rb +38 -0
  25. data/lib/mural/client/workspaces.rb +33 -0
  26. data/lib/mural/client.rb +119 -0
  27. data/lib/mural/codec.rb +44 -0
  28. data/lib/mural/create_mural_params.rb +33 -0
  29. data/lib/mural/create_room_params.rb +16 -0
  30. data/lib/mural/create_sticky_note_params.rb +37 -0
  31. data/lib/mural/create_tag_params.rb +45 -0
  32. data/lib/mural/current_user.rb +21 -0
  33. data/lib/mural/duplicate_mural_params.rb +14 -0
  34. data/lib/mural/mural_board.rb +96 -0
  35. data/lib/mural/mural_export.rb +16 -0
  36. data/lib/mural/mural_invitation.rb +16 -0
  37. data/lib/mural/mural_invitation_params.rb +14 -0
  38. data/lib/mural/mural_user.rb +30 -0
  39. data/lib/mural/removed_mural_user.rb +14 -0
  40. data/lib/mural/removed_room_user.rb +14 -0
  41. data/lib/mural/room.rb +63 -0
  42. data/lib/mural/room_folder.rb +21 -0
  43. data/lib/mural/room_invitation.rb +16 -0
  44. data/lib/mural/room_invitation_params.rb +13 -0
  45. data/lib/mural/room_user.rb +17 -0
  46. data/lib/mural/search_mural_result.rb +21 -0
  47. data/lib/mural/search_room_result.rb +16 -0
  48. data/lib/mural/search_template_result.rb +18 -0
  49. data/lib/mural/tag.rb +25 -0
  50. data/lib/mural/template.rb +24 -0
  51. data/lib/mural/update_mural_params.rb +23 -0
  52. data/lib/mural/update_room_params.rb +15 -0
  53. data/lib/mural/update_room_user_params.rb +16 -0
  54. data/lib/mural/update_sticky_note_params.rb +24 -0
  55. data/lib/mural/update_tag_params.rb +22 -0
  56. data/lib/mural/version.rb +5 -0
  57. data/lib/mural/widget/area.rb +53 -0
  58. data/lib/mural/widget/arrow.rb +139 -0
  59. data/lib/mural/widget/comment.rb +92 -0
  60. data/lib/mural/widget/create_file_params.rb +56 -0
  61. data/lib/mural/widget/file.rb +34 -0
  62. data/lib/mural/widget/icon.rb +34 -0
  63. data/lib/mural/widget/image.rb +77 -0
  64. data/lib/mural/widget/shape.rb +79 -0
  65. data/lib/mural/widget/sticky_note.rb +81 -0
  66. data/lib/mural/widget/table.rb +54 -0
  67. data/lib/mural/widget/table_cell.rb +50 -0
  68. data/lib/mural/widget/text.rb +58 -0
  69. data/lib/mural/widget/update_file_params.rb +50 -0
  70. data/lib/mural/widget.rb +158 -0
  71. data/lib/mural/workspace.rb +47 -0
  72. data/lib/mural/workspace_invitation.rb +16 -0
  73. data/lib/mural.rb +27 -0
  74. metadata +132 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 35d1d5b409d40946faea660284f87875d36785f57278c967c93a645effe6fa24
4
+ data.tar.gz: 589cdad5b6ef75573fbca62b86de32b43bc084723c4c3a4a8a7589d46e81b82d
5
+ SHA512:
6
+ metadata.gz: a2ed7a6155ab38a55199c17442a07dfb23db5e2191df44096668b1ec73d52a860b80abd0e62439611d726b0f4e95e8eb29e6e75c8b72b840a0ee684fb5d74cf8
7
+ data.tar.gz: 7ca63988d68d1f4c3e9099121229582244295aa605e4928c71cdee185432aad202c3206ba457299ddaf41de40112703340158033a0ab3da183ab05b45e3f0201
@@ -0,0 +1,28 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: ["main"]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ ruby-version: ['3.2', '3.3', '3.4']
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby-version }}
26
+ bundler-cache: true
27
+ - name: Run tests
28
+ run: bundle exec rake
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.9
data/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # Mural Ruby
2
+
3
+ Ruby library for the [Mural](https://app.mural.co) public API.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ git checkout https://github.com/mickaelpham/mural-ruby
9
+ cd mural-ruby
10
+ bundle install
11
+ ```
12
+
13
+ ## Authorization
14
+
15
+ 1. [Register a new app][register-app] and gather your `client_id` and
16
+ `client_secret`. For the scopes, pick the minimum required for your
17
+ application.
18
+
19
+ 2. Create a `.env` file with the following template and fill in
20
+ `MURAL_CLIENT_ID` and `MURAL_CLIENT_SECRET` with those values:
21
+
22
+ ```
23
+ MURAL_CLIENT_ID=
24
+ MURAL_CLIENT_SECRET=
25
+ MURAL_SCOPE=
26
+ MURAL_REDIRECT_URI=http://localhost:4567/callback
27
+ MURAL_HOST=app.mural.co
28
+ ```
29
+
30
+ 3. Run the script to request your access and refresh tokens:
31
+
32
+ ```sh
33
+ bin/authorize
34
+ ```
35
+
36
+ 4. Start the console:
37
+
38
+ ```sh
39
+ bin/console
40
+ ```
41
+
42
+ 5. From the console, create a client instance and start using it, e.g.:
43
+
44
+ ```sh
45
+ irb(main):001> mural = Mural::Client.from_env
46
+ =>
47
+ #<Mural::Client:0x0000000120baa740
48
+ ...
49
+ irb(main):002> mural.users.current_user
50
+ =>
51
+ #<Mural::CurrentUser:0x0000000124614bd8
52
+ @avatar="<AVATAR_URL>",
53
+ @company_id=nil,
54
+ @company_name=nil,
55
+ @created_on=1753301275000,
56
+ @email="<USER_EMAIL>",
57
+ @first_name="<USER_FIRST_NAME>",
58
+ @id="=<USER_ID>",
59
+ @last_active_workspace="<USER_WORKSPACE>",
60
+ @last_name="<USER_LAST_NAME>",
61
+ @type="member">
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### Upload a file to a mural
67
+
68
+ To upload a `my.pdf` file that's located in the same directory as where you
69
+ are running the script:
70
+
71
+ ```rb
72
+ MURAL_ID = 'workspace-1.mural-1'
73
+
74
+ client = Mural::Client.from_env
75
+
76
+ # Create an asset, receive an URL to upload the content to.
77
+ asset = client.mural_content.create_asset(
78
+ MURAL_ID,
79
+ file_extension: 'pdf',
80
+ asset_type: 'file'
81
+ )
82
+
83
+ # Upload the asset to the received URL.
84
+ request = Net::HTTP::Put.new(uri)
85
+ request['x-ms-blob-type'] = asset.headers.blob_type
86
+
87
+ path = File.expand_path('./my.pdf', __dir__)
88
+ request.body = File.read(path)
89
+
90
+ Net::HTTP.start(
91
+ uri.hostname, uri.port, use_ssl: uri.scheme == 'https'
92
+ ) do |http|
93
+ http.request request
94
+ end
95
+
96
+ # Create a `file` widget on the mural to display the asset preview.
97
+ params = Mural::Widget::CreateFileParams.new.tap do |params|
98
+ params.name = asset.name
99
+ params.x = 250
100
+ params.y = 0
101
+ end
102
+
103
+ client.mural_content.create_file(MURAL_ID, params)
104
+ ```
105
+
106
+ ## Known limitations
107
+
108
+ - `DrawWidget`, AKA sketches, are not returned by the `GET widgets` endpoint.
109
+
110
+ ![draw widget example](./img/draw-widget.png)
111
+
112
+ - Similarly, `InkingWidget`, AKA drawings, are not returned by the endpoint.
113
+
114
+ ![inking widget example](./img/inking-widget.png)
115
+
116
+ - Mind maps are smart widgets, they are simply a collection of text and arrow
117
+ widgets. There are no specific `type` for a mind map in the API.
118
+
119
+ ![mind map example](./img/mind-map.png)
120
+
121
+ - Likewise, smart planners are collection of widgets, and the API doesn't
122
+ specify anything about them.
123
+
124
+ ![smart planner example](./img/smart-planner.png)
125
+
126
+ [register-app]: https://developers.mural.co/public/docs/register-your-app
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'minitest/test_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ Minitest::TestTask.create
8
+ RuboCop::RakeTask.new
9
+
10
+ desc 'Run the test suite and gather code coverage'
11
+ task :coverage do
12
+ ENV['COVERAGE'] = '1'
13
+ Rake::Task['test'].invoke
14
+ end
15
+
16
+ task default: %i[test rubocop]
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org/>
Binary file
Binary file
data/img/mind-map.png ADDED
Binary file
Binary file
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Asset
5
+ include Mural::Codec
6
+
7
+ # https://developers.mural.co/public/reference/createasset
8
+ define_attributes(
9
+ name: 'name',
10
+ url: 'url',
11
+ headers: 'headers'
12
+ )
13
+
14
+ def self.decode(json)
15
+ super.tap do |asset_url|
16
+ asset_url.headers = Headers.decode(asset_url.headers)
17
+ end
18
+ end
19
+
20
+ class Headers
21
+ include Mural::Codec
22
+
23
+ define_attributes(blob_type: 'x-ms-blob-type')
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ module Authentication
6
+ def authorize_url
7
+ URI::HTTPS.build(
8
+ host: host,
9
+ path: '/api/public/v1/authorization/oauth2/',
10
+ query: URI.encode_www_form(authorize_query)
11
+ ).to_s
12
+ end
13
+
14
+ def request_token(code)
15
+ uri = URI::HTTPS.build(
16
+ host: host,
17
+ path: '/api/public/v1/authorization/oauth2/token'
18
+ )
19
+
20
+ res = Net::HTTP.post_form(uri, request_token_payload(code))
21
+ data = JSON.parse res.body
22
+
23
+ @access_token = data['access_token']
24
+ @refresh_token = data['refresh_token']
25
+
26
+ data
27
+ end
28
+
29
+ def refresh
30
+ uri = URI::HTTPS.build(
31
+ host: host,
32
+ path: '/api/public/v1/authorization/oauth2/token'
33
+ )
34
+
35
+ res = Net::HTTP.post_form(uri, refresh_token_payload)
36
+ json = JSON.parse res.body
37
+
38
+ @access_token = json['access_token']
39
+ @refresh_token = json['refresh_token']
40
+
41
+ nil
42
+ end
43
+
44
+ private
45
+
46
+ def authorize_query
47
+ {
48
+ client_id: client_id,
49
+ redirect_uri: redirect_uri,
50
+ scope: scope,
51
+ response_type: 'code'
52
+ }
53
+ end
54
+
55
+ def request_token_payload(code)
56
+ {
57
+ client_id: client_id,
58
+ client_secret: client_secret,
59
+ redirect_uri: redirect_uri,
60
+ code: code,
61
+ grant_type: 'authorization_code'
62
+ }
63
+ end
64
+
65
+ def refresh_token_payload
66
+ {
67
+ client_id: client_id,
68
+ client_secret: client_secret,
69
+ refresh_token: refresh_token,
70
+ grant_type: 'refresh_token'
71
+ }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class MuralContent
6
+ module Files
7
+ # https://developers.mural.co/public/reference/createfile
8
+ def create_file(mural_id, params)
9
+ json = post(
10
+ "/api/public/v1/murals/#{mural_id}/widgets/file",
11
+ params.encode
12
+ )
13
+
14
+ Mural::Widget::File.decode(json['value'])
15
+ end
16
+
17
+ # https://developers.mural.co/public/reference/getmuralfilewidgets
18
+ def list_files(mural_id, next_page: nil)
19
+ json = get(
20
+ "/api/public/v1/murals/#{mural_id}/widgets/files",
21
+ { next: next_page }
22
+ )
23
+
24
+ files = json['value'].map { |f| Mural::Widget::File.decode(f) }
25
+ [files, json['next']]
26
+ end
27
+
28
+ # https://developers.mural.co/public/reference/updatefile
29
+ def update_file(mural_id, widget_id:, update_file_params:)
30
+ json = patch(
31
+ "/api/public/v1/murals/#{mural_id}/widgets/file/#{widget_id}",
32
+ update_file_params.encode
33
+ )
34
+
35
+ Mural::Widget::File.decode(json['value'])
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class MuralContent
6
+ module StickyNotes
7
+ # https://developers.mural.co/public/reference/createstickynote
8
+ def create_sticky_notes(mural_id, create_sticky_note_params)
9
+ json = post(
10
+ "/api/public/v1/murals/#{mural_id}/widgets/sticky-note",
11
+ [*create_sticky_note_params].map(&:encode)
12
+ )
13
+
14
+ json['value'].map { |s| Mural::Widget::StickyNote.decode(s) }
15
+ end
16
+
17
+ # https://developers.mural.co/public/reference/updatestickynote
18
+ def update_sticky_note(mural_id, widget_id, update_sticky_note_params)
19
+ json = patch(
20
+ "/api/public/v1/murals/#{mural_id}/widgets/sticky-note" \
21
+ "/#{widget_id}",
22
+ update_sticky_note_params.encode
23
+ )
24
+
25
+ Mural::Widget::StickyNote.decode(json['value'])
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class MuralContent
6
+ module Tags
7
+ # https://developers.mural.co/public/reference/getmuraltags
8
+ def list_tags(mural_id)
9
+ json = get("/api/public/v1/murals/#{mural_id}/tags")
10
+
11
+ json['value'].map { |tag| Mural::Tag.decode(tag) }
12
+ end
13
+
14
+ # https://developers.mural.co/public/reference/gettagbyid
15
+ def retrieve_tag(mural_id, tag_id)
16
+ json = get("/api/public/v1/murals/#{mural_id}/tags/#{tag_id}")
17
+
18
+ Mural::Tag.decode(json['value'])
19
+ end
20
+
21
+ # https://developers.mural.co/public/reference/createmuraltag
22
+ def create_tag(mural_id, create_tag_params)
23
+ json = post(
24
+ "/api/public/v1/murals/#{mural_id}/tags",
25
+ create_tag_params.encode
26
+ )
27
+
28
+ Mural::Tag.decode(json['value'])
29
+ end
30
+
31
+ # https://developers.mural.co/public/reference/updatetagbyid
32
+ def update_tag(mural_id, tag_id, update_tag_params)
33
+ json = patch(
34
+ "/api/public/v1/murals/#{mural_id}/tags/#{tag_id}",
35
+ update_tag_params.encode
36
+ )
37
+
38
+ Mural::Tag.decode(json['value'])
39
+ end
40
+
41
+ # https://developers.mural.co/public/reference/deletetagbyid
42
+ def destroy_tag(mural_id, tag_id)
43
+ delete("/api/public/v1/murals/#{mural_id}/tags/#{tag_id}")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class MuralContent
6
+ module Widgets
7
+ # https://developers.mural.co/public/reference/getmuralwidgets
8
+ def list_widgets(mural_id, type: nil, parent_id: nil, next_page: nil)
9
+ json = get(
10
+ "/api/public/v1/murals/#{mural_id}/widgets",
11
+ { type: type, parentId: parent_id, next: next_page }
12
+ )
13
+
14
+ widgets = json['value'].map { |w| Mural::Widget.decode(w) }
15
+
16
+ [widgets, json['next']]
17
+ end
18
+
19
+ # https://developers.mural.co/public/reference/getmuralwidget
20
+ def retrieve_widget(mural_id, widget_id)
21
+ json = get("/api/public/v1/murals/#{mural_id}/widgets/#{widget_id}")
22
+
23
+ Mural::Widget.decode(json['value'])
24
+ end
25
+
26
+ # https://developers.mural.co/public/reference/deletewidgetbyid
27
+ def destroy_widget(mural_id, widget_id)
28
+ delete("/api/public/v1/murals/#{mural_id}/widgets/#{widget_id}")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class MuralContent
6
+ extend Forwardable
7
+
8
+ include Files
9
+ include StickyNotes
10
+ include Tags
11
+ include Widgets
12
+
13
+ def_delegators :@client, :get, :post, :patch, :delete
14
+
15
+ def initialize(client)
16
+ @client = client
17
+ end
18
+
19
+ # https://developers.mural.co/public/reference/createasset
20
+ def create_asset(mural_id, file_extension:, asset_type: nil)
21
+ json = post(
22
+ "/api/public/v1/murals/#{mural_id}/assets",
23
+ { assetType: asset_type, fileExtension: file_extension }
24
+ )
25
+
26
+ Mural::Asset.decode(json['value'])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mural
4
+ class Client
5
+ class Murals
6
+ extend Forwardable
7
+
8
+ def_delegators :@client, :get, :post, :patch, :delete
9
+
10
+ def initialize(client)
11
+ @client = client
12
+ end
13
+
14
+ # https://developers.mural.co/public/reference/getmuralbyid
15
+ def retrieve(mural_id)
16
+ json = get("/api/public/v1/murals/#{mural_id}")
17
+
18
+ ::Mural::MuralBoard.decode(json['value'])
19
+ end
20
+
21
+ # https://developers.mural.co/public/reference/createmural
22
+ def create(create_params)
23
+ json = post('/api/public/v1/murals', create_params.encode)
24
+
25
+ ::Mural::MuralBoard.decode(json['value'])
26
+ end
27
+
28
+ # https://developers.mural.co/public/reference/updatemuralbyid
29
+ def update(mural_id, update_params)
30
+ json = patch("/api/public/v1/murals/#{mural_id}", update_params.encode)
31
+
32
+ ::Mural::MuralBoard.decode(json['value'])
33
+ end
34
+
35
+ # https://developers.mural.co/public/reference/deletemuralbyid
36
+ def destroy(mural_id)
37
+ delete("/api/public/v1/murals/#{mural_id}")
38
+ end
39
+
40
+ # https://developers.mural.co/public/reference/exportmural
41
+ def export(mural_id, download_format: 'pdf')
42
+ json = post(
43
+ "/api/public/v1/murals/#{mural_id}/export",
44
+ { downloadFormat: download_format }
45
+ )
46
+
47
+ json.dig('value', 'exportId')
48
+ end
49
+
50
+ # https://developers.mural.co/public/reference/exporturlmural
51
+ def export_url(mural_id, export_id)
52
+ json = get("/api/public/v1/murals/#{mural_id}/exports/#{export_id}")
53
+
54
+ ::Mural::MuralExport.decode(json['value'])
55
+ end
56
+
57
+ # https://developers.mural.co/public/reference/duplicatemural
58
+ def duplicate(mural_id, duplicate_params)
59
+ json = post(
60
+ "/api/public/v1/murals/#{mural_id}/duplicate", duplicate_params.encode
61
+ )
62
+
63
+ ::Mural::MuralBoard.decode(json['value'])
64
+ end
65
+
66
+ # https://developers.mural.co/public/reference/getworkspacemurals
67
+ def for_workspace(workspace_id, status: nil, sort_by: nil, next_page: nil)
68
+ json = get(
69
+ "/api/public/v1/workspaces/#{workspace_id}/murals",
70
+ { status: status, sortBy: sort_by, next: next_page }
71
+ )
72
+
73
+ murals = json['value'].map do |json_mural|
74
+ ::Mural::MuralBoard.decode(json_mural)
75
+ end
76
+
77
+ [murals, json['next']]
78
+ end
79
+
80
+ # https://developers.mural.co/public/reference/getworkspacerecentmurals
81
+ def recently_opened_in_workspace(workspace_id, next_page: nil)
82
+ json = get(
83
+ "/api/public/v1/workspaces/#{workspace_id}/murals/recent",
84
+ { next: next_page }
85
+ )
86
+
87
+ murals = json['value'].map do |json_mural|
88
+ ::Mural::MuralBoard.decode(json_mural)
89
+ end
90
+
91
+ [murals, json['next']]
92
+ end
93
+
94
+ # https://developers.mural.co/public/reference/getroommurals
95
+ def for_room( # rubocop:disable Metrics/MethodLength
96
+ room_id,
97
+ folder_id: nil,
98
+ status: nil,
99
+ sort_by: nil,
100
+ next_page: nil
101
+ )
102
+ json = get(
103
+ "/api/public/v1/rooms/#{room_id}/murals",
104
+ {
105
+ folderId: folder_id,
106
+ status: status,
107
+ sortBy: sort_by,
108
+ next: next_page
109
+ }
110
+ )
111
+
112
+ murals = json['value'].map do |json_mural|
113
+ ::Mural::MuralBoard.decode(json_mural)
114
+ end
115
+
116
+ [murals, json['next']]
117
+ end
118
+
119
+ # https://developers.mural.co/public/reference/muralaccessinfo
120
+ def access_information(mural_id, mural_state:)
121
+ json = post(
122
+ "/api/public/v1/murals/#{mural_id}/access-info",
123
+ { muralState: mural_state }
124
+ )
125
+
126
+ ::Mural::MuralBoard::AccessInformation.decode(json['value'])
127
+ end
128
+
129
+ # https://developers.mural.co/public/reference/resetvisitorlink
130
+ def reset_visitor_link(mural_id)
131
+ json =
132
+ post("/api/public/v1/murals/#{mural_id}/visitor-settings/reset-link")
133
+
134
+ ::Mural::MuralBoard::VisitorsSettings.decode(json['value'])
135
+ end
136
+ end
137
+ end
138
+ end