Merge branch 'main' into import-limit

This commit is contained in:
Giebisch 2023-01-02 15:42:50 +01:00
commit 7e7966987b
71 changed files with 13041 additions and 3774 deletions

View file

@ -34,6 +34,7 @@ REDIS_ACTIVITY_PASSWORD=redispassword345
# REDIS_ACTIVITY_DB_INDEX=0
# Redis as celery broker
REDIS_BROKER_HOST=redis_broker
REDIS_BROKER_PORT=6379
REDIS_BROKER_PASSWORD=redispassword123
# Optional, use a different redis database (defaults to 0)

View file

@ -318,6 +318,10 @@ def add_status_on_create_command(sender, instance, created):
if instance.published_date < timezone.now() - timedelta(
days=1
) or instance.created_date < instance.published_date - timedelta(days=1):
# a backdated status from a local user is an import, don't add it
if instance.user.local:
return
# an out of date remote status is a low priority but should be added
priority = LOW
add_status_task.apply_async(

View file

@ -0,0 +1,48 @@
""" Our own command to all scss themes """
import glob
import os
import sass
from django.core.management.base import BaseCommand
from sass_processor.apps import APPS_INCLUDE_DIRS
from sass_processor.processor import SassProcessor
from sass_processor.utils import get_custom_functions
from bookwyrm import settings
class Command(BaseCommand):
"""command-line options"""
help = "SCSS compile all BookWyrm themes"
# pylint: disable=unused-argument
def handle(self, *args, **options):
"""compile"""
themes_dir = os.path.join(
settings.BASE_DIR, "bookwyrm", "static", "css", "themes", "*.scss"
)
for theme_scss in glob.glob(themes_dir):
basename, _ = os.path.splitext(theme_scss)
theme_css = f"{basename}.css"
self.compile_sass(theme_scss, theme_css)
def compile_sass(self, sass_path, css_path):
compile_kwargs = {
"filename": sass_path,
"include_paths": SassProcessor.include_paths + APPS_INCLUDE_DIRS,
"custom_functions": get_custom_functions(),
"precision": getattr(settings, "SASS_PRECISION", 8),
"output_style": getattr(
settings,
"SASS_OUTPUT_STYLE",
"nested" if settings.DEBUG else "compressed",
),
}
content = sass.compile(**compile_kwargs)
with open(css_path, "w") as f:
f.write(content)
self.stdout.write("Compiled SASS/SCSS file: '{0}'\n".format(sass_path))

View file

@ -0,0 +1,40 @@
""" Remove preview images for remote users """
from django.core.management.base import BaseCommand
from django.db.models import Q
from bookwyrm import models, preview_images
# pylint: disable=line-too-long
class Command(BaseCommand):
"""Remove preview images for remote users"""
help = "Remove preview images for remote users"
# pylint: disable=no-self-use,unused-argument
def handle(self, *args, **options):
"""generate preview images"""
self.stdout.write(
" | Hello! I will be removing preview images from remote users."
)
self.stdout.write(
"🧑‍🚒 ⎨ This might take quite long if your instance has a lot of remote users."
)
self.stdout.write(" | ✧ Thank you for your patience ✧")
users = models.User.objects.filter(local=False).exclude(
Q(preview_image="") | Q(preview_image=None)
)
if len(users) > 0:
self.stdout.write(
f" → Remote user preview images ({len(users)}): ", ending=""
)
for user in users:
preview_images.remove_user_preview_image_task.delay(user.id)
self.stdout.write(".", ending="")
self.stdout.write(" OK 🖼")
else:
self.stdout.write(f" | There was no remote users with preview images.")
self.stdout.write("🧑‍🚒 ⎨ Im all done! ✧ Enjoy ✧")

View file

@ -0,0 +1,631 @@
# Generated by Django 3.2.16 on 2022-12-19 15:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0170_merge_0168_auto_20221205_2331_0169_auto_20221206_0902"),
]
operations = [
migrations.AlterField(
model_name="user",
name="preferred_timezone",
field=models.CharField(
choices=[
("Africa/Abidjan", "Africa/Abidjan"),
("Africa/Accra", "Africa/Accra"),
("Africa/Addis_Ababa", "Africa/Addis_Ababa"),
("Africa/Algiers", "Africa/Algiers"),
("Africa/Asmara", "Africa/Asmara"),
("Africa/Asmera", "Africa/Asmera"),
("Africa/Bamako", "Africa/Bamako"),
("Africa/Bangui", "Africa/Bangui"),
("Africa/Banjul", "Africa/Banjul"),
("Africa/Bissau", "Africa/Bissau"),
("Africa/Blantyre", "Africa/Blantyre"),
("Africa/Brazzaville", "Africa/Brazzaville"),
("Africa/Bujumbura", "Africa/Bujumbura"),
("Africa/Cairo", "Africa/Cairo"),
("Africa/Casablanca", "Africa/Casablanca"),
("Africa/Ceuta", "Africa/Ceuta"),
("Africa/Conakry", "Africa/Conakry"),
("Africa/Dakar", "Africa/Dakar"),
("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"),
("Africa/Djibouti", "Africa/Djibouti"),
("Africa/Douala", "Africa/Douala"),
("Africa/El_Aaiun", "Africa/El_Aaiun"),
("Africa/Freetown", "Africa/Freetown"),
("Africa/Gaborone", "Africa/Gaborone"),
("Africa/Harare", "Africa/Harare"),
("Africa/Johannesburg", "Africa/Johannesburg"),
("Africa/Juba", "Africa/Juba"),
("Africa/Kampala", "Africa/Kampala"),
("Africa/Khartoum", "Africa/Khartoum"),
("Africa/Kigali", "Africa/Kigali"),
("Africa/Kinshasa", "Africa/Kinshasa"),
("Africa/Lagos", "Africa/Lagos"),
("Africa/Libreville", "Africa/Libreville"),
("Africa/Lome", "Africa/Lome"),
("Africa/Luanda", "Africa/Luanda"),
("Africa/Lubumbashi", "Africa/Lubumbashi"),
("Africa/Lusaka", "Africa/Lusaka"),
("Africa/Malabo", "Africa/Malabo"),
("Africa/Maputo", "Africa/Maputo"),
("Africa/Maseru", "Africa/Maseru"),
("Africa/Mbabane", "Africa/Mbabane"),
("Africa/Mogadishu", "Africa/Mogadishu"),
("Africa/Monrovia", "Africa/Monrovia"),
("Africa/Nairobi", "Africa/Nairobi"),
("Africa/Ndjamena", "Africa/Ndjamena"),
("Africa/Niamey", "Africa/Niamey"),
("Africa/Nouakchott", "Africa/Nouakchott"),
("Africa/Ouagadougou", "Africa/Ouagadougou"),
("Africa/Porto-Novo", "Africa/Porto-Novo"),
("Africa/Sao_Tome", "Africa/Sao_Tome"),
("Africa/Timbuktu", "Africa/Timbuktu"),
("Africa/Tripoli", "Africa/Tripoli"),
("Africa/Tunis", "Africa/Tunis"),
("Africa/Windhoek", "Africa/Windhoek"),
("America/Adak", "America/Adak"),
("America/Anchorage", "America/Anchorage"),
("America/Anguilla", "America/Anguilla"),
("America/Antigua", "America/Antigua"),
("America/Araguaina", "America/Araguaina"),
(
"America/Argentina/Buenos_Aires",
"America/Argentina/Buenos_Aires",
),
("America/Argentina/Catamarca", "America/Argentina/Catamarca"),
(
"America/Argentina/ComodRivadavia",
"America/Argentina/ComodRivadavia",
),
("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"),
("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
(
"America/Argentina/Rio_Gallegos",
"America/Argentina/Rio_Gallegos",
),
("America/Argentina/Salta", "America/Argentina/Salta"),
("America/Argentina/San_Juan", "America/Argentina/San_Juan"),
("America/Argentina/San_Luis", "America/Argentina/San_Luis"),
("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
("America/Aruba", "America/Aruba"),
("America/Asuncion", "America/Asuncion"),
("America/Atikokan", "America/Atikokan"),
("America/Atka", "America/Atka"),
("America/Bahia", "America/Bahia"),
("America/Bahia_Banderas", "America/Bahia_Banderas"),
("America/Barbados", "America/Barbados"),
("America/Belem", "America/Belem"),
("America/Belize", "America/Belize"),
("America/Blanc-Sablon", "America/Blanc-Sablon"),
("America/Boa_Vista", "America/Boa_Vista"),
("America/Bogota", "America/Bogota"),
("America/Boise", "America/Boise"),
("America/Buenos_Aires", "America/Buenos_Aires"),
("America/Cambridge_Bay", "America/Cambridge_Bay"),
("America/Campo_Grande", "America/Campo_Grande"),
("America/Cancun", "America/Cancun"),
("America/Caracas", "America/Caracas"),
("America/Catamarca", "America/Catamarca"),
("America/Cayenne", "America/Cayenne"),
("America/Cayman", "America/Cayman"),
("America/Chicago", "America/Chicago"),
("America/Chihuahua", "America/Chihuahua"),
("America/Ciudad_Juarez", "America/Ciudad_Juarez"),
("America/Coral_Harbour", "America/Coral_Harbour"),
("America/Cordoba", "America/Cordoba"),
("America/Costa_Rica", "America/Costa_Rica"),
("America/Creston", "America/Creston"),
("America/Cuiaba", "America/Cuiaba"),
("America/Curacao", "America/Curacao"),
("America/Danmarkshavn", "America/Danmarkshavn"),
("America/Dawson", "America/Dawson"),
("America/Dawson_Creek", "America/Dawson_Creek"),
("America/Denver", "America/Denver"),
("America/Detroit", "America/Detroit"),
("America/Dominica", "America/Dominica"),
("America/Edmonton", "America/Edmonton"),
("America/Eirunepe", "America/Eirunepe"),
("America/El_Salvador", "America/El_Salvador"),
("America/Ensenada", "America/Ensenada"),
("America/Fort_Nelson", "America/Fort_Nelson"),
("America/Fort_Wayne", "America/Fort_Wayne"),
("America/Fortaleza", "America/Fortaleza"),
("America/Glace_Bay", "America/Glace_Bay"),
("America/Godthab", "America/Godthab"),
("America/Goose_Bay", "America/Goose_Bay"),
("America/Grand_Turk", "America/Grand_Turk"),
("America/Grenada", "America/Grenada"),
("America/Guadeloupe", "America/Guadeloupe"),
("America/Guatemala", "America/Guatemala"),
("America/Guayaquil", "America/Guayaquil"),
("America/Guyana", "America/Guyana"),
("America/Halifax", "America/Halifax"),
("America/Havana", "America/Havana"),
("America/Hermosillo", "America/Hermosillo"),
("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"),
("America/Indiana/Knox", "America/Indiana/Knox"),
("America/Indiana/Marengo", "America/Indiana/Marengo"),
("America/Indiana/Petersburg", "America/Indiana/Petersburg"),
("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
("America/Indiana/Vevay", "America/Indiana/Vevay"),
("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
("America/Indiana/Winamac", "America/Indiana/Winamac"),
("America/Indianapolis", "America/Indianapolis"),
("America/Inuvik", "America/Inuvik"),
("America/Iqaluit", "America/Iqaluit"),
("America/Jamaica", "America/Jamaica"),
("America/Jujuy", "America/Jujuy"),
("America/Juneau", "America/Juneau"),
("America/Kentucky/Louisville", "America/Kentucky/Louisville"),
("America/Kentucky/Monticello", "America/Kentucky/Monticello"),
("America/Knox_IN", "America/Knox_IN"),
("America/Kralendijk", "America/Kralendijk"),
("America/La_Paz", "America/La_Paz"),
("America/Lima", "America/Lima"),
("America/Los_Angeles", "America/Los_Angeles"),
("America/Louisville", "America/Louisville"),
("America/Lower_Princes", "America/Lower_Princes"),
("America/Maceio", "America/Maceio"),
("America/Managua", "America/Managua"),
("America/Manaus", "America/Manaus"),
("America/Marigot", "America/Marigot"),
("America/Martinique", "America/Martinique"),
("America/Matamoros", "America/Matamoros"),
("America/Mazatlan", "America/Mazatlan"),
("America/Mendoza", "America/Mendoza"),
("America/Menominee", "America/Menominee"),
("America/Merida", "America/Merida"),
("America/Metlakatla", "America/Metlakatla"),
("America/Mexico_City", "America/Mexico_City"),
("America/Miquelon", "America/Miquelon"),
("America/Moncton", "America/Moncton"),
("America/Monterrey", "America/Monterrey"),
("America/Montevideo", "America/Montevideo"),
("America/Montreal", "America/Montreal"),
("America/Montserrat", "America/Montserrat"),
("America/Nassau", "America/Nassau"),
("America/New_York", "America/New_York"),
("America/Nipigon", "America/Nipigon"),
("America/Nome", "America/Nome"),
("America/Noronha", "America/Noronha"),
("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"),
("America/North_Dakota/Center", "America/North_Dakota/Center"),
(
"America/North_Dakota/New_Salem",
"America/North_Dakota/New_Salem",
),
("America/Nuuk", "America/Nuuk"),
("America/Ojinaga", "America/Ojinaga"),
("America/Panama", "America/Panama"),
("America/Pangnirtung", "America/Pangnirtung"),
("America/Paramaribo", "America/Paramaribo"),
("America/Phoenix", "America/Phoenix"),
("America/Port-au-Prince", "America/Port-au-Prince"),
("America/Port_of_Spain", "America/Port_of_Spain"),
("America/Porto_Acre", "America/Porto_Acre"),
("America/Porto_Velho", "America/Porto_Velho"),
("America/Puerto_Rico", "America/Puerto_Rico"),
("America/Punta_Arenas", "America/Punta_Arenas"),
("America/Rainy_River", "America/Rainy_River"),
("America/Rankin_Inlet", "America/Rankin_Inlet"),
("America/Recife", "America/Recife"),
("America/Regina", "America/Regina"),
("America/Resolute", "America/Resolute"),
("America/Rio_Branco", "America/Rio_Branco"),
("America/Rosario", "America/Rosario"),
("America/Santa_Isabel", "America/Santa_Isabel"),
("America/Santarem", "America/Santarem"),
("America/Santiago", "America/Santiago"),
("America/Santo_Domingo", "America/Santo_Domingo"),
("America/Sao_Paulo", "America/Sao_Paulo"),
("America/Scoresbysund", "America/Scoresbysund"),
("America/Shiprock", "America/Shiprock"),
("America/Sitka", "America/Sitka"),
("America/St_Barthelemy", "America/St_Barthelemy"),
("America/St_Johns", "America/St_Johns"),
("America/St_Kitts", "America/St_Kitts"),
("America/St_Lucia", "America/St_Lucia"),
("America/St_Thomas", "America/St_Thomas"),
("America/St_Vincent", "America/St_Vincent"),
("America/Swift_Current", "America/Swift_Current"),
("America/Tegucigalpa", "America/Tegucigalpa"),
("America/Thule", "America/Thule"),
("America/Thunder_Bay", "America/Thunder_Bay"),
("America/Tijuana", "America/Tijuana"),
("America/Toronto", "America/Toronto"),
("America/Tortola", "America/Tortola"),
("America/Vancouver", "America/Vancouver"),
("America/Virgin", "America/Virgin"),
("America/Whitehorse", "America/Whitehorse"),
("America/Winnipeg", "America/Winnipeg"),
("America/Yakutat", "America/Yakutat"),
("America/Yellowknife", "America/Yellowknife"),
("Antarctica/Casey", "Antarctica/Casey"),
("Antarctica/Davis", "Antarctica/Davis"),
("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"),
("Antarctica/Macquarie", "Antarctica/Macquarie"),
("Antarctica/Mawson", "Antarctica/Mawson"),
("Antarctica/McMurdo", "Antarctica/McMurdo"),
("Antarctica/Palmer", "Antarctica/Palmer"),
("Antarctica/Rothera", "Antarctica/Rothera"),
("Antarctica/South_Pole", "Antarctica/South_Pole"),
("Antarctica/Syowa", "Antarctica/Syowa"),
("Antarctica/Troll", "Antarctica/Troll"),
("Antarctica/Vostok", "Antarctica/Vostok"),
("Arctic/Longyearbyen", "Arctic/Longyearbyen"),
("Asia/Aden", "Asia/Aden"),
("Asia/Almaty", "Asia/Almaty"),
("Asia/Amman", "Asia/Amman"),
("Asia/Anadyr", "Asia/Anadyr"),
("Asia/Aqtau", "Asia/Aqtau"),
("Asia/Aqtobe", "Asia/Aqtobe"),
("Asia/Ashgabat", "Asia/Ashgabat"),
("Asia/Ashkhabad", "Asia/Ashkhabad"),
("Asia/Atyrau", "Asia/Atyrau"),
("Asia/Baghdad", "Asia/Baghdad"),
("Asia/Bahrain", "Asia/Bahrain"),
("Asia/Baku", "Asia/Baku"),
("Asia/Bangkok", "Asia/Bangkok"),
("Asia/Barnaul", "Asia/Barnaul"),
("Asia/Beirut", "Asia/Beirut"),
("Asia/Bishkek", "Asia/Bishkek"),
("Asia/Brunei", "Asia/Brunei"),
("Asia/Calcutta", "Asia/Calcutta"),
("Asia/Chita", "Asia/Chita"),
("Asia/Choibalsan", "Asia/Choibalsan"),
("Asia/Chongqing", "Asia/Chongqing"),
("Asia/Chungking", "Asia/Chungking"),
("Asia/Colombo", "Asia/Colombo"),
("Asia/Dacca", "Asia/Dacca"),
("Asia/Damascus", "Asia/Damascus"),
("Asia/Dhaka", "Asia/Dhaka"),
("Asia/Dili", "Asia/Dili"),
("Asia/Dubai", "Asia/Dubai"),
("Asia/Dushanbe", "Asia/Dushanbe"),
("Asia/Famagusta", "Asia/Famagusta"),
("Asia/Gaza", "Asia/Gaza"),
("Asia/Harbin", "Asia/Harbin"),
("Asia/Hebron", "Asia/Hebron"),
("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"),
("Asia/Hong_Kong", "Asia/Hong_Kong"),
("Asia/Hovd", "Asia/Hovd"),
("Asia/Irkutsk", "Asia/Irkutsk"),
("Asia/Istanbul", "Asia/Istanbul"),
("Asia/Jakarta", "Asia/Jakarta"),
("Asia/Jayapura", "Asia/Jayapura"),
("Asia/Jerusalem", "Asia/Jerusalem"),
("Asia/Kabul", "Asia/Kabul"),
("Asia/Kamchatka", "Asia/Kamchatka"),
("Asia/Karachi", "Asia/Karachi"),
("Asia/Kashgar", "Asia/Kashgar"),
("Asia/Kathmandu", "Asia/Kathmandu"),
("Asia/Katmandu", "Asia/Katmandu"),
("Asia/Khandyga", "Asia/Khandyga"),
("Asia/Kolkata", "Asia/Kolkata"),
("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"),
("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"),
("Asia/Kuching", "Asia/Kuching"),
("Asia/Kuwait", "Asia/Kuwait"),
("Asia/Macao", "Asia/Macao"),
("Asia/Macau", "Asia/Macau"),
("Asia/Magadan", "Asia/Magadan"),
("Asia/Makassar", "Asia/Makassar"),
("Asia/Manila", "Asia/Manila"),
("Asia/Muscat", "Asia/Muscat"),
("Asia/Nicosia", "Asia/Nicosia"),
("Asia/Novokuznetsk", "Asia/Novokuznetsk"),
("Asia/Novosibirsk", "Asia/Novosibirsk"),
("Asia/Omsk", "Asia/Omsk"),
("Asia/Oral", "Asia/Oral"),
("Asia/Phnom_Penh", "Asia/Phnom_Penh"),
("Asia/Pontianak", "Asia/Pontianak"),
("Asia/Pyongyang", "Asia/Pyongyang"),
("Asia/Qatar", "Asia/Qatar"),
("Asia/Qostanay", "Asia/Qostanay"),
("Asia/Qyzylorda", "Asia/Qyzylorda"),
("Asia/Rangoon", "Asia/Rangoon"),
("Asia/Riyadh", "Asia/Riyadh"),
("Asia/Saigon", "Asia/Saigon"),
("Asia/Sakhalin", "Asia/Sakhalin"),
("Asia/Samarkand", "Asia/Samarkand"),
("Asia/Seoul", "Asia/Seoul"),
("Asia/Shanghai", "Asia/Shanghai"),
("Asia/Singapore", "Asia/Singapore"),
("Asia/Srednekolymsk", "Asia/Srednekolymsk"),
("Asia/Taipei", "Asia/Taipei"),
("Asia/Tashkent", "Asia/Tashkent"),
("Asia/Tbilisi", "Asia/Tbilisi"),
("Asia/Tehran", "Asia/Tehran"),
("Asia/Tel_Aviv", "Asia/Tel_Aviv"),
("Asia/Thimbu", "Asia/Thimbu"),
("Asia/Thimphu", "Asia/Thimphu"),
("Asia/Tokyo", "Asia/Tokyo"),
("Asia/Tomsk", "Asia/Tomsk"),
("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"),
("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"),
("Asia/Ulan_Bator", "Asia/Ulan_Bator"),
("Asia/Urumqi", "Asia/Urumqi"),
("Asia/Ust-Nera", "Asia/Ust-Nera"),
("Asia/Vientiane", "Asia/Vientiane"),
("Asia/Vladivostok", "Asia/Vladivostok"),
("Asia/Yakutsk", "Asia/Yakutsk"),
("Asia/Yangon", "Asia/Yangon"),
("Asia/Yekaterinburg", "Asia/Yekaterinburg"),
("Asia/Yerevan", "Asia/Yerevan"),
("Atlantic/Azores", "Atlantic/Azores"),
("Atlantic/Bermuda", "Atlantic/Bermuda"),
("Atlantic/Canary", "Atlantic/Canary"),
("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"),
("Atlantic/Faeroe", "Atlantic/Faeroe"),
("Atlantic/Faroe", "Atlantic/Faroe"),
("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"),
("Atlantic/Madeira", "Atlantic/Madeira"),
("Atlantic/Reykjavik", "Atlantic/Reykjavik"),
("Atlantic/South_Georgia", "Atlantic/South_Georgia"),
("Atlantic/St_Helena", "Atlantic/St_Helena"),
("Atlantic/Stanley", "Atlantic/Stanley"),
("Australia/ACT", "Australia/ACT"),
("Australia/Adelaide", "Australia/Adelaide"),
("Australia/Brisbane", "Australia/Brisbane"),
("Australia/Broken_Hill", "Australia/Broken_Hill"),
("Australia/Canberra", "Australia/Canberra"),
("Australia/Currie", "Australia/Currie"),
("Australia/Darwin", "Australia/Darwin"),
("Australia/Eucla", "Australia/Eucla"),
("Australia/Hobart", "Australia/Hobart"),
("Australia/LHI", "Australia/LHI"),
("Australia/Lindeman", "Australia/Lindeman"),
("Australia/Lord_Howe", "Australia/Lord_Howe"),
("Australia/Melbourne", "Australia/Melbourne"),
("Australia/NSW", "Australia/NSW"),
("Australia/North", "Australia/North"),
("Australia/Perth", "Australia/Perth"),
("Australia/Queensland", "Australia/Queensland"),
("Australia/South", "Australia/South"),
("Australia/Sydney", "Australia/Sydney"),
("Australia/Tasmania", "Australia/Tasmania"),
("Australia/Victoria", "Australia/Victoria"),
("Australia/West", "Australia/West"),
("Australia/Yancowinna", "Australia/Yancowinna"),
("Brazil/Acre", "Brazil/Acre"),
("Brazil/DeNoronha", "Brazil/DeNoronha"),
("Brazil/East", "Brazil/East"),
("Brazil/West", "Brazil/West"),
("CET", "CET"),
("CST6CDT", "CST6CDT"),
("Canada/Atlantic", "Canada/Atlantic"),
("Canada/Central", "Canada/Central"),
("Canada/Eastern", "Canada/Eastern"),
("Canada/Mountain", "Canada/Mountain"),
("Canada/Newfoundland", "Canada/Newfoundland"),
("Canada/Pacific", "Canada/Pacific"),
("Canada/Saskatchewan", "Canada/Saskatchewan"),
("Canada/Yukon", "Canada/Yukon"),
("Chile/Continental", "Chile/Continental"),
("Chile/EasterIsland", "Chile/EasterIsland"),
("Cuba", "Cuba"),
("EET", "EET"),
("EST", "EST"),
("EST5EDT", "EST5EDT"),
("Egypt", "Egypt"),
("Eire", "Eire"),
("Etc/GMT", "Etc/GMT"),
("Etc/GMT+0", "Etc/GMT+0"),
("Etc/GMT+1", "Etc/GMT+1"),
("Etc/GMT+10", "Etc/GMT+10"),
("Etc/GMT+11", "Etc/GMT+11"),
("Etc/GMT+12", "Etc/GMT+12"),
("Etc/GMT+2", "Etc/GMT+2"),
("Etc/GMT+3", "Etc/GMT+3"),
("Etc/GMT+4", "Etc/GMT+4"),
("Etc/GMT+5", "Etc/GMT+5"),
("Etc/GMT+6", "Etc/GMT+6"),
("Etc/GMT+7", "Etc/GMT+7"),
("Etc/GMT+8", "Etc/GMT+8"),
("Etc/GMT+9", "Etc/GMT+9"),
("Etc/GMT-0", "Etc/GMT-0"),
("Etc/GMT-1", "Etc/GMT-1"),
("Etc/GMT-10", "Etc/GMT-10"),
("Etc/GMT-11", "Etc/GMT-11"),
("Etc/GMT-12", "Etc/GMT-12"),
("Etc/GMT-13", "Etc/GMT-13"),
("Etc/GMT-14", "Etc/GMT-14"),
("Etc/GMT-2", "Etc/GMT-2"),
("Etc/GMT-3", "Etc/GMT-3"),
("Etc/GMT-4", "Etc/GMT-4"),
("Etc/GMT-5", "Etc/GMT-5"),
("Etc/GMT-6", "Etc/GMT-6"),
("Etc/GMT-7", "Etc/GMT-7"),
("Etc/GMT-8", "Etc/GMT-8"),
("Etc/GMT-9", "Etc/GMT-9"),
("Etc/GMT0", "Etc/GMT0"),
("Etc/Greenwich", "Etc/Greenwich"),
("Etc/UCT", "Etc/UCT"),
("Etc/UTC", "Etc/UTC"),
("Etc/Universal", "Etc/Universal"),
("Etc/Zulu", "Etc/Zulu"),
("Europe/Amsterdam", "Europe/Amsterdam"),
("Europe/Andorra", "Europe/Andorra"),
("Europe/Astrakhan", "Europe/Astrakhan"),
("Europe/Athens", "Europe/Athens"),
("Europe/Belfast", "Europe/Belfast"),
("Europe/Belgrade", "Europe/Belgrade"),
("Europe/Berlin", "Europe/Berlin"),
("Europe/Bratislava", "Europe/Bratislava"),
("Europe/Brussels", "Europe/Brussels"),
("Europe/Bucharest", "Europe/Bucharest"),
("Europe/Budapest", "Europe/Budapest"),
("Europe/Busingen", "Europe/Busingen"),
("Europe/Chisinau", "Europe/Chisinau"),
("Europe/Copenhagen", "Europe/Copenhagen"),
("Europe/Dublin", "Europe/Dublin"),
("Europe/Gibraltar", "Europe/Gibraltar"),
("Europe/Guernsey", "Europe/Guernsey"),
("Europe/Helsinki", "Europe/Helsinki"),
("Europe/Isle_of_Man", "Europe/Isle_of_Man"),
("Europe/Istanbul", "Europe/Istanbul"),
("Europe/Jersey", "Europe/Jersey"),
("Europe/Kaliningrad", "Europe/Kaliningrad"),
("Europe/Kiev", "Europe/Kiev"),
("Europe/Kirov", "Europe/Kirov"),
("Europe/Kyiv", "Europe/Kyiv"),
("Europe/Lisbon", "Europe/Lisbon"),
("Europe/Ljubljana", "Europe/Ljubljana"),
("Europe/London", "Europe/London"),
("Europe/Luxembourg", "Europe/Luxembourg"),
("Europe/Madrid", "Europe/Madrid"),
("Europe/Malta", "Europe/Malta"),
("Europe/Mariehamn", "Europe/Mariehamn"),
("Europe/Minsk", "Europe/Minsk"),
("Europe/Monaco", "Europe/Monaco"),
("Europe/Moscow", "Europe/Moscow"),
("Europe/Nicosia", "Europe/Nicosia"),
("Europe/Oslo", "Europe/Oslo"),
("Europe/Paris", "Europe/Paris"),
("Europe/Podgorica", "Europe/Podgorica"),
("Europe/Prague", "Europe/Prague"),
("Europe/Riga", "Europe/Riga"),
("Europe/Rome", "Europe/Rome"),
("Europe/Samara", "Europe/Samara"),
("Europe/San_Marino", "Europe/San_Marino"),
("Europe/Sarajevo", "Europe/Sarajevo"),
("Europe/Saratov", "Europe/Saratov"),
("Europe/Simferopol", "Europe/Simferopol"),
("Europe/Skopje", "Europe/Skopje"),
("Europe/Sofia", "Europe/Sofia"),
("Europe/Stockholm", "Europe/Stockholm"),
("Europe/Tallinn", "Europe/Tallinn"),
("Europe/Tirane", "Europe/Tirane"),
("Europe/Tiraspol", "Europe/Tiraspol"),
("Europe/Ulyanovsk", "Europe/Ulyanovsk"),
("Europe/Uzhgorod", "Europe/Uzhgorod"),
("Europe/Vaduz", "Europe/Vaduz"),
("Europe/Vatican", "Europe/Vatican"),
("Europe/Vienna", "Europe/Vienna"),
("Europe/Vilnius", "Europe/Vilnius"),
("Europe/Volgograd", "Europe/Volgograd"),
("Europe/Warsaw", "Europe/Warsaw"),
("Europe/Zagreb", "Europe/Zagreb"),
("Europe/Zaporozhye", "Europe/Zaporozhye"),
("Europe/Zurich", "Europe/Zurich"),
("GB", "GB"),
("GB-Eire", "GB-Eire"),
("GMT", "GMT"),
("GMT+0", "GMT+0"),
("GMT-0", "GMT-0"),
("GMT0", "GMT0"),
("Greenwich", "Greenwich"),
("HST", "HST"),
("Hongkong", "Hongkong"),
("Iceland", "Iceland"),
("Indian/Antananarivo", "Indian/Antananarivo"),
("Indian/Chagos", "Indian/Chagos"),
("Indian/Christmas", "Indian/Christmas"),
("Indian/Cocos", "Indian/Cocos"),
("Indian/Comoro", "Indian/Comoro"),
("Indian/Kerguelen", "Indian/Kerguelen"),
("Indian/Mahe", "Indian/Mahe"),
("Indian/Maldives", "Indian/Maldives"),
("Indian/Mauritius", "Indian/Mauritius"),
("Indian/Mayotte", "Indian/Mayotte"),
("Indian/Reunion", "Indian/Reunion"),
("Iran", "Iran"),
("Israel", "Israel"),
("Jamaica", "Jamaica"),
("Japan", "Japan"),
("Kwajalein", "Kwajalein"),
("Libya", "Libya"),
("MET", "MET"),
("MST", "MST"),
("MST7MDT", "MST7MDT"),
("Mexico/BajaNorte", "Mexico/BajaNorte"),
("Mexico/BajaSur", "Mexico/BajaSur"),
("Mexico/General", "Mexico/General"),
("NZ", "NZ"),
("NZ-CHAT", "NZ-CHAT"),
("Navajo", "Navajo"),
("PRC", "PRC"),
("PST8PDT", "PST8PDT"),
("Pacific/Apia", "Pacific/Apia"),
("Pacific/Auckland", "Pacific/Auckland"),
("Pacific/Bougainville", "Pacific/Bougainville"),
("Pacific/Chatham", "Pacific/Chatham"),
("Pacific/Chuuk", "Pacific/Chuuk"),
("Pacific/Easter", "Pacific/Easter"),
("Pacific/Efate", "Pacific/Efate"),
("Pacific/Enderbury", "Pacific/Enderbury"),
("Pacific/Fakaofo", "Pacific/Fakaofo"),
("Pacific/Fiji", "Pacific/Fiji"),
("Pacific/Funafuti", "Pacific/Funafuti"),
("Pacific/Galapagos", "Pacific/Galapagos"),
("Pacific/Gambier", "Pacific/Gambier"),
("Pacific/Guadalcanal", "Pacific/Guadalcanal"),
("Pacific/Guam", "Pacific/Guam"),
("Pacific/Honolulu", "Pacific/Honolulu"),
("Pacific/Johnston", "Pacific/Johnston"),
("Pacific/Kanton", "Pacific/Kanton"),
("Pacific/Kiritimati", "Pacific/Kiritimati"),
("Pacific/Kosrae", "Pacific/Kosrae"),
("Pacific/Kwajalein", "Pacific/Kwajalein"),
("Pacific/Majuro", "Pacific/Majuro"),
("Pacific/Marquesas", "Pacific/Marquesas"),
("Pacific/Midway", "Pacific/Midway"),
("Pacific/Nauru", "Pacific/Nauru"),
("Pacific/Niue", "Pacific/Niue"),
("Pacific/Norfolk", "Pacific/Norfolk"),
("Pacific/Noumea", "Pacific/Noumea"),
("Pacific/Pago_Pago", "Pacific/Pago_Pago"),
("Pacific/Palau", "Pacific/Palau"),
("Pacific/Pitcairn", "Pacific/Pitcairn"),
("Pacific/Pohnpei", "Pacific/Pohnpei"),
("Pacific/Ponape", "Pacific/Ponape"),
("Pacific/Port_Moresby", "Pacific/Port_Moresby"),
("Pacific/Rarotonga", "Pacific/Rarotonga"),
("Pacific/Saipan", "Pacific/Saipan"),
("Pacific/Samoa", "Pacific/Samoa"),
("Pacific/Tahiti", "Pacific/Tahiti"),
("Pacific/Tarawa", "Pacific/Tarawa"),
("Pacific/Tongatapu", "Pacific/Tongatapu"),
("Pacific/Truk", "Pacific/Truk"),
("Pacific/Wake", "Pacific/Wake"),
("Pacific/Wallis", "Pacific/Wallis"),
("Pacific/Yap", "Pacific/Yap"),
("Poland", "Poland"),
("Portugal", "Portugal"),
("ROC", "ROC"),
("ROK", "ROK"),
("Singapore", "Singapore"),
("Turkey", "Turkey"),
("UCT", "UCT"),
("US/Alaska", "US/Alaska"),
("US/Aleutian", "US/Aleutian"),
("US/Arizona", "US/Arizona"),
("US/Central", "US/Central"),
("US/East-Indiana", "US/East-Indiana"),
("US/Eastern", "US/Eastern"),
("US/Hawaii", "US/Hawaii"),
("US/Indiana-Starke", "US/Indiana-Starke"),
("US/Michigan", "US/Michigan"),
("US/Mountain", "US/Mountain"),
("US/Pacific", "US/Pacific"),
("US/Samoa", "US/Samoa"),
("UTC", "UTC"),
("Universal", "Universal"),
("W-SU", "W-SU"),
("WET", "WET"),
("Zulu", "Zulu"),
],
default="UTC",
max_length=255,
),
),
]

View file

@ -0,0 +1,42 @@
# Generated by Django 3.2.16 on 2022-12-21 18:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0171_alter_user_preferred_timezone"),
]
operations = [
migrations.AlterField(
model_name="user",
name="preferred_language",
field=models.CharField(
blank=True,
choices=[
("en-us", "English"),
("ca-es", "Català (Catalan)"),
("de-de", "Deutsch (German)"),
("es-es", "Español (Spanish)"),
("eu-es", "Euskara (Basque)"),
("gl-es", "Galego (Galician)"),
("it-it", "Italiano (Italian)"),
("fi-fi", "Suomi (Finnish)"),
("fr-fr", "Français (French)"),
("lt-lt", "Lietuvių (Lithuanian)"),
("no-no", "Norsk (Norwegian)"),
("pl-pl", "Polski (Polish)"),
("pt-br", "Português do Brasil (Brazilian Portuguese)"),
("pt-pt", "Português Europeu (European Portuguese)"),
("ro-ro", "Română (Romanian)"),
("sv-se", "Svenska (Swedish)"),
("zh-hans", "简体中文 (Simplified Chinese)"),
("zh-hant", "繁體中文 (Traditional Chinese)"),
],
max_length=255,
null=True,
),
),
]

View file

@ -1,8 +1,6 @@
""" database schema for info about authors """
import re
from django.contrib.postgres.indexes import GinIndex
from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
from django.db import models
from bookwyrm import activitypub
@ -37,16 +35,7 @@ class Author(BookDataModel):
bio = fields.HtmlField(null=True, blank=True)
def save(self, *args, **kwargs):
"""clear related template caches"""
# clear template caches
if self.id:
cache_keys = [
make_template_fragment_key("titleby", [book])
for book in self.book_set.values_list("id", flat=True)
]
cache.delete_many(cache_keys)
# normalize isni format
"""normalize isni format"""
if self.isni:
self.isni = re.sub(r"\s", "", self.isni)

View file

@ -4,7 +4,6 @@ import re
from django.contrib.postgres.search import SearchVectorField
from django.contrib.postgres.indexes import GinIndex
from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
from django.db import models, transaction
from django.db.models import Prefetch
from django.dispatch import receiver
@ -208,10 +207,6 @@ class Book(BookDataModel):
if not isinstance(self, Edition) and not isinstance(self, Work):
raise ValueError("Books should be added as Editions or Works")
# clear template caches
cache_key = make_template_fragment_key("titleby", [self.id])
cache.delete(cache_key)
return super().save(*args, **kwargs)
def get_remote_id(self):

View file

@ -19,7 +19,7 @@ from bookwyrm.models import (
Review,
ReviewRating,
)
from bookwyrm.tasks import app, LOW
from bookwyrm.tasks import app, LOW, IMPORTS
from .fields import PrivacyLevels
@ -74,8 +74,7 @@ class ImportJob(models.Model):
task = start_import_task.delay(self.id)
self.task_id = task.id
self.status = "active"
self.save(update_fields=["status", "task_id"])
self.save(update_fields=["task_id"])
def complete_job(self):
"""Report that the job has completed"""
@ -328,10 +327,12 @@ class ImportItem(models.Model):
)
@app.task(queue=LOW)
@app.task(queue=IMPORTS)
def start_import_task(job_id):
"""trigger the child tasks for each row"""
job = ImportJob.objects.get(id=job_id)
job.status = "active"
job.save(update_fields=["status"])
# don't start the job if it was stopped from the UI
if job.complete:
return
@ -345,7 +346,7 @@ def start_import_task(job_id):
job.save()
@app.task(queue=LOW)
@app.task(queue=IMPORTS)
def import_item_task(item_id):
"""resolve a row into a book"""
item = ImportItem.objects.get(id=item_id)

View file

@ -4,6 +4,7 @@ from django.db import models, transaction, IntegrityError
from django.db.models import Q
from bookwyrm import activitypub
from bookwyrm.tasks import HIGH
from .activitypub_mixin import ActivitypubMixin, ActivityMixin
from .activitypub_mixin import generate_activity
from .base_model import BookWyrmModel
@ -139,8 +140,9 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
)
super().save(*args, **kwargs)
# a local user is following a remote user
if broadcast and self.user_subject.local and not self.user_object.local:
self.broadcast(self.to_activity(), self.user_subject)
self.broadcast(self.to_activity(), self.user_subject, queue=HIGH)
if self.user_object.local:
manually_approves = self.user_object.manually_approves_followers
@ -157,13 +159,14 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
def accept(self, broadcast_only=False):
"""turn this request into the real deal"""
user = self.user_object
# broadcast when accepting a remote request
if not self.user_subject.local:
activity = activitypub.Accept(
id=self.get_accept_reject_id(status="accepts"),
actor=self.user_object.remote_id,
object=self.to_activity(),
).serialize()
self.broadcast(activity, user)
self.broadcast(activity, user, queue=HIGH)
if broadcast_only:
return
@ -180,7 +183,7 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
actor=self.user_object.remote_id,
object=self.to_activity(),
).serialize()
self.broadcast(activity, self.user_object)
self.broadcast(activity, self.user_object, queue=HIGH)
self.delete()

