Skip to content

Commit 750457b

Browse files
[Fixes #12369] Create a command to regenerate the XML metadata (#12396) (#12401)
(cherry picked from commit cc3816d) Co-authored-by: Emanuele Tajariol <etj@geo-solutions.it>
1 parent 5ebe7fc commit 750457b

File tree

5 files changed

+165
-2
lines changed

5 files changed

+165
-2
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import logging
2+
from django.conf import settings
3+
4+
DEFAULT_COMMAND_LOGGER_NAME = "geonode.commands"
5+
6+
7+
def setup_logger(logger_name=DEFAULT_COMMAND_LOGGER_NAME, formatter_name="command", handler_name="command"):
8+
if logger_name not in settings.LOGGING["loggers"]:
9+
format = "%(levelname)-7s %(asctime)s %(message)s"
10+
11+
settings.LOGGING["formatters"][formatter_name] = {
12+
"format": format
13+
}
14+
settings.LOGGING["handlers"][handler_name] = {
15+
"level": "DEBUG",
16+
"class": "logging.StreamHandler",
17+
"formatter": formatter_name
18+
}
19+
settings.LOGGING["loggers"][logger_name] = {
20+
"handlers": [handler_name],
21+
"level": "INFO",
22+
"propagate": False
23+
}
24+
25+
handler = logging.StreamHandler()
26+
handler.setFormatter(logging.Formatter(fmt=format))
27+
handler.setLevel(logging.DEBUG)
28+
29+
logger = logging.getLogger(logger_name)
30+
logger.addHandler(handler)
31+
logger.setLevel(logging.INFO)
32+
logger.propagate = False
33+
34+
return logger

geonode/catalogue/management/__init__.py

Whitespace-only changes.

geonode/catalogue/management/commands/__init__.py

Whitespace-only changes.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# -*- coding: utf-8 -*-
2+
#########################################################################
3+
#
4+
# Copyright (C) 2023 OSGeo
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
#########################################################################
20+
21+
import logging
22+
23+
from django.core.management.base import BaseCommand
24+
25+
from geonode.base.management import command_utils
26+
from geonode.base.models import ResourceBase
27+
from geonode.layers.models import Dataset
28+
29+
30+
logger = logging.getLogger(__name__)
31+
32+
33+
class Command(BaseCommand):
34+
help = "Re-create XML metadata documents"
35+
36+
def add_arguments(self, parser):
37+
parser.add_argument(
38+
'-l',
39+
'--layer',
40+
dest="layers",
41+
action='append',
42+
help="Only process specified layers ")
43+
44+
parser.add_argument(
45+
"--skip-logger-setup",
46+
action="store_false",
47+
dest="setup_logger",
48+
help='Skips setup of the "geonode.br" logger, "br" handler and "br" format if not present in settings',
49+
)
50+
parser.add_argument(
51+
'-d',
52+
'--dry-run',
53+
dest="dry-run",
54+
action='store_true',
55+
help="Do not actually perform any change")
56+
57+
def handle(self, **options):
58+
requested_layers = options.get('layers')
59+
dry_run = options.get('dry-run')
60+
61+
if options.get("setup_logger"):
62+
logger = command_utils.setup_logger()
63+
64+
logger.info(f"==== Running command {__name__}")
65+
logger.info(f"{self.help}")
66+
logger.info("")
67+
68+
logger.debug(f"DRY-RUN is {dry_run}")
69+
logger.debug(f"LAYERS is {requested_layers}")
70+
71+
try:
72+
73+
layers = Dataset.objects.all()
74+
tot = len(layers)
75+
logger.info(f"Total layers in GeoNode: {tot}")
76+
i = 0
77+
cnt_ok = 0
78+
cnt_bad = 0
79+
cnt_skip = 0
80+
81+
instance: ResourceBase
82+
for instance in layers:
83+
i += 1
84+
logger.info(f"- {i}/{tot} Processing layer {instance.id} [{instance.typename}] '{instance.title}'")
85+
86+
if requested_layers and instance.typename not in requested_layers:
87+
logger.info(" - Layer filtered out by args")
88+
cnt_skip += 1
89+
continue
90+
91+
if instance.metadata_uploaded and instance.metadata_uploaded_preserve:
92+
logger.info(" - Layer filtered out since it uses custom XML")
93+
cnt_skip += 1
94+
continue
95+
96+
try:
97+
good = None
98+
if not dry_run:
99+
try:
100+
try:
101+
# the save() method triggers the metadata regeneration
102+
instance.save()
103+
good = True
104+
except Exception as e:
105+
logger.error(f"Error saving instance '{instance.title}': {e}")
106+
raise e
107+
108+
except Exception as e:
109+
logger.exception(f"Error processing '{instance.title}': {e}", e)
110+
111+
if dry_run or good:
112+
logger.info(f" - Done {instance.name}")
113+
cnt_ok += 1
114+
else:
115+
logger.warning(f"Metadata couldn't be regenerated for instance '{instance.title}' ")
116+
cnt_bad += 1
117+
118+
except Exception as e:
119+
raise e
120+
except Exception as e:
121+
raise e
122+
123+
logger.info("Work completed" + (" [DRYRUN]" if dry_run else ""))
124+
logger.info(f"- Metadata regenerated : {cnt_ok}")
125+
logger.info(f"- Metadata in error : {cnt_bad}")
126+
logger.info(f"- Resources skipped : {cnt_skip}")

geonode/catalogue/models.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,14 @@ def catalogue_post_save(instance, sender, **kwargs):
8080
resource=resources.get(), url=metadata_url, extension="xml", link_type="metadata"
8181
).update(**_d)
8282

83-
# generate an XML document (GeoNode's default is ISO)
8483
if instance.metadata_uploaded and instance.metadata_uploaded_preserve:
8584
md_doc = etree.tostring(dlxml.fromstring(instance.metadata_xml))
8685
else:
87-
md_doc = catalogue.catalogue.csw_gen_xml(instance, settings.CATALOG_METADATA_TEMPLATE)
86+
# generate an XML document (GeoNode's default is ISO)
87+
raw_xml = catalogue.catalogue.csw_gen_xml(instance, settings.CATALOG_METADATA_TEMPLATE)
88+
md_obj = dlxml.fromstring(raw_xml, parser=etree.XMLParser(remove_blank_text=True))
89+
md_doc = etree.tostring(md_obj, pretty_print=True, encoding="unicode")
90+
8891
try:
8992
csw_anytext = catalogue.catalogue.csw_gen_anytext(md_doc)
9093
except Exception as e:

0 commit comments

Comments
 (0)