Telegram attached messages (#902)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-02-02 15:24:29 +06:00 committed by GitHub
parent a34150221b
commit fa3b298af9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 88 additions and 92 deletions

View File

@ -16,7 +16,7 @@
import type { IntlString } from '@anticrm/platform'
import { Builder, Model, TypeString, TypeBoolean, Prop, ArrOf } from '@anticrm/model'
import core, { TAttachedDoc, TDoc } from '@anticrm/model-core'
import core, { TAttachedDoc } from '@anticrm/model-core'
import contact from '@anticrm/model-contact'
import telegram from './plugin'
import type { TelegramMessage, SharedTelegramMessage, SharedTelegramMessages } from '@anticrm/telegram'
@ -30,17 +30,11 @@ function TypeSharedMessage (): Type<SharedTelegramMessage> {
return { _class: telegram.class.SharedMessage, label: 'Shared message' as IntlString }
}
@Model(telegram.class.Message, core.class.Doc, DOMAIN_TELEGRAM)
export class TTelegramMessage extends TDoc implements TelegramMessage {
@Model(telegram.class.Message, core.class.AttachedDoc, DOMAIN_TELEGRAM)
export class TTelegramMessage extends TAttachedDoc implements TelegramMessage {
@Prop(TypeString(), 'Content' as IntlString)
content!: string
@Prop(TypeString(), 'Phone' as IntlString)
contactPhone!: string
@Prop(TypeString(), 'User name' as IntlString)
contactUserName!: string
@Prop(TypeBoolean(), 'Incoming' as IntlString)
incoming!: boolean
}

View File

@ -1,5 +1,19 @@
{
"string": {
"SharedMessages": "shared Telegram messages"
"SharedMessages": "shared Telegram messages",
"Next": "Next",
"Back": "Back",
"Connect": "Connect",
"Connecting": "Connecting...",
"ConnectFull": "Connect Telegram account",
"Password": "Password",
"Phone": "Phone",
"PhonePlaceholder": "+1 555 333 7777",
"PhoneDescr": "Enter your Telegram phone number to connect your account.",
"PasswordDescr": "Enter your second factor password",
"CodeDescr": "Enter the 5-digit code you received on your Telegram account.",
"Cancel": "Cancel",
"Share": "Share messages",
"PublishSelected": "Publish selected"
}
}

View File

@ -14,45 +14,48 @@
// limitations under the License.
-->
<script lang="ts">
import { ReferenceInput } from '@anticrm/text-editor'
import { createQuery, getClient } from '@anticrm/presentation'
import telegram, { SharedTelegramMessage } from '@anticrm/telegram'
import type { TelegramMessage } from '@anticrm/telegram'
import { Channel, Contact, EmployeeAccount, formatName } from '@anticrm/contact'
import contact from '@anticrm/contact'
import { ActionIcon, IconShare, Button, ScrollBox, showPopup } from '@anticrm/ui'
import TelegramIcon from './icons/Telegram.svelte'
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
import setting from '@anticrm/setting'
import contact,{ Channel,Contact,EmployeeAccount,formatName } from '@anticrm/contact'
import { getCurrentAccount,Ref,SortingOrder,Space } from '@anticrm/core'
import login from '@anticrm/login'
import { getMetadata } from '@anticrm/platform'
import { createQuery,getClient } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import type { SharedTelegramMessage, TelegramMessage } from '@anticrm/telegram'
import { ReferenceInput } from '@anticrm/text-editor'
import { ActionIcon,Button,IconShare,ScrollBox,showPopup } from '@anticrm/ui'
import telegram from '../plugin'
import Connect from './Connect.svelte'
import TelegramIcon from './icons/Telegram.svelte'
import Messages from './Messages.svelte'
export let object: Contact
let channel: Channel | undefined = undefined
const client = getClient()
client.findOne(contact.class.Channel, {
attachedTo: object._id,
provider: contact.channelProvider.Telegram
}).then((res) => channel = res)
let messages: TelegramMessage[] = []
let account: EmployeeAccount | undefined
let accounts: EmployeeAccount[] = []
let enabled: boolean
let selected: Set<Ref<SharedTelegramMessage>> = new Set<Ref<SharedTelegramMessage>>()
let selectable = false
const url = getMetadata(login.metadata.TelegramUrl) ?? ''
const messagesQuery = createQuery()
const accauntQuery = createQuery()
const accauntsQuery = createQuery()
const settingsQuery = createQuery()
const accountId = getCurrentAccount()._id
$: query = channel && (channel.value.startsWith('+')
? { contactPhone: channel.value }
: { contactUserName: channel.value })
$: query && messagesQuery.query(telegram.class.Message, { modifiedBy: accountId, ...query }, (res) => {
$: channel && messagesQuery.query(telegram.class.Message, { modifiedBy: accountId, attachedTo: channel._id }, (res) => {
messages = res
})
}, { sort: { modifiedOn: SortingOrder.Ascending }})
$: accauntQuery.query(contact.class.EmployeeAccount, { _id: accountId as Ref<EmployeeAccount> }, (result) => {
account = result[0]
$: accountsIds = messages.map((p) => p.modifiedBy as Ref<EmployeeAccount>)
$: accauntsQuery.query(contact.class.EmployeeAccount, { _id: { $in: accountsIds }}, (result) => {
accounts = result
})
$: settingsQuery.query(
@ -62,12 +65,6 @@
enabled = res.length > 0
}
)
const client = getClient()
client.findOne(contact.class.Channel, {
attachedTo: object._id,
provider: contact.channelProvider.Telegram
}).then((res) => channel = res)
async function sendMsg (to: string, msg: string) {
return await fetch(url + '/send-msg', {
@ -124,20 +121,20 @@
await sendMsg(to, event.detail)
}
function getName (message: TelegramMessage, account: EmployeeAccount | undefined): string {
return message.incoming ? object.name : account?.name ?? ''
function getName (message: TelegramMessage, accounts: EmployeeAccount[]): string {
return message.incoming ? object.name : accounts.find((p) => p._id === message.modifiedBy)?.name ?? ''
}
async function share (): Promise<void> {
const selectedMessages = messages.filter((m) => selected.has(m._id as Ref<SharedTelegramMessage>))
const selectedMessages = messages.filter((m) => selected.has(m._id as unknown as Ref<SharedTelegramMessage>))
await client.addCollection(
telegram.class.SharedMessages,
object.space,
object._id,
object._class,
'telegramMessages',
'sharedTelegramMessages',
{
messages: convertMessages(selectedMessages)
messages: convertMessages(selectedMessages, accounts)
}
)
clear()
@ -149,12 +146,12 @@
selected = selected
}
function convertMessages (messages: TelegramMessage[]): SharedTelegramMessage[] {
function convertMessages (messages: TelegramMessage[], accounts: EmployeeAccount[]): SharedTelegramMessage[] {
return messages.map((m) => {
return {
...m,
_id: m._id as Ref<SharedTelegramMessage>,
sender: getName(m, account)
_id: m._id as unknown as Ref<SharedTelegramMessage>,
sender: getName(m, accounts)
}
})
}
@ -178,7 +175,7 @@
<ActionIcon
icon={IconShare}
size={'medium'}
label={'Share messages'}
label={telegram.string.Share}
direction={'bottom'}
action={async () => {
selectable = !selectable
@ -187,8 +184,8 @@
</div>
<div class="h-full right-content">
<ScrollBox vertical stretch>
{#if messages}
<Messages messages={convertMessages(messages)} {selectable} bind:selected />
{#if messages && accounts}
<Messages messages={convertMessages(messages, accounts)} {selectable} bind:selected />
{/if}
</ScrollBox>
</div>
@ -199,10 +196,10 @@
<span>{selected.size} messages selected</span>
<div class="flex">
<div>
<Button label={'Cancel'} size={'small'} on:click={clear} />
<Button label={telegram.string.Cancel} size={'small'} on:click={clear} />
</div>
<div class="ml-3">
<Button label={'Publish selected'} size={'small'} primary disabled={!selected.size} on:click={share} />
<Button label={telegram.string.PublishSelected} size={'small'} primary disabled={!selected.size} on:click={share} />
</div>
</div>
</div>
@ -211,7 +208,7 @@
{:else}
<div class="flex-center">
<Button
label={'Connect'}
label={telegram.string.Connect}
primary
on:click={(e) => {
showPopup(Connect, {}, e.target, onConnectClose)

View File

@ -18,6 +18,7 @@
import { createEventDispatcher } from 'svelte'
import login from '@anticrm/login'
import PinPad from './PinPad.svelte'
import telegram from '../plugin'
const dispatch = createEventDispatcher()
@ -89,7 +90,7 @@
secondFactor = false
}
$: label = connecting ? 'Connecting...' : requested || secondFactor ? 'Connect' : 'Next'
$: label = connecting ? telegram.string.Connecting : requested || secondFactor ? telegram.string.Connect : telegram.string.Next
$: disabled = checkDisabled(connecting, secondFactor, password, requested, error, code, phone)
@ -120,7 +121,7 @@
<div class="card">
<div class="flex-between header">
<div class="overflow-label fs-title"><Label label={'Connect Telegram account'} /></div>
<div class="overflow-label fs-title"><Label label={telegram.string.ConnectFull} /></div>
<div
class="tool"
on:click={() => {
@ -132,19 +133,19 @@
</div>
<div class="content">
{#if secondFactor}
<p><Label label={'Enter your second factor password'} /></p>
<EditBox label={'Password'} password placeholder={'password'} bind:value={password} />
<p><Label label={telegram.string.PasswordDescr} /></p>
<EditBox label={telegram.string.Password} maxWidth="10rem" password placeholder={telegram.string.Password} bind:value={password} />
{:else if requested}
<p><Label label={'Enter the 5-digit code you received on your Telegram account.'} /></p>
<p><Label label={telegram.string.CodeDescr} /></p>
<PinPad length={5} bind:value={code} bind:error />
{:else}
<p><Label label={'Enter your Telegram phone number to connect your account.'} /></p>
<EditBox label={'Phone number'} placeholder={'+1 555 333 7777'} bind:value={phone} />
<p><Label label={telegram.string.PhoneDescr} /></p>
<EditBox label={telegram.string.Phone} maxWidth="10rem" placeholder={telegram.string.PhonePlaceholder} bind:value={phone} />
{/if}
<div class="footer">
<Button {label} primary {disabled} on:click={click} />
{#if requested || secondFactor}
<a class="link" href={'#'} on:click={back}><Label label={'Back'} /></a>
<a class="link" href={'#'} on:click={back}><Label label={telegram.string.Back} /></a>
{/if}
</div>
</div>

View File

@ -13,9 +13,9 @@
// limitations under the License.
-->
<script lang="ts">
import type { TelegramMessage } from '@anticrm/telegram'
import type { SharedTelegramMessage } from '@anticrm/telegram'
export let message: TelegramMessage
export let message: SharedTelegramMessage
</script>
<div class="datetime-container">

View File

@ -19,39 +19,13 @@
import { formatName } from '@anticrm/contact'
import { CheckBox } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import { getPlatformColorForText } from '@anticrm/ui'
export let message: SharedTelegramMessage
export let showName: boolean = false
export let selected: boolean = false
export let selectable: boolean = false
export let colors: string[] = [
'#A5D179',
'#77C07B',
'#60B96E',
'#45AEA3',
'#46CBDE',
'#47BDF6',
'#5AADF6',
'#73A6CD',
'#B977CB',
'#7C6FCD',
'#6F7BC5',
'#F28469'
]
function getNameColor (name: string): string {
let hash = 0
let i
let chr
for (i = 0; i < name.length; i++) {
chr = name.charCodeAt(i)
hash = (hash << 5) - hash + chr
hash |= 0
}
return colors[Math.abs(hash) % colors.length]
}
const dispatch = createEventDispatcher()
</script>
@ -65,7 +39,7 @@
<div class="flex-grow ml-6 flex" class:mr-6={!selectable} class:justify-end={!message.incoming}>
<div class="message" class:outcoming={!message.incoming} class:selected>
{#if showName}
<div class="name" style="color: {getNameColor(message.sender)}">{formatName(message.sender)}</div>
<div class="name" style="color: {getPlatformColorForText(message.sender)}">{formatName(message.sender)}</div>
{/if}
<div class="flex">
<div class="caption-color mr-4"><MessageViewer message={message.content} /></div>
@ -87,6 +61,7 @@
width: fit-content;
background-color: var(--theme-incoming-msg);
border-radius: 0.75rem;
overflow-wrap: anywhere;
&.outcoming {
background-color: var(--theme-outcoming-msg);

View File

@ -14,8 +14,25 @@
// limitations under the License.
//
import { mergeIds } from '@anticrm/platform'
import { IntlString, mergeIds } from '@anticrm/platform'
import telegram, { telegramId } from '@anticrm/telegram'
export default mergeIds(telegramId, telegram, {})
export default mergeIds(telegramId, telegram, {
string: {
Next: '' as IntlString,
Back: '' as IntlString,
Connect: '' as IntlString,
Connecting: '' as IntlString,
ConnectFull: '' as IntlString,
Password: '' as IntlString,
Phone: '' as IntlString,
PhonePlaceholder: '' as IntlString,
PhoneDescr: '' as IntlString,
PasswordDescr: '' as IntlString,
CodeDescr: '' as IntlString,
Cancel: '' as IntlString,
Share: '' as IntlString,
PublishSelected: '' as IntlString
}
})

View File

@ -22,11 +22,9 @@ import type { IntegrationType, Handler } from '@anticrm/setting'
/**
* @public
*/
export interface TelegramMessage extends Doc {
export interface TelegramMessage extends AttachedDoc {
content: string
incoming: boolean
contactPhone?: string
contactUserName?: string
}
/**