Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54308a4145 | ||
|
|
2eeec22868 | ||
|
|
ef50edb9e2 | ||
|
|
3ed80fa867 | ||
|
|
88f44c21f2 | ||
|
|
cf664ca2a0 | ||
|
|
485c561b18 | ||
|
|
766698cb3a | ||
|
|
feb8ec7879 | ||
|
|
082793290a | ||
|
|
b5e81ccd3b | ||
|
|
b31040901e | ||
|
|
1f610c7fc5 | ||
|
|
188a8a67c0 |
@@ -29,11 +29,12 @@ export default {
|
||||
return fetchPromise;
|
||||
},
|
||||
hasAuthCookie() {
|
||||
return !!Cookies.getJSON('cw_d_session_info');
|
||||
return !!Cookies.get('cw_d_session_info');
|
||||
},
|
||||
getAuthData() {
|
||||
if (this.hasAuthCookie()) {
|
||||
return Cookies.getJSON('cw_d_session_info');
|
||||
const savedAuthInfo = Cookies.get('cw_d_session_info');
|
||||
return JSON.parse(savedAuthInfo || '{}');
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<script setup>
|
||||
// import { defineProps } from 'vue';
|
||||
|
||||
import PriorityIcon from './components/PriorityIcon.vue';
|
||||
import StatusIcon from './components/StatusIcon.vue';
|
||||
import InboxNameAndId from './components/InboxNameAndId.vue';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
|
||||
// const props = defineProps({
|
||||
// notificationItem: {
|
||||
// type: Object,
|
||||
// default: () => {},
|
||||
// },
|
||||
// });
|
||||
|
||||
const assigneeMeta = {
|
||||
thumbnail: '',
|
||||
name: 'Michael Johnson',
|
||||
};
|
||||
const { thumbnail, name } = assigneeMeta || {};
|
||||
const status = 'open';
|
||||
const priority = 'high';
|
||||
const inboxTypeMessage = 'Mentioned by Michael';
|
||||
const inboxMessage = 'What is the best way to get started?';
|
||||
const inbox = {
|
||||
inbox_id: 16787,
|
||||
inbox_name: 'Chatwoot Support',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex max-w-[360px] flex-col pl-5 pr-3 gap-2.5 py-3 w-full bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-500 hover:bg-slate-25 dark:hover:bg-slate-800 cursor-pointer"
|
||||
>
|
||||
<div class="flex relative items-center justify-between w-full">
|
||||
<div
|
||||
class="absolute -left-3.5 flex w-2 h-2 rounded bg-woot-500 dark:bg-woot-500"
|
||||
/>
|
||||
<InboxNameAndId :inbox="inbox" />
|
||||
<div class="flex gap-2">
|
||||
<PriorityIcon :priority="priority" />
|
||||
<StatusIcon :status="status" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row justify-between items-center w-full">
|
||||
<div class="flex gap-1.5 items-center max-w-[80%]">
|
||||
<Thumbnail
|
||||
v-if="assigneeMeta"
|
||||
:src="thumbnail"
|
||||
:username="name"
|
||||
size="20px"
|
||||
/>
|
||||
<div class="flex min-w-0">
|
||||
<span
|
||||
class="font-medium text-slate-800 dark:text-slate-100 text-xs overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
>
|
||||
{{ inboxTypeMessage }}<span v-if="inboxTypeMessage">:</span>
|
||||
<span class="font-normal">{{ inboxMessage }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="font-medium text-slate-600 dark:text-slate-300 text-xs whitespace-nowrap"
|
||||
>
|
||||
10h ago
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup>
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const { inbox } = props;
|
||||
const { inbox_id: inboxId, inbox_name: inboxName } = inbox;
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="inline-flex items-center rounded-[4px] border border-slate-100 dark:border-slate-600 divide-x divide-slate-100 dark:divide-slate-600 bg-none"
|
||||
>
|
||||
<div class="flex items-center gap-0.5 py-0.5 px-1.5">
|
||||
<fluent-icon
|
||||
class="text-slate-600 dark:text-slate-300"
|
||||
icon="globe-desktop"
|
||||
size="14"
|
||||
/>
|
||||
<span class="font-medium text-slate-600 dark:text-slate-300 text-xs">
|
||||
{{ inboxName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center py-0.5 px-1.5">
|
||||
<span class="font-medium text-slate-600 dark:text-slate-300 text-xs">
|
||||
{{ inboxId }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
import { CONVERSATION_PRIORITY } from 'shared/constants/messages';
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
priority: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="inline-flex items-center justify-center rounded-md">
|
||||
<!-- High Priority -->
|
||||
<svg
|
||||
v-if="props.priority === CONVERSATION_PRIORITY.HIGH"
|
||||
class="h-4 w-4"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
|
||||
<rect x="10" y="8" width="4" height="12" rx="1" fill="#FFC291" />
|
||||
<rect x="16" y="4" width="4" height="16" rx="1" fill="#FFC291" />
|
||||
</svg>
|
||||
|
||||
<!-- Low Priority -->
|
||||
<svg
|
||||
v-if="props.priority === CONVERSATION_PRIORITY.LOW"
|
||||
class="h-4 w-4"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
|
||||
<rect x="10" y="8" width="4" height="12" rx="1" fill="#DDDDDD" />
|
||||
<rect x="16" y="4" width="4" height="16" rx="1" fill="#DDDDDD" />
|
||||
</svg>
|
||||
|
||||
<!-- Medium Priority -->
|
||||
<svg
|
||||
v-if="props.priority === CONVERSATION_PRIORITY.MEDIUM"
|
||||
class="h-4 w-4"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
|
||||
<rect x="10" y="8" width="4" height="12" rx="1" fill="#FFC291" />
|
||||
<rect x="16" y="4" width="4" height="16" rx="1" fill="#DDDDDD" />
|
||||
</svg>
|
||||
|
||||
<!-- Urgent Priority -->
|
||||
<svg
|
||||
v-if="props.priority === CONVERSATION_PRIORITY.URGENT"
|
||||
class="h-4 w-4"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect x="4" y="12" width="4" height="8" rx="1" fill="#E5484D" />
|
||||
<rect x="10" y="8" width="4" height="12" rx="1" fill="#E5484D" />
|
||||
<rect x="16" y="4" width="4" height="16" rx="1" fill="#E5484D" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,80 @@
|
||||
<script setup>
|
||||
import { CONVERSATION_STATUS } from 'shared/constants/messages';
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
status: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="inline-flex items-center justify-center rounded-md">
|
||||
<!-- Pending -->
|
||||
<svg
|
||||
v-if="props.status === CONVERSATION_STATUS.PENDING"
|
||||
class="h-3.5 w-3.5"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.1 0.0449978V1.8558C4.5486 2.2986 1.8 5.328 1.8 9C1.8 12.9762 5.0238 16.2 9 16.2C10.6641 16.2 12.195 15.6357 13.4154 14.688L14.6961 15.9687C13.1445 17.2377 11.16 18 9 18C4.0293 18 0 13.9707 0 9C0 4.3335 3.5523 0.495898 8.1 0.0449978ZM17.955 9.9C17.775 11.7099 17.0604 13.3623 15.9687 14.6952L14.688 13.4154C15.462 12.4191 15.9804 11.2149 16.1442 9.9H17.9559H17.955ZM9.9018 0.0449978C14.1534 0.467098 17.5338 3.8484 17.9568 8.1H16.1451C15.7392 4.8438 13.158 2.2626 9.9018 1.8558V0.0440979V0.0449978Z"
|
||||
class="fill-[#B9BBC6]"
|
||||
/>
|
||||
</svg>
|
||||
<!-- Open -->
|
||||
<svg
|
||||
v-if="props.status === CONVERSATION_STATUS.OPEN"
|
||||
class="h-3.5 w-3.5"
|
||||
width="19"
|
||||
height="19"
|
||||
viewBox="0 0 19 19"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.375 18.875C4.19733 18.875 0 14.6776 0 9.5C0 4.32233 4.19733 0.125 9.375 0.125C14.5526 0.125 18.75 4.32233 18.75 9.5C18.75 14.6776 14.5526 18.875 9.375 18.875ZM9.375 17C13.5172 17 16.875 13.6422 16.875 9.5C16.875 5.35786 13.5172 2 9.375 2C5.23286 2 1.875 5.35786 1.875 9.5C1.875 13.6422 5.23286 17 9.375 17Z"
|
||||
class="fill-[#ED8A5C]"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<!-- Snoozed -->
|
||||
<svg
|
||||
v-if="props.status === CONVERSATION_STATUS.SNOOZED"
|
||||
class="h-3.5 w-3.5"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9 18C4.0293 18 0 13.9707 0 9C0 4.0293 4.0293 0 9 0C13.9707 0 18 4.0293 18 9C18 13.9707 13.9707 18 9 18ZM2.9961 12.9825C3.58766 13.8676 4.36812 14.6105 5.28129 15.1577C6.19446 15.7049 7.21761 16.0428 8.27707 16.147C9.33652 16.2513 10.4059 16.1193 11.4082 15.7606C12.4105 15.4019 13.3208 14.8254 14.0736 14.0726C14.8263 13.3198 15.4027 12.4094 15.7613 11.4071C16.12 10.4047 16.2518 9.33532 16.1475 8.27588C16.0431 7.21644 15.7052 6.19332 15.1579 5.2802C14.6106 4.36707 13.8676 3.58668 12.9825 2.9952C13.3706 4.3796 13.383 5.84237 13.0186 7.23318C12.6542 8.62399 11.926 9.89269 10.9089 10.9089C9.89277 11.9258 8.62423 12.6539 7.23359 13.0183C5.84296 13.3828 4.38037 13.3704 2.9961 12.9825Z"
|
||||
class="fill-[#0B68CB]"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<!-- Resolved -->
|
||||
<svg
|
||||
v-if="props.status === CONVERSATION_STATUS.RESOLVED"
|
||||
class="h-3.5 w-3.5"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="3 3 17.92 17.92"
|
||||
>
|
||||
<path
|
||||
d="M11.96 20.92C7.01152 20.92 3 16.9084 3 11.96C3 7.01152 7.01152 3 11.96 3C16.9084 3 20.92 7.01152 20.92 11.96C20.92 16.9084 16.9084 20.92 11.96 20.92ZM11.96 19.128C15.9188 19.128 19.128 15.9188 19.128 11.96C19.128 8.00122 15.9188 4.792 11.96 4.792C8.00122 4.792 4.792 8.00122 4.792 11.96C4.792 15.9188 8.00122 19.128 11.96 19.128Z"
|
||||
class="fill-[#5BB98C]"
|
||||
/>
|
||||
<path
|
||||
d="M11.9599 17.9333C15.2589 17.9333 17.9332 15.2589 17.9332 11.96C17.9332 8.66098 15.2589 5.98663 11.9599 5.98663C8.66092 5.98663 5.98657 8.66098 5.98657 11.96C5.98657 15.2589 8.66092 17.9333 11.9599 17.9333Z"
|
||||
class="fill-[#5BB98C]"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
@@ -12,7 +12,7 @@ jest.mock('../../../utils/api', () => ({
|
||||
getHeaderExpiry: jest.fn(),
|
||||
}));
|
||||
jest.mock('js-cookie', () => ({
|
||||
getJSON: jest.fn(),
|
||||
get: jest.fn(),
|
||||
}));
|
||||
|
||||
const commit = jest.fn();
|
||||
@@ -155,14 +155,14 @@ describe('#actions', () => {
|
||||
|
||||
describe('#setUser', () => {
|
||||
it('sends correct actions if user is logged in', async () => {
|
||||
Cookies.getJSON.mockImplementation(() => true);
|
||||
Cookies.get.mockImplementation(() => true);
|
||||
actions.setUser({ commit, dispatch });
|
||||
expect(commit.mock.calls).toEqual([]);
|
||||
expect(dispatch.mock.calls).toEqual([['validityCheck']]);
|
||||
});
|
||||
|
||||
it('sends correct actions if user is not logged in', async () => {
|
||||
Cookies.getJSON.mockImplementation(() => false);
|
||||
Cookies.get.mockImplementation(() => false);
|
||||
actions.setUser({ commit, dispatch });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.CLEAR_USER],
|
||||
|
||||
@@ -27,7 +27,7 @@ export const getHeaderExpiry = response =>
|
||||
|
||||
export const setAuthCredentials = response => {
|
||||
const expiryDate = getHeaderExpiry(response);
|
||||
Cookies.set('cw_d_session_info', response.headers, {
|
||||
Cookies.set('cw_d_session_info', JSON.stringify(response.headers), {
|
||||
expires: differenceInDays(expiryDate, new Date()),
|
||||
});
|
||||
setUser(response.data.data, expiryDate);
|
||||
|
||||
@@ -34,5 +34,12 @@ export const setCookieWithDomain = (
|
||||
domain: baseDomain,
|
||||
};
|
||||
|
||||
// if type of value is object, stringify it
|
||||
// this is because js-cookies 3.0 removed builtin json support
|
||||
// ref: https://github.com/js-cookie/js-cookie/releases/tag/v3.0.0
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
Cookies.set(name, value, cookieOptions);
|
||||
};
|
||||
|
||||
@@ -107,6 +107,26 @@ describe('setCookieWithDomain', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should stringify the cookie value when setting', () => {
|
||||
setCookieWithDomain(
|
||||
'myCookie',
|
||||
{ value: 'cookieValue' },
|
||||
{
|
||||
baseDomain: 'example.com',
|
||||
}
|
||||
);
|
||||
|
||||
expect(Cookies.set).toHaveBeenCalledWith(
|
||||
'myCookie',
|
||||
JSON.stringify({ value: 'cookieValue' }),
|
||||
expect.objectContaining({
|
||||
expires: 365,
|
||||
sameSite: 'Lax',
|
||||
domain: 'example.com',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should set a cookie with custom expiration, sameSite attribute, and specific base domain', () => {
|
||||
setCookieWithDomain('myCookie', 'cookieValue', {
|
||||
expires: 7,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DEFAULT_REDIRECT_URL } from 'dashboard/constants/globals';
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
|
||||
export const hasAuthCookie = () => {
|
||||
return !!Cookies.getJSON('cw_d_session_info');
|
||||
return !!Cookies.get('cw_d_session_info');
|
||||
};
|
||||
|
||||
const getSSOAccountPath = ({ ssoAccountId, user }) => {
|
||||
|
||||
@@ -10,10 +10,10 @@ jest.mock('dashboard/store/utils/api', () => ({
|
||||
jest.mock('../CommonHelper', () => ({ replaceRouteWithReload: jest.fn() }));
|
||||
|
||||
jest.mock('js-cookie', () => ({
|
||||
getJSON: jest.fn(),
|
||||
get: jest.fn(),
|
||||
}));
|
||||
|
||||
Cookies.getJSON.mockReturnValueOnce(true).mockReturnValue(false);
|
||||
Cookies.get.mockReturnValueOnce(true).mockReturnValue(false);
|
||||
describe('#validateRouteAccess', () => {
|
||||
it('reset cookies and continues to the login page if the SSO parameters are present', () => {
|
||||
validateRouteAccess(
|
||||
@@ -40,7 +40,7 @@ describe('#validateRouteAccess', () => {
|
||||
});
|
||||
|
||||
it('redirects to dashboard if auth cookie is present', () => {
|
||||
Cookies.getJSON.mockImplementation(() => true);
|
||||
Cookies.get.mockImplementation(() => true);
|
||||
validateRouteAccess({ name: 'login' }, next);
|
||||
expect(clearBrowserSessionCookies).not.toHaveBeenCalled();
|
||||
expect(replaceRouteWithReload).toHaveBeenCalledWith('/app/');
|
||||
|
||||
@@ -2,7 +2,7 @@ module AccountCacheRevalidator
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_commit :update_account_cache, on: [:create, :update]
|
||||
after_commit :update_account_cache, on: [:create, :update, :destroy]
|
||||
end
|
||||
|
||||
def update_account_cache
|
||||
|
||||
@@ -4,6 +4,8 @@ module CacheKeys
|
||||
include CacheKeysHelper
|
||||
include Events::Types
|
||||
|
||||
CACHE_KEYS_EXPIRY = 72.hours
|
||||
|
||||
included do
|
||||
class_attribute :cacheable_models
|
||||
self.cacheable_models = [Label, Inbox, Team]
|
||||
@@ -18,26 +20,26 @@ module CacheKeys
|
||||
keys
|
||||
end
|
||||
|
||||
def invalidate_cache_key_for(key)
|
||||
prefixed_cache_key = get_prefixed_cache_key(id, key)
|
||||
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)
|
||||
update_cache_key_for_account(id, key)
|
||||
dispatch_cache_update_event
|
||||
end
|
||||
|
||||
def reset_cache_keys
|
||||
self.class.cacheable_models.each do |model|
|
||||
invalidate_cache_key_for(model.name.underscore)
|
||||
update_cache_key_for_account(id, model.name.underscore)
|
||||
end
|
||||
|
||||
dispatch_cache_update_event
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_cache_key_for_account(account_id, key)
|
||||
prefixed_cache_key = get_prefixed_cache_key(account_id, key)
|
||||
Redis::Alfred.setex(prefixed_cache_key, Time.now.utc.to_i, CACHE_KEYS_EXPIRY)
|
||||
end
|
||||
|
||||
def dispatch_cache_update_event
|
||||
Rails.configuration.dispatcher.dispatch(ACCOUNT_CACHE_INVALIDATED, Time.zone.now, cache_keys: cache_keys, account: self)
|
||||
end
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
# id :integer not null, primary key
|
||||
# additional_attributes :jsonb
|
||||
# contact_type :integer default("visitor")
|
||||
# country_code :string default("")
|
||||
# custom_attributes :jsonb
|
||||
# email :string
|
||||
# identifier :string
|
||||
# last_activity_at :datetime
|
||||
# last_name :string default("")
|
||||
# location :string default("")
|
||||
# middle_name :string default("")
|
||||
# name :string default("")
|
||||
# phone_number :string
|
||||
|
||||
@@ -7,7 +7,12 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
|
||||
|
||||
def perform_reply
|
||||
send_message_to_facebook fb_text_message_params if message.content.present?
|
||||
send_message_to_facebook fb_attachment_message_params if message.attachments.present?
|
||||
|
||||
if message.attachments.present?
|
||||
message.attachments.each do |attachment|
|
||||
send_message_to_facebook fb_attachment_message_params(attachment)
|
||||
end
|
||||
end
|
||||
rescue Facebook::Messenger::FacebookError => e
|
||||
# TODO : handle specific errors or else page will get disconnected
|
||||
handle_facebook_error(e)
|
||||
@@ -41,8 +46,7 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
|
||||
"#{error_code} - #{error_message}"
|
||||
end
|
||||
|
||||
def fb_attachment_message_params
|
||||
attachment = message.attachments.first
|
||||
def fb_attachment_message_params(attachment)
|
||||
{
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: {
|
||||
@@ -64,14 +68,6 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
|
||||
'file'
|
||||
end
|
||||
|
||||
def fb_message_params
|
||||
if message.attachments.blank?
|
||||
fb_text_message_params
|
||||
else
|
||||
fb_attachment_message_params
|
||||
end
|
||||
end
|
||||
|
||||
def sent_first_outgoing_message_after_24_hours?
|
||||
# we can send max 1 message after 24 hour window
|
||||
conversation.messages.outgoing.where('id > ?', conversation.last_incoming_message.id).count == 1
|
||||
|
||||
@@ -14,8 +14,13 @@ class Instagram::SendOnInstagramService < Base::SendOnChannelService
|
||||
end
|
||||
|
||||
def perform_reply
|
||||
send_to_facebook_page attachament_message_params if message.attachments.present?
|
||||
send_to_facebook_page message_params
|
||||
if message.attachments.present?
|
||||
message.attachments.each do |attachment|
|
||||
send_to_facebook_page attachment_message_params(attachment)
|
||||
end
|
||||
end
|
||||
|
||||
send_to_facebook_page message_params if message.content.present?
|
||||
rescue StandardError => e
|
||||
ChatwootExceptionTracker.new(e, account: message.account, user: message.sender).capture_exception
|
||||
# TODO : handle specific errors or else page will get disconnected
|
||||
@@ -33,8 +38,7 @@ class Instagram::SendOnInstagramService < Base::SendOnChannelService
|
||||
merge_human_agent_tag(params)
|
||||
end
|
||||
|
||||
def attachament_message_params
|
||||
attachment = message.attachments.first
|
||||
def attachment_message_params(attachment)
|
||||
params = {
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: {
|
||||
|
||||
@@ -24,7 +24,9 @@ class Instagram::WebhooksBaseService
|
||||
def update_instagram_profile_link(user)
|
||||
return unless user['username']
|
||||
|
||||
# TODO: Remove this once we show the social_instagram_user_name in the UI instead of the username
|
||||
@contact.additional_attributes = @contact.additional_attributes.merge({ 'social_profiles': { 'instagram': user['username'] } })
|
||||
@contact.additional_attributes = @contact.additional_attributes.merge({ 'social_instagram_user_name': user['username'] })
|
||||
@contact.save
|
||||
end
|
||||
end
|
||||
|
||||
@@ -139,7 +139,14 @@ class Line::IncomingMessageService
|
||||
def contact_attributes
|
||||
{
|
||||
name: line_contact_info['displayName'],
|
||||
avatar_url: line_contact_info['pictureUrl']
|
||||
avatar_url: line_contact_info['pictureUrl'],
|
||||
additional_attributes: additional_attributes
|
||||
}
|
||||
end
|
||||
|
||||
def additional_attributes
|
||||
{
|
||||
social_line_user_id: line_contact_info['userId']
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -78,8 +78,11 @@ class Telegram::IncomingMessageService
|
||||
|
||||
def additional_attributes
|
||||
{
|
||||
# TODO: Remove this once we show the social_telegram_user_name in the UI instead of the username
|
||||
username: telegram_params_username,
|
||||
language_code: telegram_params_language_code
|
||||
language_code: telegram_params_language_code,
|
||||
social_telegram_user_id: telegram_params_from_id,
|
||||
social_telegram_user_name: telegram_params_username
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddLocationAndCountryCodeToContacts < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :contacts, :location, :string, default: ''
|
||||
add_column :contacts, :country_code, :string, default: ''
|
||||
end
|
||||
end
|
||||
+3
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_01_24_084032) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_01_29_080827) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "pg_trgm"
|
||||
@@ -421,6 +421,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_24_084032) do
|
||||
t.integer "contact_type", default: 0
|
||||
t.string "middle_name", default: ""
|
||||
t.string "last_name", default: ""
|
||||
t.string "location", default: ""
|
||||
t.string "country_code", default: ""
|
||||
t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id"
|
||||
t.index ["account_id", "email", "phone_number", "identifier"], name: "index_contacts_on_nonempty_fields", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))"
|
||||
t.index ["account_id"], name: "index_contacts_on_account_id"
|
||||
|
||||
+3
-3
@@ -31,10 +31,10 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@braid/vue-formulate": "^2.5.2",
|
||||
"@chatwoot/prosemirror-schema": "1.0.5",
|
||||
"@chatwoot/prosemirror-schema": "1.0.7",
|
||||
"@chatwoot/utils": "^0.0.21",
|
||||
"@hcaptcha/vue-hcaptcha": "^0.3.2",
|
||||
"@june-so/analytics-next": "^1.36.5",
|
||||
"@june-so/analytics-next": "^2.0.0",
|
||||
"@radix-ui/colors": "^1.0.1",
|
||||
"@rails/actioncable": "6.1.3",
|
||||
"@rails/ujs": "^7.0.3-1",
|
||||
@@ -60,7 +60,7 @@
|
||||
"highlight.js": "~10.4.1",
|
||||
"idb": "^7.1.1",
|
||||
"ionicons": "~2.0.1",
|
||||
"js-cookie": "^2.2.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"libphonenumber-js": "^1.10.24",
|
||||
"logrocket": "^3.0.1",
|
||||
"logrocket-vuex": "^0.0.3",
|
||||
|
||||
@@ -43,10 +43,13 @@ RSpec.describe 'Super Admin accounts API', type: :request do
|
||||
it 'shows the list of accounts' do
|
||||
expect(account.cache_keys.keys).to contain_exactly(:inbox, :label, :team)
|
||||
sign_in(super_admin, scope: :super_admin)
|
||||
|
||||
now_timestamp = Time.now.utc.to_i
|
||||
post "/super_admin/accounts/#{account.id}/reset_cache"
|
||||
expect(response).to have_http_status(:redirect)
|
||||
expect(flash[:notice]).to eq('Cache keys cleared')
|
||||
expect(account.reload.cache_keys.values.map(&:to_i)).to eq([0, 0, 0])
|
||||
|
||||
expect(account.reload.cache_keys.values.all? { |v| v.to_i == now_timestamp }).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,7 +43,7 @@ describe Webhooks::InstagramEventsJob do
|
||||
instagram_inbox.reload
|
||||
|
||||
expect(instagram_inbox.contacts.count).to be 1
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_profiles']['instagram']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_instagram_user_name']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.conversations.count).to be 1
|
||||
expect(instagram_inbox.messages.count).to be 1
|
||||
expect(instagram_inbox.messages.last.content_attributes['is_unsupported']).to be_nil
|
||||
@@ -59,7 +59,7 @@ describe Webhooks::InstagramEventsJob do
|
||||
instagram_inbox.reload
|
||||
|
||||
expect(instagram_inbox.contacts.count).to be 1
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_profiles']['instagram']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_instagram_user_name']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.conversations.count).to be 1
|
||||
expect(instagram_inbox.messages.count).to be 1
|
||||
|
||||
@@ -170,7 +170,7 @@ describe Webhooks::InstagramEventsJob do
|
||||
instagram_inbox.reload
|
||||
|
||||
expect(instagram_inbox.contacts.count).to be 1
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_profiles']['instagram']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.contacts.last.additional_attributes['social_instagram_user_name']).to eq 'some_user_name'
|
||||
expect(instagram_inbox.conversations.count).to be 1
|
||||
expect(instagram_inbox.messages.count).to be 1
|
||||
expect(instagram_inbox.messages.last.content_attributes['is_unsupported']).to be true
|
||||
|
||||
@@ -14,6 +14,7 @@ RSpec.describe CacheKeys do
|
||||
before do
|
||||
allow(Redis::Alfred).to receive(:delete)
|
||||
allow(Redis::Alfred).to receive(:set)
|
||||
allow(Redis::Alfred).to receive(:setex)
|
||||
allow(Rails.configuration.dispatcher).to receive(:dispatch)
|
||||
end
|
||||
|
||||
@@ -27,28 +28,11 @@ RSpec.describe CacheKeys do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#invalidate_cache_key_for' do
|
||||
it 'deletes the cache key' do
|
||||
test_model.invalidate_cache_key_for('label')
|
||||
expect(Redis::Alfred).to have_received(:delete).with('idb-cache-key-account-1-label')
|
||||
end
|
||||
|
||||
it 'dispatches a cache update event' do
|
||||
test_model.invalidate_cache_key_for('label')
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch).with(
|
||||
CacheKeys::ACCOUNT_CACHE_INVALIDATED,
|
||||
kind_of(ActiveSupport::TimeWithZone),
|
||||
cache_keys: test_model.cache_keys,
|
||||
account: test_model
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_cache_key' do
|
||||
it 'updates the cache key' do
|
||||
allow(Time).to receive(:now).and_return(Time.parse('2023-05-29 00:00:00 UTC'))
|
||||
test_model.update_cache_key('label')
|
||||
expect(Redis::Alfred).to have_received(:set).with('idb-cache-key-account-1-label', Time.now.utc.to_i)
|
||||
expect(Redis::Alfred).to have_received(:setex).with('idb-cache-key-account-1-label', kind_of(Integer), CacheKeys::CACHE_KEYS_EXPIRY)
|
||||
end
|
||||
|
||||
it 'dispatches a cache update event' do
|
||||
@@ -66,8 +50,20 @@ RSpec.describe CacheKeys do
|
||||
it 'invalidates all cache keys for cacheable models' do
|
||||
test_model.reset_cache_keys
|
||||
test_model.class.cacheable_models.each do |model|
|
||||
expect(Redis::Alfred).to have_received(:delete).with("idb-cache-key-account-1-#{model.name.underscore}")
|
||||
expect(Redis::Alfred).to have_received(:setex).with("idb-cache-key-account-1-#{model.name.underscore}", kind_of(Integer),
|
||||
CacheKeys::CACHE_KEYS_EXPIRY)
|
||||
end
|
||||
end
|
||||
|
||||
it 'dispatches a cache update event' do
|
||||
test_model.reset_cache_keys
|
||||
|
||||
expect(Rails.configuration.dispatcher).to have_received(:dispatch).with(
|
||||
CacheKeys::ACCOUNT_CACHE_INVALIDATED,
|
||||
kind_of(ActiveSupport::TimeWithZone),
|
||||
cache_keys: test_model.cache_keys,
|
||||
account: test_model
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -250,5 +250,15 @@ RSpec.describe Inbox do
|
||||
cache_keys: inbox.account.cache_keys
|
||||
)
|
||||
end
|
||||
|
||||
it 'updates the cache key after update' do
|
||||
expect(inbox.account).to receive(:update_cache_key).with('inbox')
|
||||
inbox.update(name: 'New Name')
|
||||
end
|
||||
|
||||
it 'updates the cache key after touch' do
|
||||
expect(inbox.account).to receive(:update_cache_key).with('inbox')
|
||||
inbox.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -90,6 +90,24 @@ describe Facebook::SendOnFacebookService do
|
||||
}, { page_id: facebook_channel.page_id })
|
||||
end
|
||||
|
||||
it 'if message is sent with multiple attachments' do
|
||||
message = build(:message, content: nil, message_type: 'outgoing', inbox: facebook_inbox, account: account, conversation: conversation)
|
||||
avatar = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
avatar.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
||||
sample = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
sample.file.attach(io: Rails.root.join('spec/assets/sample.png').open, filename: 'sample.png', content_type: 'image/png')
|
||||
message.save!
|
||||
|
||||
service = described_class.new(message: message)
|
||||
|
||||
# Stub the send_to_facebook_page method on the service instance
|
||||
allow(service).to receive(:send_message_to_facebook)
|
||||
service.perform
|
||||
|
||||
# Now you can set expectations on the stubbed method for each attachment
|
||||
expect(service).to have_received(:send_message_to_facebook).exactly(:twice)
|
||||
end
|
||||
|
||||
it 'if message sent from chatwoot is failed' do
|
||||
message = create(:message, message_type: 'outgoing', inbox: facebook_inbox, account: account, conversation: conversation)
|
||||
allow(bot).to receive(:deliver).and_return({ error: { message: 'Invalid OAuth access token.', type: 'OAuthException', code: 190,
|
||||
|
||||
@@ -50,7 +50,25 @@ describe Instagram::SendOnInstagramService do
|
||||
|
||||
response = described_class.new(message: message).perform
|
||||
|
||||
expect(response).to eq({ message_id: 'anyrandommessageid1234567890' })
|
||||
expect(response).to eq({ message_id: 'anyrandommessageid1234567890' })
|
||||
end
|
||||
|
||||
it 'if message is sent from chatwoot and is outgoing with multiple attachments' do
|
||||
message = build(:message, content: nil, message_type: 'outgoing', inbox: instagram_inbox, account: account, conversation: conversation)
|
||||
avatar = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
avatar.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
||||
sample = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
sample.file.attach(io: Rails.root.join('spec/assets/sample.png').open, filename: 'sample.png', content_type: 'image/png')
|
||||
message.save!
|
||||
|
||||
service = described_class.new(message: message)
|
||||
|
||||
# Stub the send_to_facebook_page method on the service instance
|
||||
allow(service).to receive(:send_to_facebook_page)
|
||||
service.perform
|
||||
|
||||
# Now you can set expectations on the stubbed method for each attachment
|
||||
expect(service).to have_received(:send_to_facebook_page).exactly(:twice)
|
||||
end
|
||||
|
||||
it 'if message with attachment is sent from chatwoot and is outgoing' do
|
||||
|
||||
@@ -157,6 +157,7 @@ describe Line::IncomingMessageService do
|
||||
described_class.new(inbox: line_channel.inbox, params: params).perform
|
||||
expect(line_channel.inbox.conversations).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('LINE Test')
|
||||
expect(Contact.all.first.additional_attributes['social_line_user_id']).to eq('U4af4980629')
|
||||
expect(line_channel.inbox.messages.first.content).to eq('Hello, world')
|
||||
end
|
||||
end
|
||||
@@ -204,6 +205,7 @@ describe Line::IncomingMessageService do
|
||||
described_class.new(inbox: line_channel.inbox, params: image_params).perform
|
||||
expect(line_channel.inbox.conversations).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('LINE Test')
|
||||
expect(Contact.all.first.additional_attributes['social_line_user_id']).to eq('U4af4980629')
|
||||
expect(line_channel.inbox.messages.first.content).to be_nil
|
||||
expect(line_channel.inbox.messages.first.attachments.first.file_type).to eq('image')
|
||||
expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('media-354718.png')
|
||||
@@ -233,6 +235,7 @@ describe Line::IncomingMessageService do
|
||||
described_class.new(inbox: line_channel.inbox, params: video_params).perform
|
||||
expect(line_channel.inbox.conversations).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('LINE Test')
|
||||
expect(Contact.all.first.additional_attributes['social_line_user_id']).to eq('U4af4980629')
|
||||
expect(line_channel.inbox.messages.first.content).to be_nil
|
||||
expect(line_channel.inbox.messages.first.attachments.first.file_type).to eq('video')
|
||||
expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('media-354718.mp4')
|
||||
|
||||
@@ -65,6 +65,8 @@ describe Telegram::IncomingMessageService do
|
||||
described_class.new(inbox: telegram_channel.inbox, params: params).perform
|
||||
expect(telegram_channel.inbox.conversations.count).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('Sojan Jose')
|
||||
expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23)
|
||||
expect(Contact.all.first.additional_attributes['social_telegram_user_name']).to eq('sojan')
|
||||
expect(telegram_channel.inbox.messages.first.content).to eq('test')
|
||||
end
|
||||
end
|
||||
@@ -105,6 +107,8 @@ describe Telegram::IncomingMessageService do
|
||||
described_class.new(inbox: telegram_channel.inbox, params: params).perform
|
||||
expect(telegram_channel.inbox.conversations.count).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('Sojan Jose')
|
||||
expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23)
|
||||
expect(Contact.all.first.additional_attributes['social_telegram_user_name']).to eq('sojan')
|
||||
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('audio')
|
||||
end
|
||||
end
|
||||
@@ -277,6 +281,7 @@ describe Telegram::IncomingMessageService do
|
||||
described_class.new(inbox: telegram_channel.inbox, params: params).perform
|
||||
expect(telegram_channel.inbox.conversations.count).not_to eq(0)
|
||||
expect(Contact.all.first.name).to eq('Sojan Jose')
|
||||
expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(5_171_248)
|
||||
expect(telegram_channel.inbox.messages.first.content).to eq('Option 1')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3156,10 +3156,10 @@
|
||||
"@braid/vue-formulate-i18n" "^1.16.0"
|
||||
is-plain-object "^3.0.1"
|
||||
|
||||
"@chatwoot/prosemirror-schema@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@chatwoot/prosemirror-schema/-/prosemirror-schema-1.0.5.tgz#d6053692beae59d466ac0b04128fa157f59eb176"
|
||||
integrity sha512-dOzkZ2K53PPbE9AQB0RHlVs+GIEyHHdXeeW44dNSEuULwH99PmTpzA2r45QX3uaVa2j7Mip76AQbJZGKbM2fxg==
|
||||
"@chatwoot/prosemirror-schema@1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@chatwoot/prosemirror-schema/-/prosemirror-schema-1.0.7.tgz#5f681773330f8f0fa57a736d3e321b6a11f98124"
|
||||
integrity sha512-eIgBCeMjV0NEcH9NLbfuDHlLn8DQaCaJPuYlejRFJPQVxZEj6/KT9azwi1WPjOgoIZYrRc8ylaQGVVCX6hj5WQ==
|
||||
dependencies:
|
||||
markdown-it-sup "^1.0.0"
|
||||
prosemirror-commands "^1.1.4"
|
||||
@@ -3854,21 +3854,22 @@
|
||||
"@jridgewell/resolve-uri" "3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
||||
|
||||
"@june-so/analytics-next@^1.36.5":
|
||||
version "1.36.5"
|
||||
resolved "https://registry.yarnpkg.com/@june-so/analytics-next/-/analytics-next-1.36.5.tgz#030ba5a7f8fa232597185cdb706e40b7036ca7f8"
|
||||
integrity sha512-r2sp4VDngeX/ItQrlgmdKpmghg3OmPvhnTOKJ1huaHbFM2uPELpfnMRRngUVzbgbMoMeTf8QtgQVMjnUsl7G1A==
|
||||
"@june-so/analytics-next@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@june-so/analytics-next/-/analytics-next-2.0.0.tgz#979035ce812e768370d409c90b541ef238a3daa8"
|
||||
integrity sha512-7uFP94JLD7mP4qLyOwn5HBs+CC8VlevOkiGd1CIYqPSjSRmbCOI+MVcJNlTAcpyNvMi9iUnWZ3jGVO5177Di4A==
|
||||
dependencies:
|
||||
"@lukeed/uuid" "^2.0.0"
|
||||
"@segment/analytics-core" "1.2.2"
|
||||
"@segment/analytics.js-video-plugins" "^0.2.1"
|
||||
"@segment/facade" "3.4.7"
|
||||
"@segment/tsub" "^0.1.9"
|
||||
dset "^3.0.0"
|
||||
encoding "^0.1.13"
|
||||
js-cookie "^2.2.1"
|
||||
node-fetch "^2.6.1"
|
||||
"@segment/facade" "^3.4.9"
|
||||
"@segment/tsub" "1.0.1"
|
||||
dset "^3.1.2"
|
||||
js-cookie "3.0.1"
|
||||
node-fetch "^2.6.7"
|
||||
spark-md5 "^3.0.1"
|
||||
tslib "^2.1.0"
|
||||
tslib "^2.4.1"
|
||||
typescript "^4.9.5"
|
||||
unfetch "^4.1.0"
|
||||
|
||||
"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
|
||||
@@ -4068,6 +4069,15 @@
|
||||
resolved "https://registry.yarnpkg.com/@scmmishra/pico-search/-/pico-search-0.5.1.tgz#fe10a5615259623bff0095ad9af26e15d84379cb"
|
||||
integrity sha512-OKyoGy9f0Y47khEpgP3eLw2aKujJe/ndAE0IbovpsVh210GCmECtl8DLYKL+3abcorX3+e6K8S3eFs2HdH8Ksw==
|
||||
|
||||
"@segment/analytics-core@1.2.2":
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.2.2.tgz#46b1465181e089bd75890d37c68c58de36fa6c44"
|
||||
integrity sha512-zVWSDcyh7Rp32xL5v2fuEk2yZxxy+JA93vF1L3EF9XAYLSra/uEHJEswOWieXSdDHVRHes7APORp136usFE/tw==
|
||||
dependencies:
|
||||
"@lukeed/uuid" "^2.0.0"
|
||||
dset "^3.1.2"
|
||||
tslib "^2.4.1"
|
||||
|
||||
"@segment/analytics.js-video-plugins@^0.2.1":
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@segment/analytics.js-video-plugins/-/analytics.js-video-plugins-0.2.1.tgz#3596fa3887dcd9df5978dc566edf4a0aea2a9b1e"
|
||||
@@ -4075,14 +4085,13 @@
|
||||
dependencies:
|
||||
unfetch "^3.1.1"
|
||||
|
||||
"@segment/facade@3.4.7":
|
||||
version "3.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@segment/facade/-/facade-3.4.7.tgz#27e469189d45d5a2806d16571722e6b00d81429a"
|
||||
integrity sha512-Tj4aJsdmR9cl7xm7BT0NF9kYOnbIJ/3DdC1yOiLnjQRbHcnOq7WWkMDug/JCSEPF2loxGhG/oTeZybR3hpG3MA==
|
||||
"@segment/facade@^3.4.9":
|
||||
version "3.4.10"
|
||||
resolved "https://registry.yarnpkg.com/@segment/facade/-/facade-3.4.10.tgz#118fab29cf2250d3128f9b2a16d6ec76f86e3710"
|
||||
integrity sha512-xVQBbB/lNvk/u8+ey0kC/+g8pT3l0gCT8O2y9Z+StMMn3KAFAQ9w8xfgef67tJybktOKKU7pQGRPolRM1i1pdA==
|
||||
dependencies:
|
||||
"@segment/isodate-traverse" "^1.1.1"
|
||||
inherits "^2.0.4"
|
||||
klona "^2.0.5"
|
||||
new-date "^1.0.3"
|
||||
obj-case "0.2.1"
|
||||
|
||||
@@ -4098,10 +4107,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@segment/isodate/-/isodate-1.0.3.tgz#f44e8202d5edd277ce822785239474b2c9411d4a"
|
||||
integrity sha512-BtanDuvJqnACFkeeYje7pWULVv8RgZaqKHWwGFnL/g/TH/CcZjkIVTfGDp/MAxmilYHUkrX70SqwnYSTNEaN7A==
|
||||
|
||||
"@segment/tsub@^0.1.9":
|
||||
version "0.1.12"
|
||||
resolved "https://registry.yarnpkg.com/@segment/tsub/-/tsub-0.1.12.tgz#1c301a8b81e5dbda54eb0435ae808fbe65553f23"
|
||||
integrity sha512-35JB0+HuMZrn7mus/s4yOHAcuid+MzaOYxV8YAogTR4Z7AsHwn/Zn/y9XdoHp2kKdn54s6jO4IaO826v0j7qmw==
|
||||
"@segment/tsub@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@segment/tsub/-/tsub-1.0.1.tgz#4d7fad9eb84b354eec559020da7408fac3046b33"
|
||||
integrity sha512-rUpvlj/rRfOolk5rjwyrsbl0qzGLsaYgFNEiOSrwrWDryDPq1ZGdo+3Eb+E8+EC0yZOAO4F1DjJfLtaSifpx7w==
|
||||
dependencies:
|
||||
"@stdlib/math-base-special-ldexp" "^0.0.5"
|
||||
dlv "^1.1.3"
|
||||
@@ -10205,11 +10214,16 @@ dotenv@^8.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"
|
||||
integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==
|
||||
|
||||
dset@^3.0.0, dset@^3.1.1:
|
||||
dset@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a"
|
||||
integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==
|
||||
|
||||
dset@^3.1.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.3.tgz#c194147f159841148e8e34ca41f638556d9542d2"
|
||||
integrity sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==
|
||||
|
||||
duplexify@^3.4.2, duplexify@^3.6.0:
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
|
||||
@@ -10311,13 +10325,6 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
|
||||
|
||||
encoding@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
|
||||
dependencies:
|
||||
iconv-lite "^0.6.2"
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
@@ -12392,7 +12399,7 @@ iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@0.6.3, iconv-lite@^0.6.2:
|
||||
iconv-lite@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
@@ -13787,10 +13794,15 @@ js-beautify@^1.6.12:
|
||||
mkdirp "^1.0.4"
|
||||
nopt "^5.0.0"
|
||||
|
||||
js-cookie@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||
js-cookie@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
|
||||
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
|
||||
|
||||
js-cookie@^3.0.5:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
|
||||
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
|
||||
|
||||
js-string-escape@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -14046,11 +14058,6 @@ klona@^2.0.4:
|
||||
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
||||
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
||||
|
||||
klona@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc"
|
||||
integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==
|
||||
|
||||
language-subtag-registry@~0.3.2:
|
||||
version "0.3.21"
|
||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
||||
@@ -19807,7 +19814,7 @@ tslib@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
|
||||
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
|
||||
|
||||
tslib@^2.5.0, tslib@^2.6.0:
|
||||
tslib@^2.4.1, tslib@^2.5.0, tslib@^2.6.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||
@@ -19937,6 +19944,11 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@^4.9.5:
|
||||
version "4.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
|
||||
typeson-registry@^1.0.0-alpha.20:
|
||||
version "1.0.0-alpha.39"
|
||||
resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz#9e0f5aabd5eebfcffd65a796487541196f4b1211"
|
||||
|
||||
Reference in New Issue
Block a user