Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/wordpress #1280

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"hypermd": "^0.3.11",
"immutability-helper": "^3.0.1",
"jquery": "^3.4.0",
"js-base64": "^3.7.7",
"lodash": "^4.17.20",
"mobx": "^5.15.1",
"mobx-react": "^6.1.4",
Expand Down
55 changes: 55 additions & 0 deletions src/common/backend/imageHosting/wordpress/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import localeService from '@/common/locales';
import { ImageHostingService, ImageHostingServiceMeta, UploadImageRequest } from '../interface';
import { WordPressDocumentService } from '../../services/wordpress';
import { Base64ImageToBlob } from '@/common/blob';
import { IBasicRequestService } from '@/service/common/request';
import { Container } from 'typedi/Container';

class WordpressImageService extends WordPressDocumentService implements ImageHostingService {
uploadImage = async (request: UploadImageRequest) => {
const blob = Base64ImageToBlob(request.data);
return this.uploadBlob(blob);
};

uploadImageUrl = async (url: string) => {
let blob: Blob = await Container.get(IBasicRequestService).download(url);
// if (blob.type === 'image/webp') {
// blob = blob.slice(0, blob.size, 'image/jpeg');
// }
return this.uploadBlob(blob);
};

private uploadBlob = async (data: Blob): Promise<string> => {
const ext = data.type.split('/').pop();
const filename = `${new Date().getTime()}.${ext}`;
const res = await fetch(`${this.config.host}/wp-json/wp/v2/media`, {
method: 'POST',
credentials: 'omit',
headers: {
Authorization: `Basic ${this.getToken()}`,
'Content-Type': data.type,
'Content-Disposition': `attachment; filename="${filename}"`,
},
body: data,
});

const body = await res.json();
return body.source_url;
};
}

export default (): ImageHostingServiceMeta => {
return {
name: localeService.format({
id: 'backend.imageHosting.wordpress.name',
}),
icon: 'wordpress',
type: 'wordpress',
service: WordpressImageService,
builtIn: true,
builtInRemark: localeService.format({
id: 'backend.imageHosting.wordpress.builtInRemark',
defaultMessage: 'WordPress Media Service.',
}),
};
};
95 changes: 95 additions & 0 deletions src/common/backend/services/wordpress/form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.less';
import { Input } from 'antd';
import { FormComponentProps } from '@ant-design/compatible/lib/form';
import React, { Fragment } from 'react';
import { FormattedMessage } from 'react-intl';
import i18n from '@/common/locales';
import useOriginForm from '@/hooks/useOriginForm';
import { WordPressServiceConfig } from '.';

interface OneNoteProps {
verified?: boolean;
info?: WordPressServiceConfig;
}

const ExtraForm: React.FC<OneNoteProps & FormComponentProps> = props => {
const {
form: { getFieldDecorator },
form,
info,
} = props;
const { verified, handleAuthentication, formRules } = useOriginForm({
form,
initStatus: !!info,
originKey: 'host',
});
let initData: Partial<WordPressServiceConfig> = {};
if (info) {
initData = info;
}
let editMode = info ? true : false;
return (
<Fragment>
<Form.Item
label={
<FormattedMessage id="backend.services.wordpress.form.origin" defaultMessage="Origin" />
}
>
{form.getFieldDecorator('host', {
initialValue: info?.host,
rules: formRules,
})(
<Input.Search
enterButton={
<FormattedMessage
id="backend.services.wordpress.form.authentication"
defaultMessage="Authentication"
/>
}
onSearch={handleAuthentication}
disabled={verified}
/>
)}
</Form.Item>
<Form.Item
label={
<FormattedMessage id="backend.services.wordpress.form.username" defaultMessage="Email" />
}
>
{getFieldDecorator('username', {
initialValue: initData.username,
rules: [
{
required: true,
message: i18n.format({
id: 'backend.services.wordpress.form.username',
defaultMessage: 'Username is required.',
}),
},
],
})(<Input disabled={editMode} />)}
</Form.Item>
<Form.Item
label={
<FormattedMessage id="backend.services.wordpress.form.pwd" defaultMessage="Password" />
}
>
{getFieldDecorator('pwd', {
initialValue: initData.pwd,
rules: [
{
required: true,
message: i18n.format({
id: 'backend.services.wordpress.form.pwd',
defaultMessage: 'Password is required.',
}),
},
],
})(<Input disabled={editMode} type="password" />)}
</Form.Item>
</Fragment>
);
};

