Skip to content

Commit

Permalink
Enforce Random Task Selection
Browse files Browse the repository at this point in the history
* Add optional setting to Enforce Random Task Selection in the project's edit page

* If Enforce Random Task Selection is enabled, users will not be able to manually select tasks. They will be required to use the "Select A Random Task" button (does not apply to pm/admins)

* Errors appear if they try to select a task from the map

Closes #1583
  • Loading branch information
Zack LaVergne committed Jun 26, 2019
1 parent 78e05c8 commit 48d7e34
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 4 deletions.
7 changes: 7 additions & 0 deletions client/app/admin/edit-project/edit-project.html
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,13 @@ <h1 class="section__aside-title">{{ 'In this area' | translate }}</h1>
{{ 'You need at least one validation editor.' | translate }}
</p>
</div>
<div class="form__group form__group--section">
<label class="form__label">{{ 'Enforce Random Task Selection' | translate }}</label>
<label class="form__option">
<input ng-model="editProjectCtrl.project.enforceRandomTaskSelection" type="checkbox"/>{{ 'Enforce random task selection on mapping' | translate }}
</label>
<p>{{ 'If checked, users must edit tasks at random for the initial editing stage (project managers and admins are exempt). ' | translate }}</p>
</div>
</fieldset>
</div>
<!--/ settings -->
Expand Down
16 changes: 16 additions & 0 deletions client/app/project/project.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
vm.taskCommentError = false;
vm.taskCommentErrorMessage = '';
vm.wasAutoUnlocked = false;
vm.randomTaskSelectionError = false;

//authorization
vm.isAuthorized = false;
Expand Down Expand Up @@ -332,6 +333,10 @@
vm.mappingStep = 'selecting';
vm.validatingStep = 'selecting';
}

if (vm.enforceRandomTaskSelection()) {
vm.randomTaskSelectionError = false;
}
};

