From 0d7773d88f72667abdaecc6084ff396d714ddab2 Mon Sep 17 00:00:00 2001 From: jderecho Date: Fri, 3 May 2024 09:42:18 +0800 Subject: [PATCH] feat: Draft through API for Cross-Device Support (#8018) - Add APIs for cross-device message drafts ref: #6890 --- .../draft_messages_controller.rb | 28 +++++++++ config/routes.rb | 1 + lib/redis/redis_keys.rb | 1 + .../draft_messages_controller_spec.rb | 62 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 app/controllers/api/v1/accounts/conversations/draft_messages_controller.rb create mode 100644 spec/controllers/api/v1/accounts/conversations/draft_messages_controller_spec.rb diff --git a/app/controllers/api/v1/accounts/conversations/draft_messages_controller.rb b/app/controllers/api/v1/accounts/conversations/draft_messages_controller.rb new file mode 100644 index 000000000..86b7ce5bb --- /dev/null +++ b/app/controllers/api/v1/accounts/conversations/draft_messages_controller.rb @@ -0,0 +1,28 @@ +class Api::V1::Accounts::Conversations::DraftMessagesController < Api::V1::Accounts::Conversations::BaseController + def show + render json: { has_draft: false } and return unless Redis::Alfred.exists?(draft_redis_key) + + draft_message = Redis::Alfred.get(draft_redis_key) + render json: { has_draft: true, message: draft_message } + end + + def update + Redis::Alfred.set(draft_redis_key, draft_message_params) + head :ok + end + + def destroy + Redis::Alfred.delete(draft_redis_key) + head :ok + end + + private + + def draft_redis_key + format(Redis::Alfred::CONVERSATION_DRAFT_MESSAGE, id: @conversation.id) + end + + def draft_message_params + params.dig(:draft_message, :message) || '' + end +end diff --git a/config/routes.rb b/config/routes.rb index 658f2c1ac..1a6db840f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -95,6 +95,7 @@ Rails.application.routes.draw do resources :labels, only: [:create, :index] resource :participants, only: [:show, :create, :update, :destroy] resource :direct_uploads, only: [:create] + resource :draft_messages, only: [:show, :update, :destroy] end member do post :mute diff --git a/lib/redis/redis_keys.rb b/lib/redis/redis_keys.rb index f4a1520b1..3e49d87a7 100644 --- a/lib/redis/redis_keys.rb +++ b/lib/redis/redis_keys.rb @@ -8,6 +8,7 @@ module Redis::RedisKeys CONVERSATION_MAILER_KEY = 'CONVERSATION::%d'.freeze # Whether a conversation is muted ? CONVERSATION_MUTE_KEY = 'CONVERSATION::%d::MUTED'.freeze + CONVERSATION_DRAFT_MESSAGE = 'CONVERSATION::%d::DRAFT_MESSAGE'.freeze ## User Keys # SSO Auth Tokens diff --git a/spec/controllers/api/v1/accounts/conversations/draft_messages_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations/draft_messages_controller_spec.rb new file mode 100644 index 000000000..b663da73f --- /dev/null +++ b/spec/controllers/api/v1/accounts/conversations/draft_messages_controller_spec.rb @@ -0,0 +1,62 @@ +require 'rails_helper' + +RSpec.describe 'Conversation Draft Messages API', type: :request do + let(:account) { create(:account) } + + describe 'POST /api/v1/accounts/{account.id}/conversations//draft_messages' do + let(:conversation) { create(:conversation, account: account) } + let(:cache_key) { format(Redis::Alfred::CONVERSATION_DRAFT_MESSAGE, id: conversation.id) } + + context 'when it is an unauthenticated user' do + it 'returns unauthorized' do + get api_v1_account_conversation_draft_messages_url(account_id: account.id, conversation_id: conversation.display_id) + + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an authenticated user with access to the inbox' do + let(:agent) { create(:user, account: account, role: :agent) } + let(:message) { Faker::Lorem.paragraph } + + before do + create(:inbox_member, inbox: conversation.inbox, user: agent) + end + + it 'saves the draft message for the conversation' do + params = { draft_message: { message: message } } + + patch api_v1_account_conversation_draft_messages_url(account_id: account.id, conversation_id: conversation.display_id), + params: params, + headers: agent.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + expect(Redis::Alfred.get(cache_key)).to eq(params[:draft_message][:message]) + end + + it 'gets the draft message for the conversation' do + Redis::Alfred.set(cache_key, message) + + get api_v1_account_conversation_draft_messages_url(account_id: account.id, conversation_id: conversation.display_id), + headers: agent.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + expect(response.body).to include(message) + end + + it 'removes the draft messages for the conversation' do + Redis::Alfred.set(cache_key, message) + expect(Redis::Alfred.get(cache_key)).to eq(message) + + delete api_v1_account_conversation_draft_messages_url(account_id: account.id, conversation_id: conversation.display_id), + headers: agent.create_new_auth_token, + as: :json + + expect(response).to have_http_status(:success) + expect(Redis::Alfred.get(cache_key)).to be_nil + end + end + end +end