export default ExtraForm;
119 changes: 119 additions & 0 deletions src/common/backend/services/wordpress/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {
CompleteStatus,
CreateDocumentRequest,
DocumentService,
ServiceMeta,
} from '@/common/backend';
import localeService from '@/common/locales';
import form from './form';
import { encode } from 'js-base64';

export interface WordPressServiceConfig {
host: string;
username: string;
pwd: string;
}

export interface WordpressCategory {
id: number;
name: string;
slug: string;
}

export interface WordpressUser {
id: number;
name: string;
description: string;
link: string;
}

export class WordPressDocumentService implements DocumentService {
protected config: WordPressServiceConfig;

constructor(config: WordPressServiceConfig) {
this.config = config;
}

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

getToken = () => {
return encode(`${this.config.username}:${this.config.pwd}`);
};

getRepositories = async () => {
const res = await fetch(`${this.config.host}/wp-json/wp/v2/categories`, {
credentials: 'omit',
headers: {
Authorization: `Basic ${this.getToken()}`,
},
});
const data = ((await res.json()) as unknown) as WordpressCategory[];
return data.map(item => {
return {
id: String(item.id),
name: item.name,
groupName: 'wordpress',
groupId: 'wordpress',
};
});
};

createDocument = async (request: CreateDocumentRequest) => {
const res = await fetch(`${this.config.host}/wp-json/wp/v2/posts`, {
method: 'POST',
credentials: 'omit',
headers: {
Authorization: `Basic ${this.getToken()}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
status: 'private',
title: {
raw: request.title,
rendered: request.title,
},
content: {
raw: request.content,
},
categories: [Number(request.repositoryId)],
}),
});
const data = await res.json();
return {
href: data.link,
} as CompleteStatus;
};

getUserInfo = async () => {
console.log('getUserInfo:', this, this.config);
const res = await fetch(`${this.config.host}/wp-json/wp/v2/users/me`, {
credentials: 'omit',
headers: {
Authorization: `Basic ${this.getToken()}`,
},
});
const user = ((await res.json()) as unknown) as WordpressUser;
return {
name: user.name,
avatar: '',
homePage: user.link,
description: user.description,
};
};
}

export default (): ServiceMeta => {
return {
name: localeService.format({
id: 'backend.services.wordpress.name',
defaultMessage: 'WordPress',
}),
form,
icon: 'wordpress',
type: 'wordpress',
service: WordPressDocumentService,
permission: {},
};
};
7 changes: 7 additions & 0 deletions src/common/locales/data/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@
"backend.services.yuque.headerForm.slug": "路径",
"backend.services.yuque.headerForm.slug_error": "只能输入大小写字母、横线、下划线和点,至少 2 个字符。",
"backend.services.yuque.name": "语雀",
"backend.services.wordpress.name": "WordPress",
"backend.services.wordpress.form.origin": "服务器地址",
"backend.services.wordpress.form.username": "用户名",
"backend.services.wordpress.form.authentication": "授权",
"backend.services.wordpress.form.pwd": "应用密码",
"backend.imageHosting.wordpress.name": "WordPress媒体库",
"backend.imageHosting.wordpress.builtInRemark": "WordPress媒体库集成。",
"background.not_support_message": "暂时无法剪辑此类型的页面。",
"component.accountItem.delete": "删除",
"component.accountItem.edit": "编辑",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5304,6 +5304,11 @@ jquery@^3.4.0, jquery@^3.4.1:
resolved "https://registry.npm.taobao.org/jquery/download/jquery-3.6.0.tgz?cache=0&sync_timestamp=1614705221099&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjquery%2Fdownload%2Fjquery-3.6.0.tgz"
integrity sha1-xyoJ8Vwb3OFC9J2/EXC9+K2sJHA=

js-base64@^3.7.7:
version "3.7.7"
resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79"
integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==

js-string-escape@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
Expand Down
Loading