예제 #1
0
    def processing_data(self):
        """Processing data from all step"""
        self.progress_bar.setVisible(True)
        self.submit_button.setVisible(False)
        self.parent.back_button.setEnabled(False)

        self.set_status(tr('Processing data'))

        self.set_progress_bar(self.current_progress + 25)

        self.set_progress_bar(self.current_progress + 25)

        self.set_progress_bar(self.current_progress + 25)

        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 self.step_2_data.iteritems():
                properties = location['properties']
                if layer_field in properties:
                    try:
                        location['fields']
                    except KeyError:
                        location['fields'] = dict()
                    location['fields'][cadasta_field] = properties[layer_field]
                    del location['properties'][layer_field]

        self.set_progress_bar(100)

        self.set_status(tr('Finished processing data'))

        # Upload project
        self.upload_project()
예제 #2
0
    def set_widgets(self):
        """Set all widgets."""
        self.text_test_connection_button = self.test_connection_button.text()
        self.ok_label.setVisible(False)
        self.save_button.setEnabled(False)

        self.test_connection_button.clicked.connect(self.login)
        self.save_button.clicked.connect(self.save_authtoken)
        self.clear_button.setText(tr('Clear'))

        self.clear_button.setEnabled(True)
        self.clear_button.clicked.connect(self.clear_information)
        self.url_input.setText(get_url_instance())

        # If login information exists
        if not self.auth_token:
            self.auth_token = get_authtoken()

        if self.auth_token:
            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.'))
        else:
            self.token_status.setText(tr('Auth token is empty.'))
예제 #3
0
    def extract_error_detail(result):
        """Extract detail of error of connection

        :param result: result of connection
        :type result: str

        :return: detail result
        :rtype:str
        """
        error_detail = tr('Error : ')
        detail = ''
        try:
            json_result = json.loads(result)
            # get code
            code = json_result['code']
            error_detail = tr('Error %s : ' % str(code))
            try:
                # get detail
                detail = json_result['result']['detail']
            except (TypeError, KeyError):
                detail = json.dumps(json_result['result'])
        except ValueError:
            detail = result
        error_detail += detail
        return '<span style="color:red">%s</span><br>' % error_detail
예제 #4
0
    def upload_parties(self):
        """Upload party from this project."""
        self.set_status(tr('Uploading parties'))

        party = 0

        # reset progress bar
        current_progress = 0
        self.set_progress_bar(current_progress)
        total_layer = len(self.data['locations']['features'])
        progress_block = 100 / total_layer

        post_url = self._url_post_parties()

        if not post_url:
            # Project is not uploaded
            return

        for layer in self.data['locations']['features']:
            if 'party_name' in layer['fields'] and \
                            'party_type' in layer['fields']:
                post_data = {
                    'name': layer['fields']['party_name'],
                    'type': layer['fields']['party_type']
                }

                post_data = Utilities.json_dumps(post_data)

                connector = ApiConnect(get_url_instance() + post_url)
                status, result = self._call_json_post(connector, post_data)

                if status:
                    party += 1
                    try:
                        result_dict = result
                        if 'id' in result_dict:
                            layer['party_id'] = result_dict['id']
                    except ValueError as e:
                        LOGGER.exception('message')
                else:
                    self.set_progress_bar(0)
                    self.set_status(Utilities.extract_error_detail(result))
            else:
                self.set_status(tr('No party attributes found'))
            current_progress += progress_block
            self.set_progress_bar(current_progress)

        if party == 0:
            self.set_status(tr('Not uploading any party'))
        else:
            self.set_status(
                tr('Finished uploading {party} party'.format(party=party)))

        self.set_progress_bar(100)
