From ebb214f920279e9c8e1515b036b2d84f1b06e229 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Thu, 19 Jan 2017 14:51:52 +0100 Subject: [PATCH] Adding experienced mapper role --- ...819ae210_adding_experienced_mapper_role.py | 22 ++++++++++ osmtm/__init__.py | 2 + osmtm/models.py | 10 +++++ osmtm/templates/project.edit.mako | 17 ++++++++ osmtm/templates/task.unlocked.mako | 42 ++++++++++++++++--- osmtm/templates/user.mako | 15 +++++++ osmtm/templates/users.mako | 10 +++++ osmtm/tests/__init__.py | 5 +++ osmtm/tests/test_project.py | 28 ++++++++++++- osmtm/tests/test_user.py | 2 +- osmtm/views/project.py | 4 ++ osmtm/views/user.py | 12 ++++++ 12 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 alembic/versions/1bdc819ae210_adding_experienced_mapper_role.py diff --git a/alembic/versions/1bdc819ae210_adding_experienced_mapper_role.py b/alembic/versions/1bdc819ae210_adding_experienced_mapper_role.py new file mode 100644 index 00000000..8956d310 --- /dev/null +++ b/alembic/versions/1bdc819ae210_adding_experienced_mapper_role.py @@ -0,0 +1,22 @@ +"""Adding experienced mapper role + +Revision ID: 1bdc819ae210 +Revises: 4a5bf96b558d +Create Date: 2017-01-19 14:10:58.578127 + +""" + +# revision identifiers, used by Alembic. +revision = '1bdc819ae210' +down_revision = '4a5bf96b558d' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('project', sa.Column('requires_experienced_mapper_role', sa.Boolean(), nullable=True)) + + +def downgrade(): + op.drop_column('project', 'requires_experienced_mapper_role') diff --git a/osmtm/__init__.py b/osmtm/__init__.py index 16129684..fb08f547 100644 --- a/osmtm/__init__.py +++ b/osmtm/__init__.py @@ -142,6 +142,8 @@ def main(global_config, **settings): config.add_route('user_admin', '/user/{id:\d+}/admin') config.add_route('user_project_manager', '/user/{id:\d+}/project_manager') config.add_route('user_validator', '/user/{id:\d+}/validator') + config.add_route('user_experienced_mapper', + '/user/{id:\d+}/experienced_mapper') config.add_route('user_prefered_editor', '/user/prefered_editor/{editor}', xhr=True) config.add_route('user_prefered_language', diff --git a/osmtm/models.py b/osmtm/models.py index c1a1c85a..9da6dc72 100644 --- a/osmtm/models.py +++ b/osmtm/models.py @@ -119,6 +119,7 @@ class ST_SetSRID(GenericFunction): ADMIN = 1 PROJECT_MANAGER = 2 VALIDATOR = 4 +EXPERIENCED_MAPPER = 8 class User(Base): @@ -128,6 +129,7 @@ class User(Base): role_admin = ADMIN role_project_manager = PROJECT_MANAGER role_validator = VALIDATOR + role_experienced_mapper = EXPERIENCED_MAPPER role = Column(Integer, default=0) accepted_licenses = relationship("License", secondary=users_licenses_table) @@ -156,6 +158,10 @@ def is_project_manager(self): def is_validator(self): return self.role & self.role_validator + @hybrid_property + def is_experienced_mapper(self): + return self.role & self.role_experienced_mapper + def as_dict(self): return { "id": self.id, @@ -163,6 +169,7 @@ def as_dict(self): "is_admin": self.is_admin, "is_project_manager": self.is_project_manager, "is_validator": self.is_validator, + "is_experienced_mapper": self.is_experienced_mapper, } @@ -550,6 +557,9 @@ class Project(Base, Translatable): labels = relationship("Label", secondary=project_labels_table) + # whether the validation should require the validator role or not + requires_experienced_mapper_role = Column(Boolean, default=False) + def __init__(self, name, user=None): self.name = name self.author = user diff --git a/osmtm/templates/project.edit.mako b/osmtm/templates/project.edit.mako index de1bfa86..9ebe9cce 100644 --- a/osmtm/templates/project.edit.mako +++ b/osmtm/templates/project.edit.mako @@ -466,6 +466,23 @@ geometry = loads(str(project.area.geometry.data)) +
+
+
+
+ +
+ ${_("If checked, only users with the 'experienced mapper role' will be able to contribute to the current project. If not, anyone can.")} +
+
+
+
<% from osmtm.models import dumps %> diff --git a/osmtm/templates/task.unlocked.mako b/osmtm/templates/task.unlocked.mako index bd69e34e..da7842e4 100644 --- a/osmtm/templates/task.unlocked.mako +++ b/osmtm/templates/task.unlocked.mako @@ -1,26 +1,56 @@ <% from osmtm.models import TaskState +from osmtm.mako_filters import ( + markdown_filter, +) + +requires_experience = user is not None and task.project.requires_experienced_mapper_role and not (user.is_experienced_mapper or user.is_admin or user.is_project_manager) + +if user is not None: + user_link = request.route_url('user',username=user.username) +else: + user_link = '' + +author = task.project.author.username if task.project.author else '' + %> -
+
% if locked_task is not None: % if locked_task != task: <%include file="task.current_locked.mako" /> % endif % elif not task.assigned_to or task.assigned_to == user: - % if task.cur_state.state == TaskState.state_ready or task.cur_state.state == TaskState.state_invalidated: + % if requires_experience: + <% + link = 'http://www.openstreetmap.org/message/new/%s?message[title]=%s&message[body]=%s' % ( + author, + _("Privileges for project {project} in the tasking manager").format(project='%23' + str(task.project_id)), + _("I would like to be granted as experienced mapper.") + "%0D%0A%0D%0A[{0}]({1})".format( + _("Link to my profile page"), + user_link) + ) + %>