View file

@ -7,6 +7,7 @@ from django.utils import timezone
from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN
from bookwyrm.tasks import LOW
from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel
from . import fields
@ -39,9 +40,9 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
activity_serializer = activitypub.Shelf
def save(self, *args, **kwargs):
def save(self, *args, priority=LOW, **kwargs):
"""set the identifier"""
super().save(*args, **kwargs)
super().save(*args, priority=priority, **kwargs)
if not self.identifier:
self.identifier = self.get_identifier()
super().save(*args, **kwargs, broadcast=False)
@ -99,7 +100,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
activity_serializer = activitypub.ShelfItem
collection_field = "shelf"
def save(self, *args, **kwargs):
def save(self, *args, priority=LOW, **kwargs):
if not self.user:
self.user = self.shelf.user
if self.id and self.user.local:
@ -110,7 +111,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
for book in self.book.parent_work.editions.all()
]
)
super().save(*args, **kwargs)
super().save(*args, priority=priority, **kwargs)
def delete(self, *args, **kwargs):
if self.id and self.user.local:

View file

@ -526,6 +526,11 @@ def preview_image(instance, *args, **kwargs):
"""create preview images when user is updated"""
if not ENABLE_PREVIEW_IMAGES:
return
# don't call the task for remote users
if not instance.local:
return
changed_fields = instance.field_tracker.changed()
if len(changed_fields) > 0:

