Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Reading Text File of Google Calendar Entries
#1
I am working on a driver that will load in my Google Calendar entries.  I found a python script online that uses the Google Calendar API that will give me the following text from my linked calendars:
Code:
email1@gmail.com:

2019-05-07 Debo Golf Tournament
2019-05-25 Bolder Boulder Race

email2@gmail.com:

2019-05-06T09:00:00-05:00 Haircut
2019-05-10T18:00:00-05:00 MGA Blue Grass Pairing Party
2019-05-11T08:00:00-05:00 MGA Blue Grass Tournament
2019-05-14T09:30:00-05:00 Check Chlorine Level

email3@gmail.com:

2019-05-14 HMR Board Meeting

en.usa#holiday@group.v.calendar.google.com:

2019-05-05 Cinco de Mayo
2019-05-12 Mother's Day
2019-05-27 Memorial Day
2019-06-16 Father's Day


I plan to generate this file once a day through task scheduler, and I have total control of this output as well - I can set it up as a json list and then parse it out, or just use the text as shown, or something different.  I am currently at the point in the driver where I can read the data, but before I got past this, I wanted to know if it would be better to parse it as a text file or put the output into a json format and use the parser you have built in?  I have done that on a driver in the past, so more familiar with that.

Just wanted an opinion of the best way forward before I get too deep into this.
Reply
#2
XML would be the best, since it can do the most work for you on the parsing side. Set up a DTD for it, and it can do a lot of the checking, so you just have to pull the values out and convert them to your required types. You do have to deal with escaping characters that aren't legal in particular XML values as you format them out. Just escape (via character ref) any less than or ampersand or single/double quote characters in the calendar content and you'd likely avoid any issues.

Is that some sort of library, or is it just a defined network interface? If the latter you could skip the library and do it all in the driver.
Dean Roddey
Explorans limites defectum
Reply
#3
(05-09-2019, 10:12 AM)Dean Roddey Wrote: Is that some sort of library, or is it just a defined network interface? If the latter you could skip the library and do it all in the driver.

I am a true novice at this type of stuff, so maybe you could tell me whether it is a defined network interface.  Here is the Python Script that I copied and modified a bit.  As far as what you see below, once I got CQC reading it successfully, I was going to provide command line parameters for start and end dates, but for now they are hard coded:
Code:
from __future__ import print_function
import datetime
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']

def main():
   """Shows basic usage of the Google Calendar API.
   Prints the start and name of the next 10 events on the user's calendar.
   """
   creds = None
   # The file token.pickle stores the user's access and refresh tokens, and is
   # created automatically when the authorization flow completes for the first
   # time.
   if os.path.exists('token.pickle'):
       with open('token.pickle', 'rb') as token:
           creds = pickle.load(token)
   # If there are no (valid) credentials available, let the user log in.
   if not creds or not creds.valid:
       if creds and creds.expired and creds.refresh_token:
           creds.refresh(Request())
       else:
           flow = InstalledAppFlow.from_client_secrets_file(
               'credentials.json', SCOPES)
           creds = flow.run_local_server()
       # Save the credentials for the next run
       with open('token.pickle', 'wb') as token:
           pickle.dump(creds, token)

   service = build('calendar', 'v3', credentials=creds)

   # This code is to fetch the calendar ids shared with me
   # Src: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list
   page_token = None
   calendar_ids = []
   while True:
       calendar_list = service.calendarList().list(pageToken=page_token).execute()
       for calendar_list_entry in calendar_list['items']:
   #        if '@qxf2.com' in calendar_list_entry['id']:
               calendar_ids.append(calendar_list_entry['id'])
       page_token = calendar_list.get('nextPageToken')
       if not page_token:
           break

   # This code is to look for all-day events in each calendar for the month of May
   # Src: https://developers.google.com/google-apps/calendar/v3/reference/events/list
   # You need to get this from command line
   # Bother about it later!
   start_date = datetime.datetime(
       2019, 5, 1, 00, 00, 00, 0).isoformat() + 'Z'
   end_date = datetime.datetime(2019, 12, 30, 23, 59, 59, 0).isoformat() + 'Z'

   for calendar_id in calendar_ids:
       count = 0
       print('\n%s:\n' % calendar_id)
       eventsResult = service.events().list(
           calendarId=calendar_id,
           timeMin=start_date,
           timeMax=end_date,
           singleEvents=True,
           orderBy='startTime').execute()
       events = eventsResult.get('items', [])
      # if not events:
      #     print('No upcoming events found.')
       for event in events:
      #     if event.has_key('summary'):
      #         if 'PTO' in event['summary']:
                   count += 1
                   start = event['start'].get(
                       'dateTime', event['start'].get('date'))
                   print(start, event['summary'])
       # print('Total days off for %s is %d' % (calendar_id, count))