예제 #5
0
    def upload_project(self):
        """Upload project to cadasta."""
        # check requirement attributes
        if self.check_requirement():
            return

        self.set_status(tr('Uploading project'))
        self.current_progress = 0
        self.set_progress_bar(self.current_progress)

        post_data = {
            'name': self.data['project_name'],
            'description': self.data['description'],
            'extent': self.data['extent'],
            'access': 'private' if self.data['private'] else 'public',
            'contacts': self.data['contacts']
        }

        if self.data['project_url']:
            post_data['urls'] = [self.data['project_url']]

        post_url = '/api/v1/organizations/%s/projects/' % (
            self.data['organisation']['slug'])

        post_data = Utilities.json_dumps(post_data)

        connector = ApiConnect(get_url_instance() + post_url)
        status, result = self._call_json_post(connector, post_data)

        self.set_progress_bar(self.current_progress + self.upload_increment)
        self.set_status(tr('Finished uploading project'))

        if status:
            self.project_upload_result = result
            upload_questionnaire_attribute = False
            # create questionnaire first
            # after creating location, questionnaire is blocked
            if self.data['questionnaire']:
                upload_questionnaire_attribute = True
                self.upload_questionnaire_project()
            total_locations = len(self.data['locations']['features'])
            if total_locations > 0:
                self.upload_locations(upload_questionnaire_attribute)
                self.upload_parties()
                self.upload_relationships()
            self.rerender_saved_layer()
            self.set_progress_bar(100)
        else:
            self.set_progress_bar(0)
            self.set_status(Utilities.extract_error_detail(result))

        self.set_status(tr('Finished'))
        self.parent.close()
예제 #6
0
    def upload_relationships(self):
        """Upload relationships attribute to cadasta."""
        self.set_status(tr('Uploading relationship'))

        # reset progress bar
        current_progress = 0
        self.set_progress_bar(current_progress)
        total_layer = len(self.data['locations']['features'])
        progress_block = 100 / total_layer

        relationship = 0

        url = self._url_post_relationships()

        for layer in self.data['locations']['features']:

            if 'relationship_type' in layer['fields'] and \
                            'spatial_id' in layer and \
                            'party_id' in layer:

                post_data = {
                    'tenure_type': layer['fields']['relationship_type'],
                    'spatial_unit': layer['spatial_id'],
                    'party': layer['party_id']
                }

                post_data = Utilities.json_dumps(post_data)

                connector = ApiConnect(get_url_instance() + url)
                status, result = self._call_json_post(connector, post_data)

                if status:
                    relationship += 1
                else:
                    self.set_progress_bar(0)
                    self.set_status(Utilities.extract_error_detail(result))
            else:
                self.set_status(tr('No relationship attributes found'))

            current_progress += progress_block
            self.set_progress_bar(current_progress)

        if relationship == 0:
            self.set_status(tr('Not uploading any relationship'))
        else:
            self.set_status(
                tr('Finished uploading {num} relationship'.format(
                    num=relationship)))

        self.set_progress_bar(100)
예제 #7
0
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('The plugin integrates with the cadasta.org platform')))
    message.add(m.Paragraph(tr('developed by kartoza.com')))
    return message
예제 #8
0
    def add(self, item):
        """add a Text MessageElement to the existing Text

        Strings can be passed and are automatically converted in to
        item.Text()

        Args:
            Text text, an element to add to the text

        Returns:
            None

        Raises:
            Errors are propagated
        """
        if self._is_stringable(item) or self._is_qstring(item):
            self.items.append(PlainText(item))
        elif isinstance(item, MessageElement):
            self.items.append(item)
        elif isinstance(item, QPyNullVariant):
            self.items.append(
                PlainText(
                    tr('Null (PyQt4.QtCore.QPyNullVariant) found from the data.'
                       )))
        else:
            raise InvalidMessageItemError(item, item.__class__)
예제 #9
0
    def on_next_button_released(self):
        """Handle the Next button release.

        .. note:: This is an automatic Qt slot
           executed when the Next button is released.
        """
        current_step = self.get_current_step()
        valid_status, message = current_step.validate_step()

        if not valid_status:
            self.message_bar = QgsMessageBar()
            self.message_bar.pushWarning(
                tr('Error'),
                message
            )
            LOGGER.info(message)
            return

        self.steps.append(current_step)

        # Determine the new step to be switched
        new_step = current_step.get_next_step()

        if new_step is not None:
            # Prepare the next tab
            self.prepare_the_next_step(new_step)
            new_step.set_widgets()
        else:
            # Wizard complete
            self.accept()
            return

        self.go_to_step(new_step)
