コード例 #1
0
 def __init__(self, parent):
     super(google_drive, self).__init__(parent, self.parameters)
     self.importDataFromService = QgisODKimportDataFromService(self.module)
     self.authorization = None
     self.verification = None
     self.client_id = "88596974458-r5dckj032ton00idb87c4oivqq2k1pks.apps.googleusercontent.com"
     self.client_secret = "c6qKnhBdVxkPMH88lHf285hQ"
     self.getCollectors()
コード例 #2
0
ファイル: QgisODK_mod_dialog.py プロジェクト: cuulee/QgisODK
 def __init__(self, parent, parameters):
     super(external_service, self).__init__(parent)
     self.parent = parent
     self.module = parent.parent().parent().parent().module
     self.importDataFromService = QgisODKimportDataFromService(self)
     self.iface = parent.parent().parent().parent().module.iface
     self.resize(QSize(310,260))
     self.setColumnCount(2)
     self.setColumnWidth(0, 152)
     self.setColumnWidth(1, 152)
     self.setRowCount(len(parameters)-1)
     self.verticalHeader().hide()
     self.horizontalHeader().hide()
     
     S = QSettings()
     for row,parameter in enumerate(parameters):
         if row == 0:
             self.service_id = parameter[1]
             continue
         row = row -1
         pKey = QTableWidgetItem (parameter[0])
         pKey.setFlags(pKey.flags() ^ Qt.ItemIsEditable)
         pValue = QTableWidgetItem (parameter[1])
         self.setItem(row,0,pKey)
         valueFromSettings = S.value("qgisodk/%s/%s/" % (self.service_id,self.item(row,0).text()), defaultValue =  "undef")
         if not valueFromSettings or valueFromSettings == "undef":
             self.setItem(row,1,pValue)
             S.setValue("qgisodk/%s/%s/" % (self.service_id,self.item(row,0).text()),parameter[1])
         else:
             self.setItem(row,1,QTableWidgetItem (valueFromSettings))
