Skip to content

Commit

Permalink
✨ support TickTick
Browse files Browse the repository at this point in the history
  • Loading branch information
DiamondYuan committed Feb 1, 2020
1 parent c84eae1 commit 2f1a823
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 0 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"image",
"option",
"repos",
"ticktick",
"yuque"
],
"typescript.tsdk": "node_modules/typescript/lib",
Expand Down
45 changes: 45 additions & 0 deletions src/common/backend/services/ticktick/headerForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Form, Select } from 'antd';
import { FormComponentProps } from 'antd/lib/form';
import React, { Fragment } from 'react';
import backend from '../..';
import Dida365DocumentService from './service';
import locale from '@/common/locales';
import { useFetch } from '@shihengtech/hooks';

const HeaderForm: React.FC<FormComponentProps> = ({ form: { getFieldDecorator } }) => {
const service = backend.getDocumentService() as Dida365DocumentService;
const tagsResponse = useFetch(async () => service.getTags(), [service], {
initialState: {
data: [],
},
});

return (
<Fragment>
<Form.Item>
{getFieldDecorator('tags', {
initialValue: [],
})(
<Select
mode="tags"
maxTagCount={3}
style={{ width: '100%' }}
placeholder={locale.format({
id: 'backend.services.dida365.headerForm.applyTags',
defaultMessage: 'Apply tags',
})}
loading={tagsResponse.loading}
>
{tagsResponse.data?.map(o => (
<Select.Option key={o} value={o} title={o}>
{o}
</Select.Option>
))}
</Select>
)}
</Form.Item>
</Fragment>
);
};

export default HeaderForm;
21 changes: 21 additions & 0 deletions src/common/backend/services/ticktick/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import localeService from '@/common/locales';
import { ServiceMeta } from '@/common/backend';
import Service from './service';
import headerForm from './headerForm';

export default (): ServiceMeta => {
return {
name: localeService.format({
id: 'backend.services.ticktick.name',
defaultMessage: 'TickTick',
}),
icon: 'dida365',
type: 'ticktick',
headerForm,
service: Service,
permission: {
origins: ['https://api.ticktick.com/*'],
permissions: ['webRequest', 'webRequestBlocking'],
},
};
};
170 changes: 170 additions & 0 deletions src/common/backend/services/ticktick/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import { Container } from 'typedi';
import { generateUuid } from '@web-clipper/shared/lib/uuid';
import localeService from '@/common/locales';
import { IWebRequestService } from '@/service/common/webRequest';
import {
CreateDocumentRequest,
CompleteStatus,
UnauthorizedError,
Repository,
} from '@/common/backend/services/interface';
import { DocumentService } from '@/common/backend/index';
import { extend, RequestMethod } from 'umi-request';

interface TickTickProfile {
name: string;
username: string;
picture: string;
}

interface TickTickCheckResponse {
projectProfiles: {
id: string;
name: string;
isOwner: boolean;
closed: boolean;
groupId: string;
}[];
projectGroups: {
id: string;
name: string;
}[];
tags: {
name: string;
}[];
}
interface TickTickCreateDocumentRequest extends CreateDocumentRequest {
tags: string[];
}

