package it.niedermann.nextcloud.deck.remote.api; import static it.niedermann.nextcloud.deck.exceptions.DeckException.Hint.CAPABILITIES_VERSION_NOT_PARSABLE; import static it.niedermann.nextcloud.deck.exceptions.TraceableException.makeTraceableIfFails; import android.graphics.Color; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import it.niedermann.android.util.ColorUtil; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.exceptions.DeckException; import it.niedermann.nextcloud.deck.model.AccessControl; import it.niedermann.nextcloud.deck.model.Attachment; import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Card; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.model.Stack; import it.niedermann.nextcloud.deck.model.User; import it.niedermann.nextcloud.deck.model.enums.ActivityType; import it.niedermann.nextcloud.deck.model.enums.EAttachmentType; import it.niedermann.nextcloud.deck.model.full.FullBoard; import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.model.full.FullStack; import it.niedermann.nextcloud.deck.model.ocs.Activity; import it.niedermann.nextcloud.deck.model.ocs.Capabilities; import it.niedermann.nextcloud.deck.model.ocs.Version; import it.niedermann.nextcloud.deck.model.ocs.comment.DeckComment; import it.niedermann.nextcloud.deck.model.ocs.comment.Mention; import it.niedermann.nextcloud.deck.model.ocs.comment.OcsComment; import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProject; import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectList; import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectResource; import it.niedermann.nextcloud.deck.model.ocs.user.GroupMemberUIDs; import it.niedermann.nextcloud.deck.model.ocs.user.OcsUser; import it.niedermann.nextcloud.deck.model.ocs.user.OcsUserList; public class JsonToEntityParser { @SuppressWarnings("unchecked") protected static T parseJsonObject(JsonObject obj, Class mType) { if (mType == FullBoard.class) { return (T) parseBoard(obj); } else if (mType == FullCard.class) { return (T) parseCard(obj); } else if (mType == FullStack.class) { return (T) parseStack(obj); } else if (mType == Label.class) { return (T) parseLabel(obj); } else if (mType == Activity.class) { return (T) parseActivity(obj); } else if (mType == Capabilities.class) { return (T) parseCapabilities(obj); } else if (mType == OcsUserList.class) { return (T) parseOcsUserList(obj); } else if (mType == OcsUser.class) { return (T) parseSingleOcsUser(obj); } else if (mType == Attachment.class) { return (T) parseAttachment(obj); } else if (mType == OcsComment.class) { return (T) parseOcsComment(obj); } else if (mType == GroupMemberUIDs.class) { return (T) parseGroupMemberUIDs(obj); } else if (mType == OcsProjectList.class) { return (T) parseOcsProjectList(obj); } throw new IllegalArgumentException("unregistered type: " + mType.getCanonicalName()); } private static GroupMemberUIDs parseGroupMemberUIDs(JsonObject obj) { DeckLog.verbose(obj); GroupMemberUIDs uids = new GroupMemberUIDs(); makeTraceableIfFails(() -> { JsonElement data = obj.get("ocs").getAsJsonObject().get("data"); if (!data.isJsonNull() && data.getAsJsonObject().has("users")) { JsonElement users = data.getAsJsonObject().get("users"); if (!users.isJsonNull() && users.isJsonArray()) { for (JsonElement userElement : users.getAsJsonArray()) { uids.add(userElement.getAsString()); } } } }, obj); return uids; } private static OcsUserList parseOcsUserList(JsonObject obj) { DeckLog.verbose(obj); OcsUserList ocsUserList = new OcsUserList(); makeTraceableIfFails(() -> { JsonElement data = obj.get("ocs").getAsJsonObject().get("data"); if (!data.isJsonNull() && data.getAsJsonObject().has("users")) { JsonElement users = data.getAsJsonObject().get("users"); if (!users.isJsonNull() && users.isJsonArray()) { for (JsonElement userElement : users.getAsJsonArray()) { JsonObject singleUserElement = userElement.getAsJsonObject(); OcsUser user = new OcsUser(); user.setDisplayName(singleUserElement.get("label").getAsString()); user.setId( singleUserElement.get("value").getAsJsonObject() .get("shareWith").getAsString() ); ocsUserList.addUser(user); } } } }, obj); return ocsUserList; } private static OcsUser parseSingleOcsUser(JsonObject obj) { DeckLog.verbose(obj); OcsUser ocsUser = new OcsUser(); makeTraceableIfFails(() -> { JsonElement data = obj.get("ocs").getAsJsonObject().get("data"); if (!data.isJsonNull()) { JsonObject user = data.getAsJsonObject(); if (user.has("id")) { ocsUser.setId(user.get("id").getAsString()); } if (user.has("displayname")) { ocsUser.setDisplayName(user.get("displayname").getAsString()); } } }, obj); return ocsUser; } private static OcsProjectList parseOcsProjectList(JsonObject obj) { DeckLog.verbose(obj); OcsProjectList projectList = new OcsProjectList(); makeTraceableIfFails(() -> { JsonElement data = obj.get("ocs").getAsJsonObject().get("data"); if (!data.isJsonNull() && data.isJsonArray()) { JsonArray projectJsonArray = data.getAsJsonArray(); for (JsonElement jsonArrayElement : projectJsonArray) { if (jsonArrayElement.isJsonObject()) { JsonObject jsonObject = jsonArrayElement.getAsJsonObject(); OcsProject project = new OcsProject(); project.setId(jsonObject.get("id").getAsLong()); project.setName(getNullAsEmptyString(jsonObject.get("name"))); project.setResources(new ArrayList<>()); JsonElement jsonResources = jsonObject.get("resources"); if (jsonResources != null && jsonResources.isJsonArray()) { JsonArray resourcesArray = jsonResources.getAsJsonArray(); for (JsonElement resourceElement : resourcesArray) { if (resourceElement.isJsonObject()) { OcsProjectResource resource = parseOcsProjectResource(resourceElement.getAsJsonObject()); resource.setProjectId(project.getId()); project.getResources().add(resource); } } } projectList.add(project); } } } }, obj); return projectList; } private static OcsProjectResource parseOcsProjectResource(JsonObject obj) { DeckLog.verbose(obj); OcsProjectResource resource = new OcsProjectResource(); makeTraceableIfFails(() -> { if (obj.has("id")) { String idString = obj.get("id").getAsString(); if (idString != null && idString.trim().length() > 0) { if (idString.matches("[0-9]+")) { resource.setId(Long.parseLong(idString.trim())); } else { resource.setIdString(idString); } } } if (obj.has("type")) { resource.setType(getNullAsEmptyString(obj.get("type"))); } if (obj.has("name")) { resource.setName(getNullAsEmptyString(obj.get("name"))); } if (obj.has("link")) { resource.setLink(getNullAsEmptyString(obj.get("link"))); } if (obj.has("iconUrl")) { resource.setIconUrl(getNullAsEmptyString(obj.get("iconUrl"))); } if (obj.has("path")) { resource.setPath(obj.get("path").getAsString()); } if (obj.has("mimetype")) { resource.setMimetype(obj.get("mimetype").getAsString()); } if (obj.has("preview-available")) { resource.setPreviewAvailable(obj.get("preview-available").getAsBoolean()); } else { resource.setPreviewAvailable(false); } }, obj); return resource; } private static OcsComment parseOcsComment(JsonObject obj) { DeckLog.verbose(obj); OcsComment comment = new OcsComment(); makeTraceableIfFails(() -> { JsonElement data = obj.get("ocs").getAsJsonObject().get("data"); if (data.isJsonArray()) { for (JsonElement deckComment : data.getAsJsonArray()) { comment.addComment(parseDeckComment(deckComment)); } } else { comment.addComment(parseDeckComment(data)); } }, obj); return comment; } private static DeckComment parseDeckComment(JsonElement data) { DeckLog.verbose(data); DeckComment deckComment = new DeckComment(); makeTraceableIfFails(() -> { JsonObject commentJson = data.getAsJsonObject(); deckComment.setId(commentJson.get("id").getAsLong()); deckComment.setObjectId(commentJson.get("objectId").getAsLong()); deckComment.setMessage(commentJson.get("message").getAsString()); deckComment.setActorId(commentJson.get("actorId").getAsString()); deckComment.setActorDisplayName(commentJson.get("actorDisplayName").getAsString()); deckComment.setActorType(commentJson.get("actorType").getAsString()); deckComment.setCreationDateTime(getTimestampFromString(commentJson.get("creationDateTime"))); if (commentJson.has("replyTo")) { JsonObject replyTo = commentJson.get("replyTo").getAsJsonObject(); deckComment.setParentId(replyTo.get("id").getAsLong()); } JsonElement mentions = commentJson.get("mentions"); if (mentions != null && mentions.isJsonArray()) { for (JsonElement mention : mentions.getAsJsonArray()) { deckComment.addMention(parseMention(mention)); } } }, data); return deckComment; } private static Mention parseMention(JsonElement mentionJson) { Mention mention = new Mention(); DeckLog.verbose(mentionJson); makeTraceableIfFails(() -> { JsonObject mentionObject = mentionJson.getAsJsonObject(); mention.setMentionId(mentionObject.get("mentionId").getAsString()); mention.setMentionType(mentionObject.get("mentionType").getAsString()); mention.setMentionDisplayName(mentionObject.get("mentionDisplayName").getAsString()); }, mentionJson); return mention; } protected static FullBoard parseBoard(JsonObject e) { FullBoard fullBoard = new FullBoard(); DeckLog.verbose(e); Board board = new Board(); makeTraceableIfFails(() -> { board.setTitle(getNullAsEmptyString(e.get("title"))); board.setColor(getNullAsEmptyString(e.get("color"))); board.setEtag(getNullAsNull(e.get("ETag"))); // bugfix inital sync missing archived flag boolean isArchived = false; if (e.has("archived")) { JsonElement archived = e.get("archived"); isArchived = !archived.isJsonNull() && archived.getAsBoolean(); } board.setArchived(isArchived); board.setLastModified(getTimestampFromLong(e.get("lastModified"))); board.setDeletedAt(getTimestampFromLong(e.get("deletedAt"))); board.setId(e.get("id").getAsLong()); fullBoard.setBoard(board); if (e.has("labels") && !e.get("labels").isJsonNull()) { JsonArray labelsJson = e.getAsJsonArray("labels"); List