View file

@ -71,20 +71,29 @@ def get_wrapped_text(text, font, content_width):
low = 0
high = len(text)
draw = ImageDraw.Draw(Image.new("RGB", (100, 100)))
try:
# ideal length is determined via binary search
while low < high:
mid = math.floor(low + high)
wrapped_text = textwrap.fill(text, width=mid)
width = font.getsize_multiline(wrapped_text)[0]
left, top, right, bottom = draw.multiline_textbbox(
(0, 0), wrapped_text, font=font
)
width = right - left
height = bottom - top
if width < content_width:
low = mid
else:
high = mid - 1
except AttributeError:
wrapped_text = text
height = 26
return wrapped_text
return wrapped_text, height
def generate_texts_layer(texts, content_width):
@ -100,47 +109,53 @@ def generate_texts_layer(texts, content_width):
text_y = 0
if "text_zero" in texts and texts["text_zero"]:
# Text one (Book title)
text_zero = get_wrapped_text(texts["text_zero"], font_text_zero, content_width)
# Text zero (Site preview domain name)
text_zero, text_height = get_wrapped_text(
texts["text_zero"], font_text_zero, content_width
)
text_layer_draw.multiline_text(
(0, text_y), text_zero, font=font_text_zero, fill=TEXT_COLOR
)
try:
text_y = text_y + font_text_zero.getsize_multiline(text_zero)[1] + 16
text_y = text_y + text_height + 16
except (AttributeError, IndexError):
text_y = text_y + 26
if "text_one" in texts and texts["text_one"]:
# Text one (Book title)
text_one = get_wrapped_text(texts["text_one"], font_text_one, content_width)
# Text one (Book/Site title, User display name)
text_one, text_height = get_wrapped_text(
texts["text_one"], font_text_one, content_width
)
text_layer_draw.multiline_text(
(0, text_y), text_one, font=font_text_one, fill=TEXT_COLOR
)
try:
text_y = text_y + font_text_one.getsize_multiline(text_one)[1] + 16
text_y = text_y + text_height + 16
except (AttributeError, IndexError):
text_y = text_y + 26
if "text_two" in texts and texts["text_two"]:
# Text one (Book subtitle)
text_two = get_wrapped_text(texts["text_two"], font_text_two, content_width)
# Text two (Book subtitle)
text_two, text_height = get_wrapped_text(
texts["text_two"], font_text_two, content_width
)
text_layer_draw.multiline_text(
(0, text_y), text_two, font=font_text_two, fill=TEXT_COLOR
)
try:
text_y = text_y + font_text_one.getsize_multiline(text_two)[1] + 16
text_y = text_y + text_height + 16
except (AttributeError, IndexError):
text_y = text_y + 26
if "text_three" in texts and texts["text_three"]:
# Text three (Book authors)
text_three = get_wrapped_text(
# Text three (Book authors, Site tagline, User address)
text_three, _ = get_wrapped_text(
texts["text_three"], font_text_three, content_width
)
@ -172,7 +187,7 @@ def generate_instance_layer(content_width):
instance_text_x = 0
if logo_img:
logo_img.thumbnail((50, 50), Image.ANTIALIAS)
logo_img.thumbnail((50, 50), Image.Resampling.LANCZOS)
instance_layer.paste(logo_img, (0, 0))
@ -183,7 +198,7 @@ def generate_instance_layer(content_width):
(instance_text_x, 10), site.name, font=font_instance, fill=TEXT_COLOR
)
line_width = 50 + 10 + font_instance.getsize(site.name)[0]
line_width = 50 + 10 + round(font_instance.getlength(site.name))
line_layer = Image.new(
"RGBA", (line_width, 2), color=(*(ImageColor.getrgb(TEXT_COLOR)), 50)
@ -253,10 +268,12 @@ def generate_default_inner_img():
default_cover_draw = ImageDraw.Draw(default_cover)
text = "no image :("
text_dimensions = font_cover.getsize(text)
text_left, text_top, text_right, text_bottom = font_cover.getbbox(text)
text_width, text_height = text_right - text_left, text_bottom - text_top
text_coords = (
math.floor((inner_img_width - text_dimensions[0]) / 2),
math.floor((inner_img_height - text_dimensions[1]) / 2),
math.floor((inner_img_width - text_width) / 2),
math.floor((inner_img_height - text_height) / 2),
)
default_cover_draw.text(text_coords, text, font=font_cover, fill="white")
@ -273,7 +290,9 @@ def generate_preview_image(
# Cover
try:
inner_img_layer = Image.open(picture)
inner_img_layer.thumbnail((inner_img_width, inner_img_height), Image.ANTIALIAS)
inner_img_layer.thumbnail(
(inner_img_width, inner_img_height), Image.Resampling.LANCZOS
)
color_thief = ColorThief(picture)
dominant_color = color_thief.get_color(quality=1)
except: # pylint: disable=bare-except
@ -453,12 +472,15 @@ def generate_edition_preview_image_task(book_id):
@app.task(queue=LOW)
def generate_user_preview_image_task(user_id):
"""generate preview_image for a book"""
"""generate preview_image for a user"""
if not settings.ENABLE_PREVIEW_IMAGES:
return
user = models.User.objects.get(id=user_id)
if not user.local:
return
texts = {
"text_one": user.display_name,
"text_three": f"@{user.localname}@{settings.DOMAIN}",
@ -472,3 +494,25 @@ def generate_user_preview_image_task(user_id):
image = generate_preview_image(texts=texts, picture=avatar)
save_and_cleanup(image, instance=user)
@app.task(queue=LOW)
def remove_user_preview_image_task(user_id):
"""remove preview_image for a user"""
if not settings.ENABLE_PREVIEW_IMAGES:
return
user = models.User.objects.get(id=user_id)
try:
file_name = user.preview_image.name
except ValueError:
file_name = None
# Delete image in model
user.preview_image.delete(save=False)
user.save(broadcast=False, update_fields=["preview_image"])
# Delete image file
if file_name and default_storage.exists(file_name):
default_storage.delete(file_name)

View file

@ -193,7 +193,8 @@ STATICFILES_FINDERS = [
]
SASS_PROCESSOR_INCLUDE_FILE_PATTERN = r"^.+\.[s]{0,1}(?:a|c)ss$"
SASS_PROCESSOR_ENABLED = True
# when debug is disabled, make sure to compile themes once with `./bw-dev compile_themes`
SASS_PROCESSOR_ENABLED = DEBUG
# minify css is production but not dev
if not DEBUG:
@ -287,6 +288,7 @@ LANGUAGES = [
("ca-es", _("Català (Catalan)")),
("de-de", _("Deutsch (German)")),
("es-es", _("Español (Spanish)")),
("eu-es", _("Euskara (Basque)")),
("gl-es", _("Galego (Galician)")),
("it-it", _("Italiano (Italian)")),
("fi-fi", _("Suomi (Finnish)")),

View file

@ -17,7 +17,7 @@ def create_key_pair():
random_generator = Random.new().read
key = RSA.generate(1024, random_generator)
private_key = key.export_key().decode("utf8")
public_key = key.publickey().export_key().decode("utf8")
public_key = key.public_key().export_key().decode("utf8")
return private_key, public_key

View file

@ -1,3 +1,53 @@
.summary-on-open {
display: none;
}
@media only screen and (max-width: 768px) {
.navbar-menu {
text-align: right;
padding-right: 1rem;
.tags {
justify-content: flex-end;
}
#navbar-dropdown {
&[open] {
.summary-on-open {
display: initial;
position: fixed;
top: 0;
left: 0;
right: 0;
height: 3rem;
z-index: 31;
background-color: $dropdown-content-background-color;
padding: 1rem 1.75rem;
line-height: 1;
}
}
.dropdown-menu {
padding-top: 0;
top: 3rem;
}
.dropdown-content {
padding-top: 0;
box-shadow: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.navbar-item {
// see ../components/_details.scss :: Navbar details
padding-right: 1.75rem;
font-size: 1rem;
}
}
}
}
.image {
overflow: hidden;
}

View file

@ -46,4 +46,16 @@
document
.querySelectorAll("[data-remove]")
.forEach((node) => node.addEventListener("click", removeInput));
// Get the element, add a keypress listener...
document.getElementById("subjects").addEventListener("keypress", function (e) {
// e.target is the element where it listens!
// if e.target is input field within the "subjects" div, do stuff
if (e.target && e.target.nodeName == "INPUT") {
// Item found, prevent default
if (event.keyCode == 13) {
event.preventDefault();
}
}
});
})();

View file

@ -14,3 +14,5 @@ app = Celery(
LOW = "low_priority"
MEDIUM = "medium_priority"
HIGH = "high_priority"
# import items get their own queue because they're such a pain in the ass
IMPORTS = "imports"

View file

@ -10,8 +10,9 @@
{% endblock %}
{% block about_content %}
{% get_current_language as LANGUAGE_CODE %}
{# seven day cache #}
{% cache 604800 about_page_superlatives %}
{% cache 604800 about_page_superlatives LANGUAGE_CODE %}
{% get_book_superlatives as superlatives %}
<section class=" pb-4">

View file

@ -81,7 +81,7 @@
{% include 'snippets/form_errors.html' with errors_list=form.languages.errors id="desc_languages" %}
</div>
<div class="field">
<div class="field" id="subjects">
<label class="label" for="id_add_subjects">
{% trans "Subjects:" %}
</label>

View file

@ -4,17 +4,17 @@
{% with user_path=status.user.local_path username=status.user.display_name book_path=book.local_path book_title=book|book_title %}
{% if status.status_type == 'GeneratedNote' %}
{% if status.content == 'wants to read' %}
{% if status.content == 'wants to read' or status.content == '<p>wants to read</p>' %}
{% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> wants to read <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %}
{% endif %}
{% if status.content == 'finished reading' %}
{% if finished reading or status.content == '<p>finished reading</p>' %}
{% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> finished reading <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %}
{% endif %}
{% if status.content == 'started reading' %}
{% if started reading or status.content == '<p>started reading</p>' %}
{% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> started reading <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %}
@ -38,3 +38,4 @@
{% endif %}
{% endwith %}

View file

@ -41,7 +41,7 @@
</dl>
</div>
{% if not job.complete and show_progress %}
{% if job.status == "active" and show_progress %}
<div class="box is-processing">
<div class="block">
<span class="icon icon-spinner is-pulled-left" aria-hidden="true"></span>

View file

@ -10,7 +10,8 @@
</div>
{% get_current_language as LANGUAGE_CODE %}
{% cache 60 * 60 LANGUAGE_CODE %}
{# 1 hour cache #}
{% cache 3600 landing LANGUAGE_CODE %}
{% get_landing_books as books %}
<section class="tile is-ancestor">
<div class="tile is-vertical is-6">

View file

@ -74,7 +74,7 @@
</li>
</ul>
{% endif %}
{% if perms.edit_instance_settings %}
{% if perms.bookwyrm.edit_instance_settings %}
<h2 class="menu-label">{% trans "System" %}</h2>
<ul class="menu-list">
<li>

View file

@ -29,7 +29,7 @@
{% trans "Copy the theme file into the <code>bookwyrm/static/css/themes</code> directory on your server from the command line." %}
</li>
<li>
{% trans "Run <code>./bw-dev collectstatic</code>." %}
{% trans "Run <code>./bw-dev compile_themes</code> and <code>./bw-dev collectstatic</code>." %}
</li>
<li>
{% trans "Add the file name using the form below to make it available in the application interface." %}

View file

@ -4,8 +4,8 @@
{% spaceless %}
{% get_current_language as LANGUAGE_CODE %}
{# 6 month cache #}
{% cache 15552000 titleby LANGUAGE_CODE book.id %}
{# 10 second cache #}
{% cache 10 titleby LANGUAGE_CODE book.id %}
{% if book.authors.exists %}
{% blocktrans trimmed with path=book.local_path title=book|book_title %}

View file

@ -13,6 +13,10 @@
<span class="ml-2">{{ request.user.display_name }}</span>
</span>
<span class="icon icon-arrow-down is-hidden-mobile" aria-hidden="true"></span>
<span class="summary-on-open">
<span class="icon icon-arrow-left is-small" aria-hidden="true"></span>
{% trans "Back" %}
</span>
</summary>
<div class="dropdown-menu">

View file

@ -14,6 +14,7 @@ from bookwyrm.preview_images import (
generate_edition_preview_image_task,
generate_user_preview_image_task,
generate_preview_image,
remove_user_preview_image_task,
save_and_cleanup,
)
@ -46,6 +47,37 @@ class PreviewImages(TestCase):
),
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.remote_user_with_preview = models.User.objects.create_user(
"badger@your.domain.here",
"badger@badger.com",
"badgeword",
local=False,
remote_id="https://example.com/users/badger",
inbox="https://example.com/users/badger/inbox",
outbox="https://example.com/users/badger/outbox",
avatar=SimpleUploadedFile(
avatar_file,
open(avatar_file, "rb").read(),
content_type="image/jpeg",
),
)
self.work = models.Work.objects.create(title="Test Work")
self.edition = models.Edition.objects.create(
title="Example Edition",
@ -122,6 +154,14 @@ class PreviewImages(TestCase):
self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT
)
def test_remote_user_preview(self, *args, **kwargs):
"""a remote user doesnt get a user preview"""
generate_user_preview_image_task(self.remote_user.id)
self.remote_user.refresh_from_db()
self.assertFalse(self.remote_user.preview_image)
def test_generate_user_preview_images_task(self, *args, **kwargs):
"""test task's external calls"""
with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock:
@ -129,3 +169,11 @@ class PreviewImages(TestCase):
args = generate_mock.call_args.kwargs
self.assertEqual(args["texts"]["text_one"], "possum")
self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}")
def test_remove_user_preview_image_task(self, *args, **kwargs):
"""you can delete the preview image for a (remote) user"""
remove_user_preview_image_task(self.remote_user_with_preview.id)
self.remote_user_with_preview.refresh_from_db()
self.assertFalse(self.remote_user_with_preview.preview_image)

View file

@ -63,7 +63,7 @@ class TransactionInboxCreate(TransactionTestCase):
with patch("bookwyrm.activitystreams.add_status_task.apply_async") as mock:
views.inbox.activity_task(activity)
self.assertEqual(mock.call_count, 2)
self.assertEqual(mock.call_count, 0)
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")

12
bw-dev
View file

@ -92,6 +92,7 @@ case "$CMD" in
migrate
migrate django_celery_beat
initdb
runweb python manage.py compile_themes
runweb python manage.py collectstatic --no-input
admin_code
;;
@ -122,6 +123,9 @@ case "$CMD" in
prod_error
runweb pytest -n 3 --cov-report term-missing "$@"
;;
compile_themes)
runweb python manage.py compile_themes
;;
collectstatic)
runweb python manage.py collectstatic --no-input
;;
@ -138,6 +142,7 @@ case "$CMD" in
git checkout l10n_main locale/ca_ES
git checkout l10n_main locale/de_DE
git checkout l10n_main locale/es_ES
git checkout l10n_main locale/eu_ES
git checkout l10n_main locale/fi_FI
git checkout l10n_main locale/fr_FR
git checkout l10n_main locale/gl_ES
@ -203,6 +208,7 @@ case "$CMD" in
docker-compose build
# ./update.sh
runweb python manage.py migrate
runweb python manage.py compile_themes
runweb python manage.py collectstatic --no-input
docker-compose up -d
docker-compose restart web
@ -223,6 +229,9 @@ case "$CMD" in
generate_preview_images)
runweb python manage.py generate_preview_images "$@"
;;
remove_remote_user_preview_images)
runweb python manage.py remove_remote_user_preview_images
;;
copy_media_to_s3)
awscommand "bookwyrm_media_volume:/images"\
"s3 cp /images s3://${AWS_STORAGE_BUCKET_NAME}/images\
@ -256,6 +265,7 @@ case "$CMD" in
migrate
migrate django_celery_beat
initdb
runweb python manage.py compile_themes
runweb python manage.py collectstatic --no-input
admin_code
;;
@ -283,6 +293,7 @@ case "$CMD" in
echo " dbshell"
echo " restart_celery"
echo " pytest [path]"
echo " compile_themes"
echo " collectstatic"
echo " makemessages"
echo " compilemessages [locale]"
@ -300,6 +311,7 @@ case "$CMD" in
echo " populate_suggestions"
echo " generate_thumbnails"
echo " generate_preview_images [--all]"
echo " remove_remote_user_preview_images"
echo " copy_media_to_s3"
echo " sync_media_to_s3"
echo " set_cors_to_s3 [cors file]"

