diff --git a/cadasta/api/login.py b/cadasta/api/login.py
index 2e1cc7e..a4e4f64 100644
--- a/cadasta/api/login.py
+++ b/cadasta/api/login.py
@@ -19,7 +19,7 @@
class Login(BaseApi):
- post_data = QByteArray()
+ post_data = None
def __init__(self, domain, username, password, on_finished=None):
"""Constructor.
@@ -38,6 +38,7 @@ def __init__(self, domain, username, password, on_finished=None):
:type on_finished: Function
"""
super(Login, self).__init__(domain + '/api/v1/account/login/?')
+ self.post_data = QByteArray()
self.post_data.append("username=%s&" % username)
self.post_data.append("password=%s" % password)
diff --git a/cadasta/gui/tools/helper/content/cadasta_help.py b/cadasta/gui/tools/helper/content/cadasta_help.py
index 9186ac0..654ae73 100644
--- a/cadasta/gui/tools/helper/content/cadasta_help.py
+++ b/cadasta/gui/tools/helper/content/cadasta_help.py
@@ -48,8 +48,11 @@ def content():
message = m.Message()
message.add(m.Paragraph(tr(
- 'You can find updated documentation and suggested workflows on our main '
- 'documentation pages: QGIS chapter. (requires internet access to view)')))
+ 'You can find updated documentation and suggested workflows '
+ 'on our main '
+ 'documentation pages: QGIS chapter. (requires internet '
+ 'access to view)')))
message.add(m.Paragraph(tr(
'There are three windows that will help you '
'to manage your project\'s data.')))
@@ -64,6 +67,7 @@ def content():
message.add(bullets)
message.add(m.Paragraph(tr(
- 'Use the User Settings window to log in to your account and get started!'
+ 'Use the User Settings window to log in to your account '
+ 'and get started!'
'')))
return message
diff --git a/cadasta/gui/tools/helper/content/options_help.py b/cadasta/gui/tools/helper/content/options_help.py
new file mode 100644
index 0000000..b7e4861
--- /dev/null
+++ b/cadasta/gui/tools/helper/content/options_help.py
@@ -0,0 +1,83 @@
+# coding=utf-8
+"""Help for options."""
+
+from cadasta.utilities.i18n import tr
+from extras import messaging as m
+from extras.messaging import styles
+
+INFO_STYLE = styles.INFO_STYLE
+
+__author__ = 'Irwan Fathurrahman '
+__date__ = '03/01/17'
+
+
+def options_help():
+ """Help message for Options.
+
+ :returns: A message object containing helpful information.
+ :rtype: messaging.message.Message
+ """
+ message = m.Message()
+ message.add(heading())
+ message.add(content())
+ return message
+
+
+def heading():
+ """Helper method that returns just the header.
+
+ This method was added so that the text could be reused in the
+ other contexts.
+
+ :returns: A heading object.
+ :rtype: safe.messaging.heading.Heading
+ """
+ message = m.Heading(tr('Options Help'), **INFO_STYLE)
+ return message
+
+
+def content():
+ """Helper method that returns just the content.
+
+ This method was added so that the text could be reused in the
+ other contexts.
+
+ :returns: A message object without brand element.
+ :rtype: safe.messaging.message.Message
+ """
+
+ message = m.Message()
+
+ message.add(m.Paragraph(tr(
+ 'Options will help you redefine url of Cadasta that is used as '
+ 'source. And also it create a credential to be used on submit '
+ 'new or updated projects.')))
+
+ message.add(m.Paragraph(tr(
+ 'There are 3 input that all of that are required.')))
+
+ bullets = m.BulletedList()
+ bullets.add(m.Text(
+ m.ImportantText(tr('Cadasta URL')),
+
+ tr('- overwrite current url as cadasta source.'
+ 'default is https://platform-staging-api.cadasta.org/')
+ ))
+ bullets.add(m.Text(
+ m.ImportantText(tr('Cadasta Username')),
+ tr('- username that will be used for other request, e.g: create '
+ 'project')
+ ))
+ bullets.add(m.Text(
+ m.ImportantText(tr('Cadasta Password'))
+
+ ))
+ message.add(bullets)
+
+ message.add(m.Paragraph(tr(
+ 'Fill out the form with your username and password. Click \'Connect\' '
+ 'button '
+ 'to login. If that is successful click the \'Save\' button to save '
+ 'the settings.')))
+ message.add(m.ImportantText(tr('Note that your password is not saved.')))
+ return message
diff --git a/cadasta/gui/tools/utilities/edit_text_dialog.py b/cadasta/gui/tools/utilities/edit_text_dialog.py
index 438d0ad..17ec63d 100644
--- a/cadasta/gui/tools/utilities/edit_text_dialog.py
+++ b/cadasta/gui/tools/utilities/edit_text_dialog.py
@@ -14,7 +14,15 @@
import logging
from qgis.PyQt.QtCore import pyqtSignal
from qgis.PyQt.QtGui import (
- QDialog,
+ QDialog
+)
+from PyQt4.QtCore import QUrl, QRegExp, Qt
+from PyQt4.QtGui import (
+ QDesktopServices,
+ QColor,
+ QTextCharFormat,
+ QFont,
+ QSyntaxHighlighter
)
from cadasta.utilities.resources import get_ui_class
@@ -56,11 +64,19 @@ def __init__(self, parent=None, iface=None, text=""):
QDialog.__init__(self, parent)
self.setupUi(self)
self.setWindowTitle('Cadasta Questionnaire')
+ self.highlighter = Highlighter(self.edit_text.document())
self.show()
- self.edit_text.setText(text)
+ self.edit_text.setPlainText(text)
self.ok_button.clicked.connect(
self.close_edit_text_dialog
)
+ self.data_schema_help.mousePressEvent = self.show_advanced_help
+
+ def show_advanced_help(self, event):
+ """Show advanced help
+ """
+ QDesktopServices().openUrl(
+ QUrl("https://cadasta.github.io/api-docs/#questionnaires"))
def close_edit_text_dialog(self):
"""Function that call when ok button is clicked.
@@ -75,3 +91,54 @@ def get_text(self):
:rtype: str
"""
return self.edit_text.toPlainText()
+
+
+class Highlighter(QSyntaxHighlighter):
+ def __init__(self, parent=None):
+ super(Highlighter, self).__init__(parent)
+
+ self.highlighting_rules = []
+
+ value_format = QTextCharFormat()
+ value_format.setForeground(Qt.darkRed)
+ self.highlighting_rules.append((
+ QRegExp("\\btrue\\b|\\bnull\\b|\\bfalse\\b|\\b[0-9]+\\b"),
+ value_format
+ ))
+
+ quotation_format = QTextCharFormat()
+ quotation_format.setForeground(Qt.darkGreen)
+ self.highlighting_rules.append((QRegExp("\".*\""),
+ quotation_format))
+
+ self.comment_start_expression = QRegExp("/\\*")
+ self.comment_end_expression = QRegExp("\\*/")
+
+ def highlightBlock(self, text):
+ for pattern, highlight_format in self.highlighting_rules:
+ expression = QRegExp(pattern)
+ index = expression.indexIn(text)
+ while index >= 0:
+ length = expression.matchedLength()
+ self.setFormat(index, length, highlight_format)
+ index = expression.indexIn(text, index + length)
+
+ self.setCurrentBlockState(0)
+
+ start_index = 0
+ if self.previousBlockState() != 1:
+ start_index = self.comment_start_expression.indexIn(text)
+
+ while start_index >= 0:
+ end_index = self.comment_end_expression.indexIn(text, start_index)
+
+ if end_index == -1:
+ self.setCurrentBlockState(1)
+ comment_length = len(text) - start_index
+ else:
+ comment_length = end_index - start_index + \
+ self.comment_end_expression.matchedLength()
+
+ start_index = self.comment_start_expression.indexIn(
+ text,
+ start_index + comment_length)
diff --git a/cadasta/gui/tools/utilities/questionnaire.py b/cadasta/gui/tools/utilities/questionnaire.py
index f811f9e..bb74df6 100644
--- a/cadasta/gui/tools/utilities/questionnaire.py
+++ b/cadasta/gui/tools/utilities/questionnaire.py
@@ -140,28 +140,22 @@ def generate_new_questionnaire(
for field in current_layer.fields():
field_name = field.name()
if field_name != 'id':
- if field_name not in attributes_in_questionnaire:
- if field_name not in mapped_fields:
- try:
- # check location attributes in question group
- location_attributes["questions"].append(
- {
- "index": index,
- "name": field_name,
- "label": field_name,
- "type": mapping_type[
- field.typeName().lower()
- ],
- "required": False,
- "constraint": 'null',
- "default": 'null',
- "hint": 'null',
- "relevant": 'null',
- }
- )
- except KeyError:
- pass
- index += 1
+ if field_name not in mapped_fields:
+ try:
+ # check location attributes in question group
+ location_attributes["questions"].append(
+ {
+ "name": field_name,
+ "label": field_name,
+ "type": mapping_type[
+ field.typeName().lower()
+ ],
+ "required": False
+ }
+ )
+ except KeyError:
+ pass
+ index += 1
# insert into questionnaire
index = -1
@@ -171,15 +165,69 @@ def generate_new_questionnaire(
break
if index == -1:
- location_attributes['index'] = 1
questionnaire['question_groups'].append(
location_attributes)
else:
- location_attributes['index'] = index
questionnaire['question_groups'][index] = location_attributes
return json.dumps(questionnaire, indent=4)
+ def add_index(self, question_object, index):
+ """Add index to question.
+
+ :param question_object: object to be added index
+ :type question_object: dict
+
+ :param index: current index
+ :type index: int
+
+ :return: latest index
+ :rtype: int
+ """
+ if 'index' not in question_object:
+ question_object['index'] = index
+ else:
+ if question_object['index'] - index != 1:
+ question_object['index'] = index + 1
+ index += 1
+ return index
+
+ def validate_questionnaire(self, questionnaire):
+ """Validate and fix questionnaire file.
+
+ :param questionnaire: questionnaire string
+ :type questionnaire: str
+
+ :return: validated questionnaire
+ :rtype: str
+ """
+ questionnaire_obj = json.loads(questionnaire)
+ index = 1
+ for question in questionnaire_obj['questions']:
+ index = self.add_index(question, index)
+
+ if 'options' in question:
+ option_index = 1
+ for option in question['options']:
+ option_index = self.add_index(option, option_index)
+
+ index = 1
+ for question_group in questionnaire_obj['question_groups']:
+ index = self.add_index(question_group, index)
+
+ if 'questions' in question_group:
+ question_index = 1
+ for question in question_group['questions']:
+ question_index = self.add_index(question, question_index)
+ if 'hint' not in question:
+ question['hint'] = 'null'
+ if 'default' not in question:
+ question['default'] = 'null'
+ if 'relevant' not in question:
+ question['relevant'] = 'null'
+
+ return json.dumps(questionnaire_obj)
+
def update_questionnaire(
self, organization_slug, project_slug, questionnaire):
"""Update questionnaire of selected project.
diff --git a/cadasta/gui/tools/widget/options_widget.py b/cadasta/gui/tools/widget/options_widget.py
index 100ed1f..4227d94 100644
--- a/cadasta/gui/tools/widget/options_widget.py
+++ b/cadasta/gui/tools/widget/options_widget.py
@@ -79,7 +79,7 @@ def set_widgets(self):
tr('Clear')
)
- self.clear_button.setEnabled(False)
+ self.clear_button.setEnabled(True)
self.clear_button.clicked.connect(
self.clear_information
)
@@ -90,9 +90,16 @@ def set_widgets(self):
self.auth_token = get_authtoken()
if self.auth_token:
- self.clear_button.setEnabled(True)
self.test_connection_button.setEnabled(False)
self.username_input.setText(get_setting('username'))
+ self.username_input.setReadOnly(True)
+ self.password_input.setReadOnly(True)
+ self.username_input.setStyleSheet(
+ "QLineEdit { background-color: '#d9d9d9'; color: '#5b5b5b'; "
+ "selection-background-color: '#969292'; }")
+ self.password_input.setStyleSheet(
+ "QLineEdit { background-color: '#d9d9d9'; color: '#5b5b5b'; "
+ "selection-background-color: '#969292'; }")
self.token_status.setText(
tr('Auth token is saved.')
)
@@ -103,11 +110,15 @@ def set_widgets(self):
def clear_information(self):
"""Clear login information."""
+ self.username_input.setReadOnly(False)
+ self.password_input.setReadOnly(False)
+ self.username_input.setStyleSheet("")
+ self.password_input.setStyleSheet("")
self.username_input.clear()
self.password_input.clear()
+ self.ok_label.clear()
delete_authtoken()
delete_setting('username')
- self.clear_button.setEnabled(False)
self.test_connection_button.setEnabled(True)
self.token_status.setText(
tr(
@@ -166,6 +177,7 @@ def on_finished(self, result):
"""On finished function when tools request is finished."""
self.ok_label.setVisible(True)
+ self.clear_button.setEnabled(True)
if 'auth_token' in result:
self.auth_token = result['auth_token']
self.save_button.setEnabled(True)
@@ -191,6 +203,14 @@ def save_authtoken(self):
save_url_instance(self.url)
self.save_button.setEnabled(False)
self.save_organizations()
+ self.username_input.setReadOnly(True)
+ self.password_input.setReadOnly(True)
+ self.username_input.setStyleSheet(
+ "QLineEdit { background-color: '#d9d9d9'; color: '#5b5b5b'; "
+ "selection-background-color: '#969292'; }")
+ self.password_input.setStyleSheet(
+ "QLineEdit { background-color: '#d9d9d9'; color: '#5b5b5b'; "
+ "selection-background-color: '#969292'; }")
def save_organizations(self):
"""Save organizations of user.
diff --git a/cadasta/gui/tools/wizard/step_project_creation02.py b/cadasta/gui/tools/wizard/step_project_creation02.py
index 34dd918..67437b8 100644
--- a/cadasta/gui/tools/wizard/step_project_creation02.py
+++ b/cadasta/gui/tools/wizard/step_project_creation02.py
@@ -11,6 +11,8 @@
"""
+import logging
+
from cadasta.gui.tools.utilities.edit_text_dialog import EditTextDialog
from cadasta.gui.tools.utilities.questionnaire import QuestionnaireUtility
from cadasta.gui.tools.wizard.wizard_step import WizardStep
@@ -24,6 +26,8 @@
FORM_CLASS = get_wizard_step_ui_class(__file__)
+LOGGER = logging.getLogger('CadastaQGISPlugin')
+
class StepProjectCreation2(WizardStep, FORM_CLASS, QuestionnaireUtility):
"""Step 2 for project creation."""
diff --git a/cadasta/gui/tools/wizard/step_project_creation03.py b/cadasta/gui/tools/wizard/step_project_creation03.py
index f68f588..f2fb347 100644
--- a/cadasta/gui/tools/wizard/step_project_creation03.py
+++ b/cadasta/gui/tools/wizard/step_project_creation03.py
@@ -21,6 +21,7 @@
QgsFeature,
QCoreApplication
)
+import json
from PyQt4.QtCore import QByteArray, QVariant
from cadasta.gui.tools.wizard.wizard_step import WizardStep
from cadasta.utilities.i18n import tr
@@ -33,6 +34,7 @@
)
from cadasta.common.setting import get_csv_path
from cadasta.vector import tools
+from cadasta.gui.tools.utilities.questionnaire import QuestionnaireUtility
__copyright__ = "Copyright 2016, Cadasta"
__license__ = "GPL version 3"
@@ -44,7 +46,7 @@
LOGGER = logging.getLogger('CadastaQGISPlugin')
-class StepProjectCreation3(WizardStep, FORM_CLASS):
+class StepProjectCreation3(WizardStep, FORM_CLASS, QuestionnaireUtility):
"""Step 3 for project creation."""
upload_increment = 20
@@ -61,14 +63,24 @@ def __init__(self, parent=None):
self.current_progress = 0
self.data = None
self.spatial_api = None
+ self.step_1_data = None
+ self.step_2_data = None
+ self.questionnaire = None
def set_widgets(self):
"""Set all widgets on the tab."""
+ self.text_edit.setStyleSheet(
+ "background-color: #f0f0f0; color: #757575"
+ )
self.progress_bar.setVisible(False)
self.lbl_status.setText(
tr('Are you sure to upload the data?')
)
self.submit_button.setFocus()
+ self.step_1_data = self.parent.step_1_data()
+ self.step_2_data, self.questionnaire = self.parent.step_2_data()
+ # Validate questionnaire data
+ self.questionnaire = self.validate_questionnaire(self.questionnaire)
def set_status(self, status):
"""Show status in label and text edit.
@@ -100,18 +112,16 @@ def processing_data(self):
self.set_progress_bar(self.current_progress + 25)
- step_1_data = self.parent.step_1_data()
self.set_progress_bar(self.current_progress + 25)
- step_2_data, questionnaire = self.parent.step_2_data()
self.set_progress_bar(self.current_progress + 25)
- self.data = step_1_data
- self.data['questionnaire'] = questionnaire
+ self.data = self.step_1_data
+ self.data['questionnaire'] = self.questionnaire
# Finalize the data
for location in self.data['locations']['features']:
- for cadasta_field, layer_field in step_2_data.iteritems():
+ for cadasta_field, layer_field in self.step_2_data.iteritems():
properties = location['properties']
if layer_field in properties:
try:
@@ -201,7 +211,7 @@ def upload_project(self):
# after creating location, questionnaire is blocked
if self.data['questionnaire']:
upload_questionnaire_attribute = True
- self.update_questionnaire_project()
+ self.upload_questionnaire_project()
total_locations = len(self.data['locations']['features'])
if total_locations > 0:
self.upload_locations(upload_questionnaire_attribute)
@@ -216,6 +226,7 @@ def upload_project(self):
)
self.set_status(tr('Finished'))
+ self.parent.close()
def rerender_saved_layer(self):
"""Rerender saved layer on cadasta."""
@@ -278,6 +289,11 @@ def upload_locations(self, update_questionnaire_attribute):
failed = 0
+ try:
+ questionnaire = json.loads(self.questionnaire)
+ except ValueError:
+ questionnaire = {}
+
for location in self.data['locations']['features']:
post_data = {
'geometry': location['geometry'],
@@ -294,6 +310,11 @@ def upload_locations(self, update_questionnaire_attribute):
if 'id' in post_data['attributes']:
del post_data['attributes']['id']
+ for question in \
+ questionnaire['question_groups'][0]['questions']:
+ if question['name'] not in post_data['attributes']:
+ post_data['attributes'][question['name']] = u''
+
connector = ApiConnect(get_url_instance() + post_url)
post_data = Utilities.json_dumps(post_data)
status, result = self._call_json_post(
@@ -497,8 +518,8 @@ def get_next_step(self):
"""
return None
- def update_questionnaire_project(self):
- """Update questionnaire."""
+ def upload_questionnaire_project(self):
+ """Upload questionnaire."""
self.set_status(
tr('Update questionnaire')
)
diff --git a/cadasta/gui/tools/wizard/step_project_download01.py b/cadasta/gui/tools/wizard/step_project_download01.py
index 94da599..361697c 100644
--- a/cadasta/gui/tools/wizard/step_project_download01.py
+++ b/cadasta/gui/tools/wizard/step_project_download01.py
@@ -82,6 +82,8 @@ def set_widgets(self):
self.add_contact_label.mousePressEvent = self.add_contact_label_clicked
self.set_enabled_add_contact_label(False)
self.project_combo_box.setFocus()
+ set_setting('public_project',
+ self.public_projects_checkbox.checkState() == Qt.Checked)
def add_contact_label_clicked(self, event):
"""Handler for add_contact_label clicked. """
@@ -148,6 +150,7 @@ def get_available_projects_finished(self, result):
"""
self.throbber_loader.setVisible(False)
self.project_combo_box.clear()
+ self.public_projects_checkbox.setEnabled(True)
if result[0]:
projects = sorted(result[1], key=itemgetter('slug'))
@@ -211,7 +214,7 @@ def project_combo_box_changed(self):
if project['description']:
self.project_description_label.setText(
- self.tr(project['description'].encode('utf-8')))
+ project['description'])
else:
self.project_description_label.setText(
self.tr(project['name'].encode('utf-8')))
@@ -254,6 +257,7 @@ def project_combo_box_changed(self):
def get_available_projects(self):
"""Get available projects."""
self.throbber_loader.setVisible(True)
+ self.public_projects_checkbox.setEnabled(False)
self.project_api = Project(
on_finished=self.get_available_projects_finished)
diff --git a/cadasta/gui/tools/wizard/step_project_download02.py b/cadasta/gui/tools/wizard/step_project_download02.py
index 2d07fe8..f87763b 100644
--- a/cadasta/gui/tools/wizard/step_project_download02.py
+++ b/cadasta/gui/tools/wizard/step_project_download02.py
@@ -1,4 +1,5 @@
-# coding=utf-8
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
"""
Cadasta project download step -**Cadasta Wizard**
@@ -37,6 +38,7 @@
from cadasta.api.api_connect import ApiConnect
from cadasta.common.setting import get_url_instance
from cadasta.vector import tools
+from cadasta.common.setting import get_setting
__copyright__ = "Copyright 2016, Cadasta"
__license__ = "GPL version 3"
@@ -71,7 +73,7 @@ def set_widgets(self):
self.warning_label.setText(self.loading_label_string)
self.get_project_spatial(
self.project['organization']['slug'], self.project['slug'])
- self.parent.next_button.setEnabled(False)
+ self.parent.next_button.setEnabled(True)
def validate_step(self):
"""Check if the step is valid.
@@ -118,25 +120,48 @@ def organization_projects_spatial_call_finished(self, result):
organization_slug,
project_slug)
self.progress_bar.setValue(50)
- relationship_layer = self.relationships_layer(vlayers)
- self.progress_bar.setValue(80)
- party_layer = self.parties_layer()
+
+ download_relationship_and_party = False
+
+ if self.project['access'] == 'public':
+ # Get organization
+ status, results = self.organisation_api.summary_organization(
+ organization_slug)
+
+ if status and 'users' in results:
+ for user in results['users']:
+ if user['username'] == get_setting('username'):
+ download_relationship_and_party = True
+ break
+ else:
+ download_relationship_and_party = True
+
+ relationship_layer_id = None
party_layer_id = None
- if party_layer:
- party_layer_id = party_layer.id()
+
+ if download_relationship_and_party:
+ relationship_layer = self.relationships_layer(vlayers)
+ if relationship_layer:
+ relationship_layer_id = relationship_layer.id()
+
+ party_layer = self.parties_layer()
+ if party_layer:
+ party_layer_id = party_layer.id()
+
+ self.progress_bar.setValue(80)
QCoreApplication.processEvents()
Utilities.save_project_basic_information(
self.project,
vlayers,
- relationship_layer.id(),
+ relationship_layer_id,
party_layer_id
)
else:
pass
self.progress_bar.setValue(self.progress_bar.maximum())
- self.parent.next_button.setEnabled(True)
self.warning_label.setText(self.loaded_label_string)
+ self.parent.close()
def save_organizations(self):
"""Save organizations of user.
@@ -166,6 +191,7 @@ def parties_layer(self):
:param vector_layer: QGS vector layer in memory
:type vector_layer: QgsVectorLayer
"""
+
organization_slug = self.project['organization']['slug']
project_slug = self.project['slug']
attribute = 'parties'
@@ -175,8 +201,8 @@ def parties_layer(self):
if os.path.isfile(csv_path):
os.remove(csv_path)
- api = '/api/v1/organizations/{organization_slug}/projects/' \
- '{project_slug}/parties/'.format(
+ api = u'/api/v1/organizations/{organization_slug}/projects/' \
+ u'{project_slug}/parties/'.format(
organization_slug=organization_slug,
project_slug=project_slug)
@@ -308,12 +334,13 @@ def relationships_layer(self, vector_layers):
:return: Relationship layer
:rtype: QgsVectorLayer
"""
+
organization_slug = self.project['organization']['slug']
project_slug = self.project['slug']
attribute = 'relationships'
- api = '/api/v1/organizations/{organization_slug}/projects/' \
- '{project_slug}/spatial/{spatial_unit_id}/relationships/'
+ api = u'/api/v1/organizations/{organization_slug}/projects/' \
+ u'{project_slug}/spatial/{spatial_unit_id}/relationships/'
csv_path = get_csv_path(
organization_slug,
@@ -346,10 +373,11 @@ def relationships_layer(self, vector_layers):
for index, feature in enumerate(vector_layer.getFeatures()):
attributes = feature.attributes()
+ spatial_unit_id = attributes[spatial_id_index]
spatial_api = api.format(
organization_slug=organization_slug,
project_slug=project_slug,
- spatial_unit_id=attributes[spatial_id_index]
+ spatial_unit_id=spatial_unit_id
)
connector = ApiConnect(get_url_instance() + spatial_api)
status, results = connector.get(paginated=True)
diff --git a/cadasta/gui/tools/wizard/step_project_update01.py b/cadasta/gui/tools/wizard/step_project_update01.py
index 7893c3b..d4074ff 100644
--- a/cadasta/gui/tools/wizard/step_project_update01.py
+++ b/cadasta/gui/tools/wizard/step_project_update01.py
@@ -130,7 +130,7 @@ def project_combo_box_changed(self):
try:
if project['information']['description']:
self.project_description_label.setText(
- self.tr(project['information']['description']))
+ project['information']['description'])
else:
self.project_description_label.setText(
self.tr('No description'))
diff --git a/cadasta/gui/tools/wizard/step_project_update03.py b/cadasta/gui/tools/wizard/step_project_update03.py
index 05d748f..8e255de 100644
--- a/cadasta/gui/tools/wizard/step_project_update03.py
+++ b/cadasta/gui/tools/wizard/step_project_update03.py
@@ -54,6 +54,9 @@ def __init__(self, parent=None):
def set_widgets(self):
"""Set all widgets on the tab."""
+ self.text_edit.setStyleSheet(
+ "background-color: #f0f0f0; color: #757575"
+ )
self.project = self.parent.project['information']
if 'layers' in self.project:
for project_layer in self.project['layers']:
@@ -143,8 +146,8 @@ def update_project(self):
def update_spatial_location(self):
"""Update spatial information."""
- update_loc_api = '/api/v1/organizations/{organization_slug}/' \
- 'projects/{project_slug}/spatial/{spatial_unit_id}/'
+ update_loc_api = u'/api/v1/organizations/{organization_slug}/' \
+ u'projects/{project_slug}/spatial/{spatial_unit_id}/'
location_type_idx = self.layer.fieldNameIndex('type')
location_id_idx = self.layer.fieldNameIndex('id')
@@ -152,9 +155,17 @@ def update_spatial_location(self):
for layer in self.vlayers:
features = layer.getFeatures()
- # Remove unneeded fields
- field_names = [field.name() for field in
- layer.pendingFields()]
+ # Get field names
+ field_names = []
+ layer_prefix = self.project['organization']['slug'] + '/' + \
+ self.project['slug']
+
+ for field_name in layer.pendingFields():
+ if layer_prefix not in field_name.name() and \
+ 'relationships_' not in field_name.name() and \
+ 'parties_' not in field_name.name():
+ field_names.append(field_name.name())
+
field_names.remove('id')
field_names.remove('type')
@@ -223,12 +234,19 @@ def update_relationship_attributes(self):
relationship_type_idx = 2
attributes_idx = 4
- update_api = '/api/v1/organizations/{organization_slug}/projects/' \
- '{project_slug}/relationships/tenure/{relationship_id}/'
+ update_api = u'/api/v1/organizations/{organization_slug}/projects/' \
+ u'{project_slug}/relationships/tenure/{relationship_id}/'
- field_names = [
- field.name() for field in relationship_layer.pendingFields()
- ]
+ # Get field names
+ field_names = []
+ layer_prefix = self.project['organization']['slug'] + '/' + \
+ self.project['slug']
+
+ for field_name in relationship_layer.pendingFields():
+ if layer_prefix not in field_name.name() and \
+ 'relationships_' not in field_name.name() and \
+ 'parties_' not in field_name.name():
+ field_names.append(field_name.name())
# Remove unneeded fields
field_names.remove('spatial_id')
@@ -281,11 +299,21 @@ def update_party_attributes(self):
name_idx = 1
type_idx = 2
- update_api = '/api/v1/organizations/{organization_slug}/projects/' \
- '{project_slug}/parties/{party_id}/'
+ update_api = u'/api/v1/organizations/{organization_slug}/projects/' \
+ u'{project_slug}/parties/{party_id}/'
+
+ # Get field names
+ field_names = []
+ layer_prefix = self.project['organization']['slug'] + '/' + \
+ self.project['slug']
+
+ for field_name in party_layer.pendingFields():
+ if layer_prefix not in field_name.name() and \
+ 'relationships_' not in field_name.name() and \
+ 'parties_' not in field_name.name():
+ field_names.append(field_name.name())
# Remove unneeded fields
- field_names = [field.name() for field in party_layer.pendingFields()]
field_names.remove('id')
field_names.remove('name')
field_names.remove('type')
@@ -362,6 +390,7 @@ def upload_update(self):
)
self.set_progress_bar(100)
+ self.parent.close()
def upload_update_locations(
self,
@@ -417,8 +446,8 @@ def add_new_locations(self, geometry, location_type, attributes=None):
through the project's questionnaire
:type attributes: dict
"""
- api = '/api/v1/organizations/{organization_slug}/projects/' \
- '{project_slug}/spatial/'.format(
+ api = u'/api/v1/organizations/{organization_slug}/projects/' \
+ u'{project_slug}/spatial/'.format(
organization_slug=self.project['organization']['slug'],
project_slug=self.project['slug'])
diff --git a/cadasta/gui/ui/utilities/edit_text_dialog.ui b/cadasta/gui/ui/utilities/edit_text_dialog.ui
index c0575ad..4d59c1b 100644
--- a/cadasta/gui/ui/utilities/edit_text_dialog.ui
+++ b/cadasta/gui/ui/utilities/edit_text_dialog.ui
@@ -33,10 +33,19 @@
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
+
0
-
@@ -49,7 +58,17 @@
9
-
-
+
+
+ PointingHandCursor
+
+
+ Data Schema Help
+
+
+
+ -
+
-
diff --git a/cadasta/gui/ui/wizard/step_project_creation02.ui b/cadasta/gui/ui/wizard/step_project_creation02.ui
index 1b62195..57b2016 100644
--- a/cadasta/gui/ui/wizard/step_project_creation02.ui
+++ b/cadasta/gui/ui/wizard/step_project_creation02.ui
@@ -129,23 +129,46 @@
10
-
-
-
-
- 75
- true
-
-
-
- PointingHandCursor
-
-
- > Advanced
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ true
+
+
+
+ PointingHandCursor
+
+
+ > Advanced
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
-
diff --git a/cadasta/gui/ui/wizard/step_project_creation03.ui b/cadasta/gui/ui/wizard/step_project_creation03.ui
index aa657c0..71e6d92 100644
--- a/cadasta/gui/ui/wizard/step_project_creation03.ui
+++ b/cadasta/gui/ui/wizard/step_project_creation03.ui
@@ -156,10 +156,13 @@
-
- false
+ true
- ForbiddenCursor
+ ArrowCursor
+
+
+ false
true
diff --git a/cadasta/gui/ui/wizard/step_project_update03.ui b/cadasta/gui/ui/wizard/step_project_update03.ui
index aa657c0..0339a10 100644
--- a/cadasta/gui/ui/wizard/step_project_update03.ui
+++ b/cadasta/gui/ui/wizard/step_project_update03.ui
@@ -156,10 +156,10 @@
-
- false
+ true
- ForbiddenCursor
+ ArrowCursor
true
diff --git a/cadasta/utilities/utilities.py b/cadasta/utilities/utilities.py
index 71ed995..14a312f 100644
--- a/cadasta/utilities/utilities.py
+++ b/cadasta/utilities/utilities.py
@@ -15,6 +15,7 @@
import logging
import os
import shutil
+import unicodedata
from qgis.core import (
QgsVectorLayer,
QgsMapLayerRegistry,
@@ -375,13 +376,23 @@ def get_downloaded_projects(organization):
os.path.join(dirpath, f)).split('.')[1].split(
splitter)
names = []
+
+ try:
+ project_name = abs_path[-2].decode('utf-8')
+ except (UnicodeDecodeError, UnicodeEncodeError):
+ project_name = unicode(abs_path[-2])
+
+ normalized = unicodedata.normalize(
+ 'NFKC',
+ project_name)
+
names.append(abs_path[-3])
- names.append(abs_path[-2])
+ names.append(normalized)
names.append(abs_path[-1])
+
list_files.append(
'/'.join(names)
)
-
projects = []
for layer in QgsMapLayerRegistry.instance().mapLayers().values():
diff --git a/resources/questionnaire.json b/resources/questionnaire.json
index cec8b65..734fbf8 100644
--- a/resources/questionnaire.json
+++ b/resources/questionnaire.json
@@ -1,6 +1,5 @@
{
"filename": "",
- "title": "",
"id_string": "",
"questions": [
{
@@ -8,81 +7,57 @@
"label": "Label",
"type": "ST",
"required": false,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":1
+ "relevant": null
},
{
"name": "end",
"label": "Label",
"type": "EN",
"required": false,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":2
+ "relevant": null
},
{
"name": "today",
"label": "Label",
"type": "TD",
"required": false,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":3
+ "relevant": null
},
{
"name": "deviceid",
"label": "Label",
"type": "DI",
"required": false,
- "constraint": null,
- "default": null,
- "hint": null,
- "relevant": null,
- "index":4
- },
- {
- "name": "title",
- "label": "Cadasta Platform - UAT Survey",
- "type": "NO",
- "required": false,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":5
+ "relevant": null
},
{
"name": "party_type",
"label": "Party Classification",
"type": "S1",
"required": true,
- "constraint": null,
"default": null,
"hint": null,
"relevant": null,
- "index":6,
"options": [
{
"name": "GR",
- "label": "Group",
- "index": 1
+ "label": "Group"
},
{
"name": "IN",
- "label": "Individual",
- "index": 2
+ "label": "Individual"
},
{
"name": "CO",
- "label": "Corporation",
- "index": 3
+ "label": "Corporation"
}
]
},
@@ -91,73 +66,59 @@
"label": "Party Name",
"type": "TX",
"required": true,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":7
+ "relevant": null
},
{
"name": "location_geometry",
"label": "Location of Parcel",
"type": "GT",
"required": false,
- "constraint": null,
"default": null,
"hint": null,
- "relevant": null,
- "index":8
+ "relevant": null
},
{
"name": "location_type",
"label": "What is the land feature?",
"type": "S1",
"required": true,
- "constraint": null,
"default": null,
"hint": null,
"relevant": null,
- "index":9,
"options": [
{
"name": "PA",
- "label": "Parcel",
- "index": 1
+ "label": "Parcel"
},
{
"name": "CB",
- "label": "Community Boundary",
- "index": 2
+ "label": "Community Boundary"
},
{
"name": "BU",
- "label": "Building",
- "index": 3
+ "label": "Building"
},
{
"name": "AP",
- "label": "Apartment",
- "index": 4
+ "label": "Apartment"
},
{
"name": "PX",
- "label": "Project Extent",
- "index": 5
+ "label": "Project Extent"
},
{
"name": "RW",
- "label": "Right-of-way",
- "index": 6
+ "label": "Right-of-way"
},
{
"name": "NP",
- "label": "National Park Boundary",
- "index": 7
+ "label": "National Park Boundary"
},
{
"name": "MI",
- "label": "Miscellaneous",
- "index": 8
+ "label": "Miscellaneous"
}
]
},
@@ -166,106 +127,85 @@
"label": "What is the social tenure type?",
"type": "S1",
"required": true,
- "constraint": null,
"default": null,
"hint": null,
"relevant": null,
- "index":10,
"options": [
{
"name": "AL",
- "label": "All Types",
- "index": 1
+ "label": "All Types"
},
{
"name": "CR",
- "label": "Carbon Rights",
- "index": 2
+ "label": "Carbon Rights"
},
{
"name": "CO",
- "label": "Concessionary Rights",
- "index": 3
+ "label": "Concessionary Rights"
},
{
"name": "CU",
- "label": "Customary Rights",
- "index": 4
+ "label": "Customary Rights"
},
{
"name": "EA",
- "label": "Easement",
- "index": 5
+ "label": "Easement"
},
{
"name": "ES",
- "label": "Equitable Servitude",
- "index": 6
+ "label": "Equitable Servitude"
},
{
"name": "FH",
- "label": "Freehold",
- "index": 7
+ "label": "Freehold"
},
{
"name": "GR",
- "label": "Grazing Rights",
- "index": 8
+ "label": "Grazing Rights"
},
{
"name": "HR",
- "label": "Hunting/Fishing/Harvest Rights",
- "index": 9
+ "label": "Hunting/Fishing/Harvest Rights"
},
{
"name": "IN",
- "label": "Indigenous Land Rights",
- "index": 10
+ "label": "Indigenous Land Rights"
},
{
"name": "JT",
- "label": "Joint Tenancy",
- "index": 11
+ "label": "Joint Tenancy"
},
{
"name": "LH",
- "label": "Leasehold",
- "index": 12
+ "label": "Leasehold"
},
{
"name": "LL",
- "label": "Longterm leasehold",
- "index": 13
+ "label": "Longterm leasehold"
},
{
"name": "MR",
- "label": "Mineral Rights",
- "index": 14
+ "label": "Mineral Rights"
},
{
"name": "OC",
- "label": "Occupancy (No Documented Rights)",
- "index": 15
+ "label": "Occupancy (No Documented Rights)"
},
{
"name": "TN",
- "label": "Tenancy (Documented Sub-lease)",
- "index": 16
+ "label": "Tenancy (Documented Sub-lease)"
},
{
"name": "TC",
- "label": "Tenancy in Common",
- "index": 17
+ "label": "Tenancy in Common"
},
{
"name": "UC",
- "label": "Undivided Co-ownership",
- "index": 18
+ "label": "Undivided Co-ownership"
},
{
"name": "WR",
- "label": "Water Rights",
- "index": 19
+ "label": "Water Rights"
}
]
}