Skip to content

Commit

Permalink
Merge pull request #1169 from hotosm/develop
Browse files Browse the repository at this point in the history
Release v3.0.2
  • Loading branch information
dakotabenjamin committed Aug 27, 2018
2 parents 27403bc + af90fa3 commit d8b287a
Show file tree
Hide file tree
Showing 30 changed files with 573 additions and 205 deletions.
19 changes: 12 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
FROM python:3.6-jessie

# Install dependencies for shapely
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y libgeos-dev
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y libgeos-dev \
&& rm -rf /var/lib/apt/lists/*


# Uncomment and set with valid connection string for use locally
#ENV TM_DB=postgresql://user:pass@host/db

WORKDIR /src

# Add and install Python modules
ADD requirements.txt /src/requirements.txt
RUN cd /src; pip install -r requirements.txt
ADD requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

ADD . /src
ADD . .

# Expose
EXPOSE 8000

# Gunicorn configured for single-core machine, if more cores available increase workers using formula ((cores x 2) + 1))
CMD cd /src; NEW_RELIC_CONFIG_FILE=newrelic.ini newrelic-admin run-program gunicorn -b 0.0.0.0:8000 -w 5 --timeout 179 manage:application
CMD NEW_RELIC_CONFIG_FILE=newrelic.ini newrelic-admin run-program gunicorn -b 0.0.0.0:8000 -w 5 --timeout 179 manage:application

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ python -m unittest discover tests/server

On boot the Tasking Manager App will look for the following environment vars:

* **TASKING_MANAGER_ENV** - Allows you to specify which config to load from ./server/config.py Acceptable values:
* **TM_ENV** - Allows you to specify which config to load from ./server/config.py Acceptable values:
* **Dev** - This is the default
* **Staging** - Use this for your staging/test environment
* **Prod** - Use this for your production environment
Expand Down
7 changes: 6 additions & 1 deletion client/app/admin/edit-project/edit-project.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,14 @@ <h1 class="section__aside-title">{{ 'In this area' | translate }}</h1>
ng-model="info.perTaskInstructions" rows="4">
</textarea>
<p><strong>{{ 'Tip' | translate }}:</strong> {{ 'You can use Markdown. (HTML is not allowed)' | translate }}</p>
<p>Put here anything that can be useful to users while taking a task. {x}, {y} and {z} will be replaced by the corresponding parameters for each task.
<p ng-if="editProjectCtrl.project.taskCreationMode == 'GRID' ">
Put here anything that can be useful to users while taking a task. {x}, {y} and {z} will be replaced by the corresponding parameters for each task.
{x}, {y} and {z} parameters can only be be used on tasks generated in the Tasking Manager and not on imported tasks.
For example: « This task involves loading extra data. Click [here](http://localhost:8111/import?new_layer=true&url=http://www.domain.com/data/{x}/{y}/{z}/routes_2009.osm) to load the data into JOSM ».</p>
<p ng-if="editProjectCtrl.project.taskCreationMode == 'ARBITRARY'">
Put here anything that can be useful to users while taking a task. If you have added extra properties within the GeoJSON of the task, they can be referenced by surrounding them in curly braces. For eg. if you have a property called "import_url" in your GeoJSON, you can reference it like:
<code>This task involves loading extra data. Click [here](http://localhost:8111/import?new_layer=true&url={import_url}) to load the data into JOSM</code>
</p>
<button class="button button--secondary button--small"
ng-click="editProjectCtrl.showPreviewPerTaskInstructions = !editProjectCtrl.showPreviewPerTaskInstructions">
{{ 'Preview' | translate }}
Expand Down
16 changes: 15 additions & 1 deletion client/app/profile/profile.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
vm.username = '';
vm.currentlyLoggedInUser = null;
vm.userDetails = null;
vm.userStats = null;
vm.osmUserDetails = null;
vm.projects = [];
vm.map = null;
Expand Down Expand Up @@ -50,8 +51,9 @@
var hoverIdentify = true;
var clickIdentify = true;
projectMapService.addPopupOverlay(hoverIdentify, clickIdentify);
getUserProjects();
getLevelSettings();
getUserStats();
getUserProjects();
}

/**
Expand Down Expand Up @@ -205,5 +207,17 @@
vm.mapperLevelAdvanced = data.mapperLevelAdvanced;
});
}

/**
* Get stats about the user
*/
function getUserStats() {
var resultsPromise = userService.getUserStats(vm.username);
resultsPromise.then(function (data) {
// On success, set the detailed stats for this user
vm.userStats = data;
});
}

}
})();
7 changes: 7 additions & 0 deletions client/app/profile/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ <h4>{{ profileCtrl.username }}'s {{ 'Progress' | translate }}</h4>
</div>
<hr/>
</div>
<div>
<h4>Stats</h4>
<span>Time Spent Mapping (TM3 only)</span>
<span class="pull-right">{{ profileCtrl.userStats.timeSpentMapping | amDurationFormat : 'second' }}</span>
<hr/>
</div>
<div>
<h4>OSM details</h4>
<div ng-show="profileCtrl.osmUserDetails">
Expand All @@ -84,6 +90,7 @@ <h4>OSM details</h4>
{{ 'OSM heat map' | translate }}
</a>
</p>
<hr/>
</div>
</div>
<div class="roles pull-right">
Expand Down
4 changes: 4 additions & 0 deletions client/app/project/project-dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ <h2>{{ 'Last activity' | translate }}</h2>
href="/user/{{ item.actionBy }}">{{ item.actionBy }}</a></span>
<span ng-show="item.action === 'LOCKED_FOR_VALIDATION'">{{ 'Task locked for validation by' | translate }} <a
href="/user/{{ item.actionBy }}">{{ item.actionBy }}</a></span>
<span ng-show="item.action === 'AUTO_UNLOCKED_FOR_MAPPING'">{{ 'Task automatically unlocked for mapping by' | translate }} <a
href="/user/{{ item.actionBy }}">{{ item.actionBy }}</a></span>
<span ng-show="item.action === 'AUTO_UNLOCKED_FOR_VALIDATION'">{{ 'Task automatically unlocked for validation by' | translate }} <a
href="/user/{{ item.actionBy }}">{{ item.actionBy }}</a></span>
<span ng-show="item.action === 'STATE_CHANGE' && item.actionText === 'BADIMAGERY'">{{ 'Task marked as bad imagery by' | translate }} <a
href="/user/{{ item.actionBy }}">{{ item.actionBy }}</a></span>
<span ng-show="item.action === 'STATE_CHANGE' && item.actionText === 'MAPPED'">{{ 'Task mapped by' | translate }} <a
Expand Down
90 changes: 65 additions & 25 deletions client/app/project/project.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
*/
angular
.module('taskingManager')
.controller('projectController', ['$timeout', '$interval', '$scope', '$location', '$routeParams', '$window', 'configService', 'mapService', 'projectService', 'styleService', 'taskService', 'geospatialService', 'editorService', 'authService', 'accountService', 'userService', 'licenseService', 'messageService', 'drawService', 'languageService', 'userPreferencesService', projectController]);

