Documentation, improvements on validation, refactor

Validate get boad
change pattern of api params
Import only one board by api
Populate data from api
Update class diagram
Update documentation
Add return when success
Sort comments
Fix order of cards
Instructions of attachments

Signed-off-by: Vitor Mattos <vitor@php.rio>
This commit is contained in:
Vitor Mattos
2021-07-25 00:15:50 -03:00
committed by Julius Härtl
parent 202ea30090
commit e87c063076
9 changed files with 400 additions and 175 deletions

View File

@@ -9,11 +9,14 @@ Project management, time management or ideation, Deck makes it easier for you to
## Using Deck
Overall, Deck is easy to use. You can create boards, add users, share the Deck, work collaboratively and in real time.
1. [Create my first board](#1-create-my-first-board)
2. [Create stacks and cards](#2-create-stacks-and-cards)
3. [Handle cards options](#3-handle-cards-options)
4. [Archive old tasks](#4-archive-old-tasks)
5. [Manage your board](#5-manage-your-board)
- 1. [Create my first board](#1-create-my-first-board)
- 2. [Create stacks and cards](#2-create-stacks-and-cards)
- 3. [Handle cards options](#3-handle-cards-options)
- 4. [Archive old tasks](#4-archive-old-tasks)
- 5. [Manage your board](#5-manage-your-board)
- 6. [Import boards](#6-import-boards)
- [Trello JSON](#trello-json)
- [Trello API](#trello-api)
### 1. Create my first board
In this example, we're going to create a board and share it with an other nextcloud user.
@@ -69,6 +72,70 @@ The **sharing tab** allows you to add users or even groups to your boards.
**Deleted objects** allows you to return previously deleted stacks or cards.
The **Timeline** allows you to see everything that happened in your boards. Everything!
### 6. Import boards
Importing can be done using the API or the `occ` `deck:import` command.
It is possible to import from the following sources:
#### Trello JSON
Steps:
* Create the data file
* Access Trello
* go to the board you want to export
* Follow the steps in [Trello documentation](https://help.trello.com/article/747-exporting-data-from-trello-1) and export as JSON
* Create the configuration file
* Execute the import informing the import file path, data file and source as `Trello JSON`
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloJson-schema.json) for import `Trello JSON`
Example configuration file:
```json
{
"owner": "admin",
"color": "0800fd",
"uidRelation": {
"johndoe": "johndoe"
}
}
```
**Limitations**:
Importing from a JSON file imports up to 1000 actions. To find out how many actions the board to be imported has, identify how many actions the JSON has.
#### Trello API
Import using API is recommended for boards with more than 1000 actions.
Trello makes it possible to attach links to a card. Deck does not have this feature. Attachments and attachment links are added in a markdown table at the end of the description for every imported card that has attachments in Trello.
* Get the API Key and API Token [here](https://developer.atlassian.com/cloud/trello/guides/rest-api/api-introduction/#authentication-and-authorization)
* Get the ID of the board you want to import by making a request to:
https://api.trello.com/1/members/me/boards?key={yourKey}&token={yourToken}&fields=id,name
This ID you will use in the configuration file in the `board` property
* Create the configuration file
Create the configuration file respecting the [JSON Schema](https://github.com/nextcloud/deck/blob/master/lib/Service/fixtures/config-trelloApi-schema.json) for import `Trello JSON`
Example configuration file:
```json
{
"owner": "admin",
"color": "0800fd",
"api": {
"key": "0cc175b9c0f1b6a831c399e269772661",
"token": "92eb5ffee6ae2fec3ad71c777531578f4a8a08f09d37b73795649038408b5f33"
},
"board": "8277e0910d750195b4487976",
"uidRelation": {
"johndoe": "johndoe"
}
}
```
## Search
Deck provides a global search either through the unified search in the Nextcloud header or with the inline search next to the board controls.

View File

@@ -1,4 +1,4 @@
## Implement import
* Create a new class `lib/service/BoardImport<ImportName>Service.php` where `<ImportName>` is the name of the source system.
* Use the `lib/service/BoardImportTrelloService.php` class as inspiration
* Use the `lib/service/BoardImportTrelloJsonService.php` class as inspiration

View File

@@ -4,175 +4,211 @@
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="361pt" height="738pt"
viewBox="0.00 0.00 361.01 738.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 734)">
<svg width="464pt" height="830pt"
viewBox="0.00 0.00 463.51 830.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 826)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-734 357.012,-734 357.012,4 -4,4"/>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-826 459.512,-826 459.512,4 -4,4"/>
<!-- A0 -->
<g id="node1" class="node">
<title>A0</title>
<polygon fill="#fff8dc" stroke="#000000" points="165.909,-730 70.091,-730 70.091,-674 171.909,-674 171.909,-724 165.909,-730"/>
<polyline fill="none" stroke="#000000" points="165.909,-730 165.909,-724 "/>
<polyline fill="none" stroke="#000000" points="171.909,-724 165.909,-724 "/>
<text text-anchor="middle" x="121" y="-717" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Classes used on</text>
<text text-anchor="middle" x="121" y="-705" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">board import.</text>
<text text-anchor="middle" x="121" y="-693" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Methods just to</text>
<text text-anchor="middle" x="121" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">illustrate.</text>
<polygon fill="#fff8dc" stroke="#000000" points="177.409,-822 81.591,-822 81.591,-766 183.409,-766 183.409,-816 177.409,-822"/>
<polyline fill="none" stroke="#000000" points="177.409,-822 177.409,-816 "/>
<polyline fill="none" stroke="#000000" points="183.409,-816 177.409,-816 "/>
<text text-anchor="middle" x="132.5" y="-809" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Classes used on</text>
<text text-anchor="middle" x="132.5" y="-797" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">board import.</text>
<text text-anchor="middle" x="132.5" y="-785" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Methods just to</text>
<text text-anchor="middle" x="132.5" y="-773" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">illustrate.</text>
</g>
<!-- A1 -->
<g id="node2" class="node">
<title>A1</title>
<polygon fill="none" stroke="#000000" points="108.7773,-588 23.2227,-588 23.2227,-552 108.7773,-552 108.7773,-588"/>
<text text-anchor="middle" x="66" y="-567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ApiController</text>
<polygon fill="none" stroke="#000000" points="120.2773,-680 34.7227,-680 34.7227,-644 120.2773,-644 120.2773,-680"/>
<text text-anchor="middle" x="77.5" y="-659" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ApiController</text>
</g>
<!-- A2 -->
<g id="node3" class="node">
<title>A2</title>
<polygon fill="none" stroke="#000000" points="0,-422 0,-454 132,-454 132,-422 0,-422"/>
<text text-anchor="start" x="9.607" y="-435" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportApiController</text>
<polygon fill="none" stroke="#000000" points="0,-366 0,-422 132,-422 132,-366 0,-366"/>
<text text-anchor="start" x="45.8645" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="16.1335" y="-391" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+getAllowedSystems()</text>
<text text-anchor="start" x="20.0185" y="-379" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+getConfigSchema()</text>
<polygon fill="none" stroke="#000000" points="11.5,-514 11.5,-546 143.5,-546 143.5,-514 11.5,-514"/>
<text text-anchor="start" x="21.107" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportApiController</text>
<polygon fill="none" stroke="#000000" points="11.5,-458 11.5,-514 143.5,-514 143.5,-458 11.5,-458"/>
<text text-anchor="start" x="57.3645" y="-495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="27.6335" y="-483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+getAllowedSystems()</text>
<text text-anchor="start" x="31.5185" y="-471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+getConfigSchema()</text>
</g>
<!-- A1&#45;&gt;A2 -->
<g id="edge1" class="edge">
<title>A1&#45;&gt;A2</title>
<path fill="none" stroke="#000000" d="M66,-541.6693C66,-517.4424 66,-482.1663 66,-454.2238"/>
<polygon fill="#000000" stroke="#000000" points="66,-551.957 61.5001,-541.9569 66,-546.957 66.0001,-541.957 66.0001,-541.957 66.0001,-541.957 66,-546.957 70.5001,-541.957 66,-551.957 66,-551.957"/>
<path fill="none" stroke="#000000" d="M77.5,-633.6693C77.5,-609.4424 77.5,-574.1663 77.5,-546.2238"/>
<polygon fill="#000000" stroke="#000000" points="77.5,-643.957 73.0001,-633.9569 77.5,-638.957 77.5001,-633.957 77.5001,-633.957 77.5001,-633.957 77.5,-638.957 82.0001,-633.957 77.5,-643.957 77.5,-643.957"/>
</g>
<!-- A3 -->
<g id="node4" class="node">
<title>A3</title>
<polygon fill="none" stroke="#000000" points="92,-272 92,-304 200,-304 200,-272 92,-272"/>
<text text-anchor="start" x="101.828" y="-285" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportService</text>
<polygon fill="none" stroke="#000000" points="92,-192 92,-272 200,-272 200,-192 92,-192"/>
<text text-anchor="start" x="125.8645" y="-253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="118.9105" y="-241" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+bootstrap()</text>
<text text-anchor="start" x="105.857" y="-229" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+validateSystem()</text>
<text text-anchor="start" x="108.218" y="-217" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateConfig()</text>
<text text-anchor="start" x="112.107" y="-205" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateData()</text>
<polygon fill="none" stroke="#000000" points="103.5,-364 103.5,-396 211.5,-396 211.5,-364 103.5,-364"/>
<text text-anchor="start" x="113.328" y="-377" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportService</text>
<polygon fill="none" stroke="#000000" points="103.5,-284 103.5,-364 211.5,-364 211.5,-284 103.5,-284"/>
<text text-anchor="start" x="137.3645" y="-345" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="130.4105" y="-333" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+bootstrap()</text>
<text text-anchor="start" x="117.357" y="-321" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+validateSystem()</text>
<text text-anchor="start" x="119.718" y="-309" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateConfig()</text>
<text text-anchor="start" x="123.607" y="-297" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateData()</text>
</g>
<!-- A2&#45;&gt;A3 -->
<g id="edge2" class="edge">
<title>A2&#45;&gt;A3</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M87.8604,-365.7328C95.8577,-349.5382 105.0823,-330.8583 113.7939,-313.2174"/>
<polygon fill="#000000" stroke="#000000" points="118.2935,-304.1057 117.9004,-315.0646 116.0795,-308.5889 113.8656,-313.072 113.8656,-313.072 113.8656,-313.072 116.0795,-308.5889 109.8308,-311.0795 118.2935,-304.1057 118.2935,-304.1057"/>
<text text-anchor="middle" x="88.3076" y="-342.7378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M99.3604,-457.7328C107.3577,-441.5382 116.5823,-422.8583 125.2939,-405.2174"/>
<polygon fill="#000000" stroke="#000000" points="129.7935,-396.1057 129.4004,-407.0646 127.5795,-400.5889 125.3656,-405.072 125.3656,-405.072 125.3656,-405.072 127.5795,-400.5889 121.3308,-403.0795 129.7935,-396.1057 129.7935,-396.1057"/>
<text text-anchor="middle" x="99.8076" y="-434.7378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A7 -->
<g id="node8" class="node">
<title>A7</title>
<polygon fill="none" stroke="#000000" points="216.8384,-132 75.1616,-132 75.1616,-96 216.8384,-96 216.8384,-132"/>
<text text-anchor="middle" x="146" y="-111" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportTrelloService</text>
<polygon fill="none" stroke="#000000" points=".5,-196 .5,-228 147.5,-228 147.5,-196 .5,-196"/>
<text text-anchor="start" x="10.1075" y="-209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportTrelloApiService</text>
<polygon fill="none" stroke="#000000" points=".5,-164 .5,-196 147.5,-196 147.5,-164 .5,-164"/>
<text text-anchor="start" x="44.9655" y="-177" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+name:string</text>
</g>
<!-- A3&#45;&gt;A7 -->
<g id="edge6" class="edge">
<title>A3&#45;&gt;A7</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M139.3307,-191.9484C139.0775,-174.9176 139.4199,-156.9169 140.358,-142.5095"/>
<polygon fill="#000000" stroke="#000000" points="141.1915,-132.2681 144.8655,-142.6002 140.7859,-137.2516 140.3803,-142.2351 140.3803,-142.2351 140.3803,-142.2351 140.7859,-137.2516 135.8951,-141.87 141.1915,-132.2681 141.1915,-132.2681"/>
<text text-anchor="middle" x="130.6738" y="-170.919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="#fff8dc" stroke="#000000" points="317.7872,-270 218.2128,-270 218.2128,-226 323.7872,-226 323.7872,-264 317.7872,-270"/>
<polyline fill="none" stroke="#000000" points="317.7872,-270 317.7872,-264 "/>
<polyline fill="none" stroke="#000000" points="323.7872,-264 317.7872,-264 "/>
<text text-anchor="middle" x="271" y="-257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">validateSystem is</text>
<text text-anchor="middle" x="271" y="-245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">public because is</text>
<text text-anchor="middle" x="271" y="-233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">used on Api.</text>
</g>
<!-- A3&#45;&gt;A8 -->
<g id="edge8" class="edge">
<title>A3&#45;&gt;A8</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M200.1992,-248C206.1915,-248 212.1837,-248 218.176,-248"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="264.1131,-720 189.8869,-720 189.8869,-684 264.1131,-684 264.1131,-720"/>
<text text-anchor="middle" x="227" y="-699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Command</text>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="148,-592 148,-624 307,-624 307,-592 148,-592"/>
<text text-anchor="start" x="199.9955" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImport</text>
<polygon fill="none" stroke="#000000" points="148,-560 148,-592 307,-592 307,-560 148,-560"/>
<text text-anchor="start" x="157.907" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+boardImportCommandService</text>
<polygon fill="none" stroke="#000000" points="148,-516 148,-560 307,-560 307,-516 148,-516"/>
<text text-anchor="start" x="200.8305" y="-541" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#configure()</text>
<text text-anchor="start" x="177.76" y="-529" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#execute(input,output)</text>
</g>
<!-- A4&#45;&gt;A5 -->
<g id="edge3" class="edge">
<title>A4&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M227,-673.6356C227,-659.1554 227,-641.0451 227,-624.0324"/>
<polygon fill="#000000" stroke="#000000" points="227,-683.9227 222.5001,-673.9227 227,-678.9227 227.0001,-673.9227 227.0001,-673.9227 227.0001,-673.9227 227,-678.9227 231.5001,-673.9228 227,-683.9227 227,-683.9227"/>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="150,-434 150,-466 304,-466 304,-434 150,-434"/>
<text text-anchor="start" x="159.7715" y="-447" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportCommandService</text>
<polygon fill="none" stroke="#000000" points="150,-354 150,-434 304,-434 304,-354 150,-354"/>
<text text-anchor="start" x="199.9105" y="-415" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+bootstrap()</text>
<text text-anchor="start" x="206.8645" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="186.857" y="-391" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+validateSystem()</text>
<text text-anchor="start" x="189.218" y="-379" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateConfig()</text>
<text text-anchor="start" x="193.107" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateData()</text>
</g>
<!-- A5&#45;&gt;A6 -->
<g id="edge4" class="edge">
<title>A5&#45;&gt;A6</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M227,-515.8313C227,-503.0442 227,-489.2707 227,-476.0248"/>
<polygon fill="#000000" stroke="#000000" points="227,-466.0234 231.5001,-476.0234 227,-471.0234 227.0001,-476.0234 227.0001,-476.0234 227.0001,-476.0234 227,-471.0234 222.5001,-476.0235 227,-466.0234 227,-466.0234"/>
<text text-anchor="middle" x="218.5476" y="-494.7051" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A6&#45;&gt;A3 -->
<g id="edge5" class="edge">
<title>A6&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M198.8975,-353.7949C192.3634,-340.7268 185.3528,-326.7057 178.6417,-313.2834"/>
<polygon fill="#000000" stroke="#000000" points="174.0529,-304.1057 182.55,-311.0375 176.289,-308.5779 178.5251,-313.05 178.5251,-313.05 178.5251,-313.05 176.289,-308.5779 174.5001,-315.0625 174.0529,-304.1057 174.0529,-304.1057"/>
</g>
<!-- A7&#45;&gt;A3 -->
<g id="edge7" class="edge">
<title>A7&#45;&gt;A3</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M150.8085,-132.2681C152.1233,-145.2693 152.7703,-163.6033 152.7495,-181.8528"/>
<polygon fill="#000000" stroke="#000000" points="152.6693,-191.9484 148.249,-181.9129 152.7091,-186.9485 152.7489,-181.9487 152.7489,-181.9487 152.7489,-181.9487 152.7091,-186.9485 157.2487,-181.9845 152.6693,-191.9484 152.6693,-191.9484"/>
<text text-anchor="middle" x="160.8916" y="-146.5403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M118.1816,-283.9135C108.8174,-268.3662 99.2841,-251.7769 91.3901,-237.2456"/>
<polygon fill="#000000" stroke="#000000" points="86.4575,-228.0253 95.1426,-234.7202 88.8161,-232.4341 91.1747,-236.8429 91.1747,-236.8429 91.1747,-236.8429 88.8161,-232.4341 87.2068,-238.9656 86.4575,-228.0253 86.4575,-228.0253"/>
<text text-anchor="middle" x="101.613" y="-269.7117" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A9 -->
<g id="node10" class="node">
<title>A9</title>
<polygon fill="#fff8dc" stroke="#000000" points="347.024,-142 234.976,-142 234.976,-86 353.024,-86 353.024,-136 347.024,-142"/>
<polyline fill="none" stroke="#000000" points="347.024,-142 347.024,-136 "/>
<polyline fill="none" stroke="#000000" points="353.024,-136 347.024,-136 "/>
<text text-anchor="middle" x="294" y="-129" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">To create an import</text>
<text text-anchor="middle" x="294" y="-117" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">to another system,</text>
<text text-anchor="middle" x="294" y="-105" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create another class</text>
<text text-anchor="middle" x="294" y="-93" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">similar to this.</text>
<polygon fill="none" stroke="#000000" points="165.5,-202 165.5,-234 319.5,-234 319.5,-202 165.5,-202"/>
<text text-anchor="start" x="175.272" y="-215" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportTrelloJsonService</text>
<polygon fill="none" stroke="#000000" points="165.5,-158 165.5,-202 319.5,-202 319.5,-158 165.5,-158"/>
<text text-anchor="start" x="213.4655" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+name:string</text>
<text text-anchor="start" x="189.981" y="-171" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#needValidateData:true</text>
</g>
<!-- A7&#45;&gt;A9 -->
<!-- A3&#45;&gt;A9 -->
<g id="edge9" class="edge">
<title>A7&#45;&gt;A9</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M216.8203,-114C222.85,-114 228.8796,-114 234.9093,-114"/>
<title>A3&#45;&gt;A9</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M184.0053,-283.9135C191.7033,-270.4392 200.1928,-256.1822 208.2827,-243.1605"/>
<polygon fill="#000000" stroke="#000000" points="213.8049,-234.3677 212.2972,-245.2295 211.1456,-238.6019 208.4864,-242.8361 208.4864,-242.8361 208.4864,-242.8361 211.1456,-238.6019 204.6756,-240.4428 213.8049,-234.3677 213.8049,-234.3677"/>
<text text-anchor="middle" x="185.6959" y="-260.9851" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A10 -->
<g id="node11" class="node">
<title>A10</title>
<polygon fill="none" stroke="#000000" points="207.513,-36 84.487,-36 84.487,0 207.513,0 207.513,-36"/>
<text text-anchor="middle" x="146" y="-21" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;abstract&gt;&gt;</text>
<text text-anchor="middle" x="146" y="-9" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ABoardImportService</text>
<polygon fill="#fff8dc" stroke="#000000" points="329.2872,-362 229.7128,-362 229.7128,-318 335.2872,-318 335.2872,-356 329.2872,-362"/>
<polyline fill="none" stroke="#000000" points="329.2872,-362 329.2872,-356 "/>
<polyline fill="none" stroke="#000000" points="335.2872,-356 329.2872,-356 "/>
<text text-anchor="middle" x="282.5" y="-349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">validateSystem is</text>
<text text-anchor="middle" x="282.5" y="-337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">public because is</text>
<text text-anchor="middle" x="282.5" y="-325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">used on Api.</text>
</g>
<!-- A7&#45;&gt;A10 -->
<!-- A3&#45;&gt;A10 -->
<g id="edge11" class="edge">
<title>A3&#45;&gt;A10</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M211.6992,-340C217.6915,-340 223.6837,-340 229.676,-340"/>
</g>
<!-- A4 -->
<g id="node5" class="node">
<title>A4</title>
<polygon fill="none" stroke="#000000" points="275.6131,-812 201.3869,-812 201.3869,-776 275.6131,-776 275.6131,-812"/>
<text text-anchor="middle" x="238.5" y="-791" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Command</text>
</g>
<!-- A5 -->
<g id="node6" class="node">
<title>A5</title>
<polygon fill="none" stroke="#000000" points="159.5,-684 159.5,-716 318.5,-716 318.5,-684 159.5,-684"/>
<text text-anchor="start" x="211.4955" y="-697" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImport</text>
<polygon fill="none" stroke="#000000" points="159.5,-652 159.5,-684 318.5,-684 318.5,-652 159.5,-652"/>
<text text-anchor="start" x="169.407" y="-665" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+boardImportCommandService</text>
<polygon fill="none" stroke="#000000" points="159.5,-608 159.5,-652 318.5,-652 318.5,-608 159.5,-608"/>
<text text-anchor="start" x="212.3305" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#configure()</text>
<text text-anchor="start" x="189.26" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#execute(input,output)</text>
</g>
<!-- A4&#45;&gt;A5 -->
<g id="edge3" class="edge">
<title>A4&#45;&gt;A5</title>
<path fill="none" stroke="#000000" d="M238.5,-765.6356C238.5,-751.1554 238.5,-733.0451 238.5,-716.0324"/>
<polygon fill="#000000" stroke="#000000" points="238.5,-775.9227 234.0001,-765.9227 238.5,-770.9227 238.5001,-765.9227 238.5001,-765.9227 238.5001,-765.9227 238.5,-770.9227 243.0001,-765.9228 238.5,-775.9227 238.5,-775.9227"/>
</g>
<!-- A6 -->
<g id="node7" class="node">
<title>A6</title>
<polygon fill="none" stroke="#000000" points="161.5,-526 161.5,-558 315.5,-558 315.5,-526 161.5,-526"/>
<text text-anchor="start" x="171.2715" y="-539" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">BoardImportCommandService</text>
<polygon fill="none" stroke="#000000" points="161.5,-446 161.5,-526 315.5,-526 315.5,-446 161.5,-446"/>
<text text-anchor="start" x="211.4105" y="-507" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+bootstrap()</text>
<text text-anchor="start" x="218.3645" y="-495" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+import()</text>
<text text-anchor="start" x="198.357" y="-483" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+validateSystem()</text>
<text text-anchor="start" x="200.718" y="-471" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateConfig()</text>
<text text-anchor="start" x="204.607" y="-459" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#validateData()</text>
</g>
<!-- A5&#45;&gt;A6 -->
<g id="edge4" class="edge">
<title>A5&#45;&gt;A6</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M238.5,-607.8313C238.5,-595.0442 238.5,-581.2707 238.5,-568.0248"/>
<polygon fill="#000000" stroke="#000000" points="238.5,-558.0234 243.0001,-568.0234 238.5,-563.0234 238.5001,-568.0234 238.5001,-568.0234 238.5001,-568.0234 238.5,-563.0234 234.0001,-568.0235 238.5,-558.0234 238.5,-558.0234"/>
<text text-anchor="middle" x="230.0476" y="-586.7051" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A6&#45;&gt;A3 -->
<g id="edge5" class="edge">
<title>A6&#45;&gt;A3</title>
<path fill="none" stroke="#000000" d="M210.3975,-445.7949C203.8634,-432.7268 196.8528,-418.7057 190.1417,-405.2834"/>
<polygon fill="#000000" stroke="#000000" points="185.5529,-396.1057 194.05,-403.0375 187.789,-400.5779 190.0251,-405.05 190.0251,-405.05 190.0251,-405.05 187.789,-400.5779 186.0001,-407.0625 185.5529,-396.1057 185.5529,-396.1057"/>
</g>
<!-- A7&#45;&gt;A3 -->
<g id="edge7" class="edge">
<title>A7&#45;&gt;A3</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M97.9053,-228.0253C106.7908,-241.8914 116.9013,-258.6532 126.2689,-274.9373"/>
<polygon fill="#000000" stroke="#000000" points="131.3842,-283.9135 122.5232,-277.4533 128.9085,-279.5694 126.4329,-275.2253 126.4329,-275.2253 126.4329,-275.2253 128.9085,-279.5694 130.3426,-272.9972 131.3842,-283.9135 131.3842,-283.9135"/>
<text text-anchor="middle" x="114.768" y="-235.7794" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A8 -->
<g id="node9" class="node">
<title>A8</title>
<polygon fill="none" stroke="#000000" points="91.5,-64 91.5,-108 224.5,-108 224.5,-64 91.5,-64"/>
<text text-anchor="start" x="128.54" y="-89" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">&lt;&lt;abstract&gt;&gt;</text>
<text text-anchor="start" x="110.4935" y="-77" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ABoardImportService</text>
<polygon fill="none" stroke="#000000" points="91.5,-32 91.5,-64 224.5,-64 224.5,-32 91.5,-32"/>
<text text-anchor="start" x="103.536" y="-45" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">#needValidateData:false</text>
<polygon fill="none" stroke="#000000" points="91.5,0 91.5,-32 224.5,-32 224.5,0 91.5,0"/>
<text text-anchor="start" x="101.177" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">+needValidateData():bool</text>
</g>
<!-- A7&#45;&gt;A8 -->
<g id="edge8" class="edge">
<title>A7&#45;&gt;A8</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M92.5609,-163.778C100.7701,-149.9005 110.666,-133.1718 120.2304,-117.0034"/>
<polygon fill="none" stroke="#000000" points="123.418,-118.4891 125.497,-108.1003 117.3932,-114.9251 123.418,-118.4891"/>
<text text-anchor="middle" x="94.5148" y="-140.8737" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">implements</text>
</g>
<!-- A9&#45;&gt;A3 -->
<g id="edge10" class="edge">
<title>A7&#45;&gt;A10</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M146,-95.9431C146,-82.0862 146,-62.6861 146,-46.7075"/>
<polygon fill="none" stroke="#000000" points="149.5001,-46.3023 146,-36.3023 142.5001,-46.3023 149.5001,-46.3023"/>
<text text-anchor="middle" x="137.5476" y="-74.817" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">implements</text>
<title>A9&#45;&gt;A3</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M225.8999,-234.3677C219.0397,-246.9491 210.794,-261.2976 202.4241,-275.2765"/>
<polygon fill="#000000" stroke="#000000" points="197.2079,-283.9135 198.5256,-273.0271 199.7928,-279.6335 202.3777,-275.3535 202.3777,-275.3535 202.3777,-275.3535 199.7928,-279.6335 206.2297,-277.6799 197.2079,-283.9135 197.2079,-283.9135"/>
<text text-anchor="middle" x="224.5929" y="-251.325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">uses</text>
</g>
<!-- A9&#45;&gt;A8 -->
<g id="edge13" class="edge">
<title>A9&#45;&gt;A8</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M219.7216,-157.9466C212.1469,-145.2925 203.4984,-130.8444 195.1077,-116.827"/>
<polygon fill="none" stroke="#000000" points="198.0677,-114.9573 189.9285,-108.1747 192.0615,-118.5526 198.0677,-114.9573"/>
<text text-anchor="middle" x="203.1595" y="-143.7351" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">implements</text>
</g>
<!-- A11 -->
<g id="node12" class="node">
<title>A11</title>
<polygon fill="#fff8dc" stroke="#000000" points="449.524,-224 337.476,-224 337.476,-168 455.524,-168 455.524,-218 449.524,-224"/>
<polyline fill="none" stroke="#000000" points="449.524,-224 449.524,-218 "/>
<polyline fill="none" stroke="#000000" points="455.524,-218 449.524,-218 "/>
<text text-anchor="middle" x="396.5" y="-211" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">To create an import</text>
<text text-anchor="middle" x="396.5" y="-199" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">to another system,</text>
<text text-anchor="middle" x="396.5" y="-187" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create another class</text>
<text text-anchor="middle" x="396.5" y="-175" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">similar to this.</text>
</g>
<!-- A9&#45;&gt;A11 -->
<g id="edge12" class="edge">
<title>A9&#45;&gt;A11</title>
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M319.8008,-196C325.693,-196 331.5853,-196 337.4776,-196"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -5,13 +5,20 @@
// {generate:true}
[note: Classes used on board import. Methods just to illustrate. {bg:cornsilk}]
[ApiController]<-[BoardImportApiController|+import();+getAllowedSystems();+getConfigSchema()]
[BoardImportApiController]uses-.->[BoardImportService|+import();+bootstrap();+validateSystem();#validateConfig();#validateData();]
[Command]<-[BoardImport|+boardImportCommandService|#configure();#execute(input,output)]
[BoardImport]uses-.->[BoardImportCommandService|+bootstrap();+import();+validateSystem();#validateConfig();#validateData()]
[BoardImportCommandService]->[BoardImportService]
[BoardImportService]uses-.->[BoardImportTrelloService]
[BoardImportTrelloService]uses-.->[BoardImportService]
[BoardImportService]uses-.->[BoardImportTrelloApiService|+name:string]
[BoardImportTrelloApiService]uses-.->[BoardImportService]
[BoardImportTrelloApiService]implements-.-^[<<abstract>> ABoardImportService|#needValidateData:false|+needValidateData():bool]
[BoardImportService]uses-.->[BoardImportTrelloJsonService|+name:string;#needValidateData:true]
[BoardImportTrelloJsonService]uses-.->[BoardImportService]
[BoardImportService]-[note: validateSystem is public because is used on Api. {bg:cornsilk}]
[BoardImportTrelloService]-[note: To create an import to another system, create another class similar to this. {bg:cornsilk}]
[BoardImportTrelloService]implements-.-^[<<abstract>> ABoardImportService]
[BoardImportTrelloJsonService]-[note: To create an import to another system, create another class similar to this. {bg:cornsilk}]
[BoardImportTrelloJsonService]implements-.-^[<<abstract>> ABoardImportService]

View File

@@ -37,6 +37,7 @@ abstract class ABoardImportService {
public static $name = '';
/** @var BoardImportService */
private $boardImportService;
/** @var bool */
protected $needValidateData = true;
/** @var Stack[] */
protected $stacks = [];

View File

@@ -180,7 +180,7 @@ class BoardImportService {
$className = 'OCA\Deck\Service\\'.$matches['class'];
if (!class_exists($className)) {
/** @psalm-suppress UnresolvableInclude */
require_once $name;
require_once $className;
}
/** @psalm-suppress InvalidPropertyFetch */
$name = $className::$name;

View File

@@ -23,14 +23,11 @@
namespace OCA\Deck\Service;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use OCP\AppFramework\Http;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
class BoardImportTrelloApiService extends BoardImportTrelloJsonService {
/** @var string */
@@ -38,16 +35,17 @@ class BoardImportTrelloApiService extends BoardImportTrelloJsonService {
protected $needValidateData = false;
/** @var IClient */
private $httpClient;
/** @var ILogger */
/** @var LoggerInterface */
protected $logger;
/** @var string */
private $baseApiUrl = 'https://api.trello.com/1';
/** @var ?\stdClass[] */
private $boards;
public function __construct(
IUserManager $userManager,
IL10N $l10n,
ILogger $logger,
LoggerInterface $logger,
IClientService $httpClientService
) {
parent::__construct($userManager, $l10n);
@@ -56,44 +54,150 @@ class BoardImportTrelloApiService extends BoardImportTrelloJsonService {
}
public function bootstrap(): void {
$this->getBoards();
$this->populateBoard();
$this->populateMembers();
$this->populateLabels();
$this->populateLists();
$this->populateCheckLists();
$this->populateCards();
$this->populateActions();
parent::bootstrap();
}
private function getBoards() {
$boards = $this->doRequest('/members/me/boards');
private function populateActions(): void {
$data = $this->getImportService()->getData();
$data->actions = $this->doRequest(
'/boards/' . $data->id . '/actions',
[
'filter' => 'commentCard',
'fields=memberCreator,type,data,date',
'memberCreator_fields' => 'username',
'limit' => 1000
]
);
}
private function doRequest($path, $queryString = []) {
try {
private function populateCards(): void {
$data = $this->getImportService()->getData();
$data->cards = $this->doRequest(
'/boards/' . $data->id . '/cards',
[
'fields' => 'id,idMembers,dateLastActivity,closed,idChecklists,name,idList,pos,desc,due,labels',
'attachments' => true,
'attachment_fields' => 'name,url,date',
'limit' => 1000
]
);
}
private function populateCheckLists(): void {
$data = $this->getImportService()->getData();
$data->checklists = $this->doRequest(
'/boards/' . $data->id . '/checkLists',
[
'fields' => 'id,idCard,name',
'checkItem_fields' => 'id,state,name',
'limit' => 1000
]
);
}
private function populateLists(): void {
$data = $this->getImportService()->getData();
$data->lists = $this->doRequest(
'/boards/' . $data->id . '/lists',
[
'fields' => 'id,name,closed',
'limit' => 1000
]
);
}
private function populateLabels(): void {
$data = $this->getImportService()->getData();
$data->labels = $this->doRequest(
'/boards/' . $data->id . '/labels',
[
'fields' => 'id,color,name',
'limit' => 1000
]
);
}
private function populateMembers(): void {
$data = $this->getImportService()->getData();
$data->members = $this->doRequest(
'/boards/' . $data->id . '/members',
[
'fields' => 'username',
'limit' => 1000
]
);
}
private function populateBoard(): void {
$toImport = $this->getImportService()->getConfig('board');
$board = $this->doRequest(
'/boards/' . $toImport,
['fields' => 'id,name']
);
if ($board instanceof \stdClass) {
$this->getImportService()->setData($board);
return;
}
throw new \Exception('Invalid board id to import');
}
/**
* @return array|\stdClass
*/
private function doRequest(string $path = '', array $queryString = []) {
$target = $this->baseApiUrl . $path;
try {
$result = $this->httpClient
->get($target, $this->getQueryString($queryString))
->getBody();
if (is_string($result)) {
$data = json_decode($result);
} catch (ClientException $e) {
$status = $e->getCode();
if ($status === Http::STATUS_FORBIDDEN) {
$this->logger->info($target . ' refused.', ['app' => 'deck']);
} else {
$this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'deck']);
}
} catch (RequestException $e) {
$this->logger->logException($e, [
'message' => 'Could not connect to ' . $target,
'level' => ILogger::INFO,
'app' => 'deck',
]);
} catch (\Throwable $e) {
$this->logger->logException($e, ['app' => 'deck']);
if (is_array($data)) {
$data = array_merge(
$data,
$this->paginate($path, $queryString, $data)
);
}
return $data;
}
throw new \Exception('Invalid return of api');
} catch (\Throwable $e) {
$this->logger->critical(
$e->getMessage(),
['app' => 'deck']
);
throw new \Exception($e->getMessage());
}
}
private function getQueryString($params = []): array {
private function paginate(string $path = '', array $queryString = [], array $data = []): array {
if (empty($queryString['limit'])) {
return [];
}
if (count($data) < $queryString['limit']) {
return [];
}
$queryString['before'] = end($data)->id;
$return = $this->doRequest($path, $queryString);
if (is_array($return)) {
return $return;
}
throw new \Exception('Invalid return of api');
}
private function getQueryString(array $params = []): array {
$apiSettings = $this->getImportService()->getConfig('api');
$params['key'] = $apiSettings->key;
$params['value'] = $apiSettings->token;
return $params;
$params['token'] = $apiSettings->token;
return [
'query' => $params
];
}
}

View File

@@ -111,6 +111,7 @@ class BoardImportTrelloJsonService extends ABoardImportService {
return $c->id;
}, $values);
$trelloComments = array_combine($keys, $values);
$trelloComments = $this->sortComments($trelloComments);
foreach ($trelloComments as $commentId => $trelloComment) {
$comment = new Comment();
if (!empty($this->getImportService()->getConfig('uidRelation')->{$trelloComment->memberCreator->username})) {
@@ -131,6 +132,18 @@ class BoardImportTrelloJsonService extends ABoardImportService {
return $comments;
}
private function sortComments(array $comments): array {
$comparison = function($a, $b) {
if ($a->date == $b->date) {
return 0;
}
return ($a->date < $b->date) ? -1 : 1;
};
usort($comments, $comparison);
return $comments;
}
public function getCardLabelAssignment(): array {
$cardsLabels = [];
foreach ($this->getImportService()->getData()->cards as $trelloCard) {
@@ -221,7 +234,7 @@ class BoardImportTrelloJsonService extends ABoardImportService {
$cardsOnStack[] = $card;
$this->stacks[$trelloCard->idList]->setCards($cardsOnStack);
$card->setType('plain');
$card->setOrder($trelloCard->idShort);
$card->setOrder($trelloCard->pos);
$card->setOwner($this->getImportService()->getConfig('owner')->getUID());
$card->setDescription($trelloCard->desc);
if ($trelloCard->due) {

View File

@@ -6,20 +6,17 @@
"properties": {
"key": {
"type": "string",
"pattern": "^\\w{32}$"
"pattern": "^[0-9a-fA-F]{32}$"
},
"token": {
"type": "string",
"pattern": "^\\w{1,}$"
"pattern": "^[0-9a-fA-F]{64}$"
}
}
},
"boards": {
"type": "array",
"items": {
"board": {
"type": "string",
"pattern": "^\\w{1,}$"
}
},
"uidRelation": {
"type": "object",