Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forbid to split tasks with zoom level >=18 or area < 25k m2 #4055

Merged
merged 3 commits into from
Jan 19, 2021
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
7 changes: 7 additions & 0 deletions backend/models/postgis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ class ST_Area(GenericFunction):
type = None


class ST_GeogFromWKB(GenericFunction):
""" Exposes PostGIS ST_GeogFromWKB function """

name = "ST_GeogFromWKB"
type = None


class ST_Buffer(GenericFunction):
""" Exposes PostGIS ST_Buffer function """

Expand Down
12 changes: 11 additions & 1 deletion backend/services/grid/split_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from geoalchemy2 import shape
from backend.models.dtos.grid_dto import SplitTaskDTO
from backend.models.dtos.mapping_dto import TaskDTOs
from backend.models.postgis.utils import ST_Transform
from backend.models.postgis.utils import ST_Transform, ST_Area, ST_GeogFromWKB
from backend.models.postgis.task import Task, TaskStatus, TaskAction
from backend.models.postgis.project import Project
from backend.models.postgis.utils import NotFound, InvalidGeoJson
Expand Down Expand Up @@ -171,6 +171,16 @@ def split_task(split_task_dto: SplitTaskDTO) -> TaskDTOs:

original_geometry = shape.to_shape(original_task.geometry)

# Fetch the task geometry in meters
original_task_area_m = db.engine.execute(
ST_Area(ST_GeogFromWKB(original_task.geometry))
).scalar()

if (
original_task.zoom and original_task.zoom >= 18
) or original_task_area_m < 25000:
raise SplitServiceError("Task is too small to be split")

# check its locked for mapping by the current user
if TaskStatus(original_task.task_status) != TaskStatus.LOCKED_FOR_MAPPING:
raise SplitServiceError("Status must be LOCKED_FOR_MAPPING to split")
Expand Down
43 changes: 39 additions & 4 deletions frontend/src/components/taskSelection/actionSidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function CompletionTabForMapping({
const token = useSelector((state) => state.auth.get('token'));
const [showHelp, setShowHelp] = useState(false);
const [showMapChangesModal, setShowMapChangesModal] = useState(false);
const [splitTaskError, setSplitTaskError] = useState(false);
const radioInput = 'radio-input input-reset pointer v-mid dib h2 w2 mr2 br-100 ba b--blue-light';
const fetchLockedTasks = useFetchLockedTasks();
const clearLockedTasks = useClearLockedTasks();
Expand All @@ -48,10 +49,14 @@ export function CompletionTabForMapping({
`projects/${project.projectId}/tasks/actions/split/${tasksIds[0]}/`,
token,
'POST',
).then((r) => {
clearLockedTasks();
navigate(`../tasks/`);
});
)
.then((r) => {
clearLockedTasks();
navigate(`../tasks/`);
})
.catch((e) => {
setSplitTaskError(true);
});
} else {
setShowMapChangesModal('split');
}
Expand Down Expand Up @@ -107,6 +112,17 @@ export function CompletionTabForMapping({
{(close) => <UnsavedMapChangesModalContent close={close} action={showMapChangesModal} />}
</Popup>
)}
{splitTaskError && (
<Popup
modal
open
closeOnEscape={true}
closeOnDocumentClick={true}
onClose={() => setSplitTaskError(false)}
>
{(close) => <TaskSplitErrorModalContent close={close} />}
</Popup>
)}
{showReadCommentsAlert && (
<div
className="tc pa2 mb1 bg-grey-light blue-dark pointer"
Expand Down Expand Up @@ -444,6 +460,25 @@ function UnsavedMapChangesModalContent({ close, action }: Object) {
);
}

function TaskSplitErrorModalContent({ close }: Object) {
return (
<div className="blue-dark bg-white pv2 pv4-ns ph2 ph4-ns tc">
<div className="cf tc orange pb3">
<AlertIcon height="50px" width="50px" />
</div>
<h3 className="barlow-condensed f3 fw6 mv0">
<FormattedMessage {...messages.splitTaskError} />
</h3>
<div className="mv4 lh-title">
<FormattedMessage {...messages.splitTaskErrorDescription} />
</div>
<Button className="bg-red white" onClick={() => close()}>
<FormattedMessage {...messages.closeModal} />
</Button>
</div>
);
}

function TaskSpecificInstructions({ instructions, open = true }: Object) {
const [isOpen, setIsOpen] = useState(open);
return (
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/components/taskSelection/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,14 @@ export default defineMessages({
id: 'project.tasks.action.split_task',
defaultMessage: 'Split task',
},
splitTaskError: {
id: 'project.tasks.action.split_task.error',
defaultMessage: 'It was not possible to split the task',
},
splitTaskErrorDescription: {
id: 'project.tasks.action.split_task.error.description',
defaultMessage: 'This task is already too small and can not be split.',
},
selectAnotherTask: {
id: 'project.tasks.action.select_another_task',
defaultMessage: 'Select another task',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,8 @@
"project.tasks.action.options.incomplete": "No",
"project.tasks.action.options.bad_imagery": "The imagery is bad",
"project.tasks.action.split_task": "Split task",
"project.tasks.action.split_task.error": "It was not possible to split the task",
"project.tasks.action.split_task.error.description": "This task is already too small and can not be split.",
"project.tasks.action.select_another_task": "Select another task",
"project.tasks.action.stop_validation": "Stop validation",
"project.tasks.action.tasks_map": "Tasks map",
Expand Down