function projectController($timeout, $interval, $scope, $location, $routeParams, $window, configService, mapService, projectService, styleService, taskService, geospatialService, editorService, authService, accountService, userService, licenseService, messageService, drawService, languageService, userPreferencesService) {
.controller('projectController', ['$timeout', '$interval', '$scope', '$location', '$routeParams', '$window', 'moment', 'configService', 'mapService', 'projectService', 'styleService', 'taskService', 'geospatialService', 'editorService', 'authService', 'accountService', 'userService', 'licenseService', 'messageService', 'drawService', 'languageService', 'userPreferencesService', projectController]);

function projectController($timeout, $interval, $scope, $location, $routeParams, $window, moment, configService, mapService, projectService, styleService, taskService, geospatialService, editorService, authService, accountService, userService, licenseService, messageService, drawService, languageService, userPreferencesService) {
var vm = this;
vm.id = 0;
vm.projectData = null;
Expand Down Expand Up @@ -39,6 +38,7 @@
vm.taskUnLockErrorMessage = '';
vm.taskSplitError = false;
vm.taskSplitCode == null;
vm.wasAutoUnlocked = false;

//authorization
vm.isAuthorized = false;
Expand All @@ -51,6 +51,7 @@
//task data
vm.selectedTaskData = null;
vm.lockedTaskData = null;
vm.lockTime = {};
vm.multiSelectedTasksData = [];
vm.multiLockedTasks = [];

Expand Down Expand Up @@ -190,6 +191,7 @@
vm.taskSplitError = false;
vm.taskSplitCode == null;
vm.taskUndoError = false;
vm.wasAutoUnlocked = false;
}

/**
Expand Down Expand Up @@ -348,6 +350,23 @@
});
};

vm.getLockTime = function() {
var task = null;
if (vm.selectedTaskData) {
task = vm.selectedTaskData;
}
else if (vm.multiSelectedTasksData) {
task = vm.multiSelectedTasksData[0];
}
if (task != null && task.taskId in vm.lockTime) {
var lockTime = moment.utc(vm.lockTime[task.taskId]);
return lockTime.add(2, 'hours').diff(moment.utc(), 'minutes');
}
else {
return null;
}
};

/**
* Initilaise a project using it's id
* @param id - id of the project to initialise
Expand Down Expand Up @@ -543,9 +562,24 @@
vm.lockedByCurrentUserVectorLayer.getSource().clear();
}
vm.lockedTasksForCurrentUser = [];
if (vm.mappingStep === 'locked' || vm.validatingStep === 'locked') {
vm.mappingStep = 'viewing';
vm.validatingStep = 'viewing';
vm.wasAutoUnlocked = true;
}
});
}

function getLastLockedAction(task) {
var mostRecentAction = task.taskHistory[0];
task.taskHistory.forEach(function(action) {
if (action.actionDate > mostRecentAction.actionDate) {
mostRecentAction = action;
}
});
return mostRecentAction;
}

/**
* Has the current user got tasks locked for mapping
* @returns {boolean}
Expand Down Expand Up @@ -794,6 +828,7 @@
vm.mappingStep = 'locked';
vm.lockedTaskData = data;
vm.currentTab = 'mapping';
vm.lockTime[vm.selectedTaskData.taskId] = getLastLockedAction(vm.lockedTaskData).actionDate;
}
else {
vm.mappingStep = 'viewing';
Expand All @@ -804,6 +839,7 @@
vm.validatingStep = 'locked';
vm.lockedTaskData = data;
vm.currentTab = 'validation';
vm.lockTime[vm.selectedTaskData.taskId] = getLastLockedAction(vm.lockedTaskData).actionDate;
}
else {
vm.validatingStep = 'viewing';
Expand Down Expand Up @@ -1055,6 +1091,7 @@
vm.selectedTaskData = data;
vm.isSelectedMappable = true;
vm.lockedTaskData = data;
vm.lockTime[taskId] = getLastLockedAction(vm.lockedTaskData).actionDate;
vm.isSelectedSplittable = isTaskSplittable(vm.taskVectorLayer.getSource().getFeatures(), data.taskId);
}, function (error) {
onLockError(projectId, error);
Expand Down Expand Up @@ -1093,7 +1130,7 @@
};

/**
* Call api to lock currently selected task for mapping. Will update view and map after unlock.
* Call api to lock currently selected task for validation. Will update view and map after unlock.
*/
vm.lockSelectedTaskValidation = function () {
vm.lockingReason = 'VALIDATION';
Expand All @@ -1120,6 +1157,7 @@
vm.selectedTaskData = tasks[0];
vm.isSelectedValidatable = true;
vm.lockedTaskData = tasks[0];
vm.lockTime[taskId] = getLastLockedAction(vm.lockedTaskData).actionDate;
}, function (error) {
onLockError(projectId, error);
});
Expand Down Expand Up @@ -1227,22 +1265,22 @@
layer_name: encodeURIComponent('Task Boundaries #' + vm.projectData.projectId + '- Do not edit or upload'),
data: encodeURIComponent('<?xml version="1.0" encoding="utf8"?><osm generator="JOSM" upload="never" version="0.6"></osm>')
}
var isEmptyTaskLayerSuccess = editorService.sendJOSMCmd('http://127.0.0.1:8111/load_data', emptyTaskLayerParams);
if (!isEmptyTaskLayerSuccess) {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
}
editorService.sendJOSMCmd('http://127.0.0.1:8111/load_data', emptyTaskLayerParams)
.catch(function() {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
});

