-make google api user friendly

This commit is contained in:
2026-04-28 13:41:22 +02:00
parent 6b1162ebfc
commit 69f8565a61
5 changed files with 124 additions and 44 deletions
@@ -7,7 +7,7 @@ namespace LeanderShiftPlannerV2.FileIO;
public static class GoogleApiLoader public static class GoogleApiLoader
{ {
public static bool CheckFileSystem() public static bool CheckFileSystem_ReadFile()
{ {
if (!Directory.Exists(Constants.DataPath)) if (!Directory.Exists(Constants.DataPath))
Directory.CreateDirectory(Constants.DataPath); Directory.CreateDirectory(Constants.DataPath);
@@ -20,10 +20,22 @@ public static class GoogleApiLoader
} }
return true; return true;
} }
public static bool CheckFileSystem_ReadToken()
{
if (!Directory.Exists(Constants.DataPath))
Directory.CreateDirectory(Constants.DataPath);
if (!File.Exists(Constants.DataPath + Constants.GoogleApiTokenPath))
{
File.Create(Constants.DataPath + Constants.GoogleApiTokenPath);
return false;
}
return true;
}
public static Dictionary<string, string> ReadFile() public static Dictionary<string, string> ReadFile()
{ {
if (!CheckFileSystem()) return new Dictionary<string, string>(); if (!CheckFileSystem_ReadFile()) return new Dictionary<string, string>();
Dictionary<string, string> apiSecrets = new Dictionary<string, string>(); Dictionary<string, string> apiSecrets = new Dictionary<string, string>();
try try
@@ -51,4 +63,30 @@ public static class GoogleApiLoader
return apiSecrets; return apiSecrets;
} }
public static void WriteToken(string token)
{
if (File.Exists(Constants.DataPath + Constants.GoogleApiTokenPath))
File.Delete(Constants.DataPath + Constants.GoogleApiTokenPath);
File.Create(Constants.DataPath + Constants.GoogleApiTokenPath).Close();
File.WriteAllText(Constants.DataPath + Constants.GoogleApiTokenPath, token);
}
public static string? ReadToken()
{
if (!CheckFileSystem_ReadToken()) return null;
string tokenString = null;
try
{
tokenString = File.ReadAllText(Constants.DataPath + Constants.GoogleApiTokenPath);
}
catch (Exception ex)
{
//TODO
Console.WriteLine($"Fehler beim Lesen der Datei: {ex.Message}");
}
return (tokenString.Equals(String.Empty) ? null : tokenString);
}
} }
@@ -8,10 +8,10 @@
<ApplicationIcon>Resources/icon/ShiftPlannerIcon.ico</ApplicationIcon> <ApplicationIcon>Resources/icon/ShiftPlannerIcon.ico</ApplicationIcon>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault> <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<PackageIcon>Resources\icon\ShiftPlannerIcon.png</PackageIcon> <PackageIcon>Resources\icon\ShiftPlannerIcon.png</PackageIcon>
<AssemblyVersion>1.0.5</AssemblyVersion> <AssemblyVersion>2.0.2</AssemblyVersion>
<FileVersion>1.0.5</FileVersion> <FileVersion>2.0.2</FileVersion>
<NeutralLanguage>en</NeutralLanguage> <NeutralLanguage>en</NeutralLanguage>
<Version>1.0.5</Version> <Version>2.0.2</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -10,6 +10,8 @@ using System.Threading.Tasks;
using LeanderShiftPlannerV2.Model; using LeanderShiftPlannerV2.Model;
using LeanderShiftPlannerV2.Util; using LeanderShiftPlannerV2.Util;
using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Calendar.v3; using Google.Apis.Calendar.v3;
using Google.Apis.Services; using Google.Apis.Services;
using LeanderShiftPlannerV2.FileIO; using LeanderShiftPlannerV2.FileIO;
@@ -30,51 +32,81 @@ public class TimesheetService
public async Task GenerateGoogleTimeSheets(List<Person> persons, bool randomize) public async Task GenerateGoogleTimeSheets(List<Person> persons, bool randomize)
{ {
string[] scopes = { CalendarService.Scope.CalendarReadonly };
const string applicationName = "LeanderShiftPlanner"; const string applicationName = "LeanderShiftPlanner";
Dictionary<string, string> secrets = GoogleApiLoader.ReadFile(); Dictionary<string, string> secrets = GoogleApiLoader.ReadFile();
if (!secrets.ContainsKey(Constants.GoogleClientId) || !secrets.ContainsKey(Constants.GoogleClientSecret)) if (!secrets.ContainsKey(Constants.GoogleClientId) || !secrets.ContainsKey(Constants.GoogleClientSecret))
return; return;
if (secrets[Constants.GoogleClientId].Equals(string.Empty) || secrets[Constants.GoogleClientSecret].Equals(string.Empty)) if (secrets[Constants.GoogleClientId].Equals(string.Empty) ||
secrets[Constants.GoogleClientSecret].Equals(string.Empty))
return; return;
UserCredential credential;
string[] scopes = { CalendarService.Scope.CalendarReadonly };
ClientSecrets clientSecrets = new ClientSecrets(); ClientSecrets clientSecrets = new ClientSecrets();
clientSecrets.ClientId = secrets[Constants.GoogleClientId]; clientSecrets.ClientId = secrets[Constants.GoogleClientId];
clientSecrets.ClientSecret = secrets[Constants.GoogleClientSecret]; clientSecrets.ClientSecret = secrets[Constants.GoogleClientSecret];
//clientSecrets.ClientId = "823920428427-ub5n9a9dkfpuvjlut4eneg2058so49o3.apps.googleusercontent.com"; string? tokenString = GoogleApiLoader.ReadToken();
//clientSecrets.ClientSecret = "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";
UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, "user", CancellationToken.None);
try
{
TokenResponse token = new TokenResponse { RefreshToken = tokenString };
credential = new UserCredential(
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = clientSecrets
}),
"user",
token
);
if (!await credential.RefreshTokenAsync(CancellationToken.None))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, "user",
CancellationToken.None);
GoogleApiLoader.WriteToken(credential.Token.RefreshToken);
}
}
catch (Exception e)
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, "user",
CancellationToken.None);
GoogleApiLoader.WriteToken(credential.Token.RefreshToken);
}
// Erstelle den CalendarService // Erstelle den CalendarService
var service = new CalendarService(new BaseClientService.Initializer() CalendarService service = new CalendarService(new BaseClientService.Initializer()
{ {
HttpClientInitializer = credential, HttpClientInitializer = credential,
ApplicationName = applicationName, ApplicationName = applicationName,
}); });
foreach (Person person in persons) foreach (Person person in persons)
{ {
foreach (string month in Constants.Months) foreach (string month in Constants.Months)
{ {
if (month == Constants.Months[0]) continue; if (month == Constants.Months[0]) continue;
List<(DateTime, DateTime, bool)> timesheetValue = new List<(DateTime, DateTime, bool)>(); List<(DateTime, DateTime, bool)> timesheetValue = new List<(DateTime, DateTime, bool)>();
// Aktuelles Datum // Aktuelles Datum
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
// Erster Tag des aktuellen Monats (00:00:00 Uhr) // Erster Tag des aktuellen Monats (00:00:00 Uhr)
DateTime firstDayOfMonth = new DateTime(now.Year, Constants.Months.IndexOf(month), 1, 0, 0, 0); DateTime firstDayOfMonth = new DateTime(now.Year, Constants.Months.IndexOf(month), 1, 0, 0, 0);
// Letzter Tag des aktuellen Monats (23:59:59 Uhr) // Letzter Tag des aktuellen Monats (23:59:59 Uhr)
DateTime lastDayOfMonth = new DateTime(now.Year, Constants.Months.IndexOf(month), DateTime.DaysInMonth(now.Year, Constants.Months.IndexOf(month)), DateTime lastDayOfMonth = new DateTime(now.Year, Constants.Months.IndexOf(month),
DateTime.DaysInMonth(now.Year, Constants.Months.IndexOf(month)),
23, 59, 59); 23, 59, 59);
// Beispiel: Liste die nächsten 10 Ereignisse im ITM Kalender auf // Beispiel: Liste die nächsten 10 Ereignisse im ITM Kalender auf
var requestItm = service.Events.List("on089es7kq4ugi3rqvslkn7720@group.calendar.google.com"); var requestItm = service.Events.List("on089es7kq4ugi3rqvslkn7720@group.calendar.google.com");
requestItm.TimeMinDateTimeOffset = firstDayOfMonth; requestItm.TimeMinDateTimeOffset = firstDayOfMonth;
requestItm.TimeMaxDateTimeOffset = lastDayOfMonth; requestItm.TimeMaxDateTimeOffset = lastDayOfMonth;
requestItm.SingleEvents = true; requestItm.SingleEvents = true;
var requestWebService = service.Events.List("s4rdo3uk2on8ualv1goaktbiec@group.calendar.google.com"); var requestWebService = service.Events.List("s4rdo3uk2on8ualv1goaktbiec@group.calendar.google.com");
requestWebService.TimeMinDateTimeOffset = firstDayOfMonth; requestWebService.TimeMinDateTimeOffset = firstDayOfMonth;
requestWebService.TimeMaxDateTimeOffset = lastDayOfMonth; requestWebService.TimeMaxDateTimeOffset = lastDayOfMonth;
@@ -82,14 +114,14 @@ public class TimesheetService
var eventsItm = await requestItm.ExecuteAsync(); var eventsItm = await requestItm.ExecuteAsync();
var eventsWebService = await requestWebService.ExecuteAsync(); var eventsWebService = await requestWebService.ExecuteAsync();
foreach (var eventItem in eventsItm.Items) foreach (var eventItem in eventsItm.Items)
{ {
if (eventItem.Start.DateTime == null || eventItem.End.DateTime == null) continue; if (eventItem.Start.DateTime == null || eventItem.End.DateTime == null) continue;
if (eventItem.Summary.Contains(person.FirstName)) if (eventItem.Summary.Contains(person.FirstName))
{ {
DateTime dayStart = (DateTime) eventItem.Start.DateTime; DateTime dayStart = (DateTime)eventItem.Start.DateTime;
DateTime dayEnd = (DateTime) eventItem.End.DateTime; DateTime dayEnd = (DateTime)eventItem.End.DateTime;
timesheetValue.Add((dayStart, dayEnd, (dayEnd.Hour > 13))); timesheetValue.Add((dayStart, dayEnd, (dayEnd.Hour > 13)));
} }
} }
@@ -99,12 +131,12 @@ public class TimesheetService
if (eventItem.Start.DateTime == null || eventItem.End.DateTime == null) continue; if (eventItem.Start.DateTime == null || eventItem.End.DateTime == null) continue;
if (eventItem.Summary.Contains(person.FirstName)) if (eventItem.Summary.Contains(person.FirstName))
{ {
DateTime dayStart = (DateTime) eventItem.Start.DateTime; DateTime dayStart = (DateTime)eventItem.Start.DateTime;
DateTime dayEnd = (DateTime) eventItem.End.DateTime; DateTime dayEnd = (DateTime)eventItem.End.DateTime;
timesheetValue.Add((dayStart, dayEnd, false)); timesheetValue.Add((dayStart, dayEnd, false));
} }
} }
person.Timesheets.Add(new Timesheet(month, timesheetValue)); person.Timesheets.Add(new Timesheet(month, timesheetValue));
} }
@@ -124,17 +156,18 @@ public class TimesheetService
if (pattern.Count == 0) continue; if (pattern.Count == 0) continue;
List<DateTime> holidays = await GetHolidays(); List<DateTime> holidays = await GetHolidays();
List<DateTime> weekends = GetWeekends(); List<DateTime> weekends = GetWeekends();
int monthHours = person.Hours * 4; int monthHours = person.Hours * 4;
foreach (string month in Constants.Months) foreach (string month in Constants.Months)
{ {
if (month == Constants.Months[0]) continue; if (month == Constants.Months[0]) continue;
List<(DateTime, DateTime, bool)> timesheetValue = new List<(DateTime, DateTime, bool)>(); List<(DateTime, DateTime, bool)> timesheetValue = new List<(DateTime, DateTime, bool)>();
int currentPersonHours = 0; int currentPersonHours = 0;
int currentPatternIndex = 0; int currentPatternIndex = 0;
int dayOfMonth = 1; int dayOfMonth = 1;
int lastDayOfMonth = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth).AddMonths(1).AddDays(-1).Day; int lastDayOfMonth = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth)
.AddMonths(1).AddDays(-1).Day;
while (currentPersonHours != monthHours) while (currentPersonHours != monthHours)
{ {
DateTime currentDay = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth); DateTime currentDay = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth);
@@ -148,7 +181,8 @@ public class TimesheetService
{ {
case 6: case 6:
{ {
DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0, 0); DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0,
0);
DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 16, 0, 0); DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 16, 0, 0);
timesheetValue.Add((dayStart, dayEnd, true)); timesheetValue.Add((dayStart, dayEnd, true));
currentPersonHours += 6; currentPersonHours += 6;
@@ -156,7 +190,8 @@ public class TimesheetService
} }
case 4: case 4:
{ {
DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0, 0); DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0,
0);
DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 13, 0, 0); DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 13, 0, 0);
timesheetValue.Add((dayStart, dayEnd, false)); timesheetValue.Add((dayStart, dayEnd, false));
currentPersonHours += 4; currentPersonHours += 4;
@@ -164,7 +199,8 @@ public class TimesheetService
} }
case 2: case 2:
{ {
DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 14, 0, 0); DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 14, 0,
0);
DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 16, 0, 0); DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 16, 0, 0);
timesheetValue.Add((dayStart, dayEnd, false)); timesheetValue.Add((dayStart, dayEnd, false));
currentPersonHours += 2; currentPersonHours += 2;
@@ -172,14 +208,15 @@ public class TimesheetService
} }
case 1: case 1:
{ {
DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0, 0); DateTime dayStart = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 9, 0,
0);
DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 10, 0, 0); DateTime dayEnd = new DateTime(currentDay.Year, currentDay.Month, currentDay.Day, 10, 0, 0);
timesheetValue.Add((dayStart, dayEnd, false)); timesheetValue.Add((dayStart, dayEnd, false));
currentPersonHours += 1; currentPersonHours += 1;
break; break;
} }
} }
dayOfMonth++; dayOfMonth++;
if (dayOfMonth > lastDayOfMonth) throw new Exception("Too many hours!"); if (dayOfMonth > lastDayOfMonth) throw new Exception("Too many hours!");
currentPatternIndex = (currentPatternIndex + 1) % pattern.Count; currentPatternIndex = (currentPatternIndex + 1) % pattern.Count;
@@ -202,7 +239,8 @@ public class TimesheetService
for (int i = 0; i <= daysInYear; i++) for (int i = 0; i <= daysInYear; i++)
{ {
DateTime currentDay = firstDayOfYear.AddDays(i); DateTime currentDay = firstDayOfYear.AddDays(i);
if (currentDay.DayOfWeek == DayOfWeek.Saturday || currentDay.DayOfWeek == DayOfWeek.Sunday) weekends.Add(currentDay); if (currentDay.DayOfWeek == DayOfWeek.Saturday || currentDay.DayOfWeek == DayOfWeek.Sunday)
weekends.Add(currentDay);
} }
return weekends; return weekends;
@@ -295,7 +333,7 @@ public class TimesheetService
private int CalcHours(Timesheet timesheet) private int CalcHours(Timesheet timesheet)
{ {
double hours = 0; double hours = 0;
foreach ((DateTime, DateTime, bool) tuple in timesheet.Value) foreach ((DateTime, DateTime, bool) tuple in timesheet.Value)
{ {
if (tuple.Item3) if (tuple.Item3)
@@ -307,32 +345,34 @@ public class TimesheetService
hours += (tuple.Item2 - tuple.Item1).TotalHours; hours += (tuple.Item2 - tuple.Item1).TotalHours;
} }
} }
return (int) hours; return (int)hours;
} }
private async Task CheckForNotEnoughHours(Person person) private async Task CheckForNotEnoughHours(Person person)
{ {
List<DateTime> holidays = await GetHolidays(); List<DateTime> holidays = await GetHolidays();
List<DateTime> weekends = GetWeekends(); List<DateTime> weekends = GetWeekends();
int monthHours = person.Hours * 4; int monthHours = person.Hours * 4;
foreach (string month in Constants.Months) foreach (string month in Constants.Months)
{ {
if (month == Constants.Months[0]) continue; if (month == Constants.Months[0]) continue;
Timesheet timesheet = person.GetTimeSheetByMonth(month); Timesheet timesheet = person.GetTimeSheetByMonth(month);
List<(DateTime, DateTime, bool)> timesheetValue = timesheet.Value; List<(DateTime, DateTime, bool)> timesheetValue = timesheet.Value;
int currentPersonHours = CalcHours(timesheet); int currentPersonHours = CalcHours(timesheet);
List<int> pattern = GetPattern((person.Hours * 4) - currentPersonHours); List<int> pattern = GetPattern((person.Hours * 4) - currentPersonHours);
int currentPatternIndex = 0; int currentPatternIndex = 0;
int dayOfMonth = 1; int dayOfMonth = 1;
int lastDayOfMonth = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth).AddMonths(1).AddDays(-1).Day; int lastDayOfMonth = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth)
.AddMonths(1).AddDays(-1).Day;
while (currentPersonHours != monthHours) while (currentPersonHours != monthHours)
{ {
DateTime currentDay = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth); DateTime currentDay = new DateTime(DateTime.Now.Year, Constants.Months.IndexOf(month), dayOfMonth);
if (holidays.Contains(currentDay) || weekends.Contains(currentDay) || CheckForDayIsNotEmpty(currentDay, timesheetValue)) if (holidays.Contains(currentDay) || weekends.Contains(currentDay) ||
CheckForDayIsNotEmpty(currentDay, timesheetValue))
{ {
dayOfMonth++; dayOfMonth++;
continue; continue;
@@ -373,7 +413,7 @@ public class TimesheetService
break; break;
} }
} }
dayOfMonth++; dayOfMonth++;
if (dayOfMonth > lastDayOfMonth) throw new Exception($"Too many hours for Person {person.FirstName}!"); if (dayOfMonth > lastDayOfMonth) throw new Exception($"Too many hours for Person {person.FirstName}!");
currentPatternIndex = (currentPatternIndex + 1) % pattern.Count; currentPatternIndex = (currentPatternIndex + 1) % pattern.Count;
@@ -387,7 +427,7 @@ public class TimesheetService
{ {
if (tuple.Item1.Date.Day == currentDay.Day) return true; if (tuple.Item1.Date.Day == currentDay.Day) return true;
} }
return false; return false;
} }
} }
+1
View File
@@ -21,6 +21,7 @@ namespace LeanderShiftPlannerV2.Util
public const string GoogleClientId = "GoogleClientId"; public const string GoogleClientId = "GoogleClientId";
public const string GoogleClientSecret = "GoogleClientSecret"; public const string GoogleClientSecret = "GoogleClientSecret";
public const string GoogleApiFileResource = @"Resources/templates/googleapi.txt"; public const string GoogleApiFileResource = @"Resources/templates/googleapi.txt";
public const string GoogleApiTokenPath = @"/googleapitoken.txt";
// TimeSheets // TimeSheets
public static readonly string TimeSheetSourceRandom = "Random"; public static readonly string TimeSheetSourceRandom = "Random";
@@ -47,7 +47,8 @@ public partial class LeanderShiftPlannerMainWindow : Window
private void CreateApiFile() private void CreateApiFile()
{ {
GoogleApiLoader.CheckFileSystem(); GoogleApiLoader.CheckFileSystem_ReadFile();
GoogleApiLoader.CheckFileSystem_ReadToken();
} }
// ------------------------------------------------------UI-Interactions------------------------------------------------------ // ------------------------------------------------------UI-Interactions------------------------------------------------------