예제 #10
0
    def validate_step(self):
        """Check if the step is valid.

        :returns: Tuple of validation status and error message if any
        :rtype: ( bool, str )
        """
        error_message = ''

        if self.project_url() and \
                not is_valid_url(self.project_url()):
            error_message = tr('Invalid url.')

        if not self.project_name() or \
                not self.selected_organisation():
            error_message = tr('Empty required field.')

        return (error_message == '', error_message)
    def validate_step(self):
        """Check if the step is valid.

        :returns: Tuple of validation status and error message if any
        :rtype: ( bool, str )
        """
        error_message = ''
        if not self.location_type_box.currentText() or \
                    tr('No field') in self.location_type_box.currentText():
            error_message = tr(
                'Location type field is required, please select.'
            )

        return (
            error_message == '',
            error_message
        )
예제 #12
0
 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)
예제 #13
0
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('Cadasta Help'), **INFO_STYLE)
    return message
예제 #14
0
    def project_combo_box_changed(self):
        """Update description when combo box changed."""
        project = self.selected_project()
        if not project:
            self.project_description_label.setText(
                tr('This is the read only project description that '
                   'changes when the combo box above is changed.'))
            self.project_url_label.setText('-')
            self.contact_information_label.setText('-')
            self.privacy_status_label.setText('-')
            self.set_enabled_add_contact_label(False)
            return

        if project['description']:
            self.project_description_label.setText(project['description'])
        else:
            self.project_description_label.setText(
                self.tr(project['name'].encode('utf-8')))

        if project['urls']:
            project_urls = ''
            for url in project['urls']:
                project_urls += url + ' \n'

            if not project_urls.isspace():
                project_urls = project_urls[:-2]
                self.project_url_label.setText(project_urls)
            else:
                self.project_url_label.setText('-')
        else:
            self.project_url_label.setText('-')

        if project['contacts']:
            project_contacts = ''
            for contact in project['contacts']:
                project_contacts += contact['name']
                if 'email' in contact and contact['email']:
                    project_contacts += ', ' + contact['email']
                if 'tel' in contact and contact['tel']:
                    project_contacts += ', ' + contact['tel']
                project_contacts += ' \n'

            if project_contacts:
                self.set_enabled_add_contact_label(True)
                self.current_contacts = project['contacts']
                project_contacts = project_contacts[:-2]
                self.contact_information_label.setText(project_contacts)
        else:
            self.contact_information_label.setText('-')
            self.set_enabled_add_contact_label(False)

        if project['access']:
            self.privacy_status_label.setText(project['access'].title())
예제 #15
0
    def validate_step(self):
        """Check if the step is valid.

        :returns: Tuple of validation status and error message if any
        :rtype: ( bool, str )
        """
        error_message = ''

        if not self.selected_project():
            error_message += tr('Missing project.')

        return (error_message == '', error_message)
예제 #16
0
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
예제 #17
0
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('You can find updated documentation and suggested workflows '
               'on our main '
               'documentation pages: <a href="https://docs.cadasta.org/en/'
               '11-qgis-plugin.html">QGIS chapter</a>. (requires internet '
               'access to view)')))
    message.add(
        m.Paragraph(
            tr('There are three windows that will help you '
               'to manage your project\'s data.')))

    bullets = m.BulletedList()
    bullets.add(m.Text(m.ImportantText(tr('Download Project'))))
    bullets.add(m.Text(m.ImportantText(tr('Create Project'))))
    bullets.add(m.Text(m.ImportantText(tr('Update Project'))))
    message.add(bullets)

    message.add(
        m.Paragraph(
            tr('Use the <b>User Settings</b> window to log in to your account '
               'and get started!'
               '')))
    return message
예제 #18
0
    def upload_questionnaire_project(self):
        """Upload questionnaire."""
        self.set_status(tr('Update questionnaire'))
        post_url = '/api/v1/organizations/' \
                   '%s/projects/%s/questionnaire/' % (
                       self.data['organisation']['slug'],
                       self.project_upload_result['slug']
                   )

        post_data = QByteArray()
        post_data.append(self.data['questionnaire'])

        connector = ApiConnect(get_url_instance() + post_url)
        status, result = self._call_json_put(connector, post_data)

        self.set_status(tr('Finished update questionnaire'))
        if status:
            self.set_progress_bar(self.current_progress +
                                  self.upload_increment)
        else:
            self.set_progress_bar(0)
            self.set_status(Utilities.extract_error_detail(result))