View file

@ -14,6 +14,7 @@ dbshell \
restart_celery \
pytest \
pytest_coverage_report \
compile_themes \
collectstatic \
makemessages \
compilemessages \
@ -31,6 +32,7 @@ populate_lists_streams \
populate_suggestions \
generate_thumbnails \
generate_preview_images \
remove_remote_user_preview_images \
copy_media_to_s3 \
set_cors_to_s3 \
setup \
@ -43,42 +45,44 @@ function __bw_complete -a cmds cmd desc
complete -f -c bw-dev -n "not __fish_seen_subcommand_from $cmds" -a $cmd -d $desc
end
__bw_complete "$commands" "up" "bring one or all service(s) up"
__bw_complete "$commands" "service_ports_web" "run command on the web container with its portsenabled and mapped"
__bw_complete "$commands" "initdb" "initialize database"
__bw_complete "$commands" "resetdb" "!! WARNING !! reset database"
__bw_complete "$commands" "makemigrations" "create new migrations"
__bw_complete "$commands" "migrate" "perform all migrations"
__bw_complete "$commands" "bash" "open up bash within the web container"
__bw_complete "$commands" "shell" "open the Python shell within the web container"
__bw_complete "$commands" "dbshell" "open the database shell within the web container"
__bw_complete "$commands" "restart_celery" "restart the celery container"
__bw_complete "$commands" "pytest" "run unit tests"
__bw_complete "$commands" "collectstatic" "copy changed static files into the installation"
__bw_complete "$commands" "makemessages" "extract all localizable messages from the code"
__bw_complete "$commands" "compilemessages" "compile .po localization files to .mo"
__bw_complete "$commands" "update_locales" "run makemessages and compilemessages for the en_US and additional locales"
__bw_complete "$commands" "build" "build the containers"
__bw_complete "$commands" "clean" "bring the cluster down and remove all containers"
__bw_complete "$commands" "black" "run Python code formatting tool"
__bw_complete "$commands" "prettier" "run JavaScript code formatting tool"
__bw_complete "$commands" "eslint" "run JavaScript linting tool"
__bw_complete "$commands" "stylelint" "run SCSS linting tool"
__bw_complete "$commands" "formatters" "run multiple formatter tools"
__bw_complete "$commands" "populate_streams" "populate the main streams"
__bw_complete "$commands" "populate_lists_streams" "populate streams for book lists"
__bw_complete "$commands" "populate_suggestions" "populate book suggestions"
__bw_complete "$commands" "generate_thumbnails" "generate book thumbnails"
__bw_complete "$commands" "generate_preview_images" "generate book preview images"
__bw_complete "$commands" "collectstatic_watch" "watch filesystem and copy changed static files"
__bw_complete "$commands" "copy_media_to_s3" "run the `s3 cp` command to copy media to a bucket on S3"
__bw_complete "$commands" "sync_media_to_s3" "run the `s3 sync` command to sync media with a bucket on S3"
__bw_complete "$commands" "set_cors_to_s3" "push a CORS configuration defined in .json to s3"
__bw_complete "$commands" "setup" "perform first-time setup"
__bw_complete "$commands" "admin_code" "get the admin code"
__bw_complete "$commands" "remove_2fa" "remove 2FA from user"
__bw_complete "$commands" "confirm_email" "manually confirm email of user and set active"
__bw_complete "$commands" "runweb" "run a command on the web container"
__bw_complete "$commands" "up" "bring one or all service(s) up"
__bw_complete "$commands" "service_ports_web" "run command on the web container with its portsenabled and mapped"
__bw_complete "$commands" "initdb" "initialize database"
__bw_complete "$commands" "resetdb" "!! WARNING !! reset database"
__bw_complete "$commands" "makemigrations" "create new migrations"
__bw_complete "$commands" "migrate" "perform all migrations"
__bw_complete "$commands" "bash" "open up bash within the web container"
__bw_complete "$commands" "shell" "open the Python shell within the web container"
__bw_complete "$commands" "dbshell" "open the database shell within the web container"
__bw_complete "$commands" "restart_celery" "restart the celery container"
__bw_complete "$commands" "pytest" "run unit tests"
__bw_complete "$commands" "compile_themes" "compile themes css files"
__bw_complete "$commands" "collectstatic" "copy changed static files into the installation"
__bw_complete "$commands" "makemessages" "extract all localizable messages from the code"
__bw_complete "$commands" "compilemessages" "compile .po localization files to .mo"
__bw_complete "$commands" "update_locales" "run makemessages and compilemessages for the en_US and additional locales"
__bw_complete "$commands" "build" "build the containers"
__bw_complete "$commands" "clean" "bring the cluster down and remove all containers"
__bw_complete "$commands" "black" "run Python code formatting tool"
__bw_complete "$commands" "prettier" "run JavaScript code formatting tool"
__bw_complete "$commands" "eslint" "run JavaScript linting tool"
__bw_complete "$commands" "stylelint" "run SCSS linting tool"
__bw_complete "$commands" "formatters" "run multiple formatter tools"
__bw_complete "$commands" "populate_streams" "populate the main streams"
__bw_complete "$commands" "populate_lists_streams" "populate streams for book lists"
__bw_complete "$commands" "populate_suggestions" "populate book suggestions"
__bw_complete "$commands" "generate_thumbnails" "generate book thumbnails"
__bw_complete "$commands" "generate_preview_images" "generate site/book/user preview images"
__bw_complete "$commands" "remove_remote_user_preview_images" "remove preview images for remote users"
__bw_complete "$commands" "collectstatic_watch" "watch filesystem and copy changed static files"
__bw_complete "$commands" "copy_media_to_s3" "run the `s3 cp` command to copy media to a bucket on S3"
__bw_complete "$commands" "sync_media_to_s3" "run the `s3 sync` command to sync media with a bucket on S3"
__bw_complete "$commands" "set_cors_to_s3" "push a CORS configuration defined in .json to s3"
__bw_complete "$commands" "setup" "perform first-time setup"
__bw_complete "$commands" "admin_code" "get the admin code"
__bw_complete "$commands" "remove_2fa" "remove 2FA from user"
__bw_complete "$commands" "confirm_email" "manually confirm email of user and set active"
__bw_complete "$commands" "runweb" "run a command on the web container"
function __bw_complete_subcommand -a cmd

