public IHttpActionResult CleanClipboard(string id) { if (!ModelState.IsValid) { return(BadRequest(ModelState.ToString())); } if (id == null) { throw new ArgumentNullException(nameof(id)); } var uid = Guid.Parse(id); var createdAt = GetOriginCreatedAt(uid); if (!createdAt.HasValue) { return(DtoResultV5.Success(Json, "Data already deleted")); } string path = GetFullClipboardDataPath(createdAt.Value); //ensure orig item and (soft)deleted item in the same file if (!File.Exists(path)) { return(DtoResultV5.Success(Json, "no data")); } var notes = ReadLskjson <Guid, DtoClipboardItem>(path, CollectLskjsonLineClipboard); var foundNote = notes.FirstOrDefault(n => n.Uid == uid); if (foundNote == null) { return(DtoResultV5.Success(Json, "already deleted")); } foundNote.HasDeleted = true; //todo - replace with real UserId(get by session id) foundNote.DeletedBy = Constants.DevDeleteUserId + DateTime.Now.ToString("dd"); foundNote.DeletedAt = DateTime.Now; //need replace a line in the file - seems there is no way to just rewrite one line, have to re-write entire file // - https://stackoverflow.com/questions/1971008/edit-a-specific-line-of-a-text-file-in-c-sharp // - https://stackoverflow.com/questions/13509532/how-to-find-and-replace-text-in-a-file-with-c-sharp var backupPath = path.Replace(Constants.LskjsonPrefix, Constants.LskjsonPrefix + DateTime.Now.ToString("dd-HHmmss-")); File.Move(path, backupPath); var success = AppendNoteToFile(path, notes.ToArray()); if (success) { File.Delete(backupPath); return(DtoResultV5.Success(Json, "Data deleted")); } else { File.Move(backupPath, path); return(DtoResultV5.Fail(Json, "Failed to delete data")); } }
public IHttpActionResult Delete2(string id, [FromBody] DeleteBody body) { if (string.IsNullOrEmpty(id)) { throw new ArgumentNullException(nameof(id)); } if (body == null) { throw new ArgumentNullException(nameof(body)); } var perf = PerfCounter.NewThenCheck(this.ToString() + "." + MethodBase.GetCurrentMethod().Name); var fulfillmentPath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Fulfillments); var antiSpamResult = PassAntiSpamDefender(fulfillmentPath, AuthMode.SimpleDeletion); if (!antiSpamResult.Valid) { return(DtoResultV5.Fail(BadRequest, antiSpamResult.Message)); } perf.Check("anti spam end"); SyncRoutine(fulfillmentPath); perf.Check("sync routine end"); var fulfillments = ReadLskjson <Guid, RoutineFulfillment>(fulfillmentPath, CollectLskjsonLineIncludeDeleted); perf.Check("read fulfillment end"); var inputUid = Guid.Parse(id); var fulfill = fulfillments.FirstOrDefault(f => f.Uid == inputUid); if (fulfill == null) { return(DtoResultV5.Fail(BadRequest, "Routine not found, may already deleted, please refresh page")); } fulfill.IsDeleted = true; fulfill.DeleteAt = DateTime.Now; fulfill.DeletedBy = "fixme-delete"; fulfill.DeleteReason = body.Reason; WriteToFile(fulfillmentPath, fulfillments); perf.End("override fulfill end", true); return(DtoResultV5.Success(Json, DtoRoutine.From(fulfill, false))); }
public IHttpActionResult PutRecursive(string id, [FromBody] PutRecursiveBody body) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (body == null) { throw new ArgumentNullException(nameof(body)); } if (body.Enable && (body.IntervalDays ?? 0) < 1) { throw new ArgumentException($"invalid recursive interval {body.IntervalDays}"); } var perf = PerfCounter.NewThenCheck(this.ToString() + "." + MethodBase.GetCurrentMethod().Name); var fulfillmentPath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Fulfillments); SyncRoutine(fulfillmentPath); perf.Check("sync routine end"); var fulfillments = ReadLskjson <Guid, RoutineFulfillment>(fulfillmentPath, CollectLskjsonLineIncludeDeleted); perf.Check("read fulfillment end"); var inputUid = Guid.Parse(id); var fulfill = fulfillments.FirstOrDefault(f => f.Uid == inputUid); if (fulfill == null) { return(DtoResultV5.Fail(BadRequest, "expired data found, please reload page first.")); } fulfill.EnableSchedule = body.Enable; if (body.Enable) { fulfill.RecursiveIntervalDays = body.IntervalDays; } fulfill.UpdateBy = "fixme-put-rec"; fulfill.UpdateAt = DateTime.Now; WriteToFile(fulfillmentPath, fulfillments); perf.End("override fulfill end", true); return(DtoResultV5.Success(Json, DtoRoutine.From(fulfill, false))); }
public IHttpActionResult Get(string id, string history = null) { if (string.IsNullOrWhiteSpace(id)) { return(DtoResultV5.Fail(BadRequest, "id is empty")); } if (Constants.LskArchived.Equals(history, StringComparison.OrdinalIgnoreCase)) { var archivePath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Archives); var archivedRecords = ReadLskjson <Guid, FulfillmentArchive>(archivePath, CollectLskjsonLineIncludeDeleted); var recordsByParentUid = archivedRecords.Where(a => id.Equals(a.ParentUid.ToString(), StringComparison.OrdinalIgnoreCase)); return(DtoResultV5.Success(Json, recordsByParentUid.Select(r => DtoFulfillmentArchive.From(r)))); } else { var fulfillments = ReadFulfillmentsOfThisYear(AuthMode.None); var fulfillment = fulfillments.FirstOrDefault(f => id.Equals(f.Uid.ToString(), StringComparison.OrdinalIgnoreCase)); var dto = fulfillment == null ? null : DtoRoutine.From(fulfillment, true); return(DtoResultV5.Success(Json, dto)); } }
public IHttpActionResult Clipboard([FromBody] PutBody putBody) { if (putBody == null) { throw new ArgumentNullException(nameof(putBody)); } if (putBody.Uid == null) { throw new ArgumentNullException(nameof(putBody.Uid)); } var inputUid = Guid.Parse(putBody.Uid); //todo improve this, hard coded as dev session id for now if (!CheckHeaderSession()) { //return Unauthorized(); } var createdAt = GetOriginCreatedAt(inputUid); if (!createdAt.HasValue) { throw new InvalidOperationException("Data already deleted, please reload to latest then edit"); } var path = GetFullClipboardDataPath(createdAt.Value); //ensure orig item and updated item in the same file if (!File.Exists(path)) { return(DtoResultV5.Success(this.Json, "no data")); } //perf - O(n) is 2n here, can be optimized to n var notes = ReadLskjson <Guid, DtoClipboardItem>(path, CollectLskjsonLineClipboard); var foundNote = notes.FirstOrDefault(n => n.Uid == inputUid); var foundChild = notes.FirstOrDefault(n => n.ParentUid == inputUid); //ensure the relation is a chain, not a tree if (foundChild != null) { throw new InvalidOperationException("Data already changed, please reload to latest then edit"); } if (foundNote != null) { var newNote = Utility.DeepClone(foundNote); newNote.Uid = Guid.NewGuid(); //reset newNote.Data = putBody.Data; //todo - replace with real UserId(get by session id) newNote.HasUpdated = true; newNote.LastUpdatedBy = Constants.DevUpdateUserId + DateTime.Now.ToString("dd"); newNote.LastUpdatedAt = DateTime.Now; newNote.ParentUid = foundNote.Uid; AppendNoteToFile(path, newNote); AppendObjectToFile(GetFullClipboardIndexPath(newNote.CreatedAt), DtoLskjsonIndex.From(newNote)); //return DtoResultV5.Success(Json, MapToJSNameConvention(newNote), "Data updated"); return(DtoResultV5.Success(Json, newNote, "Data updated")); //do the map on client side } else { return(DtoResultV5.Fail(Json, "The data you want to update may have been deleted")); } }
public IHttpActionResult DeleteHistoryRecord2(string parentId, string id, [FromBody] DeleteHistoryBody body) { if (string.IsNullOrEmpty(parentId)) { throw new ArgumentNullException(nameof(parentId)); } if (body == null) { throw new ArgumentNullException(nameof(body)); } if (body.Kind != Constants.LskArchived && body.Kind != Constants.LskStaged) { return(DtoResultV5.Fail(BadRequest, $"unsupported deletion: '{body.Kind}'")); } var perf = PerfCounter.NewThenCheck(this.ToString() + "." + MethodBase.GetCurrentMethod().Name); var fulfillmentPath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Fulfillments); var antiSpamResult = PassAntiSpamDefender(fulfillmentPath, AuthMode.SimpleDeletion); if (!antiSpamResult.Valid) { return(DtoResultV5.Fail(BadRequest, antiSpamResult.Message)); } perf.Check("anti spam end"); SyncRoutine(fulfillmentPath); perf.Check("sync routine end"); var inputParentUid = Guid.Parse(parentId); var inputUid = Guid.Parse(id); string filePath = null; List <ILskjsonLine> allRecords = null; FulfillmentArchive history = null; if (body.Kind == Constants.LskStaged) { filePath = fulfillmentPath; var fulfillments = ReadLskjson <Guid, RoutineFulfillment>(filePath, CollectLskjsonLineIncludeDeleted); var fulfill = fulfillments.FirstOrDefault(f => f.Uid == inputParentUid); if (fulfill == null) { return(DtoResultV5.Fail(BadRequest, "Routine not found, may already deleted, please refresh page")); } if (!fulfill.HasMigrated) { return(DtoResultV5.Fail(BadRequest, "Migrate routine first")); } if (fulfill.StagedArchives == null || fulfill.StagedArchives.Length == 0) { return(DtoResultV5.Fail(BadRequest, "No staged history found, please refresh page")); } allRecords = fulfillments.ToList <ILskjsonLine>(); history = fulfill.StagedArchives.FirstOrDefault(s => s.Uid == inputUid); } else if (body.Kind == Constants.LskArchived) { filePath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Archives); var historyRecords = ReadLskjson <Guid, FulfillmentArchive>(filePath, CollectLskjsonLineIncludeDeleted); allRecords = historyRecords.ToList <ILskjsonLine>(); history = historyRecords.FirstOrDefault(h => h.ParentUid == inputParentUid && h.Uid == inputUid); } if (history == null) { return(DtoResultV5.Fail(BadRequest, $"No {body.Kind} history matches with provided id, please refresh page")); } history.IsDeleted = true; history.DeleteAt = DateTime.Now; history.DeletedBy = "fixme-del"; history.DeleteReason = body.Reason; WriteToFile(filePath, allRecords); perf.End($"delete {body.Kind} history end", true); return(DtoResultV5.Success(Json, body.Kind)); }
public IHttpActionResult Put(string id, [FromBody] PutBody body) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (body == null) { throw new ArgumentNullException(nameof(body)); } var perf = PerfCounter.NewThenCheck(this.ToString() + "." + MethodBase.GetCurrentMethod().Name); var fulfillmentPath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Fulfillments); var antiSpamResult = PassAntiSpamDefender(fulfillmentPath, AuthMode.None); if (!antiSpamResult.Valid) { return(DtoResultV5.Fail(BadRequest, antiSpamResult.Message)); } perf.Check("anti spam end"); SyncRoutine(fulfillmentPath); perf.Check("sync routine end"); var fulfillments = ReadLskjson <Guid, RoutineFulfillment>(fulfillmentPath, CollectLskjsonLineIncludeDeleted); perf.Check("read fulfillment end"); var inputUid = Guid.Parse(id); var fulfill = fulfillments.FirstOrDefault(f => f.Uid == inputUid); if (fulfill == null) { return(DtoResultV5.Fail(BadRequest, "expired data found, please reload page first.")); } var offsetDays = int.Parse(antiSpamResult.Message); var date = DateTime.Now.AddDays(-1 * Math.Abs(offsetDays)); var record = new FulfillmentArchive(fulfill.Uid, body.LastRemark, date, "fixme-put", DateTime.Now); if (fulfill.StagedArchives == null) { fulfill.StagedArchives = new[] { record }; } else { var staged = fulfill.StagedArchives.ToList(); staged.Add(record); if (staged.Count >= Constants.LskFulfillmentActiveRecords + Constants.LskFulfillmentArchiveUnit) { const int startIndex = 0; var archiveUnit = staged.GetRange(startIndex, Constants.LskFulfillmentArchiveUnit); var archivePath = GetFullIntrospectionDataPath(DateTime.Now, IntrospectionDataType.Archives); AppendObjectToFile(archivePath, archiveUnit.ToArray()); staged.RemoveRange(startIndex, archiveUnit.Count); fulfill.HasArchived = true; } fulfill.StagedArchives = staged.ToArray(); } //fulfill.StagedArchives = fulfill.StagedArchives.Concat(new[] { record }).ToArray(); fulfill.UpdateBy = "fixme-update"; fulfill.UpdateAt = DateTime.Now; WriteToFile(fulfillmentPath, fulfillments); perf.End("override fulfill end", true); return(DtoResultV5.Success(Json, DtoRoutine.From(fulfill, false))); }