diff --git a/oauthInfo.json b/oauthInfo.json index 5cf504e..8c2580f 100644 --- a/oauthInfo.json +++ b/oauthInfo.json @@ -13,12 +13,5 @@ "authorizationUrl": "https://www.tistory.com/oauth/authorize", "tokenUrl": "https://www.tistory.com/oauth/access_token", "redirectUri": "http://localhost" - }, - "google": { - "clientId": "CLIENT_ID", - "clientSecret": "CLIENT_SECRET", - "authorizationUrl": "https://accounts.google.com/o/oauth2/auth", - "tokenUrl": "https://accounts.google.com/o/oauth2/token", - "redirectUri": "http://localhost" - } + } } diff --git a/src/main/apis/photos-api.js b/src/main/apis/photos-api.js deleted file mode 100644 index d6a1655..0000000 --- a/src/main/apis/photos-api.js +++ /dev/null @@ -1,120 +0,0 @@ -const oauth2 = require('../oauth/ElectronOauth2'); -const ExternalOAuth2 = require('../oauth/ExternalOAuth2') -const fetch = require('isomorphic-fetch') -const {clipboard, session} = require('electron') -const OauthInfoReader = require('../oauth/OauthInfoReader') -const appInfo = require('../appInfo'); -const OAuthRequestManager = require('../oauth/OAuthRequestManager'); - -class GoogleAuthApi { - #googleOAuth - - constructor() { - this.#googleOAuth = null - } - - makeGoogleOAuth() { - if (!this.#googleOAuth) { - const oauthInfoReader = new OauthInfoReader() - const oauthInfo = oauthInfoReader.getGoogle() - - this.#googleOAuth = oauth2(oauthInfo, { - alwaysOnTop: true, - autoHideMenuBar: true, - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - session: session.fromPartition("google:oauth2:" + new Date()) - } - }) - } - - return this.#googleOAuth - } - - requestAuth(successHandler, failureHandler) { - const oauthInfoReader = new OauthInfoReader() - const oauth2 = new ExternalOAuth2(oauthInfoReader.getGoogle()) - OAuthRequestManager.saveRequestInfo("oauth", (searchParams) => { - const code = searchParams.get("code") - oauth2.requestToken(code) - .then(data => { - if (data.error) { - throw new Error(`${data.error}: ${data.error_description}`) - } - - return data - }) - .then(successHandler) - .catch(failureHandler) - }) - - oauth2.requestAuth({ - scope: ['https://www.googleapis.com/auth/photoslibrary.readonly'] - }) - } - - getAccessToken() { - return this.makeGoogleOAuth().getAccessToken({ - scope: ['https://www.googleapis.com/auth/photoslibrary.readonly'] - }) - } - - refreshToken(refreshToken) { - return this.makeGoogleOAuth().refreshToken(refreshToken) - } -} -module.exports.GoogleAuthApi = GoogleAuthApi - - -class PhotosApi { - constructor(auth) { - this.auth = auth - } - - fetchMediaItems(pageSize = 100, nextPageToken = null) { - console.log("fetchMediaItems", this.auth.access_token, pageSize, nextPageToken) - return fetch('https://photoslibrary.googleapis.com/v1/mediaItems:search', { - method: 'post', - headers: { - 'Content-type': 'application/json', - 'Authorization': `Bearer ${this.auth.access_token}` - }, - body: JSON.stringify({ - pageSize: pageSize, - pageToken: nextPageToken, - filters: { - mediaTypeFilter: { - mediaTypes: ['PHOTO'] - } - } - }) - }) - .then(res => { - if (!res.ok) { - console.error("fetch failed", res) - throw new Error(res.status) - } - - return res.json() - }) - .then(json => { - return { - images: json.mediaItems.map(item => { - const width = item.mediaMetadata.width > 1920? 1920 : item.mediaMetadata.width - const thumbnailWidth = 340 - return { - id: item.id, - url: `${item.baseUrl}=w${width}`, - thumbnail: `${item.baseUrl}=w${thumbnailWidth}`, - title: item.filename, - timestamp: item.mediaMetadata.creationTime - } - }), - nextPageToken: json.nextPageToken - } - - }) - } -} -module.exports.PhotosApi = PhotosApi diff --git a/src/main/events/google-photos.js b/src/main/events/google-photos.js deleted file mode 100644 index b98cb1e..0000000 --- a/src/main/events/google-photos.js +++ /dev/null @@ -1,61 +0,0 @@ -const { ipcMain } = require('electron') -const settings = require('electron-settings') -const { GoogleAuthApi, PhotosApi } = require('../apis/photos-api') - -module.exports = () => { - const authApi = new GoogleAuthApi() - const fetchImages = async (evt, nextPageToken) => { - console.log('fetchImage', nextPageToken) - const auth = settings.getSync('google-auth') - - try { - if (!auth || !auth.access_token) { - throw new Error("NO_AUTH") - } - evt.sender.send('start-fetch-google-photos-images') - const photosApi = new PhotosApi(auth) - const data = await photosApi.fetchMediaItems(100, nextPageToken) - evt.sender.send('receive-google-photos-images', data) - - } catch(e) { - console.error(e) - if (auth && auth.refresh_token) { - try { - const refreshAuth = await authApi.refreshToken(auth.refresh_token) - settings.setSync('google-auth', refreshAuth) - fetchImages(evt, nextPageToken) - return - } catch (authError) { - settings.setSync('google-auth', null) - evt.sender.send('receive-google-connected', false) - } - } else { - evt.sender.send('receive-google-connected', false) - } - evt.sender.send('receive-google-photos-images', null) - } - } - - ipcMain.on('fetch-google-photos-images', (evt, nextPageToken) => { - console.log('Main.receive: fetch-google-photos-images', nextPageToken) - fetchImages(evt, nextPageToken) - }) - - ipcMain.on("request-google-photos-auth", (evt, arg) => { - console.log('Main.receive: request-google-photos-auth') - authApi.requestAuth((auth) => { - settings.setSync('google-auth', auth) - evt.sender.send('receive-google-connected', true) - fetchImages(evt, null)// - }, (e) => { - console.error(e) - evt.sender.send('receive-message', `오류가 발생했습니다. (${e.message})`) - }) - }) - - ipcMain.on("disconnect-google-photos-auth", (evt, arg) => { - console.log('Main.receive: disconnect-google-photos-auth') - settings.unsetSync('google-auth') - evt.sender.send('receive-google-connected', false) - }) -} diff --git a/src/main/ipc-event.js b/src/main/ipc-event.js index aa7fccc..afb3f10 100644 --- a/src/main/ipc-event.js +++ b/src/main/ipc-event.js @@ -1,13 +1,11 @@ const authEvents = require('./events/auth') const contentEvents = require('./events/content') const preferenceEvents = require('./events/preference') -const googlePhotosEvents = require('./events/google-photos') const googleAnalyticsEvents = require('./events/google-analytics') module.exports.init = () => { authEvents() contentEvents() preferenceEvents() - googlePhotosEvents() googleAnalyticsEvents() } diff --git a/src/renderer/components/editor/codemirror/MarkdownEditor.js b/src/renderer/components/editor/codemirror/MarkdownEditor.js index 7f0d6e4..309edbe 100644 --- a/src/renderer/components/editor/codemirror/MarkdownEditor.js +++ b/src/renderer/components/editor/codemirror/MarkdownEditor.js @@ -8,8 +8,6 @@ import { Button, Box } from '@mui/material' import { FormatBold, FormatItalic, FormatUnderlined, Attachment } from '@mui/icons-material' import CodeMirrorHelper from './CodeMirrorHelper' -import GooglePhotosDialog from '../plugins/google-photos/GooglePhotosDialog' -import googlePhotosLogo from '../../../images/google-photos-logo.png' import "../../../styles/lib/codemirror/tistory-markdown-theme.scss" import "codemirror/lib/codemirror.css" import "codemirror/addon/dialog/dialog.css" @@ -75,7 +73,6 @@ export default function MarkdownEditor({ value, onOpenFile, onChange }) { const currentAuth = useSelector(state => state.currentAuth) const currentBlog = useSelector(state => state.currentBlog) const [markdownValue, setMarkdownValue] = useState(MarkdownHelper.htmlToMarkdown(value)) - const [openGooglePhotos, setOpenGooglePhotos] = useState(false) const editorRef = useRef(null) const imageUploadEnabled = useMemo(() => currentAuth.provider == 'tistory', [currentAuth]) @@ -124,18 +121,6 @@ export default function MarkdownEditor({ value, onOpenFile, onChange }) { CodeMirrorHelper.link(editorRef.current.getCodeMirror()) } - function handleGooglePhotos(e) { - setOpenGooglePhotos(true) - } - - function handleCloseGooglePhotos() { - setOpenGooglePhotos(false) - } - - function handleInsertImage(url, fileName) { - ipcRenderer.send("add-image-url", currentAuth.uuid, currentBlog.name, url, fileName) - } - function handleFinishUploadFile(e, fileUrl) { CodeMirrorHelper.insertImage(editorRef.current.getCodeMirror(), fileUrl) } @@ -163,7 +148,6 @@ export default function MarkdownEditor({ value, onOpenFile, onChange }) { Link - {imageUploadEnabled && } {imageUploadEnabled && } @@ -178,12 +162,6 @@ export default function MarkdownEditor({ value, onOpenFile, onChange }) { value={markdownValue} onChange={handleChangeContent} /> - - ) } diff --git a/src/renderer/components/editor/plugins/google-photos/GooglePhotos.js b/src/renderer/components/editor/plugins/google-photos/GooglePhotos.js deleted file mode 100644 index 85362b6..0000000 --- a/src/renderer/components/editor/plugins/google-photos/GooglePhotos.js +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { ipcRenderer } from 'electron' -import update from 'immutability-helper' -import { Button } from '@mui/material' -import Loading from '../../../Loading' -import PhotoList from './PhotoList' - - -export default function GooglePhotos({ connected, onConnect, onDisconnect, onSelectImage }) { - const [initialized, setInitialized] = useState(false) - const [images, setImages] = useState([]) - const [fetching, setFetching] = useState(false) - const [nextPageToken, setNextPageToken] = useState(null) - - function handleReceiveImages(e, data) { - if (data === null) { - onDisconnect() - return - } - - console.log("connected", data) - - setInitialized(true) - setImages(update(images, { - $push: data.images - })) - setNextPageToken(data.nextPageToken) - setFetching(false) - onConnect(true) - } - - function handleStartFetch(e) { - setFetching(true) - } - - function handleReceiveConnected(e, connected) { - setInitialized(true) - - if (connected) { - onConnect() - } else { - setImages([]) - setNextPageToken(null) - onDisconnect() - } - } - - function handleRequestFetch() { - ipcRenderer.send('fetch-google-photos-images', nextPageToken) - } - - function handleRequestAuth() { - ipcRenderer.send("request-google-photos-auth") - } - - function handleImageSelect(image) { - if (confirm('이미지를 삽입하시겠습니까?')) { - onSelectImage(image.url, image.title) - } - } - - useEffect(() => { - handleRequestFetch() - ipcRenderer.on("receive-google-photos-images", handleReceiveImages) - ipcRenderer.on("start-fetch-google-photos-images", handleStartFetch) - ipcRenderer.on("receive-google-connected", handleReceiveConnected) - - return () => { - ipcRenderer.removeListener("receive-google-photos-images", handleReceiveImages) - ipcRenderer.removeListener("start-fetch-google-photos-images", handleStartFetch) - ipcRenderer.removeListener("receive-google-connected", handleReceiveConnected) - } - }, []) - - - if (!initialized) { - return ( -
-
- -
-
- ) - } - - if (!connected) { - return ( -
-
- -
-
- ) - } - - return ( - - ) -} diff --git a/src/renderer/components/editor/plugins/google-photos/GooglePhotosDialog.js b/src/renderer/components/editor/plugins/google-photos/GooglePhotosDialog.js deleted file mode 100644 index d9acc96..0000000 --- a/src/renderer/components/editor/plugins/google-photos/GooglePhotosDialog.js +++ /dev/null @@ -1,69 +0,0 @@ -import React, { Component } from 'react' -import autobind from 'autobind-decorator' -import { ipcRenderer } from 'electron' - -import { Dialog, Button, DialogTitle, DialogContent, DialogActions } from '@mui/material' -import GooglePhotos from './GooglePhotos' - -class GooglePhotosDialog extends Component { - - constructor(props) { - super(props) - this.state = { - connected: false - } - } - - @autobind - handleDisconnect() { - this.setState({ - connected: false - }) - } - - @autobind - handleConnect() { - this.setState({ - connected: true - }) - } - - @autobind - handleRequestDisconnect() { - ipcRenderer.send("disconnect-google-photos-auth") - } - - render() { - const { connected } = this.state - const { open, onClose, onSelectImage } = this.props - - return( - - Google Photos - - - - - - - {connected && - - } - - - - ) - } -} - -export default GooglePhotosDialog diff --git a/src/renderer/components/editor/plugins/google-photos/PhotoList.js b/src/renderer/components/editor/plugins/google-photos/PhotoList.js deleted file mode 100644 index 7105689..0000000 --- a/src/renderer/components/editor/plugins/google-photos/PhotoList.js +++ /dev/null @@ -1,110 +0,0 @@ -import React, { Component, Fragment } from 'react' -import autobind from 'autobind-decorator' - -import { - ImageList, ImageListItem, ImageListItemBar, - ListSubheader, - IconButton -} from '@mui/material' - -import { AddCircleOutline } from '@mui/icons-material' - -import Loading from '../../../../components/Loading' -import { timestampsToDate } from '../../../../modules/ContentHelper' - -const styles = { - buttonIcon: { - color: 'rgba(255, 255, 255, 0.54)' - }, - gridTitleBar: { - background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)' - } -} - -class PhotoList extends Component { - - componentDidMount() { - const { album, onBack } = this.props - const { list } = this.refs - list.addEventListener('scroll', this.handleScrollList) - } - - componentWillUnmount() { - const { list } = this.refs - list.removeEventListener('scroll', this.handleScrollList) - } - - @autobind - handleScrollList(e) { - const { onFetch, images, fetching } = this.props - const { clientHeight, scrollHeight, scrollTop } = e.target - - if (fetching) { - return - } - - if (clientHeight + scrollTop + 200 > scrollHeight) { - onFetch() - } - } - - render() { - const { onClick, images, fetching } = this.props - - let lastDate = '' - let currentDate = '' - - return ( -
-
- {images.length === 0 && fetching && -
- -
- } - - {images.length > 0 && - - {images.map(item => { - let prevDate = currentDate - currentDate = timestampsToDate(item.timestamp) - - let tile = [ - - {item.title} - onClick(item)}> - - - } - /> - - ] - - if (prevDate != currentDate) { - tile.unshift( - - {currentDate} - - ) - } - - return tile - })} - - } - - {images.length > 0 && fetching && -
- -
- } -
-
- ) - } -} - -export default PhotoList diff --git a/src/renderer/components/editor/tinymce/TinymceEditor.js b/src/renderer/components/editor/tinymce/TinymceEditor.js index d183150..c6d3b9b 100644 --- a/src/renderer/components/editor/tinymce/TinymceEditor.js +++ b/src/renderer/components/editor/tinymce/TinymceEditor.js @@ -8,7 +8,6 @@ import { Editor } from '@tinymce/tinymce-react' import 'tinymce-plugin-opengraph' import 'tinymce-plugin-codeblock' -import './plugins/google-photos' import './plugins/file-upload' import 'codemirror/mode/clojure/clojure' @@ -17,25 +16,24 @@ import 'codemirror/mode/clike/clike' import 'codemirror/mode/go/go' import 'codemirror/mode/xml/xml' -import GooglePhotosDialog from '../plugins/google-photos/GooglePhotosDialog' import { makeThumbnail } from '../../../modules/ThumbnailHelper' export default function TinymceEditor({ value, onImageHandler, onOpenFile, onChange }) { const currentAuth = useSelector(state => state.currentAuth) const currentBlog = useSelector(state => state.currentBlog) - const [openGooglePhotos, setOpenGooglePhotos] = useState(false) const imageUploadEnabled = useMemo(() => currentAuth.provider == 'tistory', [currentAuth]) const tinymcePlugins = useMemo(() => { if (imageUploadEnabled) { - return 'link table lists codeblock opengraph google-photos file-upload autoresize searchreplace' + return 'link table lists codeblock opengraph file-upload autoresize searchreplace' } else { return 'link table lists codeblock opengraph autoresize searchreplace' } }, [imageUploadEnabled]) + const tinymceToolbar = useMemo(() => { if (imageUploadEnabled) { - return 'blocks bold italic link inlinecode | alignleft aligncenter alignright | bullist numlist | blockquote codeblock google-photos file-upload opengraph hr removeformat' + return 'blocks bold italic link inlinecode | alignleft aligncenter alignright | bullist numlist | blockquote codeblock file-upload opengraph hr removeformat' } else { return 'blocks bold italic link inlinecode | alignleft aligncenter alignright | bullist numlist | blockquote codeblock opengraph hr removeformat' } @@ -86,17 +84,6 @@ export default function TinymceEditor({ value, onImageHandler, onOpenFile, onCha }) } - function handleInsertImage(url, filename) { - if (!imageUploadEnabled) { - return - } - ipcRenderer.send("add-image-url", currentAuth.uuid, currentBlog.name, url, filename) - } - - function handleToggleGooglePhotos() { - setOpenGooglePhotos(!openGooglePhotos) - } - useEffect(() => { ipcRenderer.on("finish-add-file", handleFinishUploadFile) @@ -145,9 +132,6 @@ export default function TinymceEditor({ value, onImageHandler, onOpenFile, onCha opengraph: { fetch_handler: handleFetchOpengraph }, - google_photos: { - open_handler: handleToggleGooglePhotos - }, open_file_handler: onOpenFile, init_instance_callback: (editor) => { editor.ui.registry.addIcon('media', 'M') @@ -156,12 +140,6 @@ export default function TinymceEditor({ value, onImageHandler, onOpenFile, onCha } }} /> - - ) } diff --git a/src/renderer/components/editor/tinymce/plugins/google-photos/index.js b/src/renderer/components/editor/tinymce/plugins/google-photos/index.js deleted file mode 100644 index 12fdf4b..0000000 --- a/src/renderer/components/editor/tinymce/plugins/google-photos/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import tinymce from 'tinymce' -import plugin from './plugin' - -tinymce.PluginManager.add('google-photos', plugin) diff --git a/src/renderer/components/editor/tinymce/plugins/google-photos/plugin.js b/src/renderer/components/editor/tinymce/plugins/google-photos/plugin.js deleted file mode 100644 index efd1261..0000000 --- a/src/renderer/components/editor/tinymce/plugins/google-photos/plugin.js +++ /dev/null @@ -1,27 +0,0 @@ -import googlePhotosLogo from '../../../../../images/google-photos-logo.png' - -const plugin = function(editor) { - editor.options.register("google_photos", { - processor: 'object' - }) - - const settings = editor.options.get("google_photos") - if (!settings.open_handler) { - return - } - - - - editor.addCommand('google-photos', settings.open_handler) - editor.ui.registry.addIcon('google-photos', ``) - - editor.ui.registry.addButton('google-photos', { - icon: 'google-photos', - tooltip: 'Google Photos', - onAction: () => { - editor.execCommand('google-photos') - } - }) -} - -export default plugin diff --git a/src/renderer/images/google-photos-logo.png b/src/renderer/images/google-photos-logo.png deleted file mode 100644 index a368568..0000000 Binary files a/src/renderer/images/google-photos-logo.png and /dev/null differ diff --git a/src/renderer/styles/components/rich-editor.scss b/src/renderer/styles/components/rich-editor.scss index 4a92301..3a28d9e 100644 --- a/src/renderer/styles/components/rich-editor.scss +++ b/src/renderer/styles/components/rich-editor.scss @@ -28,60 +28,3 @@ } } } - -/* photos plugin */ -.ico-google-photos { - display:inline-block; width: 16px; height:16px; - background:url('../images/google-photos-logo.png') no-repeat; background-size:16px 16px; -} -.tox-container .plugin-google-photos { min-width:640px } - -.btn-disconnect-google-photos { - position: absolute !important; left:0; -} -.plugin-google-photos { - min-width: 640px; min-height:480px; position: relative; - .google-photos-wrap { - position:absolute; top:0; bottom:0; left:0; right:0; overflow:auto; - .google-photos-cover { display: flex;justify-content: center;align-items: center; height: 100%;} - .google-photos-footer { display: flex;justify-content: center;align-items: center; height: 100px; width:100%; } - - .photos-list { - position:absolute; top:0; bottom:0; left:0; right:0; overflow:hidden; overflow-y:auto; - - - .photos-item-wrap { - margin: -2px; - - .photos-sub-header { - clear: both; - padding: 20px; - } - - .photos-item { - float: left; - width: 50%; - height: 184px; - box-sizing: border-box; - flex-shrink: 0; - - .photos-item-image-wrap { - height: 100%; - display:block; - position: relative; - overflow: hidden; - - .photos-item-image { - left: 50%; - top: 50%; - width: 100%; - position: relative; - transform: translate(-50%, -50%); - } - } - } - } - } - } - -}