View file

@ -11,6 +11,7 @@ dbshell
restart_celery
pytest
pytest_coverage_report
compile_themes
collectstatic
makemessages
compilemessages
@ -28,6 +29,7 @@ populate_lists_streams
populate_suggestions
generate_thumbnails
generate_preview_images
remove_remote_user_preview_images
copy_media_to_s3
set_cors_to_s3
setup

View file

@ -13,6 +13,7 @@ dbshell
restart_celery
pytest
pytest_coverage_report
compile_themes
collectstatic
makemessages
compilemessages
@ -30,6 +31,7 @@ populate_lists_streams
populate_suggestions
generate_thumbnails
generate_preview_images
remove_remote_user_preview_images
copy_media_to_s3
set_cors_to_s3
setup

View file

@ -62,7 +62,7 @@ services:
build: .
networks:
- main
command: celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority
command: celery -A celerywyrm worker -l info -Q high_priority,medium_priority,low_priority,imports
volumes:
- .:/app
- static_volume:/app/static

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-11 21:08+0000\n"
"POT-Creation-Date: 2022-12-21 17:58+0000\n"
"PO-Revision-Date: 2021-02-28 17:19-0800\n"
"Last-Translator: Mouse Reeve <mousereeve@riseup.net>\n"
"Language-Team: English <LL@li.org>\n"
@ -206,26 +206,26 @@ msgstr ""
msgid "Blocked"
msgstr ""
#: bookwyrm/models/fields.py:27
#: bookwyrm/models/fields.py:28
#, python-format
msgid "%(value)s is not a valid remote_id"
msgstr ""
#: bookwyrm/models/fields.py:36 bookwyrm/models/fields.py:45
#: bookwyrm/models/fields.py:37 bookwyrm/models/fields.py:46
#, python-format
msgid "%(value)s is not a valid username"
msgstr ""
#: bookwyrm/models/fields.py:181 bookwyrm/templates/layout.html:142
#: bookwyrm/models/fields.py:182 bookwyrm/templates/layout.html:142
#: bookwyrm/templates/ostatus/error.html:29
msgid "username"
msgstr ""
#: bookwyrm/models/fields.py:186
#: bookwyrm/models/fields.py:187
msgid "A user with that username already exists."
msgstr ""
#: bookwyrm/models/fields.py:205
#: bookwyrm/models/fields.py:206
#: bookwyrm/templates/snippets/privacy-icons.html:3
#: bookwyrm/templates/snippets/privacy-icons.html:4
#: bookwyrm/templates/snippets/privacy_select.html:11
@ -233,7 +233,7 @@ msgstr ""
msgid "Public"
msgstr ""
#: bookwyrm/models/fields.py:206
#: bookwyrm/models/fields.py:207
#: bookwyrm/templates/snippets/privacy-icons.html:7
#: bookwyrm/templates/snippets/privacy-icons.html:8
#: bookwyrm/templates/snippets/privacy_select.html:14
@ -241,14 +241,14 @@ msgstr ""
msgid "Unlisted"
msgstr ""
#: bookwyrm/models/fields.py:207
#: bookwyrm/models/fields.py:208
#: bookwyrm/templates/snippets/privacy_select.html:17
#: bookwyrm/templates/user/relationships/followers.html:6
#: bookwyrm/templates/user/relationships/layout.html:11
msgid "Followers"
msgstr ""
#: bookwyrm/models/fields.py:208
#: bookwyrm/models/fields.py:209
#: bookwyrm/templates/snippets/create_status/post_options_block.html:6
#: bookwyrm/templates/snippets/privacy-icons.html:15
#: bookwyrm/templates/snippets/privacy-icons.html:16
@ -272,15 +272,15 @@ msgstr ""
msgid "Stopped"
msgstr ""
#: bookwyrm/models/import_job.py:84 bookwyrm/models/import_job.py:92
#: bookwyrm/models/import_job.py:83 bookwyrm/models/import_job.py:91
msgid "Import stopped"
msgstr ""
#: bookwyrm/models/import_job.py:359 bookwyrm/models/import_job.py:384
#: bookwyrm/models/import_job.py:360 bookwyrm/models/import_job.py:385
msgid "Error loading book"
msgstr ""
#: bookwyrm/models/import_job.py:368
#: bookwyrm/models/import_job.py:369
msgid "Could not find a match for book"
msgstr ""
@ -317,19 +317,19 @@ msgstr ""
msgid "Everything else"
msgstr ""
#: bookwyrm/settings.py:213
#: bookwyrm/settings.py:214
msgid "Home Timeline"
msgstr ""
#: bookwyrm/settings.py:213
#: bookwyrm/settings.py:214
msgid "Home"
msgstr ""
#: bookwyrm/settings.py:214
#: bookwyrm/settings.py:215
msgid "Books Timeline"
msgstr ""
#: bookwyrm/settings.py:214
#: bookwyrm/settings.py:215
#: bookwyrm/templates/guided_tour/user_profile.html:101
#: bookwyrm/templates/search/layout.html:22
#: bookwyrm/templates/search/layout.html:43
@ -337,71 +337,71 @@ msgstr ""
msgid "Books"
msgstr ""
#: bookwyrm/settings.py:286
#: bookwyrm/settings.py:287
msgid "English"
msgstr ""
#: bookwyrm/settings.py:287
#: bookwyrm/settings.py:288
msgid "Català (Catalan)"
msgstr ""
#: bookwyrm/settings.py:288
#: bookwyrm/settings.py:289
msgid "Deutsch (German)"
msgstr ""
#: bookwyrm/settings.py:289
#: bookwyrm/settings.py:290
msgid "Español (Spanish)"
msgstr ""
#: bookwyrm/settings.py:290
#: bookwyrm/settings.py:291
msgid "Galego (Galician)"
msgstr ""
#: bookwyrm/settings.py:291
#: bookwyrm/settings.py:292
msgid "Italiano (Italian)"
msgstr ""
#: bookwyrm/settings.py:292
#: bookwyrm/settings.py:293
msgid "Suomi (Finnish)"
msgstr ""
#: bookwyrm/settings.py:293
#: bookwyrm/settings.py:294
msgid "Français (French)"
msgstr ""
#: bookwyrm/settings.py:294
#: bookwyrm/settings.py:295
msgid "Lietuvių (Lithuanian)"
msgstr ""
#: bookwyrm/settings.py:295
#: bookwyrm/settings.py:296
msgid "Norsk (Norwegian)"
msgstr ""
#: bookwyrm/settings.py:296
#: bookwyrm/settings.py:297
msgid "Polski (Polish)"
msgstr ""
#: bookwyrm/settings.py:297
#: bookwyrm/settings.py:298
msgid "Português do Brasil (Brazilian Portuguese)"
msgstr ""
#: bookwyrm/settings.py:298
#: bookwyrm/settings.py:299
msgid "Português Europeu (European Portuguese)"
msgstr ""
#: bookwyrm/settings.py:299
#: bookwyrm/settings.py:300
msgid "Română (Romanian)"
msgstr ""
#: bookwyrm/settings.py:300
#: bookwyrm/settings.py:301
msgid "Svenska (Swedish)"
msgstr ""
#: bookwyrm/settings.py:301
#: bookwyrm/settings.py:302
msgid "简体中文 (Simplified Chinese)"
msgstr ""
#: bookwyrm/settings.py:302
#: bookwyrm/settings.py:303
msgid "繁體中文 (Traditional Chinese)"
msgstr ""
@ -598,25 +598,25 @@ msgstr[1] ""
msgid "Thats great!"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:127
#: bookwyrm/templates/annual_summary/layout.html:128
#, python-format
msgid "That makes an average of %(pages)s pages per book."
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:132
#: bookwyrm/templates/annual_summary/layout.html:134
#, python-format
msgid "(%(no_page_number)s book doesnt have pages)"
msgid_plural "(%(no_page_number)s books dont have pages)"
msgid "(No page data was available for %(no_page_number)s book)"
msgid_plural "(No page data was available for %(no_page_number)s books)"
msgstr[0] ""
msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:148
#: bookwyrm/templates/annual_summary/layout.html:150
msgid "Their shortest read this year…"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:155
#: bookwyrm/templates/annual_summary/layout.html:176
#: bookwyrm/templates/annual_summary/layout.html:245
#: bookwyrm/templates/annual_summary/layout.html:157
#: bookwyrm/templates/annual_summary/layout.html:178
#: bookwyrm/templates/annual_summary/layout.html:247
#: bookwyrm/templates/book/book.html:56
#: bookwyrm/templates/discover/large-book.html:22
#: bookwyrm/templates/landing/large-book.html:26
@ -624,44 +624,44 @@ msgstr ""
msgid "by"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:161
#: bookwyrm/templates/annual_summary/layout.html:182
#: bookwyrm/templates/annual_summary/layout.html:163
#: bookwyrm/templates/annual_summary/layout.html:184
#, python-format
msgid "<strong>%(pages)s</strong> pages"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:169
#: bookwyrm/templates/annual_summary/layout.html:171
msgid "…and the longest"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:200
#: bookwyrm/templates/annual_summary/layout.html:202
#, python-format
msgid "%(display_name)s set a goal of reading %(goal)s book in %(year)s,<br /> and achieved %(goal_percent)s%% of that goal"
msgid_plural "%(display_name)s set a goal of reading %(goal)s books in %(year)s,<br /> and achieved %(goal_percent)s%% of that goal"
msgstr[0] ""
msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:209
#: bookwyrm/templates/annual_summary/layout.html:211
msgid "Way to go!"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:224
#: bookwyrm/templates/annual_summary/layout.html:226
#, python-format
msgid "%(display_name)s left %(ratings_total)s rating, <br />their average rating is %(rating_average)s"
msgid_plural "%(display_name)s left %(ratings_total)s ratings, <br />their average rating is %(rating_average)s"
msgstr[0] ""
msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:238
#: bookwyrm/templates/annual_summary/layout.html:240
msgid "Their best rated review"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:251
#: bookwyrm/templates/annual_summary/layout.html:253
#, python-format
msgid "Their rating: <strong>%(rating)s</strong>"
msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:268
#: bookwyrm/templates/annual_summary/layout.html:270
#, python-format
msgid "All the books %(display_name)s read in %(year)s"
msgstr ""
@ -5349,7 +5349,7 @@ msgid "Copy the theme file into the <code>bookwyrm/static/css/themes</code> dire
msgstr ""
#: bookwyrm/templates/settings/themes.html:32
msgid "Run <code>./bw-dev collectstatic</code>."
msgid "Run <code>./bw-dev compile_themes</code> and <code>./bw-dev collectstatic</code>."
msgstr ""
#: bookwyrm/templates/settings/themes.html:35
@ -6049,7 +6049,7 @@ msgstr ""
msgid "Choose wisely! Your username cannot be changed."
msgstr ""
#: bookwyrm/templates/snippets/register_form.html:64
#: bookwyrm/templates/snippets/register_form.html:66
msgid "Sign Up"
msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -19,52 +19,96 @@ server {
# return 301 https://your-domain.com$request_uri;
}
#
# server {
# listen [::]:443 ssl http2;
# listen 443 ssl http2;
#
# server_name your-domain.com;
#
# client_max_body_size 3M;
#
# if ($host != "your-domain.com") {
# return 301 $scheme://your-domain.com$request_uri;
# }
#
# # SSL code
# ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem;
# ssl_certificate_key /etc/nginx/ssl/live/your-domain.com/privkey.pem;
#
# location ~ /.well-known/acme-challenge {
# allow all;
# root /var/www/certbot;
# }
#
# location ~ ^/(login[^-/]|password-reset|resend-link|2fa-check) {
# limit_req zone=loginlimit;
#
# proxy_pass http://web;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $host;
# proxy_redirect off;
# }
#
# location / {
# proxy_pass http://web;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $host;
# proxy_redirect off;
# }
#
# location /images/ {
# alias /app/images/;
# }
#
# location /static/ {
# alias /app/static/;
# }
# }
server {
access_log /var/log/nginx/access.log cache_log;
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name your-domain.com;
client_max_body_size 3M;
if ($host != "your-domain.com") {
return 301 $scheme://your-domain.com$request_uri;
}
# SSL code
ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/your-domain.com/privkey.pem;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/certbot;
}
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
#include /etc/nginx/mime.types;
#default_type application/octet-stream;
gzip on;
gzip_disable "msie6";
proxy_read_timeout 1800s;
chunked_transfer_encoding on;
# store responses to anonymous users for up to 1 minute
proxy_cache bookwyrm_cache;
proxy_cache_valid any 1m;
add_header X-Cache-Status $upstream_cache_status;
# ignore the set cookie header when deciding to
# store a response in the cache
proxy_ignore_headers Cache-Control Set-Cookie Expires;
# PUT requests always bypass the cache
# logged in sessions also do not populate the cache
# to avoid serving personal data to anonymous users
proxy_cache_methods GET HEAD;
proxy_no_cache $cookie_sessionid;
proxy_cache_bypass $cookie_sessionid;
# tell the web container the address of the outside client
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
location ~ ^/(login[^-/]|password-reset|resend-link|2fa-check) {
limit_req zone=loginlimit;
proxy_pass http://web;
}
# do not log periodic polling requests from logged in users
location /api/updates/ {
access_log off;
proxy_pass http://web;
}
location / {
proxy_pass http://web;
}
# directly serve images and static files from the
# bookwyrm filesystem using sendfile.
# make the logs quieter by not reporting these requests
location ~ ^/(images|static)/ {
root /app;
try_files $uri =404;
add_header X-Cache-Status STATIC;
access_log off;
}
# monitor the celery queues with flower, no caching enabled
location /flower/ {
proxy_pass http://flower:8888;
proxy_cache_bypass 1;
}
}
# Reverse-Proxy server
# server {

View file

@ -1,26 +1,26 @@
aiohttp==3.8.1
aiohttp==3.8.3
bleach==5.0.1
celery==5.2.2
celery==5.2.7
colorthief==0.2.1
Django==3.2.16
django-celery-beat==2.2.1
django-compressor==2.4.1
django-celery-beat==2.4.0
django-compressor==4.1
django-imagekit==4.1.0
django-model-utils==4.0.0
django-sass-processor==1.0.1
environs==9.3.4
django-model-utils==4.2.0
django-sass-processor==1.2.2
environs==9.5.0
flower==1.2.0
libsass==0.21.0
libsass==0.22.0
Markdown==3.3.3
Pillow>=9.0.0
psycopg2==2.8.4
pycryptodome==3.9.4
python-dateutil==2.8.1
Pillow>=9.3.0
psycopg2==2.9.5
pycryptodome==3.16.0
python-dateutil==2.8.2
redis==3.4.1
requests==2.22.0
responses==0.10.14
pytz>=2021.1
boto3==1.17.88
requests==2.28.1
responses==0.22.0
pytz>=2022.7
boto3==1.26.32
django-storages==1.11.1
django-redis==5.2.0
opentelemetry-api==1.11.1