You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	fetchblob
This commit is contained in:
		| @@ -131,6 +131,7 @@ dependencies { | ||||
|     compile "com.android.support:appcompat-v7:23.0.1" | ||||
|     compile "com.facebook.react:react-native:+"  // From node_modules | ||||
|     compile project(':react-native-sqlite-storage') | ||||
|     compile project(':react-native-fetch-blob') | ||||
| } | ||||
|  | ||||
| // Run this once to be able to run the application with BUCK | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
|     android:versionName="1.0"> | ||||
|  | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  | ||||
|     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | ||||
|     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | ||||
|  | ||||
| @@ -25,6 +26,7 @@ | ||||
|         <intent-filter> | ||||
|             <action android:name="android.intent.action.MAIN" /> | ||||
|             <category android:name="android.intent.category.LAUNCHER" /> | ||||
|      <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/> | ||||
|         </intent-filter> | ||||
|       </activity> | ||||
|       <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> | ||||
|   | ||||
| @@ -9,36 +9,38 @@ import com.facebook.react.ReactPackage; | ||||
| import com.facebook.react.shell.MainReactPackage; | ||||
| import com.facebook.soloader.SoLoader; | ||||
| import org.pgsqlite.SQLitePluginPackage; | ||||
| import com.RNFetchBlob.RNFetchBlobPackage; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
|  | ||||
| public class MainApplication extends Application implements ReactApplication { | ||||
|  | ||||
|   private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { | ||||
|     @Override | ||||
|     public boolean getUseDeveloperSupport() { | ||||
|       return BuildConfig.DEBUG; | ||||
|     } | ||||
| 	private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { | ||||
| 		@Override | ||||
| 		public boolean getUseDeveloperSupport() { | ||||
| 			return BuildConfig.DEBUG; | ||||
| 		} | ||||
|  | ||||
|     @Override | ||||
|     protected List<ReactPackage> getPackages() { | ||||
|       return Arrays.<ReactPackage>asList( | ||||
|           new SQLitePluginPackage(), | ||||
|           new MainReactPackage(), | ||||
|             new RNFSPackage() | ||||
|       ); | ||||
|     } | ||||
|   }; | ||||
| 		@Override | ||||
| 		protected List<ReactPackage> getPackages() { | ||||
| 			return Arrays.<ReactPackage>asList( | ||||
| 				new SQLitePluginPackage(), | ||||
| 				new MainReactPackage(), | ||||
| 				new RNFSPackage(), | ||||
| 				new RNFetchBlobPackage() | ||||
| 			); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|   @Override | ||||
|   public ReactNativeHost getReactNativeHost() { | ||||
|     return mReactNativeHost; | ||||
|   } | ||||
| 	@Override | ||||
| 	public ReactNativeHost getReactNativeHost() { | ||||
| 		return mReactNativeHost; | ||||
| 	} | ||||
|  | ||||
|   @Override | ||||
|   public void onCreate() { | ||||
|     super.onCreate(); | ||||
|     SoLoader.init(this, /* native exopackage */ false); | ||||
|   } | ||||
| 	@Override | ||||
| 	public void onCreate() { | ||||
| 		super.onCreate(); | ||||
| 		SoLoader.init(this, /* native exopackage */ false); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -5,4 +5,7 @@ project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../no | ||||
| include ':app' | ||||
|  | ||||
| include ':react-native-sqlite-storage' | ||||
| project(':react-native-sqlite-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlite-storage/src/android') | ||||
| project(':react-native-sqlite-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlite-storage/src/android') | ||||
|  | ||||
| include ':react-native-fetch-blob' | ||||
| project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android') | ||||
| @@ -85,15 +85,21 @@ class FileApiDriverOneDrive { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	async get(path) { | ||||
| 		let content = null; | ||||
| 	async get(path, options = null) { | ||||
| 		if (!options) options = {}; | ||||
|  | ||||
| 		try { | ||||
| 			content = await this.api_.execText('GET', this.makePath_(path) + ':/content'); | ||||
| 			if (options.target == 'file') { | ||||
| 				let response = await this.api_.exec('GET', this.makePath_(path) + ':/content', null, null, options); | ||||
| 				return response; | ||||
| 			} else { | ||||
| 				let content = await this.api_.execText('GET', this.makePath_(path) + ':/content'); | ||||
| 				return content; | ||||
| 			} | ||||
| 		} catch (error) { | ||||
| 			if (error.code == 'itemNotFound') return null; | ||||
| 			throw error; | ||||
| 		} | ||||
| 		return content; | ||||
| 	} | ||||
|  | ||||
| 	async mkdir(path) { | ||||
|   | ||||
| @@ -62,7 +62,8 @@ class FileApi { | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	get(path, options = {}) { | ||||
| 	get(path, options = null) { | ||||
| 		if (!options) options = {}; | ||||
| 		if (!options.encoding) options.encoding = 'utf8'; | ||||
| 		this.logger().debug('get ' + this.fullPath_(path)); | ||||
| 		return this.driver_.get(this.fullPath_(path), options); | ||||
|   | ||||
| @@ -46,6 +46,7 @@ class Setting extends BaseModel { | ||||
| 	} | ||||
|  | ||||
| 	static setConstant(key, value) { | ||||
| 		if (!(key in this.constants_)) throw new Error('Unknown constant key: ' + key); | ||||
| 		this.constants_[key] = value; | ||||
| 	} | ||||
|  | ||||
| @@ -152,6 +153,9 @@ Setting.defaults_ = { | ||||
| Setting.constants_ = { | ||||
| 	'appName': 'joplin', | ||||
| 	'appId': 'SET_ME', // Each app should set this identifier | ||||
| 	'resourceDir': '', | ||||
| 	'profileDir': '', | ||||
| 	'tempDir': '', | ||||
| } | ||||
|  | ||||
| export { Setting }; | ||||
| @@ -84,6 +84,7 @@ class OneDriveApi { | ||||
| 		try { | ||||
| 			const json = await r.json(); | ||||
| 			this.setAuth(json); | ||||
| 			this.dispatch('authRefreshed', this.auth()); | ||||
| 		} catch (error) { | ||||
| 			const text = await r.text(); | ||||
| 			error.message += ': ' + text; | ||||
| @@ -110,6 +111,7 @@ class OneDriveApi { | ||||
|  | ||||
| 		if (!options) options = {}; | ||||
| 		if (!options.headers) options.headers = {}; | ||||
| 		if (!options.target) options.target = 'string'; | ||||
|  | ||||
| 		if (method != 'GET') { | ||||
| 			options.method = method; | ||||
| @@ -137,7 +139,13 @@ class OneDriveApi { | ||||
| 		for (let i = 0; i < 5; i++) { | ||||
| 			options.headers['Authorization'] = 'bearer ' + this.token(); | ||||
|  | ||||
| 			let response = await shim.fetch(url, options); | ||||
| 			let response = null; | ||||
| 			if (options.target == 'string') { | ||||
| 				response = await shim.fetch(url, options); | ||||
| 			} else { // file | ||||
| 				response = await shim.fetchBlob(url, options); | ||||
| 			} | ||||
|  | ||||
| 			if (!response.ok) { | ||||
| 				let errorResponse = await response.json(); | ||||
| 				let error = this.oneDriveErrorResponseToError(errorResponse); | ||||
| @@ -194,7 +202,7 @@ class OneDriveApi { | ||||
|  | ||||
| 		let body = new shim.FormData(); | ||||
| 		body.append('client_id', this.clientId()); | ||||
| 		body.append('client_secret', this.clientSecret()); | ||||
| 		// body.append('client_secret', this.clientSecret()); // TODO: NEEDED FOR NODE | ||||
| 		body.append('refresh_token', this.auth_.refresh_token); | ||||
| 		body.append('redirect_uri', 'http://localhost:1917'); | ||||
| 		body.append('grant_type', 'refresh_token'); | ||||
|   | ||||
| @@ -29,6 +29,7 @@ reg.oneDriveApi = () => { | ||||
| 	} | ||||
|  | ||||
| 	reg.oneDriveApi_.on('authRefreshed', (a) => { | ||||
| 		reg.logger().info('Saving updated OneDrive auth.'); | ||||
| 		Setting.setValue('sync.onedrive.auth', JSON.stringify(a)); | ||||
| 	}); | ||||
| 	 | ||||
| @@ -58,6 +59,7 @@ reg.synchronizer = async () => { | ||||
|  | ||||
| 	let fileApi = await reg.fileApi(); | ||||
| 	reg.synchronizer_ = new Synchronizer(reg.db(), fileApi); | ||||
| 	reg.synchronizer_.setLogger(reg.logger()); | ||||
| 	return reg.synchronizer_; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -320,6 +320,12 @@ class Synchronizer { | ||||
| 						// 	await Resource.setContent(newContent, remoteResourceContent); | ||||
| 						// } | ||||
|  | ||||
| 						if (newContent.type_ == BaseModel.TYPE_RESOURCE && action == 'createLocal') { | ||||
| 							let localResourceContentPath = Resource.fullPath(newContent); | ||||
| 							let remoteResourceContentPath = this.resourceDirName_ + '/' + newContent.id; | ||||
| 							await this.api().get(remoteResourceContentPath, { path: localResourceContentPath, target: 'file' }); | ||||
| 						} | ||||
|  | ||||
| 						await ItemClass.save(newContent, options); | ||||
|  | ||||
| 						this.logSyncOperation(action, local, content, reason); | ||||
|   | ||||
| @@ -10,10 +10,11 @@ | ||||
|     "dropbox": "^2.5.4", | ||||
|     "form-data": "^2.1.4", | ||||
|     "moment": "^2.18.1", | ||||
|     "react": "16.0.0-alpha.6", | ||||
|     "react-native": "0.44.0", | ||||
|     "react": "16.0.0-alpha.12", | ||||
|     "react-native": "0.46.0", | ||||
|     "react-native-action-button": "^2.6.9", | ||||
|     "react-native-checkbox": "^1.1.0", | ||||
|     "react-native-fetch-blob": "^0.10.6", | ||||
|     "react-native-fs": "^2.3.3", | ||||
|     "react-native-popup-menu": "^0.7.4", | ||||
|     "react-native-side-menu": "^0.20.1", | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { createStore } from 'redux'; | ||||
| import { combineReducers } from 'redux'; | ||||
| import { StackNavigator } from 'react-navigation'; | ||||
| import { addNavigationHelpers } from 'react-navigation'; | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { Log } from 'lib/log.js' | ||||
| import { Note } from 'lib/models/note.js' | ||||
| import { Folder } from 'lib/models/folder.js' | ||||
| @@ -193,9 +194,47 @@ const AppNavigator = StackNavigator({ | ||||
| 	OneDriveLogin: { screen: OneDriveLoginScreen }, | ||||
| }); | ||||
|  | ||||
| import RNFetchBlob from 'react-native-fetch-blob' | ||||
|  | ||||
|  | ||||
| class AppComponent extends React.Component { | ||||
|  | ||||
| 	componentDidMount() { | ||||
| 	async componentDidMount() { | ||||
|  | ||||
| 		shim.fetchBlob = async function(url, options) { | ||||
| 			if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 			if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 			let headers = options.headers ? options.headers : {}; | ||||
| 			let method = options.method ? options.method : 'GET'; | ||||
|  | ||||
| 			let dirs = RNFetchBlob.fs.dirs; | ||||
| 			let localFilePath = options.path; | ||||
| 			if (localFilePath.indexOf('/') !== 0) localFilePath = dirs.DocumentDir + '/' + localFilePath; | ||||
|  | ||||
| 			delete options.path; | ||||
|  | ||||
| 			try { | ||||
| 				let response = await RNFetchBlob.config({ | ||||
| 					path: localFilePath | ||||
| 				}).fetch(method, url, headers); | ||||
|  | ||||
| 				// Returns an object that roughtly compatible with a standard Response object | ||||
| 				let output = { | ||||
| 					ok: response.respInfo.status < 400, | ||||
| 					path: response.data, | ||||
| 					text: response.text, | ||||
| 					json: response.json, | ||||
| 					status: response.respInfo.status, | ||||
| 					headers: response.respInfo.headers, | ||||
| 				}; | ||||
|  | ||||
| 				return output; | ||||
| 			} catch (error) { | ||||
| 				throw new Error('fetchBlob: ' + method + ' ' + url + ': ' + error.toString()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		let db = new Database(new DatabaseDriverReactNative()); | ||||
| 		reg.setDb(db); | ||||
|  | ||||
| @@ -209,33 +248,39 @@ class AppComponent extends React.Component { | ||||
| 		BaseItem.loadClass('Tag', Tag); | ||||
| 		BaseItem.loadClass('NoteTag', NoteTag); | ||||
|  | ||||
| 		db.open({ name: '/storage/emulated/0/Download/joplin-44.sqlite' }).then(() => { | ||||
| 		try { | ||||
| 			await db.open({ name: '/storage/emulated/0/Download/joplin-44.sqlite' }) | ||||
| 			Log.info('Database is ready.'); | ||||
| 		}).then(() => { | ||||
|  | ||||
| 			//await db.exec('DELETE FROM notes'); | ||||
| 			//await db.exec('DELETE FROM folders'); | ||||
| 			//await db.exec('DELETE FROM tags'); | ||||
| 			//await db.exec('DELETE FROM note_tags'); | ||||
| 			//await db.exec('DELETE FROM resources'); | ||||
| 			//await db.exec('DELETE FROM deleted_items'); | ||||
|  | ||||
| 			Log.info('Loading settings...'); | ||||
| 			return Setting.load(); | ||||
| 		}).then(() => { | ||||
| 			await Setting.load(); | ||||
| 			 | ||||
| 			Setting.setConstant('appId', 'net.cozic.joplin-android'); | ||||
| 			Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir); | ||||
|  | ||||
| 			Log.info('Loading folders...'); | ||||
|  | ||||
| 			return Folder.all().then((folders) => { | ||||
| 				this.props.dispatch({ | ||||
| 					type: 'FOLDERS_UPDATE_ALL', | ||||
| 					folders: folders, | ||||
| 				}); | ||||
| 				return folders; | ||||
| 			}).catch((error) => { | ||||
| 				Log.warn('Cannot load folders', error); | ||||
| 			let folders = await Folder.all(); | ||||
|  | ||||
| 			this.props.dispatch({ | ||||
| 				type: 'FOLDERS_UPDATE_ALL', | ||||
| 				folders: folders, | ||||
| 			}); | ||||
| 		}).then((folders) => { | ||||
|  | ||||
| 			this.props.dispatch({ | ||||
| 				type: 'Navigation/NAVIGATE', | ||||
| 				routeName: 'Folders', | ||||
| 			}); | ||||
| 		}).catch((error) => { | ||||
| 		} catch (error) { | ||||
| 			Log.error('Initialization error:', error); | ||||
| 		}); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sideMenu_change(isOpen) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user