if __name__ == '__main__':
   main()
Reply
#4
It's a littel hard to tell, since I don't grok Python very much. But there are no HTTP operations exposed there. That may be what's going on behind the scenes of course, and it lists the URLs in the comments, but they are apparently using a wrapper library. The raw HTTP interface may be documented somewhere as well.
Dean Roddey
Explorans limites defectum
Reply
#5
I decided to go with JSON since I am more familiar with it - I have a file that is correctly formatted (MenuGCal.json) and placed in the MacroFileRoot folder, but running into a road block within the driver to load the file in.  It compiles fine, and runs fine until it gets to CalFile.Open.  once I execute that line within debug, it says the macro is complete, even though I was using the step command (F11).  No errors are thrown, although I am not trying to catch any.  Currently on 5.3.943.

Code:
Class=[NonFinal]
    ClassPath MEng.User.CQC.Drivers.GCal.GCal;
    ParentClass MEng.Object;
EndClass;

Imports=
    MEng.System.Runtime.FileInStream;
    MEng.System.Runtime.StringTokenizer;
EndImports;

Types=
    ArrayOf[String] StrArray;
EndTypes;

Members=
    StringTokenizer.ParmStrList m_MyStrArray;
EndMembers;


Methods=[Public,Final]

    Constructor()
    Begin
    EndConstructor;

    Method Start() Returns Int4
    Begin
 Locals=
            FileInStream CalFile;
            Card4 IndexErr;
            String TarLine;
            String CurLine;
            StringTokenizer STok;
        EndLocals;
        
        //Open CalFile
        CalFile.Open("\\MenuGCal.json");
        
        //Search for the last in the list before end of stream
        While(!CalFile.EndOfStream())
            CalFile.GetLine(CurLine);
            CurLine.StripWhitespace();
            If (!CurLine.IsEmpty())
                TarLine := CurLine;
            EndIf;
        EndWhile;
            
        Return 0;
        
    EndMethod;

EndMethods;
Reply
#6
That's not a valid file path in CML. CML can only access files under [cqc]\CQCData\MacroFileRoot\ on the machine where the macro is running. And that corresponds to the / directory, i.e. that's the root of the CML file space, and they use forward slashes as well to avoid all the silliness of having to escape backslashes.

So you should create some directory under MacroFileRoot on that machine and dump the the files there, say MyGCalendar, then access them as /MyGCalendar/MenuGCal.json or some such.
Dean Roddey
Explorans limites defectum
Reply
#7
I made the change as you suggested - placed the file MenuGCal.json in C:\Program Files\CQC\CQCData\MacroFileRoot\GCal - still having the same issue - seems simple, but that is sometimes the way it goes, here is the change I made:

Code:
       //Open CalFile
       CalFile.Open("/GCal/MenuGCal.json");

