public void ImportMissingWorkspaceAndUser() { RunAsync(async delegate { var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning coffee", ModifiedAt = new DateTime(2014, 1, 3), WorkspaceId = 1, UserId = 2, }; var timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.AreNotEqual(Guid.Empty, timeEntryData.WorkspaceId); var workspaceRows = await DataStore.Table <WorkspaceData> ().QueryAsync(m => m.Id == timeEntryData.WorkspaceId); var workspaceData = workspaceRows.FirstOrDefault(); Assert.IsNotNull(workspaceData); Assert.IsNotNull(workspaceData.RemoteId); Assert.AreEqual(DateTime.MinValue, workspaceData.ModifiedAt); var userRows = await DataStore.Table <UserData> ().QueryAsync(m => m.Id == timeEntryData.UserId); var userData = userRows.FirstOrDefault(); Assert.IsNotNull(userData); Assert.IsNotNull(userData.RemoteId); Assert.AreEqual(DateTime.MinValue, userData.ModifiedAt); }); }
public Task <TimeEntryJson> CreateTimeEntry(TimeEntryJson jsonObject) { var url = new Uri(v8Url, "time_entries"); jsonObject.CreatedWith = Platform.DefaultCreatedWith; return(CreateObject(url, jsonObject)); }
public Task <TimeEntryJson> UpdateTimeEntry(TimeEntryJson jsonObject) { var url = new Uri(v8Url, String.Format("time_entries/{0}", jsonObject.Id.Value.ToString())); var user = ServiceContainer.Resolve <AuthManager> ().User; return(UpdateObject(url, jsonObject)); }
public static TimeEntryData Import(this TimeEntryJson json, IDataStoreContext ctx, Guid?localIdHint = null, TimeEntryData mergeBase = null) { var converter = ServiceContainer.Resolve <TimeEntryJsonConverter> (); return(converter.Import(ctx, json, localIdHint, mergeBase)); }
private static void DecodeDuration(TimeEntryData data, TimeEntryJson json) { var now = Time.UtcNow.Truncate(TimeSpan.TicksPerSecond); // Decode duration: TimeSpan duration; if (json.Duration < 0) { data.State = TimeEntryState.Running; duration = now.ToUnix() + TimeSpan.FromSeconds(json.Duration); } else { data.State = TimeEntryState.Finished; duration = TimeSpan.FromSeconds(json.Duration); } // Set start and stop times based on the duration: if (data.State == TimeEntryState.Finished) { data.StartTime = json.StartTime.ToUtc(); data.StopTime = json.StartTime.ToUtc() + duration; } else { data.StartTime = now - duration; data.StopTime = null; } }
public TimeEntryData Import(IDataStoreContext ctx, TimeEntryJson json, Guid?localIdHint = null, TimeEntryData mergeBase = null) { var log = ServiceContainer.Resolve <ILogger> (); var data = GetByRemoteId <TimeEntryData> (ctx, json.Id.Value, localIdHint); var merger = mergeBase != null ? new TimeEntryMerger(mergeBase) : null; if (merger != null && data != null) { merger.Add(new TimeEntryData(data)); } if (json.DeletedAt.HasValue) { if (data != null) { // TODO: Delete TimeEntryTag intermediate data log.Info(Tag, "Deleting local data for {0}.", data.ToIdString()); ctx.Delete(data); data = null; } } else if (merger != null || ShouldOverwrite(data, json)) { data = data ?? new TimeEntryData(); ImportJson(ctx, data, json); if (merger != null) { merger.Add(data); data = merger.Result; } if (merger != null) { log.Info(Tag, "Importing {0}, merging with local data.", data.ToIdString()); } else { log.Info(Tag, "Importing {0}, replacing local data.", data.ToIdString()); } data = ctx.Put(data); // Also update tags from the JSON we are merging: if (mergeBase == null || (mergeBase != null && mergeBase.ModifiedAt != data.ModifiedAt)) { log.Info(Tag, "Resetting tags for {0}.", data.ToIdString()); ResetTags(ctx, data, json); } } else { log.Info(Tag, "Skipping import of {0}.", json.ToIdString()); } return(data); }
public void ImportUpdated() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryData = await DataStore.PutAsync(new TimeEntryData() { RemoteId = 2, Description = "", WorkspaceId = workspaceData.Id, UserId = userData.Id, ModifiedAt = new DateTime(2014, 1, 2, 10, 0, 0, DateTimeKind.Utc), }); var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning coffee", WorkspaceId = 1, UserId = 3, ModifiedAt = new DateTime(2014, 1, 2, 10, 1, 0, DateTimeKind.Utc).ToLocalTime(), // JSON deserialized to local }; timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.AreNotEqual(Guid.Empty, timeEntryData.Id); Assert.AreEqual(2, timeEntryData.RemoteId); Assert.AreEqual("Morning coffee", timeEntryData.Description); Assert.AreEqual(new DateTime(2014, 1, 2, 10, 1, 0, DateTimeKind.Utc), timeEntryData.ModifiedAt); Assert.AreEqual(workspaceData.Id, timeEntryData.WorkspaceId); Assert.AreEqual(userData.Id, timeEntryData.UserId); Assert.IsFalse(timeEntryData.IsDirty); Assert.IsFalse(timeEntryData.RemoteRejected); Assert.IsNull(timeEntryData.DeletedAt); }); // Warn the user that the test result might be invalid if (TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).TotalMinutes >= 0) { Assert.Inconclusive("The test machine timezone should be set to GTM-1 or less to test datetime comparison."); } }
public void ImportUpdatedTruncatedStartTime() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryData = await DataStore.PutAsync(new TimeEntryData() { RemoteId = 2, Description = "", WorkspaceId = workspaceData.Id, UserId = userData.Id, ModifiedAt = new DateTime(2014, 8, 5, 7, 32, 40, DateTimeKind.Utc), }); var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning coffee", WorkspaceId = 1, UserId = 3, StartTime = new DateTime(2014, 8, 5, 7, 32, 40, DateTimeKind.Utc).ToLocalTime(), Duration = -1407223960, ModifiedAt = new DateTime(2014, 8, 5, 9, 9, 33, DateTimeKind.Utc).ToLocalTime(), // JSON deserialized to local }; timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.AreNotEqual(Guid.Empty, timeEntryData.Id); Assert.AreEqual(2, timeEntryData.RemoteId); Assert.AreEqual("Morning coffee", timeEntryData.Description); Assert.AreEqual(new DateTime(2014, 8, 5, 7, 32, 40, DateTimeKind.Utc).Ticks, timeEntryData.StartTime.Ticks); Assert.AreEqual(new DateTime(2014, 8, 5, 9, 9, 33, DateTimeKind.Utc), timeEntryData.ModifiedAt); Assert.AreEqual(workspaceData.Id, timeEntryData.WorkspaceId); Assert.AreEqual(userData.Id, timeEntryData.UserId); Assert.IsFalse(timeEntryData.IsDirty); Assert.IsFalse(timeEntryData.RemoteRejected); Assert.IsNull(timeEntryData.DeletedAt); }); }
private static void ImportJson(IDataStoreContext ctx, TimeEntryData data, TimeEntryJson json) { var userId = GetUserLocalId(ctx, json.UserId); var workspaceId = GetLocalId <WorkspaceData> (ctx, json.WorkspaceId); var projectId = GetLocalId <ProjectData> (ctx, json.ProjectId); var taskId = GetLocalId <TaskData> (ctx, json.TaskId); data.Description = json.Description; data.IsBillable = json.IsBillable; data.DurationOnly = json.DurationOnly; data.UserId = userId; data.WorkspaceId = workspaceId; data.ProjectId = projectId; data.TaskId = taskId; DecodeDuration(data, json); ImportCommonJson(data, json); }
public void ImportUpdatedOverwriteRejectedLocal() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryData = await DataStore.PutAsync(new TimeEntryData() { RemoteId = 2, Description = "", WorkspaceId = workspaceData.Id, UserId = userData.Id, ModifiedAt = new DateTime(2014, 1, 2, 10, 1, 0, DateTimeKind.Utc), IsDirty = true, RemoteRejected = true, }); var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning coffee", WorkspaceId = 1, UserId = 3, ModifiedAt = new DateTime(2014, 1, 2, 10, 0, 0, DateTimeKind.Utc).ToLocalTime(), }; timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.AreEqual("Morning coffee", timeEntryData.Description); Assert.AreEqual(new DateTime(2014, 1, 2, 10, 0, 0, DateTimeKind.Utc), timeEntryData.ModifiedAt); }); }
public void ImportDefaultUser() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning coffee", WorkspaceId = 1, ModifiedAt = new DateTime(2014, 1, 3), }; await SetUpFakeUser(userData.Id); var timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.AreNotEqual(Guid.Empty, timeEntryData.Id); Assert.AreEqual(2, timeEntryData.RemoteId); Assert.AreEqual("Morning coffee", timeEntryData.Description); Assert.AreEqual(new DateTime(2014, 1, 3), timeEntryData.ModifiedAt); Assert.AreEqual(workspaceData.Id, timeEntryData.WorkspaceId); Assert.AreEqual(userData.Id, timeEntryData.UserId); Assert.IsFalse(timeEntryData.IsDirty); Assert.IsFalse(timeEntryData.RemoteRejected); Assert.IsNull(timeEntryData.DeletedAt); }); }
public void ImportPastDeleted() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryData = await DataStore.PutAsync(new TimeEntryData() { RemoteId = 2, Description = "Morning coffee", WorkspaceId = workspaceData.Id, UserId = userData.Id, ModifiedAt = new DateTime(2014, 1, 3), }); var timeEntryJson = new TimeEntryJson() { Id = 2, DeletedAt = new DateTime(2014, 1, 2), }; var ret = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); Assert.IsNull(ret); var rows = await DataStore.Table <TimeEntryData> ().QueryAsync(m => m.Id == timeEntryData.Id); Assert.That(rows, Has.Count.EqualTo(0)); }); }
private static void DecodeDuration (TimeEntryData data, TimeEntryJson json) { var now = Time.UtcNow.Truncate (TimeSpan.TicksPerSecond); // Decode duration: TimeSpan duration; if (json.Duration < 0) { data.State = TimeEntryState.Running; duration = now.ToUnix () + TimeSpan.FromSeconds (json.Duration); } else { data.State = TimeEntryState.Finished; duration = TimeSpan.FromSeconds (json.Duration); } // Set start and stop times based on the duration: if (data.State == TimeEntryState.Finished) { data.StartTime = json.StartTime.ToUtc (); data.StopTime = json.StartTime.ToUtc () + duration; } else { data.StartTime = now - duration; data.StopTime = null; } }
public TimeEntryData Import (IDataStoreContext ctx, TimeEntryJson json, Guid? localIdHint = null, TimeEntryData mergeBase = null) { var data = GetByRemoteId<TimeEntryData> (ctx, json.Id.Value, localIdHint); var merger = mergeBase != null ? new TimeEntryMerger (mergeBase) : null; if (merger != null && data != null) merger.Add (new TimeEntryData (data)); if (json.DeletedAt.HasValue) { if (data != null) { // TODO: Delete TimeEntryTag intermediate data ctx.Delete (data); data = null; } } else if (merger != null || ShouldOverwrite (data, json)) { data = data ?? new TimeEntryData (); ImportJson (ctx, data, json); if (merger != null) { merger.Add (data); data = merger.Result; } data = ctx.Put (data); // Also update tags from the JSON we are merging: if (mergeBase == null || (mergeBase != null && mergeBase.ModifiedAt != data.ModifiedAt)) { ResetTags (ctx, data, json); } } return data; }
private static void ResetTags (IDataStoreContext ctx, TimeEntryData timeEntryData, TimeEntryJson json) { // Don't touch the tags when the field is null if (json.Tags == null) { return; } var con = ctx.Connection; // Resolve tags to IDs: var tagIds = new List<Guid> (); foreach (var tagName in json.Tags) { // Prevent importing empty (invalid) tags: if (String.IsNullOrWhiteSpace (tagName)) { continue; } var id = ctx.GetTagIdFromName (timeEntryData.WorkspaceId, tagName); if (id == Guid.Empty) { // Need to create a new tag: var tagData = new TagData () { Name = tagName, WorkspaceId = timeEntryData.WorkspaceId, }; con.Insert (tagData); id = timeEntryData.Id; } tagIds.Add (id); } // Iterate over TimeEntryTags and determine which to keep and which to discard: var inters = con.Table<TimeEntryTagData> ().Where (m => m.TimeEntryId == timeEntryData.Id); var toDelete = new List<TimeEntryTagData> (); foreach (var inter in inters) { if (tagIds.Contains (inter.TagId)) { tagIds.Remove (inter.TagId); } else { toDelete.Add (inter); } } // Delete unused tags intermediate rows: foreach (var inter in toDelete) { ctx.Delete (inter); } // Create new intermediate rows: foreach (var tagId in tagIds) { ctx.Put (new TimeEntryTagData () { TagId = tagId, TimeEntryId = timeEntryData.Id, }); } }
private static void ResetTags(IDataStoreContext ctx, TimeEntryData timeEntryData, TimeEntryJson json) { // Don't touch the tags when the field is null if (json.Tags == null) { return; } var con = ctx.Connection; // Resolve tags to IDs: var tagIds = new List <Guid> (); foreach (var tagName in json.Tags) { // Prevent importing empty (invalid) tags: if (String.IsNullOrWhiteSpace(tagName)) { continue; } var id = ctx.GetTagIdFromName(timeEntryData.WorkspaceId, tagName); if (id == Guid.Empty) { // Need to create a new tag: var tagData = new TagData() { Name = tagName, WorkspaceId = timeEntryData.WorkspaceId, }; con.Insert(tagData); id = timeEntryData.Id; } tagIds.Add(id); } // Iterate over TimeEntryTags and determine which to keep and which to discard: var inters = con.Table <TimeEntryTagData> ().Where(m => m.TimeEntryId == timeEntryData.Id); var toDelete = new List <TimeEntryTagData> (); foreach (var inter in inters) { if (tagIds.Contains(inter.TagId)) { tagIds.Remove(inter.TagId); } else { toDelete.Add(inter); } } // Delete unused tags intermediate rows: foreach (var inter in toDelete) { ctx.Delete(inter); } // Create new intermediate rows: foreach (var tagId in tagIds) { ctx.Put(new TimeEntryTagData() { TagId = tagId, TimeEntryId = timeEntryData.Id, }); } }
public TimeEntryData Import (IDataStoreContext ctx, TimeEntryJson json, Guid? localIdHint = null, TimeEntryData mergeBase = null) { var log = ServiceContainer.Resolve<ILogger> (); var data = GetByRemoteId<TimeEntryData> (ctx, json.Id.Value, localIdHint); var merger = mergeBase != null ? new TimeEntryMerger (mergeBase) : null; if (merger != null && data != null) { merger.Add (new TimeEntryData (data)); } if (json.DeletedAt.HasValue) { if (data != null) { // TODO: Delete TimeEntryTag intermediate data log.Info (Tag, "Deleting local data for {0}.", data.ToIdString ()); ctx.Delete (data); data = null; } } else if (merger != null || ShouldOverwrite (data, json)) { data = data ?? new TimeEntryData (); ImportJson (ctx, data, json); if (merger != null) { merger.Add (data); data = merger.Result; } if (merger != null) { log.Info (Tag, "Importing {0}, merging with local data.", data.ToIdString ()); } else { log.Info (Tag, "Importing {0}, replacing local data.", data.ToIdString ()); } data = ctx.Put (data); // Also update tags from the JSON we are merging: if (mergeBase == null || (mergeBase != null && mergeBase.ModifiedAt != data.ModifiedAt)) { log.Info (Tag, "Resetting tags for {0}.", data.ToIdString ()); ResetTags (ctx, data, json); } } else { log.Info (Tag, "Skipping import of {0}.", json.ToIdString ()); } return data; }
public Task DeleteTimeEntry(TimeEntryJson jsonObject) { var url = new Uri(v8Url, String.Format("time_entries/{0}", jsonObject.Id.Value.ToString())); return(DeleteObject(url)); }
private static void ImportJson (IDataStoreContext ctx, TimeEntryData data, TimeEntryJson json) { var userId = GetUserLocalId (ctx, json.UserId); var workspaceId = GetLocalId<WorkspaceData> (ctx, json.WorkspaceId); var projectId = GetLocalId<ProjectData> (ctx, json.ProjectId); var taskId = GetLocalId<TaskData> (ctx, json.TaskId); data.Description = json.Description; data.IsBillable = json.IsBillable; data.DurationOnly = json.DurationOnly; data.UserId = userId; data.WorkspaceId = workspaceId; data.ProjectId = projectId; data.TaskId = taskId; DecodeDuration (data, json); ImportCommonJson (data, json); }
public void ImportNewTags() { RunAsync(async delegate { var workspaceData = await DataStore.PutAsync(new WorkspaceData() { RemoteId = 1, Name = "Test", ModifiedAt = new DateTime(2014, 1, 2), }); var userData = await DataStore.PutAsync(new UserData() { RemoteId = 3, Name = "John", DefaultWorkspaceId = workspaceData.Id, ModifiedAt = new DateTime(2014, 1, 2), }); var timeEntryData = await DataStore.PutAsync(new TimeEntryData() { RemoteId = 2, Description = "Morning coffee", WorkspaceId = workspaceData.Id, UserId = userData.Id, ModifiedAt = new DateTime(2014, 1, 3), }); var tag1Data = await DataStore.PutAsync(new TagData() { Name = "mobile", WorkspaceId = workspaceData.Id, }); var tag2Data = await DataStore.PutAsync(new TagData() { Name = "on-site", WorkspaceId = workspaceData.Id, }); var tag3Data = await DataStore.PutAsync(new TagData() { Name = "off-site", WorkspaceId = workspaceData.Id, }); await DataStore.PutAsync(new TimeEntryTagData() { TimeEntryId = timeEntryData.Id, TagId = tag1Data.Id, }); await DataStore.PutAsync(new TimeEntryTagData() { TimeEntryId = timeEntryData.Id, TagId = tag2Data.Id, }); var timeEntryJson = new TimeEntryJson() { Id = 2, Description = "Morning tea", WorkspaceId = 1, UserId = 3, Tags = new List <string> () { "mobile", "off-site" }, ModifiedAt = new DateTime(2014, 1, 4), }; timeEntryData = await DataStore.ExecuteInTransactionAsync(ctx => converter.Import(ctx, timeEntryJson)); var timeEntryTagRows = await DataStore.Table <TimeEntryTagData> ().QueryAsync(m => m.TimeEntryId == timeEntryData.Id); var tags = timeEntryTagRows.Select(r => r.TagId).ToList(); Assert.That(tags, Has.Count.EqualTo(2)); Assert.That(tags, Has.Exactly(1).Matches <Guid> (id => id == tag1Data.Id)); Assert.That(tags, Has.Exactly(1).Matches <Guid> (id => id == tag3Data.Id)); }); }