Merge branch 'develop' into CW-1823
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts::Contacts::BaseController
|
||||
include HmacConcern
|
||||
before_action :ensure_inbox, only: [:create]
|
||||
|
||||
def create
|
||||
@contact_inbox = ContactInboxBuilder.new(
|
||||
contact: @contact,
|
||||
inbox: @inbox,
|
||||
source_id: params[:source_id]
|
||||
source_id: params[:source_id],
|
||||
hmac_verified: hmac_verified?
|
||||
).perform
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseController
|
||||
include Events::Types
|
||||
include DateRangeHelper
|
||||
include HmacConcern
|
||||
|
||||
before_action :conversation, except: [:index, :meta, :search, :create, :filter]
|
||||
before_action :inbox, :contact, :contact_inbox, only: [:create]
|
||||
@@ -104,9 +105,6 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
end
|
||||
|
||||
def set_conversation_status
|
||||
# TODO: temporary fallback for the old bot status in conversation, we will remove after couple of releases
|
||||
# commenting this out to see if there are any errors, if not we can remove this in subsequent releases
|
||||
# status = params[:status] == 'bot' ? 'pending' : params[:status]
|
||||
@conversation.status = params[:status]
|
||||
@conversation.snoozed_until = parse_date_time(params[:snoozed_until].to_s) if params[:snoozed_until]
|
||||
end
|
||||
@@ -152,7 +150,8 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
ContactInboxBuilder.new(
|
||||
contact: @contact,
|
||||
inbox: @inbox,
|
||||
source_id: params[:source_id]
|
||||
source_id: params[:source_id],
|
||||
hmac_verified: hmac_verified?
|
||||
).perform
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module HmacConcern
|
||||
def hmac_verified?
|
||||
ActiveModel::Type::Boolean.new.cast(params[:hmac_verified]).present?
|
||||
end
|
||||
end
|
||||
@@ -50,6 +50,13 @@ class SuperAdmin::AccountsController < SuperAdmin::ApplicationController
|
||||
# rubocop:enable Rails/I18nLocaleTexts
|
||||
end
|
||||
|
||||
def reset_cache
|
||||
requested_resource.reset_cache_keys
|
||||
# rubocop:disable Rails/I18nLocaleTexts
|
||||
redirect_back(fallback_location: [namespace, requested_resource], notice: 'Cache keys cleared')
|
||||
# rubocop:enable Rails/I18nLocaleTexts
|
||||
end
|
||||
|
||||
def destroy
|
||||
account = Account.find(params[:id])
|
||||
|
||||
|
||||
@@ -10,15 +10,22 @@
|
||||
"TITLE": "Manage Audit Logs",
|
||||
"DESC": "Audit Logs are trails for events and actions in a Chatwoot System.",
|
||||
"TABLE_HEADER": [
|
||||
"User",
|
||||
"Action",
|
||||
"IP Address",
|
||||
"Time"
|
||||
"Activity",
|
||||
"Time",
|
||||
"IP Address"
|
||||
]
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "AuditLogs retrieved successfully",
|
||||
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later"
|
||||
},
|
||||
"ACTION": {
|
||||
"ADD": "created",
|
||||
"EDIT": "updated",
|
||||
"DELETE": "deleted",
|
||||
"SIGN_IN": "signed in",
|
||||
"SIGN_OUT": "signed out",
|
||||
"SYSTEM": "System"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="column content-box">
|
||||
<div class="column content-box audit-log--settings">
|
||||
<!-- List Audit Logs -->
|
||||
<div class="row">
|
||||
<div class="small-8 columns with-right-space ">
|
||||
<div>
|
||||
<div>
|
||||
<p
|
||||
v-if="!uiFlags.fetchingList && !records.length"
|
||||
class="no-items-error-message"
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
<table
|
||||
v-if="!uiFlags.fetchingList && records.length"
|
||||
class="woot-table"
|
||||
class="woot-table width-100"
|
||||
>
|
||||
<colgroup>
|
||||
<col class="column-activity" />
|
||||
<col />
|
||||
<col />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<!-- Header -->
|
||||
<th
|
||||
@@ -29,12 +34,8 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="auditLogItem in records" :key="auditLogItem.id">
|
||||
<td class="wrap-break-words">{{ auditLogItem.username }}</td>
|
||||
<td class="wrap-break-words">
|
||||
{{ auditLogItem.auditable_type }}.{{ auditLogItem.action }}
|
||||
</td>
|
||||
<td class="remote-address">
|
||||
{{ auditLogItem.remote_address }}
|
||||
{{ generateLogText(auditLogItem) }}
|
||||
</td>
|
||||
<td class="wrap-break-words">
|
||||
{{
|
||||
@@ -44,6 +45,9 @@
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td class="remote-address">
|
||||
{{ auditLogItem.remote_address }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -81,13 +85,48 @@ export default {
|
||||
records: 'auditlogs/getAuditLogs',
|
||||
uiFlags: 'auditlogs/getUIFlags',
|
||||
meta: 'auditlogs/getMeta',
|
||||
agentList: 'agents/getAgents',
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
// Fetch API Call
|
||||
this.$store.dispatch('auditlogs/fetch', { page: 1 });
|
||||
this.$store.dispatch('agents/get');
|
||||
},
|
||||
methods: {
|
||||
getAgentName(email) {
|
||||
if (email === null) {
|
||||
return this.$t('AUDIT_LOGS.ACTION.SYSTEM');
|
||||
}
|
||||
const agentName = this.agentList.find(agent => agent.email === email)
|
||||
?.name;
|
||||
// If agent does not exist(removed/deleted), return email from audit log
|
||||
return agentName || email;
|
||||
},
|
||||
generateLogText(auditLogItem) {
|
||||
const username = this.getAgentName(auditLogItem.username);
|
||||
const auditableType = auditLogItem.auditable_type.toLowerCase();
|
||||
const action = auditLogItem.action.toLowerCase();
|
||||
|
||||
const logActions = {
|
||||
create: this.$t('AUDIT_LOGS.ACTION.ADD'),
|
||||
destroy: this.$t('AUDIT_LOGS.ACTION.DELETE'),
|
||||
update: this.$t('AUDIT_LOGS.ACTION.EDIT'),
|
||||
sign_in: this.$t('AUDIT_LOGS.ACTION.SIGN_IN'),
|
||||
sign_out: this.$t('AUDIT_LOGS.ACTION.SIGN_OUT'),
|
||||
};
|
||||
|
||||
// detect if the action is custom user action, which involves
|
||||
// only the user, such as signing in, signing out etc.
|
||||
// if it is, then do not show the auditable type
|
||||
const userActions = this.getUserActions(action);
|
||||
return `${username} ${logActions[action] || action} ${
|
||||
userActions ? '' : auditableType
|
||||
}`;
|
||||
},
|
||||
getUserActions(action) {
|
||||
return ['sign_in', 'sign_out'].includes(action);
|
||||
},
|
||||
onPageChange(page) {
|
||||
window.history.pushState({}, null, `${this.$route.path}?page=${page}`);
|
||||
try {
|
||||
@@ -101,12 +140,24 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.remote-address {
|
||||
width: 14rem;
|
||||
}
|
||||
.wrap-break-words {
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.audit-log--settings {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
|
||||
.remote-address {
|
||||
width: 14rem;
|
||||
}
|
||||
|
||||
.wrap-break-words {
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.column-activity {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -42,11 +42,10 @@
|
||||
</div>
|
||||
<p
|
||||
v-if="message.showAvatar || hasRecordedResponse"
|
||||
v-dompurify-html="agentName"
|
||||
class="agent-name"
|
||||
:class="$dm('text-slate-700', 'dark:text-slate-200')"
|
||||
>
|
||||
{{ agentName }}
|
||||
</p>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ class Channels::Whatsapp::TemplatesSyncSchedulerJob < ApplicationJob
|
||||
|
||||
def perform
|
||||
Channel::Whatsapp.where('message_templates_last_updated <= ? OR message_templates_last_updated IS NULL',
|
||||
15.minutes.ago).find_in_batches do |channels_batch|
|
||||
channels_batch.each do |channel|
|
||||
Channels::Whatsapp::TemplatesSyncJob.perform_later(channel)
|
||||
end
|
||||
3.hours.ago).limit(Limits::BULK_EXTERNAL_HTTP_CALLS_LIMIT).all.each do |channel|
|
||||
Channels::Whatsapp::TemplatesSyncJob.perform_later(channel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,29 +4,41 @@ module CacheKeys
|
||||
include CacheKeysHelper
|
||||
include Events::Types
|
||||
|
||||
included do
|
||||
class_attribute :cacheable_models
|
||||
self.cacheable_models = [Label, Inbox, Team]
|
||||
end
|
||||
|
||||
def cache_keys
|
||||
{
|
||||
label: fetch_value_for_key(id, Label.name.underscore),
|
||||
inbox: fetch_value_for_key(id, Inbox.name.underscore),
|
||||
team: fetch_value_for_key(id, Team.name.underscore)
|
||||
}
|
||||
keys = {}
|
||||
self.class.cacheable_models.each do |model|
|
||||
keys[model.name.underscore.to_sym] = fetch_value_for_key(id, model.name.underscore)
|
||||
end
|
||||
|
||||
keys
|
||||
end
|
||||
|
||||
def invalidate_cache_key_for(key)
|
||||
prefixed_cache_key = get_prefixed_cache_key(id, key)
|
||||
Redis::Alfred.del(prefixed_cache_key)
|
||||
dispatch_cache_udpate_event
|
||||
Redis::Alfred.delete(prefixed_cache_key)
|
||||
dispatch_cache_update_event
|
||||
end
|
||||
|
||||
def update_cache_key(key)
|
||||
prefixed_cache_key = get_prefixed_cache_key(id, key)
|
||||
Redis::Alfred.set(prefixed_cache_key, Time.now.utc.to_i)
|
||||
dispatch_cache_udpate_event
|
||||
dispatch_cache_update_event
|
||||
end
|
||||
|
||||
def reset_cache_keys
|
||||
self.class.cacheable_models.each do |model|
|
||||
invalidate_cache_key_for(model.name.underscore)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def dispatch_cache_udpate_event
|
||||
def dispatch_cache_update_event
|
||||
Rails.configuration.dispatcher.dispatch(ACCOUNT_CACHE_INVALIDATED, Time.zone.now, cache_keys: cache_keys, account: self)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,7 +23,8 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS
|
||||
|
||||
def sync_templates
|
||||
response = HTTParty.get("#{api_base_path}/configs/templates", headers: api_headers)
|
||||
whatsapp_channel.update(message_templates: response['waba_templates'], message_templates_last_updated: Time.now.utc) if response.success?
|
||||
whatsapp_channel[:message_templates] = response['waba_templates'] if response.success?
|
||||
whatsapp_channel.update(message_templates_last_updated: Time.now.utc)
|
||||
end
|
||||
|
||||
def validate_provider_config?
|
||||
|
||||
@@ -24,8 +24,8 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi
|
||||
|
||||
def sync_templates
|
||||
templates = fetch_whatsapp_templates("#{business_account_path}/message_templates?access_token=#{whatsapp_channel.provider_config['api_key']}")
|
||||
|
||||
whatsapp_channel.update(message_templates: templates, message_templates_last_updated: Time.now.utc) if templates.present?
|
||||
whatsapp_channel[:message_templates] = templates if templates.present?
|
||||
whatsapp_channel.update(message_templates_last_updated: Time.now.utc)
|
||||
end
|
||||
|
||||
def fetch_whatsapp_templates(url)
|
||||
|
||||
@@ -35,7 +35,9 @@
|
||||
<div class="flex flex-col items-start justify-between w-full md:flex-row md:items-center pt-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<% if @article.author&.avatar_url&.present? %>
|
||||
<img src="<%= @article.author.avatar_url %>" alt="<%= @article.author.display_name %>" class="w-12 h-12 border rounded-full pr-1">
|
||||
<div class="pr-1">
|
||||
<img src="<%= @article.author.avatar_url %>" alt="<%= @article.author.display_name %>" class="w-12 h-12 border rounded-full">
|
||||
</div>
|
||||
<% end %>
|
||||
<div>
|
||||
<h5 class="text-base font-medium text-slate-900 mb-2"><%= @article.author.available_name %></h5>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<section class="main-content__body">
|
||||
<hr/>
|
||||
<%= form_for([:reset_cache, namespace, page.resource], method: :post, html: { class: "form" }) do |f| %>
|
||||
<div class="form-actions">
|
||||
<p>This will clear the IndexedDB cache keys from redis. <br>The next load will fetch the data from backend.</p>
|
||||
<%= f.submit 'Reset Frontend Cache' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -87,3 +87,5 @@ as well as a link to its edit page.
|
||||
</section>
|
||||
|
||||
<%= render partial: "seed_data", locals: {page: page} %>
|
||||
|
||||
<%= render partial: "reset_cache", locals: {page: page} %>
|
||||
|
||||
Reference in New Issue
Block a user