Here is the JSON File, which parses fine on https://jsoneditoronline.org/:
Code:
{
"email1@gmail.com":[
{"DateID":"2019-05-07",
"Event":"Debo Golf Tournament"},
{"DateID":"2019-05-25",
"Event":"Bolder Boulder Race"},
],
"email2@gmail.com":[
{"DateID":"2019-05-06T09:00:00-05:00",
"Event":"Haircut"},
{"DateID":"2019-05-10T18:00:00-05:00",
"Event":"MGA Blue Grass Pairing Party"},
{"DateID":"2019-05-11T08:00:00-05:00",
"Event":"MGA Blue Grass Tournament"},
{"DateID":"2019-05-14T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-05-17T08:00:00-05:00",
"Event":"Moses College Trip"},
{"DateID":"2019-05-28T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-06-10T09:00:00-05:00",
"Event":"Haircut"},
{"DateID":"2019-06-11T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-06-20T09:00:00-05:00",
"Event":"Change Air Filters"},
{"DateID":"2019-06-25T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-07-09T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-07-10T10:00:00-05:00",
"Event":"Dentist"},
{"DateID":"2019-07-23T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-08-06T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-08-20T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-09-03T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-09-17T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-10-01T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-10-15T08:00:00-05:00",
"Event":"Truett's Birthday"},
{"DateID":"2019-10-15T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-10-29T09:30:00-05:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-11-12T09:30:00-06:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-11-26T09:30:00-06:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-12-10T09:30:00-06:00",
"Event":"Check Chlorine Level"},
{"DateID":"2019-12-24T09:30:00-06:00",
"Event":"Check Chlorine Level"},
],
"email3@gmail.com":[
{"DateID":"2019-05-14",
"Event":"HMR Board Meeting"},
],
"contacts":[
],
"holidays":[
{"DateID":"2019-05-05",
"Event":"Cinco de Mayo"},
{"DateID":"2019-05-12",
"Event":"Mother's Day"},
{"DateID":"2019-05-27",
"Event":"Memorial Day"},
{"DateID":"2019-06-16",
"Event":"Father's Day"},
{"DateID":"2019-07-04",
"Event":"Independence Day"},
{"DateID":"2019-09-02",
"Event":"Labor Day"},
{"DateID":"2019-10-14",
"Event":"Columbus Day (regional holiday)"},
{"DateID":"2019-10-31",
"Event":"Halloween"},
{"DateID":"2019-11-03",
"Event":"Daylight Saving Time ends"},
{"DateID":"2019-11-11",
"Event":"Veterans Day"},
{"DateID":"2019-11-28",
"Event":"Thanksgiving Day"},
{"DateID":"2019-11-29",
"Event":"Black Friday"},
{"DateID":"2019-12-24",
"Event":"Christmas Eve"},
{"DateID":"2019-12-25",
"Event":"Christmas Day"},
],
}
Reply
#8
The file open wouldn't care at all what is in it. It's just opening the file for reading. Though you wouldn't actually open it if you were going to parse it using the JSON parser. You can just pass it the path.

However, be sure that the program that writes the file (or if you did it manually) that you had admin rights. Else it won't actually get put there, it'll get put into some redirected path under your own user account.

Run a text editor as admin and navigate there and see if the file is there.
Dean Roddey
Explorans limites defectum
Reply
#9
I did what you suggested with the same results, so a bit at a full stop. You mentioned:

"Though you wouldn't actually open it if you were going to parse it using the JSON parser. You can just pass it the path."

I looked through the reference docments and didn't see how I could do that. Maybe that would solve my problem.

I would be happy to send you the driver if you think that would help.
Reply
#10
Oops, sorry, I was off by a level of indirection. You have to create an input stream, which is probably you were opening there and I missed that bit. So, you would open the stream and pass that to the JSON parser.

Add a try/catch, and dump the exception (which you access as $Exception within the Catch block) to the log to see what it's saying, or you can dump it to a file.

Oh, I guess one possibly reason it can't open it is that you are running CQC under the standard system account for services, but you are creating the file under your account and so he can't open it. You could write out files in that case and read them back, since they would both be created under the same account, but in this case it's under different accounts. So that might be an issue.

And I should have also said to open a command prompt as admin and go to that directory and see if you see it there. If the file already exists, it's possible the editor, even in admin mode would still show it to you even if it was in that redirected location.

One sanity check also is have the driver create an output text stream and write a bit to a file and close it. Make sure that file shows up there as well, just to make absolutely sure you are looking in the right place.
Dean Roddey
Explorans limites defectum
Reply


Possibly Related Threads...
Thread Author Replies Views Last Post
  Generic-Network Monitor - Config File Error gReatAutomation 17 607 06-27-2019, 11:46 AM
Last Post: gReatAutomation
  Google Calendar and Web Browser kblagron 4 485 04-25-2019, 10:10 PM
Last Post: kblagron
  Is it possible to tie in CQC into a third part calendar to drive schedules ghurty 6 686 01-01-2019, 05:30 PM
Last Post: Dean Roddey
  File Tag Repository and .M4A Files kblagron 10 1,590 11-18-2018, 04:40 PM
Last Post: Dean Roddey
  Question on Formatting of Variable Text kblagron 2 1,209 09-07-2018, 08:52 PM
Last Post: kblagron
  Echo Config file issues ghurty 6 1,811 07-08-2018, 07:13 PM
Last Post: ghurty
  Embedded Variable in Text zra 2 1,107 05-07-2018, 09:59 AM
Last Post: zra
  Text To Speech RichardU 3 1,385 01-10-2018, 12:30 PM
Last Post: RichardU
  Writing to an external file from trigger event Ira 21 6,165 11-13-2017, 02:08 PM
Last Post: znelbok
  Google backup and sync and CQC kfly 4 2,235 10-06-2017, 11:17 AM
Last Post: kfly

Forum Jump:


Users browsing this thread: 1 Guest(s)