Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #136 from mgilangjanuar/staging
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
mgilangjanuar authored Dec 11, 2021
2 parents 39b93c3 + da347c9 commit 4c515f4
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "teledrive",
"version": "0.1.0",
"version": "1.0.0",
"repository": "git@github.com:mgilangjanuar/teledrive.git",
"author": "M Gilang Januar <mgilangjanuar@gmail.com>",
"license": "MIT",
Expand Down
Binary file not shown.
Binary file not shown.
6 changes: 3 additions & 3 deletions server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "server",
"version": "0.1.0",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"private": true,
Expand All @@ -9,7 +9,7 @@
"build": "rimraf dist && eslint --fix -c .eslintrc.js --ext .ts . && tsc"
},
"dependencies": {
"@mgilangjanuar/telegram": "2.0.9",
"@mgilangjanuar/telegram": "2.0.11",
"@sentry/node": "^6.14.1",
"@sentry/tracing": "^6.14.1",
"@types/moment": "^2.13.0",
Expand Down Expand Up @@ -76,4 +76,4 @@
"rimraf": "^3.0.2",
"typescript": "^4.4.2"
}
}
}
4 changes: 4 additions & 0 deletions server/src/api/v1/Files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ export class Files {
key = AES.encrypt(JSON.stringify({ file: { id: file.id }, session: req.tg.session.save() }), process.env.FILES_JWT_SECRET).toString()
}

if (!file.sharing_options?.length && !currentFile.sharing_options?.length) {
key = null
}

