diff --git a/deployment/.env b/deployment/.env index c78c3f8..31c0bd8 100644 --- a/deployment/.env +++ b/deployment/.env @@ -248,7 +248,7 @@ PYTHONPATH=/home/web/django_project:/geonode USE_DEFAULT_GEOSERVER_STYLE=False INITIAL_FIXTURES=True -VERSION=4.4.5 +VERSION=4.4.6 ISTSOS_VERSION=2.4.1-2 # ------ GEOSERVER ------ diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index efee098..fa7ba29 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -59,9 +59,6 @@ services: # Geoserver backend geoserver: - # TODO: - # Using older geoserver - # image: kartoza/sadc_gip:geoserver-3.1.netcfd image: kartoza/geoserver:2.23.0-geo-v2023.09.15 healthcheck: test: "curl --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://127.0.0.1:8080/geoserver/rest/workspaces/geonode.html" @@ -71,11 +68,6 @@ services: start_period: 60s env_file: - .env - - # TODO: - # Uncomment this if using netcfd - # environment: - # - DATABASE_URL=postgres://geonode:geonode@db:5432/geonode volumes: - geodatadir:/spcgeonode-geodatadir/ ports: @@ -105,7 +97,7 @@ services: - POSTGRES_USER=${GEONODE_DATABASE_USER} - POSTGRES_PASSWORD=${GEONODE_DATABASE_PASSWORD} volumes: - - database:/var/lib/postgresql/16/ + - ./volumes/database:/var/lib/postgresql/16/ - ./backups:/backups restart: on-failure ports: diff --git a/django_project/gwml2 b/django_project/gwml2 index e802410..40746ec 160000 --- a/django_project/gwml2 +++ b/django_project/gwml2 @@ -1 +1 @@ -Subproject commit e80241077d4d149e857055bc105ba937741fa96a +Subproject commit 40746ecc11cc2d9d033ec59bb21102e2bd619ddd diff --git a/django_project/igrac/admin.py b/django_project/igrac/admin.py index 5a6740c..a8b4b81 100644 --- a/django_project/igrac/admin.py +++ b/django_project/igrac/admin.py @@ -1,6 +1,7 @@ from adminsortable.admin import SortableAdmin from django.contrib import admin from django.http import HttpResponseRedirect +from django.urls import reverse from django.utils.html import format_html from django.utils.translation import ugettext_lazy as _ from preferences.admin import PreferencesAdmin @@ -15,6 +16,7 @@ from igrac.models.groundwater_layer import GroundwaterLayer from igrac.models.map_slug import MapSlugMapping from igrac.models.profile import IgracProfile +from igrac.models.registration_page import RegistrationPage from igrac.models.site_preference import SitePreference @@ -118,3 +120,25 @@ def _organisations(self, obj: GroundwaterLayer): admin.site.register(GroundwaterLayer, GroundwaterLayerAdmin) + + +class RegistrationPageAdmin(admin.ModelAdmin): + list_display = ('code', 'user', 'created_at', 'url') + readonly_fields = ('code', 'user', 'created_at', 'url') + + def url(self, obj: RegistrationPage): + """Return registration url.""" + if obj.user: + return 'Link is not valid' + if obj.code: + url = reverse( + 'account_signup_with_code', + kwargs={'code': obj.code} + ) + return format_html( + f'Registration URL' + ) + return '-' + + +admin.site.register(RegistrationPage, RegistrationPageAdmin) diff --git a/django_project/igrac/forms/groundwater_layer.py b/django_project/igrac/forms/groundwater_layer.py index b93ec33..dc754dd 100644 --- a/django_project/igrac/forms/groundwater_layer.py +++ b/django_project/igrac/forms/groundwater_layer.py @@ -1,3 +1,4 @@ +import time import xml.etree.ElementTree as ET import requests @@ -81,14 +82,14 @@ def update_sql(self, tree): elif well_type == GGMN: mv = 'mv_well_ggmn' sql = ( - "select id, ggis_uid, original_id, name, feature_type,purpose, status, organisation, " - 'number_of_measurements_level as "groundwater_level_data", ' - 'number_of_measurements_quality as "groundwater_quality_data", ' - 'number_of_measurements_yield as "abstraction_discharge", ' - "country, year_of_drilling, aquifer_name, aquifer_type,manager, detail, location, created_at, created_by, last_edited_at, last_edited_by " - f"from {mv} where organisation_id IN (" + - f"{','.join(organisations)}" + - ") order by created_at DESC" + "select id, ggis_uid, original_id, name, feature_type,purpose, status, organisation, " + 'number_of_measurements_level as "groundwater_level_data", ' + 'number_of_measurements_quality as "groundwater_quality_data", ' + 'number_of_measurements_yield as "abstraction_discharge", ' + "country, year_of_drilling, aquifer_name, aquifer_type,manager, detail, location, created_at, created_by, last_edited_at, last_edited_by " + f"from {mv} where organisation_id IN (" + + f"{','.join(organisations)}" + + ") order by created_at DESC" ) tree.find('metadata/entry/virtualTable/sql').text = sql @@ -101,6 +102,7 @@ class CreateGroundwaterLayerForm(_BaseGroundwaterLayerForm): help_text='The layer name that will be created.', widget=forms.TextInput(attrs={'style': 'width:500px'}) ) + loop = 1 def clean_well_type(self): """Well type.""" @@ -143,6 +145,29 @@ def clean_name(self): ) return name + def get_dataset( + self, target_layer_name, workspace, store + ): + """Get dataset.""" + if self.loop < 10: + call_command('updatelayers', filter=target_layer_name) + try: + dataset = Dataset.objects.get( + workspace=workspace, store=store, name=target_layer_name + ) + if dataset and self.target_layer: + dataset.use_featureinfo_custom_template = self.target_layer.use_featureinfo_custom_template + dataset.featureinfo_custom_template = self.target_layer.featureinfo_custom_template + dataset.save() + + return dataset + except Dataset.DoesNotExist: + time.sleep(2) + self.loop += 1 + return self.get_dataset(target_layer_name, workspace, store) + else: + return None + def run(self): """Run it for duplication data.""" name = self.cleaned_data['name'] @@ -197,19 +222,7 @@ def run(self): if style: layer.default_style = style gs_catalog.save(layer) - call_command('updatelayers', filter=target_layer_name) - try: - dataset = Dataset.objects.get( - workspace=workspace, store=store, name=target_layer_name - ) - if dataset and self.target_layer: - dataset.use_featureinfo_custom_template = self.target_layer.use_featureinfo_custom_template - dataset.featureinfo_custom_template = self.target_layer.featureinfo_custom_template - dataset.save() - - return dataset - except Dataset.DoesNotExist: - return None + return self.get_dataset(target_layer_name, workspace, store) else: raise Exception(r.content) diff --git a/django_project/igrac/migrations/0011_registrationpage.py b/django_project/igrac/migrations/0011_registrationpage.py new file mode 100644 index 0000000..9906e7c --- /dev/null +++ b/django_project/igrac/migrations/0011_registrationpage.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.20 on 2024-02-23 06:10 + +import datetime +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('igrac', '0010_alter_groundwaterlayer_options'), + ] + + operations = [ + migrations.CreateModel( + name='RegistrationPage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.TextField(max_length=16, unique=True)), + ('created_at', models.DateTimeField(blank=True, default=datetime.datetime.now)), + ('note', models.TextField(blank=True, null=True)), + ('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/django_project/igrac/models/groundwater_layer.py b/django_project/igrac/models/groundwater_layer.py index b57b197..6a46782 100644 --- a/django_project/igrac/models/groundwater_layer.py +++ b/django_project/igrac/models/groundwater_layer.py @@ -1,5 +1,7 @@ from django.contrib.gis.db import models from django.contrib.postgres.fields import ArrayField +from django.db.models.signals import post_delete +from django.dispatch import receiver from geonode.layers.models import Dataset from igrac.models.site_preference import SitePreference @@ -29,3 +31,11 @@ def assign_template(self, target_layer=None): layer.use_featureinfo_custom_template = target_layer.use_featureinfo_custom_template layer.featureinfo_custom_template = target_layer.featureinfo_custom_template layer.save() + + +@receiver(post_delete, sender=GroundwaterLayer) +def groundwater_layer_deleted( + sender, instance: GroundwaterLayer, using, **kwargs +): + if instance.layer: + instance.layer.delete() diff --git a/django_project/igrac/models/registration_page.py b/django_project/igrac/models/registration_page.py new file mode 100644 index 0000000..a315a92 --- /dev/null +++ b/django_project/igrac/models/registration_page.py @@ -0,0 +1,48 @@ +"""Registration page that needs to be used for register.""" + +import random +import string +from datetime import datetime + +from django.contrib.auth import get_user_model +from django.db import models + +User = get_user_model() + + +def id_generator( + size=36, + chars=string.ascii_letters + string.digits + '+_-' +): + """ID Generator.""" + return ''.join(random.choice(chars) for _ in range(size)) + + +class RegistrationPage(models.Model): + """Registration page that has random uuid. + + User can just register through this model. + When user is created through this page, it will be invalid + and need to create new one. + """ + + user = models.OneToOneField( + User, on_delete=models.SET_NULL, + blank=True, null=True + ) + code = models.TextField(max_length=16, unique=True) + created_at = models.DateTimeField( + default=datetime.now, blank=True + ) + note = models.TextField( + blank=True, null=True + ) + + def __str__(self): + return str(self.code) + + def save(self, *args, **kwargs): + """Save model.""" + if not self.code: + self.code = id_generator() + return super().save(*args, **kwargs) diff --git a/django_project/igrac/templates/account/signup-not-found.html b/django_project/igrac/templates/account/signup-not-found.html new file mode 100644 index 0000000..804510a --- /dev/null +++ b/django_project/igrac/templates/account/signup-not-found.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% load i18n %} +{% load static %} +{% load bootstrap_tags %} +{% load igrac_bootstrap_tags %} + +{% block page_title %} +