@burgan-tech/morph-touch-runtime 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/burgan-tech-morph-touch-runtime-0.0.2.tgz +0 -0
- package/package.json +21 -0
- package/touch/Extensions/.gitkeep +0 -0
- package/touch/Functions/.gitkeep +0 -0
- package/touch/Functions/check-livekit-room-access.1.0.0.json +28 -0
- package/touch/Functions/check-livekit-room-access.http +44 -0
- package/touch/Functions/get-absence-entry.1.0.0.json +28 -0
- package/touch/Functions/get-advisor-stats.1.0.0.json +27 -0
- package/touch/Functions/get-available-slots.1.0.0.json +30 -0
- package/touch/Functions/get-available-slots.http +29 -0
- package/touch/Functions/get-chat-rooms.1.0.0.json +28 -0
- package/touch/Functions/get-chat-rooms.http +62 -0
- package/touch/Functions/get-customer-info.1.0.0.json +27 -0
- package/touch/Functions/get-matrix-sync.1.0.0.json +28 -0
- package/touch/Functions/get-rezervations.1.0.0.json +26 -0
- package/touch/Functions/get-rezervations.http +59 -0
- package/touch/Functions/get-room-messages.1.0.0.json +29 -0
- package/touch/Functions/get-room-messages.http +45 -0
- package/touch/Functions/rezervation-transfer.http +118 -0
- package/touch/Functions/send-room-message.1.0.0.json +29 -0
- package/touch/Functions/src/CheckLivekitRoomAccessMapping.csx +238 -0
- package/touch/Functions/src/GetAbsenceEntryMapping.csx +225 -0
- package/touch/Functions/src/GetAdvisorStatsMapping.csx +190 -0
- package/touch/Functions/src/GetAvailableSlotsMapping.csx +468 -0
- package/touch/Functions/src/GetChatRoomsMapping.csx +202 -0
- package/touch/Functions/src/GetCustomerInfoMapping.csx +140 -0
- package/touch/Functions/src/GetMatrixSyncMapping.csx +197 -0
- package/touch/Functions/src/GetRezervationsMapping.csx +162 -0
- package/touch/Functions/src/GetRoomMessagesMapping.csx +165 -0
- package/touch/Functions/src/SendCancelNotificationMapping.csx +63 -0
- package/touch/Functions/src/SendRoomMessageMapping.csx +131 -0
- package/touch/Schemas/.gitkeep +0 -0
- package/touch/Schemas/absence-entry.1.0.0.json +232 -0
- package/touch/Schemas/advisor-chat-rooms.1.0.0.json +62 -0
- package/touch/Schemas/chat-room.1.0.0.json +110 -0
- package/touch/Schemas/notification-sender.1.0.0.json +159 -0
- package/touch/Schemas/portfolio-manager.1.0.0.json +63 -0
- package/touch/Schemas/rezervation.1.0.0.json +102 -0
- package/touch/Tasks/.gitkeep +0 -0
- package/touch/Tasks/cancel-absence-entry-for-rezervation.1.0.0.json +21 -0
- package/touch/Tasks/check-already-completed-chat-room.1.0.0.json +24 -0
- package/touch/Tasks/check-duplicate-portfolio-manager.1.0.0.json +23 -0
- package/touch/Tasks/check-duplicate-rezervation.1.0.0.json +23 -0
- package/touch/Tasks/check-existing-permanent-chat-room.1.0.0.json +21 -0
- package/touch/Tasks/check-randevu-time.1.0.0.json +17 -0
- package/touch/Tasks/create-permanent-chat-room.1.0.0.json +28 -0
- package/touch/Tasks/determine-transfer-type.1.0.0.json +16 -0
- package/touch/Tasks/enrich-rezervations-for-transfer.1.0.0.json +23 -0
- package/touch/Tasks/execute-permanent-chatroom-update.1.0.0.json +21 -0
- package/touch/Tasks/execute-rez-chatroom-transfer.1.0.0.json +21 -0
- package/touch/Tasks/execute-rezervation-transfer.1.0.0.json +19 -0
- package/touch/Tasks/fetch-absence-entries-for-transfer.1.0.0.json +23 -0
- package/touch/Tasks/fetch-advisors-for-transfer.1.0.0.json +23 -0
- package/touch/Tasks/fetch-permanent-chatrooms-for-transfer.1.0.0.json +23 -0
- package/touch/Tasks/fetch-rez-chatrooms-for-transfer.1.0.0.json +23 -0
- package/touch/Tasks/fetch-rezervations-for-transfer.1.0.0.json +22 -0
- package/touch/Tasks/get-absence-entry-task.1.0.0.json +23 -0
- package/touch/Tasks/get-available-slots-http.1.0.0.json +27 -0
- package/touch/Tasks/get-available-slots.1.0.0.json +24 -0
- package/touch/Tasks/get-chat-room-data-for-rezervation.1.0.0.json +23 -0
- package/touch/Tasks/get-chat-token.1.0.0.json +27 -0
- package/touch/Tasks/get-matrix-room-messages.1.0.0.json +25 -0
- package/touch/Tasks/get-matrix-sync.1.0.0.json +25 -0
- package/touch/Tasks/get-rezervation-data-task.1.0.0.json +22 -0
- package/touch/Tasks/get-rezervation-state-task.1.0.0.json +22 -0
- package/touch/Tasks/get-rezervations-task.1.0.0.json +21 -0
- package/touch/Tasks/get-user-info-for-rezervation.1.0.0.json +24 -0
- package/touch/Tasks/get-video-call-url.1.0.0.json +17 -0
- package/touch/Tasks/invite-user-to-rezervation-room.1.0.0.json +27 -0
- package/touch/Tasks/join-chat-room-for-rezervation.1.0.0.json +28 -0
- package/touch/Tasks/join-matrix-room.1.0.0.json +27 -0
- package/touch/Tasks/join-user-to-room.1.0.0.json +27 -0
- package/touch/Tasks/merge-invited-user.1.0.0.json +17 -0
- package/touch/Tasks/merge-rezervation-update.1.0.0.json +16 -0
- package/touch/Tasks/merge-target-advisor-for-transfer.1.0.0.json +17 -0
- package/touch/Tasks/merge-update-body-for-randevu-update.1.0.0.json +16 -0
- package/touch/Tasks/merge-video-call-urls.1.0.0.json +17 -0
- package/touch/Tasks/query-chat-room-instances.1.0.0.json +23 -0
- package/touch/Tasks/remove-member-from-room.1.0.0.json +28 -0
- package/touch/Tasks/send-matrix-room-message.1.0.0.json +26 -0
- package/touch/Tasks/send-push-notification.1.0.0.json +26 -0
- package/touch/Tasks/send-sms-notification.1.0.0.json +26 -0
- package/touch/Tasks/set-chat-room-status-active.1.0.0.json +16 -0
- package/touch/Tasks/set-chat-room-status-deactive.1.0.0.json +16 -0
- package/touch/Tasks/set-previous-advisor.1.0.0.json +16 -0
- package/touch/Tasks/set-user-from-headers-for-rezervation.1.0.0.json +17 -0
- package/touch/Tasks/start-absence-entry-for-rezervation.1.0.0.json +21 -0
- package/touch/Tasks/start-chat-room-for-rezervation.1.0.0.json +20 -0
- package/touch/Tasks/start-notification-sender.1.0.0.json +20 -0
- package/touch/Tasks/start-permanent-chat-room.1.0.0.json +21 -0
- package/touch/Tasks/start-transfer-from-absence-entry.1.0.0.json +19 -0
- package/touch/Tasks/start-video-call.1.0.0.json +22 -0
- package/touch/Tasks/trigger-chat-room-deactivate.1.0.0.json +21 -0
- package/touch/Tasks/trigger-chat-room-transfer.1.0.0.json +21 -0
- package/touch/Tasks/trigger-chat-room-update.1.0.0.json +20 -0
- package/touch/Tasks/trigger-rezervation-add-invited-participant.1.0.0.json +20 -0
- package/touch/Tasks/trigger-rezervation-apply-update.1.0.0.json +20 -0
- package/touch/Tasks/trigger-rezervation-to-in-meet.1.0.0.json +20 -0
- package/touch/Tasks/trigger-rezervation-video-call-update.1.0.0.json +21 -0
- package/touch/Tasks/validate-date-for-rezervation.1.0.0.json +18 -0
- package/touch/Tasks/validate-slot-for-rezervation.1.0.0.json +24 -0
- package/touch/Tasks/validate-transfer-availability.1.0.0.json +23 -0
- package/touch/Views/.gitkeep +0 -0
- package/touch/Workflows/.gitkeep +0 -0
- package/touch/Workflows/absence-entry.http +458 -0
- package/touch/Workflows/absence-entry.json +179 -0
- package/touch/Workflows/add-participant-to-rezervation.http +47 -0
- package/touch/Workflows/add-participant-to-rezervation.json +340 -0
- package/touch/Workflows/chat-room.http +207 -0
- package/touch/Workflows/chat-room.json +452 -0
- package/touch/Workflows/investment-advisor.json +367 -0
- package/touch/Workflows/notification-sender.http +299 -0
- package/touch/Workflows/notification-sender.json +262 -0
- package/touch/Workflows/portfolio-manager.json +367 -0
- package/touch/Workflows/randevu-update.http +87 -0
- package/touch/Workflows/rezervation-start.json +467 -0
- package/touch/Workflows/rezervation-transfer.json +512 -0
- package/touch/Workflows/rezervation-update.http +87 -0
- package/touch/Workflows/rezervation-update.json +485 -0
- package/touch/Workflows/rezervation.http +214 -0
- package/touch/Workflows/rezervation.json +726 -0
- package/touch/Workflows/src/AllChatRoomsSuccessRule.csx +65 -0
- package/touch/Workflows/src/AlwaysTrueRule.csx +13 -0
- package/touch/Workflows/src/AnyChatRoomFailedRule.csx +64 -0
- package/touch/Workflows/src/AutoProcessRule.csx +38 -0
- package/touch/Workflows/src/BuildRezChatRoomPlanMapping.csx +160 -0
- package/touch/Workflows/src/CanStartRezervationTimerMapping.csx +48 -0
- package/touch/Workflows/src/CanStartTransferMapping.csx +14 -0
- package/touch/Workflows/src/CancelAbsenceEntryForRezervationMapping.csx +48 -0
- package/touch/Workflows/src/CancelAbsenceForRandevuUpdateMapping.csx +62 -0
- package/touch/Workflows/src/ChatRoomCreatedFailedRule.csx +54 -0
- package/touch/Workflows/src/ChatRoomCreatedSuccessRule.csx +54 -0
- package/touch/Workflows/src/ChatRoomRemoveMapping.csx +104 -0
- package/touch/Workflows/src/ChatRoomTransferInviteMapping.csx +109 -0
- package/touch/Workflows/src/ChatRoomTransferRemoveMapping.csx +71 -0
- package/touch/Workflows/src/ChatRoomUpdateMapping.csx +107 -0
- package/touch/Workflows/src/CheckAlreadyCompletedChatRoomMapping.csx +100 -0
- package/touch/Workflows/src/CheckDuplicatePortfolioManagerMapping.csx +119 -0
- package/touch/Workflows/src/CheckDuplicateRezervationMapping.csx +150 -0
- package/touch/Workflows/src/CheckExistingPermanentChatRoomMapping.csx +169 -0
- package/touch/Workflows/src/CheckRandevuTimeMapping.csx +67 -0
- package/touch/Workflows/src/CheckRezervationStateActiveOrInMeetRule.csx +14 -0
- package/touch/Workflows/src/CreateAbsenceEntryForRezervationMapping.csx +111 -0
- package/touch/Workflows/src/CreateAbsenceForRandevuUpdateMapping.csx +108 -0
- package/touch/Workflows/src/CreateChatRoomForRezervationMapping.csx +122 -0
- package/touch/Workflows/src/CreatePermanentChatRoomMapping.csx +140 -0
- package/touch/Workflows/src/CustomerControlToEndRule.csx +14 -0
- package/touch/Workflows/src/DetermineTransferTypeMapping.csx +92 -0
- package/touch/Workflows/src/EnrichRezervationsForTransferMapping.csx +495 -0
- package/touch/Workflows/src/ExecutePermanentChatRoomUpdateMapping.csx +124 -0
- package/touch/Workflows/src/ExecuteRezChatRoomTransferMapping.csx +95 -0
- package/touch/Workflows/src/ExecuteTransferMapping.csx +152 -0
- package/touch/Workflows/src/FetchAbsenceEntriesForTransferMapping.csx +116 -0
- package/touch/Workflows/src/FetchAdvisorsForTransferMapping.csx +145 -0
- package/touch/Workflows/src/FetchPermanentChatRoomsMapping.csx +128 -0
- package/touch/Workflows/src/FetchRezervationsForTransferMapping.csx +124 -0
- package/touch/Workflows/src/GetChatRoomDataForRezervationMapping.csx +100 -0
- package/touch/Workflows/src/GetChatTokenMapping.csx +85 -0
- package/touch/Workflows/src/GetRezervationDataForAddParticipantMapping.csx +105 -0
- package/touch/Workflows/src/GetRezervationDataForRandevuUpdateMapping.csx +110 -0
- package/touch/Workflows/src/GetRezervationDataMapping.csx +111 -0
- package/touch/Workflows/src/GetRezervationStateForRandevuUpdateMapping.csx +80 -0
- package/touch/Workflows/src/GetRezervationStateMapping.csx +92 -0
- package/touch/Workflows/src/GetUserInfoForRezervationMapping.csx +63 -0
- package/touch/Workflows/src/GetVideoCallUrlMapping.csx +62 -0
- package/touch/Workflows/src/HasChangedAdvisorRule.csx +28 -0
- package/touch/Workflows/src/HasChatIntegrationRule.csx +41 -0
- package/touch/Workflows/src/HasExistingPermanentRoomRule.csx +28 -0
- package/touch/Workflows/src/InviteAdvisorForRandevuUpdateMapping.csx +86 -0
- package/touch/Workflows/src/InviteNewAdvisorToRezervationRoomMapping.csx +78 -0
- package/touch/Workflows/src/InviteNewParticipantToRandevuRoomMapping.csx +88 -0
- package/touch/Workflows/src/InvitedUserMergeMapping.csx +77 -0
- package/touch/Workflows/src/InvitedUserNotAllowedRule.csx +71 -0
- package/touch/Workflows/src/InvitedUserNotInMeetRule.csx +19 -0
- package/touch/Workflows/src/IsNotfSentRule.csx +36 -0
- package/touch/Workflows/src/JoinChatRoomForAddParticipantMapping.csx +118 -0
- package/touch/Workflows/src/JoinChatRoomForRandevuStartMapping.csx +119 -0
- package/touch/Workflows/src/JoinChatRoomForRezervationMapping.csx +118 -0
- package/touch/Workflows/src/JoinMatrixRoomMapping.csx +100 -0
- package/touch/Workflows/src/JoinUserToRoomMapping.csx +118 -0
- package/touch/Workflows/src/LoginForAddParticipantChatMapping.csx +102 -0
- package/touch/Workflows/src/LoginForRandevuStartChatMapping.csx +96 -0
- package/touch/Workflows/src/MergeRezervationUpdateMapping.csx +82 -0
- package/touch/Workflows/src/MergeTargetAdvisorForTransferMapping.csx +79 -0
- package/touch/Workflows/src/MergeUpdateBodyForRandevuUpdateMapping.csx +91 -0
- package/touch/Workflows/src/NoExistingPermanentRoomRule.csx +23 -0
- package/touch/Workflows/src/NotificationCompleteAlwaysRule.csx +14 -0
- package/touch/Workflows/src/NotificationCompleteFromPendingRule.csx +41 -0
- package/touch/Workflows/src/NotificationCompleteFromSmsRule.csx +36 -0
- package/touch/Workflows/src/NotificationPushFromPendingRule.csx +42 -0
- package/touch/Workflows/src/NotificationPushFromSmsRule.csx +36 -0
- package/touch/Workflows/src/NotificationSmsPendingRule.csx +32 -0
- package/touch/Workflows/src/PermanentDoneRule.csx +44 -0
- package/touch/Workflows/src/PermanentProcessNextRule.csx +44 -0
- package/touch/Workflows/src/RezChatRoomProcessNextRule.csx +44 -0
- package/touch/Workflows/src/RezChatRoomsDoneRule.csx +44 -0
- package/touch/Workflows/src/SendPushNotificationMapping.csx +146 -0
- package/touch/Workflows/src/SendSmsNotificationMapping.csx +138 -0
- package/touch/Workflows/src/SetChatRoomStatusActiveMapping.csx +22 -0
- package/touch/Workflows/src/SetChatRoomStatusDeactiveMapping.csx +22 -0
- package/touch/Workflows/src/SetPreviousAdvisorMapping.csx +28 -0
- package/touch/Workflows/src/SetUserFromHeadersForRezervationMapping.csx +24 -0
- package/touch/Workflows/src/SlotAvailableRule.csx +33 -0
- package/touch/Workflows/src/SlotUnavailableRule.csx +33 -0
- package/touch/Workflows/src/StartChatRoomForRezervationMapping.csx +100 -0
- package/touch/Workflows/src/StartGetChatTokenForRezervationMapping.csx +71 -0
- package/touch/Workflows/src/StartNotificationForAdvisorMapping.csx +117 -0
- package/touch/Workflows/src/StartNotificationForRezervationFromUserInfoMapping.csx +128 -0
- package/touch/Workflows/src/StartNotificationForUserMapping.csx +117 -0
- package/touch/Workflows/src/StartPermanentChatRoomMapping.csx +92 -0
- package/touch/Workflows/src/StartTransferFromAbsenceEntryMapping.csx +94 -0
- package/touch/Workflows/src/StartVideoCallCustomerSubFlowMapping.csx +37 -0
- package/touch/Workflows/src/StartVideoCallForInvitedParticipantMapping.csx +54 -0
- package/touch/Workflows/src/StartVideoCallForRandevuStartMapping.csx +70 -0
- package/touch/Workflows/src/StartVideoCallStaffSubFlowMapping.csx +37 -0
- package/touch/Workflows/src/StateActiveForUpdateRule.csx +14 -0
- package/touch/Workflows/src/StateActiveRule.csx +14 -0
- package/touch/Workflows/src/StateInMeetRule.csx +14 -0
- package/touch/Workflows/src/StateNotActiveForUpdateRule.csx +14 -0
- package/touch/Workflows/src/StateNotActiveOrInMeetRule.csx +14 -0
- package/touch/Workflows/src/StatusCustomerEnterRule.csx +25 -0
- package/touch/Workflows/src/StatusStaffEnterRule.csx +25 -0
- package/touch/Workflows/src/SyncWorkingHoursRule.csx +46 -0
- package/touch/Workflows/src/TokenSuccessRule.csx +24 -0
- package/touch/Workflows/src/TransferAllDoneRule.csx +50 -0
- package/touch/Workflows/src/TransferHasInvalidRule.csx +34 -0
- package/touch/Workflows/src/TransferProcessNextRule.csx +50 -0
- package/touch/Workflows/src/TriggerChatRoomDeactivateMapping.csx +77 -0
- package/touch/Workflows/src/TriggerChatRoomTransferMapping.csx +93 -0
- package/touch/Workflows/src/TriggerChatRoomUpdateMapping.csx +99 -0
- package/touch/Workflows/src/TriggerRezervationAddInvitedParticipantMapping.csx +77 -0
- package/touch/Workflows/src/TriggerRezervationApplyUpdateMapping.csx +66 -0
- package/touch/Workflows/src/TriggerRezervationToInMeetMapping.csx +69 -0
- package/touch/Workflows/src/TriggerRezervationVideoCallUpdateMapping.csx +67 -0
- package/touch/Workflows/src/ValidateDateForRezervationMapping.csx +60 -0
- package/touch/Workflows/src/ValidateSlotForRandevuUpdateMapping.csx +211 -0
- package/touch/Workflows/src/ValidateSlotForRezervationMapping.csx +246 -0
- package/touch/Workflows/src/ValidateTransferMapping.csx +243 -0
- package/touch/Workflows/src/VideoCallUrlUpdateMergeMapping.csx +141 -0
- package/touch/Workflows/start-chat.json +217 -0
- package/touch/Workflows/start-video-call.http +93 -0
- package/touch/Workflows/start-video-call.json +206 -0
- package/vnext.config.json +58 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Linq;
|
|
4
|
+
using System.Threading.Tasks;
|
|
5
|
+
using BBT.Workflow.Scripting;
|
|
6
|
+
using BBT.Workflow.Definitions;
|
|
7
|
+
/// <summary>
|
|
8
|
+
/// Mapping for GetAvailableSlotsTask (DaprServiceTask - Type 3)
|
|
9
|
+
/// Queries absence-entry workflow (state: complete) via Dapr service invocation to get
|
|
10
|
+
/// public holidays, working hours changes, and personal leaves.
|
|
11
|
+
/// Then calculates available appointment slots for the given advisor and date.
|
|
12
|
+
///
|
|
13
|
+
/// Working hours priority: advisor-specific > company-wide (advisor=null) > no hours
|
|
14
|
+
/// Half-day public holidays only block the holiday hours, not the entire day.
|
|
15
|
+
/// </summary>
|
|
16
|
+
public class GetAvailableSlotsMapping : ScriptBase, IMapping
|
|
17
|
+
{
|
|
18
|
+
public Task<ScriptResponse> InputHandler(WorkflowTask task, ScriptContext context)
|
|
19
|
+
{
|
|
20
|
+
var serviceTask = task as DaprServiceTask;
|
|
21
|
+
if (serviceTask == null)
|
|
22
|
+
throw new InvalidOperationException("Task must be a DaprServiceTask");
|
|
23
|
+
|
|
24
|
+
var appId = GetConfigValue("DAPR_APP_ID");
|
|
25
|
+
if (!string.IsNullOrEmpty(appId))
|
|
26
|
+
serviceTask.SetAppId(appId);
|
|
27
|
+
|
|
28
|
+
var advisorId = context.QueryParameters?["advisorId"]?.ToString();
|
|
29
|
+
var date = context.QueryParameters?["date"]?.ToString();
|
|
30
|
+
|
|
31
|
+
if (string.IsNullOrEmpty(advisorId) || string.IsNullOrEmpty(date))
|
|
32
|
+
{
|
|
33
|
+
return Task.FromResult(new ScriptResponse
|
|
34
|
+
{
|
|
35
|
+
Key = "validation-error",
|
|
36
|
+
Data = new
|
|
37
|
+
{
|
|
38
|
+
error = "advisorId and date are required",
|
|
39
|
+
errorCode = "VALIDATION_ERROR"
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var requestedDate = DateTime.Parse(date);
|
|
45
|
+
if (requestedDate.Date < DateTime.UtcNow.Date)
|
|
46
|
+
throw new ArgumentException("Date cannot be in the past.", "date");
|
|
47
|
+
|
|
48
|
+
var filterJson =
|
|
49
|
+
"{\"and\":[" +
|
|
50
|
+
"{\"or\":[{\"currentState\":{\"eq\":\"complete\"}},{\"currentState\":{\"eq\":\"complete-with-transfer\"}}]}," +
|
|
51
|
+
"{\"or\":[" +
|
|
52
|
+
"{\"attributes\":{\"advisor\":{\"eq\":\"" + advisorId + "\"}}}," +
|
|
53
|
+
"{\"attributes\":{\"absenceType\":{\"eq\":\"public-holiday\"}}}," +
|
|
54
|
+
"{\"attributes\":{\"absenceType\":{\"eq\":\"working-hours-change\"}}}" +
|
|
55
|
+
"]}" +
|
|
56
|
+
"]}";
|
|
57
|
+
|
|
58
|
+
var queryParams = new List<string>
|
|
59
|
+
{
|
|
60
|
+
"pageSize=100",
|
|
61
|
+
$"filter={filterJson}"
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
serviceTask.SetQueryString(string.Join("&", queryParams));
|
|
65
|
+
|
|
66
|
+
return Task.FromResult(new ScriptResponse());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public Task<ScriptResponse> OutputHandler(ScriptContext context)
|
|
70
|
+
{
|
|
71
|
+
try
|
|
72
|
+
{
|
|
73
|
+
var advisorId = context.QueryParameters?["advisorId"]?.ToString();
|
|
74
|
+
var dateStr = context.QueryParameters?["date"]?.ToString();
|
|
75
|
+
var duration = GetAppointmentDuration(context);
|
|
76
|
+
|
|
77
|
+
if (string.IsNullOrEmpty(advisorId) || string.IsNullOrEmpty(dateStr))
|
|
78
|
+
{
|
|
79
|
+
return Task.FromResult(new ScriptResponse
|
|
80
|
+
{
|
|
81
|
+
Key = "validation-error",
|
|
82
|
+
Data = new
|
|
83
|
+
{
|
|
84
|
+
error = "advisorId and date are required",
|
|
85
|
+
errorCode = "VALIDATION_ERROR",
|
|
86
|
+
advisorId,
|
|
87
|
+
date = dateStr
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
var requestedDate = DateTime.Parse(dateStr);
|
|
93
|
+
var dayOfWeek = requestedDate.DayOfWeek.ToString().ToLower();
|
|
94
|
+
|
|
95
|
+
var response = context.Body;
|
|
96
|
+
|
|
97
|
+
if (response?.isSuccess == false)
|
|
98
|
+
{
|
|
99
|
+
var errorType = ClassifyServiceError(response?.errorMessage?.ToString() ?? "");
|
|
100
|
+
return Task.FromResult(new ScriptResponse
|
|
101
|
+
{
|
|
102
|
+
Key = "service-error",
|
|
103
|
+
Data = new
|
|
104
|
+
{
|
|
105
|
+
error = "Failed to fetch absence entries",
|
|
106
|
+
errorCode = "SERVICE_ERROR",
|
|
107
|
+
errorType = errorType,
|
|
108
|
+
errorMessage = response?.errorMessage?.ToString(),
|
|
109
|
+
serviceInfo = new
|
|
110
|
+
{
|
|
111
|
+
appId = response?.metadata?.appId?.ToString(),
|
|
112
|
+
methodName = response?.metadata?.methodName?.ToString(),
|
|
113
|
+
httpVerb = response?.metadata?.httpVerb?.ToString()
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
Tags = new[] { "appointments", "error" }
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var responseData = response?.data;
|
|
121
|
+
var items = responseData?.items;
|
|
122
|
+
|
|
123
|
+
var instances = new List<dynamic>();
|
|
124
|
+
if (items != null)
|
|
125
|
+
{
|
|
126
|
+
foreach (var item in items)
|
|
127
|
+
{
|
|
128
|
+
instances.Add(item);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var publicHolidays = new List<dynamic>();
|
|
133
|
+
var advisorWorkingHours = new List<dynamic>();
|
|
134
|
+
var companyWorkingHours = new List<dynamic>();
|
|
135
|
+
var personalLeaves = new List<dynamic>();
|
|
136
|
+
|
|
137
|
+
foreach (var instance in instances)
|
|
138
|
+
{
|
|
139
|
+
var attributes = instance?.attributes;
|
|
140
|
+
if (attributes == null) continue;
|
|
141
|
+
|
|
142
|
+
var absenceType = attributes?.absenceType?.ToString();
|
|
143
|
+
var advisor = HasProperty(attributes, "advisor") ? attributes?.advisor?.ToString() : null;
|
|
144
|
+
|
|
145
|
+
switch (absenceType)
|
|
146
|
+
{
|
|
147
|
+
case "public-holiday":
|
|
148
|
+
publicHolidays.Add(instance);
|
|
149
|
+
break;
|
|
150
|
+
case "working-hours-change":
|
|
151
|
+
if (!string.IsNullOrEmpty(advisor) && advisor == advisorId)
|
|
152
|
+
advisorWorkingHours.Add(instance);
|
|
153
|
+
else if (string.IsNullOrEmpty(advisor))
|
|
154
|
+
companyWorkingHours.Add(instance);
|
|
155
|
+
break;
|
|
156
|
+
case "personal-leave" when advisor == advisorId:
|
|
157
|
+
personalLeaves.Add(instance);
|
|
158
|
+
break;
|
|
159
|
+
case "rezervation" when advisor == advisorId:
|
|
160
|
+
personalLeaves.Add(instance);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
var unavailableRanges = GetUnavailableRanges(personalLeaves, requestedDate);
|
|
166
|
+
|
|
167
|
+
// Half-day / full-day public holiday handling
|
|
168
|
+
var holidayRanges = GetHolidayRanges(publicHolidays, requestedDate);
|
|
169
|
+
if (holidayRanges != null)
|
|
170
|
+
{
|
|
171
|
+
if (holidayRanges.Count == 1
|
|
172
|
+
&& holidayRanges[0].Item1 == TimeSpan.Zero
|
|
173
|
+
&& holidayRanges[0].Item2 >= new TimeSpan(23, 59, 0))
|
|
174
|
+
{
|
|
175
|
+
return Task.FromResult(new ScriptResponse
|
|
176
|
+
{
|
|
177
|
+
Key = "public-holiday",
|
|
178
|
+
Data = new { availableSlots = new List<string>() },
|
|
179
|
+
Tags = new[] { "appointments", "holiday" }
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
unavailableRanges.AddRange(holidayRanges);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Working hours priority: advisor-specific > company-wide
|
|
187
|
+
var workingHours = GetWorkingHoursForDay(advisorWorkingHours, dayOfWeek);
|
|
188
|
+
if (workingHours == null || workingHours.Count == 0)
|
|
189
|
+
workingHours = GetWorkingHoursForDay(companyWorkingHours, dayOfWeek);
|
|
190
|
+
|
|
191
|
+
if (workingHours == null || workingHours.Count == 0)
|
|
192
|
+
{
|
|
193
|
+
return Task.FromResult(new ScriptResponse
|
|
194
|
+
{
|
|
195
|
+
Key = "no-working-hours",
|
|
196
|
+
Data = new { availableSlots = new List<string>() },
|
|
197
|
+
Tags = new[] { "appointments", "closed" }
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
var availableSlots = CalculateAvailableSlots(workingHours, unavailableRanges, duration);
|
|
202
|
+
|
|
203
|
+
return Task.FromResult(new ScriptResponse
|
|
204
|
+
{
|
|
205
|
+
Key = "available-slots-success",
|
|
206
|
+
Data = new { availableSlots },
|
|
207
|
+
Tags = new[] { "appointments", "availability", "success" }
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
catch (Exception ex)
|
|
211
|
+
{
|
|
212
|
+
return Task.FromResult(new ScriptResponse
|
|
213
|
+
{
|
|
214
|
+
Key = "output-error",
|
|
215
|
+
Data = new
|
|
216
|
+
{
|
|
217
|
+
error = "Internal processing error",
|
|
218
|
+
errorCode = "PROCESSING_ERROR",
|
|
219
|
+
errorDescription = ex.Message
|
|
220
|
+
},
|
|
221
|
+
Tags = new[] { "appointments", "error" }
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#region Helper Methods
|
|
227
|
+
|
|
228
|
+
private string ClassifyServiceError(string errorMessage)
|
|
229
|
+
{
|
|
230
|
+
if (errorMessage.Contains("timeout", StringComparison.OrdinalIgnoreCase))
|
|
231
|
+
return "timeout";
|
|
232
|
+
if (errorMessage.Contains("unauthorized", StringComparison.OrdinalIgnoreCase))
|
|
233
|
+
return "authentication";
|
|
234
|
+
if (errorMessage.Contains("forbidden", StringComparison.OrdinalIgnoreCase))
|
|
235
|
+
return "authorization";
|
|
236
|
+
if (errorMessage.Contains("not found", StringComparison.OrdinalIgnoreCase))
|
|
237
|
+
return "not-found";
|
|
238
|
+
if (errorMessage.Contains("service unavailable", StringComparison.OrdinalIgnoreCase))
|
|
239
|
+
return "service-unavailable";
|
|
240
|
+
if (errorMessage.Contains("connection", StringComparison.OrdinalIgnoreCase))
|
|
241
|
+
return "connection-error";
|
|
242
|
+
|
|
243
|
+
return "general-error";
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private int GetAppointmentDuration(ScriptContext context)
|
|
247
|
+
{
|
|
248
|
+
const int defaultDuration = 30;
|
|
249
|
+
|
|
250
|
+
if (context.QueryParameters != null && HasProperty(context.QueryParameters, "duration"))
|
|
251
|
+
{
|
|
252
|
+
var durationParam = context.QueryParameters["duration"];
|
|
253
|
+
int queryDuration = 0;
|
|
254
|
+
if (durationParam != null && int.TryParse(durationParam.ToString(), out queryDuration))
|
|
255
|
+
{
|
|
256
|
+
return queryDuration;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
var configDuration = GetConfigValue("Appointments:DefaultDuration");
|
|
261
|
+
int configDurationValue = 0;
|
|
262
|
+
if (!string.IsNullOrEmpty(configDuration) && int.TryParse(configDuration, out configDurationValue))
|
|
263
|
+
{
|
|
264
|
+
return configDurationValue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return defaultDuration;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#endregion
|
|
271
|
+
|
|
272
|
+
#region Business Logic Methods
|
|
273
|
+
|
|
274
|
+
/// <summary>
|
|
275
|
+
/// Returns unavailable time ranges for public holidays on the requested date.
|
|
276
|
+
/// null = no holiday on this date.
|
|
277
|
+
/// Full-day holiday: single range 00:00-23:59.
|
|
278
|
+
/// Half-day holiday: partial range (e.g., 00:00-13:00).
|
|
279
|
+
/// </summary>
|
|
280
|
+
private List<Tuple<TimeSpan, TimeSpan>> GetHolidayRanges(List<dynamic> holidays, DateTime date)
|
|
281
|
+
{
|
|
282
|
+
var ranges = new List<Tuple<TimeSpan, TimeSpan>>();
|
|
283
|
+
bool hasHoliday = false;
|
|
284
|
+
|
|
285
|
+
foreach (var holiday in holidays)
|
|
286
|
+
{
|
|
287
|
+
var holidayData = holiday?.attributes;
|
|
288
|
+
if (holidayData == null) continue;
|
|
289
|
+
|
|
290
|
+
string startDateTimeStr = null;
|
|
291
|
+
string endDateTimeStr = null;
|
|
292
|
+
|
|
293
|
+
if (HasProperty(holidayData, "startDateTime") && holidayData.startDateTime != null)
|
|
294
|
+
startDateTimeStr = holidayData.startDateTime.ToString();
|
|
295
|
+
|
|
296
|
+
if (HasProperty(holidayData, "endDateTime") && holidayData.endDateTime != null)
|
|
297
|
+
endDateTimeStr = holidayData.endDateTime.ToString();
|
|
298
|
+
|
|
299
|
+
if (string.IsNullOrEmpty(startDateTimeStr) || string.IsNullOrEmpty(endDateTimeStr))
|
|
300
|
+
continue;
|
|
301
|
+
|
|
302
|
+
var startDateTime = DateTime.Parse(startDateTimeStr);
|
|
303
|
+
var endDateTime = DateTime.Parse(endDateTimeStr);
|
|
304
|
+
|
|
305
|
+
if (date.Date < startDateTime.Date || date.Date > endDateTime.Date)
|
|
306
|
+
continue;
|
|
307
|
+
|
|
308
|
+
hasHoliday = true;
|
|
309
|
+
|
|
310
|
+
if (startDateTime.Date != endDateTime.Date)
|
|
311
|
+
{
|
|
312
|
+
if (date.Date == startDateTime.Date)
|
|
313
|
+
ranges.Add(Tuple.Create(startDateTime.TimeOfDay, new TimeSpan(23, 59, 59)));
|
|
314
|
+
else if (date.Date == endDateTime.Date)
|
|
315
|
+
ranges.Add(Tuple.Create(TimeSpan.Zero, endDateTime.TimeOfDay));
|
|
316
|
+
else
|
|
317
|
+
ranges.Add(Tuple.Create(TimeSpan.Zero, new TimeSpan(23, 59, 59)));
|
|
318
|
+
}
|
|
319
|
+
else
|
|
320
|
+
{
|
|
321
|
+
ranges.Add(Tuple.Create(startDateTime.TimeOfDay, endDateTime.TimeOfDay));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return hasHoliday ? ranges : null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private List<object> GetWorkingHoursForDay(List<dynamic> workingHoursChanges, string dayOfWeek)
|
|
329
|
+
{
|
|
330
|
+
foreach (var change in workingHoursChanges)
|
|
331
|
+
{
|
|
332
|
+
var changeData = change?.attributes;
|
|
333
|
+
if (changeData == null) continue;
|
|
334
|
+
|
|
335
|
+
var customWH = changeData?.customWorkingHours;
|
|
336
|
+
if (customWH == null) continue;
|
|
337
|
+
|
|
338
|
+
var dayHours = GetDayHoursFromCustom(customWH, dayOfWeek);
|
|
339
|
+
if (dayHours != null) return dayHours;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private List<object> GetDayHoursFromCustom(dynamic customWH, string dayOfWeek)
|
|
346
|
+
{
|
|
347
|
+
dynamic dayHours = null;
|
|
348
|
+
switch (dayOfWeek)
|
|
349
|
+
{
|
|
350
|
+
case "monday": dayHours = customWH?.monday; break;
|
|
351
|
+
case "tuesday": dayHours = customWH?.tuesday; break;
|
|
352
|
+
case "wednesday": dayHours = customWH?.wednesday; break;
|
|
353
|
+
case "thursday": dayHours = customWH?.thursday; break;
|
|
354
|
+
case "friday": dayHours = customWH?.friday; break;
|
|
355
|
+
case "saturday": dayHours = customWH?.saturday; break;
|
|
356
|
+
case "sunday": dayHours = customWH?.sunday; break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (dayHours == null) return null;
|
|
360
|
+
|
|
361
|
+
var result = new List<object>();
|
|
362
|
+
foreach (var range in dayHours)
|
|
363
|
+
{
|
|
364
|
+
var start = range?.start?.ToString();
|
|
365
|
+
var end = range?.end?.ToString();
|
|
366
|
+
if (!string.IsNullOrEmpty(start) && !string.IsNullOrEmpty(end))
|
|
367
|
+
{
|
|
368
|
+
result.Add(new { start, end });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return result.Count > 0 ? result : null;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private List<Tuple<TimeSpan, TimeSpan>> GetUnavailableRanges(List<dynamic> personalLeaves, DateTime date)
|
|
375
|
+
{
|
|
376
|
+
var ranges = new List<Tuple<TimeSpan, TimeSpan>>();
|
|
377
|
+
|
|
378
|
+
foreach (var leave in personalLeaves)
|
|
379
|
+
{
|
|
380
|
+
var leaveData = leave?.attributes;
|
|
381
|
+
if (leaveData == null) continue;
|
|
382
|
+
|
|
383
|
+
string startDateTimeStr = null;
|
|
384
|
+
string endDateTimeStr = null;
|
|
385
|
+
|
|
386
|
+
if (HasProperty(leaveData, "startDateTime") && leaveData.startDateTime != null)
|
|
387
|
+
startDateTimeStr = leaveData.startDateTime.ToString();
|
|
388
|
+
|
|
389
|
+
if (HasProperty(leaveData, "endDateTime") && leaveData.endDateTime != null)
|
|
390
|
+
endDateTimeStr = leaveData.endDateTime.ToString();
|
|
391
|
+
|
|
392
|
+
if (string.IsNullOrEmpty(startDateTimeStr) || string.IsNullOrEmpty(endDateTimeStr))
|
|
393
|
+
continue;
|
|
394
|
+
|
|
395
|
+
var startDateTime = DateTime.Parse(startDateTimeStr);
|
|
396
|
+
var endDateTime = DateTime.Parse(endDateTimeStr);
|
|
397
|
+
|
|
398
|
+
if (date.Date < startDateTime.Date || date.Date > endDateTime.Date)
|
|
399
|
+
continue;
|
|
400
|
+
|
|
401
|
+
if (startDateTime.Date != endDateTime.Date)
|
|
402
|
+
{
|
|
403
|
+
if (date.Date == startDateTime.Date)
|
|
404
|
+
ranges.Add(Tuple.Create(startDateTime.TimeOfDay, new TimeSpan(23, 59, 59)));
|
|
405
|
+
else if (date.Date == endDateTime.Date)
|
|
406
|
+
ranges.Add(Tuple.Create(TimeSpan.Zero, endDateTime.TimeOfDay));
|
|
407
|
+
else
|
|
408
|
+
ranges.Add(Tuple.Create(TimeSpan.Zero, new TimeSpan(23, 59, 59)));
|
|
409
|
+
}
|
|
410
|
+
else
|
|
411
|
+
{
|
|
412
|
+
ranges.Add(Tuple.Create(startDateTime.TimeOfDay, endDateTime.TimeOfDay));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return ranges;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private List<string> CalculateAvailableSlots(List<object> workingHours, List<Tuple<TimeSpan, TimeSpan>> unavailableRanges, int durationMinutes)
|
|
420
|
+
{
|
|
421
|
+
var slots = new List<string>();
|
|
422
|
+
var duration = TimeSpan.FromMinutes(durationMinutes);
|
|
423
|
+
|
|
424
|
+
foreach (var wh in workingHours)
|
|
425
|
+
{
|
|
426
|
+
dynamic whDyn = wh;
|
|
427
|
+
var startStr = whDyn?.start?.ToString();
|
|
428
|
+
var endStr = whDyn?.end?.ToString();
|
|
429
|
+
|
|
430
|
+
if (string.IsNullOrEmpty(startStr) || string.IsNullOrEmpty(endStr))
|
|
431
|
+
continue;
|
|
432
|
+
|
|
433
|
+
var whStart = TimeSpan.Parse(startStr);
|
|
434
|
+
var whEnd = TimeSpan.Parse(endStr);
|
|
435
|
+
|
|
436
|
+
if (whStart == whEnd)
|
|
437
|
+
continue;
|
|
438
|
+
|
|
439
|
+
var current = whStart;
|
|
440
|
+
while (current + duration <= whEnd)
|
|
441
|
+
{
|
|
442
|
+
var slotStart = current;
|
|
443
|
+
var slotEnd = current + duration;
|
|
444
|
+
|
|
445
|
+
bool isAvailable = true;
|
|
446
|
+
foreach (var ur in unavailableRanges)
|
|
447
|
+
{
|
|
448
|
+
if (slotStart < ur.Item2 && slotEnd > ur.Item1)
|
|
449
|
+
{
|
|
450
|
+
isAvailable = false;
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (isAvailable)
|
|
456
|
+
{
|
|
457
|
+
slots.Add($"{slotStart:hh\\:mm}-{slotEnd:hh\\:mm}");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
current = current + duration;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return slots;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
#endregion
|
|
468
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Threading.Tasks;
|
|
4
|
+
using BBT.Workflow.Scripting;
|
|
5
|
+
using BBT.Workflow.Definitions;
|
|
6
|
+
|
|
7
|
+
/// <summary>
|
|
8
|
+
/// Mapping for query-chat-room-instances DaprServiceTask (Type 3).
|
|
9
|
+
/// Flow-level function (scope: F) -- no instance context.
|
|
10
|
+
/// Reads "user" OR "advisor" from query parameters (mutually exclusive).
|
|
11
|
+
/// For advisor: server filter advisorId=X OR members contains { role: "member", memberId: X }.
|
|
12
|
+
/// For user: returns rooms where user=X (server-side filter).
|
|
13
|
+
/// </summary>
|
|
14
|
+
public class GetChatRoomsMapping : ScriptBase, IMapping
|
|
15
|
+
{
|
|
16
|
+
public Task<ScriptResponse> InputHandler(WorkflowTask task, ScriptContext context)
|
|
17
|
+
{
|
|
18
|
+
var serviceTask = task as DaprServiceTask;
|
|
19
|
+
if (serviceTask == null)
|
|
20
|
+
throw new InvalidOperationException("Task must be a DaprServiceTask");
|
|
21
|
+
|
|
22
|
+
var appId = GetConfigValue("DAPR_APP_ID");
|
|
23
|
+
if (!string.IsNullOrEmpty(appId))
|
|
24
|
+
serviceTask.SetAppId(appId);
|
|
25
|
+
|
|
26
|
+
var user = ReadParam(context, "user");
|
|
27
|
+
var advisor = ReadParam(context, "advisor");
|
|
28
|
+
|
|
29
|
+
bool hasUser = !string.IsNullOrWhiteSpace(user);
|
|
30
|
+
bool hasAdvisor = !string.IsNullOrWhiteSpace(advisor);
|
|
31
|
+
|
|
32
|
+
if (hasUser && hasAdvisor)
|
|
33
|
+
throw new InvalidOperationException("VALIDATION_ERROR: user and advisor are mutually exclusive, provide only one");
|
|
34
|
+
|
|
35
|
+
if (!hasUser && !hasAdvisor)
|
|
36
|
+
throw new InvalidOperationException("VALIDATION_ERROR: either user or advisor query parameter is required");
|
|
37
|
+
|
|
38
|
+
string attributeFilter;
|
|
39
|
+
if (hasUser)
|
|
40
|
+
{
|
|
41
|
+
var escaped = user.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
|
42
|
+
attributeFilter = "{\"attributes\":{\"user\":{\"eq\":\"" + escaped + "\"}}}";
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
{
|
|
46
|
+
var escaped = advisor.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
|
47
|
+
attributeFilter = "{\"attributes\":{\"advisorId\":{\"eq\":\"" + escaped + "\"}}}";
|
|
48
|
+
|
|
49
|
+
// attributeFilter = "{\"or\":[" +
|
|
50
|
+
// "{\"attributes\":{\"advisorId\":{\"eq\":\"" + escaped + "\"}}}," +
|
|
51
|
+
// "{\"attributes\":{\"members\":{\"contains\":{\"role\":\"member\",\"memberId\":\"" + escaped + "\"}}}" +
|
|
52
|
+
// "]}";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var roomType = ReadParam(context, "roomType");
|
|
56
|
+
if (!string.IsNullOrWhiteSpace(roomType))
|
|
57
|
+
{
|
|
58
|
+
var escapedType = roomType.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
|
59
|
+
attributeFilter = "{\"and\":[" + attributeFilter + ",{\"attributes\":{\"roomType\":{\"eq\":\"" + escapedType + "\"}}}]}";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var state = ReadParam(context, "state");
|
|
63
|
+
string stateFilter;
|
|
64
|
+
if (string.IsNullOrWhiteSpace(state))
|
|
65
|
+
{
|
|
66
|
+
stateFilter = "{\"or\":[{\"currentState\":{\"eq\":\"activated\"}},{\"currentState\":{\"eq\":\"deactivated\"}}]}";
|
|
67
|
+
}
|
|
68
|
+
else
|
|
69
|
+
{
|
|
70
|
+
var escapedState = state.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
|
71
|
+
stateFilter = "{\"currentState\":{\"eq\":\"" + escapedState + "\"}}";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var filterBody = "{\"and\":[" + attributeFilter + "," + stateFilter + "]}";
|
|
75
|
+
var queryParams = new List<string>
|
|
76
|
+
{
|
|
77
|
+
"pageSize=100",
|
|
78
|
+
"filter=" + filterBody
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
serviceTask.SetQueryString(string.Join("&", queryParams));
|
|
82
|
+
|
|
83
|
+
return Task.FromResult(new ScriptResponse());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public Task<ScriptResponse> OutputHandler(ScriptContext context)
|
|
87
|
+
{
|
|
88
|
+
try
|
|
89
|
+
{
|
|
90
|
+
var response = context.Body;
|
|
91
|
+
|
|
92
|
+
if (response?.isSuccess == false)
|
|
93
|
+
{
|
|
94
|
+
var errorMessage = response?.errorMessage?.ToString() ?? "Service call failed";
|
|
95
|
+
return Task.FromResult(new ScriptResponse
|
|
96
|
+
{
|
|
97
|
+
Key = "get-chat-rooms-failure",
|
|
98
|
+
Data = new
|
|
99
|
+
{
|
|
100
|
+
error = errorMessage,
|
|
101
|
+
errorCode = "SERVICE_ERROR",
|
|
102
|
+
rooms = new List<object>()
|
|
103
|
+
},
|
|
104
|
+
Tags = new[] { "chat", "rooms", "error" }
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var responseData = response?.data;
|
|
109
|
+
var items = responseData?.items;
|
|
110
|
+
var rooms = new List<object>();
|
|
111
|
+
|
|
112
|
+
if (items != null)
|
|
113
|
+
{
|
|
114
|
+
foreach (var item in items)
|
|
115
|
+
{
|
|
116
|
+
// Runtime may expose instance payload as "attributes" or "data"
|
|
117
|
+
var attributes = item?.attributes ?? item?.data;
|
|
118
|
+
if (attributes == null) continue;
|
|
119
|
+
|
|
120
|
+
var metadata = item?.metadata;
|
|
121
|
+
string currentState = metadata != null ? GetString(metadata, "currentState") : null;
|
|
122
|
+
|
|
123
|
+
string roomId = null;
|
|
124
|
+
if (HasProperty(attributes, "chatIntegration") && attributes.chatIntegration != null)
|
|
125
|
+
roomId = GetString(attributes.chatIntegration, "roomId");
|
|
126
|
+
|
|
127
|
+
var members = new List<object>();
|
|
128
|
+
if (HasProperty(attributes, "members") && attributes.members != null)
|
|
129
|
+
{
|
|
130
|
+
foreach (var m in attributes.members)
|
|
131
|
+
{
|
|
132
|
+
var mid = GetString(m, "memberId") ?? GetString(m, "advisorId");
|
|
133
|
+
members.Add(new { memberId = mid, role = GetString(m, "role") });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var instanceKey = GetString(item, "key");
|
|
138
|
+
rooms.Add(new
|
|
139
|
+
{
|
|
140
|
+
id = GetString(item, "id") ?? instanceKey,
|
|
141
|
+
instanceKey = instanceKey,
|
|
142
|
+
user = GetString(attributes, "user"),
|
|
143
|
+
advisorType = GetString(attributes, "advisorType"),
|
|
144
|
+
advisorId = GetString(attributes, "advisorId"),
|
|
145
|
+
roomId = roomId,
|
|
146
|
+
status = GetString(attributes, "status"),
|
|
147
|
+
roomType = GetString(attributes, "roomType"),
|
|
148
|
+
startDateTime = GetString(attributes, "startDateTime"),
|
|
149
|
+
endDateTime = GetString(attributes, "endDateTime"),
|
|
150
|
+
members = members,
|
|
151
|
+
metadata = currentState != null ? new { currentState } : null
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return Task.FromResult(new ScriptResponse
|
|
157
|
+
{
|
|
158
|
+
Key = "get-chat-rooms-success",
|
|
159
|
+
Data = new { rooms = rooms },
|
|
160
|
+
Tags = new[] { "chat", "rooms", "success" }
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (Exception ex)
|
|
164
|
+
{
|
|
165
|
+
return Task.FromResult(new ScriptResponse
|
|
166
|
+
{
|
|
167
|
+
Key = "get-chat-rooms-error",
|
|
168
|
+
Data = new
|
|
169
|
+
{
|
|
170
|
+
error = "Internal processing error",
|
|
171
|
+
errorCode = "PROCESSING_ERROR",
|
|
172
|
+
errorDescription = ex.Message,
|
|
173
|
+
rooms = new List<object>()
|
|
174
|
+
},
|
|
175
|
+
Tags = new[] { "chat", "rooms", "error" }
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private string ReadParam(ScriptContext context, string name)
|
|
181
|
+
{
|
|
182
|
+
if (context.QueryParameters == null || !HasProperty(context.QueryParameters, name))
|
|
183
|
+
return null;
|
|
184
|
+
var val = context.QueryParameters[name];
|
|
185
|
+
return val != null ? val.ToString() : null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private string GetString(dynamic obj, string name)
|
|
189
|
+
{
|
|
190
|
+
if (obj == null) return null;
|
|
191
|
+
try
|
|
192
|
+
{
|
|
193
|
+
if (HasProperty(obj, name))
|
|
194
|
+
{
|
|
195
|
+
var v = GetPropertyValue(obj, name);
|
|
196
|
+
return v?.ToString();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch { }
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|