static async Task SetAttributes(Exist.Query exist, DateTime day, Dictionary <string, int> counts, Dictionary <string, TimeSpan> durations, HashSet <string> tags) { Console.WriteLine($"{day.ToString("yyyy-MM-dd")} {String.Join(" ", counts.Select(kvp => $"{kvp.Key}={kvp.Value}"))} {String.Join(" ", durations.Select(kvp => $"{kvp.Key}={kvp.Value.ToString(@"hh\:mm")}"))} {String.Join(" ", tags.Select(tag => $"tag=\"{tag}\""))}"); var attributes = new Dictionary <string, int>( counts.Concat( durations.Select(kvp => new KeyValuePair <string, int>(kvp.Key, (int)kvp.Value.TotalMinutes)) ) ); await exist.SetAttributes(day, attributes); await exist.AddTags(day, tags); }
static async Task Main(IConfigurationRoot config, JObject configJson, bool verbose, int offset, int range) { var togglConfig = config.GetSection("Toggl"); var toggl = new Toggl.Query(togglConfig["ApiToken"], togglConfig.GetSection("Workspaces").GetChildren().Select(s => s.Value).ToList()); var existConfig = config.GetSection("Exist"); var exist = new Exist.Query(existConfig["AccessToken"]); var tzOffset = configJson["TimeZoneOffset"].Value <int>(); var rules = configJson["Rules"].Select(rule => new Rule(rule)); var maxDay = DateTimeOffset.Now.Date.AddDays(1 - offset); var minDay = DateTimeOffset.Now.Date.AddDays(1 - offset - range); Console.WriteLine($"Querying days {offset} --> {offset + range - 1} ({minDay.ToString("yyyy-MM-dd")} --> {maxDay.ToString("yyyy-MM-dd")})"); var existTags = await exist.GetTags(); var togglQuery = new Dictionary <string, string>(); togglQuery["since"] = minDay.ToString("yyyy-MM-dd"); togglQuery["until"] = maxDay.ToString("yyyy-MM-dd"); var timeEntries = await toggl.GetDetails(existTags, togglQuery); Console.WriteLine($"Got entries {timeEntries.Last().start} --> {timeEntries.First().end}"); var counts = new Dictionary <string, int>(); var durations = new Dictionary <string, TimeSpan>(); var tags = new HashSet <string>(); ResetAttributes(rules, counts, durations, tags); await exist.AcquireAttributes(counts.Keys); var lastDay = DateTime.MinValue; foreach (var timeEntry in timeEntries) { var day = timeEntry.start.AddMinutes(tzOffset).Date; if (day < minDay || day >= maxDay) { continue; } if (lastDay == DateTime.MinValue) { lastDay = day; } if (lastDay != day) { await SetAttributes(exist, lastDay, counts, durations, tags); ResetAttributes(rules, counts, durations, tags); } foreach (var rule in rules) { if (rule.IsMatch(JObject.FromObject(timeEntry))) { if (rule.Pattern["$set"]["tags"] != null) { foreach (var tag in rule.Pattern["$set"]["tags"].ToObject <string[]>()) { tags.Add(tag); } } if (rule.Pattern["$set"]["matchingTags"] != null && rule.Pattern["$set"]["matchingTags"].ToObject <bool>() == true) { foreach (var tag in timeEntry.tags) { if (existTags.Contains(tag, StringComparer.CurrentCultureIgnoreCase)) { tags.Add(tag); } } } if (rule.Pattern["$set"]["count_attribute"] != null) { counts[rule.Pattern["$set"]["count_attribute"].ToObject <string>()]++; } if (rule.Pattern["$set"]["duration_attribute"] != null) { durations[rule.Pattern["$set"]["duration_attribute"].ToObject <string>()] += timeEntry.duration; } } } if (verbose) { if (lastDay != day) { Console.WriteLine("------------------------------"); } Console.WriteLine($"{day.ToString("yyyy-MM-dd")} {timeEntry.start.TimeOfDay.ToString(@"hh\:mm")}-{timeEntry.end.TimeOfDay.ToString(@"hh\:mm")} ({(timeEntry.end - timeEntry.start).ToString(@"hh\:mm")}) {timeEntry.project}/{timeEntry.description} [{String.Join(", ", timeEntry.tags)}]"); } lastDay = day; } await SetAttributes(exist, lastDay, counts, durations, tags); }