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_ACTIVITY_DB_INDEX=0
# Redis as celery broker # Redis as celery broker
REDIS_BROKER_HOST=redis_broker
REDIS_BROKER_PORT=6379 REDIS_BROKER_PORT=6379
REDIS_BROKER_PASSWORD=redispassword123 REDIS_BROKER_PASSWORD=redispassword123
# Optional, use a different redis database (defaults to 0) # 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( if instance.published_date < timezone.now() - timedelta(
days=1 days=1
) or instance.created_date < instance.published_date - 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 priority = LOW
add_status_task.apply_async( 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 """ """ database schema for info about authors """
import re import re
from django.contrib.postgres.indexes import GinIndex 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 django.db import models
from bookwyrm import activitypub from bookwyrm import activitypub
@ -37,16 +35,7 @@ class Author(BookDataModel):
bio = fields.HtmlField(null=True, blank=True) bio = fields.HtmlField(null=True, blank=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
"""clear related template caches""" """normalize isni format"""
# 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
if self.isni: if self.isni:
self.isni = re.sub(r"\s", "", 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.search import SearchVectorField
from django.contrib.postgres.indexes import GinIndex from django.contrib.postgres.indexes import GinIndex
from django.core.cache import cache 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 import models, transaction
from django.db.models import Prefetch from django.db.models import Prefetch
from django.dispatch import receiver from django.dispatch import receiver
@ -208,10 +207,6 @@ class Book(BookDataModel):
if not isinstance(self, Edition) and not isinstance(self, Work): if not isinstance(self, Edition) and not isinstance(self, Work):
raise ValueError("Books should be added as Editions or Works") 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) return super().save(*args, **kwargs)
def get_remote_id(self): def get_remote_id(self):

View file

@ -19,7 +19,7 @@ from bookwyrm.models import (
Review, Review,
ReviewRating, ReviewRating,
) )
from bookwyrm.tasks import app, LOW from bookwyrm.tasks import app, LOW, IMPORTS
from .fields import PrivacyLevels from .fields import PrivacyLevels
@ -74,8 +74,7 @@ class ImportJob(models.Model):
task = start_import_task.delay(self.id) task = start_import_task.delay(self.id)
self.task_id = task.id self.task_id = task.id
self.status = "active" self.save(update_fields=["task_id"])
self.save(update_fields=["status", "task_id"])
def complete_job(self): def complete_job(self):
"""Report that the job has completed""" """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): def start_import_task(job_id):
"""trigger the child tasks for each row""" """trigger the child tasks for each row"""
job = ImportJob.objects.get(id=job_id) 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 # don't start the job if it was stopped from the UI
if job.complete: if job.complete:
return return
@ -345,7 +346,7 @@ def start_import_task(job_id):
job.save() job.save()
@app.task(queue=LOW) @app.task(queue=IMPORTS)
def import_item_task(item_id): def import_item_task(item_id):
"""resolve a row into a book""" """resolve a row into a book"""
item = ImportItem.objects.get(id=item_id) 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 django.db.models import Q
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.tasks import HIGH
from .activitypub_mixin import ActivitypubMixin, ActivityMixin from .activitypub_mixin import ActivitypubMixin, ActivityMixin
from .activitypub_mixin import generate_activity from .activitypub_mixin import generate_activity
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
@ -139,8 +140,9 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
) )
super().save(*args, **kwargs) 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: 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: if self.user_object.local:
manually_approves = self.user_object.manually_approves_followers manually_approves = self.user_object.manually_approves_followers
@ -157,13 +159,14 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
def accept(self, broadcast_only=False): def accept(self, broadcast_only=False):
"""turn this request into the real deal""" """turn this request into the real deal"""
user = self.user_object user = self.user_object
# broadcast when accepting a remote request
if not self.user_subject.local: if not self.user_subject.local:
activity = activitypub.Accept( activity = activitypub.Accept(
id=self.get_accept_reject_id(status="accepts"), id=self.get_accept_reject_id(status="accepts"),
actor=self.user_object.remote_id, actor=self.user_object.remote_id,
object=self.to_activity(), object=self.to_activity(),
).serialize() ).serialize()
self.broadcast(activity, user) self.broadcast(activity, user, queue=HIGH)
if broadcast_only: if broadcast_only:
return return
@ -180,7 +183,7 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
actor=self.user_object.remote_id, actor=self.user_object.remote_id,
object=self.to_activity(), object=self.to_activity(),
).serialize() ).serialize()
self.broadcast(activity, self.user_object) self.broadcast(activity, self.user_object, queue=HIGH)
self.delete() self.delete()