コード例 #3
0
class google_drive(external_service):
    parameters = [["id", "google_drive"], ["google drive login", ""],
                  ["data collectors emails", ""], ["folder", ""],
                  ["data collection table ID", ""],
                  ["notifications?(YES/NO)", "YES"]]

    def __init__(self, parent):
        super(google_drive, self).__init__(parent, self.parameters)
        self.importDataFromService = QgisODKimportDataFromService(self.module)
        self.authorization = None
        self.verification = None
        self.client_id = "88596974458-r5dckj032ton00idb87c4oivqq2k1pks.apps.googleusercontent.com"
        self.client_secret = "c6qKnhBdVxkPMH88lHf285hQ"
        self.getCollectors()

    def collectData(self):
        '''
        interactive table selection
        '''
        #remoteTableName, response = self.getAvailableDataCollections()
        remoteTableName = QgisODKImportCollectedData.getXFormID(self)
        if remoteTableName:
            remoteTableID = self.getIdFromName(remoteTableName)
        else:
            self.iface.messageBar().pushMessage(
                self.tr("QGISODK plugin"),
                self.tr("no data collect table selected"),
                level=QgsMessageBar.CRITICAL,
                duration=6)
            return

        if remoteTableID != '':
            remoteTable = self.getTable(remoteTableID)
            remoteTableMetadata = self.getMetadataFromID(remoteTableID)
            self.importDataFromService.view(remoteTableMetadata, remoteTable)
        else:
            self.iface.messageBar().pushMessage(
                self.tr("QGISODK plugin"),
                self.tr("undefined data collect table ID"),
                level=QgsMessageBar.CRITICAL,
                duration=6)

    def getCollectors(self):
        collectorsFromParams = self.getValue("data collectors emails").split(
            ' ')
        self.collectors = []
        email_regex = re.compile(
            r"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")
        for collector in collectorsFromParams:
            if email_regex.match(collector):
                self.collectors.append(collector)

    def send_message(self, FROM, TO, SUBJECT, MSG):
        if not self.authorization:
            self.get_authorization()

        # create a message to send
        message = MIMEText(MSG.encode('utf-8'), 'plain', 'utf-8')
        message['to'] = TO
        message['from'] = FROM
        message['subject'] = SUBJECT.encode('utf-8')
        body = {'raw': base64.b64encode(message.as_string())}

        url = 'https://www.googleapis.com/gmail/v1/users/me/messages/send'
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token']),
            'Content-Type': 'application/json'
        }

        response = requests.post(url,
                                 headers=headers,
                                 data=json.dumps(body),
                                 proxies=self.getProxiesConf())

    def notify(self, XFormName, XFormFolder, collectTableId, collectTableName):
        if self.getValue('notifications?(YES/NO)').upper() == 'YES':
            message = self.tr('''
You are receiving this automatically generated message because you are taking part to a Open Data Kit survey

Your ODK Collect app has to be configured with the following parameters:
a new form called %s has been uploaded in the folder %s shared with you
The Data Collection table is named %s and has the following uri:

https://docs.google.com/spreadsheets/d/%s/edit
            ''') % (XFormName, XFormFolder, collectTableName, collectTableId)
            for email in self.collectors:
                self.send_message(self.getValue('google drive login'), email,
                                  'ODK survey notification', message)

    def shareFileWithCollectors(self, id, role='reader', type='user'):
        url = 'https://www.googleapis.com/drive/v3/files/%s/permissions' % id
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token']),
            'Content-Type': 'application/json'
        }
        for email in self.collectors:
            metadata = {"role": role, "type": type, "emailAddress": email}
            response = requests.post(url,
                                     headers=headers,
                                     data=json.dumps(metadata),
                                     proxies=self.getProxiesConf())

    def getExportMethod(self):
        return 'exportXForm'

    def getExportExtension(self):
        return 'xml'

    def getIdFromName(self, fileName, mimeType=None):
        if not self.authorization:
            self.get_authorization()
        url = 'https://www.googleapis.com/drive/v3/files'
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token'])
        }
        params = {"q": "name = '%s'" % fileName, "spaces": "drive"}
        response = requests.get(url,
                                headers=headers,
                                params=params,
                                proxies=self.getProxiesConf())
        if response.status_code == requests.codes.ok:
            found = response.json()
            files = found['files']
            if len(files) > 0:
                if mimeType:
                    if files[0]['mimeType'] == mimeType:
                        return files[0]['id']
                    else:
                        return None
                else:
                    return files[0]['id']
            else:
                return None

    def getMetadataFromID(self, fileID):
        if not self.authorization:
            self.get_authorization()
        url = 'https://www.googleapis.com/drive/v3/files/' + fileID
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token'])
        }
        response = requests.get(url,
                                headers=headers,
                                proxies=self.getProxiesConf())
        if response.status_code == requests.codes.ok:
            return response.json()
        else:
            return None

    def getAvailableDataCollections(self):
        if not self.authorization:
            self.get_authorization()

        url = 'https://www.googleapis.com/drive/v3/files'
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token'])
        }
        folderID = self.getIdFromName(
            self.getValue('folder'),
            mimeType='application/vnd.google-apps.folder')
        params = {
            "q":
            "mimeType = 'application/vnd.google-apps.spreadsheet' and '%s' in parents"
            % folderID,
            "spaces":
            "drive"
        }
        response = requests.get(url,
                                headers=headers,
                                params=params,
                                proxies=self.getProxiesConf())
        if response.status_code == requests.codes.ok:
            files = response.json()["files"]
            filesList = []
            for file in files:
                filesList.append(file["name"])
            if filesList != []:
                return filesList, response
            else:
                return None, response
        else:
            return None, response

    def createNew(self, name, mimeType, parentsId=None):
        if not self.authorization:
            self.get_authorization()
        if mimeType == 'application/vnd.google-apps.folder' and name == '':
            return 'root'
        foundId = self.getIdFromName(name, mimeType=mimeType)
        if foundId:
            return foundId
        else:
            url = 'https://www.googleapis.com/drive/v3/files'
            headers = {
                'Authorization':
                'Bearer {}'.format(self.authorization['access_token']),
                'Content-Type':
                'application/json'
            }
            metadata = {"name": name, "mimeType": mimeType}
            if parentsId:
                metadata['parents'] = [parentsId]
            response = requests.post(url,
                                     headers=headers,
                                     data=json.dumps(metadata),
                                     proxies=self.getProxiesConf())
            if response.status_code != 200 or 'error' in response.json():
                return None
            return response.json()['id']

    def get_verification(self):  #phase 1 oauth2
        verification_params = {
            'response_type': 'code',
            'client_id': self.client_id,
            'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob:auto',  #
            'scope':
            'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/gmail.send',  #'https://www.googleapis.com/auth/drive.file',
            'login_hint': self.getValue('google drive login')
        }
        response = requests.post(
            'https://accounts.google.com/o/oauth2/v2/auth',
            params=verification_params,
            proxies=self.getProxiesConf())
        if response.status_code == requests.codes.ok:
            self.verification = internalBrowser.getCode(
                response.text, self.getValue('google drive login'))

    def get_authorization(self):  #phase 2 oauth2
        if not self.verification:
            self.get_verification()

        authorization_params = {
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': self.verification,
            'grant_type': 'authorization_code',
            'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob:auto'
        }
        response = requests.post('https://www.googleapis.com/oauth2/v4/token',
                                 params=authorization_params,
                                 proxies=self.getProxiesConf())
        if response.status_code == requests.codes.ok:
            authorization = response.json()
            if 'error' in authorization:
                QMessageBox().warning(
                    None, "Google authorization error",
                    "Google authorization error: %s" % authorization['error'])
                self.verification = None
                self.authorization = None
            else:
                self.authorization = authorization
        elif response.status_code == 401:  # token expired
            refresh_params = {
                'client_id': self.client_id,
                'client_secret': self.client_secret,
                'refresh_token': self.authorization['refresh_token'],
                'grant_type': 'refresh_token'
            }

        else:
            pass  #print response.reason

    def _getLayer(self, remoteTableName):
        if self.getValue("data collection table ID") == '':
            self.iface.messageBar().pushMessage(
                self.tr("QGISODK plugin"),
                self.tr("undefined data collect table ID"),
                level=QgsMessageBar.CRITICAL,
                duration=6)
            return

        if not self.authorization:
            self.get_authorization()

        metadata = self.getMetadataFromID(
            self.getValue("data collection table ID"))
        if metadata:
            layerName = metadata['name']
        else:
            layerName = self.tr('collected-data')

        remoteData = self.getTable()
        geojson = self.getLayerFromTable(remoteData)

        if geojson:
            workDir = QgsProject.instance().readPath("./")
            geoJsonFileName = layerName + '_odk-' + time.strftime(
                "%d-%m-%Y") + '.geojson'
            with open(os.path.join(workDir, geoJsonFileName),
                      "w") as geojson_file:
                geojson_file.write(json.dumps(geojson))
            layer = self.iface.addVectorLayer(os.path.join(workDir, layerName),
                                              layerName[:-8], "ogr")
            QgsMapLayerRegistry.instance().addMapLayer(layer)
        else:
            self.iface.messageBar().pushMessage(
                self.tr("QGISODK plugin"), self.tr("error loading csv table"))

    def getLayerFromTable(
        self,
        remoteData,
    ):
        geojson = {
            "type": "FeatureCollection",
            "crs": {
                "type": "name",
                "properties": {
                    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
                }
            },
            "features": []
        }
        for record in remoteData:
            if 'GEOMETRY' in record:
                geomType, geomCoordinates = self.guessGeomType(
                    record['GEOMETRY'])
                feature = {
                    "type": "Feature",
                    "properties": {},
                    "geometry": {
                        "type": geomType
                    }
                }

                # build geojson geometry
                jsonCoordinates = []
                for geomCoordinate in geomCoordinates:
                    jsonCoordinates.append(
                        [float(geomCoordinate[1]),
                         float(geomCoordinate[0])])
                if geomType == 'Point':
                    feature["geometry"]["coordinates"] = [
                        jsonCoordinates[0][0], jsonCoordinates[0][1]
                    ]
                if geomType == 'LineString':
                    feature["geometry"]["coordinates"] = jsonCoordinates
                if geomType == 'Polygon':
                    feature["geometry"]["coordinates"] = [jsonCoordinates]
            else:
                feature = {
                    "type": "Feature",
                    "properties": {},
                    "geometry": None
                }

            # build geojson properties
            for fieldKey, fieldValue in record.iteritems():
                if not fieldKey in ('GEOMETRY', ):  # field exclusion
                    feature["properties"][fieldKey] = fieldValue

            geojson["features"].append(feature)

        #metadata = self.getMetadataFromID(self.getValue("data collection table ID"))
        #if metadata:
        #    layerName = metadata['name']
        #else:
        #    layerName = self.tr('collected-data')

        return geojson

    def getTable(self, tableID):
        if not self.authorization:
            self.get_authorization()

        #step1 - verify if form exists:
        url = 'https://docs.google.com/spreadsheets/d/%s/export?format=csv&id=%s&gid=0' % (
            tableID, self.getValue("data collection table ID"))
        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token']),
            'Content-Type': 'application/json'
        }

        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            csvIO = StringIO.StringIO(response.text)
            csvIn = csv.DictReader(csvIO, delimiter=',', quotechar='"')
            csvList = []
            for row in csvIn:
                csvList.append(row)
            geometryField = ''
            for field in csvList[0].keys():
                if 'GEOMETRY' in field.upper():
                    geometryField = field
                    prefix = field[:-8]
                    len_prefix = len(field) - 8
            newCsvList = []
            for row in csvList:
                newRow = {}
                for field in row.keys():
                    newRow[field[len_prefix:]] = row[field]  # remap field
                newCsvList.append(newRow)
            return newCsvList
        else:
            print "getTable", response, response.text

    def setDataSubmissionTable(self, xForm_id):
        if not self.authorization:
            self.get_authorization()

        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token'])
        }

        folderId = self.createNew(self.getValue('folder'),
                                  'application/vnd.google-apps.folder')
        self.shareFileWithCollectors(folderId, role='reader')

        content_table_id = self.createNew(
            xForm_id[:-4] + "-collect-table",
            'application/vnd.google-apps.spreadsheet',
            parentsId=folderId)
        self.shareFileWithCollectors(content_table_id, role='writer')
        if content_table_id:
            url = 'https://www.googleapis.com/drive/v3/files/' + content_table_id
            response = requests.get(url,
                                    headers=headers,
                                    proxies=self.getProxiesConf())
            self.notify(xForm_id, self.getValue('folder'),
                        response.json()['id'],
                        response.json()['name'])
            return 'https://docs.google.com/spreadsheets/d/%s/edit' % response.json(
            )['id']
        else:
            return None

    def sendForm(self, xForm_id, xForm):
        if not self.authorization:
            self.get_authorization()

        xForm_id += '.xml'
        fileId = self.getIdFromName(xForm_id)

        folderId = self.createNew(self.getValue('folder'),
                                  'application/vnd.google-apps.folder')
        self.shareFileWithCollectors(folderId, role='reader')

        metadata = {
            "name": xForm_id,
            "description": 'uploaded by QGISODK plugin'
        }

        if fileId:
            method = "PATCH"
            url = 'https://www.googleapis.com/upload/drive/v3/files/%s?uploadType=multipart' % fileId
        else:
            method = "POST"
            url = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart'
            metadata['parents'] = [folderId]

        headers = {
            'Authorization':
            'Bearer {}'.format(self.authorization['access_token'])
        }

        data = ('metadata', json.dumps(metadata),
                'application/json; charset=UTF-8')

        file = (xForm, open(xForm, 'r'), 'text/xml')
        files = {'data': data, 'file': file}
        response = requests.request(method,
                                    url,
                                    headers=headers,
                                    files=files,
                                    proxies=self.getProxiesConf())
        self.shareFileWithCollectors(response.json()['id'], role='reader')

        return response
