def sync_file_from_dropbox(node_id, use_ust=True, callback=None): """ Sync file which was updated on dropbox Arguments: node_id: updated file use_ust: if True, process remove in User Synchronous mode """ node, db_sess = _get_node(node_id) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, node.user) else: ust_start(node.user) l.info("sync_file_FROM_dropbox: '%s'" % (node.db_path, )) try: # Read file content from dropbox if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.read_file(encode_if_unicode(node.db_path), callback=(yield gen.Callback(yield_key))) content = yield gen.Wait(yield_key) else: content = db_sess.read_file(encode_if_unicode(node.db_path)) # And save it to local storage _save_and_convert(node, content) # User may want to know that this file was synced append_to_changes_list(node.user, node.db_path) except Exception, e: err_msg = "SYNC_file_from_dropbox: '%s' (%s)" %\ (node.db_path, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def _save_and_convert(node, content): """ Helper - saves content into local file and converts to html if needed NOTE: caller must process all exceptions """ # Sanity check if not node.is_file: l.error("save_and_convert: '%s' is not a file ?!" % (node.srv_src, )) return # Store it in local copy # TODO: use Tornado's async IO f = open(encode_if_unicode(node.srv_src), "wb") f.write(encode_if_unicode(content)) f.close() l.info("save_and_convert: SRC saved '%s' (%d bytes), " % (node.srv_src, len(content), )) # Convert markdown to html if os.path.splitext(node.db_path)[1] in settings.SUPPORTED_EXTS: html = md_to_html(node, content) # Store it on server # TODO: use Tornado's async IO f = open(encode_if_unicode(node.srv_html), "wb") f.write(html.encode('utf-8')) f.close() l.info("save_and_convert: HTML saved '%s' (%d bytes), " % (node.srv_html, len(html), )) MDBTree.objects.filter(pk=node.pk).update(last_synced = datetime.utcnow())
def save_node(node_id, content, use_ust=True, callback=None): """ Save content into node (must be a file !) Arguments: node_id: node to update content: content to write to file use_ust: if True, process save in User Synchronous mode """ node, db_sess = _get_node(node_id) l.info("save_node: %s" % (node.db_path, )) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, node.user) else: ust_start(node.user) try: # First save to dropbox u_content = force_unicode((smart_unicode(content))) if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.write_file(encode_if_unicode(node.db_path), u_content, callback=(yield gen.Callback(yield_key))) ret_dict = yield gen.Wait(yield_key) else: ret_dict = db_sess.write_file(encode_if_unicode(node.db_path), u_content) # Then to local storage _save_and_convert(node, content) except Exception, e: err_msg = "save_node: can't save %s (%s)" %\ (node.db_path, e, ) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def rename_node(node_id, new_filename, use_ust=True, callback=None): """ Rename node to new_filename Arguments: node_id: node to rename new_filename: filename to remove to (can be both directory and file) use_ust: if True, process remove in User Synchronous mode """ node, db_sess = _get_node(node_id) l.info("rename_node: '%s' -> '%s'" % (node.db_path, new_filename, )) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, node.user) else: ust_start(node.user) # TODO: Dropbox exception's text contains HTML, which can't be parsed # TODO: correctly by frontend, use Reason (part of exception dict) try: # First rename on dropbox new_db_path = get_dropbox_path(os.path.split(node.db_path)[0], new_filename) from_path = encode_if_unicode(node.db_path) to_path = encode_if_unicode(new_db_path) if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.move_file(from_path, to_path, callback=(yield gen.Callback(yield_key))) ret_dict = yield gen.Wait(yield_key) else: db_sess.db_client.file_move(from_path, to_path) # Then on local storage new_src = get_server_src_file_path(node.user, new_db_path) forced_rename(node.srv_src, new_src) new_html = get_server_html_file_path(node.user, new_db_path) if new_html != "": forced_rename(node.srv_html, new_html) # And the object itself MDBTree.objects.filter(pk=node.pk).update( db_path = new_db_path, srv_src = new_src, srv_html = new_html, ) except Exception, e: err_msg = "rename_node: '%s' -> '%s' (%s)" %\ (node.db_path, new_filename, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def create_new_file(parent_node_id, filename, content, use_ust=True, callback=None): """ Add new file TO dropbox and also to our database and to server NOTE: filename should be just the name of the file, without any path elements (it will be added as file in parent_node) Arguments: parent_node_id: dir where the file should be created filename: name of new file content: initial content use_ust: if True, process remove in User Synchronous mode """ parent_node, db_sess = _get_node(parent_node_id) l.info("create_new_file: '%s' in '%s' (%d bytes)" %\ (filename, parent_node.db_path, len(content), )) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, parent_node.user) else: ust_start(parent_node.user) try: # We first create file ON dropbox and then sync it back # to our database and server to keep the exec logic consistent db_file_path = get_dropbox_path(parent_node.db_path, filename) if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.write_file(encode_if_unicode(db_file_path), content, callback=(yield gen.Callback(yield_key))) ret_dict = yield gen.Wait(yield_key) else: ret_dict = db_sess.write_file(encode_if_unicode(db_file_path), content) l.info("create_new_file: '%s' in '%s' DONE. Now syncing dir..." %\ (filename, parent_node.db_path, )) if django_settings.ASYNC_DROPBOX: yield_key = object() add_file_from_dropbox(parent_node.id, db_file_path, datetime.utcnow(), use_ust=False, callback=(yield gen.Callback(yield_key))) ret_dict = yield gen.Wait(yield_key) else: add_file_from_dropbox(parent_node.id, db_file_path, datetime.utcnow(), use_ust=False) except Exception, e: err_msg = "create_new_file: '%s' in '%s' (%s)" %\ (filename, parent_node.db_path, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def remove_node_as_file(node_id, skip_dropbox=False, use_ust=True, callback=None): """ Remove node (must be a file !) Arguments: node_id: node to remove skip_dropbox: if True, only remove from local storage (used in sync) use_ust: if True, process remove in User Synchronous mode """ node, db_sess = _get_node(node_id) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, node.user) else: ust_start(node.user) try: # First remove from dropbox if not skip_dropbox: if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.delete_file(encode_if_unicode(node.db_path), callback=(yield gen.Callback(yield_key))) yield gen.Wait(yield_key) else: db_sess.db_client.file_delete(encode_if_unicode(node.db_path)) else: l.info("remove_node_as_file: '%s' skipping dropbox removal" %\ (node.db_path, )) # Then from local storage for file in (node.srv_html, node.srv_src): l.info("remove_node_as_file: removing '%s'" %\ (file, )) if not os.path.exists(file): l.info("remove_node_as_file: '%s' does not exists ?!" %\ (file, )) else: os.remove(file) # Also delete treebeard node node.delete() except Exception, e: err_msg = "remove_node_as_file: '%s' (%s)" %\ (node.db_path, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def create_new_dir(parent_node_id, dir_name, use_ust=True, callback=None): """ Add new directory TO dropbox and also to our database and to server NOTE: directory should be just the name of the directory, without any path elements (it will be added in parent_node) Arguments: parent_node_id: dir where the new dir should be created filename: name of new dir use_ust: if True, process remove in User Synchronous mode """ parent_node, db_sess = _get_node(parent_node_id) l.info("create_new_dir: '%s' in '%s'" %\ (dir_name, parent_node.db_path, )) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, parent_node.user) else: ust_start(parent_node.user) try: # First save to dropbox db_dir_path = get_dropbox_path(parent_node.db_path, dir_name) if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.create_folder(encode_if_unicode(db_dir_path), callback=(yield gen.Callback(yield_key))) ret_dict = yield gen.Wait(yield_key) else: ret_dict = db_sess.db_client.file_create_folder(encode_if_unicode(db_dir_path)) l.info("create_new_dir: '%s' in '%s' DONE. Now syncing parent..." %\ (dir_name, parent_node.db_path, )) if django_settings.ASYNC_DROPBOX: yield_key = object() add_dir_from_dropbox(parent_node.id, db_dir_path, use_ust=False, callback=(yield gen.Callback(yield_key))) yield gen.Wait(yield_key) else: add_dir_from_dropbox(parent_node.id, db_dir_path, use_ust=False) except Exception, e: err_msg = "create_new_dir: '%s' -> '%s' (%s)" %\ (dir_name, parent_node.db_path, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def remove_node_as_dir(node_id, skip_dropbox=False, use_ust=True, callback=None): """ Remove node (must be a directory !) Arguments: node_id: node to remove skip_dropbox: if True, only remove from local storage (used in sync) use_ust: if True, process remove in User Synchronous mode """ node, db_sess = _get_node(node_id) if use_ust: if django_settings.ASYNC_DROPBOX: yield gen.Task(async_ust_start, node.user) else: ust_start(node.user) try: # Remove dir from dropbox if asked if not skip_dropbox: # Removes dir from dropbox (recursively) if django_settings.ASYNC_DROPBOX: yield_key = object() db_sess.delete_file(encode_if_unicode(node.db_path), callback=(yield gen.Callback(yield_key))) yield gen.Wait(yield_key) else: db_sess.db_client.file_delete(encode_if_unicode(node.db_path)) else: l.info("remove_node_as_dir: '%s' skipping dropbox removal" %\ (node.db_path, )) # Then from local storage remove_server_dir(node.user, node.db_path) # Go through treebeard to find and delete node's descendants for child in node.get_children(): child.delete() # And finally delete treebeard node node.delete() except Exception, e: err_msg = "remove_node_as_dir: '%s' (%s)" %\ (node.db_path, e,) l.error(err_msg) raise MDBException("ERROR: "+err_msg)
def get_src_url(self): """ Figures out src url for node """ if self.is_file: #url = self.file.srv_src_file.replace(settings.NGINX_ROOT, '', 1) #url = settings.NGINX_WWW[:7]+self.user.slug+'.'+settings.NGINX_WWW[7:]+self.db_path url = settings.NGINX_WWW+'/users/'+self.user.slug+self.db_path else: url = self.db_path return encode_if_unicode(url)
def get_html_url(self): """ Figures out html url for node """ if self.is_file: # We rendered .html only for supported files path_no_ext, ext = os.path.splitext(self.db_path) if ext in settings.SUPPORTED_EXTS: #url = self.file.srv_html_file.replace(settings.NGINX_ROOT, '', 1) url = settings.NGINX_WWW[:7]+self.user.slug+'.'+settings.NGINX_WWW[7:]+path_no_ext+'.html' #url = settings.NGINX_WWW+'/users/'+self.user.slug+path_no_ext+'.html' else: url = self.get_src_url() else: url = self.db_path return encode_if_unicode(url)
def get_absolute_url(self): """ Returns absolute url based on node type """ return ('view_node_src', (), { 'path': urllib.quote(encode_if_unicode(self.db_path.lstrip('/')), safe=""), # "%/:=&?~#+!$,;'@()*[]" })
def get_db_path(self): """ Returns dropbox path (actual node name) """ return encode_if_unicode(self.db_path)
def basename(self): """ Returns basename for node """ if self.db_path == '/': return '/' else: return encode_if_unicode(os.path.basename(self.db_path))