public async Task <IActionResult> SelectCourses(int districtId, string orgSourceId, IEnumerable <string> SelectedCourses) { var repo = new DistrictRepo(db, districtId); var model = await repo.Lines <CsvCourse>() //.Where(c => JsonConvert.DeserializeObject<CsvCourse>(c.RawData).orgSourcedId == orgSourceId.ToString()) .Where(c => SelectedCourses.Contains(c.SourcedId)) .ToListAsync(); ViewBag.districtId = districtId; foreach (var course in model) { bool include = SelectedCourses.Contains(course.SourcedId); if (course.IncludeInSync == include) { continue; } course.IncludeInSync = include; course.Touch(); repo.PushLineHistory(course, isNewData: false); } await repo.Committer.Invoke(); return(RedirectToAction(nameof(SelectCourses), new { districtId, orgSourceId }).WithSuccess("Courses saved successfully")); }
/// <summary> /// Helper to mark a record to be included in the next push to LMS /// </summary> private void IncludeReadyTouch(DataSyncLine line) { line.IncludeInSync = true; line.SyncStatus = SyncStatus.ReadyToApply; line.Touch(); Repo.PushLineHistory(line, isNewData: false); }
public async Task <IActionResult> DataSyncLineEdit(DataSyncLine postedLine) { var repo = new DistrictRepo(db, postedLine.DistrictId); var line = await repo.Lines().SingleOrDefaultAsync(l => l.DataSyncLineId == postedLine.DataSyncLineId); // not currently editable //bool isNewData = line.RawData != postedLine.RawData; line.TargetId = postedLine.TargetId; line.IncludeInSync = postedLine.IncludeInSync; line.LoadStatus = postedLine.LoadStatus; line.SyncStatus = postedLine.SyncStatus; line.Touch(); repo.PushLineHistory(line, isNewData: false); await repo.Committer.Invoke(); return(RedirectToAction(nameof(DataSyncLineEdit), line.DataSyncLineId).WithSuccess("Dataline updated successfully")); }
public async Task <IActionResult> SelectOrgs(int districtId, IEnumerable <string> SelectedOrgs) { var repo = new DistrictRepo(db, districtId); var model = await repo.Lines <CsvOrg>().ToListAsync(); foreach (var org in model) { bool include = SelectedOrgs.Contains(org.SourcedId); if (org.IncludeInSync == include) { continue; } org.IncludeInSync = include; org.Touch(); repo.PushLineHistory(org, isNewData: false); } await repo.Committer.Invoke(); return(RedirectToAction(nameof(SelectOrgs), new { districtId }).WithSuccess("Orgs saved successfully")); }
private async Task ApplyLine <T>(DistrictRepo repo, DataSyncLine line) where T : CsvBaseObject { switch (line.LoadStatus) { case LoadStatus.None: Logger.Here().LogWarning($"None should not be flagged for Sync: {line.RawData}"); return; } ApiPostBase data; var apiManager = new ApiManager(repo.District.LmsApiBaseUrl) { ApiAuthenticator = ApiAuthenticatorFactory.GetApiAuthenticator(repo.District.LmsApiAuthenticatorType, repo.District.LmsApiAuthenticationJsonData) }; if (line.Table == nameof(CsvEnrollment)) { var enrollment = new ApiEnrollmentPost(line.RawData); CsvEnrollment csvEnrollment = JsonConvert.DeserializeObject <CsvEnrollment>(line.RawData); DataSyncLine cls = repo.Lines <CsvClass>().SingleOrDefault(l => l.SourcedId == csvEnrollment.classSourcedId); DataSyncLine usr = repo.Lines <CsvUser>().SingleOrDefault(l => l.SourcedId == csvEnrollment.userSourcedId); var map = new EnrollmentMap { classTargetId = cls?.TargetId, userTargetId = usr?.TargetId, }; // this provides a mapping of LMS TargetIds (rather than sourcedId's) enrollment.EnrollmentMap = map; enrollment.ClassTargetId = cls?.TargetId; enrollment.UserTargetId = usr?.TargetId; // cache map in the database (for display/troubleshooting only) line.EnrollmentMap = JsonConvert.SerializeObject(map); data = enrollment; } else if (line.Table == nameof(CsvClass)) { var classCsv = JsonConvert.DeserializeObject <CsvClass>(line.RawData); // Get course & school of this class var course = repo.Lines <CsvCourse>().SingleOrDefault(l => l.SourcedId == classCsv.courseSourcedId); var courseCsv = JsonConvert.DeserializeObject <CsvCourse>(course.RawData); // Get Term of this class // TODO: Handle multiple terms, termSourceIds can be a comma separated list of terms. var term = repo.Lines <CsvAcademicSession>().SingleOrDefault(s => s.SourcedId == classCsv.termSourcedIds); var org = repo.Lines <CsvOrg>().SingleOrDefault(o => o.SourcedId == classCsv.schoolSourcedId); var _class = new ApiClassPost(line.RawData) { CourseTargetId = course.TargetId, SchoolTargetId = org.TargetId, TermTargetId = string.IsNullOrWhiteSpace(term.TargetId) ? "2018" : term.TargetId, //TODO: Add a default term setting in District Entity Period = classCsv.periods }; data = _class; } else { data = new ApiPost <T>(line.RawData); } data.DistrictId = repo.District.TargetId; data.DistrictName = repo.District.Name; data.LastSeen = line.LastSeen; data.SourcedId = line.SourcedId; data.TargetId = line.TargetId; data.Status = line.LoadStatus.ToString(); var response = await apiManager.Post(GetEntityEndpoint(data.EntityType.ToLower(), repo), data); if (response.Success) { line.SyncStatus = SyncStatus.Applied; if (!string.IsNullOrEmpty(response.TargetId)) { line.TargetId = response.TargetId; } line.Error = null; } else { line.SyncStatus = SyncStatus.ApplyFailed; line.Error = response.ErrorMessage; // The Lms can send false success if the entity already exist. In such a case we read the targetId if (!string.IsNullOrEmpty(response.TargetId)) { line.TargetId = response.TargetId; } } line.Touch(); repo.PushLineHistory(line, isNewData: false); }
private async Task <bool> ProcessRecord <T>(T record, string table, DateTime now) where T : CsvBaseObject { if (string.IsNullOrEmpty(record.sourcedId)) { throw new ProcessingException(Logger.Here(), $"Record of type {typeof(T).Name} contains no SourcedId: {JsonConvert.SerializeObject(record)}"); } DataSyncLine line = await Repo.Lines <T>().SingleOrDefaultAsync(l => l.SourcedId == record.sourcedId); bool isNewRecord = line == null; Repo.CurrentHistory.NumRows++; string data = JsonConvert.SerializeObject(record); if (isNewRecord) { // already deleted if (record.isDeleted) { Repo.CurrentHistory.NumDeleted++; return(false); } Repo.CurrentHistory.NumAdded++; line = new DataSyncLine { SourcedId = record.sourcedId, DistrictId = Repo.DistrictId, LoadStatus = LoadStatus.Added, LastSeen = now, Table = table, }; Repo.AddLine(line); } else // existing record, check if it has changed { line.LastSeen = now; line.Touch(); // no change to the data, skip! if (line.RawData == data) { if (line.SyncStatus != SyncStatus.Loaded) { line.LoadStatus = LoadStatus.NoChange; } return(false); } // status should be deleted if (record.isDeleted) { Repo.CurrentHistory.NumDeleted++; line.LoadStatus = LoadStatus.Deleted; } else if (line.SyncStatus == SyncStatus.Loaded && line.LoadStatus == LoadStatus.Added) { Repo.CurrentHistory.NumAdded++; line.LoadStatus = LoadStatus.Added; // if added, leave added } else { Repo.CurrentHistory.NumModified++; line.LoadStatus = LoadStatus.Modified; } } line.RawData = data; line.SourcedId = record.sourcedId; line.SyncStatus = SyncStatus.Loaded; Repo.PushLineHistory(line, isNewData: true); return(isNewRecord); }