コード例 #4
0
 def __init__(self, parent):
     super(aggregate, self).__init__(parent, self.parameters)
     self.importDataFromService = QgisODKimportDataFromService(self.module)
コード例 #5
0
class aggregate(external_service):
    parameters = [["id", "aggregate"], ["url", ''], ["lastID", ''],
                  ["user", ''], ["password", '']]

    def __init__(self, parent):
        super(aggregate, self).__init__(parent, self.parameters)
        self.importDataFromService = QgisODKimportDataFromService(self.module)

    def getExportMethod(self):
        return 'exportXForm'

    def getExportExtension(self):
        return 'xml'

    def getFormList(self, xForm_id):
        method = 'GET'
        url = self.getValue('url') + '//formList'
        response = requests.request(method, url)
        root = ET.fromstring(response.content)
        keylist = [
            form.attrib['url'].split('=')[1] for form in root.findall('form')
        ]
        return xForm_id in keylist, response

    def sendForm(self, xForm_id, xForm):

        #        step1 - verify if form exists:
        form_key, response = self.getFormList(xForm_id)
        if response.status_code != requests.codes.ok:
            return response
        if form_key:
            method = 'POST'
            url = self.getValue('url') + '//formUpload'
        else:
            method = 'POST'
            url = self.getValue('url') + '//formUpload'
