Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 32 additions & 31 deletions mapswipe_workers/mapswipe_workers/definitions.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
import os
import json
import logging
import logging.config
from logging.handlers import TimedRotatingFileHandler
import os

from mapswipe_workers.project_types.build_area.build_area_project import (
BuildAreaProject,
)
from mapswipe_workers.project_types.change_detection.change_detection_project import (
ChangeDetectionProject,
)
from mapswipe_workers.project_types.footprint.footprint_project import FootprintProject

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))

CONFIG_DIR = os.path.abspath(
'/usr/share/config/mapswipe_workers/'
)

CONFIG_PATH = os.path.join(
CONFIG_DIR,
'configuration.json'
)

SERVICE_ACCOUNT_KEY_PATH = os.path.join(
CONFIG_DIR,
'serviceAccountKey.json'
)

LOGGING_CONFIG_PATH = os.path.join(
CONFIG_DIR,
'logging.cfg'
)

DATA_PATH = os.path.abspath(
'/var/lib/mapswipe_workers/'
)

logging.config.fileConfig(
fname=LOGGING_CONFIG_PATH,
disable_existing_loggers=True
)
logger = logging.getLogger('Mapswipe Workers')
CONFIG_DIR = os.path.abspath("/usr/share/config/mapswipe_workers/")

CONFIG_PATH = os.path.join(CONFIG_DIR, "configuration.json")

SERVICE_ACCOUNT_KEY_PATH = os.path.join(CONFIG_DIR, "serviceAccountKey.json")

LOGGING_CONFIG_PATH = os.path.join(CONFIG_DIR, "logging.cfg")

DATA_PATH = os.path.abspath("/var/lib/mapswipe_workers/")

PROJECT_TYPE_CLASSES = {
1: BuildAreaProject,
2: FootprintProject,
3: ChangeDetectionProject,
}

PROJECT_TYPE_NAMES = {
1: BuildAreaProject.project_type_name,
2: FootprintProject.project_type_name,
3: ChangeDetectionProject.project_type_name,
}

logging.config.fileConfig(fname=LOGGING_CONFIG_PATH, disable_existing_loggers=True)
logger = logging.getLogger("Mapswipe Workers")


class CustomError(Exception):
Expand Down
40 changes: 13 additions & 27 deletions mapswipe_workers/mapswipe_workers/mapswipe_workers.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
import ast
import json
import time

import click
import schedule as sched
import json
import ast

from mapswipe_workers.definitions import CustomError
from mapswipe_workers.definitions import logger
from mapswipe_workers.utils import slack
from mapswipe_workers.utils import sentry

