private void IntegrationOnBoardChanged(object sender, BoardChangedEventArgs boardChangedEventArgs) { var sb = new StringBuilder(); if (boardChangedEventArgs.BoardStructureChanged) sb.AppendLine("Board structure changed."); if (boardChangedEventArgs.AddedCards.Any()) sb.AppendLine(string.Format("{0} card(s) were added.", boardChangedEventArgs.AddedCards.Count)); if (boardChangedEventArgs.UpdatedCards.Any()) sb.AppendLine(string.Format("{0} card(s) were updated.", boardChangedEventArgs.UpdatedCards.Count)); if (boardChangedEventArgs.MovedCards.Any()) sb.AppendLine(string.Format("{0} card(s) were moved.", boardChangedEventArgs.MovedCards.Count)); if (boardChangedEventArgs.BlockedCards.Any()) sb.AppendLine(string.Format("{0} card(s) were blocked.", boardChangedEventArgs.BlockedCards.Count)); ShowMessage(sb.ToString()); }
private CheckForUpdatesLoopResult SetupCheckForUpdatesLoop() { const int pulse = 1000; var pollingInterval = (long) _integrationSettings.CheckForUpdatesIntervalSeconds*1000; var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); do { if (!stopWatch.IsRunning) stopWatch.Restart(); if (ShouldContinue) { while (stopWatch.ElapsedMilliseconds < pollingInterval) { if (!ShouldContinue) return CheckForUpdatesLoopResult.Exit; Thread.Sleep(pulse); } } try { stopWatch.Stop(); //Now do the work var checkResults = _api.CheckForUpdates(_board.Id, _board.Version); if (checkResults == null) continue; OnBoardStatusChecked(new BoardStatusCheckedEventArgs {HasChanges = checkResults.HasUpdates}); if (!checkResults.HasUpdates) continue; try { _boardLock.EnterUpgradeableReadLock(); var boardChangedEventArgs = new BoardChangedEventArgs(); if (checkResults.Events.Any(x => x.RequiresBoardRefresh)) { boardChangedEventArgs.BoardWasReloaded = true; OnBoardChanged(boardChangedEventArgs); return CheckForUpdatesLoopResult.Continue; } //Now we need to spin through and update the board //and create the information to event foreach (var boardEvent in checkResults.Events) { try { switch (GetEventType(boardEvent.EventType)) { case EventType.CardCreation: var addCardEvent = CreateCardAddEvent(boardEvent, checkResults.AffectedLanes); if (addCardEvent != null) boardChangedEventArgs.AddedCards.Add(addCardEvent); break; case EventType.CardMove: var movedCardEvent = CreateCardMoveEvent(boardEvent, checkResults.AffectedLanes); if (movedCardEvent != null) boardChangedEventArgs.MovedCards.Add(movedCardEvent); break; case EventType.CardFieldsChanged: var changedFieldsEvent = CreateCardUpdateEvent(boardEvent, checkResults.AffectedLanes); if (changedFieldsEvent != null) boardChangedEventArgs.UpdatedCards.Add(changedFieldsEvent); break; case EventType.CardDeleted: boardChangedEventArgs.DeletedCards.Add(CreateCardDeletedEvent(boardEvent)); break; case EventType.CardBlocked: if (boardEvent.IsBlocked) boardChangedEventArgs.BlockedCards.Add(CreateCardBlockedEvent(boardEvent, checkResults.AffectedLanes)); else boardChangedEventArgs.UnBlockedCards.Add(CreateCardUnBlockedEvent(boardEvent, checkResults.AffectedLanes)); break; case EventType.UserAssignment: if (boardEvent.IsUnassigning) boardChangedEventArgs.UnAssignedUsers.Add(CreateCardUserUnAssignmentEvent(boardEvent, checkResults.AffectedLanes)); else boardChangedEventArgs.AssignedUsers.Add(CreateCardUserAssignmentEvent(boardEvent, checkResults.AffectedLanes)); break; case EventType.CommentPost: boardChangedEventArgs.PostedComments.Add(CreateCommentPostedEvent(boardEvent)); break; case EventType.WipOverride: boardChangedEventArgs.WipOverrides.Add(CreateWipOverrideEvent(boardEvent, checkResults.AffectedLanes)); break; case EventType.UserWipOverride: boardChangedEventArgs.UserWipOverrides.Add(CreateUserWipOverrideEvent(boardEvent)); break; case EventType.AttachmentChange: var attachmentEvent = CreateAttachmentEvent(boardEvent); if (attachmentEvent != null) boardChangedEventArgs.AttachmentChangedEvents.Add(attachmentEvent); break; case EventType.CardMoveToBoard: boardChangedEventArgs.CardMoveToBoardEvents.Add(CreateCardMoveToBoardEvent(boardEvent)); break; case EventType.CardMoveFromBoard: boardChangedEventArgs.CardMoveFromBoardEvents.Add(CreateCardMoveFromBoardEvent(boardEvent)); break; case EventType.BoardEdit: boardChangedEventArgs.BoardEditedEvents.Add(CreateBoardEditedEvent(boardEvent)); boardChangedEventArgs.BoardStructureChanged = true; break; case EventType.BoardCardTypesChanged: boardChangedEventArgs.BoardCardTypesChangedEvents.Add(new BoardCardTypesChangedEvent(boardEvent.EventDateTime)); boardChangedEventArgs.BoardStructureChanged = true; break; case EventType.BoardClassOfServiceChanged: boardChangedEventArgs.BoardClassOfServiceChangedEvents.Add( new BoardClassOfServiceChangedEvent(boardEvent.EventDateTime)); boardChangedEventArgs.BoardStructureChanged = true; break; case EventType.Unrecognized: //Console.Beep(); break; } } catch (Exception ex) { OnClientError(new ClientErrorEventArgs { Exception = ex, Message = "Error processing board change event. " + ex.Message }); } } OnBoardChanged(boardChangedEventArgs); _boardLock.EnterWriteLock(); try { //we need to check to see if there is a need to refresh the entire board //if so, we need to refresh the entire board and raise the board refreshed event if (!checkResults.RequiresRefesh()) { //since the board does not require a refresh, then just change the effected lanes ApplyBoardChanges(checkResults.CurrentBoardVersion, checkResults.AffectedLanes); } else { _board = checkResults.NewPayload; OnBoardRefresh(new BoardInfoRefreshedEventArgs {FromBoardChange = true}); } } catch (Exception ex) { OnClientError(new ClientErrorEventArgs { Exception = ex, Message = "Error applying board changes or raising board refresh." }); } finally { _boardLock.ExitWriteLock(); } } catch (Exception ex) { OnClientError(new ClientErrorEventArgs {Exception = ex, Message = "Error processing board events."}); } finally { _boardLock.ExitUpgradeableReadLock(); } } catch (Exception ex) { OnClientError(new ClientErrorEventArgs {Exception = ex, Message = "Error checking for board events."}); } } while (ShouldContinue); stopWatch.Stop(); return CheckForUpdatesLoopResult.Exit; }
public virtual void OnBoardChanged(BoardChangedEventArgs eventArgs) { var eventToRaise = BoardChanged; if (eventToRaise != null) eventToRaise(this, eventArgs); }
protected virtual void BoardUpdate(long boardId, BoardChangedEventArgs eventArgs, ILeanKitApi integration) { if (eventArgs.BoardStructureChanged) { Log.Debug(String.Format("Received BoardStructureChanged event for [{0}], reloading Configuration", boardId)); // TODO: Ideally this would be ReloadConfiguration(boardId); ReloadConfiguration(); } var boardConfig = Configuration.Mappings.FirstOrDefault(x => x.Identity.LeanKit == boardId); if (boardConfig == null) { Log.Debug(String.Format("Expected a configuration for board [{0}].", boardId)); return; } Log.Debug(String.Format("Received board changed event for board [{0}]", boardId)); // check for content change events if (!boardConfig.UpdateTargetItems) { Log.Info("Skipped target item update because 'UpdateTargetItems' is disabled."); } else { Log.Info("Checking for updated cards."); if (eventArgs.UpdatedCards.Any()) { var itemsUpdated = new List<string>(); foreach (var updatedCardEvent in eventArgs.UpdatedCards) { try { if (updatedCardEvent.UpdatedCard == null) throw new Exception("Updated card is null"); if (updatedCardEvent.OriginalCard == null) throw new Exception("Original card is null"); var card = updatedCardEvent.UpdatedCard; if (string.IsNullOrEmpty(card.ExternalCardID) && !string.IsNullOrEmpty(card.ExternalSystemUrl)) { // try to grab id from url var pos = card.ExternalSystemUrl.LastIndexOf('='); if (pos > 0) card.ExternalCardID = card.ExternalSystemUrl.Substring(pos + 1); } if (string.IsNullOrEmpty(card.ExternalCardID)) continue; // still invalid; skip this card if (card.Title != updatedCardEvent.OriginalCard.Title) itemsUpdated.Add("Title"); if (card.Description != updatedCardEvent.OriginalCard.Description) itemsUpdated.Add("Description"); if (card.Tags != updatedCardEvent.OriginalCard.Tags) itemsUpdated.Add("Tags"); if (card.Priority != updatedCardEvent.OriginalCard.Priority) itemsUpdated.Add("Priority"); if (card.DueDate != updatedCardEvent.OriginalCard.DueDate) itemsUpdated.Add("DueDate"); if (card.Size != updatedCardEvent.OriginalCard.Size) itemsUpdated.Add("Size"); if (card.IsBlocked != updatedCardEvent.OriginalCard.IsBlocked) itemsUpdated.Add("Blocked"); if (itemsUpdated.Count <= 0) continue; CardUpdated(card, itemsUpdated, boardConfig); } catch (Exception e) { var card = updatedCardEvent.UpdatedCard ?? updatedCardEvent.OriginalCard ?? new Card(); string.Format("Error processing blocked card, [{0}]: {1}", card.Id, e.Message).Error(e); } } } if (eventArgs.BlockedCards.Any()) { var itemsUpdated = new List<string>(); foreach (var cardBlockedEvent in eventArgs.BlockedCards) { try { var card = cardBlockedEvent.BlockedCard; if (string.IsNullOrEmpty(card.ExternalCardID) && !string.IsNullOrEmpty(card.ExternalSystemUrl)) { // try to grab id from url var pos = card.ExternalSystemUrl.LastIndexOf('='); if (pos > 0) card.ExternalCardID = card.ExternalSystemUrl.Substring(pos + 1); } if (string.IsNullOrEmpty(card.ExternalCardID)) continue; // still invalid; skip this card if (card.IsBlocked != cardBlockedEvent.BlockedCard.IsBlocked) itemsUpdated.Add("Blocked"); if (itemsUpdated.Count <= 0) continue; CardUpdated(card, itemsUpdated, boardConfig); } catch (Exception e) { var card = cardBlockedEvent.BlockedCard ?? new Card(); string.Format("Error processing blocked card, [{0}]: {1}", card.Id, e.Message).Error(e); } } } if (eventArgs.UnBlockedCards.Any()) { var itemsUpdated = new List<string>(); foreach (var cardUnblockedEvent in eventArgs.UnBlockedCards) { try { var card = cardUnblockedEvent.UnBlockedCard; if (string.IsNullOrEmpty(card.ExternalCardID) && !string.IsNullOrEmpty(card.ExternalSystemUrl)) { // try to grab id from url var pos = card.ExternalSystemUrl.LastIndexOf('='); if (pos > 0) card.ExternalCardID = card.ExternalSystemUrl.Substring(pos + 1); } if (string.IsNullOrEmpty(card.ExternalCardID)) continue; // still invalid; skip this card if (card.IsBlocked != cardUnblockedEvent.UnBlockedCard.IsBlocked) itemsUpdated.Add("Blocked"); if (itemsUpdated.Count <= 0) continue; CardUpdated(card, itemsUpdated, boardConfig); } catch (Exception e) { var card = cardUnblockedEvent.UnBlockedCard ?? new Card(); string.Format("Error processing unblocked card, [{0}]: {1}", card.Id, e.Message).Error(e); } } } } // check for content change events if (!boardConfig.CreateTargetItems) { Log.Info("Skipped checking for newly added cards because 'CreateTargetItems' is disabled."); } else { Log.Info("Checking for added cards."); if (eventArgs.AddedCards.Any()) { foreach (var newCard in eventArgs.AddedCards.Select(cardAddEvent => cardAddEvent.AddedCard) .Where(newCard => newCard != null && string.IsNullOrEmpty(newCard.ExternalCardID))) { try { CreateNewItem(newCard, boardConfig); } catch (Exception e) { string.Format("Error processing newly created card, [{0}]: {1}", newCard.Id, e.Message).Error(e); } } } } if (!boardConfig.UpdateTargetItems && !boardConfig.CreateTargetItems) { Log.Info("Skipped checking moved cards because 'UpdateTargetItems' and 'CreateTargetItems' are disabled."); UpdateBoardVersion(boardId); return; } if (eventArgs.MovedCards.Any()) { Log.Debug("Checking for cards moved to mapped lanes."); foreach (var movedCardEvent in eventArgs.MovedCards.Where(x => x != null && x.ToLane != null && x.MovedCard != null)) { try { if (!movedCardEvent.ToLane.Id.HasValue) continue; if (boardConfig.LaneToStatesMap.Any() && boardConfig.LaneToStatesMap.ContainsKey(movedCardEvent.ToLane.Id.Value)) { var states = boardConfig.LaneToStatesMap[movedCardEvent.ToLane.Id.Value]; if (states != null && states.Count > 0) { try { if (!string.IsNullOrEmpty(movedCardEvent.MovedCard.ExternalCardID) && boardConfig.UpdateTargetItems) { UpdateStateOfExternalItem(movedCardEvent.MovedCard, states, boardConfig); } else if (string.IsNullOrEmpty(movedCardEvent.MovedCard.ExternalCardID) && boardConfig.CreateTargetItems) { // This may be a task card being moved to the parent board, or card being moved from another board CreateNewItem(movedCardEvent.MovedCard, boardConfig); } } catch (Exception e) { Log.Error("Exception for UpdateStateOfExternalItem: " + e.Message); } } else Log.Debug(string.Format("No states are mapped to the Lane [{0}]", movedCardEvent.ToLane.Id.Value)); } else { Log.Debug(string.Format("No states are mapped to the Lane [{0}]", movedCardEvent.ToLane.Id.Value)); } } catch (Exception e) { string.Format("Error processing moved card, [{0}]: {1}", movedCardEvent.MovedCard.Id, e.Message).Error(e); } } } else { Log.Debug(string.Format("No Card Move Events detected event for board [{0}], exiting method", boardId)); } UpdateBoardVersion(boardId); }
public void SimulateUpdateEvent(long boardId, BoardChangedEventArgs eventArgs, ILeanKitApi api) { base.BoardUpdate(boardId, eventArgs, api); }
protected override void OnStartTest() { var api = LeanKitClientFactory.Create(new LeanKitBasicAuth()); var eventArgs = new BoardChangedEventArgs { UpdatedCards = new List<CardUpdateEvent> {CardUpdateEvent} }; TestItem.SimulateUpdateEvent(BoardId, eventArgs, api); }