#        method = 'POST'
#        url = self.getValue('url')+'//formUpload'
#step1 - upload form: POST if new PATCH if exixtent
        files = open(xForm, 'r')
        files = {'form_def_file': files}
        response = requests.request(method,
                                    url,
                                    files=files,
                                    proxies=self.getProxiesConf())
        return response

    def collectData(self, layer):
        if not layer:
            return
        XFormKey = layer.name()
        response, remoteTable = self.getTable(XFormKey)
        if response.status_code == 200:
            print 'before Update Layer'
            if remoteTable:
                print 'table have some data'
#                self.importDataFromService.updateLayer(layer,remoteTable)
        else:
            self.iface.messageBar().pushMessage(self.tr("QGISODK plugin"),
                                                self.tr("Form is invalid"),
                                                level=QgsMessageBar.CRITICAL,
                                                duration=6)

    def getTable(self, XFormKey):
        url = self.getValue('url') + '/view/submissionList?formId=' + XFormKey
        method = 'GET'
        try:
            response = requests.request(method,
                                        url,
                                        proxies=self.getProxiesConf())


#        Read instance id
        except:
            print 'not able to downlaod'
            sys.exit()
        table = []
        if not response.status_code == 200:
            return response, table
        root = ET.fromstring(response.content)
        ns = '{http://opendatakit.org/submissions}'
        instance_ids = [child.text for child in root[0].findall(ns + 'id')]
        print 'instance ids before filter', instance_ids
        lastID = self.getValue('lastID')
        print 'lastID is', lastID
        lastindex = 0
        try:
            lastindex = instance_ids.index(lastID)
        except:
            print 'first download'
        ns1 = '{http://www.opendatakit.org/cursor}'
        lastReturnedURI = ET.fromstring(
            root[1].text).findall(ns1 + 'uriLastReturnedValue')[0].text
        print 'server lastID is', lastReturnedURI
        if lastID == lastReturnedURI:
            print 'No Download returning'
            return response, table
        instance_ids = instance_ids[lastindex:]
        print 'downloading', instance_ids
        for id in instance_ids:
            if id:
                url = self.getValue(
                    'url'
                ) + '/view/downloadSubmission?formId={}[@version=null and @uiVersion=null]/{}[@key={}]'.format(
                    XFormKey, XFormKey, id)
                try:
                    response = requests.request(method, url)
                except:
                    print 'not able to fetch'
                if not response.status_code == 200:
                    return response
                root1 = ET.fromstring(response.content)
                data = root1[0].findall(ns + XFormKey)
                dict = {
                    child.tag.replace(ns, ''): child.text
                    for child in data[0]
                }
                mediaFile = root1.findall(ns + 'mediaFile')
                if len(mediaFile) > 0:
                    mediaDict = {
                        child.tag.replace(ns, ''): child.text
                        for child in mediaFile[0]
                    }
                    for key, value in dict.iteritems():
                        if value == mediaDict['filename']:
                            dict[key] = self.importDataFromService.cleanURIm(
                                mediaDict['downloadUrl'], XFormKey, value)
                table.append(dict)
        self.getValue('lastID', lastReturnedURI)
        return response, table