+ ${_('You need to be an **experienced mapper** to contribute to this project.')|markdown_filter} + ${_("You think you are an **experienced mapper**? Click [this link](${link}) to send a message to the author to ask him form permissions to work on this project.", + mapping={'link': link})| markdown_filter, n} +

+
+ % endif + % if task.cur_state.state == TaskState.state_ready or task.cur_state.state == TaskState.state_invalidated: +

+ class="btn btn-success ${'disabled' if requires_experience else ''}">   ${_('Start mapping')}

% elif (task.cur_state.state == TaskState.state_done or task.cur_state.state == TaskState.state_validated): % if user == task.states[0].user: -
+ ${_('Marked as done by mistake?')}
diff --git a/osmtm/templates/users.mako b/osmtm/templates/users.mako index 06de75c6..05964814 100644 --- a/osmtm/templates/users.mako +++ b/osmtm/templates/users.mako @@ -27,6 +27,9 @@ % if user.is_validator: % endif + % if user.is_experienced_mapper: + + % endif % endfor % endif @@ -60,6 +63,13 @@ ${_('Validator')} +
  • + +
  • diff --git a/osmtm/tests/__init__.py b/osmtm/tests/__init__.py index 515b8139..262f4fa8 100644 --- a/osmtm/tests/__init__.py +++ b/osmtm/tests/__init__.py @@ -28,6 +28,7 @@ ADMIN_USER_ID = 3 PROJECT_MANAGER_USER_ID = 4 VALIDATOR_ID = 5 +EXPERIENCED_MAPPER_ID = 6 translation_manager.options.update({ 'locales': ['en', 'fr'], @@ -67,6 +68,10 @@ def populate_db(): user.role = User.role_validator DBSession.add(user) + user = User(EXPERIENCED_MAPPER_ID, u'user_experienced_mapper') + user.role = User.role_experienced_mapper + DBSession.add(user) + license = License() license.name = u'LicenseBar' license.description = u'the_description_for_license_bar' diff --git a/osmtm/tests/test_project.py b/osmtm/tests/test_project.py index 6c059923..8f44c9d7 100644 --- a/osmtm/tests/test_project.py +++ b/osmtm/tests/test_project.py @@ -763,7 +763,7 @@ def test_project_users(self): res = self.testapp.get('/project/%d/users' % project_id, status=200, xhr=True) - self.assertEqual(len(res.json), 5) + self.assertEqual(len(res.json), 6) res = self.testapp.get('/project/%d/users?q=pro' % project_id, status=200, xhr=True) @@ -1063,3 +1063,29 @@ def test_home__search_label(self): }) projects = res.html.select('.project') self.assertEqual(len(projects), 0) + + def test_project__experienced_mapper(self): + import transaction + from osmtm.models import DBSession, Project + project_id = self.create_project() + project = DBSession.query(Project).get(project_id) + project.requires_experienced_mapper_role = True + DBSession.add(project) + DBSession.flush() + transaction.commit() + + project = DBSession.query(Project).get(project_id) + tasks = project.tasks + headers_user1 = self.login_as_user1() + from osmtm.tests import EXPERIENCED_MAPPER_ID + headers_exp_map = self.login_as_user(EXPERIENCED_MAPPER_ID) + + res = self.testapp.get('/project/%d/task/%d' % (project_id, + tasks[0].id), + headers=headers_user1, status=200, xhr=True) + self.assertTrue('experienced mapper' in res.body) + + res = self.testapp.get('/project/%d/task/%d' % (project_id, + tasks[0].id), + headers=headers_exp_map, status=200, xhr=True) + self.assertFalse('experienced mapper' in res.body) diff --git a/osmtm/tests/test_user.py b/osmtm/tests/test_user.py index 19beb772..047be781 100644 --- a/osmtm/tests/test_user.py +++ b/osmtm/tests/test_user.py @@ -16,7 +16,7 @@ def test_users__logged_in(self): def test_users_json(self): res = self.testapp.get('/users.json', status=200) - self.assertEqual(len(res.json), 6) + self.assertEqual(len(res.json), 7) def test_users_json__query(self): res = self.testapp.get('/users.json', diff --git a/osmtm/views/project.py b/osmtm/views/project.py index d9888275..bc95b934 100644 --- a/osmtm/views/project.py +++ b/osmtm/views/project.py @@ -282,6 +282,10 @@ def project_edit(request): ('requires_validator_role' in request.params and request.params['requires_validator_role'] == 'on') + project.requires_experienced_mapper_role = \ + ('requires_experienced_mapper_role' in request.params and + request.params['requires_experienced_mapper_role'] == 'on') + project.status = request.params['status'] project.priority = request.params['priority'] diff --git a/osmtm/views/user.py b/osmtm/views/user.py index 06b36a9f..cacd9043 100644 --- a/osmtm/views/user.py +++ b/osmtm/views/user.py @@ -100,6 +100,18 @@ def user_validator(request): username=user.username)) +@view_config(route_name='user_experienced_mapper', permission="user_edit") +def user_experienced_mapper(request): + id = request.matchdict['id'] + user = DBSession.query(User).get(id) + + user.role ^= User.role_experienced_mapper + DBSession.flush() + + return HTTPFound(location=route_path("user", request, + username=user.username)) + + @view_config(route_name='user', renderer='user.mako') def user(request):