diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index e4ee2c31a..4c2abb521 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -1,7 +1,8 @@ """ handle reading a csv from an external service, defaults are from Goodreads """ import csv +from datetime import timedelta from django.utils import timezone -from bookwyrm.models import ImportJob, ImportItem +from bookwyrm.models import ImportJob, ImportItem, SiteSettings class Importer: @@ -33,6 +34,7 @@ class Importer: "reading": ["currently-reading", "reading", "currently reading"], } + # pylint: disable=too-many-locals def create_job(self, user, csv_file, include_reviews, privacy): """check over a csv and creates a database entry for the job""" csv_reader = csv.DictReader(csv_file, delimiter=self.delimiter) @@ -49,7 +51,13 @@ class Importer: source=self.service, ) + enforce_limit, allowed_imports = self.get_import_limit(user) + if enforce_limit and allowed_imports <= 0: + job.complete_job() + return job for index, entry in rows: + if enforce_limit and index >= allowed_imports: + break self.create_item(job, index, entry) return job @@ -99,6 +107,24 @@ class Importer: """use the dataclass to create the formatted row of data""" return {k: entry.get(v) for k, v in mappings.items()} + def get_import_limit(self, user): # pylint: disable=no-self-use + """check if import limit is set and return how many imports are left""" + site_settings = SiteSettings.objects.get() + import_size_limit = site_settings.import_size_limit + import_limit_reset = site_settings.import_limit_reset + enforce_limit = import_size_limit and import_limit_reset + allowed_imports = 0 + + if enforce_limit: + time_range = timezone.now() - timedelta(days=import_limit_reset) + import_jobs = ImportJob.objects.filter( + user=user, created_date__gte=time_range + ) + # pylint: disable=consider-using-generator + imported_books = sum([job.successful_item_count for job in import_jobs]) + allowed_imports = import_size_limit - imported_books + return enforce_limit, allowed_imports + def create_retry_job(self, user, original_job, items): """retry items that didn't import""" job = ImportJob.objects.create( @@ -110,7 +136,13 @@ class Importer: mappings=original_job.mappings, retry=True, ) - for item in items: + enforce_limit, allowed_imports = self.get_import_limit(user) + if enforce_limit and allowed_imports <= 0: + job.complete_job() + return job + for index, item in enumerate(items): + if enforce_limit and index >= allowed_imports: + break # this will re-normalize the raw data self.create_item(job, item.index, item.data) return job diff --git a/bookwyrm/migrations/0167_sitesettings_import_size_limit.py b/bookwyrm/migrations/0167_sitesettings_import_size_limit.py new file mode 100644 index 000000000..fdbfaf51d --- /dev/null +++ b/bookwyrm/migrations/0167_sitesettings_import_size_limit.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.16 on 2022-12-05 13:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0166_sitesettings_imports_enabled"), + ] + + operations = [ + migrations.AddField( + model_name="sitesettings", + name="import_size_limit", + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name="sitesettings", + name="import_limit_reset", + field=models.IntegerField(default=0), + ), + ] diff --git a/bookwyrm/migrations/0171_merge_20221219_2020.py b/bookwyrm/migrations/0171_merge_20221219_2020.py new file mode 100644 index 000000000..53d44872f --- /dev/null +++ b/bookwyrm/migrations/0171_merge_20221219_2020.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.16 on 2022-12-19 20:20 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0167_sitesettings_import_size_limit"), + ("bookwyrm", "0170_merge_0168_auto_20221205_2331_0169_auto_20221206_0902"), + ] + + operations = [] diff --git a/bookwyrm/migrations/0173_merge_20230102_1444.py b/bookwyrm/migrations/0173_merge_20230102_1444.py new file mode 100644 index 000000000..c3e37a76f --- /dev/null +++ b/bookwyrm/migrations/0173_merge_20230102_1444.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.16 on 2023-01-02 14:44 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0171_merge_20221219_2020"), + ("bookwyrm", "0172_alter_user_preferred_language"), + ] + + operations = [] diff --git a/bookwyrm/migrations/0174_merge_20230111_1523.py b/bookwyrm/migrations/0174_merge_20230111_1523.py new file mode 100644 index 000000000..fd57083f6 --- /dev/null +++ b/bookwyrm/migrations/0174_merge_20230111_1523.py @@ -0,0 +1,12 @@ +# Generated by Django 3.2.16 on 2023-01-11 15:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0173_merge_20230102_1444"), + ] + + operations = [] diff --git a/bookwyrm/models/site.py b/bookwyrm/models/site.py index 533a37b30..747565161 100644 --- a/bookwyrm/models/site.py +++ b/bookwyrm/models/site.py @@ -90,6 +90,8 @@ class SiteSettings(SiteModel): # controls imports_enabled = models.BooleanField(default=True) + import_size_limit = models.IntegerField(default=0) + import_limit_reset = models.IntegerField(default=0) field_tracker = FieldTracker(fields=["name", "instance_tagline", "logo"]) diff --git a/bookwyrm/static/css/bookwyrm/utilities/_size.scss b/bookwyrm/static/css/bookwyrm/utilities/_size.scss index cbc74d7ab..258aa9a73 100644 --- a/bookwyrm/static/css/bookwyrm/utilities/_size.scss +++ b/bookwyrm/static/css/bookwyrm/utilities/_size.scss @@ -40,6 +40,10 @@ width: 500px !important; } +.is-h-em { + height: 1em !important; +} + .is-h-xs { height: 80px !important; } diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index 325caa92b..f3062a447 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -15,6 +15,12 @@ {% endif %} {% if site.imports_enabled %} + {% if import_size_limit and import_limit_reset %} +
+

{% blocktrans %}Currently you are allowed to import {{ import_size_limit }} books every {{ import_limit_reset }} days.{% endblocktrans %}

+

{% blocktrans %}You have {{ allowed_imports }} left.{% endblocktrans %}

+
+ {% endif %} {% if recent_avg_hours or recent_avg_minutes %}

@@ -90,7 +96,12 @@

- + {% if not import_limit_reset and not import_size_limit or allowed_imports > 0 %} + + {% else %} + +

{% trans "You've reached the import limit." %}

+ {% endif%} {% else %}
diff --git a/bookwyrm/templates/settings/imports/imports.html b/bookwyrm/templates/settings/imports/imports.html index 135af34ed..108003d85 100644 --- a/bookwyrm/templates/settings/imports/imports.html +++ b/bookwyrm/templates/settings/imports/imports.html @@ -57,8 +57,39 @@
{% endif %} +
+ + + {% trans "Limit the amount of imports" %} + + + +
+
+ {% trans "Some users might try to import a large number of books, which you want to limit." %} + {% trans "Set the value to 0 to not enforce any limit." %} +
+
+ + + + + + {% csrf_token %} +
+ +
+
+
+
-