--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/management/commands/importimages.py Fri Aug 12 10:59:57 2016 +0200
@@ -0,0 +1,187 @@
+# -*- coding: UTF-8 -*-
+from django.core.management.base import BaseCommand, CommandError
+from django.core.management import call_command
+from django.conf import settings
+from iconolab.models import Collection, Image, ImageStats, Item, ItemMetadata
+from PIL import Image as ImagePIL
+import os, csv, pprint, re, json
+
+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(
+ '--encoding',
+ dest='encoding',
+ default='utf-8',
+ help='CSV file encoding'
+
+ )
+ parser.add_argument(
+ '--collection-fixture',
+ dest='collection_fixture',
+ default=False,
+ help='loads the fixture then insert extracted data into the created collection',
+ )
+ parser.add_argument(
+ '--collection-id',
+ dest='collection_id',
+ default=False,
+ help='insert extracted data into the specified collection instead of trying to load a collection fixture',
+ )
+
+ def handle(self, *args, **options):
+ pp = pprint.PrettyPrinter(indent=4)
+ try:
+ # Check we have a collection to store data into:
+ source_dir = os.path.dirname(os.path.realpath(options.get("csv_path")))
+ print("# Checking collection args")
+ if options.get("collection_fixture"):
+ print("## Finding collection json data in "+source_dir)
+ fixture_path = os.path.join(source_dir, options.get("collection_fixture"))
+ if not os.path.isfile(fixture_path):
+ print("### No "+options.get("collection_fixture")+".json file was found in the source directory")
+ raise ValueError("!!! Fixture file "+fixture_path+" was not found !!!")
+ try:
+ with open(fixture_path) as json_fixture_file:
+ collection_data = json.loads(json_fixture_file.read())
+ if len(collection_data) != 1:
+ raise ValueError("!!! Collection fixture has either 0 or more than one item. It should only provide one and only one collection !!!")
+ 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. !!!")
+ elif options.get("collection_id"):
+ print("## Finding collection with id "+options.get("collection_id"))
+ try:
+ collection = Collection.objects.get(pk=options.get("collection_id"))
+ 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. !!!")
+ # We read the csv
+ csvreader = csv.DictReader(open(options.get("csv_path"), encoding=options.get("encoding")), 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=[]
+ for row in csvreader:
+ cleaned_row_data = {}
+ for key in settings.IMPORT_FIELDS_DICT.keys():
+ cleaned_row_data[key] = ""
+ for row_key in row.keys():
+ if row_key in settings.IMPORT_FIELDS_DICT[key]:
+ 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")]
+ filtered_csv_data = []
+ # Now we trim the cleaned_csv_data dict to keep only entries that have at least one image
+ for item in cleaned_csv_data:
+ item["SRC_IMG_FILES"] = []
+ has_image = False
+ for image in image_list:
+ if image.startswith(item["INV"]):
+ item["SRC_IMG_FILES"].append(image)
+ has_image = True
+ if has_image:
+ filtered_csv_data.append(item)
+ print("## found " + str(len(filtered_csv_data))+" items with at least one image")
+ print("# Importing data into Iconolab")
+ if options.get("collection_fixture"):
+ print("## Loading collection fixture")
+ call_command("loaddata", fixture_path)
+ collection = Collection.objects.get(
+ pk = collection_data[0]["pk"]
+ )
+ print("## Converting image and moving it to static dir, creating Image and Item objects")
+ target_dir = os.path.join(settings.MEDIA_ROOT, "uploads")
+ print("### Images will be stored in "+target_dir)
+ for item in filtered_csv_data:
+ print("#### Computing metadatas for item "+item["INV"]+" (inv number)")
+ item_authors = item["AUTR"]
+ item_school = item["ECOLE"]
+ item_designation = ""
+ if item.get("TITR", ""):
+ item_designation = item["TITR"]
+ elif item.get("DENO", ""):
+ item_designation = item["DENO"]
+ elif item.get("APPL", ""):
+ item_designation = item["APPL"]
+ item_datation = ""
+ if item.get("PERI", ""):
+ item_datation = item["PERI"]
+ elif item.get("MILL", ""):
+ item_datation = item["MILL"]
+ elif item.get("EPOQ", ""):
+ item_datation = item["EPOQ"]
+ item_technics = item["TECH"]
+ item_measurements = item["DIMS"]
+ item_create_or_usage_location = item["LIEUX"]
+ item_discovery_context = item["DECV"]
+ item_conservation_location = item["LOCA"]
+ item_photo_credits = item["PHOT"]
+ item_inventory_number = item["INV"]
+ item_joconde_ref = item["REF"]
+ if ItemMetadata.objects.filter(item__collection = collection, inventory_number = item_inventory_number).exists():
+ print("#### An item with "+item["INV"]+" for inventory number, already exists in databse in the import collection")
+ else:
+ print("#### Creating item "+item["INV"]+" (inv number) in databse")
+ item_object = Item.objects.create(
+ collection = collection
+ )
+ ItemMetadata.objects.create(
+ item = item_object,
+ authors = item_authors,
+ school = item_school,
+ designation = item_designation,
+ datation = item_datation,
+ technics = item_technics,
+ measurements = item_measurements,
+ create_or_usage_location = item_create_or_usage_location,
+ discovery_context = item_discovery_context,
+ conservation_location = item_conservation_location,
+ photo_credits = item_photo_credits,
+ inventory_number = item_inventory_number,
+ joconde_ref = item_joconde_ref
+ )
+ print("#### Computing item image(s)")
+ for image in item["SRC_IMG_FILES"]:
+ (image_name, ext) = os.path.splitext(image)
+ image_path = os.path.join(target_dir, image_name) + ".jpg"
+ if os.path.isfile(image_path):
+ print("##### A jpeg file already exists in target dir for "+ image)
+ try:
+ im = ImagePIL.open(image_path)
+ im_width, im_height = im.size
+ except Exception as e:
+ print(e)
+ 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_width, im_height = im.size
+ except Exception as e:
+ print(e)
+ new_image = Image.objects.create(
+ item = item_object,
+ media = image_path,
+ name = image_name,
+ height = im_height,
+ width = im_width
+ )
+ ImageStats.objects.create(
+ image = new_image
+ )
+ print("# All done!")
+ except FileNotFoundError:
+ print("!!! File "+options.get("csv_path")+" does not exist. !!!")
+ except ValueError as e:
+ print(str(e))
+
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/migrations/0008_auto_20160811_1050.py Fri Aug 12 10:59:57 2016 +0200
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.7 on 2016-08-11 10:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('iconolab', '0007_auto_20160805_1304'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='itemmetadata',
+ name='description',
+ ),
+ migrations.RemoveField(
+ model_name='itemmetadata',
+ name='domain',
+ ),
+ migrations.RemoveField(
+ model_name='itemmetadata',
+ name='title',
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='authors',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='conservation_location',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='create_or_usage_location',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='datation',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='designation',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='discovery_context',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='inventory_number',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='measurements',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='photo_credits',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='school',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AddField(
+ model_name='itemmetadata',
+ name='technics',
+ field=models.CharField(default='', max_length=255),
+ ),
+ migrations.AlterField(
+ model_name='itemmetadata',
+ name='joconde_ref',
+ field=models.CharField(default='', max_length=255),
+ ),
+ ]
--- a/src/iconolab/models.py Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/models.py Fri Aug 12 10:59:57 2016 +0200
@@ -43,10 +43,22 @@
class ItemMetadata(models.Model):
item = models.OneToOneField('Item', related_name='metadatas')
- joconde_ref = models.CharField(max_length=20)
- domain = models.CharField(max_length=255)
- title = models.CharField(max_length=255)
- description = models.CharField(max_length=255)
+ authors = models.CharField(max_length=255, default="")
+ school = models.CharField(max_length=255, default="")
+ designation = models.CharField(max_length=255, default="")
+ datation = models.CharField(max_length=255, default="")
+ technics = models.CharField(max_length=255, default="")
+ measurements = models.CharField(max_length=255, default="")
+ create_or_usage_location = models.CharField(max_length=255, default="")
+ discovery_context = models.CharField(max_length=255, default="")
+ conservation_location = models.CharField(max_length=255, default="")
+ photo_credits = models.CharField(max_length=255, default="")
+ inventory_number = models.CharField(max_length=255, default="")
+ joconde_ref = models.CharField(max_length=255, default="")
+
+ @property
+ def get_joconde_url(self):
+ return self.joconde_ref
class ImageStats(models.Model):
--- a/src/iconolab/settings/__init__.py Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/settings/__init__.py Fri Aug 12 10:59:57 2016 +0200
@@ -147,3 +147,27 @@
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"],
+
+}
+NO_IMG_CONVERSION_EXTS = [".jpg"]
+IMG_CONVERSION_EXTS = [".tif", ".tiff"]
--- a/src/iconolab/templates/iconolab/detail_annotation.html Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/templates/iconolab/detail_annotation.html Fri Aug 12 10:59:57 2016 +0200
@@ -77,7 +77,7 @@
<h4 id="annotation-comments-header">Commentaires</h4>
<ul class="list-group annotation-comments" id="comments">
{% for comment in comments %}
- <li class="list-group-item" id="c{{ comment.id }}" style="margin-left:calc({{ comment.level }}*5px);">
+ <li class="list-group-item {% if comment.id in notifications_comments_ids %}list-group-item-warning{% endif %}" id="c{{ comment.id }}" style="margin-left:calc({{ comment.level }}*5px);">
<p id="c{{comment.id}}-content" class="comment-content">{{ comment.comment }}</p>
<hr class="comment-separator">
{% if comment.allow_thread and user.is_authenticated %}<div class="pull-right"><a class="btn btn-default btn-xs reply-to-btn" id="reply-to-{{comment.id}}" class="comment-reply-link">Répondre</a></div>{% endif %}
--- a/src/iconolab/templates/iconolab/detail_item.html Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/templates/iconolab/detail_item.html Fri Aug 12 10:59:57 2016 +0200
@@ -21,11 +21,18 @@
{% endfor %}
</div>
<div class="col-md-6">
- <h2>{% if item.metadatas.title %}{{item.metadatas.title}}{% else %}Objet sans titre{% endif %}</h2>
- {% if item.metadatas.description %}
- <h4>Description: </h4>
- <p>{{item.metadatas.description}}</p><br>
- {% endif %}
+ {% if item.metadatas.designation %}<h3>Désignation: <small>{{item.metadatas.designation}}</small></h3>{% endif %}
+ {% if item.metadatas.authors %}<h4>Auteur(s): <small>{{item.metadatas.designation}}</small></h4>{% endif %}
+ {% if item.metadatas.conservation_location %}<h4>Conservé à: <small>{{item.metadatas.conservation_location}}</small></h4>{% endif %}
+ {% if item.metadatas.datation %}<h4>Datation: <small>{{item.metadatas.datation}}</small></h4>{% endif %}
+ {% if item.metadatas.technics %}<h5>Techniques: <small>{{item.metadatas.technics}}</small></h5>{% endif %}
+ {% if item.metadatas.measurements %}<h5>Mesures: {{item.metadatas.measurements}}</h5>{% endif %}
+ {% if item.metadatas.create_or_usage_location %}<h5>Lieu de création/utilisation: <small>{{item.metadatas.create_or_usage_location}}</small></h5>{% endif %}
+ {% if item.metadatas.discovery_context %}<h5>Contexte de découverte: <small>{{item.metadatas.discovery_context}}</small></h5>{% endif %}
+ {% if item.metadatas.photo_credits %}<h5>Crédits photographique: <small>{{item.metadatas.photo_credits}}</small></h5>{% endif %}
+ {% if item.metadatas.inventory_number %}<h5>Numéro d'inventaire: <small>{{item.metadatas.inventory_number}}</small></h5>{% endif %}
+ {% if item.metadatas.joconde_ref %}<h5>Cet objet dans Joconde <small>{{item.metadatas.get_joconde_url}}</small></h5>{% endif %}
+ <br>
{% if item.images.all.count > 1 %}
<h4>Autres images pour cet objet: </h4>
{% for image in item.images.all %}
--- a/src/iconolab/templates/iconolab/user_home.html Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/templates/iconolab/user_home.html Fri Aug 12 10:59:57 2016 +0200
@@ -16,13 +16,13 @@
<div class="panel panel-default" style="padding-left: 10px; padding-right: 10px;">
{% if profile_user == request.user %}
{% notifications_unread as unread_count %}
- <h4><span class="badge notif-badge {% if unread_count %}badge-error{% endif %}">{{unread_count}}</span> Notifications non lues
+ <h4><span class="badge notif-badge {% if unread_count %}badge-warning{% endif %}">{{unread_count}} <i class="fa fa-envelope-o" aria-hidden="true"></i></span> Notifications non lues
<a href="{% url 'user_notifications' %}" class="btn btn-default btn-xs">Voir toutes mes notifications</a>
- <a href="{% url 'user_home' profile_user.id %}?clear_notifications=True" class="btn btn-default btn-xs">Tout marquer comme lu</a>
+ {% if unread_count %}<a href="{% url 'user_home' profile_user.id %}?clear_notifications=True" class="btn btn-default btn-xs">Tout marquer comme lu</a>{% endif %}
</h4>
<div class="row">
<div class="col-md-12">
- {% if notifications %}
+ {% if unread_count %}
<ul class="list-group">
{% for notification in notifications.unread %}
<a
--- a/src/iconolab/templates/iconolab/user_notifications.html Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/templates/iconolab/user_notifications.html Fri Aug 12 10:59:57 2016 +0200
@@ -33,6 +33,30 @@
</a>
{% endfor %}
</ul>
+
+ {% if notifications.has_previous or notifications.has_next %}
+ <ul class="pagination pull-right">
+ {% if notifications.has_previous %}
+ <li>
+ <a href="{% url 'user_notifications' %}?page={{notifications.previous_page_number}}" aria-label="Previous">
+ <span aria-hidden="true">«</span>
+ </a>
+ </li>
+ {% endif %}
+ {% for page in notifications.paginator.page_range %}
+ <li id="page-link-{{page}}" class="pagination-link {% if page == notifications.number %}active{% endif %}">
+ <a {% if page != notifications.number %}href="{% url 'user_notifications' %}?page={{page}}"{% endif %}>{{page}}</a>
+ </li>
+ {% endfor %}
+ {% if notifications.has_next %}
+ <li>
+ <a href="{% url 'user_notifications' %}?page={{notifications.next_page_number}}" aria-label="Next">
+ <span aria-hidden="true">»</span>
+ </a>
+ </li>
+ {% endif %}
+ </ul>
+ {% endif %}
{% endif %}
</div>
</div>
--- a/src/iconolab/templates/partials/header.html Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/templates/partials/header.html Fri Aug 12 10:59:57 2016 +0200
@@ -22,7 +22,10 @@
<ul class="nav navbar-nav navbar-right">
{% if request.user.is_authenticated %}
{% notifications_unread as unread_count %}
- <li><a href="{% url 'user_home' request.user.id %}">{{user.username}}: Mon espace <span class="badge {% if unread_count %}badge-error{% endif %}">{{ unread_count }}</span></a></li>
+ <li><a href="{% url 'user_home' request.user.id %}">
+ {{user.username}}: Mon espace <span class="badge {% if unread_count %}badge-warning{% endif %}">
+ {{ unread_count }} <i class="fa fa-envelope-o" aria-hidden="true"></i> </span>
+ </a></li>
<li><a href="{% url 'account:logout' %}">Se déconnecter</a></li>
{% else %}
<li><a href="{% url 'account:register' %}">Créer un compte</a></li>
--- a/src/iconolab/urls.py Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/urls.py Fri Aug 12 10:59:57 2016 +0200
@@ -29,14 +29,14 @@
url(r'^$', views.iconolab.RedirectView.as_view(url=reverse_lazy("home"))),
url(r'^admin/', admin.site.urls),
url(r'^home$', views.iconolab.GlobalHomepageView.as_view(), name="home"),
- url(r'^collections/(?P<collection_name>[a-z]+)$', views.iconolab.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
- url(r'^collections/(?P<collection_name>[a-z]+)/items/(?P<item_guid>[^/]+)$', views.iconolab.ShowItemView.as_view(), name='item_detail'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)$', views.iconolab.ShowImageView.as_view(), name='image_detail'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.iconolab.CreateAnnotationView.as_view()), name='annotation_create'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.iconolab.ShowAnnotationView.as_view(), name='annotation_detail'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.iconolab.EditAnnotationView.as_view()), name='annotation_edit'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.iconolab.ShowRevisionView.as_view(), name='revision_detail'),
- url(r'^collections/(?P<collection_name>[a-z]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.iconolab.MergeProposalView.as_view()), name='annotation_merge'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)$', views.iconolab.CollectionHomepageView.as_view(), name='collection_home'), # Home fond
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/items/(?P<item_guid>[^/]+)$', views.iconolab.ShowItemView.as_view(), name='item_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)$', views.iconolab.ShowImageView.as_view(), name='image_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.iconolab.CreateAnnotationView.as_view()), name='annotation_create'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.iconolab.ShowAnnotationView.as_view(), name='annotation_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.iconolab.EditAnnotationView.as_view()), name='annotation_edit'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/detail', views.iconolab.ShowRevisionView.as_view(), name='revision_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/(?P<revision_guid>[^/]+)/merge$', login_required(views.iconolab.MergeProposalView.as_view()), name='annotation_merge'),
url(r'^user/(?P<slug>[a-z0-9\-]+)/home/?$', views.iconolab.UserHomeView.as_view(), name="user_home"),
url(r'^user/notifications/all/?$', login_required(views.iconolab.UserNotificationsView.as_view()), name="user_notifications"),
url(r'^errors/404', views.iconolab.NotFoundErrorView.as_view(), name="404error"),
--- a/src/iconolab/views/iconolab.py Fri Aug 12 10:59:26 2016 +0200
+++ b/src/iconolab/views/iconolab.py Fri Aug 12 10:59:57 2016 +0200
@@ -64,8 +64,15 @@
context = {}
notifications = Notification.objects.filter(recipient=request.user)
context["notifications_unread_ids"] = notifications.unread().values_list("id", flat=True)
- notifications.mark_all_as_read()
- context["notifications"] = notifications
+ page = request.GET.get("page", 1)
+ paginator = Paginator(notifications, 50)
+ try:
+ notifications_list = paginator.page(page)
+ except PageNotAnInteger:
+ notifications_list = paginator.page(1)
+ except EmptyPage:
+ notifications_list = paginator.page(paginator.num_pages)
+ context["notifications"] = notifications_list
return render(request, 'iconolab/user_notifications.html', context)
@@ -259,6 +266,20 @@
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",
+ target_content_type__app_label="iconolab",
+ target_content_type__model="annotation",
+ target_object_id=annotation.id
+ ).unread()
+ context["notifications_comments_ids"] = [int(val) for val in user_comment_notifications.values_list("action_object_object_id", flat=True)]
+ comment_list_ids = [comment.id for comment in context["comments"] ]
+ 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()
@@ -384,6 +405,19 @@
context['revision'] = revision
context['tags_data'] = revision.get_tags_json()
context['comment'] = revision.creation_comment.first()
+ if request.user.is_authenticated() and annotation.author == request.user:
+ notified_revision = Notification.objects.filter(
+ 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",
+ target_content_type__model="annotation",
+ target_object_id=annotation.id
+ ).unread()
+ if notified_revision:
+ notified_revision.first().mark_as_read()
+ context["notified_revision"] = True
return render(request, 'iconolab/detail_revision.html', context)