Google Kalender
Im Fach "Projekt" beim Prof. Dr. rer. nat. Hans-Christian Rodrian haben wir für eine Firma ein Konzept für Synchronisation einer Datenbank bzw. MS Outlook mit Google Kalender entwiekelt. In diesem Projekt war ich für Arbeit mit dem Kalender zuständig. Im folgendem ist Information zu finden, die für Arbeit mit Google kalender benötig ist.
Der Projekt wurde in C# für Platform .NET geschrieben, alle folgende Quelltextbeispile sind in C#.
Weboberflache.
Die Felde des Kalenders(Weboberfläche):
API.
Jeder Termin im Calender wird durch Instanz der Klasse EventEntry representiert.
Folgende Tabelle zeigt Zusammengang zwischen der Klasse und Oberfläche des Kalenders:
Feld: | Bedeutung: |
---|---|
Title.Text | Entspricht dem Feld “Was” im Termin |
Times[0].StartTime | Der Anfang des Termins |
Times[0].EndTime | Das Ende des Termins |
Content.Content | Entspricht dem Feld „Beschreibung“ im Termin |
Locations[0].ValueString | Entspricht dem Feld „Wo“ im Termin |
Times[0].AllDay | Ganztägig |
Außerdem sind folgende Felder der Klasse von Bedeutung:
Feld: | Bedeutung: |
---|---|
Published | Die Zeit der Erstellung des Termins |
Updated | Die Zeit der letzten Änderung des Termins |
EventId | Eindeutiger ID des Termins im Kalender |
Datenbank.
Um eine Synchronisation durchzufuhren braucht man entfernte, neue und geänderte Termine zu ermitteln. Dafür ist ein altes Zustand (eine Kopie) des Kalenders nötig. Diese Kopie speichern wir in einer Datenbank. Die Tabelle, wo die Kopie gespeichert wird, kann z.B. so aussehen:
Tabelle "GOOGLEKOPIE":
Column Name | Data Type | Nullable | Primary Key |
---|---|---|---|
TERMINIDINDB | VARCHAR | No | Yes |
TERMINIDINGOOGLE | VARCHAR | No | No |
BESCHREIBUNG | VARCHAR | Yes | No |
ANFANGDATUM | DATE | Yes | No |
ENDEDATUM | DATE | Yes | No |
TITL | VARCHAR | Yes | No |
Die Felder der Tabelle:
TERMINIDINDB: besteht aus Datum der Erzeugung des Termins und ID des Termins:
terminIdInDB = termin.Published + " " + termin.EventId;
MANDANTID: ID eines Klients in Datenbank, der Besitzer des Kalenders ist.
TERMINIDINGOOGLE: ID eines Termins im Kalender: termin.EventId.
BESCHREIBUNG: Entspricht dem Feld „Beschreibung“ im Termin: termin.Content.Content.
ANFANGDATUM: Der Anfang des Termins: Times[0].StartTime.
ENDEDATUM: Das Ende des Termins: termin.Times[0].EndTime
TITLE: Entspricht dem Feld “Was” im Termin: termin.Title.Text
Um geänderte Termine zu finden, braucht man noch die Zeit der letzten Synchronisation. Dafür ist eine Tabelle mit einem einziegem Feld vorgesehen.
Tabelle "SYNCINFOTABLE":
Column Name | Data Type | Nullable | Primary Key |
---|---|---|---|
LASTSYNC | DATE | No | Yes |
Besonderheit.
Um Kopie eines Kalenders mit Kalender zu vergleichen, braucht man die Daten aus Datenbank in ein Objekt umzuwandeln, der mit einem Objekt der Klasse "EventEntry" verglichen werden kann. Die einfachste Lösung wäre eine neue Instanz der Klasse "EventEntry" zu machen und entsprechende Felder zu initialisieren, z.B. mit Hilfe der Methode:
- public EventEntry erzeugeTermin(String title, DateTime anfang, DateTime ende)
- {
-
- EventEntry res = new EventEntry (title);
- When eventTime = new When();
- eventTime.StartTime = anfang;
- eventTime.EndTime = ende;
- res.Times.Add(eventTime);
- return res;
-
Das Problem ist, dass der Feld "EventId" read-only ist und dementsprechend "per Hand" nicht initialisirt werden kann. Deswegen braucht man eine Klasse, die die Klasse "EventEntry" erweitert und den Feld "EventId" irgendwie ersetzt , z.B. die Klasse "EventEntryInner":
- class EventEntryInner:EventEntry
- {
- private new String EventId;
-
- public String GetEventId()
- {
- return EventId;
- }
-
- public void SetEventId(string value)
- {
- this.EventId = value;
- }
-
- }
Arbeit mit Kalender.
Um Zugang zum Google Calender zu bekommen, braucht man eine Instanz von der Klasse CalendarService, die z.B. so zu erhalten ist:
CalendarService service = new CalendarService("GoogleCalender");
Der Objekt "servise" erstellt Verknupfung mit einem Calender dürch:
service.setUserCredentials(userName, password);
wo "username" und "password" die Zugangdaten sind, die Benutzer beim Erstellen des Calenders angibt.
Der Objekt "service" stellt zur Verfugung folgende wichtige Methoden:
Get(Uri uri) und insert(Uri uri,EventEntry event).
Methode Get(Uri uri) gibt zurück Link auf Objekt der Klasse EventEntry, der unter Uri "uri" im Kalender gespeichert ist.
Methode insert(Uri uri,EventEntry event) fugt in Kalender einen Termin mit Eigenschaften des Objekts "event"
Falls aber eine Menge von Terminen eingetragen soll, bring die Methode "insert" kein gutes Ergebniss, da es zu grosser Verzögerung kommt. Als eine Alternative kann man folgende Methode benutzen:
- public List<EventEntry> setTermine(List<EventEntry> terminListe)
- {
- List<EventEntry> resultat = new List<EventEntry>();
-
- var feedUri = "https://www.google.com/calendar/feeds/default/private/full";
- EventQuery query = new EventQuery(feedUri);
- query.ExtraParameters = "orderby=starttime&max-results=100000";// maksimale anzahl von terminen, die bearbeiten werden
- EventFeed feed = service.Query(query);
- AtomFeed batchFeed = new AtomFeed(feed);
-
- foreach (var termin in terminListe)
- {
- batchFeed.Entries.Add(termin);
- }
- EventFeed batchResultFeed = (EventFeed)service.Batch(batchFeed, new Uri(feed.Batch));
- foreach (EventEntry entry in batchResultFeed.Entries)
- {
- if (entry.BatchData.Status.Code != 200 && entry.BatchData.Status.Code != 201)// wird geprüft, ob alles ok ist
- {
- return null;// falls nicht, null ubergeben
- }
- resultat.Add(entry);
- }
- return resultat;
- }
Die Liste "terminListe" in dieser Methode enthält Objekte, mit deren eine Action in Kalender dürchgefurt werden soll. Welche genau bestimmt der Feld "BatchData". Z.B:
termin.BatchData = new GDataBatchEntryData("A", GDataBatchOperationType.update)
Die Methode "setTermine" liefert eine Liste mit geänderten Terminen.
Einen Termin löschen:
Angenommen will man einen Termin aus Kalender löschen. Die ID des Termins in Kalender ist bekannt(in Datenbank ist die unter "TERMINIDINGOOGLE" gespeichert): "TERMINIDINGOOGLE"="12345"
- uri = new Uri("https://www.google.com/calendar/feeds/default/private/full/" + 12345);
- termin=service.Get(uri.ToString()) as EventEntry;
- termin.Delete()
Termine aus Kalender holen:
- public EventFeed GetTermine(DateTime von, DateTime bis)
- {
- EventQuery myQuery = new EventQuery("https://www.google.com/calendar/feeds/default/private/full");
- myQuery.ExtraParameters = "orderby=starttime&max-results=100000";
- myQuery.StartTime = von;
- myQuery.EndTime = bis;
- EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;
- return myResultsFeed;
- }
Die Zeile:
myQuery.ExtraParameters = "orderby=starttime&max-results=100000";
ist sehr wichtig. Wenn man die Zeile weglässt, bekommt man nur die erste 25 Termine. Die Zeile setzt die Anzahl den geliferten Terminen auf 100000.
Erfindung entferneten,neuen und geänderten Terminen.
Neue Termine.
Termine, die im Kalender zu finden sind und in der Tabelle "GOOGLEKOPIE" dagegen nicht, gelten als neue Termine.
Beispiel: in der Tabelle "GOOGLEKOPIE" sind Termine "A" und "B" gespeichert. Kalender hat im Moment Termine "A","B" und "C". Der Termin "C" befindet sich im Kalender aber nicht in der Tabelle "GOOGLEKOPIE", d.h. zur Zeit der letzten Synchronisation hat der Termin noch nicht existiert. Der Termin gilt als ein neuer. Als Bezeichner von Terminen, der für Vergleich verwendet wird(im Beispiel sind das "A","B" und "C") benutz man den Feld "TERMINIDINGOOGLE" aus Tabelle "GOOGLEKOPIE" und den Feld "EventId" eines Termins aus Kalender.
Entfernte Termine.
Für entfernte Termine ist die gleiche Vorgehensweise gültig wie für neue Termine mit dem Unterschied, dass ein entfernter Termin in Datenbank zu finden ist, aber nicht im Kalender.
Geänderte Termine.
Als geänderte Termine gelten die Termine, deren Datum im Feld "Updated" später ist als Datum im Feld "LASTSYNC" in Tabelle "SYNCINFOTABLE".
Beispiel: letzte Synchronisation wurde am 01.01.2010 um 01:00 Uhr durchgeführt, d.h. der Feld "LASTSYNC" in Tabelle "SYNCINFOTABLE" enthält : "01.01.2010 01:00:00". Ein Termin im Kalender wurde am 01.01.2010 um 01:15 Uhr geändert, d.h. sein Feld "Updated" enthält: "01.01.2010 01:15:00". Der Termin gilt als geäderter, da das Datum seines Feldes "Updated" später ist als Datum im Feld "LASTSYNC" in Tabelle "SYNCINFOTABLE".
Methode:
Um neue und entfernte Termine zu finden, kann man folgende Methode benutzen:
- public static EventEntry[] GetFehlendeTermine(EventEntry[] a, EventEntry[] b)
- {
- EventEntryIdComparator eeic = new EventEntryIdComparator();
- IEnumerable<EventEntry> res = a.Except(b, eeic);
- return res.ToArray();
- }
Falls Array "a" die Termine aus Datenbank enthält und Array "b" die Termine aus Kalender, dann sind im Ergebniss entfernte Termine. Falls umgekert- neue Termine.
Die Klasse "EventIdComparator" kann so aussehen:
- class EventEntryIdComparator : IEqualityComparer<EventEntry>
- {
- private String getId(EventEntry entry)
- {
- if (entry is EventEntryInner)
- return ((EventEntryInner)entry).GetEventId().Trim();
- else
- {
- return entry.EventId.Trim();
- }
- }
-
- public bool Equals(EventEntry x, EventEntry y)
- {
- string id1 = getId(x);
- string id2 = getId(y);
- return id1.Equals(id2);
-
-
- }
-
- public int GetHashCode(EventEntry obj)
- {
- return getId(obj).GetHashCode();
-
- }
- }