diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..d25b9f1
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wrapper/src/main/java/wekan/wrapper/api/CardService.java b/wrapper/src/main/java/wekan/wrapper/api/CardService.java
new file mode 100644
index 0000000..19f5e96
--- /dev/null
+++ b/wrapper/src/main/java/wekan/wrapper/api/CardService.java
@@ -0,0 +1,74 @@
+package wekan.wrapper.api;
+
+import retrofit2.Call;
+import retrofit2.http.*;
+import wekan.wrapper.entity.Card;
+
+import java.util.List;
+
+public interface CardService {
+
+ /**
+ * Get all cards belonging to a list
+ *
+ * @param boardID The board ID of cards
+ * @param lidtID The list ID of cards
+ * @return list of cards in the list
+ */
+ @GET("/api/boards/{board}/lists/{list}/cards")
+ Call> getAllCards(@Path("board") String boardID, @Path("list") String lidtID);
+
+ /**
+ * Delete a card
+ *
+ * @param boardID The board ID of card
+ * @param listID The list ID of card
+ * @param cardID The card ID
+ * @return void
+ */
+ @DELETE("/api/boards/{board}/lists/{list}/cards/{card}")
+ Call deleteCard(@Path("board") String boardID, @Path("list") String listID, @Path("card") String cardID);
+
+ /**
+ *
+ * @param card new Card
+ * @param boardID The ID of the board destination
+ * @param listID The ID of the list destination
+ * @return the card with matching ID
+ */
+ @POST("/api/boards/{board}/lists/{list}/cards")
+ Call newCard(@Path("board") String boardID, @Path("list") String listID, @Body Card card);
+
+ /**
+ * Get information card
+ * @param boardID the ID of the board
+ * @param listID the ID of the list
+ * @param cardID the ID of the card
+ * @return card body
+ */
+ @GET("/api/boards/{board}/lists/{list}/cards/{card}")
+ Call getCard(@Path("board") String boardID, @Path("list") String listID, @Path("card") String cardID);
+
+ /**
+ * Get list of cards by swinlaneID
+ * @param boardID the ID of the board
+ * @param swimlaneID the ID of the swimlane
+ * @return list of swimlane cards
+ */
+ @GET("/api/boards/{board}/swimlanes/{swimlane}/cards")
+ Call> getCardsForswimlane(@Path("board") String boardID, @Path("swimlane") String swimlaneID);
+
+ /**
+ * Update a card
+ *
+ * @param card params to update
+ * @param boardID the id of the board
+ * @param listID the id of the list
+ * @param cardID the id of the card to modify
+ * @return The card with the matching ID
+ */
+ @Headers("Content-Type: application/merge-patch+json")
+ @PUT("/api/boards/{board}/lists/{list}/cards/{card}")
+ Call putCard(@Path("board") String boardID, @Path("list") String listID,
+ @Path("card") String cardID, @Body Card card);
+}
diff --git a/wrapper/src/main/java/wekan/wrapper/entity/Card.java b/wrapper/src/main/java/wekan/wrapper/entity/Card.java
new file mode 100644
index 0000000..14d7bde
--- /dev/null
+++ b/wrapper/src/main/java/wekan/wrapper/entity/Card.java
@@ -0,0 +1,328 @@
+package wekan.wrapper.entity;
+
+import com.google.gson.annotations.SerializedName;
+import java.util.Date;
+import java.util.List;
+
+public class Card {
+
+ //Constructor for add card
+ public Card(String authorId, String title, String swimlaneId, String description) {
+ this.authorId= authorId;
+ this.title = title;
+ this.swimlaneId = swimlaneId;
+ this.description = description;
+ }
+
+ public Card() {
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Boolean getArchived() {
+ return archived;
+ }
+
+ public void setArchived(Boolean archived) {
+ this.archived = archived;
+ }
+
+ public String getParentId() {
+ return parentId;
+ }
+
+ public void setParentId(String parentId) {
+ this.parentId = parentId;
+ }
+
+ public String getListId() {
+ return listId;
+ }
+
+ public void setListId(String listId) {
+ this.listId = listId;
+ }
+
+ public String getSwimlaneId() {
+ return swimlaneId;
+ }
+
+ public void setSwimlaneId(String swimlaneId) {
+ this.swimlaneId = swimlaneId;
+ }
+
+ public String getBoardId() {
+ return boardId;
+ }
+
+ public void setBoardId(String boardId) {
+ this.boardId = boardId;
+ }
+
+ public String getCoverId() {
+ return coverId;
+ }
+
+ public void setCoverId(String coverId) {
+ this.coverId = coverId;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ public void setColor(Color color) {
+ this.color = color;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getModifiedAt() {
+ return modifiedAt;
+ }
+
+ public void setModifiedAt(Date modifiedAt) {
+ this.modifiedAt = modifiedAt;
+ }
+
+ public List getCustomFields() {
+ return customFields;
+ }
+
+ public void setCustomFields(List customFields) {
+ this.customFields = customFields;
+ }
+
+ public Date getDateLastActivity() {
+ return dateLastActivity;
+ }
+
+ public void setDateLastActivity(Date dateLastActivity) {
+ this.dateLastActivity = dateLastActivity;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getRequestedBy() {
+ return requestedBy;
+ }
+
+ public void setRequestedBy(String requestedBy) {
+ this.requestedBy = requestedBy;
+ }
+
+ public String getAssignedBy() {
+ return assignedBy;
+ }
+
+ public void setAssignedBy(String assignedBy) {
+ this.assignedBy = assignedBy;
+ }
+
+ public List getLabelIds() {
+ return labelIds;
+ }
+
+ public void setLabelIds(List labelIds) {
+ this.labelIds = labelIds;
+ }
+
+ public List getMembers() {
+ return members;
+ }
+
+ public void setMembers(List members) {
+ this.members = members;
+ }
+
+ public List getAssignees() {
+ return assignees;
+ }
+
+ public void setAssignees(List assignees) {
+ this.assignees = assignees;
+ }
+
+ public Date getReceivedAt() {
+ return receivedAt;
+ }
+
+ public void setReceivedAt(Date receivedAt) {
+ this.receivedAt = receivedAt;
+ }
+
+ public Date getStartAt() {
+ return startAt;
+ }
+
+ public void setStartAt(Date startAt) {
+ this.startAt = startAt;
+ }
+
+ public Date getDueAt() {
+ return dueAt;
+ }
+
+ public void setDueAt(Date dueAt) {
+ this.dueAt = dueAt;
+ }
+
+ public Date getEndAt() {
+ return endAt;
+ }
+
+ public void setEndAt(Date endAt) {
+ this.endAt = endAt;
+ }
+
+ public int getSpentTime() {
+ return spentTime;
+ }
+
+ public void setSpentTime(int spentTime) {
+ this.spentTime = spentTime;
+ }
+
+ public Boolean getOvertime() {
+ return isOvertime;
+ }
+
+ public void setOvertime(Boolean overtime) {
+ isOvertime = overtime;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public int getSort() {
+ return sort;
+ }
+
+ public void setSort(int sort) {
+ this.sort = sort;
+ }
+
+ public int getSubtaskSort() {
+ return subtaskSort;
+ }
+
+ public void setSubtaskSort(int subtaskSort) {
+ this.subtaskSort = subtaskSort;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getLinkedId() {
+ return linkedId;
+ }
+
+ public void setLinkedId(String linkedId) {
+ this.linkedId = linkedId;
+ }
+
+ @Override
+ public String toString() {
+ return "Card{" +
+ "id='" + id + '\'' +
+ ", title='" + title + '\'' +
+ ", archived=" + archived +
+ ", parentId='" + parentId + '\'' +
+ ", listId='" + listId + '\'' +
+ ", swimlaneId='" + swimlaneId + '\'' +
+ ", boardId='" + boardId + '\'' +
+ ", coverId='" + coverId + '\'' +
+ ", color='" + color + '\'' +
+ ", createdAt=" + createdAt +
+ ", modifiedAt=" + modifiedAt +
+ ", customFields=" + customFields +
+ ", dateLastActivity=" + dateLastActivity +
+ ", description='" + description + '\'' +
+ ", requestedBy='" + requestedBy + '\'' +
+ ", assignedBy='" + assignedBy + '\'' +
+ ", labelIds=" + labelIds +
+ ", members=" + members +
+ ", assignees=" + assignees +
+ ", receivedAt='" + receivedAt + '\'' +
+ ", startAt='" + startAt + '\'' +
+ ", dueAt='" + dueAt + '\'' +
+ ", endAt='" + endAt + '\'' +
+ ", spentTime=" + spentTime +
+ ", isOvertime=" + isOvertime +
+ ", userId='" + userId + '\'' +
+ ", sort=" + sort +
+ ", subtaskSort=" + subtaskSort +
+ ", type='" + type + '\'' +
+ ", linkedId='" + linkedId + '\'' +
+ '}';
+ }
+
+ @SerializedName("_id")
+ private String id;
+ private String title;
+ private Boolean archived;
+ private String parentId;
+ private String listId;
+ private String swimlaneId;
+ private String boardId;
+ private String coverId;
+ private Color color;
+ private Date createdAt;
+ private Date modifiedAt;
+ private List customFields;
+ private Date dateLastActivity;
+ private String description;
+ private String requestedBy;
+ private String assignedBy;
+ private List labelIds;
+ private List members;
+ private List assignees;
+ private Date receivedAt;
+ private Date startAt;
+ private Date dueAt;
+ private Date endAt;
+ private int spentTime;
+ private Boolean isOvertime;
+ private String userId;
+ private int sort;
+ private int subtaskSort;
+ private String type;
+ private String linkedId;
+ private String authorId;
+}
diff --git a/wrapper/src/test/java/wekan/wrapper/api/CardServiceTest.java b/wrapper/src/test/java/wekan/wrapper/api/CardServiceTest.java
new file mode 100644
index 0000000..be4bbe0
--- /dev/null
+++ b/wrapper/src/test/java/wekan/wrapper/api/CardServiceTest.java
@@ -0,0 +1,192 @@
+package wekan.wrapper.api;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import wekan.wrapper.entity.Card;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class CardServiceTest {
+ private MockWebServer mockWebServer = new MockWebServer();
+ private CardService service = null;
+
+ @Before
+ public void setUp() {
+ try {
+ mockWebServer.start();
+ service = new Retrofit.Builder()
+ .baseUrl(mockWebServer.url(""))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(CardService.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @After
+ public void teardown() {
+ try {
+ mockWebServer.shutdown();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void getAllCardsTest(){
+ MockResponse response = new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setBody(
+ "[{\"_id\":\"J5a86fPe2DhqN3QbF0\",\"title\":\"card 0\",\"description\":\"proof 0\"}," +
+ "{\"_id\":\"J5a86fPe2DhqN3QbF1\",\"title\":\"card 1\",\"description\":\"proof 1\"}]"
+ );
+
+ mockWebServer.enqueue(response);
+
+ try {
+ List cards = service.getAllCards("oKthRbLqoXZr5NNua","iA6pmp6fENvF7AaTX").
+ execute().body();
+
+ assertNotNull(cards);
+ assertEquals("Numbero of card not ok",2, cards.size());
+
+ for (int i = 0; i < cards.size(); i++) {
+ assertEquals("J5a86fPe2DhqN3QbF" + i, cards.get(i).getId());
+ assertEquals("card " + i, cards.get(i).getTitle());
+ assertEquals("proof " + i, cards.get(i).getDescription());
+ }
+
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void getCardTest(){
+ MockResponse response = new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setBody(card);
+ try {
+ Card card = service.getCard(
+ "oKthRbLqoXZr5NNua","iA6pmp6fENvF7AaTX","J5a86fPe2DhqN3QbF")
+ .execute().body();
+ assertNotNull(card);
+ assertEquals("J5a86fPe2DhqN3QbF", card.getId() );
+ assertEquals("patch", card.getTitle());
+ assertEquals("iA6pmp6fENvF7AaTX", card.getListId());
+ assertEquals("2019-11-10T11:21:31.116Z", card.getCreatedAt().toString());
+
+ }catch (IOException e){
+ e.printStackTrace();
+ }
+ mockWebServer.enqueue(response);
+
+ }
+
+ @Test
+ public void newCardTest(){
+ MockResponse response = new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setBody(
+ "{\"_id\":\"FGgYsTzrwLJM8QT6W\"}"
+ );
+
+ mockWebServer.enqueue(response);
+
+ try {
+ Card card = service.newCard(
+ "oKthRbLqoXZr5NNua","iA6pmp6fENvF7AaTX",cardToAdd)
+ .execute().body();
+
+ assertNotNull(card);
+ assertEquals("FGgYsTzrwLJM8QT6W", card.getId());
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void getCardsForSwimlaneTest() throws IOException {
+ MockResponse response = new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setBody("[{\"_id\":\"J5a86fPe2DhqN3QbF0\",\"title\":\"card 0\",\"description\":\"proof\",\"listId\":\"iA6pmp6fENvF7AaTX0\"}," +
+ "{\"_id\":\"J5a86fPe2DhqN3QbF1\",\"title\":\"card 1\",\"description\":\"proof\",\"listId\":\"iA6pmp6fENvF7AaTX1\"}," +
+ "{\"_id\":\"J5a86fPe2DhqN3QbF2\",\"title\":\"card 2\",\"description\":\"proof\",\"listId\":\"iA6pmp6fENvF7AaTX2\"}]");
+
+ mockWebServer.enqueue(response);
+ List cards = service.getCardsForswimlane(
+ "oKthRbLqoXZr5NNua","ScwkAWCRW23duajxJ")
+ .execute().body();
+ assertNotNull(cards);
+ assertEquals(3, cards.size());
+ for(int i = 0; i < cards.size(); i++){
+ assertEquals("J5a86fPe2DhqN3QbF" + i, cards.get(i).getId());
+ assertEquals("card " + i, cards.get(i).getTitle());
+ assertEquals("iA6pmp6fENvF7AaTX" + i, cards.get(i).getListId());
+ assertEquals("proof", cards.get(i).getDescription());
+ }
+ }
+
+ @Test
+ public void updateCardTest() throws Exception {
+ MockResponse response = new MockResponse()
+ .setResponseCode(HttpURLConnection.HTTP_OK)
+ .setBody("{\"_id\":\"sig8KLcMcPTGx5GfF\"}");
+
+ mockWebServer.enqueue(response);
+ Card update = new Card();
+ update.setTitle("newTitle");
+
+ Card card = service.putCard("","","",update)
+ .execute().body();
+ assertNotNull(card);
+ assertEquals("sig8KLcMcPTGx5GfF", card.getId());
+
+ }
+
+ private static final String card =
+ "{"+
+ "\"_id\":\"J5a86fPe2DhqN3QbF\"," +
+ "\"title\":\"title1\","+
+ "\"boardId\":\"oKthRbLqoXZr5NNua\"," +
+ "\"listId\":\"iA6pmp6fENvF7AaTX\"," +
+ "\"description\":\"proof\"," +
+ "\"userId\":\"jPdkf3a9bmfZWx3GR\"," +
+ "\"swimlaneId\":\"ScwkAWCRW23duajxJ\"," +
+ "\"sort\":\"1\"," +
+ "\"members\":\"[]\"," +
+ "\"archived\":\"false\"," +
+ "\"parentId\":\"\"," +
+ "\"coverId\":\"\"," +
+ "\"createdAt\":\"2019-11-10T11:21:31.116Z\"," +
+ "\"modifiedAt\":\"2019-11-10T21:49:58.023Z\"," +
+ "\"customFields\":\"[]\"," +
+ "\"dateLastActivity\":\"2019-11-10T21:49:58.024Z\"," +
+ "\"requestedBy\":\"\"," +
+ "\"assignedBy\":\"\"," +
+ "\"labelIds\":\"[]\"," +
+ "\"assignees\":\"[]\"," +
+ "\"spentTime\":\"0\"," +
+ "\"isOvertime\":\"false\"," +
+ "\"subtaskSort\":\"-1\"," +
+ "\"type\":\"cardType-card\"," +
+ "\"linkedId\":\"" +
+ "}";
+
+ private static final Card cardToAdd = new Card(
+ "jPdkf3a9bmfZWx3GR","cardAdded","ScwkAWCRW23duajxJ",
+ "proof");
+}