예제 #19
0
    def add(self, text):
        """add a Text MessageElement to the existing Text

        Strings can be passed and are automatically converted in to
        item.Text()

        :param text: An element to add to the text.
        :type text: str
        """
        if self._is_stringable(text) or self._is_qstring(text):
            self.text.append(PlainText(text))
        elif isinstance(text, Text):
            self.text.append(text)
        elif isinstance(text, QPyNullVariant):
            self.text.append(
                PlainText(
                    tr('Null (PyQt4.QtCore.QPyNullVariant) found from the data.'
                       )))
        elif text is None:
            self.text.append(PlainText(
                tr('None or Null found from the data.')))
        else:
            raise InvalidMessageItemError(text, text.__class__)
예제 #20
0
 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.test_connection_button.setEnabled(True)
     self.token_status.setText(tr('Auth token is empty.'))
     self.unauthenticated.emit()
예제 #21
0
    def _render(self):
        """Create a Message version of this ErrorMessage

        Args:
            none

        Returns:
            the Message instance of this ErrorMessage

        Raises:
            Errors are propagated
        """
        message = Message()
        message.add(Heading(tr('Problem'), **PROBLEM_STYLE))
        message.add(
            Paragraph(
                tr('The following problem(s) were encountered whilst running the '
                   'analysis.')))
        items = BulletedList()
        for p in reversed(self.problems):
            # p is _always_ not None
            items.add(p)
        message.add(items)

        message.add(Heading(tr('Suggestion'), **SUGGESTION_STYLE))
        message.add(
            Paragraph(tr('You can try the following to resolve the issue:')))
        if len(self.suggestions) < 1:
            suggestions = self.standard_suggestions()
            message.add(suggestions)
        else:
            items = BulletedList()
            for s in reversed(self.suggestions):
                if s is not None:
                    items.add(s)
            message.add(items)

        if len(self.details) > 0:
            items = BulletedList()
            message.add(Heading(tr('Details'), **DETAILS_STYLE))
            message.add(
                Paragraph(
                    tr('These additional details were reported when the problem '
                       'occurred.')))
            for d in self.details:
                if d is not None:
                    items.add(d)
            message.add(items)

        message.add(Heading(tr('Diagnostics'), **TRACEBACK_STYLE))
        message.add(self.tracebacks)
        return message
    def set_widgets(self):
        """Set all widgets on the tab."""
        if not self.layer or self.layer != self.parent.layer:
            self.layer = self.parent.layer
            self.set_attributes_box()
        self.advanced_box.setVisible(False)
        self.advanced_button.mousePressEvent = self.toogled_advanced_area
        self.questionnaire_button.clicked.connect(
            self.show_questionnaire
        )
        self.check_questionnaire()
        self.label.setToolTip(
            tr('Location type field is required please select.'))

        # Set tab focus
        self.location_type_box.setFocus()
    def set_attributes_box(self):
        """Set all attribute box widgets."""
        field_names = [field.name() for field in self.layer.pendingFields()]

        self.layer_attributes = []

        for elem in self.layer.getFeatures():
            self.layer_attributes.append(
                (dict(zip(field_names, elem.attributes())))
            )

        field_names.append('--------- {field} ----------'.format(
                field=tr('No field')))
        self.set_items_combo_box(self.location_type_box, field_names)
        self.set_items_combo_box(self.party_name_box, field_names)
        self.set_items_combo_box(self.relationship_type_box, field_names)
        self.set_items_combo_box(self.party_type_box, field_names)
예제 #24
0
    def emit(self, record):
        """Try to log the message to QGIS if available, otherwise do nothing.

        :param record: logging record containing whatever info needs to be
                logged.
        """
        try:
            # Check logging.LogRecord properties for lots of other goodies
            # like line number etc. you can get from the log message.
            QgsMessageLog.logMessage(record.getMessage(), 'CadastaQGISPlugin',
                                     0)
        except MemoryError:
            message = tr(
                'Due to memory limitations on this machine, Cadasta can not '
                'handle the full log')
            print message
            QgsMessageLog.logMessage(message, 'CadastaQGISPlugin', 0)