//load task square(s) into JOSM
var taskImportParams = {
url: editorService.getOSMXMLUrl(vm.projectData.projectId, vm.getSelectTaskIds()),
new_layer: false
}
var isTaskImportSuccess = editorService.sendJOSMCmd('http://127.0.0.1:8111/import', taskImportParams);
if (!isTaskImportSuccess) {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
}
editorService.sendJOSMCmd('http://127.0.0.1:8111/import', taskImportParams)
.catch(function() {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
});
}

//load aerial photography if present
Expand All @@ -1258,11 +1296,11 @@
type: imageryUrl.toLowerCase().substring(0, 3),
url: encodeURIComponent(imageryUrl)
};
var isImagerySuccess = editorService.sendJOSMCmd('http://127.0.0.1:8111/imagery', imageryParams);
if (!isImagerySuccess) {
//warn that imagery couldn't be loaded
vm.editorStartError = 'josm-imagery-error';
}
editorService.sendJOSMCmd('http://127.0.0.1:8111/imagery', imageryParams)
.catch(function() {
//warn that imagery couldn't be loaded
vm.editorStartError = 'josm-imagery-error';
});
}

// load a new empty layer in josm for osm data, this step necessary to have a custom name for the layer
Expand All @@ -1273,11 +1311,11 @@
layer_name: 'OSM Data',
data: encodeURIComponent('<?xml version="1.0" encoding="utf8"?><osm generator="JOSM" version="0.6"></osm>')
}
var isEmptyOSMLayerSuccess = editorService.sendJOSMCmd('http://127.0.0.1:8111/load_data', emptyOSMLayerParams);
if (!isEmptyOSMLayerSuccess) {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
}
editorService.sendJOSMCmd('http://127.0.0.1:8111/load_data', emptyOSMLayerParams)
.catch(function() {
//warn that JSOM couldn't be started
vm.editorStartError = 'josm-error';
});

var loadAndZoomParams = {
left: extentTransformed[0],
Expand Down Expand Up @@ -1454,7 +1492,9 @@
vm.multiSelectedTasksData = tasks;
vm.multiLockedTasks = tasks;
vm.isSelectedValidatable = true;

vm.multiLockedTasks.forEach(function(task) {
vm.lockTime[task.taskId] = getLastLockedAction(task).actionDate;
})
}, function (error) {
onLockError(vm.projectData.projectId, error)
});
Expand Down
Loading

0 comments on commit d8b287a

Please sign in to comment.