from mapswipe_workers import auth
from mapswipe_workers.generate_stats import generate_stats
from mapswipe_workers.firebase_to_postgres import transfer_results
from mapswipe_workers.firebase_to_postgres import update_data
from mapswipe_workers.project_types.build_area.build_area_project import (
BuildAreaProject,
from mapswipe_workers.definitions import (
PROJECT_TYPE_CLASSES,
PROJECT_TYPE_NAMES,
CustomError,
logger,
)
from mapswipe_workers.firebase_to_postgres import transfer_results, update_data
from mapswipe_workers.generate_stats import generate_stats
from mapswipe_workers.project_types.build_area import build_area_tutorial
from mapswipe_workers.project_types.footprint.footprint_project import FootprintProject
from mapswipe_workers.project_types.change_detection.change_detection_project import (
ChangeDetectionProject,
)
from mapswipe_workers.project_types.change_detection import change_detection_tutorial
from mapswipe_workers.utils import user_management
from mapswipe_workers.utils import sentry, slack, user_management


class PythonLiteralOption(click.Option):
Expand Down Expand Up @@ -346,14 +340,6 @@ def _run():


def _run_create_projects(project_draft_ids=None):
project_types = {
# Make sure to import all project types here
1: BuildAreaProject,
2: FootprintProject,
3: ChangeDetectionProject,
}
project_type_names = {1: "Build Area", 2: "Footprint", 3: "Change Detection"}

fb_db = auth.firebaseDB()
ref = fb_db.reference("v2/projectDrafts/")
project_drafts = ref.get()
Expand Down Expand Up @@ -381,7 +367,7 @@ def _run_create_projects(project_draft_ids=None):
project_type = project_draft.get("projectType", 1)
try:
# TODO: Document properly
project = project_types[project_type](project_draft)
project = PROJECT_TYPE_CLASSES[project_type](project_draft)
project.geometry = project.validate_geometries()
project.create_groups()
project.calc_required_results()
Expand All @@ -392,7 +378,7 @@ def _run_create_projects(project_draft_ids=None):
f"### PROJECT CREATION SUCCESSFUL ###{newline}"
f"Project Name: {project.name}{newline}"
f"Project Id: {project.projectId}{newline}"
f"Project Type: {project_type_names[project_type]}"
f"Project Type: {PROJECT_TYPE_NAMES[project_type]}"
f"{newline}"
f"Make sure to activate the project "
f"using the manager dashboard."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class BuildAreaProject(BaseProject):
The subclass for an import of the type Footprint
"""

projectType = 1
project_type = 1
project_type_name = "Build Area"

def __init__(self, project_draft):
# this will create the basis attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class ChangeDetectionProject(BaseProject):
The subclass for an import of the type Footprint
"""

projectType = 1
project_type = 3
project_type_name = "Change Detection"

def __init__(self, project_draft):
# this will create the basis attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,56 @@
from mapswipe_workers.definitions import logger
from mapswipe_workers.base.base_project import BaseProject
from mapswipe_workers.project_types.footprint import grouping_functions as g
from mapswipe_workers.project_types.footprint.footprint_group \
import FootprintGroup
from mapswipe_workers.project_types.footprint.footprint_group import FootprintGroup


class FootprintProject(BaseProject):
"""
The subclass for an import of the type Footprint
"""

projectType = 2
project_type = 2
project_type_name = "Footprint"

def __init__(self, project_draft):
# this will create the basis attributes
super().__init__(project_draft)

# set group size
self.groupSize = project_draft['groupSize']
self.inputGeometries = project_draft['inputGeometries']
self.tileServer = self.get_tile_server(project_draft['tileServer'])
self.groupSize = project_draft["groupSize"]
self.inputGeometries = project_draft["inputGeometries"]
self.tileServer = self.get_tile_server(project_draft["tileServer"])

def validate_geometries(self):
raw_input_file = (
f'{DATA_PATH}/'
f'input_geometries/raw_input_{self.projectId}.geojson'
)
f"{DATA_PATH}/" f"input_geometries/raw_input_{self.projectId}.geojson"
)
valid_input_file = (
f'{DATA_PATH}/'
f'input_geometries/valid_input_{self.projectId}.geojson'
)
f"{DATA_PATH}/" f"input_geometries/valid_input_{self.projectId}.geojson"
)

if not os.path.isdir('{}/input_geometries'.format(DATA_PATH)):
os.mkdir('{}/input_geometries'.format(DATA_PATH))
if not os.path.isdir("{}/input_geometries".format(DATA_PATH)):
os.mkdir("{}/input_geometries".format(DATA_PATH))

# download file from given url
url = self.inputGeometries
urllib.request.urlretrieve(url, raw_input_file)
logger.info(
f'{self.projectId}'
f' - __init__ - '
f'downloaded input geometries from url and saved as file: '
f'{raw_input_file}'
)
f"{self.projectId}"
f" - __init__ - "
f"downloaded input geometries from url and saved as file: "
f"{raw_input_file}"
)
self.inputGeometries = raw_input_file

# open the raw input file and get layer
driver = ogr.GetDriverByName('GeoJSON')
driver = ogr.GetDriverByName("GeoJSON")
datasource = driver.Open(raw_input_file, 0)
try:
layer = datasource.GetLayer()
LayerDefn = layer.GetLayerDefn()
except AttributeError:
raise CustomError('Value error in input geometries file')
raise CustomError("Value error in input geometries file")