const { affected } = await Model.createQueryBuilder('files')
.update({
...file.name ? { name: file.name } : {},
Expand Down
57 changes: 51 additions & 6 deletions server/src/api/v1/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,47 @@ export class Messages {
return res.send({ messages: result })
}

@Endpoint.GET('/sponsoredMessages/:type/:id', { middlewares: [Auth] })
public async sponsoredMessages(req: Request, res: Response): Promise<any> {
const { type, id } = req.params
const { accessHash } = req.query

let peer: Api.InputPeerChannel
if (type === 'channel') {
peer = new Api.InputPeerChannel({
channelId: bigInt(id),
accessHash: bigInt(accessHash as string) })
} else {
return res.send({ messages: {
messages: [],
chats: [],
users: []
} })
}
const messages = await req.tg.invoke(new Api.channels.GetSponsoredMessages({ channel: peer }))
return res.send({ messages })
}

@Endpoint.POST('/readSponsoredMessages/:type/:id', { middlewares: [Auth] })
public async readSponsoredMessages(req: Request, res: Response): Promise<any> {
const { type, id } = req.params
const { accessHash } = req.query
const { random_id: randomId } = req.body

let peer: Api.InputPeerChannel
if (type === 'channel') {
peer = new Api.InputPeerChannel({
channelId: bigInt(id),
accessHash: bigInt(accessHash as string) })
} else {
return res.status(202).send({ accepted: true })
}
const accepted = await req.tg.invoke(new Api.channels.ViewSponsoredMessage({
channel: peer, randomId: Buffer.from(randomId)
}))
return res.status(202).send({ accepted })
}

@Endpoint.POST('/read/:type/:id', { middlewares: [Auth] })
public async read(req: Request, res: Response): Promise<any> {
const { type, id } = req.params
Expand Down Expand Up @@ -155,19 +196,21 @@ export class Messages {
@Endpoint.POST('/forward/:msgId', { middlewares: [Auth] })
public async forward(req: Request, res: Response): Promise<any> {
const { msgId } = req.params
const { from, to } = req.body as { from: {
const { from, to } = req.body as { from?: {
type: string,
id: number,
accessHash?: string
}, to: {
type: string,
id: number,
accessHash?: string
} }
} | string }

let fromPeer: Api.InputPeerChannel | Api.InputPeerUser | Api.InputPeerChat
let toPeer: Api.InputPeerChannel | Api.InputPeerUser | Api.InputPeerChat
if (from.type === 'channel') {
let fromPeer: Api.InputPeerChannel | Api.InputPeerUser | Api.InputPeerChat | 'me'
let toPeer: Api.InputPeerChannel | Api.InputPeerUser | Api.InputPeerChat | string
if (!from) {
fromPeer = 'me'
} else if (from.type === 'channel') {
fromPeer = new Api.InputPeerChannel({
channelId: bigInt(from.id),
accessHash: bigInt(from.accessHash as string) })
Expand All @@ -181,7 +224,9 @@ export class Messages {
accessHash: bigInt(from.accessHash as string) })
}

if (to.type === 'channel') {
if (typeof to === 'string') {
toPeer = to
} else if (to.type === 'channel') {
toPeer = new Api.InputPeerChannel({
channelId: bigInt(to.id),
accessHash: bigInt(to.accessHash as string) })
Expand Down
22 changes: 22 additions & 0 deletions upgrade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const fs = require('fs')
const { execSync } = require('child_process')

const root = fs.readFileSync('./package.json', 'utf-8')
const rootObj = JSON.parse(root)
rootObj.version = process.argv[2]
fs.writeFileSync('./package.json', JSON.stringify(rootObj, null, 2))

const api = fs.readFileSync('./server/package.json', 'utf-8')
const apiObj = JSON.parse(api)
apiObj.version = process.argv[2]
fs.writeFileSync('./server/package.json', JSON.stringify(apiObj, null, 2))
// execSync('cd ./server && yarn install && cd ..')

const web = fs.readFileSync('./web/package.json', 'utf-8')
const webObj = JSON.parse(web)
webObj.version = process.argv[2]
fs.writeFileSync('./web/package.json', JSON.stringify(webObj, null, 2))
// execSync('cd ./web && yarn install && cd ..')

execSync('yarn install && yarn workspaces run build')
execSync(`git add . && git commit -m "${process.argv[2]}"`)
4 changes: 2 additions & 2 deletions web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "web",
"version": "0.1.0",
"version": "1.0.0",
"private": true,
"dependencies": {
"@craco/craco": "^6.3.0",
Expand Down Expand Up @@ -87,4 +87,4 @@
"workbox-strategies": "^5.1.3",
"workbox-streams": "^5.1.3"
}
}
}
39 changes: 32 additions & 7 deletions web/src/pages/dashboard/components/Messaging.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const Messaging: React.FC<Props> = ({ me, collapsed, parent, setCollapsed }) =>
}, [messageHistory])

useEffect(() => {
const setDataMessages = (dialog?: any) => {
const setDataMessages = (dialog?: any, sponsoredMessages?: { messages: any[], chats: any[], users: any[] }) => {
setMessagesParsed(messages?.messages.reduce((res: any[], msg: any) => {
let user = messages?.users.find((user: any) => user.id === (msg.fromId || msg.peerId)?.userId)
if (!user) {
Expand Down Expand Up @@ -197,16 +197,41 @@ const Messaging: React.FC<Props> = ({ me, collapsed, parent, setCollapsed }) =>
} : undefined
} : null
]
}, []).filter(Boolean).sort((a: any, b: any) => a.date - b.date) || [])
}, sponsoredMessages?.messages?.map((msg: any) => {
let user = sponsoredMessages?.users.find((user: any) => user.id === (msg.fromId || msg.peerId)?.userId)
if (!user) {
user = sponsoredMessages?.chats.find((user: any) => user.id === (msg.fromId || msg.peerId)?.channelId)
}
return {
id: `${message?.id.replace(/\?.*$/gi, '')}/sponsor`,
messageId: message?.id,
key: 'sponsor',
position: 'left',
type: 'text',
// status: me?.user.tg_id == user?.id ? msg.id <= dialog?.dialog?.readOutboxMaxId ? 'read' : 'received' : undefined,
title: user ? user.title || `${user.firstName || ''} ${user.lastName || ''}`.trim() : 'Unknown',
text: <ReactMarkdown className="messageItem" remarkPlugins={[remarkGfm]}>{msg.message ? `${msg.message.replaceAll('\n', ' \n')}\n\n_(sponsored message)_` : 'Unknown message'}</ReactMarkdown>,
message: msg.message,
fwdFrom: msg.fwdFrom,
date: new Date().getTime(),
titleColor: `#${`${user?.id.toString(16)}000000`.slice(0, 6)}`,
user
}
}) || []).filter(Boolean).sort((a: any, b: any) => a.date - b.date) || [])
// messageList.current?.scrollToRow = 50
}
if (message) {
req.get(`/dialogs/${message.id}`).then(({ data }) => {
setDataMessages(data.dialog)
// const sidebar = document.querySelector('.ant-layout-sider.ant-layout-sider-light.messaging')
// if (sidebar) {
// sidebar.scroll({ top: sidebar.scrollHeight, behavior: 'smooth' })
// }
req.get(`/messages/sponsoredMessages/${message.id}`).then(({ data: sponsoredData }) => {
setDataMessages(data.dialog, sponsoredData?.messages)
sponsoredData.messages?.messages.map((msg: any) => req.post(`/messages/readSponsoredMessages/${message.id}`, { random_id: msg.randomId?.data }))
// const sidebar = document.querySelector('.ant-layout-sider.ant-layout-sider-light.messaging')
// if (sidebar) {
// sidebar.scroll({ top: sidebar.scrollHeight, behavior: 'smooth' })
// }
}).catch(_ => {
setDataMessages(data.dialog)
})
})
} else {
setDataMessages()
Expand Down
88 changes: 63 additions & 25 deletions web/src/pages/dashboard/components/Share.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CopyOutlined, InfoCircleOutlined, LinkOutlined, MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
import { ArrowRightOutlined, CopyOutlined, InfoCircleOutlined, LinkOutlined, MinusCircleOutlined, PlusOutlined, WarningOutlined } from '@ant-design/icons'
import { AutoComplete, Button, Col, Divider, Empty, Form, Input, message, Modal, notification, Row, Spin, Switch, Typography } from 'antd'
import { useForm } from 'antd/lib/form/Form'
import * as clipboardy from 'clipboardy'
Expand All @@ -10,7 +10,7 @@ interface Props {
me: any,
dataSource?: [any[], (data: any[]) => void],
onFinish?: () => void,
dataSelect: [any, (data: any) => void]
dataSelect: [{ row: any, action: string }, (data?: { row: any, action: string }) => void]
}

const Share: React.FC<Props> = ({
Expand Down Expand Up @@ -41,15 +41,16 @@ const Share: React.FC<Props> = ({

useEffect(() => {
if (selectShare) {
const isPublic = (selectShare.sharing_options || [])?.includes('*')
const isPublic = (selectShare.row.sharing_options || [])?.includes('*')
setIsPublic(isPublic)
setSharingOptions(selectShare.sharing_options)
setSharingOptions(selectShare.row.sharing_options)
formShare.setFieldsValue({
id: selectShare.id,
id: selectShare.row.id,
message: 'Hey, please check this out! 👆',
public: isPublic,
sharing_options: selectShare.sharing_options?.length ? selectShare.sharing_options.filter((opt: string) => opt !== '*') : [''],
link: selectShare.type === 'folder' ? `${window.location.origin}/dashboard/shared?parent=${selectShare.id}` : `${window.location.origin}/view/${selectShare.id}`
sharing_options: selectShare.row.sharing_options?.length ? selectShare.row.sharing_options.filter((opt: string) => opt !== '*') : [''],
link: selectShare.row.type === 'folder' ? `${window.location.origin}/dashboard/shared?parent=${selectShare.row.id}` : `${window.location.origin}/view/${selectShare.row.id}`,
username: null
})
} else {
formShare.resetFields()
Expand All @@ -58,17 +59,36 @@ const Share: React.FC<Props> = ({

const share = async () => {
setLoadingShare(true)
const { id, public: isPublic, sharing_options: sharingOpts } = formShare.getFieldsValue()
const { id, public: isPublic, sharing_options: sharingOpts, username } = formShare.getFieldsValue()

const sharing = [
const sharing = sharingOpts?.length ? [
...new Set([...sharingOpts === undefined ? sharingOptions : sharingOpts, isPublic ? '*' : null]
.filter(sh => isPublic ? sh : sh !== '*').filter(Boolean)) as any
]
] : []
setSharingOptions(sharing)

try {
await req.patch(`/files/${id}`, { file: { sharing_options: sharing } })
dataSource?.[1](dataSource?.[0].map(file => file.id === id ? { ...file, sharing_options: sharing } : file))
if (selectShare?.action === 'share') {
await req.patch(`/files/${id}`, { file: { sharing_options: sharing } })
dataSource?.[1](dataSource?.[0].map(file => file.id === id ? { ...file, sharing_options: sharing } : file))
} else {
const [type, peerId, _id, accessHash] = selectShare.row.forward_info?.split('/') || [null, null, null, null]
await req.post(`/messages/forward/${selectShare.row.message_id}`, {
...selectShare.row.forward_info ? {
from: {
id: peerId,
type,
accessHash
}
} : {},
to: username
})
notification.success({
message: 'Success',
description: `${selectShare?.row.name} sent to @${username} successfully`
})
formShare.setFieldsValue({ username: null })
}
} catch (error: any) {
if (error?.response?.status === 402) {
notification.error({
Expand All @@ -77,6 +97,7 @@ const Share: React.FC<Props> = ({
})
setSelectShare(undefined)
}
setLoadingShare(false)
}
setLoadingShare(false)
onFinish?.()
Expand All @@ -87,21 +108,21 @@ const Share: React.FC<Props> = ({
return message.info('Copied!')
}

return <Modal visible={selectShare}
return <Modal visible={selectShare?.row}
onCancel={() => setSelectShare(undefined)}
footer={null}
title={`Share ${selectShare?.name}`}>
<Form form={formShare} layout="horizontal">
title={`${selectShare?.action === 'share' ? 'Share' : 'Send'} ${selectShare?.row.name}`}>
<Form form={formShare} layout="horizontal" onFinish={share}>
<Form.Item name="id" hidden>
<Input />
</Form.Item>
{selectShare?.type !== 'folder' ? <Form.Item name="public" label="Make public">
{selectShare?.row.type !== 'folder' && selectShare?.action === 'share' ? <Form.Item name="public" label="Make public">
<Switch checked={isPublic} onClick={val => {
setIsPublic(val)
share()
}} />
</Form.Item> : ''}
{!isPublic && <Form.List name="sharing_options">
{!isPublic && selectShare?.action === 'share' && <Form.List name="sharing_options">
{(fields, { add, remove }) => <>
{fields.map((field, i) => <Row gutter={14} key={i}>
<Col span={22}>
Expand All @@ -126,16 +147,33 @@ const Share: React.FC<Props> = ({
</Form.Item>
</>}
</Form.List>}
{selectShare?.action === 'forward' && <>
<Form.Item rules={[{ required: true, message: 'Username is required' }]} name="username">
<AutoComplete notFoundContent={<Empty />} options={users?.map((user: any) => ({ value: user.username }))}>
<Input placeholder="username" prefix="@" onChange={e => setUsername(e.target.value)} />
</AutoComplete>
</Form.Item>
<Form.Item style={{ textAlign: 'right' }}>
<Button htmlType="submit" shape="round" loading={loadingShare} icon={<ArrowRightOutlined />}>Send</Button>
</Form.Item>
</>}
{selectShare?.action === 'share' && <Typography.Paragraph type="secondary">
<WarningOutlined /> Your encrypted session will be saved for downloading this file
</Typography.Paragraph>}
<Divider />
<Spin spinning={loadingShare}>
<Typography.Paragraph type="secondary">
<InfoCircleOutlined /> You are shared {isPublic ? 'with anyone.' :
`with ${formShare.getFieldValue('sharing_options')?.[0] || 'no one'}
${formShare.getFieldValue('sharing_options')?.filter(Boolean).length > 1 ? ` and ${formShare.getFieldValue('sharing_options')?.filter(Boolean).length - 1} people` : ''}`}
</Typography.Paragraph>
{sharingOptions?.[0] ? <Form.Item label={<><LinkOutlined /> &nbsp;Share URL</>} name="link">
<Input.Search readOnly contentEditable={false} enterButton={<CopyOutlined />} onSearch={copy} />
</Form.Item> : ''}
{selectShare?.action === 'share' ? <>
<Typography.Paragraph type="secondary">
<InfoCircleOutlined /> You are shared {isPublic ? 'with anyone.' :
`with ${formShare.getFieldValue('sharing_options')?.[0] || 'no one'}
${formShare.getFieldValue('sharing_options')?.filter(Boolean).length > 1 ? ` and ${formShare.getFieldValue('sharing_options')?.filter(Boolean).length - 1} people` : ''}`}
</Typography.Paragraph>
{sharingOptions?.[0] ? <Form.Item label={<><LinkOutlined /> &nbsp;Share URL</>} name="link">
<Input.Search readOnly contentEditable={false} enterButton={<CopyOutlined />} onSearch={copy} />
</Form.Item> : ''}
</> : <Typography.Paragraph type="secondary">
<InfoCircleOutlined /> You will send this file to the user directly
</Typography.Paragraph>}
</Spin>
</Form>
</Modal>
Expand Down
Loading

0 comments on commit 4c515f4

Please sign in to comment.