def upload_parties(self, api, party_name, party_type, attributes=None): """Upload party data. :param api: Api url to upload party :type api: str :param party_name: Party name :type party_name: str :param party_type: Party type :type party_type: str :param attributes: Project-specific attributes that are defined through the project's questionnaire :type attributes: dict """ post_data = { 'name': party_name, 'type': party_type } if attributes: post_data['attributes'] = attributes connector = ApiConnect(get_url_instance() + api) status, result = connector.patch_json(Utilities.json_dumps(post_data)) if status: self.set_status( self.tr('Party updated.') ) else: self.set_status( Utilities.extract_error_detail(result) )
def upload_relationship(self, api, relationship_type, attributes=None): """Upload relationship data. :param api: Api url to upload party :type api: str :param relationship_type: Relationship type :type relationship_type: str :param attributes: Project-specific attributes that are defined through the project's questionnaire :type attributes: dict """ post_data = { 'tenure_type': relationship_type, } if attributes: post_data['attributes'] = attributes connector = ApiConnect(get_url_instance() + api) status, result = connector.patch_json(Utilities.json_dumps(post_data)) if status: self.set_status( self.tr('Relationship updated.') ) else: self.set_status( Utilities.extract_error_detail(result) )
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)
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()
def organization_projects_spatial_call_finished(self, result): """Function when Organization Project Spatial Api finished. :param result: result of request :type result: (bool, list/dict/str) """ self.save_organizations() if result[0]: # save result to local file organization_slug = result[2] project_slug = result[3] vlayers = Utilities.save_layer(result[1], organization_slug, project_slug) self.progress_bar.setValue(50) 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 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, party_layer_id) else: pass self.progress_bar.setValue(self.progress_bar.maximum()) self.warning_label.setText(self.loaded_label_string) self.parent.close()
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)
def update_project(self): """Update a basic project information in an organization.""" step2 = self.parent.step_project_update02 contact_item_list = step2.project_contact_list.selectedItems() contacts = [] for contact_item in contact_item_list: contact = contact_item.data(Qt.UserRole) contact_data = {} if contact.name: contact_data['name'] = contact.name if contact.phone: contact_data['tel'] = contact.phone if contact.email: contact_data['email'] = contact.email contacts.append(contact_data) access = 'private' if step2.access_checkbox.isChecked() else 'public' post_data = { 'name': step2.project_name_text.displayText(), 'description': step2.project_desc_text.toPlainText(), 'access': access, 'contacts': contacts } if step2.project_url_text.displayText(): post_data['urls'] = [ step2.project_url_text.displayText() ] status, response = step2.send_update_request(post_data) if status: Utilities.update_project_basic_information( information=response, vlayers=self.vlayers ) self.set_status( self.tr('Update success') ) else: self.set_status( Utilities.extract_error_detail(response) )
def add_new_locations(self, geometry, location_type, attributes=None): """Add new location :param geometry: Location geojson geometry :type geometry: str :param location_type: Location type :type location_type: str :param attributes: Project-specific attributes that are defined through the project's questionnaire :type attributes: dict """ api = u'/api/v1/organizations/{organization_slug}/projects/' \ u'{project_slug}/spatial/'.format( organization_slug=self.project['organization']['slug'], project_slug=self.project['slug']) post_data = { 'geometry': geometry } if location_type: post_data['type'] = location_type if attributes: post_data['attributes'] = attributes connector = ApiConnect(get_url_instance() + api) status, result = connector.post_json(Utilities.json_dumps(post_data)) if status: self.set_status( self.tr('Location added.') ) return result['properties']['id'] else: self.set_status( Utilities.extract_error_detail(result) ) return None
def upload_update_locations( self, api, geometry, location_type, attributes=None): """Upload update location data. :param api: Api url to upload location :type api: str :param geometry: Location geojson geometry :type geometry: str :param location_type: Location type :type location_type: str :param attributes: Project-specific attributes that are defined through the project's questionnaire :type attributes: dict """ post_data = { 'geometry': geometry, 'type': location_type } if attributes: post_data['attributes'] = attributes connector = ApiConnect(get_url_instance() + api) status, result = connector.patch_json(Utilities.json_dumps(post_data)) if status: self.set_status( self.tr('Location updated.') ) else: self.set_status( Utilities.extract_error_detail(result) )
def layer_will_be_removed(self, layer_id): """Function that triggered when layer will be removed. :param layer_id: Removed layer id. :type layer_id: QString """ layer = QgsMapLayerRegistry.instance().mapLayer(layer_id) layer_names = layer.name().split('/') if len(layer_names) > 1 and \ ('relationships' in layer.name() or 'parties' in layer.name()): try: organization_slug, project_slug, attribute = layer_names Utilities.add_tabular_layer( layer, organization_slug, project_slug, attribute ) setting_value = '%s/%s' % ( organization_slug, project_slug ) setting_file = get_setting('layers_added') if setting_file: setting_files = setting_file.split(',') setting_files.remove(setting_value) setting_file = ','.join(setting_files) set_setting('layers_added', setting_file) else: self.project_update_wizard.setEnabled(False) if not get_setting('layers_added'): self.project_update_wizard.setEnabled(False) except ValueError: return
def organization_projects_spatial_call_finished(self, result): """Function when Organization Project Spatial Api finished. :param result: result of request :type result: (bool, list/dict/str) """ if result[0]: # save result to local file organization_slug = result[2] project_slug = result[3] vlayers = Utilities.save_layer(result[1], organization_slug, project_slug) relationship_layer = self.relationships_layer( vlayers, organization_slug, project_slug) party_layer = self.parties_layer(organization_slug, project_slug) QCoreApplication.processEvents() Utilities.save_project_basic_information( information=self.project_upload_result, vlayers=vlayers, relationship_layer_id=relationship_layer.id(), party_layer_id=party_layer.id()) else: pass
def layer_added(self, layer): """Function that triggered when layer was added. :param layer: Added layer. :type layer: QgsVectorLayer """ # Load csv file layer_names = layer.name().split('/') if len(layer_names) > 2 and \ ('relationships' in layer.name() or 'parties' in layer.name()): try: organization_slug, project_slug, attribute = layer_names Utilities.load_csv_file_to_layer( layer, organization_slug, project_slug, attribute) self.project_update_wizard.setEnabled(True) setting_value = '%s/%s' % ( organization_slug, project_slug ) setting_file = get_setting('layers_added') if not setting_file: set_setting('layers_added', setting_value) else: if setting_value not in setting_file: set_setting( 'layers_added', setting_file + ',' + setting_value ) except ValueError: return
def get_downloaded_project(self, results): """Get downloaded project from organization slug. :param results: result of request :type results: (bool, list/dict/str) """ projects = [] if not results[0]: self.throbber_loader.setVisible(False) return for organization in results[1]: projects.extend( Utilities.get_downloaded_projects(organization['slug'])) self.get_available_projects_finished(projects)
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
def get_available_projects_finished(self, result): """Function when Project Api finished. :param result: result of request :type result: (bool, list/dict/str) """ 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')) processed_downloaded_projects = [] downloaded_projects = Utilities.get_all_downloaded_projects() for downloaded_project in downloaded_projects: project_descriptions = downloaded_project['name'].split('/') organization = project_descriptions[0] name = project_descriptions[1] processed_downloaded_projects.append( (organization + '-' + name).encode('utf-8')) for index, project in enumerate(projects): project_slug = '{organization_slug}-{project_slug}'.format( organization_slug=project['organization']['slug'].encode( 'utf-8'), project_slug=project['slug'].encode('utf-8')) self.project_combo_box.addItem(project['name'], project) self.project_combo_box.setCurrentIndex(index) self.project_combo_box.model().item(index).setEnabled( project_slug not in processed_downloaded_projects) # Set selected to first item self.project_combo_box.setCurrentIndex(0) else: pass
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))
def relationships_layer(self, vector_layers): """Create relationship layer. :param vector_layers: List of QGS vector layer in memory :type vector_layers: list of QgsVectorLayer :return: Relationship layer :rtype: QgsVectorLayer """ organization_slug = self.project['organization']['slug'] project_slug = self.project['slug'] attribute = 'relationships' api = u'/api/v1/organizations/{organization_slug}/projects/' \ u'{project_slug}/spatial/{spatial_unit_id}/relationships/' csv_path = get_csv_path(organization_slug, project_slug, attribute) if os.path.isfile(csv_path): os.remove(csv_path) relationship_layer = tools.create_memory_layer( layer_name='%s/%s/%s' % (organization_slug, project_slug, attribute), geometry=QGis.NoGeometry, fields=[ QgsField('spatial_id', QVariant.String, "string"), QgsField('rel_id', QVariant.String, "string"), QgsField('rel_name', QVariant.String, "string"), QgsField('party_id', QVariant.String, "string"), QgsField('attributes', QVariant.String, "string"), ]) QgsMapLayerRegistry.instance().addMapLayer(relationship_layer) for vector_layer in vector_layers: # Add relationship layer id to spatial attribute table spatial_id_index = vector_layer.fieldNameIndex('id') 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=spatial_unit_id) connector = ApiConnect(get_url_instance() + spatial_api) status, results = connector.get(paginated=True) if not status or len(results) == 0: continue try: for result in results: relationship_layer.startEditing() fet = QgsFeature() questionnaire_attr = result['attributes'] if not questionnaire_attr: questionnaire_attr = '-' else: questionnaire_attr = json.dumps(questionnaire_attr) fet.setAttributes([ attributes[spatial_id_index], result['id'], result['tenure_type'], result['party']['id'], questionnaire_attr, ]) relationship_layer.addFeature(fet, True) relationship_layer.commitChanges() except (IndexError, KeyError): continue self.process_attributes(relationship_layer) Utilities.add_tabular_layer(relationship_layer, organization_slug, project_slug, attribute) return relationship_layer
def parties_layer(self): """Create parties layer. :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' csv_path = get_csv_path(organization_slug, project_slug, attribute) if os.path.isfile(csv_path): os.remove(csv_path) api = u'/api/v1/organizations/{organization_slug}/projects/' \ u'{project_slug}/parties/'.format( organization_slug=organization_slug, project_slug=project_slug) connector = ApiConnect(get_url_instance() + api) status, results = connector.get(paginated=True) if not status: return party_layer = tools.create_memory_layer( layer_name='%s/%s/%s' % (organization_slug, project_slug, attribute), geometry=QGis.NoGeometry, fields=[ QgsField('id', QVariant.String, "string"), QgsField('name', QVariant.String, "string"), QgsField('type', QVariant.String, "string"), QgsField('attributes', QVariant.String, "string"), ]) QgsMapLayerRegistry.instance().addMapLayer(party_layer) for party in results: party_layer.startEditing() feature = QgsFeature() questionnaire_attr = party['attributes'] if not questionnaire_attr: questionnaire_attr = '-' else: questionnaire_attr = json.dumps(questionnaire_attr) feature.setAttributes([ party['id'], party['name'], party['type'], questionnaire_attr ]) party_layer.addFeature(feature, True) party_layer.commitChanges() QCoreApplication.processEvents() self.process_attributes(party_layer) Utilities.add_tabular_layer(party_layer, organization_slug, project_slug, attribute) return party_layer
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))
def update_party_attributes(self): """Update party attribute for this project.""" information = Utilities.get_basic_information_by_vector(self.layer) if not information: return if 'party_layer_id' not in information: return party_id = information['party_layer_id'] party_layer = QgsMapLayerRegistry.instance().mapLayer(party_id) if not party_layer: return party_feats = party_layer.getFeatures() id_idx = 0 name_idx = 1 type_idx = 2 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.remove('id') field_names.remove('name') field_names.remove('type') for feature in party_feats: attributes = feature.attributes() api = update_api.format( organization_slug=self.project['organization']['slug'], project_slug=self.project['slug'], party_id=attributes[id_idx] ) # Check if there are questionnaire attributes questionnaire_attributes = dict() for field_name in field_names: index = party_layer.fieldNameIndex(field_name) if index == -1: continue questionnaire = attributes[index] if questionnaire and questionnaire != '-': questionnaire_attributes[field_name] = questionnaire self.upload_parties( api, attributes[name_idx], attributes[type_idx], questionnaire_attributes )