mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 15:23:02 +00:00 
			
		
		
		
	#538:
-Refactoring gdrive and file handling -Improved error handling for gdrive -bugfix "gdrive stopping after a while" - Renaming book title working - Still Bugs in upload file to gdrive and renaming author
This commit is contained in:
		| @@ -5,9 +5,9 @@ try: | |||||||
| except ImportError: | except ImportError: | ||||||
|     pass |     pass | ||||||
| import os | import os | ||||||
|  |  | ||||||
| from ub import config | from ub import config | ||||||
| import cli | import cli | ||||||
|  | import shutil | ||||||
|  |  | ||||||
| from sqlalchemy import * | from sqlalchemy import * | ||||||
| from sqlalchemy.ext.declarative import declarative_base | from sqlalchemy.ext.declarative import declarative_base | ||||||
| @@ -16,6 +16,57 @@ from sqlalchemy.orm import * | |||||||
|  |  | ||||||
| import web | import web | ||||||
|  |  | ||||||
|  | class Singleton: | ||||||
|  |     """ | ||||||
|  |     A non-thread-safe helper class to ease implementing singletons. | ||||||
|  |     This should be used as a decorator -- not a metaclass -- to the | ||||||
|  |     class that should be a singleton. | ||||||
|  |  | ||||||
|  |     The decorated class can define one `__init__` function that | ||||||
|  |     takes only the `self` argument. Also, the decorated class cannot be | ||||||
|  |     inherited from. Other than that, there are no restrictions that apply | ||||||
|  |     to the decorated class. | ||||||
|  |  | ||||||
|  |     To get the singleton instance, use the `Instance` method. Trying | ||||||
|  |     to use `__call__` will result in a `TypeError` being raised. | ||||||
|  |  | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, decorated): | ||||||
|  |         self._decorated = decorated | ||||||
|  |  | ||||||
|  |     def Instance(self): | ||||||
|  |         """ | ||||||
|  |         Returns the singleton instance. Upon its first call, it creates a | ||||||
|  |         new instance of the decorated class and calls its `__init__` method. | ||||||
|  |         On all subsequent calls, the already created instance is returned. | ||||||
|  |  | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             return self._instance | ||||||
|  |         except AttributeError: | ||||||
|  |             self._instance = self._decorated() | ||||||
|  |             return self._instance | ||||||
|  |  | ||||||
|  |     def __call__(self): | ||||||
|  |         raise TypeError('Singletons must be accessed through `Instance()`.') | ||||||
|  |  | ||||||
|  |     def __instancecheck__(self, inst): | ||||||
|  |         return isinstance(inst, self._decorated) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Singleton | ||||||
|  | class Gauth: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.auth = GoogleAuth(settings_file=os.path.join(config.get_main_dir,'settings.yaml')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Singleton | ||||||
|  | class Gdrive: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.drive = getDrive(gauth=Gauth.Instance().auth) | ||||||
|  |  | ||||||
|  |  | ||||||
| engine = create_engine('sqlite:///{0}'.format(cli.gdpath), echo=False) | engine = create_engine('sqlite:///{0}'.format(cli.gdpath), echo=False) | ||||||
| Base = declarative_base() | Base = declarative_base() | ||||||
|  |  | ||||||
| @@ -110,9 +161,12 @@ def getFolderInFolder(parentId, folderName,drive=None): | |||||||
|         query = "title = '%s' and " % folderName.replace("'", "\\'") |         query = "title = '%s' and " % folderName.replace("'", "\\'") | ||||||
|     folder = query + "'%s' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" % parentId |     folder = query + "'%s' in parents and mimeType = 'application/vnd.google-apps.folder' and trashed = false" % parentId | ||||||
|     fileList = drive.ListFile({'q': folder}).GetList() |     fileList = drive.ListFile({'q': folder}).GetList() | ||||||
|     return fileList[0] |     if fileList.__len__() == 0: | ||||||
|  |         return None | ||||||
|  |     else: | ||||||
|  |         return fileList[0] | ||||||
|  |  | ||||||
|  | # Search for id of root folder in gdrive database, if not found request from gdrive and store in internal database | ||||||
| def getEbooksFolderId(drive=None): | def getEbooksFolderId(drive=None): | ||||||
|     storedPathName = session.query(GdriveId).filter(GdriveId.path == '/').first() |     storedPathName = session.query(GdriveId).filter(GdriveId.path == '/').first() | ||||||
|     if storedPathName: |     if storedPathName: | ||||||
| @@ -131,11 +185,14 @@ def getEbooksFolderId(drive=None): | |||||||
|  |  | ||||||
|  |  | ||||||
| def getFile(pathId, fileName, drive=None): | def getFile(pathId, fileName, drive=None): | ||||||
|     drive = getDrive(drive) |     drive = getDrive(Gdrive.Instance().drive) | ||||||
|     metaDataFile = "'%s' in parents and trashed = false and title = '%s'" % (pathId, fileName.replace("'", "\\'")) |     metaDataFile = "'%s' in parents and trashed = false and title = '%s'" % (pathId, fileName.replace("'", "\\'")) | ||||||
|  |  | ||||||
|     fileList = drive.ListFile({'q': metaDataFile}).GetList() |     fileList = drive.ListFile({'q': metaDataFile}).GetList() | ||||||
|     return fileList[0] |     if fileList.__len__() == 0: | ||||||
|  |         return None | ||||||
|  |     else: | ||||||
|  |         return fileList[0] | ||||||
|  |  | ||||||
|  |  | ||||||
| def getFolderId(path, drive=None): | def getFolderId(path, drive=None): | ||||||
| @@ -156,12 +213,17 @@ def getFolderId(path, drive=None): | |||||||
|                 if storedPathName: |                 if storedPathName: | ||||||
|                     currentFolderId = storedPathName.gdrive_id |                     currentFolderId = storedPathName.gdrive_id | ||||||
|                 else: |                 else: | ||||||
|                     currentFolderId = getFolderInFolder(currentFolderId, x, drive)['id'] |                     currentFolder = getFolderInFolder(currentFolderId, x, drive) | ||||||
|                     gDriveId = GdriveId() |                     if currentFolder: | ||||||
|                     gDriveId.gdrive_id = currentFolderId |                         gDriveId = GdriveId() | ||||||
|                     gDriveId.path = currentPath |                         gDriveId.gdrive_id = currentFolder['id'] | ||||||
|                     session.merge(gDriveId) |                         gDriveId.path = currentPath | ||||||
|                     dbChange = True |                         session.merge(gDriveId) | ||||||
|  |                         dbChange = True | ||||||
|  |                         currentFolderId = currentFolder['id'] | ||||||
|  |                     else: | ||||||
|  |                         currentFolderId= None | ||||||
|  |                         break | ||||||
|         if dbChange: |         if dbChange: | ||||||
|             session.commit() |             session.commit() | ||||||
|     else: |     else: | ||||||
| @@ -169,15 +231,17 @@ def getFolderId(path, drive=None): | |||||||
|     return currentFolderId |     return currentFolderId | ||||||
|  |  | ||||||
|  |  | ||||||
| def getFileFromEbooksFolder(drive, path, fileName): | def getFileFromEbooksFolder(path, fileName): | ||||||
|     drive = getDrive(drive) |     drive = getDrive(Gdrive.Instance().drive) | ||||||
|     if path: |     if path: | ||||||
|         # sqlCheckPath=path if path[-1] =='/' else path + '/' |         # sqlCheckPath=path if path[-1] =='/' else path + '/' | ||||||
|         folderId = getFolderId(path, drive) |         folderId = getFolderId(path, drive) | ||||||
|     else: |     else: | ||||||
|         folderId = getEbooksFolderId(drive) |         folderId = getEbooksFolderId(drive) | ||||||
|  |     if folderId: | ||||||
|     return getFile(folderId, fileName, drive) |         return getFile(folderId, fileName, drive) | ||||||
|  |     else: | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |  | ||||||
| def copyDriveFileRemote(drive, origin_file_id, copy_title): | def copyDriveFileRemote(drive, origin_file_id, copy_title): | ||||||
| @@ -192,9 +256,9 @@ def copyDriveFileRemote(drive, origin_file_id, copy_title): | |||||||
|     return None |     return None | ||||||
|  |  | ||||||
|  |  | ||||||
| def downloadFile(drive, path, filename, output): | def downloadFile(path, filename, output): | ||||||
|     drive = getDrive(drive) |     # drive = getDrive(drive) | ||||||
|     f = getFileFromEbooksFolder(drive, path, filename) |     f = getFileFromEbooksFolder(path, filename) | ||||||
|     f.GetContentFile(output) |     f.GetContentFile(output) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -238,8 +302,8 @@ def copyToDrive(drive, uploadFile, createRoot, replaceFiles, | |||||||
|             driveFile.Upload() |             driveFile.Upload() | ||||||
|  |  | ||||||
|  |  | ||||||
| def uploadFileToEbooksFolder(drive, destFile, f): | def uploadFileToEbooksFolder(destFile, f): | ||||||
|     drive = getDrive(drive) |     drive = getDrive(Gdrive.Instance().drive) | ||||||
|     parent = getEbooksFolder(drive) |     parent = getEbooksFolder(drive) | ||||||
|     splitDir = destFile.split('/') |     splitDir = destFile.split('/') | ||||||
|     for i, x in enumerate(splitDir): |     for i, x in enumerate(splitDir): | ||||||
| @@ -349,10 +413,24 @@ def getChangeById (drive, change_id): | |||||||
|         change = drive.auth.service.changes().get(changeId=change_id).execute() |         change = drive.auth.service.changes().get(changeId=change_id).execute() | ||||||
|         return change |         return change | ||||||
|     except (errors.HttpError) as error: |     except (errors.HttpError) as error: | ||||||
|         web.app.logger.exception(error) |         app.logger.info(error.message) | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
| # Deletes the local hashes database to force search for new folder names | # Deletes the local hashes database to force search for new folder names | ||||||
| def deleteDatabaseOnChange(): | def deleteDatabaseOnChange(): | ||||||
|     session.query(GdriveId).delete() |     session.query(GdriveId).delete() | ||||||
|     session.commit() |     session.commit() | ||||||
|  |  | ||||||
|  | def updateGdriveCalibreFromLocal(): | ||||||
|  |     backupCalibreDbAndOptionalDownload(Gdrive.Instance().drive) | ||||||
|  |     copyToDrive(Gdrive.Instance().drive, config.config_calibre_dir, False, True) | ||||||
|  |     for x in os.listdir(config.config_calibre_dir): | ||||||
|  |         if os.path.isdir(os.path.join(config.config_calibre_dir, x)): | ||||||
|  |             shutil.rmtree(os.path.join(config.config_calibre_dir, x)) | ||||||
|  |  | ||||||
|  | # update gdrive.db on edit of books title | ||||||
|  | def updateDatabaseOnEdit(ID,newPath): | ||||||
|  |     storedPathName = session.query(GdriveId).filter(GdriveId.gdrive_id == ID).first() | ||||||
|  |     if storedPathName: | ||||||
|  |         storedPathName.path = newPath | ||||||
|  |         session.commit() | ||||||
|   | |||||||
| @@ -56,16 +56,6 @@ RET_SUCCESS = 1 | |||||||
| RET_FAIL = 0 | RET_FAIL = 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| def update_download(book_id, user_id): |  | ||||||
|     check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id == |  | ||||||
|                                                                                           book_id).first() |  | ||||||
|  |  | ||||||
|     if not check: |  | ||||||
|         new_download = ub.Downloads(user_id=user_id, book_id=book_id) |  | ||||||
|         ub.session.add(new_download) |  | ||||||
|         ub.session.commit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def make_mobi(book_id, calibrepath): | def make_mobi(book_id, calibrepath): | ||||||
|     error_message = None |     error_message = None | ||||||
|     vendorpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + |     vendorpath = os.path.join(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + | ||||||
| @@ -243,7 +233,6 @@ def send_mail(book_id, kindle_mail, calibrepath): | |||||||
|  |  | ||||||
| def get_attachment(file_path): | def get_attachment(file_path): | ||||||
|     """Get file as MIMEBase message""" |     """Get file as MIMEBase message""" | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         file_ = open(file_path, 'rb') |         file_ = open(file_path, 'rb') | ||||||
|         attachment = MIMEBase('application', 'octet-stream') |         attachment = MIMEBase('application', 'octet-stream') | ||||||
| @@ -306,7 +295,7 @@ def get_sorted_author(value): | |||||||
|     return value2 |     return value2 | ||||||
|  |  | ||||||
|  |  | ||||||
| def delete_book(book, calibrepath): | def delete_book_file(book, calibrepath): | ||||||
|     # check that path is 2 elements deep, check that target path has no subfolders |     # check that path is 2 elements deep, check that target path has no subfolders | ||||||
|     if "/" in book.path: |     if "/" in book.path: | ||||||
|         path = os.path.join(calibrepath, book.path) |         path = os.path.join(calibrepath, book.path) | ||||||
| @@ -314,16 +303,8 @@ def delete_book(book, calibrepath): | |||||||
|     else: |     else: | ||||||
|         logging.getLogger('cps.web').error("Deleting book " + str(book.id) + " failed, book path value: "+ book.path) |         logging.getLogger('cps.web').error("Deleting book " + str(book.id) + " failed, book path value: "+ book.path) | ||||||
|  |  | ||||||
| # ToDo: Implement delete book on gdrive |  | ||||||
| def delete_book_gdrive(book): |  | ||||||
|     # delete book and path of book in gdrive.db |  | ||||||
|     # delete book and path of book on gdrive |  | ||||||
|     #gFile = gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive, os.path.dirname(book.path), titledir) |  | ||||||
|     #gFile.Trash() |  | ||||||
|     pass |  | ||||||
|  |  | ||||||
|  | def update_dir_stucture_file(book_id, calibrepath): | ||||||
| def update_dir_stucture(book_id, calibrepath): |  | ||||||
|     localbook = db.session.query(db.Books).filter(db.Books.id == book_id).first() |     localbook = db.session.query(db.Books).filter(db.Books.id == book_id).first() | ||||||
|     path = os.path.join(calibrepath, localbook.path) |     path = os.path.join(calibrepath, localbook.path) | ||||||
|  |  | ||||||
| @@ -372,18 +353,64 @@ def update_dir_structure_gdrive(book_id): | |||||||
|  |  | ||||||
|     if titledir != new_titledir: |     if titledir != new_titledir: | ||||||
|         # print (titledir) |         # print (titledir) | ||||||
|         gFile = gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive, os.path.dirname(book.path), titledir) |         gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir) | ||||||
|         gFile['title'] = new_titledir |         if gFile: | ||||||
|         gFile.Upload() |             gFile['title'] = new_titledir | ||||||
|         book.path = book.path.split('/')[0] + '/' + new_titledir |  | ||||||
|  |             gFile.Upload() | ||||||
|  |             book.path = book.path.split('/')[0] + '/' + new_titledir | ||||||
|  |             gd.updateDatabaseOnEdit(gFile['id'], book.path)     # only child folder affected | ||||||
|  |         else: | ||||||
|  |             error = _(u'File %s not found on gdrive' % book.path) # file not found | ||||||
|  |  | ||||||
|     if authordir != new_authordir: |     if authordir != new_authordir: | ||||||
|         gFile = gd.getFileFromEbooksFolder(web.Gdrive.Instance().drive, None, authordir) |         gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir) | ||||||
|         gFile['title'] = new_authordir |         # gFileDirOrig = gd.getFileFromEbooksFolder(None, authordir) | ||||||
|         gFile.Upload() |         if gFile: | ||||||
|         book.path = new_authordir + '/' + book.path.split('/')[1] |             # check if authordir exisits | ||||||
|  |             gFileDirOrig = gd.getFileFromEbooksFolder(None, authordir) | ||||||
|  |             if gFileDirOrig: | ||||||
|  |                 gFile['parents'].append({"id": gFileDirOrig['id']}) | ||||||
|  |                 gFile.Upload() | ||||||
|  |             else: | ||||||
|  |                 # Folder is not exisiting | ||||||
|  |                 #parent = drive.CreateFile({'title': authordir, 'parents': [{"kind": "drive#fileLink", 'id': root folder id}], | ||||||
|  |                 #                           "mimeType": "application/vnd.google-apps.folder"}) | ||||||
|  |                 parent.Upload() | ||||||
|  |             # gFile['title'] = new_authordir | ||||||
|  |             # gFile.Upload() | ||||||
|  |             book.path = new_authordir + '/' + book.path.split('/')[1] | ||||||
|  |             gd.updateDatabaseOnEdit(gFile['id'], book.path) | ||||||
|  |             # Todo last element from parent folder moved to different folder, what to do with parent folder? | ||||||
|  |             # parent folder affected | ||||||
|  |         else: | ||||||
|  |             error = _(u'File %s not found on gdrive' % authordir) # file not found | ||||||
|     return error |     return error | ||||||
|  |  | ||||||
|  | # ToDo: Implement delete book on gdrive | ||||||
|  | def delete_book_gdrive(book): | ||||||
|  |     # delete book and path of book in gdrive.db | ||||||
|  |     # delete book and path of book on gdrive | ||||||
|  |     #gFile = gd.getFileFromEbooksFolder(os.path.dirname(book.path), titledir) | ||||||
|  |     #gFile.Trash() | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ################################## External interface | ||||||
|  |  | ||||||
|  | def update_dir_stucture(book_id, calibrepath): | ||||||
|  |     if ub.config.config_use_google_drive: | ||||||
|  |         return update_dir_structure_gdrive(book_id) | ||||||
|  |     else: | ||||||
|  |         return update_dir_stucture_file(book_id, calibrepath) | ||||||
|  |  | ||||||
|  | def delete_book(book, calibrepath): | ||||||
|  |     if ub.config.config_use_google_drive: | ||||||
|  |         return delete_book_file(book, calibrepath) | ||||||
|  |     else: | ||||||
|  |         return delete_book_gdrive(book) | ||||||
|  | ################################## | ||||||
|  |  | ||||||
|  |  | ||||||
| class Updater(threading.Thread): | class Updater(threading.Thread): | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import sys | |||||||
| import os | import os | ||||||
| try: | try: | ||||||
|     from gevent.pywsgi import WSGIServer |     from gevent.pywsgi import WSGIServer | ||||||
|     from gevent import monkey |  | ||||||
|     from gevent.pool import Pool |     from gevent.pool import Pool | ||||||
|     from gevent import __version__ as geventVersion |     from gevent import __version__ as geventVersion | ||||||
|     gevent_present = True |     gevent_present = True | ||||||
| @@ -52,7 +51,6 @@ class server: | |||||||
|         if gevent_present: |         if gevent_present: | ||||||
|             web.app.logger.info('Starting Gevent server') |             web.app.logger.info('Starting Gevent server') | ||||||
|             # leave subprocess out to allow forking for fetchers and processors |             # leave subprocess out to allow forking for fetchers and processors | ||||||
|             monkey.patch_all(subprocess=False) |  | ||||||
|             self.start_gevent() |             self.start_gevent() | ||||||
|         else: |         else: | ||||||
|             web.app.logger.info('Starting Tornado server') |             web.app.logger.info('Starting Tornado server') | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								cps/ub.py
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								cps/ub.py
									
									
									
									
									
								
							| @@ -691,6 +691,20 @@ def get_mail_settings(): | |||||||
