|
49 | 49 | from .usermanagement import user_login_required, login_required_if_no_ano |
50 | 50 | from .string_helper import strip_whitespaces |
51 | 51 |
|
| 52 | +import tempfile |
| 53 | +import requests |
| 54 | +from werkzeug.datastructures import FileStorage |
| 55 | + |
52 | 56 | editbook = Blueprint('edit-book', __name__) |
53 | 57 | log = logger.create() |
54 | 58 |
|
@@ -100,78 +104,19 @@ def show_edit_book(book_id): |
100 | 104 | def edit_book(book_id): |
101 | 105 | return do_edit_book(book_id) |
102 | 106 |
|
103 | | - |
104 | 107 | @editbook.route("/upload", methods=["POST"]) |
105 | 108 | @login_required_if_no_ano |
106 | 109 | @upload_required |
107 | 110 | def upload(): |
108 | | - if len(request.files.getlist("btn-upload-format")): |
| 111 | + if request.form.get("upload_url"): |
| 112 | + return do_upload_url(request.form.get("upload_url")) |
| 113 | + elif len(request.files.getlist("btn-upload")): |
| 114 | + return do_upload_file_list(request.files.getlist("btn-upload")) |
| 115 | + elif len(request.files.getlist("btn-upload-format")): |
109 | 116 | book_id = request.form.get('book_id', -1) |
110 | 117 | return do_edit_book(book_id, request.files.getlist("btn-upload-format")) |
111 | | - elif len(request.files.getlist("btn-upload")): |
112 | | - for requested_file in request.files.getlist("btn-upload"): |
113 | | - try: |
114 | | - modify_date = False |
115 | | - # create the function for sorting... |
116 | | - calibre_db.create_functions(config) |
117 | | - meta, error = file_handling_on_upload(requested_file) |
118 | | - if error: |
119 | | - return error |
120 | | - |
121 | | - db_book, input_authors, title_dir = create_book_on_upload(modify_date, meta) |
122 | | - |
123 | | - # Comments need book id therefore only possible after flush |
124 | | - modify_date |= edit_book_comments(Markup(meta.description).unescape(), db_book) |
125 | | - |
126 | | - book_id = db_book.id |
127 | | - title = db_book.title |
128 | | - if config.config_use_google_drive: |
129 | | - helper.upload_new_file_gdrive(book_id, |
130 | | - input_authors[0], |
131 | | - title, |
132 | | - title_dir, |
133 | | - meta.file_path, |
134 | | - meta.extension.lower()) |
135 | | - for file_format in db_book.data: |
136 | | - file_format.name = (helper.get_valid_filename(title, chars=42) + ' - ' |
137 | | - + helper.get_valid_filename(input_authors[0], chars=42)) |
138 | | - else: |
139 | | - error = helper.update_dir_structure(book_id, |
140 | | - config.get_book_path(), |
141 | | - input_authors[0], |
142 | | - meta.file_path, |
143 | | - title_dir + meta.extension.lower()) |
144 | | - move_coverfile(meta, db_book) |
145 | | - if modify_date: |
146 | | - calibre_db.set_metadata_dirty(book_id) |
147 | | - # save data to database, reread data |
148 | | - calibre_db.session.commit() |
149 | | - |
150 | | - if config.config_use_google_drive: |
151 | | - gdriveutils.updateGdriveCalibreFromLocal() |
152 | | - if error: |
153 | | - flash(error, category="error") |
154 | | - link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book_id), escape(title)) |
155 | | - upload_text = N_("File %(file)s uploaded", file=link) |
156 | | - WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(title))) |
157 | | - helper.add_book_to_thumbnail_cache(book_id) |
158 | | - |
159 | | - if len(request.files.getlist("btn-upload")) < 2: |
160 | | - if current_user.role_edit() or current_user.role_admin(): |
161 | | - resp = {"location": url_for('edit-book.show_edit_book', book_id=book_id)} |
162 | | - return make_response(jsonify(resp)) |
163 | | - else: |
164 | | - resp = {"location": url_for('web.show_book', book_id=book_id)} |
165 | | - return Response(json.dumps(resp), mimetype='application/json') |
166 | | - except (OperationalError, IntegrityError, StaleDataError) as e: |
167 | | - calibre_db.session.rollback() |
168 | | - log.error_or_exception("Database error: {}".format(e)) |
169 | | - flash(_("Oops! Database Error: %(error)s.", error=e.orig if hasattr(e, "orig") else e), |
170 | | - category="error") |
171 | | - return make_response(jsonify(location=url_for("web.index"))) |
172 | 118 | abort(404) |
173 | 119 |
|
174 | | - |
175 | 120 | @editbook.route("/admin/book/convert/<int:book_id>", methods=['POST']) |
176 | 121 | @login_required_if_no_ano |
177 | 122 | @edit_required |
@@ -613,6 +558,93 @@ def table_xchange_author_title(): |
613 | 558 | return make_response(jsonify(success=True)) |
614 | 559 | return "" |
615 | 560 |
|
| 561 | +def do_upload_url(url: str) -> FileStorage: |
| 562 | + try: |
| 563 | + r = requests.get(url, stream=True, timeout=30) |
| 564 | + r.raise_for_status() |
| 565 | + url_end = r.url.split('/')[-1] |
| 566 | + filename_sanitized = "".join(c for c in url_end if c.isalnum() or c in "._-") # sanitize filename |
| 567 | + filename = filename_sanitized if len(filename_sanitized) > 0 else "uploaded_file" |
| 568 | + |
| 569 | + with tempfile.NamedTemporaryFile(delete=False) as tmp: |
| 570 | + for chunk in r.iter_content(): |
| 571 | + tmp.write(chunk) |
| 572 | + tmp.flush() |
| 573 | + tmp_name = tmp.name |
| 574 | + |
| 575 | + except Exception as e: |
| 576 | + log.error_or_exception("File download error: {}".format(e)) |
| 577 | + flash(_("Oops! Download failed: %(error)s.", error=e.orig if hasattr(e, "orig") else e), |
| 578 | + category="error") |
| 579 | + return make_response(jsonify(location=url_for("web.index"))) |
| 580 | + |
| 581 | + with open(tmp_name, 'rb') as f: |
| 582 | + file_storage = FileStorage(f, filename=filename) |
| 583 | + resp = do_upload_file_list([file_storage]) |
| 584 | + |
| 585 | + return resp |
| 586 | + |
| 587 | +def do_upload_file_list(file_list: list[FileStorage]): |
| 588 | + for requested_file in file_list: |
| 589 | + try: |
| 590 | + modify_date = False |
| 591 | + # create the function for sorting... |
| 592 | + calibre_db.create_functions(config) |
| 593 | + meta, error = file_handling_on_upload(requested_file) |
| 594 | + if error: |
| 595 | + return error |
| 596 | + |
| 597 | + db_book, input_authors, title_dir = create_book_on_upload(modify_date, meta) |
| 598 | + |
| 599 | + # Comments need book id therefore only possible after flush |
| 600 | + modify_date |= edit_book_comments(Markup(meta.description).unescape(), db_book) |
| 601 | + |
| 602 | + book_id = db_book.id |
| 603 | + title = db_book.title |
| 604 | + if config.config_use_google_drive: |
| 605 | + helper.upload_new_file_gdrive(book_id, |
| 606 | + input_authors[0], |
| 607 | + title, |
| 608 | + title_dir, |
| 609 | + meta.file_path, |
| 610 | + meta.extension.lower()) |
| 611 | + for file_format in db_book.data: |
| 612 | + file_format.name = (helper.get_valid_filename(title, chars=42) + ' - ' |
| 613 | + + helper.get_valid_filename(input_authors[0], chars=42)) |
| 614 | + else: |
| 615 | + error = helper.update_dir_structure(book_id, |
| 616 | + config.get_book_path(), |
| 617 | + input_authors[0], |
| 618 | + meta.file_path, |
| 619 | + title_dir + meta.extension.lower()) |
| 620 | + move_coverfile(meta, db_book) |
| 621 | + if modify_date: |
| 622 | + calibre_db.set_metadata_dirty(book_id) |
| 623 | + # save data to database, reread data |
| 624 | + calibre_db.session.commit() |
| 625 | + |
| 626 | + if config.config_use_google_drive: |
| 627 | + gdriveutils.updateGdriveCalibreFromLocal() |
| 628 | + if error: |
| 629 | + flash(error, category="error") |
| 630 | + link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book_id), escape(title)) |
| 631 | + upload_text = N_("File %(file)s uploaded", file=link) |
| 632 | + WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(title))) |
| 633 | + helper.add_book_to_thumbnail_cache(book_id) |
| 634 | + |
| 635 | + if len(file_list) < 2: |
| 636 | + if current_user.role_edit() or current_user.role_admin(): |
| 637 | + resp = {"location": url_for('edit-book.show_edit_book', book_id=book_id)} |
| 638 | + return make_response(jsonify(resp)) |
| 639 | + else: |
| 640 | + resp = {"location": url_for('web.show_book', book_id=book_id)} |
| 641 | + return Response(json.dumps(resp), mimetype='application/json') |
| 642 | + except (OperationalError, IntegrityError, StaleDataError) as e: |
| 643 | + calibre_db.session.rollback() |
| 644 | + log.error_or_exception("Database error: {}".format(e)) |
| 645 | + flash(_("Oops! Database Error: %(error)s.", error=e.orig if hasattr(e, "orig") else e), |
| 646 | + category="error") |
| 647 | + return make_response(jsonify(location=url_for("web.index"))) |
616 | 648 |
|
617 | 649 | def do_edit_book(book_id, upload_formats=None): |
618 | 650 | modify_date = False |
|
0 commit comments