# create layer for valid_input_file to store all valid geometries
outDriver = ogr.GetDriverByName("GeoJSON")
Expand All @@ -67,21 +65,18 @@ def validate_geometries(self):
outDriver.DeleteDataSource(valid_input_file)
outDataSource = outDriver.CreateDataSource(valid_input_file)
outLayer = outDataSource.CreateLayer(
"geometries",
geom_type=ogr.wkbMultiPolygon
)
"geometries", geom_type=ogr.wkbMultiPolygon
)
for i in range(0, LayerDefn.GetFieldCount()):
fieldDefn = LayerDefn.GetFieldDefn(i)
outLayer.CreateField(fieldDefn)
outLayerDefn = outLayer.GetLayerDefn()

# check if raw_input_file layer is empty
if layer.GetFeatureCount() < 1:
err = 'empty file. No geometries provided'
err = "empty file. No geometries provided"
# TODO: How to user logger and exceptions?
logger.warning(
f'{self.projectId} - check_input_geometry - {err}'
)
logger.warning(f"{self.projectId} - check_input_geometry - {err}")
raise Exception(err)

# get geometry as wkt
Expand All @@ -106,37 +101,36 @@ def validate_geometries(self):
if not feat_geom.IsValid():
layer.DeleteFeature(fid)
logger.warning(
f'{self.projectId}'
f' - check_input_geometries - '
f'deleted invalid feature {fid}'
)
f"{self.projectId}"
f" - check_input_geometries - "
f"deleted invalid feature {fid}"
)

# we accept only POLYGON or MULTIPOLYGON geometries
elif geom_name != 'POLYGON' and geom_name != 'MULTIPOLYGON':
elif geom_name != "POLYGON" and geom_name != "MULTIPOLYGON":
layer.DeleteFeature(fid)
logger.warning(
f'{self.projectId}'
f' - check_input_geometries - '
f'deleted non polygon feature {fid}'
)
f"{self.projectId}"
f" - check_input_geometries - "
f"deleted non polygon feature {fid}"
)

else:
# Create output Feature
outFeature = ogr.Feature(outLayerDefn)
# Add field values from input Layer
for i in range(0, outLayerDefn.GetFieldCount()):
outFeature.SetField(
outLayerDefn.GetFieldDefn(i).GetNameRef(),
feature.GetField(i)
)
outLayerDefn.GetFieldDefn(i).GetNameRef(), feature.GetField(i)
)
outFeature.SetGeometry(feat_geom)
outLayer.CreateFeature(outFeature)
outFeature = None

# check if layer is empty
if layer.GetFeatureCount() < 1:
err = 'no geometries left after checking validity and geometry type.'
logger.warning(f'{self.projectId} - check_input_geometry - {err}')
err = "no geometries left after checking validity and geometry type."
logger.warning(f"{self.projectId} - check_input_geometry - {err}")
raise Exception(err)

del datasource
Expand All @@ -146,30 +140,25 @@ def validate_geometries(self):
self.validInputGeometries = valid_input_file

logger.info(
f'{self.projectId}'
f' - check_input_geometry - '
f'filtered correct input geometries and created file: '
f'{valid_input_file}'
)
f"{self.projectId}"
f" - check_input_geometry - "
f"filtered correct input geometries and created file: "
f"{valid_input_file}"
)
return wkt_geometry

def create_groups(self):
"""
The function to create groups of footprint geometries
"""

raw_groups = g.group_input_geometries(
self.validInputGeometries,
self.groupSize
)
raw_groups = g.group_input_geometries(self.validInputGeometries, self.groupSize)

for group_id, item in raw_groups.items():
group = FootprintGroup(self, group_id)
group.create_tasks(item['feature_ids'], item['feature_geometries'])
group.create_tasks(item["feature_ids"], item["feature_geometries"])
self.groups.append(group)

logger.info(
f'{self.projectId} '
f'- create_groups - '
f'created groups dictionary'
)
f"{self.projectId} " f"- create_groups - " f"created groups dictionary"
)