|  |  | ||||||
|     return data |     return data | ||||||
|  |  | ||||||
|  | # Save downloaded books per user in calibre-web's own database | ||||||
|  | def update_download(book_id, user_id): | ||||||
|  |     check = session.query(Downloads).filter(Downloads.user_id == user_id).filter(Downloads.book_id == | ||||||
|  |                                                                                           book_id).first() | ||||||
|  |  | ||||||
|  |     if not check: | ||||||
|  |         new_download = Downloads(user_id=user_id, book_id=book_id) | ||||||
|  |         session.add(new_download) | ||||||
|  |         session.commit() | ||||||
|  |  | ||||||
|  | # Delete non exisiting downloaded books in calibre-web's own database | ||||||
|  | def delete_download(book_id): | ||||||
|  |     session.query(Downloads).filter(book_id == Downloads.book_id).delete() | ||||||
|  |     session.commit() | ||||||
|  |  | ||||||
| # Generate user Guest (translated text), as anoymous user, no rights | # Generate user Guest (translated text), as anoymous user, no rights | ||||||
| def create_anonymous_user(): | def create_anonymous_user(): | ||||||
|   | |||||||
							
								
								
									
										196
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -50,7 +50,7 @@ from flask_principal import __version__ as flask_principalVersion | |||||||
| from flask_babel import Babel | from flask_babel import Babel | ||||||
| from flask_babel import gettext as _ | from flask_babel import gettext as _ | ||||||
| import requests | import requests | ||||||
| import zipfile | # import zipfile | ||||||
| from werkzeug.security import generate_password_hash, check_password_hash | from werkzeug.security import generate_password_hash, check_password_hash | ||||||
| from werkzeug.datastructures import Headers | from werkzeug.datastructures import Headers | ||||||
| from babel import Locale as LC | from babel import Locale as LC | ||||||
| @@ -77,7 +77,6 @@ import tempfile | |||||||
| import hashlib | import hashlib | ||||||
| from redirect import redirect_back, is_safe_url | from redirect import redirect_back, is_safe_url | ||||||
|  |  | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     from urllib.parse import quote |     from urllib.parse import quote | ||||||
|     from imp import reload |     from imp import reload | ||||||
| @@ -109,57 +108,6 @@ def md5(fname): | |||||||
|     return hash_md5.hexdigest() |     return hash_md5.hexdigest() | ||||||
|  |  | ||||||
|  |  | ||||||
| class Singleton: |  | ||||||
|     """ |  | ||||||
|     A non-thread-safe helper class to ease implementing singletons. |  | ||||||
|     This should be used as a decorator -- not a metaclass -- to the |  | ||||||
|     class that should be a singleton. |  | ||||||
|  |  | ||||||
|     The decorated class can define one `__init__` function that |  | ||||||
|     takes only the `self` argument. Also, the decorated class cannot be |  | ||||||
|     inherited from. Other than that, there are no restrictions that apply |  | ||||||
|     to the decorated class. |  | ||||||
|  |  | ||||||
|     To get the singleton instance, use the `Instance` method. Trying |  | ||||||
|     to use `__call__` will result in a `TypeError` being raised. |  | ||||||
|  |  | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     def __init__(self, decorated): |  | ||||||
|         self._decorated = decorated |  | ||||||
|  |  | ||||||
|     def Instance(self): |  | ||||||
|         """ |  | ||||||
|         Returns the singleton instance. Upon its first call, it creates a |  | ||||||
|         new instance of the decorated class and calls its `__init__` method. |  | ||||||
|         On all subsequent calls, the already created instance is returned. |  | ||||||
|  |  | ||||||
|         """ |  | ||||||
|         try: |  | ||||||
|             return self._instance |  | ||||||
|         except AttributeError: |  | ||||||
|             self._instance = self._decorated() |  | ||||||
|             return self._instance |  | ||||||
|  |  | ||||||
|     def __call__(self): |  | ||||||
|         raise TypeError('Singletons must be accessed through `Instance()`.') |  | ||||||
|  |  | ||||||
|     def __instancecheck__(self, inst): |  | ||||||
|         return isinstance(inst, self._decorated) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @Singleton |  | ||||||
| class Gauth: |  | ||||||
|     def __init__(self): |  | ||||||
|         self.auth = GoogleAuth(settings_file=os.path.join(config.get_main_dir,'settings.yaml')) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @Singleton |  | ||||||
| class Gdrive: |  | ||||||
|     def __init__(self): |  | ||||||
|         self.drive = gdriveutils.getDrive(gauth=Gauth.Instance().auth) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class ReverseProxied(object): | class ReverseProxied(object): | ||||||
|     """Wrap the application in this middleware and configure the |     """Wrap the application in this middleware and configure the | ||||||
|     front-end server to add these headers, to let you quietly bind |     front-end server to add these headers, to let you quietly bind | ||||||
| @@ -305,14 +253,6 @@ def authenticate(): | |||||||
|         {'WWW-Authenticate': 'Basic realm="Login Required"'}) |         {'WWW-Authenticate': 'Basic realm="Login Required"'}) | ||||||
|  |  | ||||||
|  |  | ||||||
| def updateGdriveCalibreFromLocal(): |  | ||||||
|     gdriveutils.backupCalibreDbAndOptionalDownload(Gdrive.Instance().drive) |  | ||||||
|     gdriveutils.copyToDrive(Gdrive.Instance().drive, config.config_calibre_dir, False, True) |  | ||||||
|     for x in os.listdir(config.config_calibre_dir): |  | ||||||
|         if os.path.isdir(os.path.join(config.config_calibre_dir, x)): |  | ||||||
|             shutil.rmtree(os.path.join(config.config_calibre_dir, x)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def requires_basic_auth_if_no_ano(f): | def requires_basic_auth_if_no_ano(f): | ||||||
|     @wraps(f) |     @wraps(f) | ||||||
|     def decorated(*args, **kwargs): |     def decorated(*args, **kwargs): | ||||||
| @@ -736,8 +676,9 @@ def feed_hot(): | |||||||
|                 .filter(db.Books.id == book.Downloads.book_id).first() |                 .filter(db.Books.id == book.Downloads.book_id).first() | ||||||
|             ) |             ) | ||||||
|         else: |         else: | ||||||
|             ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() |             ub.delete_download(book.Downloads.book_id) | ||||||
|             ub.session.commit() |             # ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() | ||||||
|  |             # ub.session.commit() | ||||||
|     numBooks = entries.__len__() |     numBooks = entries.__len__() | ||||||
|     pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks) |     pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, numBooks) | ||||||
|     xml = render_title_template('feed.xml', entries=entries, pagination=pagination) |     xml = render_title_template('feed.xml', entries=entries, pagination=pagination) | ||||||
| @@ -920,7 +861,7 @@ def get_opds_download_link(book_id, book_format): | |||||||
|     data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first() |     data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first() | ||||||
|     app.logger.info(data.name) |     app.logger.info(data.name) | ||||||
|     if current_user.is_authenticated: |     if current_user.is_authenticated: | ||||||
|         helper.update_download(book_id, int(current_user.id)) |         ub.update_download(book_id, int(current_user.id)) | ||||||
|     file_name = book.title |     file_name = book.title | ||||||
|     if len(book.authors) > 0: |     if len(book.authors) > 0: | ||||||
|         file_name = book.authors[0].name + '_' + file_name |         file_name = book.authors[0].name + '_' + file_name | ||||||
| @@ -935,7 +876,7 @@ def get_opds_download_link(book_id, book_format): | |||||||
|     startTime = time.time() |     startTime = time.time() | ||||||
|     if config.config_use_google_drive: |     if config.config_use_google_drive: | ||||||
|         app.logger.info(time.time() - startTime) |         app.logger.info(time.time() - startTime) | ||||||
|         df = gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, data.name + "." + book_format) |         df = gdriveutils.getFileFromEbooksFolder(book.path, data.name + "." + book_format) | ||||||
|         return do_gdrive_download(df, headers) |         return do_gdrive_download(df, headers) | ||||||
|     else: |     else: | ||||||
|         response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)) |         response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)) | ||||||
| @@ -1158,8 +1099,9 @@ def hot_books(page): | |||||||
|             if downloadBook: |             if downloadBook: | ||||||
|                 entries.append(downloadBook) |                 entries.append(downloadBook) | ||||||
|             else: |             else: | ||||||
|                 ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() |                 ub.delete_download(book.Downloads.book_id) | ||||||
|                 ub.session.commit() |                 # ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete() | ||||||
|  |                 # ub.session.commit() | ||||||
|         numBooks = entries.__len__() |         numBooks = entries.__len__() | ||||||
|         pagination = Pagination(page, config.config_books_per_page, numBooks) |         pagination = Pagination(page, config.config_books_per_page, numBooks) | ||||||
|         return render_title_template('index.html', random=random, entries=entries, pagination=pagination, |         return render_title_template('index.html', random=random, entries=entries, pagination=pagination, | ||||||
| @@ -1486,13 +1428,12 @@ def delete_book(book_id): | |||||||
|             # delete book from Shelfs, Downloads, Read list |             # delete book from Shelfs, Downloads, Read list | ||||||
|             ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete() |             ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).delete() | ||||||
|             ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete() |             ub.session.query(ub.ReadBook).filter(ub.ReadBook.book_id == book_id).delete() | ||||||
|             ub.session.query(ub.Downloads).filter(ub.Downloads.book_id == book_id).delete() |             # ToDo check Downloads.book right | ||||||
|  |             ub.delete_download(book_id) | ||||||
|  |             # ub.session.query(ub.Downloads).filter(ub.Downloads.book_id == book_id).delete() | ||||||
|             ub.session.commit() |             ub.session.commit() | ||||||
|  |  | ||||||
|             if config.config_use_google_drive: |             helper.delete_book(book, config.config_calibre_dir) | ||||||
|                 helper.delete_book_gdrive(book)  # ToDo really delete file |  | ||||||
|             else: |  | ||||||
|                 helper.delete_book(book, config.config_calibre_dir) |  | ||||||
|             # check if only this book links to: |             # check if only this book links to: | ||||||
|             # author, language, series, tags, custom columns |             # author, language, series, tags, custom columns | ||||||
|             modify_database_object([u''], book.authors, db.Authors, db.session, 'author') |             modify_database_object([u''], book.authors, db.Authors, db.session, 'author') | ||||||
| @@ -1560,7 +1501,7 @@ def watch_gdrive(): | |||||||
|         address = '%s/gdrive/watch/callback' % filedata['web']['redirect_uris'][0] |         address = '%s/gdrive/watch/callback' % filedata['web']['redirect_uris'][0] | ||||||
|         notification_id = str(uuid4()) |         notification_id = str(uuid4()) | ||||||
|         try: |         try: | ||||||
|             result = gdriveutils.watchChange(Gdrive.Instance().drive, notification_id, |             result = gdriveutils.watchChange(gdriveutils.Gdrive.Instance().drive, notification_id, | ||||||
|                                'web_hook', address, gdrive_watch_callback_token, current_milli_time() + 604800*1000) |                                'web_hook', address, gdrive_watch_callback_token, current_milli_time() + 604800*1000) | ||||||
|             settings = ub.session.query(ub.Settings).first() |             settings = ub.session.query(ub.Settings).first() | ||||||
|             settings.config_google_drive_watch_changes_response = json.dumps(result) |             settings.config_google_drive_watch_changes_response = json.dumps(result) | ||||||
| @@ -1585,7 +1526,7 @@ def revoke_watch_gdrive(): | |||||||
|     last_watch_response = config.config_google_drive_watch_changes_response |     last_watch_response = config.config_google_drive_watch_changes_response | ||||||
|     if last_watch_response: |     if last_watch_response: | ||||||
|         try: |         try: | ||||||
|             gdriveutils.stopChannel(Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId']) |             gdriveutils.stopChannel(gdriveutils.Gdrive.Instance().drive, last_watch_response['id'], last_watch_response['resourceId']) | ||||||
|         except HttpError: |         except HttpError: | ||||||
|             pass |             pass | ||||||
|         settings = ub.session.query(ub.Settings).first() |         settings = ub.session.query(ub.Settings).first() | ||||||
| @@ -1611,7 +1552,7 @@ def on_received_watch_confirmation(): | |||||||
|             try: |             try: | ||||||
|                 j = json.loads(data) |                 j = json.loads(data) | ||||||
|                 app.logger.info('Getting change details') |                 app.logger.info('Getting change details') | ||||||
|                 response = gdriveutils.getChangeById(Gdrive.Instance().drive, j['id']) |                 response = gdriveutils.getChangeById(gdriveutils.Gdrive.Instance().drive, j['id']) | ||||||
|                 app.logger.debug(response) |                 app.logger.debug(response) | ||||||
|                 if response: |                 if response: | ||||||
|                     dbpath = os.path.join(config.config_calibre_dir, "metadata.db") |                     dbpath = os.path.join(config.config_calibre_dir, "metadata.db") | ||||||
| @@ -1620,14 +1561,14 @@ def on_received_watch_confirmation(): | |||||||
|                         app.logger.info('Database file updated') |                         app.logger.info('Database file updated') | ||||||
|                         copyfile(dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time()))) |                         copyfile(dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time()))) | ||||||
|                         app.logger.info('Backing up existing and downloading updated metadata.db') |                         app.logger.info('Backing up existing and downloading updated metadata.db') | ||||||
|                         gdriveutils.downloadFile(Gdrive.Instance().drive, None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db")) |                         gdriveutils.downloadFile(None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db")) | ||||||
|                         app.logger.info('Setting up new DB') |                         app.logger.info('Setting up new DB') | ||||||
|                         # prevent error on windows, as os.rename does on exisiting files |                         # prevent error on windows, as os.rename does on exisiting files | ||||||
|                         shutil.move(os.path.join(tmpDir, "tmp_metadata.db"), dbpath) |                         shutil.move(os.path.join(tmpDir, "tmp_metadata.db"), dbpath) | ||||||
|                         db.setup_db() |                         db.setup_db() | ||||||
|             except Exception as e: |             except Exception as e: | ||||||
|                 app.logger.exception(e) |                 app.logger.info(e.message) | ||||||
|  |                 # app.logger.exception(e) | ||||||
|         updateMetaData() |         updateMetaData() | ||||||
|     return '' |     return '' | ||||||
|  |  | ||||||
| @@ -1793,19 +1734,22 @@ def advanced_search(): | |||||||
|  |  | ||||||
|  |  | ||||||
| def get_cover_via_gdrive(cover_path): | def get_cover_via_gdrive(cover_path): | ||||||
|     df = gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, cover_path, 'cover.jpg') |     df = gdriveutils.getFileFromEbooksFolder(cover_path, 'cover.jpg') | ||||||
|     if not gdriveutils.session.query(gdriveutils.PermissionAdded).filter(gdriveutils.PermissionAdded.gdrive_id == df['id']).first(): |     if df: | ||||||
|         df.GetPermissions() |         if not gdriveutils.session.query(gdriveutils.PermissionAdded).filter(gdriveutils.PermissionAdded.gdrive_id == df['id']).first(): | ||||||
|         df.InsertPermission({ |             df.GetPermissions() | ||||||
|                         'type': 'anyone', |             df.InsertPermission({ | ||||||
|                         'value': 'anyone', |                             'type': 'anyone', | ||||||
|                         'role': 'reader', |                             'value': 'anyone', | ||||||
|                         'withLink': True}) |                             'role': 'reader', | ||||||
|         permissionAdded = gdriveutils.PermissionAdded() |                             'withLink': True}) | ||||||
|         permissionAdded.gdrive_id = df['id'] |             permissionAdded = gdriveutils.PermissionAdded() | ||||||
|         gdriveutils.session.add(permissionAdded) |             permissionAdded.gdrive_id = df['id'] | ||||||
|         gdriveutils.session.commit() |             gdriveutils.session.add(permissionAdded) | ||||||
|     return df.metadata.get('webContentLink') |             gdriveutils.session.commit() | ||||||
|  |         return df.metadata.get('webContentLink') | ||||||
|  |     else: | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.route("/cover/<path:cover_path>") | @app.route("/cover/<path:cover_path>") | ||||||
| @@ -1813,9 +1757,15 @@ def get_cover_via_gdrive(cover_path): | |||||||
| def get_cover(cover_path): | def get_cover(cover_path): | ||||||
|     if config.config_use_google_drive: |     if config.config_use_google_drive: | ||||||
|         try: |         try: | ||||||
|             return redirect(get_cover_via_gdrive(cover_path)) |             path=get_cover_via_gdrive(cover_path) | ||||||
|         except: |             if path: | ||||||
|             app.logger.error(cover_path + '/cover.jpg ' + 'not found on GDrive') |                 return redirect(path) | ||||||
|  |             else: | ||||||
|  |                 app.logger.error(cover_path + '/cover.jpg not found on GDrive') | ||||||
|  |                 return send_from_directory(os.path.join(os.path.dirname(__file__), "static"), "generic_cover.jpg") | ||||||
|  |         except Exception as e: | ||||||
|  |             app.logger.error("Message "+e.message) | ||||||
|  |             # traceback.print_exc() | ||||||
|             return send_from_directory(os.path.join(os.path.dirname(__file__), "static"),"generic_cover.jpg") |             return send_from_directory(os.path.join(os.path.dirname(__file__), "static"),"generic_cover.jpg") | ||||||
|     else: |     else: | ||||||
|         return send_from_directory(os.path.join(config.config_calibre_dir, cover_path), "cover.jpg") |         return send_from_directory(os.path.join(config.config_calibre_dir, cover_path), "cover.jpg") | ||||||
| @@ -1834,7 +1784,7 @@ def serve_book(book_id, book_format): | |||||||
|             headers["Content-Type"] = mimetypes.types_map['.' + book_format] |             headers["Content-Type"] = mimetypes.types_map['.' + book_format] | ||||||
|         except KeyError: |         except KeyError: | ||||||
|             headers["Content-Type"] = "application/octet-stream" |             headers["Content-Type"] = "application/octet-stream" | ||||||
|         df = gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, data.name + "." + book_format) |         df = gdriveutils.getFileFromEbooksFolder(book.path, data.name + "." + book_format) | ||||||
|         return do_gdrive_download(df, headers) |         return do_gdrive_download(df, headers) | ||||||
|     else: |     else: | ||||||
|         return send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format) |         return send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format) | ||||||
| @@ -1956,7 +1906,7 @@ def get_download_link(book_id, book_format): | |||||||
|     if data: |     if data: | ||||||
|         # collect downloaded books only for registered user and not for anonymous user |         # collect downloaded books only for registered user and not for anonymous user | ||||||
|         if current_user.is_authenticated: |         if current_user.is_authenticated: | ||||||
|             helper.update_download(book_id, int(current_user.id)) |             ub.update_download(book_id, int(current_user.id)) | ||||||
|         file_name = book.title |         file_name = book.title | ||||||
|         if len(book.authors) > 0: |         if len(book.authors) > 0: | ||||||
|             file_name = book.authors[0].name + '_' + file_name |             file_name = book.authors[0].name + '_' + file_name | ||||||
| @@ -1968,8 +1918,11 @@ def get_download_link(book_id, book_format): | |||||||
|             headers["Content-Type"] = "application/octet-stream" |             headers["Content-Type"] = "application/octet-stream" | ||||||
|         headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf-8')), book_format) |         headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf-8')), book_format) | ||||||
|         if config.config_use_google_drive: |         if config.config_use_google_drive: | ||||||
|             df = gdriveutils.getFileFromEbooksFolder(Gdrive.Instance().drive, book.path, '%s.%s' % (data.name, book_format)) |             df = gdriveutils.getFileFromEbooksFolder(book.path, '%s.%s' % (data.name, book_format)) | ||||||
|             return do_gdrive_download(df, headers) |             if df: | ||||||
|  |                 return do_gdrive_download(df, headers) | ||||||
|  |             else: | ||||||
|  |                 abort(404) | ||||||
|         else: |         else: | ||||||
|             response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)) |             response = make_response(send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format)) | ||||||
|             response.headers = headers |             response.headers = headers | ||||||
| @@ -2150,7 +2103,7 @@ def send_to_kindle(book_id): | |||||||
|         if result is None: |         if result is None: | ||||||
|             flash(_(u"Book successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail), |             flash(_(u"Book successfully send to %(kindlemail)s", kindlemail=current_user.kindle_mail), | ||||||
|                   category="success") |                   category="success") | ||||||
|             helper.update_download(book_id, int(current_user.id)) |             ub.update_download(book_id, int(current_user.id)) | ||||||
|         else: |         else: | ||||||
|             flash(_(u"There was an error sending this book: %(res)s", res=result), category="error") |             flash(_(u"There was an error sending this book: %(res)s", res=result), category="error") | ||||||
|     else: |     else: | ||||||
| @@ -2398,8 +2351,9 @@ def profile(): | |||||||
|         if downloadBook: |         if downloadBook: | ||||||
|             downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) |             downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) | ||||||
|         else: |         else: | ||||||
|             ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete() |             ub.delete_download(book.book_id) | ||||||
|             ub.session.commit() |             # ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete() | ||||||
|  |             # ub.session.commit() | ||||||
|     if request.method == "POST": |     if request.method == "POST": | ||||||
|         to_save = request.form.to_dict() |         to_save = request.form.to_dict() | ||||||
|         content.random_books = 0 |         content.random_books = 0 | ||||||
| @@ -2671,7 +2625,7 @@ def configuration_helper(origin): | |||||||
|             reboot_required = True |             reboot_required = True | ||||||
|         try: |         try: | ||||||
|             if content.config_use_google_drive and is_gdrive_ready() and not os.path.exists(config.config_calibre_dir + "/metadata.db"): |             if content.config_use_google_drive and is_gdrive_ready() and not os.path.exists(config.config_calibre_dir + "/metadata.db"): | ||||||
|                 gdriveutils.downloadFile(Gdrive.Instance().drive, None, "metadata.db", config.config_calibre_dir + "/metadata.db") |                 gdriveutils.downloadFile(None, "metadata.db", config.config_calibre_dir + "/metadata.db") | ||||||
|             if db_change: |             if db_change: | ||||||
|                 if config.db_configured: |                 if config.db_configured: | ||||||
|                     db.session.close() |                     db.session.close() | ||||||
| @@ -2842,8 +2796,9 @@ def edit_user(user_id): | |||||||
|         if downloadBook: |         if downloadBook: | ||||||
|             downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) |             downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) | ||||||
|         else: |         else: | ||||||
|             ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete() |             ub.delete_download(book.book_id) | ||||||
|             ub.session.commit() |             # ub.session.query(ub.Downloads).filter(book.book_id == ub.Downloads.book_id).delete() | ||||||
|  |             # ub.session.commit() | ||||||
|     if request.method == "POST": |     if request.method == "POST": | ||||||
|         to_save = request.form.to_dict() |         to_save = request.form.to_dict() | ||||||
|         if "delete" in to_save: |         if "delete" in to_save: | ||||||
| @@ -3051,16 +3006,14 @@ def edit_book(book_id): | |||||||
|                 edited_books_id.add(book.id) |                 edited_books_id.add(book.id) | ||||||
|                 book.author_sort = helper.get_sorted_author(input_authors[0]) |                 book.author_sort = helper.get_sorted_author(input_authors[0]) | ||||||
|  |  | ||||||
|  |         if config.config_use_google_drive: | ||||||
|  |             gdriveutils.updateGdriveCalibreFromLocal() | ||||||
|  |  | ||||||
|         error = False |         error = False | ||||||
|         for b in edited_books_id: |         for b in edited_books_id: | ||||||
|             if config.config_use_google_drive: |             error = helper.update_dir_stucture(b, config.config_calibre_dir) | ||||||
|                 error = helper.update_dir_structure_gdrive(b) |  | ||||||
|             else: |  | ||||||
|                 error = helper.update_dir_stucture(b, config.config_calibre_dir) |  | ||||||
|             if error:   # stop on error |             if error:   # stop on error | ||||||
|                 break |                 break | ||||||
|         if config.config_use_google_drive: |  | ||||||
|             updateGdriveCalibreFromLocal() |  | ||||||
|  |  | ||||||
|         if not error: |         if not error: | ||||||
|             if to_save["cover_url"]: |             if to_save["cover_url"]: | ||||||
| @@ -3232,7 +3185,7 @@ def save_cover(url, book_path): | |||||||
|         f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb") |         f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb") | ||||||
|         f.write(img.content) |         f.write(img.content) | ||||||
|         f.close() |         f.close() | ||||||
|         gdriveutils.uploadFileToEbooksFolder(Gdrive.Instance().drive, os.path.join(book_path, 'cover.jpg'), os.path.join(tmpDir, f.name)) |         gdriveutils.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), os.path.join(tmpDir, f.name)) | ||||||
|         app.logger.info("Cover is saved on gdrive") |         app.logger.info("Cover is saved on gdrive") | ||||||
|         return true |         return true | ||||||
|  |  | ||||||
| @@ -3344,29 +3297,30 @@ def upload(): | |||||||
|  |  | ||||||
|             db.session.add(db_book) |             db.session.add(db_book) | ||||||
|             db.session.flush()  # flush content get db_book.id avalible |             db.session.flush()  # flush content get db_book.id avalible | ||||||
|             # ToDo: Book should be moved to foldername with id in it |  | ||||||
|             if config.config_use_google_drive: |  | ||||||
|                 error = helper.update_dir_structure_gdrive(db_book.id) |  | ||||||
|             else: |  | ||||||
|                 error = helper.update_dir_stucture(db_book.id, config.config_calibre_dir) |  | ||||||
|             # ToDo: Handle error |  | ||||||
|             # add comment |             # add comment | ||||||
|             upload_comment = Markup(meta.description).unescape() |             upload_comment = Markup(meta.description).unescape() | ||||||
|             if upload_comment != "": |             if upload_comment != "": | ||||||
|                 db.session.add(db.Comments(upload_comment, db_book.id)) |                 db.session.add(db.Comments(upload_comment, db_book.id)) | ||||||
|             db.session.commit() |  | ||||||
|  |  | ||||||
|             input_tags = tags.split(',') |             input_tags = tags.split(',') | ||||||
|             input_tags = list(map(lambda it: it.strip(), input_tags)) |             input_tags = list(map(lambda it: it.strip(), input_tags)) | ||||||
|             if input_tags[0] !="": |             if input_tags[0] !="": | ||||||
|                 modify_database_object(input_tags, db_book.tags, db.Tags, db.session, 'tags') |                 modify_database_object(input_tags, db_book.tags, db.Tags, db.session, 'tags') | ||||||
|  |  | ||||||
|  |             db.session.commit() | ||||||
|  |  | ||||||
|  |             if config.config_use_google_drive: | ||||||
|  |                 gdriveutils.updateGdriveCalibreFromLocal() | ||||||
|  |             error = helper.update_dir_stucture(db_book.id, config.config_calibre_dir) | ||||||
|  |             # ToDo: Handle error | ||||||
|  |             if error: | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|             if db_language is not None:  # display Full name instead of iso639.part3 |             if db_language is not None:  # display Full name instead of iso639.part3 | ||||||
|                 db_book.languages[0].language_name = _(meta.languages) |                 db_book.languages[0].language_name = _(meta.languages) | ||||||
|             author_names = [] |             author_names = [] | ||||||
|             for author in db_book.authors: |             for author in db_book.authors: | ||||||
|                 author_names.append(author.name) |                 author_names.append(author.name) | ||||||
|             if config.config_use_google_drive: |  | ||||||
|                 updateGdriveCalibreFromLocal() |  | ||||||
|             if len(request.files.getlist("btn-upload")) < 2: |             if len(request.files.getlist("btn-upload")) < 2: | ||||||
|                 cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() |                 cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() | ||||||
|                 if current_user.role_edit() or current_user.role_admin(): |                 if current_user.role_edit() or current_user.role_admin(): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 OzzieIsaacs
					OzzieIsaacs