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"));
        }
Example #2
0
		/// <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"));
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }