BallotMessageDecoder.m 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2014-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "BallotMessageDecoder.h"
  21. #import "BallotManager.h"
  22. #import "BallotKeys.h"
  23. #ifdef DEBUG
  24. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  25. #else
  26. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  27. #endif
  28. @interface BallotMessageDecoder ()
  29. @property EntityManager *entityManager;
  30. @property BallotManager *ballotManager;
  31. @end
  32. @implementation BallotMessageDecoder
  33. + (instancetype)messageDecoder {
  34. BallotMessageDecoder *decoder = [[BallotMessageDecoder alloc] init];
  35. EntityManager *entityManager =[[EntityManager alloc] init];
  36. decoder.entityManager = entityManager;
  37. BallotManager *manager = [BallotManager ballotManagerWithEntityManager:entityManager];
  38. decoder.ballotManager = manager;
  39. return decoder;
  40. }
  41. - (BallotMessage *)decodeCreateBallotFromBox:(BoxBallotCreateMessage *)boxMessage forConversation:(Conversation *)conversation {
  42. return [self decodeBallotCreateMessage:boxMessage forConversation:conversation];
  43. }
  44. - (BallotMessage *)decodeCreateBallotFromGroupBox:(GroupBallotCreateMessage *)boxMessage forConversation:(Conversation *)conversation {
  45. return [self decodeBallotCreateMessage:boxMessage forConversation:conversation];
  46. }
  47. - (NSString *)decodeCreateBallotTitleFromBox:(BoxBallotCreateMessage *)boxMessage {
  48. NSError *error;
  49. NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:boxMessage.jsonData options:0 error:&error];
  50. if (json == nil) {
  51. DDLogError(@"Error parsing ballot json data %@, %@", error, [error userInfo]);
  52. return nil;
  53. }
  54. return [json objectForKey: JSON_KEY_TITLE];
  55. }
  56. - (NSNumber *)decodeNotificationCreateBallotStateFromBox:(BoxBallotCreateMessage *)boxMessage {
  57. NSData *jsonData;
  58. if ([boxMessage isKindOfClass:[BoxBallotCreateMessage class]]) {
  59. jsonData = ((BoxBallotCreateMessage *)boxMessage).jsonData;
  60. } else if ([boxMessage isKindOfClass:[GroupBallotCreateMessage class]]) {
  61. jsonData = ((GroupBallotCreateMessage *)boxMessage).jsonData;
  62. } else {
  63. DDLogError(@"Ballot decode: invalid message type");
  64. return nil;
  65. }
  66. NSError *error;
  67. NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
  68. return [json objectForKey: JSON_KEY_STATE];
  69. }
  70. - (BallotMessage *)decodeBallotCreateMessage:(AbstractMessage *)boxMessage forConversation:(Conversation *)conversation {
  71. NSData *ballotId;
  72. NSData *jsonData;
  73. if ([boxMessage isKindOfClass:[BoxBallotCreateMessage class]]) {
  74. ballotId = ((BoxBallotCreateMessage *)boxMessage).ballotId;
  75. jsonData = ((BoxBallotCreateMessage *)boxMessage).jsonData;
  76. } else if ([boxMessage isKindOfClass:[GroupBallotCreateMessage class]]) {
  77. ballotId = ((GroupBallotCreateMessage *)boxMessage).ballotId;
  78. jsonData = ((GroupBallotCreateMessage *)boxMessage).jsonData;
  79. } else {
  80. DDLogError(@"Ballot decode: invalid message type");
  81. return nil;
  82. }
  83. /* Create Message in DB */
  84. BallotMessage *message = [_entityManager.entityCreator ballotMessageFromBox:boxMessage];
  85. Ballot *ballot = [_entityManager.entityFetcher ballotForBallotId:ballotId];
  86. if (ballot != nil) {
  87. [self updateExistingBallot:ballot jsonData:jsonData];
  88. } else {
  89. ballot = [self createNewBallotWithId:ballotId creatorId:boxMessage.fromIdentity jsonData:jsonData];
  90. }
  91. // error parsing data
  92. if (ballot == nil) {
  93. if (message) {
  94. [[_entityManager entityDestroyer] deleteObjectWithObject:message];
  95. }
  96. return nil;
  97. }
  98. ballot.modifyDate = [NSDate date];
  99. ballot.conversation = conversation;
  100. message.ballot = ballot;
  101. return message;
  102. }
  103. - (BOOL)decodeVoteFromGroupBox:(GroupBallotVoteMessage *)boxMessage {
  104. return [self decodeVoteForIdentity:boxMessage.fromIdentity ballotId:boxMessage.ballotId jsonData:boxMessage.jsonChoiceData];
  105. }
  106. - (BOOL)decodeVoteFromBox:(BoxBallotVoteMessage *)boxMessage {
  107. return [self decodeVoteForIdentity:boxMessage.fromIdentity ballotId:boxMessage.ballotId jsonData:boxMessage.jsonChoiceData];
  108. }
  109. - (BOOL)decodeVoteForIdentity:(NSString *)contactId ballotId:(NSData *)ballotId jsonData:(NSData *)jsonData {
  110. Ballot *ballot = [_entityManager.entityFetcher ballotForBallotId:ballotId];
  111. if (ballot == nil) {
  112. DDLogError(@"no ballot found for vote");
  113. return NO;
  114. }
  115. if (ballot.isClosed) {
  116. DDLogError(@"ballot already closed");
  117. return NO;
  118. }
  119. ballot.modifyDate = [NSDate date];
  120. [ballot incrementUnreadUpdateCount];
  121. return [self parseJsonVoteData:jsonData forContact:contactId inBallot:ballot];
  122. }
  123. - (void)updateExistingBallot:(Ballot *)ballot jsonData:(NSData *)jsonData {
  124. ballot.modifyDate = [NSDate date];
  125. [ballot incrementUnreadUpdateCount];
  126. [self parseJsonCreateData:jsonData forBallot:ballot];
  127. }
  128. - (Ballot *)createNewBallotWithId:(NSData *)ballotId creatorId:(NSString *)creatorId jsonData:(NSData *)jsonData {
  129. Ballot *ballot = [_entityManager.entityCreator ballot];
  130. ballot.id = ballotId;
  131. ballot.creatorId = creatorId;
  132. ballot.createDate = [NSDate date];
  133. if ([self parseJsonCreateData:jsonData forBallot:ballot]) {
  134. return ballot;
  135. }
  136. // parse failed: remove the ballot we just created
  137. [[_entityManager entityDestroyer] deleteObjectWithObject:ballot];
  138. return nil;
  139. }
  140. - (BOOL)parseJsonVoteData:(NSData *)jsonData forContact:(NSString *)contactId inBallot:(Ballot *)ballot {
  141. NSError *error;
  142. NSArray *choiceArray = (NSArray *)[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
  143. if (choiceArray == nil) {
  144. DDLogError(@"Error parsing ballot vote data %@, %@", error, [error userInfo]);
  145. return NO;
  146. }
  147. for (NSArray *choice in choiceArray) {
  148. if ([choice count] != 2) {
  149. //ignore invalid entries
  150. continue;
  151. }
  152. NSNumber *choiceId = [choice objectAtIndex:0];
  153. NSNumber *value = [choice objectAtIndex:1];
  154. [_ballotManager updateBallot:ballot choiceId:choiceId withResult:value forContact:contactId];
  155. }
  156. return YES;
  157. }
  158. - (BOOL)parseJsonCreateData:(NSData *)jsonData forBallot:(Ballot *)ballot {
  159. NSError *error;
  160. NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
  161. if (json == nil) {
  162. DDLogError(@"Error parsing ballot json data %@, %@", error, [error userInfo]);
  163. return NO;
  164. }
  165. ballot.title = [json objectForKey: JSON_KEY_TITLE];
  166. ballot.type = [json objectForKey: JSON_KEY_TYPE];
  167. ballot.state = [json objectForKey: JSON_KEY_STATE];
  168. ballot.assessmentType = [json objectForKey: JSON_KEY_ASSESSMENT_TYPE];
  169. ballot.choicesType = [json objectForKey: JSON_KEY_CHOICES_TYPE];
  170. NSArray *choicesArray = [json objectForKey: JSON_KEY_CHOICES];
  171. NSArray *participantIds = [json objectForKey: JSON_KEY_PARTICIPANTS];
  172. NSMutableSet *choices = [NSMutableSet set];
  173. for (NSDictionary *choiceData in choicesArray) {
  174. BallotChoice *choice = [self handleChoiceData: choiceData participantIds: participantIds forBallot: ballot];
  175. [choices addObject: choice];
  176. }
  177. ballot.choices = choices;
  178. return YES;
  179. }
  180. - (BallotChoice *)handleChoiceData:(NSDictionary *)choiceData participantIds: (NSArray *) participantIds forBallot:(Ballot *)ballot {
  181. NSNumber *choiceId = [choiceData objectForKeyedSubscript: JSON_CHOICE_KEY_ID];
  182. BallotChoice *choice = [_entityManager.entityFetcher ballotChoiceForBallotId:ballot.id choiceId:choiceId];
  183. if (choice == nil) {
  184. choice = [_entityManager.entityCreator ballotChoice];
  185. choice.id = [choiceData objectForKeyedSubscript: JSON_CHOICE_KEY_ID];
  186. }
  187. choice.ballot = ballot;
  188. choice.name = [choiceData objectForKeyedSubscript: JSON_CHOICE_KEY_NAME];
  189. choice.orderPosition = [choiceData objectForKeyedSubscript: JSON_CHOICE_KEY_ORDER_POSITION];
  190. NSArray *choiceResult = [choiceData objectForKeyedSubscript: JSON_CHOICE_KEY_RESULT];
  191. if ([choiceResult count] != [participantIds count]) {
  192. DDLogError(@"Invalid ballot create message: choice result array count does not match participant array count");
  193. return choice;
  194. }
  195. NSInteger i=0;
  196. for (NSNumber *value in choiceResult) {
  197. NSString *contactId = [participantIds objectAtIndex: i];
  198. [_ballotManager updateBallot:ballot choiceId:choice.id withResult:value forContact:contactId];
  199. i++;
  200. }
  201. return choice;
  202. }
  203. @end