import csv ui
This commit is contained in:
parent
5911d422f5
commit
1d7816d9d7
4 changed files with 91 additions and 1 deletions
|
@ -333,7 +333,8 @@ class CsvImporter(Task):
|
||||||
success = import_function(row)
|
success = import_function(row)
|
||||||
self.progress(success)
|
self.progress(success)
|
||||||
|
|
||||||
def validate_file(self, filename: str) -> bool:
|
@classmethod
|
||||||
|
def validate_file(cls, filename: str) -> bool:
|
||||||
"""Validate that the given file is a valid CSV export ZIP file.
|
"""Validate that the given file is a valid CSV export ZIP file.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
@ -213,6 +213,66 @@
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
</article>
|
</article>
|
||||||
|
<article>
|
||||||
|
<details>
|
||||||
|
<summary>{% trans 'Import marks, reviews and notes from CSV' %}</summary>
|
||||||
|
<form action="{% url 'users:import_csv' %}"
|
||||||
|
method="post"
|
||||||
|
enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
<ul>
|
||||||
|
<li>{% trans 'Upload a ZIP file containing CSV files exported from NeoDB.' %}</li>
|
||||||
|
<li>{% trans 'Existing marks and reviews with newer dates will be preserved.' %}</li>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
<input type="file" name="file" required accept=".zip">
|
||||||
|
<p>
|
||||||
|
{% trans 'Visibility' %}:
|
||||||
|
<br>
|
||||||
|
<label for="csv_visibility_0">
|
||||||
|
<input type="radio"
|
||||||
|
name="visibility"
|
||||||
|
value="0"
|
||||||
|
required=""
|
||||||
|
id="csv_visibility_0"
|
||||||
|
checked>
|
||||||
|
{% trans 'Public' %}
|
||||||
|
</label>
|
||||||
|
<label for="csv_visibility_1">
|
||||||
|
<input type="radio"
|
||||||
|
name="visibility"
|
||||||
|
value="1"
|
||||||
|
required=""
|
||||||
|
id="csv_visibility_1">
|
||||||
|
{% trans 'Followers Only' %}
|
||||||
|
</label>
|
||||||
|
<label for="csv_visibility_2">
|
||||||
|
<input type="radio"
|
||||||
|
name="visibility"
|
||||||
|
value="2"
|
||||||
|
required=""
|
||||||
|
id="csv_visibility_2">
|
||||||
|
{% trans 'Mentioned Only' %}
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<input type="submit" value="{% trans 'Import' %}" />
|
||||||
|
<small>
|
||||||
|
{% if csv_import_task %}
|
||||||
|
<br>
|
||||||
|
{% trans 'Last import started' %}: {{ csv_import_task.created_time }}
|
||||||
|
{% trans 'Status' %}: {{ csv_import_task.get_state_display }}。
|
||||||
|
<br>
|
||||||
|
{{ csv_import_task.message }}
|
||||||
|
{% if csv_import_task.metadata.failed_items %}
|
||||||
|
{% trans 'Failed items' %}:
|
||||||
|
<br>
|
||||||
|
<textarea readonly>{% for item in csv_import_task.metadata.failed_items %}{{item}} {% endfor %}</textarea>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</article>
|
||||||
<article>
|
<article>
|
||||||
<details>
|
<details>
|
||||||
<summary>{% trans 'Export Data' %}</summary>
|
<summary>{% trans 'Export Data' %}</summary>
|
||||||
|
|
|
@ -15,6 +15,7 @@ urlpatterns = [
|
||||||
path("data/import/douban", import_douban, name="import_douban"),
|
path("data/import/douban", import_douban, name="import_douban"),
|
||||||
path("data/import/letterboxd", import_letterboxd, name="import_letterboxd"),
|
path("data/import/letterboxd", import_letterboxd, name="import_letterboxd"),
|
||||||
path("data/import/opml", import_opml, name="import_opml"),
|
path("data/import/opml", import_opml, name="import_opml"),
|
||||||
|
path("data/import/csv", import_csv, name="import_csv"),
|
||||||
path("data/export/reviews", export_reviews, name="export_reviews"),
|
path("data/export/reviews", export_reviews, name="export_reviews"),
|
||||||
path("data/export/marks", export_marks, name="export_marks"),
|
path("data/export/marks", export_marks, name="export_marks"),
|
||||||
path("data/export/csv", export_csv, name="export_csv"),
|
path("data/export/csv", export_csv, name="export_csv"),
|
||||||
|
|
|
@ -14,6 +14,7 @@ from django.utils.translation import gettext as _
|
||||||
from common.utils import GenerateDateUUIDMediaFilePath
|
from common.utils import GenerateDateUUIDMediaFilePath
|
||||||
from journal.exporters import CsvExporter, DoufenExporter, NdjsonExporter
|
from journal.exporters import CsvExporter, DoufenExporter, NdjsonExporter
|
||||||
from journal.importers import (
|
from journal.importers import (
|
||||||
|
CsvImporter,
|
||||||
DoubanImporter,
|
DoubanImporter,
|
||||||
GoodreadsImporter,
|
GoodreadsImporter,
|
||||||
LetterboxdImporter,
|
LetterboxdImporter,
|
||||||
|
@ -98,6 +99,7 @@ def data(request):
|
||||||
"import_task": DoubanImporter.latest_task(request.user),
|
"import_task": DoubanImporter.latest_task(request.user),
|
||||||
"export_task": DoufenExporter.latest_task(request.user),
|
"export_task": DoufenExporter.latest_task(request.user),
|
||||||
"csv_export_task": CsvExporter.latest_task(request.user),
|
"csv_export_task": CsvExporter.latest_task(request.user),
|
||||||
|
"csv_import_task": CsvImporter.latest_task(request.user),
|
||||||
"ndjson_export_task": NdjsonExporter.latest_task(request.user),
|
"ndjson_export_task": NdjsonExporter.latest_task(request.user),
|
||||||
"letterboxd_task": LetterboxdImporter.latest_task(request.user),
|
"letterboxd_task": LetterboxdImporter.latest_task(request.user),
|
||||||
"goodreads_task": GoodreadsImporter.latest_task(request.user),
|
"goodreads_task": GoodreadsImporter.latest_task(request.user),
|
||||||
|
@ -319,3 +321,29 @@ def import_opml(request):
|
||||||
else:
|
else:
|
||||||
messages.add_message(request, messages.ERROR, _("Invalid file."))
|
messages.add_message(request, messages.ERROR, _("Invalid file."))
|
||||||
return redirect(reverse("users:data"))
|
return redirect(reverse("users:data"))
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def import_csv(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
f = (
|
||||||
|
settings.MEDIA_ROOT
|
||||||
|
+ "/"
|
||||||
|
+ GenerateDateUUIDMediaFilePath("x.zip", settings.SYNC_FILE_PATH_ROOT)
|
||||||
|
)
|
||||||
|
os.makedirs(os.path.dirname(f), exist_ok=True)
|
||||||
|
with open(f, "wb+") as destination:
|
||||||
|
for chunk in request.FILES["file"].chunks():
|
||||||
|
destination.write(chunk)
|
||||||
|
if not CsvImporter.validate_file(f):
|
||||||
|
messages.add_message(request, messages.ERROR, _("Invalid file."))
|
||||||
|
return redirect(reverse("users:data"))
|
||||||
|
CsvImporter.create(
|
||||||
|
request.user,
|
||||||
|
visibility=int(request.POST.get("visibility", 0)),
|
||||||
|
file=f,
|
||||||
|
).enqueue()
|
||||||
|
messages.add_message(
|
||||||
|
request, messages.INFO, _("File is uploaded and will be imported soon.")
|
||||||
|
)
|
||||||
|
return redirect(reverse("users:data"))
|
||||||
|
|
Loading…
Add table
Reference in a new issue