public static DataTable parseFile(string fileName) { QuestionParser questionParser = new QuestionParser(); List <Question> questions = new List <Question>(); string path = Path.Combine(Environment.CurrentDirectory, @"QuestionFiles\", fileName); //Skipping first line since it's version block string[] lines = File.ReadAllLines(path).Skip(1).ToArray(); QuestionPart questionPart = QuestionPart.StartOfFile; foreach (var line in lines) { if (line != string.Empty || (line == string.Empty && questionPart != QuestionPart.QuestionDescription)) { questionPart = questionParser.identifyQuestionPart(line, questionPart); questionParser.parseLine(line, questionPart); if (questionPart == QuestionPart.QuestionDescription) { questions.Add(questionParser.ParsedQuestion); questionParser.resetQuestion(); } } } return(CreateDataTable(questions)); }
/// <summary> /// Removes a set question option from the specified question part /// </summary> /// <param name="part"></param> /// <param name="name"></param> /// <param name="language">Null to remove all instances, otherwise remove a specific label</param> public void RemoveQuestionOption(QuestionPart part, int optionId, string language = null) { var option = part.QuestionOptions.SingleOrDefault(c => c.Id == optionId); bool removed = false; if (language == null) { part.QuestionOptions.Remove(option); removed = true; } else { option?.QuestionOptionLabels.Remove( option.QuestionOptionLabels.SingleOrDefault(v => v.Language == language)); if (option?.QuestionOptionLabels.Count == 0) { part.QuestionOptions.Remove(option); removed = true; } } //Update order if fully removed if (removed) { foreach (var remainingOption in part.QuestionOptions) { if (remainingOption.Order > option.Order) { remainingOption.Order--; } } } }
/// <summary> /// /// </summary> /// <param name="survey"></param> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="responseData"></param> /// <param name="response"></param> internal void SaveIntegerResponse(Survey survey, QuestionPart question, JObject responseData, SurveyResponse response) { if (response.ResponseValues.Count == 0) { response.ResponseValues.Add(new IntegerResponse()); } (response.ResponseValues[0] as IntegerResponse).Value = responseData.GetValue("value").ToObject <int> (); }
/// <summary> /// /// </summary> /// <param name="survey"></param> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="responseData"></param> /// <param name="response"></param> internal void SaveDecimalResponse(Survey survey, QuestionPart question, JObject responseData, SurveyResponse response) { if (response.ResponseValues.Count == 0) { //response.ResponseValues = new List<ResponseValue>(); response.ResponseValues.Add(new DecimalResponse()); } (response.ResponseValues[0] as DecimalResponse).Value = responseData.GetValue("value").ToObject <double> (); }
public void parseLine(string line, QuestionPart questionPart) { //if(line != string.Empty) //{ switch (questionPart) { case QuestionPart.QuestionName: parseQuestionName(line); break; case QuestionPart.PictureSpeechName: parsePictureSpeechName(line); break; case QuestionPart.DifficultyFlagsRefs: parseDifficultyFlagsRefs(line); break; case QuestionPart.Dates: parseDates(line); break; case QuestionPart.QuestionText: ParsedQuestion.Text = line; break; case QuestionPart.QuestionAnswer1: parseAnswer(line, 1); break; case QuestionPart.QuestionAnswer2: parseAnswer(line, 2); break; case QuestionPart.QuestionAnswer3: parseAnswer(line, 3); break; case QuestionPart.QuestionAnswer4: parseAnswer(line, 4); break; case QuestionPart.QuestionAnswer5: parseAnswer(line, 5); break; case QuestionPart.QuestionDescription: ParsedQuestion.Description = line; break; default: break; } //} }
/// <summary> /// Sets a question option value on the specified question part. If langauge is null then the default label is used, otherwise /// the value data is set on the matched langauge label. /// </summary> /// <param name="questionPart"></param> /// <param name="name"></param> /// <param name="value"></param> /// <param name="language"></param> public QuestionOption SetQuestionOptionLabel(QuestionPart questionPart, int id, string code, string name, string value, string language = null) { var option = questionPart.QuestionOptions.SingleOrDefault(o => o.Id == id); if (option != null) { if (language == null) { language = option.QuestionOptionLabels.First().Language; } // replace code if different and unique from other codes if (option.Code != code) { var allCodes = questionPart.QuestionOptions.Select(o => o.Code); if (!allCodes.Contains(code)) { option.Code = code; } else { throw new ArgumentException("Cannot have duplicate options!"); } } var optionLabel = option.QuestionOptionLabels.FirstOrDefault(v => v.Language == language); if (optionLabel == null) { option.QuestionOptionLabels.Add(new QuestionOptionLabel() { Language = language, Value = value, QuestionOption = option }); } else { var allLabels = questionPart.QuestionOptions.Where(q => q.Name == name && q.Id != id).SelectMany(o => o.QuestionOptionLabels.Where(q => q.Language == language).Select(l => l.Value)); if (!allLabels.Contains(value)) { optionLabel.Value = value; } else { throw new ArgumentException("Cannot have duplicate options"); } } return(option); } else { return(this.AddQuestionOption(questionPart, code, name, value, language)); } }
public void ReOrderOptions(QuestionPart part, List <QuestionOption> newOrder) { Dictionary <int, int> newOrderDict = newOrder.ToDictionary(r => r.Id, r => r.Order); foreach (var option in part.QuestionOptions) { if (newOrderDict.ContainsKey(option.Id)) { option.Order = newOrderDict[option.Id]; } } }
public void UpdateQuestionPartName(int surveyId, QuestionPart qp, string newName) { //name update doesn't require any other updates (with part ID being used for question reference) if (qp != null) { if (this._unitOfWork.Surveys.QuestionNameIsUnique(surveyId, newName, qp.Name)) { qp.Name = newName; } else { throw new ArgumentException("Question name must be unique."); } } }
/// <summary> /// /// </summary> /// <param name="survey"></param> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="responseData"></param> /// <returns></returns> internal void SaveLocationResponse(Survey survey, QuestionPart question, JObject responseData, SurveyResponse response) { if (response.ResponseValues.Count == 0) { //response.ResponseValues = new List<ResponseValue>(); response.ResponseValues.Add(new LocationResponse()); } var value = responseData.ToObject <LocationResponse> (); (response.ResponseValues[0] as LocationResponse).Latitude = value.Latitude; (response.ResponseValues[0] as LocationResponse).Longitude = value.Longitude; (response.ResponseValues[0] as LocationResponse).Address = value.Address; //LocationResponse locationResponseValue = responseData.ToObject<LocationResponse>(); return; }
public void Test_SetQuestionConfiguration() { Survey survey = new Survey() { // Title = "Test Survey", }; var view = this._surveyBuilderService.AddSurveyView(survey, "View"); var questionPart = new QuestionPart(); this._surveyBuilderService.AddQuestionPart(view, new DAL.Models.Questions.QuestionPart(), null); this._surveyBuilderService.SetQuestionConfiguration(questionPart, "cat", "dog"); Assert.True(true); }
public QuestionPart identifyQuestionPart(string line, QuestionPart previousPart) { switch (previousPart) { case QuestionPart.QuestionName: return(QuestionPart.PictureSpeechName); case QuestionPart.PictureSpeechName: return(QuestionPart.DifficultyFlagsRefs); case QuestionPart.DifficultyFlagsRefs: return(QuestionPart.Dates); case QuestionPart.Dates: if (line != string.Empty) { return(QuestionPart.QuestionText); } else { return(QuestionPart.QuestionAnswer5); } case QuestionPart.QuestionText: return(QuestionPart.QuestionAnswer1); case QuestionPart.QuestionAnswer1: return(QuestionPart.QuestionAnswer2); case QuestionPart.QuestionAnswer2: return(QuestionPart.QuestionAnswer3); case QuestionPart.QuestionAnswer3: return(QuestionPart.QuestionAnswer4); case QuestionPart.QuestionAnswer4: return(QuestionPart.QuestionAnswer5); case QuestionPart.QuestionAnswer5: return(QuestionPart.QuestionDescription); default: return(QuestionPart.QuestionName); } }
/// <summary> /// /// </summary> /// <param name="survey"></param> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="responseData"></param> /// <param name="response"></param> internal void SaveOptionSelectResponse(Survey survey, QuestionPart question, JObject responseData, SurveyResponse response) { response.ResponseValues.Clear(); var values = responseData["values"].ToObject <List <OptionSelectResponse> > (); foreach (var val in values) { response.ResponseValues.Add(new OptionSelectResponse() { Value = val.Value, Name = val.Name, Code = val.Code }); } return; }
/// <summary> /// Sets a configuration value for the specified question part /// </summary> /// <param name="questionPart"></param> /// <param name="name"></param> /// <param name="value"></param> public QuestionConfiguration SetQuestionConfiguration(QuestionPart questionPart, string name, object value) { var configuration = questionPart.QuestionConfigurations.SingleOrDefault(c => c.Name == name); if (configuration == null) { QuestionConfiguration qc = new QuestionConfiguration() { Name = name, Value = value.ToString(), ValueType = this._questions.QuestionTypeDefinitions[questionPart.QuestionType].QuestionConfigurations[name].ValueType }; questionPart.QuestionConfigurations.Add(qc); return(qc); } configuration.Value = value.ToString(); return(configuration); }
public void SetQuestionOptionConditionals(QuestionPart question, List <QuestionOptionConditional> conditionals) { List <QuestionOptionConditional> newSource = new List <QuestionOptionConditional>(); List <QuestionOptionConditional> updateSource = new List <QuestionOptionConditional>(); List <QuestionOptionConditional> newTarget = new List <QuestionOptionConditional>(); List <QuestionOptionConditional> updateTarget = new List <QuestionOptionConditional>(); conditionals.ForEach(conditional => { if (conditional.SourceQuestionId == question.Id) { if (conditional.Id == 0) { newSource.Add(conditional); } else { updateSource.Add(conditional); } } else { if (conditional.Id == 0) { newTarget.Add(conditional); } else { updateTarget.Add(conditional); } } }); this._unitOfWork.QuestionOptionConditionals.DeleteSourceConditionals(question.Id, updateSource.Select(c => c.Id).ToList()); this._unitOfWork.QuestionOptionConditionals.DeleteTargetConditionals(question.Id, updateTarget.Select(c => c.Id).ToList()); this._unitOfWork.QuestionOptionConditionals.AddRange(newSource); this._unitOfWork.QuestionOptionConditionals.AddRange(newTarget); this._unitOfWork.QuestionOptionConditionals.UpdateRange(updateSource); this._unitOfWork.QuestionOptionConditionals.UpdateRange(updateTarget); }
/// <summary> /// Adds a question part to the specified SurveyView - this creates a new QuestionPartView from the part /// </summary> /// <param name="view"></param> /// <param name="part"></param> /// <param name="position">0-index order, position of the qustion</param> /// <returns>A reference to the created QuestionPartView</returns> public QuestionPartView AddQuestionPart(SurveyView view, QuestionPart part, QuestionTypeDefinition definition, int position = -1) { QuestionPartView questionPartView = new QuestionPartView { QuestionPart = part }; if (position >= 0) { questionPartView.Order = position; (view.QuestionPartViews as List <QuestionPartView>)?.Insert(position, questionPartView); } else { (view.QuestionPartViews as List <QuestionPartView>)?.Add(questionPartView); questionPartView.Order = view.QuestionPartViews.Count - 1; } return(questionPartView); }
/// <summary> /// /// </summary> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="repeat"></param> /// <returns></returns> private async Task <SurveyResponse> GenerateSurveyResponse(QuestionPart question, SurveyRespondent respondent, int repeat) { return(await this._unitOfWork.SurveyResponses.GetMostRecentResponseForQuestionByRespondentAsync(question.Id, (SurveyRespondent)respondent, repeat)); }
/// <summary> /// /// </summary> /// <param name="survey"></param> /// <param name="question"></param> /// <param name="respondent"></param> /// <param name="responseData"></param> /// <param name="repeat"></param> /// <returns></returns> public async Task <bool> SaveResponse(Survey survey, QuestionPart question, SurveyRespondent respondent, JObject responseData, int repeat) { var type = this._questionTypeManager.QuestionTypeDefinitions[question.QuestionType]; if (type.ResponseValidator != null) { var responseDataUnwrapped = this.UnwrapResponseData(type.ResponseType, responseData); if (!type.ResponseValidator.ValidateResponse(responseDataUnwrapped, question.QuestionConfigurations.Cast <IQuestionConfiguration> ().ToHashSet())) { return(false); } } var surveyResponse = await this._unitOfWork.SurveyResponses.GetMostRecentResponseForQuestionByRespondentAsync(question.Id, (SurveyRespondent)respondent, repeat); if (surveyResponse == null || ( surveyResponse.SurveyAccessRecord.AccessDateTime < ((PrimaryRespondent)respondent).SurveyAccessRecords.First().AccessDateTime)) { surveyResponse = new SurveyResponse() { QuestionPart = question, Respondent = respondent, SurveyAccessRecord = ((PrimaryRespondent)respondent).SurveyAccessRecords.First(), Repeat = repeat }; this._unitOfWork.SurveyResponses.Add(surveyResponse); } // surveyResponse.Repeat = repeat; switch (type.ResponseType) { case QuestionResponseType.String: SaveStringResponse(survey, question, responseData, surveyResponse); break; case QuestionResponseType.Decimal: SaveDecimalResponse(survey, question, responseData, surveyResponse); break; case QuestionResponseType.Integer: SaveIntegerResponse(survey, question, responseData, surveyResponse); break; case QuestionResponseType.DateTime: SaveDateTimeResponse(surveyResponse, responseData); break; case QuestionResponseType.Path: SavePathResponse(surveyResponse, responseData); break; case QuestionResponseType.Json: SaveJsonResponse(surveyResponse, responseData); break; case QuestionResponseType.Location: SaveLocationResponse(survey, question, responseData, surveyResponse); break; case QuestionResponseType.Timeline: SaveTimelineResponse(surveyResponse, responseData); break; case QuestionResponseType.OptionSelect: // SaveOptionSelectResponse(survey, question, responseData, surveyResponse); break; } try { await this._unitOfWork.SaveChangesAsync(); } catch (Exception e) { this._logger.LogError(e, "Error saving response."); return(false); } return(true); }
/// <summary> /// /// </summary> /// <param name="part"></param> /// <param name="definition"></param> public void AddQuestionPartChild(QuestionPart part, QuestionTypeDefinition definition) { part.QuestionType = definition.TypeName; part.QuestionPartChildren.Add(part); }
/// <summary> /// Returns the set of question options associated with this question part. /// </summary> /// <param name="questionPart"></param> /// <param name="language">Specify a main label language</param> /// <returns></returns> public IEnumerable <QuestionOption> GetQuestionOptions(QuestionPart questionPart, string language = null) { return(questionPart.QuestionOptions); }
/// <summary> /// Retrieves the list of question configurations associated with this question part. Only values that differ /// from default values will be returned (default values are not stored). /// </summary> /// <param name="questionPart"></param> /// <returns></returns> public IEnumerable <QuestionConfiguration> GetQuestionConfigurations(QuestionPart questionPart) { return(questionPart.QuestionConfigurations); }
/// <summary> /// Removes a configuration value (resets to default) from the specified QuestionPart. /// </summary> /// <param name="part"></param> /// <param name="name"></param> public void RemoveQuestionConfiguration(QuestionPart part, string name) { part.QuestionConfigurations.Remove(part.QuestionConfigurations.SingleOrDefault(c => c.Name == name)); }
/// <summary> /// Imports options into question part from stream /// </summary> /// <param name="questionPart">Question part</param> /// <param name="name">Option Group Name</param> /// <param name="language"></param> /// <param name="fileStream">File stream of csv file</param> /// <returns></returns> public List <(string, string, string)> ImportQuestionOptions(QuestionPart questionPart, string name, string language, IFormFile file) { try { //check if the option has a value / allows multiple List <(string, string, string)> errorList = new List <(string, string, string)>(); var definition = this._questions.QuestionTypeDefinitions[questionPart.QuestionType]; if (definition != null) { if (definition.QuestionOptions.Keys.Contains(name)) { int startOptionOrderIndex = questionPart.QuestionOptions.Count(o => o.Name == name); IEnumerable <QuestionOptionData> optionData; using (var fileStream = new StreamReader(file.OpenReadStream())) { var reader = new CsvReader(fileStream); reader.Configuration.RegisterClassMap <QuestionOptionMap>(); reader.Configuration.PrepareHeaderForMatch = header => Regex.Replace(header, @"\s", string.Empty); optionData = reader.GetRecords <QuestionOptionData>().ToList(); } // get unique codes from input list var allCodes = questionPart.QuestionOptions.Select(o => o.Code); var importCodes = optionData.Select(o => o.Code).ToList(); var duplicateImportCodes = importCodes.GroupBy(c => c).Where(g => g.Count() > 1).Select(c => c.Key).ToList(); var duplicateCodes = importCodes.Intersect(allCodes).Union(duplicateImportCodes).ToList(); // get unique labels from input list for question option group var allLabels = questionPart.QuestionOptions.Where(q => q.Name == name).SelectMany(o => o.QuestionOptionLabels.Where(q => q.Language == language).Select(l => l.Value)); var importLabels = optionData.Select(o => o.Label).ToList(); var duplicateImportLabels = importLabels.GroupBy(c => c).Where(g => g.Count() > 1).Select(c => c.Key).ToList(); var duplicateLabels = importLabels.Intersect(allLabels).Union(duplicateImportLabels).ToList(); foreach (var option in optionData) { bool duplicateCode = duplicateCodes.Contains(option.Code); bool duplicateLabel = duplicateLabels.Contains(option.Label); if (duplicateCode || duplicateLabel) { string reason = duplicateCode && duplicateLabel ? "Duplicate option" : (duplicateCode ? "Duplicate Code" : "Duplicate Label"); errorList.Add((option.Code, option.Label, reason)); } else { var newOption = new QuestionOption() { Name = name, Code = option.Code, Order = startOptionOrderIndex++, QuestionOptionLabels = new LabelCollection <QuestionOptionLabel>() { new QuestionOptionLabel() { Language = language ?? "en", Value = option.Label } } }; if (definition.QuestionOptions[name].IsMultipleAllowed) { questionPart.QuestionOptions.Add(newOption); } else if (newOption.Order == 0) { questionPart.QuestionOptions.Add(newOption); } else { throw new InvalidOperationException("Cannot assign new question option, remove first."); } } } } else { throw new ArgumentException("Question Option does not exist for this question type."); } } else { throw new ArgumentException("Question Type does not exist."); } return(errorList); } catch (ValidationException exception) { if (exception.Message.StartsWith("Header")) { throw new ArgumentException("Error in CSV file. Must contain 'Code' and 'Label' header row"); } else { throw new Exception("Error during import"); } } }
/// <summary> /// /// </summary> /// <param name="part"></param> /// <param name="name"></param> /// <param name="language"></param> public QuestionOption AddQuestionOption(QuestionPart part, string code, string name, string value, string language = null) { //check if the option has a value / allows multiple var definition = this._questions.QuestionTypeDefinitions[part.QuestionType]; if (definition != null) { if (definition.QuestionOptions.Keys.Contains(name)) { //ensure code hasn't been used already var allCodes = part.QuestionOptions.Select(o => o.Code); if (allCodes.Contains(code)) { throw new ArgumentException("Cannot have duplicate options"); } var allLabels = part.QuestionOptions.Where(q => q.Name == name).SelectMany(o => o.QuestionOptionLabels.Where(q => q.Language == language).Select(l => l.Value)); if (allLabels.Contains(value)) { throw new ArgumentException("Cannot have duplicate options"); } var newOption = new QuestionOption() { Name = name, Code = code, Order = part.QuestionOptions.Count(o => o.Name == name), QuestionOptionLabels = new LabelCollection <QuestionOptionLabel>() { new QuestionOptionLabel() { Language = language ?? "en", Value = value } } }; if (definition.QuestionOptions[name].IsMultipleAllowed) { part.QuestionOptions.Add(newOption); } else if (newOption.Order == 0) { part.QuestionOptions.Add(newOption); } else { throw new InvalidOperationException("Cannot assign new question option, remove first."); } return(newOption); } else { throw new ArgumentException("Question Option does not exist for this question type."); } } else { throw new ArgumentException("Question Type does not exist."); } }