View file

@ -7,6 +7,7 @@ from django.utils import timezone
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import DOMAIN
from bookwyrm.tasks import LOW
from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
from . import fields from . import fields
@ -39,9 +40,9 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
activity_serializer = activitypub.Shelf activity_serializer = activitypub.Shelf
def save(self, *args, **kwargs): def save(self, *args, priority=LOW, **kwargs):
"""set the identifier""" """set the identifier"""
super().save(*args, **kwargs) super().save(*args, priority=priority, **kwargs)
if not self.identifier: if not self.identifier:
self.identifier = self.get_identifier() self.identifier = self.get_identifier()
super().save(*args, **kwargs, broadcast=False) super().save(*args, **kwargs, broadcast=False)
@ -99,7 +100,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
activity_serializer = activitypub.ShelfItem activity_serializer = activitypub.ShelfItem
collection_field = "shelf" collection_field = "shelf"
def save(self, *args, **kwargs): def save(self, *args, priority=LOW, **kwargs):
if not self.user: if not self.user:
self.user = self.shelf.user self.user = self.shelf.user
if self.id and self.user.local: if self.id and self.user.local:
@ -110,7 +111,7 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
for book in self.book.parent_work.editions.all() for book in self.book.parent_work.editions.all()
] ]
) )
super().save(*args, **kwargs) super().save(*args, priority=priority, **kwargs)
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
if self.id and self.user.local: 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""" """create preview images when user is updated"""
if not ENABLE_PREVIEW_IMAGES: if not ENABLE_PREVIEW_IMAGES:
return return
# don't call the task for remote users
if not instance.local:
return
changed_fields = instance.field_tracker.changed() changed_fields = instance.field_tracker.changed()
if len(changed_fields) > 0: if len(changed_fields) > 0:

View file

@ -71,20 +71,29 @@ def get_wrapped_text(text, font, content_width):
low = 0 low = 0
high = len(text) high = len(text)
draw = ImageDraw.Draw(Image.new("RGB", (100, 100)))
try: try:
# ideal length is determined via binary search # ideal length is determined via binary search
while low < high: while low < high:
mid = math.floor(low + high) mid = math.floor(low + high)
wrapped_text = textwrap.fill(text, width=mid) 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: if width < content_width:
low = mid low = mid
else: else:
high = mid - 1 high = mid - 1
except AttributeError: except AttributeError:
wrapped_text = text wrapped_text = text
height = 26
return wrapped_text return wrapped_text, height
def generate_texts_layer(texts, content_width): def generate_texts_layer(texts, content_width):
@ -100,47 +109,53 @@ def generate_texts_layer(texts, content_width):
text_y = 0 text_y = 0
if "text_zero" in texts and texts["text_zero"]: if "text_zero" in texts and texts["text_zero"]:
# Text one (Book title) # Text zero (Site preview domain name)
text_zero = get_wrapped_text(texts["text_zero"], font_text_zero, content_width) text_zero, text_height = get_wrapped_text(
texts["text_zero"], font_text_zero, content_width
)
text_layer_draw.multiline_text( text_layer_draw.multiline_text(
(0, text_y), text_zero, font=font_text_zero, fill=TEXT_COLOR (0, text_y), text_zero, font=font_text_zero, fill=TEXT_COLOR
) )
try: try:
text_y = text_y + font_text_zero.getsize_multiline(text_zero)[1] + 16 text_y = text_y + text_height + 16
except (AttributeError, IndexError): except (AttributeError, IndexError):
text_y = text_y + 26 text_y = text_y + 26
if "text_one" in texts and texts["text_one"]: if "text_one" in texts and texts["text_one"]:
# Text one (Book title) # Text one (Book/Site title, User display name)
text_one = get_wrapped_text(texts["text_one"], font_text_one, content_width) text_one, text_height = get_wrapped_text(
texts["text_one"], font_text_one, content_width
)
text_layer_draw.multiline_text( text_layer_draw.multiline_text(
(0, text_y), text_one, font=font_text_one, fill=TEXT_COLOR (0, text_y), text_one, font=font_text_one, fill=TEXT_COLOR
) )
try: try:
text_y = text_y + font_text_one.getsize_multiline(text_one)[1] + 16 text_y = text_y + text_height + 16
except (AttributeError, IndexError): except (AttributeError, IndexError):
text_y = text_y + 26 text_y = text_y + 26
if "text_two" in texts and texts["text_two"]: if "text_two" in texts and texts["text_two"]:
# Text one (Book subtitle) # Text two (Book subtitle)
text_two = get_wrapped_text(texts["text_two"], font_text_two, content_width) text_two, text_height = get_wrapped_text(
texts["text_two"], font_text_two, content_width
)
text_layer_draw.multiline_text( text_layer_draw.multiline_text(
(0, text_y), text_two, font=font_text_two, fill=TEXT_COLOR (0, text_y), text_two, font=font_text_two, fill=TEXT_COLOR
) )
try: try:
text_y = text_y + font_text_one.getsize_multiline(text_two)[1] + 16 text_y = text_y + text_height + 16
except (AttributeError, IndexError): except (AttributeError, IndexError):
text_y = text_y + 26 text_y = text_y + 26
if "text_three" in texts and texts["text_three"]: if "text_three" in texts and texts["text_three"]:
# Text three (Book authors) # Text three (Book authors, Site tagline, User address)
text_three = get_wrapped_text( text_three, _ = get_wrapped_text(
texts["text_three"], font_text_three, content_width texts["text_three"], font_text_three, content_width
) )
@ -172,7 +187,7 @@ def generate_instance_layer(content_width):
instance_text_x = 0 instance_text_x = 0
if logo_img: 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)) 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 (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( line_layer = Image.new(
"RGBA", (line_width, 2), color=(*(ImageColor.getrgb(TEXT_COLOR)), 50) "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) default_cover_draw = ImageDraw.Draw(default_cover)
text = "no image :(" 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 = ( text_coords = (
math.floor((inner_img_width - text_dimensions[0]) / 2), math.floor((inner_img_width - text_width) / 2),
math.floor((inner_img_height - text_dimensions[1]) / 2), math.floor((inner_img_height - text_height) / 2),
) )
default_cover_draw.text(text_coords, text, font=font_cover, fill="white") default_cover_draw.text(text_coords, text, font=font_cover, fill="white")
@ -273,7 +290,9 @@ def generate_preview_image(
# Cover # Cover
try: try:
inner_img_layer = Image.open(picture) 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) color_thief = ColorThief(picture)
dominant_color = color_thief.get_color(quality=1) dominant_color = color_thief.get_color(quality=1)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
@ -453,12 +472,15 @@ def generate_edition_preview_image_task(book_id):
@app.task(queue=LOW) @app.task(queue=LOW)
def generate_user_preview_image_task(user_id): 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: if not settings.ENABLE_PREVIEW_IMAGES:
return return
user = models.User.objects.get(id=user_id) user = models.User.objects.get(id=user_id)
if not user.local:
return
texts = { texts = {
"text_one": user.display_name, "text_one": user.display_name,
"text_three": f"@{user.localname}@{settings.DOMAIN}", "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) image = generate_preview_image(texts=texts, picture=avatar)
save_and_cleanup(image, instance=user) 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_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 # minify css is production but not dev
if not DEBUG: if not DEBUG:
@ -287,6 +288,7 @@ LANGUAGES = [
("ca-es", _("Català (Catalan)")), ("ca-es", _("Català (Catalan)")),
("de-de", _("Deutsch (German)")), ("de-de", _("Deutsch (German)")),
("es-es", _("Español (Spanish)")), ("es-es", _("Español (Spanish)")),
("eu-es", _("Euskara (Basque)")),
("gl-es", _("Galego (Galician)")), ("gl-es", _("Galego (Galician)")),
("it-it", _("Italiano (Italian)")), ("it-it", _("Italiano (Italian)")),
("fi-fi", _("Suomi (Finnish)")), ("fi-fi", _("Suomi (Finnish)")),

View file

@ -17,7 +17,7 @@ def create_key_pair():
random_generator = Random.new().read random_generator = Random.new().read
key = RSA.generate(1024, random_generator) key = RSA.generate(1024, random_generator)
private_key = key.export_key().decode("utf8") 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 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 { .image {
overflow: hidden; overflow: hidden;
} }

View file

@ -46,4 +46,16 @@
document document
.querySelectorAll("[data-remove]") .querySelectorAll("[data-remove]")
.forEach((node) => node.addEventListener("click", removeInput)); .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" LOW = "low_priority"
MEDIUM = "medium_priority" MEDIUM = "medium_priority"
HIGH = "high_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 %} {% endblock %}
{% block about_content %} {% block about_content %}
{% get_current_language as LANGUAGE_CODE %}
{# seven day cache #} {# seven day cache #}
{% cache 604800 about_page_superlatives %} {% cache 604800 about_page_superlatives LANGUAGE_CODE %}
{% get_book_superlatives as superlatives %} {% get_book_superlatives as superlatives %}
<section class=" pb-4"> <section class=" pb-4">

View file

@ -81,7 +81,7 @@
{% include 'snippets/form_errors.html' with errors_list=form.languages.errors id="desc_languages" %} {% include 'snippets/form_errors.html' with errors_list=form.languages.errors id="desc_languages" %}
</div> </div>
<div class="field"> <div class="field" id="subjects">
<label class="label" for="id_add_subjects"> <label class="label" for="id_add_subjects">
{% trans "Subjects:" %} {% trans "Subjects:" %}
</label> </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 %} {% 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.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 %} {% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> wants to read <a href="{{ book_path }}">{{ book_title }}</a> <a href="{{ user_path}}">{{ username }}</a> wants to read <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %} {% endblocktrans %}
{% endif %} {% endif %}
{% if status.content == 'finished reading' %} {% if finished reading or status.content == '<p>finished reading</p>' %}
{% blocktrans trimmed %} {% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> finished reading <a href="{{ book_path }}">{{ book_title }}</a> <a href="{{ user_path}}">{{ username }}</a> finished reading <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %} {% endblocktrans %}
{% endif %} {% endif %}
{% if status.content == 'started reading' %} {% if started reading or status.content == '<p>started reading</p>' %}
{% blocktrans trimmed %} {% blocktrans trimmed %}
<a href="{{ user_path}}">{{ username }}</a> started reading <a href="{{ book_path }}">{{ book_title }}</a> <a href="{{ user_path}}">{{ username }}</a> started reading <a href="{{ book_path }}">{{ book_title }}</a>
{% endblocktrans %} {% endblocktrans %}
@ -38,3 +38,4 @@
{% endif %} {% endif %}
{% endwith %} {% endwith %}

View file

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

View file

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

View file

@ -74,7 +74,7 @@
</li> </li>
</ul> </ul>
{% endif %} {% endif %}
{% if perms.edit_instance_settings %} {% if perms.bookwyrm.edit_instance_settings %}
<h2 class="menu-label">{% trans "System" %}</h2> <h2 class="menu-label">{% trans "System" %}</h2>
<ul class="menu-list"> <ul class="menu-list">
<li> <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." %} {% trans "Copy the theme file into the <code>bookwyrm/static/css/themes</code> directory on your server from the command line." %}
</li> </li>
<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>
<li> <li>
{% trans "Add the file name using the form below to make it available in the application interface." %} {% trans "Add the file name using the form below to make it available in the application interface." %}

View file

@ -4,8 +4,8 @@
{% spaceless %} {% spaceless %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{# 6 month cache #} {# 10 second cache #}
{% cache 15552000 titleby LANGUAGE_CODE book.id %} {% cache 10 titleby LANGUAGE_CODE book.id %}
{% if book.authors.exists %} {% if book.authors.exists %}
{% blocktrans trimmed with path=book.local_path title=book|book_title %} {% 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 class="ml-2">{{ request.user.display_name }}</span>
</span> </span>
<span class="icon icon-arrow-down is-hidden-mobile" aria-hidden="true"></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> </summary>
<div class="dropdown-menu"> <div class="dropdown-menu">

View file

@ -14,6 +14,7 @@ from bookwyrm.preview_images import (
generate_edition_preview_image_task, generate_edition_preview_image_task,
generate_user_preview_image_task, generate_user_preview_image_task,
generate_preview_image, generate_preview_image,
remove_user_preview_image_task,
save_and_cleanup, 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.work = models.Work.objects.create(title="Test Work")
self.edition = models.Edition.objects.create( self.edition = models.Edition.objects.create(
title="Example Edition", title="Example Edition",
@ -122,6 +154,14 @@ class PreviewImages(TestCase):
self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT 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): def test_generate_user_preview_images_task(self, *args, **kwargs):
"""test task's external calls""" """test task's external calls"""
with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock: with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock:
@ -129,3 +169,11 @@ class PreviewImages(TestCase):
args = generate_mock.call_args.kwargs args = generate_mock.call_args.kwargs
self.assertEqual(args["texts"]["text_one"], "possum") self.assertEqual(args["texts"]["text_one"], "possum")
self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}") 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: with patch("bookwyrm.activitystreams.add_status_task.apply_async") as mock:
views.inbox.activity_task(activity) 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") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async")

12
bw-dev
View file

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

View file

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

View file

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

View file

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

View file

@ -62,7 +62,7 @@ services:
build: . build: .
networks: networks:
- main - 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: volumes:
- .:/app - .:/app
- static_volume:/app/static - 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 "" msgstr ""
"Project-Id-Version: 0.0.1\n" "Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: 2021-02-28 17:19-0800\n"
"Last-Translator: Mouse Reeve <mousereeve@riseup.net>\n" "Last-Translator: Mouse Reeve <mousereeve@riseup.net>\n"
"Language-Team: English <LL@li.org>\n" "Language-Team: English <LL@li.org>\n"
@ -206,26 +206,26 @@ msgstr ""
msgid "Blocked" msgid "Blocked"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:27 #: bookwyrm/models/fields.py:28
#, python-format #, python-format
msgid "%(value)s is not a valid remote_id" msgid "%(value)s is not a valid remote_id"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:36 bookwyrm/models/fields.py:45 #: bookwyrm/models/fields.py:37 bookwyrm/models/fields.py:46
#, python-format #, python-format
msgid "%(value)s is not a valid username" msgid "%(value)s is not a valid username"
msgstr "" 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 #: bookwyrm/templates/ostatus/error.html:29
msgid "username" msgid "username"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:186 #: bookwyrm/models/fields.py:187
msgid "A user with that username already exists." msgid "A user with that username already exists."
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:205 #: bookwyrm/models/fields.py:206
#: bookwyrm/templates/snippets/privacy-icons.html:3 #: bookwyrm/templates/snippets/privacy-icons.html:3
#: bookwyrm/templates/snippets/privacy-icons.html:4 #: bookwyrm/templates/snippets/privacy-icons.html:4
#: bookwyrm/templates/snippets/privacy_select.html:11 #: bookwyrm/templates/snippets/privacy_select.html:11
@ -233,7 +233,7 @@ msgstr ""
msgid "Public" msgid "Public"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:206 #: bookwyrm/models/fields.py:207
#: bookwyrm/templates/snippets/privacy-icons.html:7 #: bookwyrm/templates/snippets/privacy-icons.html:7
#: bookwyrm/templates/snippets/privacy-icons.html:8 #: bookwyrm/templates/snippets/privacy-icons.html:8
#: bookwyrm/templates/snippets/privacy_select.html:14 #: bookwyrm/templates/snippets/privacy_select.html:14
@ -241,14 +241,14 @@ msgstr ""
msgid "Unlisted" msgid "Unlisted"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:207 #: bookwyrm/models/fields.py:208
#: bookwyrm/templates/snippets/privacy_select.html:17 #: bookwyrm/templates/snippets/privacy_select.html:17
#: bookwyrm/templates/user/relationships/followers.html:6 #: bookwyrm/templates/user/relationships/followers.html:6
#: bookwyrm/templates/user/relationships/layout.html:11 #: bookwyrm/templates/user/relationships/layout.html:11
msgid "Followers" msgid "Followers"
msgstr "" msgstr ""
#: bookwyrm/models/fields.py:208 #: bookwyrm/models/fields.py:209
#: bookwyrm/templates/snippets/create_status/post_options_block.html:6 #: bookwyrm/templates/snippets/create_status/post_options_block.html:6
#: bookwyrm/templates/snippets/privacy-icons.html:15 #: bookwyrm/templates/snippets/privacy-icons.html:15
#: bookwyrm/templates/snippets/privacy-icons.html:16 #: bookwyrm/templates/snippets/privacy-icons.html:16
@ -272,15 +272,15 @@ msgstr ""
msgid "Stopped" msgid "Stopped"
msgstr "" 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" msgid "Import stopped"
msgstr "" 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" msgid "Error loading book"
msgstr "" msgstr ""
#: bookwyrm/models/import_job.py:368 #: bookwyrm/models/import_job.py:369
msgid "Could not find a match for book" msgid "Could not find a match for book"
msgstr "" msgstr ""
@ -317,19 +317,19 @@ msgstr ""
msgid "Everything else" msgid "Everything else"
msgstr "" msgstr ""
#: bookwyrm/settings.py:213 #: bookwyrm/settings.py:214
msgid "Home Timeline" msgid "Home Timeline"
msgstr "" msgstr ""
#: bookwyrm/settings.py:213 #: bookwyrm/settings.py:214
msgid "Home" msgid "Home"
msgstr "" msgstr ""
#: bookwyrm/settings.py:214 #: bookwyrm/settings.py:215
msgid "Books Timeline" msgid "Books Timeline"
msgstr "" msgstr ""
#: bookwyrm/settings.py:214 #: bookwyrm/settings.py:215
#: bookwyrm/templates/guided_tour/user_profile.html:101 #: bookwyrm/templates/guided_tour/user_profile.html:101
#: bookwyrm/templates/search/layout.html:22 #: bookwyrm/templates/search/layout.html:22
#: bookwyrm/templates/search/layout.html:43 #: bookwyrm/templates/search/layout.html:43
@ -337,71 +337,71 @@ msgstr ""
msgid "Books" msgid "Books"
msgstr "" msgstr ""
#: bookwyrm/settings.py:286 #: bookwyrm/settings.py:287
msgid "English" msgid "English"
msgstr "" msgstr ""
#: bookwyrm/settings.py:287 #: bookwyrm/settings.py:288
msgid "Català (Catalan)" msgid "Català (Catalan)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:288 #: bookwyrm/settings.py:289
msgid "Deutsch (German)" msgid "Deutsch (German)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:289 #: bookwyrm/settings.py:290
msgid "Español (Spanish)" msgid "Español (Spanish)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:290 #: bookwyrm/settings.py:291
msgid "Galego (Galician)" msgid "Galego (Galician)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:291 #: bookwyrm/settings.py:292
msgid "Italiano (Italian)" msgid "Italiano (Italian)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:292 #: bookwyrm/settings.py:293
msgid "Suomi (Finnish)" msgid "Suomi (Finnish)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:293 #: bookwyrm/settings.py:294
msgid "Français (French)" msgid "Français (French)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:294 #: bookwyrm/settings.py:295
msgid "Lietuvių (Lithuanian)" msgid "Lietuvių (Lithuanian)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:295 #: bookwyrm/settings.py:296
msgid "Norsk (Norwegian)" msgid "Norsk (Norwegian)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:296 #: bookwyrm/settings.py:297
msgid "Polski (Polish)" msgid "Polski (Polish)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:297 #: bookwyrm/settings.py:298
msgid "Português do Brasil (Brazilian Portuguese)" msgid "Português do Brasil (Brazilian Portuguese)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:298 #: bookwyrm/settings.py:299
msgid "Português Europeu (European Portuguese)" msgid "Português Europeu (European Portuguese)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:299 #: bookwyrm/settings.py:300
msgid "Română (Romanian)" msgid "Română (Romanian)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:300 #: bookwyrm/settings.py:301
msgid "Svenska (Swedish)" msgid "Svenska (Swedish)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:301 #: bookwyrm/settings.py:302
msgid "简体中文 (Simplified Chinese)" msgid "简体中文 (Simplified Chinese)"
msgstr "" msgstr ""
#: bookwyrm/settings.py:302 #: bookwyrm/settings.py:303
msgid "繁體中文 (Traditional Chinese)" msgid "繁體中文 (Traditional Chinese)"
msgstr "" msgstr ""
@ -598,25 +598,25 @@ msgstr[1] ""
msgid "Thats great!" msgid "Thats great!"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:127 #: bookwyrm/templates/annual_summary/layout.html:128
#, python-format #, python-format
msgid "That makes an average of %(pages)s pages per book." msgid "That makes an average of %(pages)s pages per book."
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:132 #: bookwyrm/templates/annual_summary/layout.html:134
#, python-format #, python-format
msgid "(%(no_page_number)s book doesnt have pages)" msgid "(No page data was available for %(no_page_number)s book)"
msgid_plural "(%(no_page_number)s books dont have pages)" msgid_plural "(No page data was available for %(no_page_number)s books)"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:148 #: bookwyrm/templates/annual_summary/layout.html:150
msgid "Their shortest read this year…" msgid "Their shortest read this year…"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:155 #: bookwyrm/templates/annual_summary/layout.html:157
#: bookwyrm/templates/annual_summary/layout.html:176 #: bookwyrm/templates/annual_summary/layout.html:178
#: bookwyrm/templates/annual_summary/layout.html:245 #: bookwyrm/templates/annual_summary/layout.html:247
#: bookwyrm/templates/book/book.html:56 #: bookwyrm/templates/book/book.html:56
#: bookwyrm/templates/discover/large-book.html:22 #: bookwyrm/templates/discover/large-book.html:22
#: bookwyrm/templates/landing/large-book.html:26 #: bookwyrm/templates/landing/large-book.html:26
@ -624,44 +624,44 @@ msgstr ""
msgid "by" msgid "by"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:161 #: bookwyrm/templates/annual_summary/layout.html:163
#: bookwyrm/templates/annual_summary/layout.html:182 #: bookwyrm/templates/annual_summary/layout.html:184
#, python-format #, python-format
msgid "<strong>%(pages)s</strong> pages" msgid "<strong>%(pages)s</strong> pages"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:169 #: bookwyrm/templates/annual_summary/layout.html:171
msgid "…and the longest" msgid "…and the longest"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:200 #: bookwyrm/templates/annual_summary/layout.html:202
#, python-format #, 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 "%(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" 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[0] ""
msgstr[1] "" msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:209 #: bookwyrm/templates/annual_summary/layout.html:211
msgid "Way to go!" msgid "Way to go!"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:224 #: bookwyrm/templates/annual_summary/layout.html:226
#, python-format #, python-format
msgid "%(display_name)s left %(ratings_total)s rating, <br />their average rating is %(rating_average)s" 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" msgid_plural "%(display_name)s left %(ratings_total)s ratings, <br />their average rating is %(rating_average)s"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: bookwyrm/templates/annual_summary/layout.html:238 #: bookwyrm/templates/annual_summary/layout.html:240
msgid "Their best rated review" msgid "Their best rated review"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:251 #: bookwyrm/templates/annual_summary/layout.html:253
#, python-format #, python-format
msgid "Their rating: <strong>%(rating)s</strong>" msgid "Their rating: <strong>%(rating)s</strong>"
msgstr "" msgstr ""
#: bookwyrm/templates/annual_summary/layout.html:268 #: bookwyrm/templates/annual_summary/layout.html:270
#, python-format #, python-format
msgid "All the books %(display_name)s read in %(year)s" msgid "All the books %(display_name)s read in %(year)s"
msgstr "" msgstr ""
@ -5349,7 +5349,7 @@ msgid "Copy the theme file into the <code>bookwyrm/static/css/themes</code> dire
msgstr "" msgstr ""
#: bookwyrm/templates/settings/themes.html:32 #: 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 "" msgstr ""
#: bookwyrm/templates/settings/themes.html:35 #: bookwyrm/templates/settings/themes.html:35
@ -6049,7 +6049,7 @@ msgstr ""
msgid "Choose wisely! Your username cannot be changed." msgid "Choose wisely! Your username cannot be changed."
msgstr "" msgstr ""
#: bookwyrm/templates/snippets/register_form.html:64 #: bookwyrm/templates/snippets/register_form.html:66
msgid "Sign Up" msgid "Sign Up"
msgstr "" 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; # return 301 https://your-domain.com$request_uri;
} }
#
# server { server {
# listen [::]:443 ssl http2; access_log /var/log/nginx/access.log cache_log;
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name your-domain.com; listen 443 ssl http2;
#
# client_max_body_size 3M; server_name your-domain.com;
#
# if ($host != "your-domain.com") { client_max_body_size 3M;
# return 301 $scheme://your-domain.com$request_uri;
# } 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; # SSL code
# ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem;
# location ~ /.well-known/acme-challenge { ssl_certificate_key /etc/nginx/ssl/live/your-domain.com/privkey.pem;
# allow all;
# root /var/www/certbot; location ~ /.well-known/acme-challenge {
# } allow all;
# root /var/www/certbot;
# location ~ ^/(login[^-/]|password-reset|resend-link|2fa-check) { }
# limit_req zone=loginlimit;
# sendfile on;
# proxy_pass http://web; tcp_nopush on;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; tcp_nodelay on;
# proxy_set_header Host $host; keepalive_timeout 65;
# proxy_redirect off; types_hash_max_size 2048;
# } #include /etc/nginx/mime.types;
# #default_type application/octet-stream;
# location / {
# proxy_pass http://web; gzip on;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; gzip_disable "msie6";
# proxy_set_header Host $host;
# proxy_redirect off; proxy_read_timeout 1800s;
# } chunked_transfer_encoding on;
#
# location /images/ { # store responses to anonymous users for up to 1 minute
# alias /app/images/; proxy_cache bookwyrm_cache;
# } proxy_cache_valid any 1m;
# add_header X-Cache-Status $upstream_cache_status;
# location /static/ {
# alias /app/static/; # 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 # Reverse-Proxy server
# server { # server {

View file

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