vm.selectRandomTaskValidate = function () {
Expand Down Expand Up @@ -409,6 +414,9 @@
vm.map.addInteraction(vm.selectInteraction);
vm.selectInteraction.on('select', function (event) {
$scope.$apply(function () {
if (vm.enforceRandomTaskSelection()) {
vm.randomTaskSelectionError = true;
}
var feature = event.selected[0];
onTaskSelection(feature);
});
Expand Down Expand Up @@ -591,6 +599,10 @@
if ($location.search().task) {
selectTaskById($location.search().task);
}

if (vm.projectData.enforceRandomTaskSelection && vm.user.role !== 'ADMIN' && vm.user.role !== 'PROJECT_MANAGER') {
vm.randomTaskSelectionError = true;
}
}, function () {
// project not returned successfully
vm.loaded = true;
Expand Down Expand Up @@ -751,6 +763,10 @@
// for each task in features, update source
}

vm.enforceRandomTaskSelection = function() {
return vm.projectData && vm.projectData.enforceRandomTaskSelection && vm.user.role !== 'ADMIN' && vm.user.role !== 'PROJECT_MANAGER';
};

/**
* Updates the data for mapped tasks by user
* @param projectId
Expand Down
23 changes: 19 additions & 4 deletions client/app/project/project.html
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ <h3>{{ 'Choose a task' | translate }}</h3>
role="alert">
<p>{{ 'You cannot select tasks for mapping on this project because you do not have the required mapper experience level.' | translate }}</p>
</div>
<div ng-show="projectCtrl.user && projectCtrl.userCanMap">
<div ng-show="projectCtrl.user && projectCtrl.userCanMap && !projectCtrl.enforceRandomTaskSelection()">
<p>{{ 'Choose a task for mapping:' | translate }}</p>

<dl class="definition-list--options">
Expand All @@ -283,6 +283,13 @@ <h3>{{ 'Choose a task' | translate }}</h3>
</div>
</div>
</div>
<div ng-show="projectCtrl.user && projectCtrl.userCanMap && projectCtrl.enforceRandomTaskSelection()">
<p>{{ 'You must randomly select tasks' | translate }}</p>
<button ng-click="projectCtrl.selectRandomTaskMap()"
class="button pull-center">
{{ 'Select a random task' | translate }}
</button>
</div>
<div ng-show="projectCtrl.taskErrorMapping === 'task-get-error'"
class="alert alert--danger"
role="alert">
Expand Down Expand Up @@ -347,7 +354,7 @@ <h3 style="display: inline-block;">{{ 'Mapping' | translate }}</h3>
</div>
<div ng-hide="projectCtrl.taskLockError">
<div ng-show="projectCtrl.selectedTaskData ">
<div ng-show="projectCtrl.isSelectedMappable && !projectCtrl.taskLockError && projectCtrl.userCanMap"
<div ng-show="projectCtrl.isSelectedMappable && !projectCtrl.taskLockError && projectCtrl.userCanMap && !projectCtrl.enforceRandomTaskSelection()"
class="alert alert--success"
role="alert">
<p>{{ 'This task is available for mapping.' | translate }}</p>
Expand Down Expand Up @@ -380,7 +387,7 @@ <h3 style="display: inline-block;">{{ 'Mapping' | translate }}</h3>
</div>
<!-- task action buttons -->
<div class="form__group form__group--section">
<div>
<div ng-show="!(projectCtrl.enforceRandomTaskSelection() && projectCtrl.randomTaskSelectionError)">
<button ng-show="projectCtrl.isSelectedMappable && !projectCtrl.taskLockError && projectCtrl.userCanMap"
class="button button--large"
ng-click="projectCtrl.lockSelectedTaskMapping()">
Expand All @@ -393,7 +400,8 @@ <h3 style="display: inline-block;">{{ 'Mapping' | translate }}</h3>
</div>
<div>
<div class="button-group button-group--horizontal" role="group"
aria-label="{{ 'Other options' | translate }}">
aria-label="{{ 'Other options' | translate }}"
ng-show="!projectCtrl.enforceRandomTaskSelection()">
<button ng-hide="projectCtrl.taskErrorMapping === 'none-available' || !projectCtrl.userCanMap"
ng-click="projectCtrl.selectRandomTaskMap()"
class="button button--achromic">
Expand All @@ -410,6 +418,13 @@ <h3 style="display: inline-block;">{{ 'Mapping' | translate }}</h3>
</button> -->
</div>
</div>
<div ng-show="projectCtrl.randomTaskSelectionError">
<p class="error" role="alert">{{ 'Tasks must be randomly selected' | translate }}</p>
<button ng-click="projectCtrl.selectRandomTaskMap()"
class="button pull-center">
{{ 'Select a random task' | translate }}
</button>
</div>
</div>
</div>
</div>
Expand Down
28 changes: 28 additions & 0 deletions migrations/versions/0eeaa5aed53b_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""empty message
Revision ID: 0eeaa5aed53b
Revises: e36f1d0c4947
Create Date: 2019-06-26 17:31:17.238355
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '0eeaa5aed53b'
down_revision = 'e36f1d0c4947'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('projects', sa.Column('enforce_random_task_selection', sa.Boolean(), nullable=True))
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('projects', 'enforce_random_task_selection')
# ### end Alembic commands ###
1 change: 1 addition & 0 deletions server/models/dtos/project_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class ProjectDTO(Model):
mapper_level = StringType(required=True, serialized_name='mapperLevel', validators=[is_known_mapping_level])
enforce_mapper_level = BooleanType(required=True, default=False, serialized_name='enforceMapperLevel')
enforce_validator_role = BooleanType(required=True, default=False, serialized_name='enforceValidatorRole')
enforce_random_task_selection = BooleanType(required=True, default=False, serialized_name='enforceRandomTaskSelection')
allow_non_beginners = BooleanType(required=False, default=False, serialized_name='allowNonBeginners')
private = BooleanType(required=True)
entities_to_map = StringType(serialized_name='entitiesToMap')
Expand Down
4 changes: 4 additions & 0 deletions server/models/postgis/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Project(db.Model):
mapper_level = db.Column(db.Integer, default=1, nullable=False, index=True) # Mapper level project is suitable for
enforce_mapper_level = db.Column(db.Boolean, default=False)
enforce_validator_role = db.Column(db.Boolean, default=False) # Means only users with validator role can validate
enforce_random_task_selection = db.Column(db.Boolean, default=False) # Force users to edit at random to avoid mapping "easy" tasks
allow_non_beginners = db.Column(db.Boolean, default=False)
private = db.Column(db.Boolean, default=False) # Only allowed users can validate
entities_to_map = db.Column(db.String)
Expand Down Expand Up @@ -188,6 +189,7 @@ def clone(project_id: int, author_id: int):
cloned_project.mapper_level = original_project.mapper_level
cloned_project.enforce_mapper_level = original_project.enforce_mapper_level
cloned_project.enforce_validator_role = original_project.enforce_validator_role
cloned_project.enforce_random_task_selection = original_project.enforce_random_task_selection
cloned_project.private = original_project.private
cloned_project.entities_to_map = original_project.entities_to_map
cloned_project.due_date = original_project.due_date
Expand Down Expand Up @@ -230,6 +232,7 @@ def update(self, project_dto: ProjectDTO):
self.default_locale = project_dto.default_locale
self.enforce_mapper_level = project_dto.enforce_mapper_level
self.enforce_validator_role = project_dto.enforce_validator_role
self.enforce_random_task_selection = project_dto.enforce_random_task_selection
self.allow_non_beginners = project_dto.allow_non_beginners
self.private = project_dto.private
self.mapper_level = MappingLevel[project_dto.mapper_level.upper()].value
Expand Down Expand Up @@ -484,6 +487,7 @@ def _get_project_and_base_dto(self):
base_dto.aoi_bbox = shape(base_dto.area_of_interest).bounds
base_dto.enforce_mapper_level = self.enforce_mapper_level
base_dto.enforce_validator_role = self.enforce_validator_role
base_dto.enforce_random_task_selection = self.enforce_random_task_selection
base_dto.allow_non_beginners = self.allow_non_beginners
base_dto.private = self.private
base_dto.mapper_level = MappingLevel(self.mapper_level).name
Expand Down

0 comments on commit 48d7e34

Please sign in to comment.