예제 #25
0
    def __init__(self, parent=None, iface=None):
        """Constructor for the dialog.

        .. note:: In QtDesigner the advanced editor's predefined keywords
           list should be shown in english always, so when adding entries to
           cboKeyword, be sure to choose :safe_qgis:`Properties<<` and untick
           the :safe_qgis:`translatable` property.

        :param parent: Parent widget of this dialog.
        :type parent: QWidget

        :param iface: QGIS QGisAppInterface instance.
        :type iface: QGisAppInterface
        """
        super(ProjectCreationWizard, self).__init__(parent, iface)

        self.set_subtitle(tr('Cadasta project creation wizard'))
        self.layer = None
예제 #26
0
    def check_requirement(self):
        """Checking attributes that required.

        :return: Is missed
        :rtype: bool
        """
        requirement_miss = False
        for location in self.data['locations']['features']:
            try:
                location['fields']['location_type']
            except KeyError:
                self.set_progress_bar(0)
                self.set_status(
                    Utilities.extract_error_detail(
                        tr('Location_type is not found in attribute. '
                           'Please update before uploading again.')))
                requirement_miss = True
                break
        return requirement_miss
예제 #27
0
    def __init__(self, parent=None, iface=None):
        """Constructor for the dialog.

        .. note:: In QtDesigner the advanced editor's predefined keywords
           list should be shown in english always, so when adding entries to
           cboKeyword, be sure to choose :safe_qgis:`Properties<<` and untick
           the :safe_qgis:`translatable` property.

        :param parent: Parent widget of this dialog.
        :type parent: QWidget

        :param iface: QGIS QGisAppInterface instance.
        :type iface: QGisAppInterface
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.setWindowTitle(tr('About Cadasta %s' % get_plugin_version()))
        self.iface = iface
        # set the helpers
        self.show_cadasta_about()
예제 #28
0
    def __init__(self, parent=None, iface=None,
                 title='Cadasta', subtitle='', widget=None):
        """Constructor for the dialog.

        .. note:: In QtDesigner the advanced editor's predefined keywords
           list should be shown in english always, so when adding entries to
           cboKeyword, be sure to choose :safe_qgis:`Properties<<` and untick
           the :safe_qgis:`translatable` property.

        :param parent: Parent widget of this dialog.
        :type parent: QWidget

        :param iface: QGIS QGisAppInterface instance.
        :type iface: QGisAppInterface

        :param title: Title of dialog.
        :type title: str

        :param subtitle: Subtitle of dialog.
        :type subtitle: str

        :param widget: Widget that will be rendered to dialog
        :type widget: WidgetBase
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.setWindowTitle(title)
        self.label_subtitle.setText(
            tr(subtitle)
        )

        self.iface = iface
        self.set_logo()
        self.widget = widget
        if self.widget:
            self.widget.parent = self
            self.socket_layout.addWidget(self.widget)
예제 #29
0
    def upload_locations(self, update_questionnaire_attribute):
        """Upload project locations to cadasta.

        :param update_questionnaire_attribute: Boolean to check if it need to
         upload the attributes
        :type update_questionnaire_attribute: bool
        """
        self.set_status(tr('Uploading locations'))
        total_locations = len(self.data['locations']['features'])
        progress_left = \
            (100 - self.current_progress - self.upload_increment) \
            / total_locations

        post_url = '/api/v1/organizations/%s/projects/%s/spatial/' % (
            self.data['organisation']['slug'],
            self.project_upload_result['slug'])

        failed = 0

        try:
            questionnaire = json.loads(self.questionnaire)
        except ValueError:
            questionnaire = {}

        for location in self.data['locations']['features']:
            post_data = {
                'geometry': location['geometry'],
                'type': location['fields']['location_type']
            }

            if update_questionnaire_attribute:
                if location['properties']:
                    post_data['attributes'] = location['properties']
                for key, value in post_data['attributes'].iteritems():
                    # Set None to empty string
                    if not value:
                        post_data['attributes'][key] = u''
                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(connector, post_data)

            if status:
                self.set_progress_bar(self.current_progress + progress_left)
                try:
                    result_obj = result
                    if 'properties' in result_obj:
                        location['spatial_id'] = result_obj['properties']['id']
                except ValueError as e:
                    LOGGER.exception('message')
            else:
                self.set_progress_bar(0)
                self.set_status(Utilities.extract_error_detail(result))
                failed += 1

        self.set_progress_bar(100)

        if failed == 0:
            self.set_status(tr('Finished uploading all locations'))
        else:
            self.set_status(tr('Finish with %d failed' % failed))