You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Adding Dropbox sync to Electron app
This commit is contained in:
		| @@ -78,10 +78,26 @@ class Command extends BaseCommand { | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| 		} else if (syncTargetMd.name === 'dropbox') { // Dropbox | ||||
| 			const api = await syncTarget.api(); | ||||
| 			const loginUrl = api.loginUrl(); | ||||
| 			this.stdout(_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')); | ||||
| 			this.stdout(_('Step 1: Open this URL in your browser to authorise the application:')); | ||||
| 			this.stdout(loginUrl); | ||||
| 			const authCode = await this.prompt(_('Step 2: Enter the code provided by Dropbox:'), { type: 'string' }); | ||||
| 			if (!authCode) { | ||||
| 				this.stdout(_('Authentication was not completed (did not receive an authentication token).')); | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			const response = await api.execAuthToken(authCode); | ||||
| 			Setting.setValue('sync.' + this.syncTargetId_ + '.auth', JSON.stringify(response)); | ||||
| 			api.setAuthToken(response.access_token); | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTarget.label())); | ||||
| 		this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTargetMd.label)); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| @@ -100,6 +116,7 @@ class Command extends BaseCommand { | ||||
| 		this.releaseLockFn_ = null; | ||||
|  | ||||
| 		// Lock is unique per profile/database | ||||
| 		// TODO: use SQLite database to do lock? | ||||
| 		const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41 | ||||
| 		if (!await fs.pathExists(lockFilePath)) await fs.writeFile(lockFilePath, 'synclock'); | ||||
|  | ||||
| @@ -130,7 +147,7 @@ class Command extends BaseCommand { | ||||
|  | ||||
| 			const syncTarget = reg.syncTarget(this.syncTargetId_); | ||||
|  | ||||
| 			if (!syncTarget.isAuthenticated()) { | ||||
| 			if (!await syncTarget.isAuthenticated()) { | ||||
| 				app().gui().showConsole(); | ||||
| 				app().gui().maximizeConsole(); | ||||
|  | ||||
| @@ -197,7 +214,7 @@ class Command extends BaseCommand { | ||||
|  | ||||
| 		const syncTarget = reg.syncTarget(syncTargetId); | ||||
|  | ||||
| 		if (syncTarget.isAuthenticated()) { | ||||
| 		if (await syncTarget.isAuthenticated()) { | ||||
| 			const sync = await syncTarget.synchronizer(); | ||||
| 			if (sync) await sync.cancel(); | ||||
| 		} else { | ||||
|   | ||||
							
								
								
									
										111
									
								
								ElectronClient/app/gui/DropboxLoginScreen.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								ElectronClient/app/gui/DropboxLoginScreen.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| const React = require('react'); | ||||
| const { connect } = require('react-redux'); | ||||
| const { reg } = require('lib/registry.js'); | ||||
| const { bridge } = require('electron').remote.require('./bridge'); | ||||
| const { Header } = require('./Header.min.js'); | ||||
| const { themeStyle } = require('../theme.js'); | ||||
| const SyncTargetRegistry = require('lib/SyncTargetRegistry'); | ||||
| const { _ } = require('lib/locale.js'); | ||||
|  | ||||
| class DropboxLoginScreenComponent extends React.Component { | ||||
|  | ||||
| 	constructor() { | ||||
| 		super(); | ||||
|  | ||||
| 		this.dropboxApi_ = null; | ||||
|  | ||||
| 		this.state = { | ||||
| 			loginUrl: '', | ||||
| 			authCode: '', | ||||
| 			checkingAuthToken: false, | ||||
| 		}; | ||||
|  | ||||
| 		this.loginUrl_click = () => { | ||||
| 			if (!this.state.loginUrl) return; | ||||
| 			bridge().openExternal(this.state.loginUrl) | ||||
| 		} | ||||
|  | ||||
| 		this.authCodeInput_change = (event) => { | ||||
| 			this.setState({ | ||||
| 				authCode: event.target.value | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		this.submit_click = async () => { | ||||
| 			this.setState({ checkingAuthToken: true }); | ||||
|  | ||||
| 			const api = await this.dropboxApi(); | ||||
| 			try { | ||||
| 				const response = await api.execAuthToken(this.state.authCode); | ||||
| 				Setting.setValue('sync.' + this.syncTargetId() + '.auth', JSON.stringify(response)); | ||||
| 				api.setAuthToken(response.access_token); | ||||
| 				bridge().showInfoMessageBox(_('The application has been authorised!')); | ||||
| 				this.props.dispatch({ type: 'NAV_BACK' }); | ||||
| 			} catch (error) { | ||||
| 				bridge().showErrorMessageBox(_('Could not authorise application:\n\n%s\n\nPlease try again.', error.message)); | ||||
| 			} finally { | ||||
| 				this.setState({ checkingAuthToken: false }); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		this.refreshUrl(); | ||||
| 	} | ||||
|  | ||||
| 	syncTargetId() { | ||||
| 		return SyncTargetRegistry.nameToId('dropbox'); | ||||
| 	} | ||||
|  | ||||
| 	async dropboxApi() { | ||||
| 		if (this.dropboxApi_) return this.dropboxApi_; | ||||
|  | ||||
| 		const syncTarget = reg.syncTarget(this.syncTargetId()); | ||||
| 		this.dropboxApi_ = await syncTarget.api(); | ||||
| 		return this.dropboxApi_; | ||||
| 	} | ||||
|  | ||||
| 	async refreshUrl() { | ||||
| 		const api = await this.dropboxApi(); | ||||
|  | ||||
| 		this.setState({ | ||||
| 			loginUrl: api.loginUrl(), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		const style = this.props.style; | ||||
| 		const theme = themeStyle(this.props.theme); | ||||
|  | ||||
| 		const headerStyle = { | ||||
| 			width: style.width, | ||||
| 		}; | ||||
|  | ||||
| 		const inputStyle = Object.assign({}, theme.inputStyle, { width: 500 }); | ||||
|  | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<Header style={headerStyle} /> | ||||
| 				<div style={{padding: theme.margin}}> | ||||
| 					<p style={theme.textStyle}>{_('To allow Joplin to synchronise with Dropbox, please follow the steps below:')}</p> | ||||
| 					<p style={theme.textStyle}>{_('Step 1: Open this URL in your browser to authorise the application:')}</p> | ||||
| 					<a style={theme.textStyle} href="#" onClick={this.loginUrl_click}>{this.state.loginUrl}</a> | ||||
| 					<p style={theme.textStyle}>{_('Step 2: Enter the code provided by Dropbox:')}</p> | ||||
| 					<p><input type="text" value={this.state.authCode} onChange={this.authCodeInput_change} style={inputStyle}/></p> | ||||
| 					<button disabled={this.state.checkingAuthToken} onClick={this.submit_click}>{_('Submit')}</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| const mapStateToProps = (state) => { | ||||
| 	return { | ||||
| 		theme: state.settings.theme, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| const DropboxLoginScreen = connect(mapStateToProps)(DropboxLoginScreenComponent); | ||||
|  | ||||
| module.exports = { DropboxLoginScreen }; | ||||
| @@ -8,6 +8,7 @@ const Setting = require('lib/models/Setting.js'); | ||||
|  | ||||
| const { MainScreen } = require('./MainScreen.min.js'); | ||||
| const { OneDriveLoginScreen } = require('./OneDriveLoginScreen.min.js'); | ||||
| const { DropboxLoginScreen } = require('./DropboxLoginScreen.min.js'); | ||||
| const { StatusScreen } = require('./StatusScreen.min.js'); | ||||
| const { ImportScreen } = require('./ImportScreen.min.js'); | ||||
| const { ConfigScreen } = require('./ConfigScreen.min.js'); | ||||
| @@ -75,6 +76,7 @@ class RootComponent extends React.Component { | ||||
| 		const screens = { | ||||
| 			Main: { screen: MainScreen }, | ||||
| 			OneDriveLogin: { screen: OneDriveLoginScreen, title: () => _('OneDrive Login') }, | ||||
| 			DropboxLogin: { screen: DropboxLoginScreen, title: () => _('Dropbox Login') }, | ||||
| 			Import: { screen: ImportScreen, title: () => _('Import') }, | ||||
| 			Config: { screen: ConfigScreen, title: () => _('Options') }, | ||||
| 			Status: { screen: StatusScreen, title: () => _('Synchronisation Status') }, | ||||
|   | ||||
| @@ -62,6 +62,7 @@ globalStyle.icon = { | ||||
| globalStyle.lineInput = { | ||||
| 	color: globalStyle.color, | ||||
| 	backgroundColor: globalStyle.backgroundColor, | ||||
| 	fontFamily: globalStyle.fontFamily, | ||||
| }; | ||||
|  | ||||
| globalStyle.textStyle = { | ||||
|   | ||||
| @@ -29,6 +29,7 @@ const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js'); | ||||
| const SyncTargetOneDriveDev = require('lib/SyncTargetOneDriveDev.js'); | ||||
| const SyncTargetNextcloud = require('lib/SyncTargetNextcloud.js'); | ||||
| const SyncTargetWebDAV = require('lib/SyncTargetWebDAV.js'); | ||||
| const SyncTargetDropbox = require('lib/SyncTargetDropbox.js'); | ||||
| const EncryptionService = require('lib/services/EncryptionService'); | ||||
| const DecryptionWorker = require('lib/services/DecryptionWorker'); | ||||
| const BaseService = require('lib/services/BaseService'); | ||||
| @@ -38,6 +39,7 @@ SyncTargetRegistry.addClass(SyncTargetOneDrive); | ||||
| SyncTargetRegistry.addClass(SyncTargetOneDriveDev); | ||||
| SyncTargetRegistry.addClass(SyncTargetNextcloud); | ||||
| SyncTargetRegistry.addClass(SyncTargetWebDAV); | ||||
| SyncTargetRegistry.addClass(SyncTargetDropbox); | ||||
|  | ||||
| class BaseApplication { | ||||
|  | ||||
| @@ -421,8 +423,14 @@ class BaseApplication { | ||||
| 		if (Setting.value('firstStart')) { | ||||
| 			const locale = shim.detectAndSetLocale(Setting); | ||||
| 			reg.logger().info('First start: detected locale as ' + locale); | ||||
| 			if (Setting.value('env') === 'dev') Setting.setValue('sync.target', SyncTargetRegistry.nameToId('onedrive_dev')); | ||||
| 			Setting.setValue('firstStart', 0) | ||||
|  | ||||
| 			if (Setting.value('env') === 'dev') { | ||||
| 				Setting.setValue('showTrayIcon', 0); | ||||
| 				Setting.setValue('autoUpdateEnabled', 0); | ||||
| 				Setting.setValue('sync.interval', 3600); | ||||
| 			} | ||||
| 			 | ||||
| 			Setting.setValue('firstStart', 0); | ||||
| 		} else { | ||||
| 			setLocale(Setting.value('locale')); | ||||
| 		} | ||||
|   | ||||
| @@ -30,7 +30,7 @@ class BaseSyncTarget { | ||||
| 		return this.db_; | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| @@ -113,7 +113,7 @@ class BaseSyncTarget { | ||||
|  | ||||
| 	async syncStarted() { | ||||
| 		if (!this.synchronizer_) return false; | ||||
| 		if (!this.isAuthenticated()) return false; | ||||
| 		if (!await this.isAuthenticated()) return false; | ||||
| 		const sync = await this.synchronizer(); | ||||
| 		return sync.state() != 'idle'; | ||||
| 	} | ||||
|   | ||||
| @@ -12,6 +12,14 @@ class DropboxApi { | ||||
| 		this.authToken_ = null; | ||||
| 	} | ||||
|  | ||||
| 	clientId() { | ||||
| 		return this.options_.id; | ||||
| 	} | ||||
|  | ||||
| 	clientSecret() { | ||||
| 		return this.options_.secret; | ||||
| 	} | ||||
|  | ||||
| 	setLogger(l) { | ||||
| 		this.logger_ = l; | ||||
| 	} | ||||
| @@ -21,13 +29,17 @@ class DropboxApi { | ||||
| 	} | ||||
|  | ||||
| 	authToken() { | ||||
| 		return this.authToken_; // Must be "Bearer XXXXXXXXXXXXXXXXXX" | ||||
| 		return this.authToken_; // Without the "Bearer " prefix | ||||
| 	} | ||||
|  | ||||
| 	setAuthToken(v) { | ||||
| 		this.authToken_ = v; | ||||
| 	} | ||||
|  | ||||
| 	loginUrl() { | ||||
| 		return 'https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=' + this.clientId(); | ||||
| 	} | ||||
|  | ||||
| 	baseUrl(endPointFormat) { | ||||
| 		if (['content', 'api'].indexOf(endPointFormat) < 0) throw new Error('Invalid end point format: ' + endPointFormat); | ||||
| 		return 'https://' + endPointFormat + '.dropboxapi.com/2'; | ||||
| @@ -49,6 +61,35 @@ class DropboxApi { | ||||
| 		return output.join(' ');		 | ||||
| 	} | ||||
|  | ||||
| 	async execAuthToken(authCode) { | ||||
| 		const postData = { | ||||
| 			code: authCode, | ||||
| 			grant_type: 'authorization_code', | ||||
| 			client_id: this.clientId(), | ||||
| 			client_secret: this.clientSecret(), | ||||
| 		}; | ||||
|  | ||||
| 		var formBody = []; | ||||
| 		for (var property in postData) { | ||||
| 			var encodedKey = encodeURIComponent(property); | ||||
| 			var encodedValue = encodeURIComponent(postData[property]); | ||||
| 			formBody.push(encodedKey + "=" + encodedValue); | ||||
| 		} | ||||
| 		formBody = formBody.join("&"); | ||||
|  | ||||
| 		const response = await shim.fetch('https://api.dropboxapi.com/oauth2/token', { | ||||
| 			method: 'POST', | ||||
| 			headers: { | ||||
| 				'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' | ||||
| 			}, | ||||
| 			body: formBody | ||||
| 		}); | ||||
|  | ||||
| 		const responseText = await response.text(); | ||||
| 		if (!response.ok) throw new Error(responseText); | ||||
| 		return JSON.parse(responseText); | ||||
| 	} | ||||
|  | ||||
| 	async exec(method, path = '', body = null, headers = null, options = null) { | ||||
| 		if (headers === null) headers = {}; | ||||
| 		if (options === null) options = {}; | ||||
| @@ -56,7 +97,7 @@ class DropboxApi { | ||||
|  | ||||
| 		const authToken = this.authToken(); | ||||
|  | ||||
| 		if (authToken) headers['Authorization'] = authToken; | ||||
| 		if (authToken) headers['Authorization'] = 'Bearer ' + authToken; | ||||
|  | ||||
| 		const endPointFormat = ['files/upload', 'files/download'].indexOf(path) >= 0 ? 'content' : 'api'; | ||||
|  | ||||
| @@ -73,7 +114,7 @@ class DropboxApi { | ||||
| 		if (options.path) fetchOptions.path = options.path; | ||||
| 		if (body) fetchOptions.body = body; | ||||
|  | ||||
| 		const url = this.baseUrl(endPointFormat) + '/' + path; | ||||
| 		const url = path.indexOf('https://') === 0 ? path : this.baseUrl(endPointFormat) + '/' + path; | ||||
|  | ||||
| 		let tryCount = 0; | ||||
|  | ||||
|   | ||||
| @@ -26,9 +26,18 @@ class SyncTargetDropbox extends BaseSyncTarget { | ||||
| 		return _('Dropbox'); | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 		const f = this.fileApiSync(); | ||||
| 		return f && f.driver().api().authToken(); | ||||
| 	authRouteName() { | ||||
| 		return 'DropboxLogin'; | ||||
| 	} | ||||
|  | ||||
| 	async isAuthenticated() { | ||||
| 		const f = await this.fileApi(); | ||||
| 		return !!f.driver().api().authToken(); | ||||
| 	} | ||||
|  | ||||
| 	async api() { | ||||
| 		const fileApi = await this.fileApi(); | ||||
| 		return fileApi.driver().api(); | ||||
| 	} | ||||
|  | ||||
| 	syncTargetId() { | ||||
| @@ -36,7 +45,19 @@ class SyncTargetDropbox extends BaseSyncTarget { | ||||
| 	} | ||||
|  | ||||
| 	async initFileApi() { | ||||
| 		const api = new DropboxApi(); | ||||
| 		const params = parameters().dropbox; | ||||
|  | ||||
| 		const api = new DropboxApi({ | ||||
| 			id: params.id, | ||||
| 			secret: params.secret, | ||||
| 		}); | ||||
|  | ||||
| 		const authJson = Setting.value('sync.' + SyncTargetDropbox.id() + '.auth'); | ||||
| 		if (authJson) { | ||||
| 			const auth = JSON.parse(authJson); | ||||
| 			api.setAuthToken(auth.access_token); | ||||
| 		} | ||||
|  | ||||
| 		const appDir = ''; | ||||
| 		const fileApi = new FileApi(appDir, new FileApiDriverDropbox(api)); | ||||
| 		fileApi.setSyncTargetId(this.syncTargetId()); | ||||
| @@ -45,7 +66,7 @@ class SyncTargetDropbox extends BaseSyncTarget { | ||||
| 	} | ||||
|  | ||||
| 	async initSynchronizer() { | ||||
| 		if (!this.isAuthenticated()) throw new Error('User is not authentified'); | ||||
| 		if (!(await this.isAuthenticated())) throw new Error('User is not authentified'); | ||||
| 		return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType')); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class SyncTargetFilesystem extends BaseSyncTarget { | ||||
| 		return _('File system'); | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class SyncTargetMemory extends BaseSyncTarget { | ||||
| 		return 'Memory'; | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -28,7 +28,7 @@ class SyncTargetNextcloud extends BaseSyncTarget { | ||||
| 		return _('Nextcloud'); | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ class SyncTargetOneDrive extends BaseSyncTarget { | ||||
| 		return _('OneDrive'); | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return this.api().auth(); | ||||
| 	} | ||||
|  | ||||
| @@ -80,7 +80,7 @@ class SyncTargetOneDrive extends BaseSyncTarget { | ||||
| 	} | ||||
|  | ||||
| 	async initSynchronizer() { | ||||
| 		if (!this.isAuthenticated()) throw new Error('User is not authentified'); | ||||
| 		if (!await this.isAuthenticated()) throw new Error('User is not authentified'); | ||||
| 		return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType')); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class SyncTargetWebDAV extends BaseSyncTarget { | ||||
| 		return _('WebDAV'); | ||||
| 	} | ||||
|  | ||||
| 	isAuthenticated() { | ||||
| 	async isAuthenticated() { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -36,7 +36,7 @@ shared.synchronize_press = async function(comp) { | ||||
|  | ||||
| 	const action = comp.props.syncStarted ? 'cancel' : 'start'; | ||||
|  | ||||
| 	if (!reg.syncTarget().isAuthenticated()) { | ||||
| 	if (!await reg.syncTarget().isAuthenticated()) { | ||||
| 		if (reg.syncTarget().authRouteName()) { | ||||
| 			comp.props.dispatch({ | ||||
| 				type: 'NAV_GO', | ||||
|   | ||||
| @@ -99,7 +99,7 @@ class Setting extends BaseModel { | ||||
| 			}}, | ||||
| 			'noteVisiblePanes': { value: ['editor', 'viewer'], type: Setting.TYPE_ARRAY, public: false, appTypes: ['desktop'] }, | ||||
| 			'showAdvancedOptions': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['mobile' ], label: () => _('Show advanced options') }, | ||||
| 			'sync.target': { value: SyncTargetRegistry.nameToId('onedrive'), type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation target'), description: (appType) => { return appType !== 'cli' ? null : _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).') }, options: () => { | ||||
| 			'sync.target': { value: SyncTargetRegistry.nameToId('dropbox'), type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation target'), description: (appType) => { return appType !== 'cli' ? null : _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).') }, options: () => { | ||||
| 				return SyncTargetRegistry.idAndLabelPlainObject(); | ||||
| 			}}, | ||||
|  | ||||
| @@ -121,12 +121,14 @@ class Setting extends BaseModel { | ||||
|  | ||||
| 			'sync.3.auth': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.4.auth': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.7.auth': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.1.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.2.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.3.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.4.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.5.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.6.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 			'sync.7.context': { value: '', type: Setting.TYPE_STRING, public: false }, | ||||
| 		}; | ||||
|  | ||||
| 		return this.metadata_; | ||||
|   | ||||
| @@ -11,6 +11,10 @@ parameters_.dev = { | ||||
| 		id: '606fd4d7-4dfb-4310-b8b7-a47d96aa22b6', | ||||
| 		secret: 'qabchuPYL7931$ePDEQ3~_$', | ||||
| 	}, | ||||
| 	dropbox: { | ||||
| 		id: 'cx9li9ur8taq1z7', | ||||
| 		secret: 'i8f9a1mvx3bijrt', | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| parameters_.prod = { | ||||
| @@ -22,6 +26,10 @@ parameters_.prod = { | ||||
| 		id: '606fd4d7-4dfb-4310-b8b7-a47d96aa22b6', | ||||
| 		secret: 'qabchuPYL7931$ePDEQ3~_$', | ||||
| 	}, | ||||
| 	dropbox: { | ||||
| 		id: 'm044w3cvmxhzvop', | ||||
| 		secret: 'r298deqisz0od56', | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| function parameters(env = null) { | ||||
|   | ||||
| @@ -70,7 +70,7 @@ reg.scheduleSync = async (delay = null, syncOptions = null) => { | ||||
|  | ||||
| 		const syncTargetId = Setting.value('sync.target'); | ||||
|  | ||||
| 		if (!reg.syncTarget(syncTargetId).isAuthenticated()) { | ||||
| 		if (!await reg.syncTarget(syncTargetId).isAuthenticated()) { | ||||
| 			reg.logger().info('Synchroniser is missing credentials - manual sync required to authenticate.'); | ||||
| 			promiseResolve(); | ||||
| 			return; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user