# HG changeset patch # User ymh # Date 1472480356 -7200 # Node ID c1d03ab4baad5e687c6af60c63052ae29c1d313a # Parent 79b70254a5e0279036a67888c803b72d90c850b1 prepare for publication diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/management/commands/importimages.py --- a/src/iconolab/management/commands/importimages.py Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/management/commands/importimages.py Mon Aug 29 16:19:16 2016 +0200 @@ -8,15 +8,22 @@ class Command(BaseCommand): help = "import images from a directory into the media folder and creates item and image objects" - + def add_arguments(self, parser): parser.add_argument("csv_path") parser.add_argument( + '--jpeg-quality', + dest='jpeg_quality', + default=settings.IMG_JPG_DEFAULT_QUALITY, + help='Jpeg default quality' + + ) + parser.add_argument( '--encoding', dest='encoding', default='utf-8', help='CSV file encoding' - + ) parser.add_argument( '--collection-fixture', @@ -36,7 +43,13 @@ default=False, help='add metacategories to the created collection from a fixture file', ) - + parser.add_argument( + '--delimiter', + dest='csv_delimiter', + default=';', + help='csv file delimiter' + ) + def handle(self, *args, **options): pp = pprint.PrettyPrinter(indent=4) try: @@ -57,7 +70,7 @@ if collection_data[0]["model"] != "iconolab.Collection": raise ValueError("!!! Collection fixture should provide one iconolab.Collection object and nothing else. !!!") except ValueError as e: - raise ValueError("!!! JSON Data is invalid. !!!") + raise ValueError("!!! JSON Data is invalid. !!!") elif options.get("collection_id"): print("## Finding collection with id "+options.get("collection_id")) try: @@ -65,8 +78,8 @@ except Collection.DoesNotExist: raise ValueError("!!! Collection with primary key "+options.get("collection_id")+" was not found, aborting !!!") else: - raise ValueError("!!! No collection fixture or collection id, aborting because we can't properly generate data. !!!") - + raise ValueError("!!! No collection fixture or collection id, aborting because we can't properly generate data. !!!") + if options.get("metacategories_fixture"): print("## Finding metacategories fixture json data in "+source_dir) metacategories_fixture_path = os.path.join(source_dir, options.get("metacategories_fixture")) @@ -81,9 +94,9 @@ raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!") elif options.get("collection_id") and metacategory["fields"].get("collection", False) != collection.id: raise ValueError("!!! The fixture should only contain metacategories for the imported collection !!!") - + # We read the csv - csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), delimiter=";") + csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), delimiter=options.get('csv_delimiter', ';')) print("# Extracting data from csv file and storing it in standardized format") # We store data using the Jocondelab keys, as defined in settings.IMPORT_FIELDS_DICT cleaned_csv_data=[] @@ -96,7 +109,7 @@ cleaned_row_data[key] = row[row_key] break cleaned_csv_data.append(cleaned_row_data) - + print("# Finding corresponding images and filtering csv data for found images") # Listing image files in csv directory image_list = [f for f in os.listdir(source_dir) if os.path.isfile(os.path.join(source_dir, f)) and not f.endswith(".csv")] @@ -128,7 +141,7 @@ col_im = ImagePIL.open(os.path.join(source_dir, collection_image_name)) print("##### Generating or copying jpeg for "+collection_image_name) col_im.thumbnail(col_im.size) - col_im.save(collection_image_path, "JPEG", quality=100) + col_im.save(collection_image_path, "JPEG", quality=options.get("jpeg_quality", settings.IMG_JPG_DEFAULT_QUALITY)) except Exception as e: print(e) if options.get("metacategories_fixture"): @@ -138,6 +151,9 @@ print("### Images will be stored in "+target_dir) for item in filtered_csv_data: print("#### Computing metadatas for item "+item["INV"]+" (inv number)") + if not item["INV"]: + print("#### No INV number, skipping") + continue item_authors = item["AUTR"] item_school = item["ECOLE"] item_designation = "" @@ -195,16 +211,18 @@ im_width, im_height = im.size except Exception as e: print(e) + continue else: jpeg_img_path = image_path try: im = ImagePIL.open(os.path.join(source_dir, image)) print("##### Generating or copying jpeg for "+image) im.thumbnail(im.size) - im.save(jpeg_img_path, "JPEG", quality=100) + im.save(jpeg_img_path, "JPEG", quality=options.get("jpeg_quality", settings.IMG_JPG_DEFAULT_QUALITY)) im_width, im_height = im.size except Exception as e: print(e) + continue new_image = Image.objects.create( item = item_object, media = "uploads/"+image_name+".jpg", @@ -220,4 +238,3 @@ print("!!! File "+options.get("csv_path")+" does not exist. !!!") except ValueError as e: print(str(e)) - \ No newline at end of file diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/settings/__init__.py --- a/src/iconolab/settings/__init__.py Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/settings/__init__.py Mon Aug 29 16:19:16 2016 +0200 @@ -10,7 +10,7 @@ https://docs.djangoproject.com/en/1.9/ref/settings/ """ -import os, logging +import os, logging, sys # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -223,3 +223,7 @@ } NO_IMG_CONVERSION_EXTS = [".jpg"] IMG_CONVERSION_EXTS = [".tif", ".tiff"] + +IMG_JPG_DEFAULT_QUALITY = 80 + +DJANGO_RUNSERVER = (sys.argv[1] == 'runserver') diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/settings/dev.py.tmpl --- a/src/iconolab/settings/dev.py.tmpl Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/settings/dev.py.tmpl Mon Aug 29 16:19:16 2016 +0200 @@ -1,266 +1,250 @@ -""" -Django settings for iconolab project. - -Generated by 'django-admin startproject' using Django 1.9.5. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - -STATIC_ROOT = os.path.join(BASE_DIR, '../../web/static/site') -MEDIA_ROOT = os.path.join(BASE_DIR, '../../web/media') - -# dev_mode useful for src_js -# We need to add 'iconolab.utils.context_processors.env' to context processor - -SRC_JS_PATH = os.path.join(BASE_DIR, '..', '..', 'src_js') -DEV_MODE = True - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static'), - os.path.join(BASE_DIR, 'media'), - SRC_JS_PATH, -] - - - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static'), -] -BASE_URL = '' -STATIC_URL = '/static/' -MEDIA_URL = '/media/' - -LOGIN_URL = '/account/login/' - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '#8)+upuo3vc7fi15czxz53ml7*(1__q8hg=m&+9ylq&st1_kqv' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True -THUMBNAIL_DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.sites', - 'django_comments', - 'django_comments_xtd', - 'haystack', - 'iconolab.apps.IconolabApp', - 'sorl.thumbnail', - 'notifications' -] - - - -COMMENTS_APP = "django_comments_xtd" -COMMENTS_XTD_MODEL = "iconolab.models.IconolabComment" -COMMENTS_XTD_FORM_CLASS = 'iconolab.forms.comments.IconolabCommentForm' -COMMENTS_XTD_MAX_THREAD_LEVEL = 100 -COMMENTS_PER_PAGE_DEFAULT = 10 - -SITE_ID = 1 - -MIDDLEWARE_CLASSES = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'reversion.middleware.RevisionMiddleware', -] - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static'), - os.path.join(BASE_DIR, 'iconolab', 'media'), -] - -MEDIA_URL = os.path.join(BASE_DIR, 'iconolab', 'media') + "/" - -ROOT_URLCONF = 'iconolab.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR,'iconolab','templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'django.core.context_processors.media', - 'django.core.context_processors.static', - 'django.core.context_processors.i18n', - 'iconolab.utils.context_processors.env', - ], - }, - }, -] - -WSGI_APPLICATION = 'iconolab.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } -} - -# Logging - -LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"../../run/log/log.txt")) -LOG_LEVEL = logging.DEBUG -LOGGING = { - 'version': 1, - 'disable_existing_loggers': True, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'formatters' : { - 'simple' : { - 'format': "%(asctime)s - %(levelname)s : %(message)s", - }, - 'semi-verbose': { - 'format': '%(levelname)s %(asctime)s %(module)s %(message)s' - }, - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - }, - 'stream_to_console': { - 'level': LOG_LEVEL, - 'class': 'logging.StreamHandler' - }, - 'file': { - 'level': LOG_LEVEL, - 'class': 'logging.FileHandler', - 'filename': LOG_FILE, - 'formatter': 'semi-verbose', - }, - }, - 'loggers': { - 'django.request': { - 'handlers': ['file'], - 'level': LOG_LEVEL, - 'propagate': True, - }, - 'iconolab': { - 'handlers': ['file'], - 'level': LOG_LEVEL, - 'propagate': True, - }, - } -} - - -# Haystack connection -HAYSTACK_CONNECTIONS = { - 'default': { - 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', - 'URL': 'http://127.0.0.1:9200/', - 'INDEX_NAME': 'haystack', - }, -} - -# HAYSTACK_SIGNAL_PROCESSOR -HAYSTACK_SIGNAL_PROCESSOR = 'iconolab.search_indexes.signals.RevisionSignalProcessor' - -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': os.path.join(MEDIA_ROOT, 'cache'), -# 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', -# 'LOCATION': 'unix:/var/run/memcached/memcached.socket', -# 'KEY_PREFIX': 'ldt', - } -} -# Password validation -# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -IMPORT_FIELDS_DICT = { - "AUTR": [], - "ECOLE": [], - "TITR": ["Titre"], - "DENO": [], - "APPL": [], - "PERI": ["Période"], - "MILL": [], - "EPOCH": [], - "TECH": [], - "DIMS": ["Dimensions"], - "EPOCH": [], - "LIEUX": [], - "DECV": [], - "LOCA": ["Localisation"], - "PHOT": ["Photo"], - "INV": ["No inventaire",], - "REF": ["REFERENCE"], -} - -INTERNAL_TAGS_URL = BASE_URL -JOCONDE_NOTICE_BASE_URL = "http://www.culture.gouv.fr/public/mistral/joconde_fr?ACTION=CHERCHER&FIELD_98=REF&VALUE_98=" +""" +Django settings for iconolab project. + +Generated by 'django-admin startproject' using Django 1.9.5. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.9/ref/settings/ +""" +from iconolab.settings import * + +import os, logging + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +STATIC_ROOT = os.path.join(BASE_DIR, '../../web/static/site') +MEDIA_ROOT = os.path.join(BASE_DIR, '../../web/media') + +# dev_mode useful for src_js +# We need to add 'iconolab.utils.context_processors.env' to context processor + +SRC_JS_PATH = os.path.join(BASE_DIR, '..', '..', 'src_js') +DEV_MODE = True + +BASE_URL = '' +STATIC_URL = '/static/' +MEDIA_URL = '/media/' + +LOGIN_URL = '/account/login/' + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '#8)+upuo3vc7fi15czxz53ml7*(1__q8hg=m&+9ylq&st1_kqv' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True +THUMBNAIL_DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + 'django_comments', + 'django_comments_xtd', + 'haystack', + 'iconolab.apps.IconolabApp', + 'sorl.thumbnail', + 'notifications' +] + + + +COMMENTS_APP = "django_comments_xtd" +COMMENTS_XTD_MODEL = "iconolab.models.IconolabComment" +COMMENTS_XTD_FORM_CLASS = 'iconolab.forms.comments.IconolabCommentForm' +COMMENTS_XTD_MAX_THREAD_LEVEL = 100 +COMMENTS_PER_PAGE_DEFAULT = 10 + +SITE_ID = 1 + +MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'reversion.middleware.RevisionMiddleware', +] + + +ROOT_URLCONF = 'iconolab.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR,'iconolab','templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.core.context_processors.media', + 'django.core.context_processors.static', + 'django.core.context_processors.i18n', + 'iconolab.utils.context_processors.env', + ], + }, + }, +] + +WSGI_APPLICATION = 'iconolab.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.9/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + +# Logging + +LOG_FILE = os.path.abspath(os.path.join(BASE_DIR,"../../run/log/log.txt")) +LOG_LEVEL = logging.DEBUG +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'formatters' : { + 'simple' : { + 'format': "%(asctime)s - %(levelname)s : %(message)s", + }, + 'semi-verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s %(message)s' + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'stream_to_console': { + 'level': LOG_LEVEL, + 'class': 'logging.StreamHandler' + }, + 'file': { + 'level': LOG_LEVEL, + 'class': 'logging.FileHandler', + 'filename': LOG_FILE, + 'formatter': 'semi-verbose', + }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + 'iconolab': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + } +} + + +# Haystack connection +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', + 'URL': 'http://127.0.0.1:9200/', + 'INDEX_NAME': 'haystack', + }, +} + +# HAYSTACK_SIGNAL_PROCESSOR +HAYSTACK_SIGNAL_PROCESSOR = 'iconolab.search_indexes.signals.RevisionSignalProcessor' + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': os.path.join(MEDIA_ROOT, 'cache'), +# 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', +# 'LOCATION': 'unix:/var/run/memcached/memcached.socket', +# 'KEY_PREFIX': 'ldt', + } +} +# Password validation +# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.9/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +IMPORT_FIELDS_DICT = { + "AUTR": [], + "ECOLE": [], + "TITR": ["Titre"], + "DENO": [], + "APPL": [], + "PERI": ["Période"], + "MILL": [], + "EPOCH": [], + "TECH": [], + "DIMS": ["Dimensions"], + "EPOCH": [], + "LIEUX": [], + "DECV": [], + "LOCA": ["Localisation"], + "PHOT": ["Photo"], + "INV": ["No inventaire",], + "REF": ["REFERENCE"], +} + +INTERNAL_TAGS_URL = BASE_URL +JOCONDE_NOTICE_BASE_URL = "http://www.culture.gouv.fr/public/mistral/joconde_fr?ACTION=CHERCHER&FIELD_98=REF&VALUE_98=" diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/templates/iconolab/home.html --- a/src/iconolab/templates/iconolab/home.html Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/templates/iconolab/home.html Mon Aug 29 16:19:16 2016 +0200 @@ -35,9 +35,11 @@ {% block footer_js %} -{% endblock %} \ No newline at end of file +{% endblock %} diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/urls.py --- a/src/iconolab/urls.py Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/urls.py Mon Aug 29 16:19:16 2016 +0200 @@ -20,7 +20,7 @@ from django import views as django_views from iconolab import views from iconolab.search_indexes.views import IconolabSearchView -from . import settings +from django.conf import settings from django.conf.urls.static import static from django.contrib.auth.decorators import login_required @@ -51,7 +51,7 @@ url(r'^comments/', include('django_comments_xtd.urls')), url(r'^comments/annotation/post', views.comments.post_comment_iconolab, name="post_comment"), url('^user/notifications/', include(notifications.urls, namespace='notifications')), - + url(r'collections/(?P[a-z0-9\-]+)/search/(?P[a-z0-9\-]+)', IconolabSearchView.as_view(), name="collection_with_model_search"), url(r'^search/(?P[a-z0-9\-]+)', IconolabSearchView.as_view(), name="model_search"), @@ -62,7 +62,9 @@ #url(r'^search/', include('haystack.urls'), name="search_iconolab"), ] -urlpatterns += staticfiles_urlpatterns() -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -#static url -urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + +if settings.DJANGO_RUNSERVER: + urlpatterns += staticfiles_urlpatterns() + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + #static url + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff -r 79b70254a5e0 -r c1d03ab4baad src/iconolab/views/iconolab.py --- a/src/iconolab/views/iconolab.py Fri Aug 26 13:36:05 2016 +0200 +++ b/src/iconolab/views/iconolab.py Mon Aug 29 16:19:16 2016 +0200 @@ -26,7 +26,7 @@ class TestView(View): template_name = "iconolab/compare.html" - + def get(self, request, *args, **kwargs): return render(request, self.template_name) @@ -35,37 +35,37 @@ class UserHomeView(DetailView): model = User slug_field = 'id' - + def get_context_data(self, **kwargs): context = super(UserHomeView, self).get_context_data(**kwargs) return context - + def get(self, request, *args, **kwargs): self.object = self.get_object() context = self.get_context_data() profile_user = self.object context['profile_user'] = profile_user context['user_annotations'] = Annotation.objects.filter(author=profile_user).prefetch_related( - 'current_revision', - 'revisions', - 'image', - 'image__item', + 'current_revision', + 'revisions', + 'image', + 'image__item', 'image__item__collection' ) context['user_revisions_annotations'] = Annotation.objects.filter(revisions__author=profile_user).exclude(author=profile_user).prefetch_related( - 'current_revision', - 'revisions', - 'image', - 'image__item', + 'current_revision', + 'revisions', + 'image', + 'image__item', 'image__item__collection' ).distinct() comments_annotations_str_id = IconolabComment.objects.filter(user=profile_user, content_type__app_label='iconolab', content_type__model='annotation').values_list('object_pk', flat=True) comments_annotations_id = [int(str_id) for str_id in comments_annotations_str_id] context['user_comments_annotations'] = Annotation.objects.filter(id__in=comments_annotations_id).exclude(author=profile_user).exclude(annotation_guid__in=context['user_revisions_annotations'].values_list('annotation_guid', flat=True)).prefetch_related( - 'current_revision', - 'revisions', - 'image', - 'image__item', + 'current_revision', + 'revisions', + 'image', + 'image__item', 'image__item__collection' ).distinct() if request.user.is_authenticated() and self.object == request.user: @@ -75,7 +75,7 @@ return render(request, 'iconolab/user_home.html', context) class UserNotificationsView(View): - + def get(self, request, *args, **kwargs): context = {} notifications = Notification.objects.filter(recipient=request.user) @@ -98,6 +98,7 @@ Returns a boolean depending on wether (True) or not (False) the objects were found and a tuple containing the objects, with a select_related/prefetch_related on relevant related objects following this ordering: (collection, item, image, annotation, revision) ''' + objects_tuple = () if 'collection_name' in kwargs.keys(): try: @@ -136,30 +137,30 @@ context = super(CollectionHomepageView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') context['collection'] = collection - + # Recent annotations context['recent_annotations'] = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related( - 'current_revision', + 'current_revision', 'stats' ).order_by('-current_revision__created') - + # Recent annotations context['revised_annotations'] = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related( - 'current_revision', + 'current_revision', 'stats' ).annotate(revision_count=Count("revisions")).order_by('-revision_count') - + contrib_calls_annotations_ids = list(set(MetaCategoryInfo.objects.filter( - metacategory__collection__name=collection.name, + metacategory__collection__name=collection.name, metacategory__triggers_notifications=MetaCategory.CONTRIBUTORS ).order_by("comment__submit_date").values_list("comment__object_pk", flat=True))) - + collection_annotations = Annotation.objects.filter(id__in=contrib_calls_annotations_ids).all() collection_ann_dict = dict([(str(annotation.id), annotation) for annotation in collection_annotations]) context["contribution_calls_annotations_list"] = [collection_ann_dict[id] for id in contrib_calls_annotations_ids] - + return render(request, 'iconolab/collection_home.html', context) - + class ShowItemView(View, ContextMixin, IconolabObjectView): @@ -192,15 +193,15 @@ context['collection'] = collection context['image'] = image return render(request, 'iconolab/detail_image.html', context) - + class CreateAnnotationView(View, ContextMixin, IconolabObjectView): - + def get_context_data(self, **kwargs): context = super(CreateAnnotationView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') context['image_guid'] = self.kwargs.get('image_guid', '') return context - + def get(self, request, *args, **kwargs): success, result = self.check_kwargs(kwargs) if success: @@ -212,8 +213,8 @@ context['image'] = image context['form'] = annotation_form context['tags_data'] = '[]' - return render(request, 'iconolab/change_annotation.html', context) - + return render(request, 'iconolab/change_annotation.html', context) + def post(self, request, *args, **kwargs): success, result = self.check_kwargs(kwargs) if success: @@ -249,7 +250,7 @@ render(request, 'iconolab/change_annotation.html', context) class ShowAnnotationView(View, ContextMixin, IconolabObjectView): - + def get_context_data(self, **kwargs): context = super(ShowAnnotationView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') @@ -268,7 +269,7 @@ context['image'] = image context['annotation'] = annotation context['tags_data'] = annotation.current_revision.get_tags_json() - + page = request.GET.get('page', 1) per_page = request.GET.get('perpage', 10) full_comments_list = IconolabComment.objects.for_app_models('iconolab.annotation').filter(object_pk = annotation.pk).order_by('thread_id', '-order') @@ -280,12 +281,12 @@ except EmptyPage: comments_list = paginator.page(paginator.num_pages) context['comments'] = comments_list - + if request.user.is_authenticated(): user_comment_notifications = Notification.objects.filter( - recipient=request.user, - action_object_content_type__app_label='iconolab', - action_object_content_type__model='iconolabcomment', + recipient=request.user, + action_object_content_type__app_label='iconolab', + action_object_content_type__model='iconolabcomment', target_content_type__app_label='iconolab', target_content_type__model='annotation', target_object_id=annotation.id @@ -295,7 +296,7 @@ for notification in user_comment_notifications.all(): if int(notification.action_object_object_id) in comment_list_ids: notification.mark_as_read() - + image.stats.views_count += 1 image.stats.save() annotation.stats.views_count += 1 @@ -304,14 +305,14 @@ class EditAnnotationView(View, ContextMixin, IconolabObjectView): - + def get_context_data(self, **kwargs): context = super(EditAnnotationView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') context['image_guid'] = self.kwargs.get('image_guid', '') context['annotation_guid'] = self.kwargs.get('annotation_guid', '') return context - + def get(self, request, *args, **kwargs): success, result = self.check_kwargs(kwargs) if success: @@ -324,8 +325,8 @@ context['annotation'] = annotation context['form'] = annotation_form context['tags_data'] = annotation.current_revision.get_tags_json() - return render(request, 'iconolab/change_annotation.html', context) - + return render(request, 'iconolab/change_annotation.html', context) + def post(self, request, *args, **kwargs): success, result = self.check_kwargs(kwargs) if success: @@ -364,7 +365,7 @@ class ShowRevisionView(View, ContextMixin, IconolabObjectView): - + def get_context_data(self, **kwargs): context = super(ShowRevisionView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') @@ -372,7 +373,7 @@ context['annotation_guid'] = self.kwargs.get('annotation_guid', '') context['revision_guid'] = self.kwargs.get('revision_guid', '') return context - + def get(self, request, *args, **kwargs): success, result = self.check_kwargs(kwargs) if success: @@ -388,8 +389,8 @@ context['comment'] = revision.creation_comment.first() if request.user.is_authenticated() and annotation.author == request.user: ann_author_notified = Notification.objects.filter( - recipient=request.user, - action_object_content_type__app_label='iconolab', + recipient=request.user, + action_object_content_type__app_label='iconolab', action_object_content_type__model='annotationrevision', action_object_object_id=revision.id, target_content_type__app_label='iconolab', @@ -401,8 +402,8 @@ context['notified_revision'] = True if request.user.is_authenticated() and revision.author == request.user: rev_author_notified = Notification.objects.filter( - recipient=request.user, - action_object_content_type__app_label='iconolab', + recipient=request.user, + action_object_content_type__app_label='iconolab', action_object_content_type__model='annotationrevision', action_object_object_id=revision.id, target_content_type__app_label='iconolab', @@ -414,9 +415,9 @@ context['notified_revision'] = True return render(request, 'iconolab/detail_revision.html', context) - + class MergeProposalView(View, ContextMixin, IconolabObjectView): - + def get_context_data(self, **kwargs): context = super(MergeProposalView, self).get_context_data(**kwargs) context['collection_name'] = self.kwargs.get('collection_name', '') @@ -434,10 +435,10 @@ # Only show merge form if there is a revision to merge AND the current user is the annotation author if revision.state != AnnotationRevision.AWAITING or request.user != annotation.author: return RedirectView.as_view( - url=reverse('revision_detail', + url=reverse('revision_detail', kwargs={ - 'collection_name': collection.name, - 'image_guid': image.image_guid, + 'collection_name': collection.name, + 'image_guid': image.image_guid, 'annotation_guid': annotation.annotation_guid, 'revision_guid': revision.revision_guid } @@ -447,27 +448,27 @@ if 'auto_accept' in request.GET and request.GET['auto_accept'] in ['True', 'true', '1', 'yes'] and revision.parent_revision == annotation.current_revision: annotation.validate_existing_revision(revision) return RedirectView.as_view( - url=reverse('annotation_detail', + url=reverse('annotation_detail', kwargs={ - 'collection_name': collection.name, - 'image_guid': image.image_guid, + 'collection_name': collection.name, + 'image_guid': image.image_guid, 'annotation_guid': annotation.annotation_guid } ) )(request) # Auto-reject the revision only if the proper query arg is set if 'auto_reject' in request.GET and request.GET['auto_reject'] in ['True', 'true', '1', 'yes']: - annotation.reject_existing_revision(revision) + annotation.reject_existing_revision(revision) return RedirectView.as_view( - url=reverse('annotation_detail', + url=reverse('annotation_detail', kwargs={ - 'collection_name': collection.name, - 'image_guid': image.image_guid, + 'collection_name': collection.name, + 'image_guid': image.image_guid, 'annotation_guid': annotation.annotation_guid } ) )(request) - + context = self.get_context_data(**kwargs) context['collection'] = collection context['image'] = image @@ -484,11 +485,11 @@ context['current_revision'] = annotation.current_revision context['current_tags_data'] = annotation.current_revision.get_tags_json() context['current_comment'] = annotation.current_revision.creation_comment.first() - + merge_form = AnnotationRevisionForm(instance=revision) context['merge_form'] = merge_form return render(request, 'iconolab/merge_revision.html', context) - + def post(self, request, *args, **kwargs): # Handle merge form submit here success, result = self.check_kwargs(kwargs) @@ -500,7 +501,7 @@ image_guid = kwargs['image_guid'] annotation_guid = kwargs['annotation_guid'] revision_guid = kwargs['revision_guid'] - + merge_revision_form = AnnotationRevisionForm(request.POST) if merge_revision_form.is_valid(): revision_title = merge_revision_form.cleaned_data['title'] @@ -537,10 +538,10 @@ context['current_tags_data'] = annotation.current_revision.get_tags_json() context['current_comment'] = annotation.current_revision.creation_comment.first() return render(request, 'iconolab/merge_revision.html', context) - - + + class NotFoundErrorView(TemplateView): template_name='errors/404error.html' - + class HelpView(TemplateView): - template_name='iconolab/glossary.html' \ No newline at end of file + template_name='iconolab/glossary.html' diff -r 79b70254a5e0 -r c1d03ab4baad src/requirements/base.txt --- a/src/requirements/base.txt Fri Aug 26 13:36:05 2016 +0200 +++ b/src/requirements/base.txt Mon Aug 29 16:19:16 2016 +0200 @@ -11,5 +11,5 @@ pytz==2016.6.1 requests==2.11.1 six==1.10.0 -sorl-thumbnail==12.3 +sorl-thumbnail==12.4a1 urllib3==1.16 diff -r 79b70254a5e0 -r c1d03ab4baad src/requirements/base.txt.in --- a/src/requirements/base.txt.in Fri Aug 26 13:36:05 2016 +0200 +++ b/src/requirements/base.txt.in Mon Aug 29 16:19:16 2016 +0200 @@ -1,13 +1,13 @@ -Django >= 1.9 -django-comments-xtd -django-contrib-comments -django-haystack -django-notifications-hq -elasticsearch -jsonfield -Pillow -psycopg2 -pytz -requests -six -sorl-thumbnail +Django >= 1.9 +django-comments-xtd +django-contrib-comments +django-haystack +django-notifications-hq +elasticsearch +jsonfield +Pillow +psycopg2 +pytz +requests +six +sorl-thumbnail >= 12.4a1