コード例 #6
0
class ona(external_service):
    parameters = [
        ["id", "ona.io"],
        ["name", ""],
        ["project_id", ""],
        ["user", ""],
        ["password", ""],
    ]

    def __init__(self, parent):
        super(ona, self).__init__(parent, self.parameters)
        self.importDataFromService = QgisODKimportDataFromService(self.module)

    def getExportMethod(self):
        return 'exportXlsForm'

    def getExportExtension(self):
        return 'xls'

    def getAvailableDataCollections(self):
        url = 'https://api.ona.io/api/v1/projects/%s/forms' % self.getValue(
            "project_id")
        response = requests.get(url,
                                auth=requests.auth.HTTPBasicAuth(
                                    self.getValue("user"),
                                    self.getValue("password")),
                                proxies=self.getProxiesConf())
        if response.status_code != requests.codes.ok:
            return None, response
        forms = response.json()
        availableDataCollections = []
        for form in forms:
            availableDataCollections.append(form["id_string"])
        return availableDataCollections, response

    def formIDToPk(self, xForm_id):
        #verify if form exists:
        url = 'https://api.ona.io/api/v1/projects/%s/forms' % self.getValue(
            "project_id")
        response = requests.get(url,
                                auth=requests.auth.HTTPBasicAuth(
                                    self.getValue("user"),
                                    self.getValue("password")),
                                proxies=self.getProxiesConf())
        if response.status_code != requests.codes.ok:
            self.iface.messageBar().pushMessage(self.tr("QGISODK plugin"),
                                                self.tr("Response is not Ok"),
                                                level=QgsMessageBar.CRITICAL,
                                                duration=6)
            return None, response
        forms = response.json()
        form_key = None
        for form in forms:
            if form['sms_id_string'] == xForm_id:
                form_key = form['formid']
                break
        return form_key, response

    def sendForm(self, xForm_id, xForm):

        #step1 - verify if form exists:
        form_key, response = self.formIDToPk(xForm_id)
        if response.status_code != requests.codes.ok:
            return response
        if form_key:
            method = 'PATCH'
            url = 'https://api.ona.io/api/v1/forms/%s' % form_key
        else:
            method = 'POST'
            url = 'https://api.ona.io/api/v1/projects/%s/forms' % self.getValue(
                "project_id")
        #step1 - upload form: POST if new PATCH if exixtent
        files = {
            'xls_file': (xForm, open(xForm,
                                     'rb'), 'application/vnd.ms-excel', {
                                         'Expires': '0'
                                     })
        }
        response = requests.request(
            method,
            url,
            files=files,
            auth=requests.auth.HTTPBasicAuth(self.getValue("user"),
                                             self.getValue("password")),
            proxies=self.getProxiesConf()
        )  #, proxies = proxyDict,headers={'Content-Type': 'application/octet-stream'})
        return response

    def getUUIDfield(self):
        return '_uuid'

    def getJSON(self, xForm_id):
        #step1 - verify if form exists:
        form_key, response = self.formIDToPk(xForm_id)
        if response.status_code != requests.codes.ok:
            return response
        if form_key:
            url = 'https://api.ona.io/api/v1/data/%s' % form_key
            response = requests.get(url,
                                    auth=requests.auth.HTTPBasicAuth(
                                        self.getValue("user"),
                                        self.getValue("password")),
                                    proxies=self.getProxiesConf())
            return response

    def setDataSubmissionTable(self, xForm_id):
        return None  #defined by ona.io

    def collectData(self, layer=None):
        if (layer == None):
            '''
            interactive table selection
            '''
            XFormID = QgisODKImportCollectedData.getXFormID(self)
            if XFormID:
                XFormKey, response = self.formIDToPk(XFormID)
                response, remoteTable = self.getTable(XFormKey)
                self.importDataFromService.view(XFormID, remoteTable)
            else:
                self.iface.messageBar().pushMessage(
                    self.tr("QGISODK plugin"),
                    self.tr("no data collect table selected"),
                    level=QgsMessageBar.CRITICAL,
                    duration=6)

        else:
            XFormID = layer.name().lower()
            if XFormID:
                XFormKey, response = self.formIDToPk(XFormID)
                response, remoteTable = self.getTable(XFormKey)
                self.importDataFromService.getData(XFormID, remoteTable, layer)
                self.importDataFromService.writeLayer(layer)
            else:
                self.iface.messageBar().pushMessage(
                    self.tr("QGISODK plugin"),
                    self.tr("Form is invalid"),
                    level=QgsMessageBar.CRITICAL,
                    duration=6)

    def getTable(self, form_key):
        #step1 - verify if form exists:
        #form_key, response = self.formIDToPk(xForm_id)
        #if response.status_code != requests.codes.ok:
        #    self.iface.messageBar().pushMessage(self.tr("QgisODK plugin"), self.tr("error loading csv table %s, %s.") % (
        #    response.status_code, response.reason), level=QgsMessageBar.CRITICAL, duration=6)
        #    return response, None
        if form_key:
            url = 'https://api.ona.io/api/v1/data/%s.csv' % form_key
            response = requests.get(url,
                                    auth=requests.auth.HTTPBasicAuth(
                                        self.getValue("user"),
                                        self.getValue("password")),
                                    proxies=self.getProxiesConf())
            if response.status_code == 200:
                csvIO = StringIO.StringIO(response.text)
                csvIn = csv.DictReader(csvIO, delimiter=',', quotechar='"')
                csvList = []
                for row in csvIn:
                    remappedRow = {}
                    for key, value in row.iteritems():
                        if '/' in key:
                            cleanedKey = key.split('/')[-1]
                            remappedRow[cleanedKey] = value
                        else:
                            remappedRow[key] = value

                    csvList.append(remappedRow)
                return response, csvList

            else:
                self.iface.messageBar().pushMessage(
                    self.tr("QGISODK plugin"),
                    self.tr("error loading csv table %s, %s.") %
                    (response.status_code, response.reason),
                    level=QgsMessageBar.CRITICAL,
                    duration=6)
                return response, None

    def getLayerFromTable(self, remoteData, downloadAttachements=None):
        #remoteResponse = self.getJSON(xForm_id)
        #response, remoteData = self.getTable(xForm_id)
        geojson = {
            "type": "FeatureCollection",
            "crs": {
                "type": "name",
                "properties": {
                    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
                }
            },
            "features": []
        }

        for record in remoteData:
            if 'GEOMETRY' in record:
                geomType, geomCoordinates = self.guessGeomType(
                    record['GEOMETRY'])
                feature = {
                    "type": "Feature",
                    "properties": {},
                    "geometry": {
                        "type": geomType
                    }
                }

                #build geojson geometry
                jsonCoordinates = []
                for geomCoordinate in geomCoordinates:
                    jsonCoordinates.append(
                        [float(geomCoordinate[1]),
                         float(geomCoordinate[0])])
                if geomType == 'Point':
                    feature["geometry"]["coordinates"] = [
                        jsonCoordinates[0][0], jsonCoordinates[0][1]
                    ]
                if geomType == 'LineString':
                    feature["geometry"]["coordinates"] = jsonCoordinates
                if geomType == 'Polygon':
                    feature["geometry"]["coordinates"] = [jsonCoordinates]
            else:
                feature = {
                    "type": "Feature",
                    "properties": {},
                    "geometry": None
                }

            #recode attachments:
            attachements = {}
            if '_attachments' in record:
                for attachment in record['_attachments']:
                    fileKey = attachment["download_url"].split('/')[-1]
                    #todo local download attachment files if option is checked
                    attachements[fileKey] = 'https://api.ona.io' + attachment[
                        "download_url"]
                    if downloadAttachements and QgsProject.instance().readPath(
                            "./") != "./":
                        downloadDir = os.path.join(
                            QgsProject.instance().readPath("./"),
                            'attachments_%s_%s' %
                            (self.getValue("name"),
                             self.getValue("project_id")))
                        if not os.path.exists(downloadDir):
                            os.makedirs(downloadDir)
                        response = requests.get(attachements[fileKey],
                                                stream=True,
                                                proxies=self.getProxiesConf())
                        localAttachmentPath = os.path.abspath(
                            os.path.join(downloadDir, fileKey))
                        if response.status_code == 200:
                            with open(localAttachmentPath, 'wb') as f:
                                for chunk in response:
                                    f.write(chunk)
                                attachements[fileKey] = localAttachmentPath
                        else:
                            attachements[fileKey] = ''

            #build geojson properties
            for fieldKey, fieldValue in record.iteritems():
                if not fieldKey in (
                        'GEOMETRY', '_attachments', '_tags', '_notes',
                        '_bamboo_dataset_id',
                        '_geolocation'):  # field exclusion to verify

                    if fieldValue in attachements.keys():
                        fieldValue = attachements[fieldValue]

                    if "/" in fieldKey:  #check if grouped Field
                        cleanedKey = fieldKey.split("/")[-1]
                    else:
                        cleanedKey = fieldKey
                    fieldRemap = self.module.dlg.treeView.mapNameTofield(
                        cleanedKey
                    )  #try to remap field name to existing field using map to property
                    feature["properties"][fieldRemap] = fieldValue

            geojson["features"].append(feature)

        return geojson