public override async Task HandleMenuActionAsync()

in dotnet/space-translate/SpaceTranslate/WebHook/SpaceTranslateWebHookHandler.HandleMenuAction.cs [13:146]


    public override async Task<AppUserActionExecutionResult> HandleMenuActionAsync(MenuActionPayload payload)
    {
        using var loggerScopeForClientId = _logger.BeginScope("ClientId={ClientId}", payload.ClientId);
        
        var organization = await _db.Organizations.FirstOrDefaultAsync(it => it.ClientId == payload.ClientId);
        if (organization == null)
        {
            _logger.LogWarning("The organization does not exist");
            return AppUserActionExecutionResult.Failure("The organization does not exist.");
        }
        
        using var loggerScopeForUserId = _logger.BeginScope("UserId={UserId}", payload.UserId);
        
        if (payload.Context is not ChannelMessageMenuActionContext actionContext)
        {
            _logger.LogWarning("Unknown payload context type. ContextType={ContextType}", payload.Context?.GetType());
            return AppUserActionExecutionResult.Failure("The payload could not be processed.");
        }

        if (actionContext.ChannelIdentifier is not ChannelIdentifier.ChannelIdentifierId channelIdentifierId)
        {
            _logger.LogWarning("Unknown channel identifier type. ChannelIdentifierType={ChannelIdentifierType}", actionContext.ChannelIdentifier.GetType().Name);
            return AppUserActionExecutionResult.Failure("The payload could not be processed.");
        }

        var user = await _db.Users
            .Include(m => m.Organization)
            .FirstOrDefaultAsync(it => it.OrganizationId == organization.Id && it.UserId == payload.UserId);
        if (user == null)
        {
            _logger.LogWarning("User-specific permissions required (no cached credential)");
            return PermissionsRequired(null, channelIdentifierId);
        }

        var organizationConnection = organization.CreateConnection();
        var userConnection = user.CreateConnection();
        if (userConnection == null)
        {
            _logger.LogWarning("User-specific permissions required (no cached credential)");
            return PermissionsRequired(user.Scope, null);
        }
        
        var organizationChatClient = new ChatClient(organizationConnection);
        var userChatClient = new ChatClient(userConnection);

        ChannelItemRecord? originalMessage = null;
        M2ChannelRecord? originalMessageChannelInfo = null;
        try
        {
            originalMessage = await userChatClient.Messages.GetMessageAsync(
                actionContext.MessageIdentifier,
                actionContext.ChannelIdentifier,
                _ => _
                    .WithAllFieldsWildcard());
            
            // Try accessing text, if it is not accessible we need additional permissions
            var _ = originalMessage.Text;
            
            originalMessageChannelInfo = await userChatClient.Channels.GetChannelAsync(actionContext.ChannelIdentifier);
        }
        catch (PermissionDeniedException)
        {
            _logger.LogWarning("User-specific permissions required (permission denied)");
            return PermissionsRequired(user.Scope, channelIdentifierId);
        }
        catch (RefreshTokenRevokedException)
        {
            _logger.LogWarning("User-specific permissions required (refresh token revoked)");
            return PermissionsRequired(user.Scope, channelIdentifierId);
        }
        catch (PropertyNotRequestedException)
        {
            _logger.LogWarning("User-specific permissions required (property not accessible)");
            return PermissionsRequired(user.Scope, channelIdentifierId);
        }
        
        if (userConnection.AuthenticationTokens?.RefreshToken != null &&
            userConnection.AuthenticationTokens.RefreshToken != user.RefreshToken)
        {
            user.RefreshToken = userConnection.AuthenticationTokens.RefreshToken;
            await _db.SaveChangesAsync();
        }

        var cacheKey = organization.Id + "__" +
                       actionContext.ChannelIdentifier + "__" +
                       actionContext.MessageIdentifier + "__" +
                       originalMessage.Text.ToMd5();

        var cachedTranslation = await _cache.GetOrCreateAsync(cacheKey, async entry =>
        {
            if (string.IsNullOrWhiteSpace(originalMessage.Text)) return "(empty)";
            
            _logger.LogInformation("Requesting translation from DeepL...");
                
            var translatedText = await _translator.TranslateTextAsync(
                text: originalMessage.Text,
                sourceLanguageCode: null,
                targetLanguageCode: "en-US",
                options: null);
            
            _logger.LogInformation("Received translation from DeepL. DetectedSourceLanguageCode={DetectedSourceLanguageCode}", translatedText.DetectedSourceLanguageCode);

            return translatedText.Text;
        });

        if (cachedTranslation != null)
        {
            var channelInfoName = "original message";
            if (originalMessageChannelInfo.Contact.Ext is M2SharedChannelContent channelContent)
            {
                channelInfoName = $"original message in #{channelContent.Name}";
            }
            
            await organizationChatClient.Messages.SendMessageAsync(
                recipient: MessageRecipient.Member(ProfileIdentifier.Id(payload.UserId)),
                content: ChatMessage.Block(new List<MessageSectionElement>
                {
                    MessageSectionElement.MessageSection(new List<MessageBlockElement>
                    {
                        MessageBlockElement.MessageText(
                            $"Translation of [{channelInfoName}]({organization.ServerUrl}/im/translated/?message={actionContext.MessageIdentifier.ToString()!.Replace("id:", "").Replace("externalId:", "")}&channel={actionContext.ChannelIdentifier.ToString()!.Replace("id:", "")}): "),
                        MessageBlockElement.MessageDivider(),
                        MessageBlockElement.MessageText(cachedTranslation)
                    })
                }));
        }
        else
        {
            _logger.LogWarning("Could not translate message");
            return AppUserActionExecutionResult.Failure("Could not translate message.");
        }

        return await base.HandleMenuActionAsync(payload);
    }