export default class TickTickDocumentService implements DocumentService {
private request: RequestMethod;

constructor() {
const request = extend({
prefix: `https://api.ticktick.com/api/v2/`,
});
request.interceptors.response.use(
response => {
if (response.clone().status === 401) {
throw new UnauthorizedError(
localeService.format({
id: 'backend.services.ticktick.unauthorizedErrorMessage',
defaultMessage: 'Unauthorized! Please Login TickTick Web.',
})
);
}
return response;
},
{ global: false }
);

this.request = request;
}

getId = () => {
return 'TickTick';
};

getUserInfo = async () => {
const response = await this.request.get<TickTickProfile>('user/profile');
return {
name: response.name,
avatar: response.picture,
homePage: '',
description: response.username,
};
};

getTags = async (): Promise<string[]> => {
const TickTickCheckResponse = await this.request.get<TickTickCheckResponse>(`batch/check/0`);
return TickTickCheckResponse.tags.map(o => o.name);
};

getRepositories = async (): Promise<Repository[]> => {
const TickTickCheckResponse = await this.request.get<TickTickCheckResponse>(`batch/check/0`);
const groupMap = new Map<string, string>();
TickTickCheckResponse.projectGroups.forEach(group => {
groupMap.set(group.id, group.name);
});
return TickTickCheckResponse.projectProfiles
.filter(o => !o.closed)
.map(({ id, name, groupId }) => ({
id: id,
name: name,
groupId: groupId
? groupId
: localeService.format({
id: 'backend.services.ticktick.rootGroup',
defaultMessage: 'Root',
}),
groupName: groupId
? groupMap.get(groupId)!
: localeService.format({
id: 'backend.services.ticktick.rootGroup',
defaultMessage: 'Root',
}),
}));
};

createDocument = async (request: TickTickCreateDocumentRequest): Promise<CompleteStatus> => {
const webRequestService = Container.get(IWebRequestService);

const header = await webRequestService.startChangeHeader({
urls: ['https://api.ticktick.com/*'],
requestHeaders: [
{
name: 'origin',
value: 'https://ticktick.com',
},
],
});

const settings = await this.request.get<{ timeZone: string }>(
'user/preferences/settings?includeWeb=true'
);

const id = generateUuid()
.replace(/-/g, '')
.slice(0, 24);
const data = {
add: [
{
items: [],
reminders: [],
exDate: [],
dueDate: null,
priority: 0,
progress: 0,
assignee: null,
sortOrder: -4611733297427382000,
startDate: null,
isFloating: false,
status: 0,
deleted: 0,
tags: request.tags,
projectId: request.repositoryId,
title: request.title,
content: request.content,
timeZone: settings.timeZone,
id: id,
},
],
update: [],
delete: [],
};

await this.request.post('batch/task', {
data: data,
headers: {
[header.name]: header.value,
},
});

await webRequestService.end(header);

return {
href: `https://ticktick.com/#p/${request.repositoryId}/tasks/${id}`,
};
};
}
4 changes: 4 additions & 0 deletions src/common/locales/data/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"backend.services.onenote_oauth.name": "",
"backend.services.server_chan.accessToken.message": "",
"backend.services.server_chan.name": "",
"backend.services.ticktick.headerForm.applyTags": "",
"backend.services.ticktick.name": "",
"backend.services.ticktick.rootGroup": "",
"backend.services.ticktick.unauthorizedErrorMessage": "",
"backend.services.youdao.name": "Youdao",
"backend.services.youdao.unauthorizedErrorMessage": "",
"backend.services.yuque_oauth.name": "",
Expand Down
4 changes: 4 additions & 0 deletions src/common/locales/data/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"backend.services.onenote_oauth.name": "",
"backend.services.server_chan.accessToken.message": "",
"backend.services.server_chan.name": "",
"backend.services.ticktick.headerForm.applyTags": "",
"backend.services.ticktick.name": "",
"backend.services.ticktick.rootGroup": "",
"backend.services.ticktick.unauthorizedErrorMessage": "",
"backend.services.youdao.name": "",
"backend.services.youdao.unauthorizedErrorMessage": "",
"backend.services.yuque_oauth.name": "",
Expand Down
4 changes: 4 additions & 0 deletions src/common/locales/data/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"backend.services.onenote_oauth.name": "",
"backend.services.server_chan.accessToken.message": "",
"backend.services.server_chan.name": "",
"backend.services.ticktick.headerForm.applyTags": "",
"backend.services.ticktick.name": "",
"backend.services.ticktick.rootGroup": "",
"backend.services.ticktick.unauthorizedErrorMessage": "",
"backend.services.youdao.name": "",
"backend.services.youdao.unauthorizedErrorMessage": "",
"backend.services.yuque_oauth.name": "",
Expand Down
4 changes: 4 additions & 0 deletions src/common/locales/data/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"backend.services.onenote_oauth.name": "",
"backend.services.server_chan.accessToken.message": "",
"backend.services.server_chan.name": "",
"backend.services.ticktick.headerForm.applyTags": "",
"backend.services.ticktick.name": "",
"backend.services.ticktick.rootGroup": "",
"backend.services.ticktick.unauthorizedErrorMessage": "",
"backend.services.youdao.name": "",
"backend.services.youdao.unauthorizedErrorMessage": "",
"backend.services.yuque_oauth.name": "",
Expand Down
4 changes: 4 additions & 0 deletions src/common/locales/data/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"backend.services.onenote_oauth.name": "One Note",
"backend.services.server_chan.accessToken.message": "请输入 AccessToken",
"backend.services.server_chan.name": "Server酱",
"backend.services.ticktick.headerForm.applyTags": "选择标签",
"backend.services.ticktick.name": "TickTick",
"backend.services.ticktick.rootGroup": "根目录",
"backend.services.ticktick.unauthorizedErrorMessage": "授权失败,请登录网页版 TickTick。",
"backend.services.youdao.name": "有道云笔记",
"backend.services.youdao.unauthorizedErrorMessage": "授权失败,请登录网页版有道云笔记。",
"backend.services.yuque_oauth.name": "语雀(一键授权)",
Expand Down

0 comments on commit 2f1a823

Please sign in to comment.