Skip to content

Commit

Permalink
Merge pull request #72 from Meta-Network/dev/xiaotian
Browse files Browse the repository at this point in the history
feat: optimization sync draft, support generate seed pair
  • Loading branch information
meta-network-team authored Dec 22, 2021
2 parents 6d19cf4 + a1b2ab6 commit e039805
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 228 deletions.
5 changes: 5 additions & 0 deletions src/components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ const Editor: React.FC<Props> = React.memo(function Editor({ asyncContentToDB })
}, []);

const init = useCallback(() => {
const _height =
window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

const vditor = new Vditor('vditor', {
width: '100%',
height: _height - 206,
cache: {
enable: false,
},
Expand Down
18 changes: 0 additions & 18 deletions src/db/Posts.d.ts

This file was deleted.

15 changes: 7 additions & 8 deletions src/db/db.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Table, Transaction } from 'dexie';
import Dexie from 'dexie';
import type { Posts } from './Posts';
import type { Metadatas, MetadataTempDataState } from './Metadatas';
import moment from 'moment';
import { License } from '../../config';

export class StoreDB extends Dexie {
posts!: Table<Posts, number>;
posts!: Table<PostType.Posts, number>;
metadatas!: Table<Metadatas, number>;
constructor() {
super('StoreDB');
Expand All @@ -19,7 +18,7 @@ export class StoreDB extends Dexie {
.upgrade((tx: Transaction | any) => {
const time = moment().toISOString();
// TODO: modify typescript
tx.posts.toCollection().modify((post: Posts) => {
tx.posts.toCollection().modify((post: PostType.Posts) => {
// console.log('post', post);
post.cover = post.cover || '';
post.title = post.title || '';
Expand Down Expand Up @@ -62,7 +61,7 @@ export const dbPostsUpdate = async <T>(id: number, data: T): Promise<number> =>
* @param data
* @returns
*/
export const dbPostsAdd = async (data: Posts): Promise<number> => {
export const dbPostsAdd = async (data: PostType.Posts): Promise<number> => {
return await db.posts.add(data);
};

Expand All @@ -71,7 +70,7 @@ export const dbPostsAdd = async (data: Posts): Promise<number> => {
* @param id
* @returns
*/
export const dbPostsGet = async (id: number): Promise<Posts | undefined> => {
export const dbPostsGet = async (id: number): Promise<PostType.Posts | undefined> => {
return await db.posts.get(id);
};

Expand All @@ -95,7 +94,7 @@ export const dbPostsDeleteAll = async (): Promise<number> => {
* @param userId
* @returns
*/
export const dbPostsAll = async (userId: number): Promise<Posts[] | undefined> => {
export const dbPostsAll = async (userId: number): Promise<PostType.Posts[] | undefined> => {
return await db.posts
.filter((i) => !i.delete && i.userId === userId)
.reverse()
Expand All @@ -122,14 +121,14 @@ export const dbPostsWhereExist = async (id: number): Promise<boolean> => {
return result.some((post) => post.post && Number(post.post.id) === id);
};

export const dbPostsWhereByID = async (id: number): Promise<Posts | undefined> => {
export const dbPostsWhereByID = async (id: number): Promise<PostType.Posts | undefined> => {
// 草稿删除了 允许重新编辑
const result = await db.posts.filter((i) => !i.delete).toArray();
return result.find((post) => post.post && Number(post.post.id) === id);
};

// post data temp
export const PostTempData = (): Posts => ({
export const PostTempData = (): PostType.Posts => ({
cover: '',
title: '',
summary: '',
Expand Down
2 changes: 1 addition & 1 deletion src/locales/en-US/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default {
'editor.publish.item.gateway.label': 'Backup storage',
'editor.publish.item.gateway.description': 'Store all and cannot be deleted',
'editor.tips.content':
'When you submit an article and choose to directly store your metadata in IPFS, it will not go through any backend or database of Meta Network, reducing the possibility of man-in-the-middle attacks. If you want the content to be displayed in your Meta Space, you need to return to the CMS for publishing after submission.',
'When you submit an article and choose to directly store your metadata in IPFS, it will reducing the possibility of man-in-the-middle attacks as much as possible. If you want the content to be displayed in your Meta Space, you need to return to the CMS for publishing after submission.',
'editor.originalLink.title': 'Original link',
'editor.originalLink.noOriginalLink': 'No original link',
'editor.learn.content': 'Quickly learn the Meta Space editor',
Expand Down
2 changes: 1 addition & 1 deletion src/locales/zh-CN/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default {
'editor.publish.item.gateway.label': '备份存储',
'editor.publish.item.gateway.description': '存储全文,且无法删除',
'editor.tips.content':
'当您提交文章并选择在 IPFS 直接存证您的元数据时,不会经过 Meta Network 的任何后台或数据库,减少中间人攻击的可能性。若要让内容在您的 Meta Space 中显示,则需要您在提交完成后返回 CMS 进行发布。',
'当您提交文章并选择在 IPFS 直接存证您的元数据时,会最大可能减少中间人攻击的可能性。若要让内容在您的 Meta Space 中显示,则需要您在提交完成后返回 CMS 进行发布。',
'editor.originalLink.title': '原文链接',
'editor.originalLink.noOriginalLink': '没有原文链接',
'editor.learn.content': '快速学习 Meta Space 编辑器',
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Settings/components/DeleteLocalDraft/index.less
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.list {
max-width: 600px;
max-width: 700px;
:global {
.ant-list-item-meta-avatar .anticon {
font-size: 22px;
Expand Down
93 changes: 65 additions & 28 deletions src/pages/Settings/components/DeleteLocalDraft/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,36 @@ import { useIntl, useModel } from 'umi';
import { Typography, Button, Popconfirm, message, Space, Input, List, Dropdown } from 'antd';
import { DeleteOutlined, CloudSyncOutlined } from '@ant-design/icons';
import { dbPostsDeleteAll, dbMetadatasDeleteAll } from '@/db/db';
import { fetchGunDraftsAndUpdateLocal, deleteDraft, twoWaySyncDrafts } from '@/utils/gun';
import { storeGet, storeSet } from '@/utils/store';
import { KEY_META_CMS_GUN_SEED, KEY_META_CMS_GUN_PAIR } from '../../../../../config';
import {
fetchGunDraftsAndUpdateLocal,
deleteDraft,
twoWaySyncDrafts,
generateSeedAndPair,
getSeedAndPair,
saveSeedAndPair,
} from '@/utils/gun';
import styles from './index.less';
import type { KeyPair } from '@metaio/meta-signature-util';
import { generateKeys } from '@metaio/meta-signature-util';
import { useMount } from 'ahooks';

const { Text } = Typography;

const ImportSeedAndPairComponents = () => {
interface ImportSeedAndPairComponentsState {
getSeedAndPairFn: () => void;
}

const ImportSeedAndPairComponents: React.FC<ImportSeedAndPairComponentsState> = ({
getSeedAndPairFn,
}) => {
const [seedAndPairInput, setSeedAndPairInput] = useState('');
// handle import
const handleImport = useCallback(() => {
if (!seedAndPairInput) {
return;
}

const [seed, pair] = JSON.parse(seedAndPairInput);
storeSet(KEY_META_CMS_GUN_SEED, seed);
storeSet(KEY_META_CMS_GUN_PAIR, pair);
const handleImport = useCallback(async () => {
await saveSeedAndPair(seedAndPairInput);
getSeedAndPairFn();

message.success('导入成功');
}, [seedAndPairInput]);
}, [seedAndPairInput, getSeedAndPairFn]);
return (
<Space>
<Input onChange={(e) => setSeedAndPairInput(e.target.value)} value={seedAndPairInput} />
Expand All @@ -37,7 +44,8 @@ const ImportSeedAndPairComponents = () => {
export default () => {
const intl = useIntl();
const { initialState } = useModel('@@initialState');
const [syncDraftsLoading, setSyncDraftsLoading] = useState(false);
const [syncDraftsLoading, setSyncDraftsLoading] = useState<boolean>(false);
const [seedAndPair, setSeedAndPair] = useState<string>('');

/**
* handle delete all local draft
Expand Down Expand Up @@ -75,27 +83,38 @@ export default () => {
}

setSyncDraftsLoading(true);
await twoWaySyncDrafts(initialState.currentUser);
setSyncDraftsLoading(false);
try {
await twoWaySyncDrafts(initialState.currentUser);
} catch (e) {
console.error('e', e);
} finally {
setSyncDraftsLoading(false);
}
}, [initialState]);

// sync seed and pair
const seedAndPair = useMemo(() => {
// TODO: 复制出来的格式并不好看,可以考虑加密成一串字符然后导入再解密 待考虑
const seed = storeGet(KEY_META_CMS_GUN_SEED);
const pair = storeGet(KEY_META_CMS_GUN_PAIR);
return JSON.stringify([seed, pair]);
const getSeedAndPairFn = useCallback(() => {
const result = getSeedAndPair();
setSeedAndPair(result);
}, []);

// sync seed public key
const seedPublicKey = useMemo(() => {
const seed = JSON.parse(storeGet(KEY_META_CMS_GUN_SEED) || '[]');
if (!seed.length) {
const _seedAndPair = JSON.parse(seedAndPair || '[]');
if (!_seedAndPair.length) {
return '';
}
const seed = JSON.parse(_seedAndPair[0] || '[]');
const keys: KeyPair = generateKeys(seed);
return keys.public;
}, []);
}, [seedAndPair]);

// generate seed pair fn
const generateSeedAndPairFn = useCallback(async () => {
await generateSeedAndPair();
getSeedAndPairFn();
message.success('生成成功');
}, [getSeedAndPairFn]);

const list = useMemo(
() => [
Expand Down Expand Up @@ -134,15 +153,15 @@ export default () => {
<Text key="syncDraft-copy" copyable={{ text: seedAndPair }}>
{seedPublicKey.slice(0, 6)}****{seedPublicKey.slice(-4)}
</Text>,
<Dropdown overlay={<ImportSeedAndPairComponents />} trigger={['click']}>
<Dropdown
overlay={<ImportSeedAndPairComponents getSeedAndPairFn={getSeedAndPairFn} />}
trigger={['click']}
>
<Button key="syncDraft-import">导入</Button>
</Dropdown>,
<Popconfirm
title={'您确定要双向同步草稿内容吗?'}
onConfirm={twoWaySyncDraftsFn}
okButtonProps={{
loading: syncDraftsLoading,
}}
okText={intl.formatMessage({
id: 'component.button.yes',
})}
Expand All @@ -154,19 +173,37 @@ export default () => {
同步
</Button>
</Popconfirm>,
<Popconfirm
title={'您确定要重新生成 Seed & Pair 吗?'}
onConfirm={generateSeedAndPairFn}
okText={intl.formatMessage({
id: 'component.button.yes',
})}
cancelText={intl.formatMessage({
id: 'component.button.no',
})}
>
<Button key="syncDraft-sync">重新生成</Button>
</Popconfirm>,
],
},
],
[
handleDeleteAllLocalDraft,
twoWaySyncDraftsFn,
generateSeedAndPairFn,
getSeedAndPairFn,
intl,
seedAndPair,
seedPublicKey,
syncDraftsLoading,
],
);

useMount(() => {
getSeedAndPairFn();
});

return (
<List
className={styles.list}
Expand Down
6 changes: 3 additions & 3 deletions src/pages/content/drafts/Edit.less
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@

.edit {
box-sizing: border-box;
max-width: 1020px;
max-width: 2080px;
margin: 0 auto;
padding: 100px 10px 0 10px;
padding: 100px 40px 0 40px;
@media screen and (max-width: 1420px) {
padding-top: 35px;
// padding-top: 35px;
}
}
5 changes: 2 additions & 3 deletions src/pages/content/drafts/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
dbMetadatasAdd,
MetadataTempData,
} from '@/db/db';
import type { Posts } from '@/db/Posts.d';
import { imageUploadByUrlAPI, getDefaultSiteConfigAPI } from '@/helpers';
import { assign, cloneDeep } from 'lodash';
// import type Vditor from 'vditor';
Expand Down Expand Up @@ -52,7 +51,7 @@ import { storeGet } from '@/utils/store';

const Edit: React.FC = () => {
const intl = useIntl();
const [postData, setPostData] = useState<Posts>({} as Posts);
const [postData, setPostData] = useState<PostType.Posts>({} as PostType.Posts);
const [cover, setCover] = useState<string>('');
const [title, setTitle] = useState<string>('');
const [content, setContent] = useState<string>('');
Expand Down Expand Up @@ -108,7 +107,7 @@ const Edit: React.FC = () => {

// 解密
const msg = await Gun.SEA.verify(data, pair.pub);
const gunDraft = (await Gun.SEA.decrypt(msg, pair)) as Posts;
const gunDraft = (await Gun.SEA.decrypt(msg, pair)) as PostType.Posts;

// 如果文章变动
if (
Expand Down
Loading

0 comments on commit e039805

Please sign in to comment.