diff --git a/tigacrafting/migrations/0020_bookmark.py b/tigacrafting/migrations/0020_bookmark.py new file mode 100644 index 00000000..f1ec0f62 --- /dev/null +++ b/tigacrafting/migrations/0020_bookmark.py @@ -0,0 +1,30 @@ +# Generated by Django 2.2.7 on 2024-10-09 12:09 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('tigaserver_app', '0047_merge_20240813_1025'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('tigacrafting', '0019_auto_20240122_1709'), + ] + + operations = [ + migrations.CreateModel( + name='BookMark', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.CharField(help_text='Label for the bookmark. It allows the user to quickly identify why a bookmark was put', max_length=150)), + ('module', models.CharField(help_text='Label which designates the module for which the bookmark is applied', max_length=150)), + ('report', models.ForeignKey(help_text='Report to which the bookmark was applied', on_delete=django.db.models.deletion.CASCADE, related_name='report_bookmarks', to='tigaserver_app.Report')), + ('user', models.ForeignKey(help_text='User which established the bookmark', on_delete=django.db.models.deletion.CASCADE, related_name='user_bookmarks', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'report', 'label')}, + }, + ), + ] diff --git a/tigacrafting/migrations/0021_auto_20241009_1259.py b/tigacrafting/migrations/0021_auto_20241009_1259.py new file mode 100644 index 00000000..941d4d6b --- /dev/null +++ b/tigacrafting/migrations/0021_auto_20241009_1259.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.7 on 2024-10-09 12:59 + +from django.conf import settings +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('tigacrafting', '0020_bookmark'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='bookmark', + unique_together={('user', 'label')}, + ), + ] diff --git a/tigacrafting/migrations/0022_bookmark_json_filter.py b/tigacrafting/migrations/0022_bookmark_json_filter.py new file mode 100644 index 00000000..c2a2be5b --- /dev/null +++ b/tigacrafting/migrations/0022_bookmark_json_filter.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2024-10-10 10:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tigacrafting', '0021_auto_20241009_1259'), + ] + + operations = [ + migrations.AddField( + model_name='bookmark', + name='json_filter', + field=models.CharField(help_text='filter conditions when bookmark was set', max_length=500, null=True), + ), + ] diff --git a/tigacrafting/models.py b/tigacrafting/models.py index 5a2c41e0..b2cf2aa2 100644 --- a/tigacrafting/models.py +++ b/tigacrafting/models.py @@ -597,3 +597,13 @@ class Alert(models.Model): # species = models.ForeignKey(Species, related_name='validations', blank=True, null=True) # #species = models.ManyToManyField(Species) # validation_value = models.IntegerField('Validation Certainty', choices=VALIDATION_CATEGORIES, default=None, blank=True, null=True, help_text='Certainty value, 1 for probable, 2 for sure') + +class BookMark(models.Model): + user = models.ForeignKey(help_text='User which established the bookmark', to='auth.User', related_name='user_bookmarks', on_delete=models.CASCADE, ) + report = models.ForeignKey(help_text='Report to which the bookmark was applied', to='tigaserver_app.Report', related_name='report_bookmarks', on_delete=models.CASCADE, ) + label = models.CharField(help_text='Label for the bookmark. It allows the user to quickly identify why a bookmark was put', max_length=150) + module = models.CharField(help_text='Label which designates the module for which the bookmark is applied', max_length=150) + json_filter = models.CharField(help_text='filter conditions when bookmark was set', max_length=500, null=True) + + class Meta: + unique_together = ('user','label') diff --git a/tigacrafting/static/tigacrafting/javascript/coarse_filter.js b/tigacrafting/static/tigacrafting/javascript/coarse_filter.js index 1d38bf73..24d456d9 100644 --- a/tigacrafting/static/tigacrafting/javascript/coarse_filter.js +++ b/tigacrafting/static/tigacrafting/javascript/coarse_filter.js @@ -1,4 +1,12 @@ -const ask_confirmation = true; +const ask_confirmation = false; + +function escapeHtml(original_string) { + if(original_string == null){ + return null; + }else{ + return original_string.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); + } +} function make_site(report_id, type){ hide_adult_buttons(report_id); @@ -70,6 +78,33 @@ function hide_adult_buttons(report_id){ $(document).ready(function() { +function load_bookmarks(){ + $.ajax({ + url: '/api/bookmarks/', + type: "GET", + headers: { "X-CSRFToken": csrf_token }, + dataType: "json", + success: function(data) { + bookmarks = data; + init_bookmarks(); + }, + error: function(jqXHR, textStatus, errorThrown){ + //alert(jqXHR.responseJSON.message); + }, + cache: false + }); +} + +function init_bookmarks(){ + $('#bookmark_drawer').empty(); + const root = $('#bookmark_drawer'); + for(var i = 0; i < bookmarks.length; i++){ + const bookmark = bookmarks[i]; + const single_bookmark = single_bookmark_template(bookmark); + root.append(single_bookmark); + } +} + function type_shows_with_current_filter(type){ const filtered_type = $('#type_select').val(); if(filtered_type=='all'){ @@ -103,16 +138,43 @@ function reset_filter(){ $('#usernote_filter').val(''); } -function filter_to_ui(){ - const filter = ui_to_filter(); - const filter_json = JSON.parse(filter); - $('#visibility_filter').html(filter_json.visibility_readable); - $('#text_filter').html(filter_json.note); - $('#rtype_filter').html(filter_json.report_type_readable); - $('#country_filter').html(filter_json.country_readable); - $('#country_filter_exclude').html(filter_json.country_exclude_readable); - $('#ia_filter').html(filter_json.ia_threshold); - $('#usernote_filter').html(decodeURI(filter_json.note)); +function filter_to_ui(_filter){ + var filter_json; + if(_filter==null){ + const filter = ui_to_filter(); + filter_json = JSON.parse(filter); + }else{ + filter_json = JSON.parse(_filter); + } + $('#visibility_filter').html(escapeHtml(filter_json.visibility_readable)); + if( filter_json.visibility!= null && filter_json.visibility != '' ){ + $('#visibility_select option[value=' + filter_json.visibility + ']').prop('selected', true); + } + + $('#text_filter').html(escapeHtml(filter_json.note)); + $('#usernote_filter').val(filter_json.note); + + $('#rtype_filter').html(escapeHtml(filter_json.report_type_readable)); + if( filter_json.report_type!= null && filter_json.report_type != '' ){ + $('#type_select option[value=' + filter_json.report_type + ']').prop('selected', true); + } + + $('#country_filter').html(escapeHtml(filter_json.country_readable)); + if( filter_json.country!= null && filter_json.country != '' ){ + $('#country_select option[value=' + filter_json.country + ']').prop('selected', true); + } + + $('#country_filter_exclude').html(escapeHtml(filter_json.country_exclude_readable)); + if( filter_json.country_exclude!= null && filter_json.country_exclude != '' ){ + $('#country_select_exclude option[value=' + filter_json.country_exclude + ']').prop('selected', true); + } + + $('#ia_filter').html(escapeHtml(filter_json.ia_threshold)); + $("#slider").slider('value',filter_json.ia_threshold); + $( "#slider_value" ).html(escapeHtml(filter_json.ia_threshold)); + + $('#usernote_filter').html(escapeHtml(decodeURI(filter_json.note))); + $('#usernote_filter').val(filter_json.note); } function ui_to_filter(){ @@ -287,6 +349,7 @@ function classify_picture(report_id, category_id, validation_value){ success: function(data) { $('#' + report_id).unblock(); remove_report(report_id); + load_bookmarks(); }, error: function(jqXHR, textStatus, errorThrown){ if( jqXHR.responseJSON.opcode == -1 ){ @@ -310,6 +373,7 @@ function quick_upload_report(report_id){ success: function(data) { $('#' + report_id).unblock(); remove_report(report_id); + load_bookmarks(); }, error: function(jqXHR, textStatus, errorThrown){ if( jqXHR.responseJSON.opcode == -1 ){ @@ -359,10 +423,10 @@ function flip_report(report_id, flip_to_type, flip_to_subtype){ }); } -function load_data(limit=300, offset=1, q=''){ +function load_data(limit=300, offset=1, q='', seek=''){ lockui(); $.ajax({ - url: `/api/coarse_filter_reports/?limit=${limit}&offset=${offset}&q=${q}`, + url: `/api/coarse_filter_reports/?limit=${limit}&offset=${offset}&q=${q}&seek=${seek}`, type: "GET", dataType: "json", success: function(data) { @@ -387,6 +451,14 @@ function load_data(limit=300, offset=1, q=''){ init_maps(); load_previews(); set_visibility_icons(); + if(seek!=''){ + const report_bkm = $('#bkm_' + seek).data('report'); + $("#" + report_bkm).get(0).scrollIntoView(); + const filter = data.filter; + filter_to_ui(filter); + } + set_bookmarks(); + init_bookmarks(); }, error: function(jqXHR, textStatus, errorThrown){ unlockui(); @@ -413,6 +485,30 @@ function pictures_template(pictures){ return elements; } +function single_bookmark_template(bookmark){ + return ` + + ` +} + +function add_ui_bookmark(bookmark){ + const root = $('#bookmark_drawer'); + const single_bookmark = single_bookmark_template(bookmark); + root.append(single_bookmark); + bookmarks.push(bookmark); +} + +function remove_ui_bookmark(id){ + $('#bkm_' + id).remove(); + var new_bookmarks = []; + for(var i = 0; i < bookmarks.length; i++){ + if(bookmarks[i].id != id){ + new_bookmarks.push(bookmarks[i]) + } + } + bookmarks = new_bookmarks; +} + function single_report_template(report){ const pictures = pictures_template(report.photos); const report_country_name = report.country == null ? 'No country' : report.country.name_engl; @@ -434,6 +530,7 @@ function single_report_template(report){ } return `
+
@@ -568,6 +665,79 @@ $('#filters_clear').click( function(e){ load_data(page_size,1,filter); }); +function do_delete_bookmark(id, report_id){ + $.ajax({ + url: '/api/bookmark_report/', + data: { "id": id}, + type: "DELETE", + headers: { "X-CSRFToken": csrf_token }, + dataType: "json", + success: function(data) { + //apply_bookmark(report_id, label); + $('#' + report_id).removeClass('bookmarked'); + $('#bookmark_' + report_id).html(''); + remove_ui_bookmark(id); + }, + error: function(jqXHR, textStatus, errorThrown){ + //alert(jqXHR.responseJSON.message); + }, + cache: false + }); +} + +function do_create_bookmark(user_id, report_id, label){ + const filter = ui_to_filter(); + $.ajax({ + url: '/api/bookmark_report/', + data: { "report_id": report_id, "user_id": user_id, "label": label, "module": "coarse", "json_filter": filter}, + type: "POST", + headers: { "X-CSRFToken": csrf_token }, + dataType: "json", + success: function(data) { + apply_bookmark(data.id, report_id, label); + add_ui_bookmark(data); + }, + error: function(jqXHR, textStatus, errorThrown){ + alert(jqXHR.responseJSON.message); + }, + cache: false + }); +} + +function set_bookmarks(){ + for(var i=0; i < bookmarks.length; i++){ + apply_bookmark( bookmarks[i].id, bookmarks[i].report, bookmarks[i].label ); + } +} + +$('div#photo_grid').on('click', 'button.btn.btn-danger.btn-xs.btn-bookmark', function(){ + const report_id = $(this).data('id'); + if( $('#' + report_id).hasClass('bookmarked') ){ + if(confirm("Remove bookmark?")){ + do_delete_bookmark( $('#bookmark_' + report_id).data('bookmark'), report_id ); + } + }else{ + $('#bookmark_report_id').val(report_id); + $('#bookmark_label').val(''); + $('#modalBookmark').modal('show'); + //$('#' + report_id).addClass('bookmarked'); + } +}); + +function apply_bookmark(bookmark_id, report_id, label){ + $('#' + report_id).addClass('bookmarked'); + $('#bookmark_' + report_id).data('bookmark', bookmark_id); + $('#bookmark_' + report_id).html('' + escapeHtml(label)); + $('#modalBookmark').modal('hide'); +} + +$('#bookmark_submit_button').on('click',function(){ + const report_id = $('#bookmark_report_id').val(); + const label = $('#bookmark_label').val(); + //apply_bookmark(report_id, ' ' + label); + do_create_bookmark(_user_id, report_id, label); +}); + $('div#photo_grid').on('click', 'div.buttons_internal_grid button.btn.btn-primary.foot_btn.btn_hide_report', function(){ const report_id = $(this).data("report-id"); hide_or_show_report(report_id, "true"); @@ -687,18 +857,11 @@ $('div#photo_grid').on('click', 'div.buttons_internal_grid button.btn.btn-danger $('#flip_report_id').val( $(this).data("report-id") ); set_modal_defaults(); $('#modal_flip_to_site').modal('show'); - /* - if( type=='adult' ){ - $('#flip_to_type').val( "site" ); - $('#modal_flip_to_site').modal('show'); - }else{ - $('#flip_to_type').val( "adult" ); - const report_id = $(this).data("report-id"); - if(confirm("Site report will be flipped to adult report. Proceed?")){ - flip_report(report_id, 'adult', null); - } - } - */ +}); + +$('div#bookmark_drawer').on('click', 'button.btn.btn-danger.go_bookmark', function(){ + const page_size = get_page_size(); + load_data(page_size, 1, '', seek=$(this).data('id')); }); function map_init_basic(map, lat, lon) { @@ -750,8 +913,6 @@ $('#go_flip').on('click', function(){ const report_id = $('#flip_report_id').val(); const flip_to_type = $('#flip_to_type').val(); const flip_to_subtype = get_flip_to_subtype(); - //console.log(`${ flip_to_type } ${ site_cat }`); - //console.log(`${ flip_to_subtype }`); flip_report(report_id, flip_to_type, flip_to_subtype); }); diff --git a/tigacrafting/templates/tigacrafting/coarse_filter.html b/tigacrafting/templates/tigacrafting/coarse_filter.html index 24edb3b6..99f2b15a 100644 --- a/tigacrafting/templates/tigacrafting/coarse_filter.html +++ b/tigacrafting/templates/tigacrafting/coarse_filter.html @@ -1,7 +1,7 @@ {% load staticfiles %} {% load leaflet_tags %} - +
@@ -166,13 +166,16 @@ align-self: center; margin: auto; } + .bookmarked{ + outline: 0.5rem solid red; + } - + @@ -182,8 +185,11 @@ + + +