class ABCSearchEngine(ABC): QUESTION_PROPERTIES = [ 'gid', 'question', 'question_order', 'subquestions', 'answeroptions', 'title', 'type', 'attributes_lang', 'attributes', 'other' ] session_key = None server = None def __init__(self): self.get_session_key() def get_session_key(self): self.server = Server( settings.LIMESURVEY['URL_API'] + '/index.php/admin/remotecontrol') try: self.session_key = self.server.get_session_key( settings.LIMESURVEY['USER'], settings.LIMESURVEY['PASSWORD'] ) self.session_key = None if isinstance(self.session_key, dict) \ else self.session_key except TransportError: self.session_key = None def release_session_key(self): if self.session_key: self.server.release_session_key(self.session_key) @abstractmethod def find_all_questionnaires(self): """ :return: all stored surveys """ list_survey = self.server.list_surveys(self.session_key, None) return list_survey @abstractmethod def find_all_active_questionnaires(self): """ :return: all active surveys """ list_survey = self.server.list_surveys(self.session_key, None) list_active_survey = [] if isinstance(list_survey, list): for survey in list_survey: if survey['active'] == "Y" and self.survey_has_token_table(survey['sid']): list_active_survey.append(survey) else: list_active_survey = None return list_active_survey @abstractmethod def find_questionnaire_by_id(self, sid): """ :param sid: survey ID :return: survey """ list_survey = self.server.list_surveys(self.session_key, None) try: survey = next((survey for survey in list_survey if survey['sid'] == sid)) except StopIteration: survey = None return survey @abstractmethod def add_participant(self, sid): """ :param sid: Survey ID :return: dictionary with token and token_id; None if error. """ participant_data = {'email': '', 'firstname': '', 'lastname': ''} result = self.server.add_participants( self.session_key, sid, [participant_data], True ) if result \ and isinstance(result, list) \ and isinstance(result[0], dict) \ and 'error' not in result[0]: return {'token': result[0]['token'], 'tid': result[0]['tid']} else: return None @abstractmethod def delete_participant(self, survey_id, tokens_ids): """ Delete survey participant :param survey_id: survey ID :param tokens_ids: token_id to put in a list :return: on success, an array of deletion status for each participant; on failure, status array. """ result = self.server.delete_participants( self.session_key, survey_id, [tokens_ids] ) return result @abstractmethod def get_survey_title(self, sid, language): """ :param sid: survey ID :param language: language :return: title of the survey """ if self.session_key: survey_title = self.server.get_language_properties(self.session_key, sid, {'method': 'surveyls_title'}, language) if 'surveyls_title' in survey_title: survey_title = survey_title.get('surveyls_title') else: survey_title = str(sid) else: survey_title = str(sid) return survey_title @abstractmethod def get_survey_properties(self, sid, prop): """ :param sid: survey ID :param prop: the name of the propriety of the survey :return: value of the property """ result = self.server.get_survey_properties(self.session_key, sid, {'method': prop}) return result.get(prop) @abstractmethod def get_survey_languages(self, sid): """ :param sid: survey ID :return: the base and the additional idioms """ result = self.server.get_survey_properties(self.session_key, sid, ['additional_languages', 'language']) return result @abstractmethod def activate_survey(self, sid): """ Activates a survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_survey(self.session_key, sid) return result['status'] @abstractmethod def activate_tokens(self, sid): """ Activates tokens for a determined survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_tokens(self.session_key, sid) return result['status'] @abstractmethod def get_participant_properties(self, survey_id, token_id, prop): """ :param survey_id: survey ID :param token_id: token ID :param prop: property name :return: value of a determined property from a participant/token """ if self.session_key: result = self.server.get_participant_properties( self.session_key, survey_id, token_id, {'method': prop} ) result = result.get(prop) else: result = '' return result @abstractmethod def survey_has_token_table(self, sid): """ :param sid: survey ID :return: True if the survey has token table; False, if not. """ result = self.server.get_summary(self.session_key, sid, "token_completed") return isinstance(result, int) @abstractmethod def add_survey(self, sid, title, language, survey_format): """ Adds a survey to the LimeSurvey :param sid: survey ID :param title: title of the survey :param language: language of the survey :param survey_format: format of the survey :return: survey ID generated """ survey_id_generated = self.server.add_survey( self.session_key, sid, title, language, survey_format ) return survey_id_generated @abstractmethod def delete_survey(self, sid): """ remove a survey from the LimeSurvey :param sid: survey ID :return: status of the operation """ status = self.server.delete_survey(self.session_key, sid) return status['status'] @abstractmethod def get_responses_by_token(self, sid, token, language, fields=[]): """ obtains responses from a determined token :param sid: survey ID :param token: token :param language: language :param fields: fields array, using SGQA identifier :return: responses in the txt format """ if fields: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', 'code', 'short', fields) else: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete') if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt @abstractmethod def get_responses(self, sid, language, response_type, fields, heading_type): """ Obtains responses from a determined survey :param sid: survey ID :param language: language :param response_type: (optional)'short' or 'long' Optional defaults to 'short' :param fields: filter fields that must be returned :param heading_type: (optional) 'code','full' or 'abbreviated' Optional defaults to 'code' :return: responses in txt format """ responses = self.server.export_responses( self.session_key, sid, 'csv', language, 'complete', heading_type, response_type ) if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt def get_header_response(self, sid, language, token, heading_type): """ Obtain header responses :param sid: survey ID :param language: language :param heading_type: heading type (can be 'code' or 'full') :return: responses in the txt format """ responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', heading_type, 'short' ) if not isinstance(responses, str): responses = self.server.export_responses( self.session_key, sid, 'csv', language, 'complete', heading_type, 'short' ) if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt @abstractmethod def get_summary(self, sid, stat_name): """ :param sid: survey ID :param stat_name: name of the summary option - valid values are 'token_count', 'token_invalid', 'token_sent', 'token_opted_out', 'token_completed', 'completed_responses', 'incomplete_responses', 'full_responses' or 'all' :return: summary information """ summary_responses = self.server.get_summary(self.session_key, sid, stat_name) return summary_responses @abstractmethod def insert_questions(self, sid, questions_data, format_import_file): """ Imports a group of questions from a file :param sid: survey ID :param questions_data: question data :param format_import_file: lsg file :return: """ questions_data_b64 = b64encode(questions_data.encode('utf-8')) result = self.server.import_group( self.session_key, sid, questions_data_b64.decode('utf-8'), format_import_file ) if isinstance(result, dict): if 'status' in result: return None else: return result @abstractmethod def get_question_properties(self, question_id, language): """ :param question_id: question ID :param language: language of the answer :return: properties of a question of a survey """ properties = self.server.get_question_properties( self.session_key, question_id, self.QUESTION_PROPERTIES, language ) return properties def set_question_properties(self, sid, data): return self.server.set_question_properties(self.session_key, sid, data) @abstractmethod def list_groups(self, sid): """ :param sid: survey ID :return: ids and info of groups belonging to survey """ groups = self.server.list_groups(self.session_key, sid) return groups @abstractmethod def get_group_properties(self, gid): """ :param gid: group ID :param lang: group language to return correct group, as Remote Control API does not do that :return: list of group properties """ return self.server.get_group_properties(self.session_key, gid) def set_group_properties(self, sid, data): return self.server.set_group_properties( self.session_key, sid, data ) @abstractmethod def list_questions(self, sid, gid): """ :param sid: survey ID :param gid: group ID :return: ids and info of (sub-)questions of a survey/group """ question_list = [] questions = self.server.list_questions(self.session_key, sid, gid) for question in questions: question_list.append(question['id']['qid']) return question_list @abstractmethod def find_tokens_by_questionnaire(self, sid): """ :param sid: :return: tokens for specific id """ tokens = self.server.list_participants( self.session_key, sid, 0, 99999999 ) return tokens def add_group(self, sid, title, description): return self.server.add_group(self.session_key, sid, title) def add_response(self, sid, response_data): return self.server.add_response(self.session_key, sid, response_data) def set_participant_properties(self, sid, tid, properties_dict): return self.server.set_participant_properties( self.session_key, sid, tid, properties_dict )
class ABCSearchEngine(ABC): session_key = None server = None def __init__(self): self.get_session_key() def get_session_key(self): self.server = Server(settings.LIMESURVEY['URL_API'] + '/index.php/admin/remotecontrol') try: self.session_key = self.server.get_session_key( settings.LIMESURVEY['USER'], settings.LIMESURVEY['PASSWORD']) self.session_key = None if isinstance(self.session_key, dict) \ else self.session_key except TransportError: self.session_key = None def release_session_key(self): if self.session_key: self.server.release_session_key(self.session_key) @abstractmethod def find_all_questionnaires(self): """ :return: all stored surveys """ list_survey = self.server.list_surveys(self.session_key, None) return list_survey @abstractmethod def find_all_active_questionnaires(self): """ :return: all active surveys """ list_survey = self.server.list_surveys(self.session_key, None) list_active_survey = [] if isinstance(list_survey, list): for survey in list_survey: if survey['active'] == "Y" and self.survey_has_token_table( survey['sid']): list_active_survey.append(survey) else: list_active_survey = None return list_active_survey @abstractmethod def find_questionnaire_by_id(self, sid): """ :param sid: survey ID :return: survey """ list_survey = self.server.list_surveys(self.session_key, None) try: survey = next( (survey for survey in list_survey if survey['sid'] == sid)) except StopIteration: survey = None return survey @abstractmethod def add_participant(self, sid): """ :param sid: Survey ID :return: dictionary with token and token_id; None if error. """ participant_data = {'email': '', 'firstname': '', 'lastname': ''} result = self.server.add_participants(self.session_key, sid, [participant_data], True) if result \ and isinstance(result, list) \ and isinstance(result[0], dict) \ and 'error' not in result[0]: return {'token': result[0]['token'], 'tid': result[0]['tid']} else: return None @abstractmethod def delete_participant(self, survey_id, tokens_ids): """ Delete survey participant :param survey_id: survey ID :param tokens_ids: token_id to put in a list :return: on success, an array of deletion status for each participant; on failure, status array. """ result = self.server.delete_participants(self.session_key, survey_id, [tokens_ids]) return result @abstractmethod def get_survey_title(self, sid, language): """ :param sid: survey ID :param language: language :return: title of the survey """ if self.session_key: survey_title = self.server.get_language_properties( self.session_key, sid, {'method': 'surveyls_title'}, language) if 'surveyls_title' in survey_title: survey_title = survey_title.get('surveyls_title') else: survey_title = str(sid) else: survey_title = str(sid) return survey_title @abstractmethod def get_survey_properties(self, sid, prop): """ :param sid: survey ID :param prop: the name of the propriety of the survey :return: value of the property """ result = self.server.get_survey_properties(self.session_key, sid, {'method': prop}) return result.get(prop) @abstractmethod def get_survey_languages(self, sid): """ :param sid: survey ID :return: the base and the additional idioms """ result = self.server.get_survey_properties( self.session_key, sid, ['additional_languages', 'language']) return result @abstractmethod def activate_survey(self, sid): """ Activates a survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_survey(self.session_key, sid) return result['status'] @abstractmethod def activate_tokens(self, sid): """ Activates tokens for a determined survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_tokens(self.session_key, sid) return result['status'] @abstractmethod def get_participant_properties(self, survey_id, token_id, prop): """ :param survey_id: survey ID :param token_id: token ID :param prop: property name :return: value of a determined property from a participant/token """ if self.session_key: result = self.server.get_participant_properties( self.session_key, survey_id, token_id, {'method': prop}) result = result.get(prop) else: result = '' return result @abstractmethod def survey_has_token_table(self, sid): """ :param sid: survey ID :return: True if the survey has token table; False, if not. """ result = self.server.get_summary(self.session_key, sid, "token_completed") return isinstance(result, int) @abstractmethod def add_survey(self, sid, title, language, survey_format): """ Adds a survey to the LimeSurvey :param sid: survey ID :param title: title of the survey :param language: language of the survey :param survey_format: format of the survey :return: survey ID generated """ survey_id_generated = self.server.add_survey(self.session_key, sid, title, language, survey_format) return survey_id_generated @abstractmethod def delete_survey(self, sid): """ remove a survey from the LimeSurvey :param sid: survey ID :return: status of the operation """ status = self.server.delete_survey(self.session_key, sid) return status['status'] @abstractmethod def get_responses_by_token(self, sid, token, language, fields=[]): """ obtains responses from a determined token :param sid: survey ID :param token: token :param language: language :param fields: fields array, using SGQA identifier :return: responses in the txt format """ if fields: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', 'code', 'short', fields) else: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete') if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt @abstractmethod def get_responses(self, sid, language, response_type, fields, heading_type): """ Obtains responses from a determined survey :param sid: survey ID :param language: language :param response_type: (optional)'short' or 'long' Optional defaults to 'short' :param fields: filter fields that must be returned :param heading_type: (optional) 'code','full' or 'abbreviated' Optional defaults to 'code' :return: responses in txt format """ responses = self.server.export_responses(self.session_key, sid, 'csv', language, 'complete', heading_type, response_type) if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt def get_header_response(self, sid, language, token, heading_type): """ Obtain header responses :param sid: survey ID :param language: language :param heading_type: heading type (can be 'code' or 'full') :return: responses in the txt format """ responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', heading_type, 'short') if not isinstance(responses, str): responses = self.server.export_responses(self.session_key, sid, 'csv', language, 'complete', heading_type, 'short') if isinstance(responses, str): responses_txt = b64decode(responses) else: responses_txt = responses return responses_txt @abstractmethod def get_summary(self, sid, stat_name): """ :param sid: survey ID :param stat_name: name of the summary option - valid values are 'token_count', 'token_invalid', 'token_sent', 'token_opted_out', 'token_completed', 'completed_responses', 'incomplete_responses', 'full_responses' or 'all' :return: summary information """ summary_responses = self.server.get_summary(self.session_key, sid, stat_name) return summary_responses @abstractmethod def insert_questions(self, sid, questions_data, format_import_file): """ Imports a group of questions from a file :param sid: survey ID :param questions_data: question data :param format_import_file: lsg file :return: """ questions_data_b64 = b64encode(questions_data.encode('utf-8')) result = self.server.import_group(self.session_key, sid, questions_data_b64.decode('utf-8'), format_import_file) if isinstance(result, dict): if 'status' in result: return None else: return result @abstractmethod def get_question_properties(self, question_id, language): """ :param question_id: question ID :param language: language of the answer :return: properties of a question of a survey """ properties = self.server.get_question_properties( self.session_key, question_id, [ 'gid', 'question', 'subquestions', 'answeroptions', 'title', 'type', 'attributes_lang', 'attributes', 'other' ], language) return properties def set_question_properties(self, sid, data): return self.server.set_question_properties(self.session_key, sid, data) @abstractmethod def list_groups(self, sid): """ :param sid: survey ID :return: ids and info of groups belonging to survey """ groups = self.server.list_groups(self.session_key, sid) return groups @abstractmethod def get_group_properties(self, gid): """ :param gid: group ID :param lang: group language to return correct group, as Remote Control API does not do that :return: list of group properties """ return self.server.get_group_properties(self.session_key, gid) def set_group_properties(self, sid, data): return self.server.set_group_properties(self.session_key, sid, data) @abstractmethod def list_questions(self, sid, gid): """ :param sid: survey ID :param gid: group ID :return: ids and info of (sub-)questions of a survey/group """ question_list = [] questions = self.server.list_questions(self.session_key, sid, gid) for question in questions: question_list.append(question['id']['qid']) return question_list @abstractmethod def find_tokens_by_questionnaire(self, sid): """ :param sid: :return: tokens for specific id """ tokens = self.server.list_participants(self.session_key, sid, 0, 99999999) return tokens def add_group(self, sid, title, description): return self.server.add_group(self.session_key, sid, title) def add_response(self, sid, response_data): return self.server.add_response(self.session_key, sid, response_data) def set_participant_properties(self, sid, tid, properties_dict): return self.server.set_participant_properties(self.session_key, sid, tid, properties_dict)
class ABCSearchEngine(ABC): QUESTION_PROPERTIES = [ 'gid', 'question', 'question_order', 'subquestions', 'answeroptions', 'title', 'type', 'attributes_lang', 'attributes', 'other' ] session_key = None server = None def __init__(self, limesurvey_rpc=None): self.limesurvey_rpc = limesurvey_rpc or settings.LIMESURVEY[ 'URL_API'] + '/index.php/admin/remotecontrol' self.get_session_key() def get_session_key(self): self.server = Server(self.limesurvey_rpc) try: self.session_key = self.server.get_session_key( settings.LIMESURVEY['USER'], settings.LIMESURVEY['PASSWORD']) self.session_key = None if isinstance(self.session_key, dict) else self.session_key except TransportError: self.session_key = None # TODO: catch user/password exception def release_session_key(self): if self.session_key: self.server.release_session_key(self.session_key) @abstractmethod def find_all_questionnaires(self): """ :return: all stored surveys """ list_survey = self.server.list_surveys(self.session_key, None) return list_survey @abstractmethod def find_all_active_questionnaires(self): """ :return: all active surveys """ list_survey = self.server.list_surveys(self.session_key, None) list_active_survey = [] if isinstance(list_survey, list): for survey in list_survey: if survey['active'] == "Y" and self.survey_has_token_table( survey['sid']): list_active_survey.append(survey) else: list_active_survey = None return list_active_survey @abstractmethod def find_questionnaire_by_id(self, sid): """ :param sid: survey ID :return: survey """ list_survey = self.server.list_surveys(self.session_key, None) try: survey = next( (survey for survey in list_survey if survey['sid'] == sid)) except StopIteration: survey = None return survey @abstractmethod def add_participant(self, sid): """ :param sid: Survey ID :return: dictionary with token and token_id; None if error. """ participant_data = {'email': '', 'firstname': '', 'lastname': ''} result = self.server.add_participants(self.session_key, sid, [participant_data], True) if result and isinstance(result, list) and isinstance( result[0], dict) and 'error' not in result[0]: return {'token': result[0]['token'], 'tid': result[0]['tid']} else: return None @abstractmethod def delete_participants(self, survey_id, tokens_ids): """ Delete survey participant :param survey_id: survey ID :param tokens_ids: list of token ids :return: on success, a dict of deletion status for each participant; on failure, status dict. """ result = self.server.delete_participants(self.session_key, survey_id, tokens_ids) # TODO: verify if there exists participants table. The questionnary # may be deactivated but NES keep tracking it. # In case of success RPC returs a list, otherwise a dict with error status return result if 'status' not in result else None @abstractmethod def get_survey_title(self, sid, language): """ :param sid: survey ID :param language: language :return: title of the survey """ if self.session_key: survey_title = self.server.get_language_properties( self.session_key, sid, {'method': 'surveyls_title'}, language) if 'surveyls_title' in survey_title: survey_title = survey_title.get('surveyls_title') else: survey_title = str(sid) else: survey_title = str(sid) return survey_title @abstractmethod def get_survey_properties(self, sid, prop): """ :param sid: survey ID :param prop: the name of the property of the survey :return: value of the property """ result = self.server.get_survey_properties(self.session_key, sid, {'method': prop}) return result.get(prop) @abstractmethod def get_survey_languages(self, sid): """ :param sid: survey ID :return: the base and the additional idioms """ result = self.server.get_survey_properties( self.session_key, sid, ['additional_languages', 'language']) # If failed to consume API, it return a dict with one element with # 'status' as key return None if 'status' in result else result @abstractmethod def activate_survey(self, sid): """ Activates a survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_survey(self.session_key, sid) return result['status'] @abstractmethod def activate_tokens(self, sid): """ Activates tokens for a determined survey :param sid: survey ID :return: status of the survey """ result = self.server.activate_tokens(self.session_key, sid) return result['status'] @abstractmethod def get_participant_properties(self, survey_id, token_id, prop): """ :param survey_id: survey ID :param token_id: token ID :param prop: property name :return: on success, dict with value of a determined property, else dict with error status """ # Backward compatibility with last method signature. # TODO: refactor the code and remove this if if isinstance(prop, str): prop = [prop] result = self.server.get_participant_properties( self.session_key, survey_id, token_id, prop) # This if-else for backward compatibility with last method signature # TODO: refactor the code and remove this if-else if prop is not None and len(prop) == 1: return result.get(prop[0]) if 'status' not in result else None else: return result if 'status' not in result else None @abstractmethod def survey_has_token_table(self, sid): """ :param sid: survey ID :return: True if the survey has token table; False, if not. """ result = self.server.get_summary(self.session_key, sid, "token_completed") return isinstance(result, int) @abstractmethod def add_survey(self, sid, title, language, survey_format): """ Adds a survey to the LimeSurvey :param sid: survey ID :param title: title of the survey :param language: language of the survey :param survey_format: format of the survey :return: survey ID generated """ survey_id_generated = self.server.add_survey(self.session_key, sid, title, language, survey_format) return survey_id_generated @abstractmethod def delete_survey(self, sid): """ remove a survey from the LimeSurvey :param sid: survey ID :return: status of the operation """ status = self.server.delete_survey(self.session_key, sid) return status['status'] @abstractmethod def get_responses_by_token(self, sid, token, language, doctype, fields): """Obtain responses from a determined token. Limesurvey returns a string that, when b65decoded, has two new lines at the end. We eliminate that new lines. If doctype == 'csv-allanswer' export as 'csv'. The exportCompleteAnswers plugin may be not installed. See https://gitlab.com/SondagesPro/ExportAndStats/exportCompleteAnswers :param sid: survey ID :param token: token :param doctype: type of coded string ('csv', 'json, ...) :param language: language :param fields: fields array, using SGQA identifier :return: responses in the txt format """ responses = {} if fields: try: responses = self.server.export_responses_by_token( self.session_key, sid, doctype, token, language, 'complete', 'code', 'short', fields) except AttributeError: if doctype == 'csv-allanswer': responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', 'code', 'short', fields) else: try: responses = self.server.export_responses_by_token( self.session_key, sid, doctype, token, language, 'complete') except AttributeError: if doctype == 'csv-allanswer': responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete') if isinstance(responses, dict): return None responses = b64decode(responses).decode() return re.sub('\n\n', '\n', responses) @abstractmethod def get_responses(self, sid, language, response_type, fields, heading_type): """ Obtains responses from a determined survey. If doctype == 'csv-allanswer' try to export. The plugin may by not installed. :param sid: survey ID :param language: language :param response_type: (optional)'short' or 'long' Optional defaults to 'short' :param fields: filter fields that must be returned :param heading_type: (optional) 'code','full' or 'abbreviated' Optional defaults to 'code' :return: responses in txt format """ if response_type == 'long': responses = self.server.export_responses(self.session_key, sid, 'csv', language, 'complete', heading_type, response_type) else: try: responses = self.server.export_responses( self.session_key, sid, 'csv-allanswer', language, 'complete', heading_type, response_type) except AttributeError: responses = self.server.export_responses( self.session_key, sid, 'csv', language, 'complete', heading_type, response_type) return None if isinstance(responses, dict) \ else b64decode(responses).decode() def get_header_response(self, sid, language, token, heading_type): """Obtain header responses. If doctype == 'csv-allanswer' try to export. The plugin may be not installed. :param sid: survey ID :param language: language :param token: token :param heading_type: heading type (can be 'code', 'abbreviated', 'full') :return: str - responses in the txt format in case of success, else None """ if heading_type != 'abbreviated': try: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv-allanswer', token, language, 'complete', heading_type, 'short') except AttributeError: # TODO: sid: 843661 responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', heading_type, 'short') else: responses = self.server.export_responses_by_token( self.session_key, sid, 'csv', token, language, 'complete', heading_type, 'short') # For compatibility with export view call: when export_responses # returns {'status': 'No Response found by Token'} export view call # export_responses, that returns a string to responses variable and # can mount the screen with the possible data to export if isinstance(responses, dict) \ and responses['status'] == 'No Response found for Token': try: responses = self.server.export_responses( self.session_key, sid, 'csv-allanswer', language, 'complete', heading_type, 'short') except AttributeError: responses = self.server.export_responses( self.session_key, sid, 'csv', language, 'complete', heading_type, 'short') return None if isinstance(responses, dict) \ else b64decode(responses).decode() @abstractmethod def get_summary(self, sid, stat_name): """ :param sid: survey ID :param stat_name: name of the summary option - valid values are 'token_count', 'token_invalid', 'token_sent', 'token_opted_out', 'token_completed', 'completed_responses', 'incomplete_responses', 'full_responses' or 'all' :return: summary information """ summary_responses = self.server.get_summary(self.session_key, sid, stat_name) return summary_responses @abstractmethod def insert_questions(self, sid, questions_data, format_import_file): """ Import a group of questions from a file :param sid: survey ID :param questions_data: question data :param format_import_file: lsg file :return: """ questions_data_b64 = b64encode(questions_data.encode('utf-8')) result = self.server.import_group(self.session_key, sid, questions_data_b64.decode('utf-8'), format_import_file) return None if isinstance(result, dict) else result @abstractmethod def get_question_properties(self, question_id, language): """ :param question_id: question ID :param language: language of the answer :return: properties of a question of a survey """ properties = self.server.get_question_properties( self.session_key, question_id, self.QUESTION_PROPERTIES, language) if 'status' in properties and properties['status'] in [ 'Error: Invalid questionid', 'Error: Invalid language', 'Error: Invalid questionid', 'No valid Data', 'No permission', 'Invalid session key' ]: return None return properties def set_question_properties(self, sid, data): return self.server.set_question_properties(self.session_key, sid, data) @abstractmethod def list_groups(self, sid): """ :param sid: survey ID :return: on success, list of ids and info of groups belonging to survey, else, None """ groups = self.server.list_groups(self.session_key, sid) return groups if isinstance(groups, list) else None @abstractmethod def get_group_properties(self, gid): """ :param gid: LimeSurvey group id :param lang: group language to return correct group, as Remote Control API does not do that (TODO (NES-956): see why lang is gone :return: list of group properties """ result = self.server.get_group_properties(self.session_key, gid) # TODO (NES-963): treat errors return result def set_group_properties(self, sid, data): result = self.server.set_group_properties(self.session_key, sid, data) # TODO (NES-963): treat errors return result def list_questions(self, sid, gid): """List questions with their properties :param sid: LimeSurvey survey id :param gid: LimeSurvey group id :return: on success, list of question properties, else None """ questions = self.server.list_questions(self.session_key, sid, gid) return questions if isinstance(questions, list) else None @abstractmethod def list_questions_ids(self, sid, gid): """ :param sid: LimeSurvey survey id :param gid: LimeSurvey group id :return: ids and info of (sub-)questions of a survey/group """ question_ids = [] questions = self.list_questions(sid, gid) if questions is not None: for question in questions: question_ids.append(question['id']['qid']) return question_ids @abstractmethod def find_tokens_by_questionnaire(self, sid): """ :param sid: :return: list of tokens | dict with error status """ tokens = self.server.list_participants(self.session_key, sid, 0, 99999999) # If some error occurs RPC returns a dict, so return None return tokens if isinstance(tokens, list) else None def add_group(self, sid, title, description): result = self.server.add_group(self.session_key, sid, title) # TODO (NES-963): treat errors return result def add_response(self, sid, response_data): result = self.server.add_response(self.session_key, sid, response_data) # TODO (NES-963): treat errors return result def set_participant_properties(self, sid, tid, properties_dict): result = self.server.set_participant_properties( self.session_key, sid, tid, properties_dict) # TODO (NES-963): treat errors return result def import_survey(self, base64_encoded_lsa): """ :param base64_encoded_lsa: Base 64 encoded string from lsa archive :return: lime survey id of survey created """ result = self.server.import_survey(self.session_key, base64_encoded_lsa, 'lsa') # RPC returns dict with error status if an issue occurred return None if isinstance(result, dict) else result def export_survey(self, sid): """TODO (NES-956): insert docstring :param sid: LimeSurvey survey id :return: on success base64 encoded survey, else None """ result = self.server.export_survey(self.session_key, sid) if isinstance(result, dict): # Returned a dict element (error) return None return result def delete_responses(self, sid, responses): """Delete responses from LimeSurvey survey :param sid: LimeSurvey survey id :param responses: list of response ids :return: on success, dict with status ok, else None """ result = self.server.delete_responses(self.session_key, sid, responses) return result if result['status'] == 'OK' else None def update_response(self, sid, response_data): result = self.server.update_response(self.session_key, sid, response_data) return result if result['status'] == 'OK' else None