view multimerge.py @ 2:34c3a08a4a37

Copyright, etc.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 04 Jul 2016 12:49:53 +0300
parents 74f172565752
children 1e254756d0a5
line wrap: on
line source

#!/usr/bin/python
###
### Google Calendar MultiMerge v0.000001
### (C) 2016 Matti 'ccr' Hamalainen <ccr@tnsp.org>
###
### Python 2.7 <= x < 3 required! Please refer to
### README.txt for information on other depencies.
###
import os
import sys
import signal
import re
import time
import datetime
import httplib2
import ConfigParser
import oauth2client
from oauth2client import client
from oauth2client import tools
from googleapiclient import discovery


###
### Misc. helper functions
###

## Wrapper for print() that does not break when redirecting stdin/out
## because of piped output not having a defined encoding. We default
## to UTF-8 encoding in output here.
def gcm_print(smsg):
    gcm_msgbuf.append(smsg.encode("UTF-8"))
    if sys.stdout.encoding != None:
        print(smsg.encode(sys.stdout.encoding))
    else:
        print(smsg.encode("UTF-8"))


## Fatal errors
def gcm_fatal(smsg):
    gcm_print(u"ERROR: "+ smsg)
    sys.exit(1)


## Debug messages
def gcm_debug(smsg):
    if cfg.debug:
        gcm_print(u"DBG: "+ smsg)
    else:
        gcm_msgbuf.append(u"DBG: "+ smsg.encode("UTF-8"))


## Handle SIGINT signals here
def gcm_signal_handler(signal, frame):
    gcm_print("\nQuitting due to SIGINT / Ctrl+C!")
    sys.exit(0)


def gcm_get_credentials(mcfg):
    store = oauth2client.file.Storage(mcfg.credential_file)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(mcfg.secret_file, mcfg.scope)
        flow.user_agent = mcfg.app_name
        credentials = tools.run_flow(flow, store, mcfg)
    if not credentials or credentials.invalid:
        gcm_fatal("Failed to authenticate / invalid credentials.")
    return credentials


def gcm_dump_events(events):
    for event in events:
        ev_start = event["start"].get("dateTime", event["start"].get("date"))
        ev_end = event["end"].get("dateTime", event["end"].get("date"))
        gcm_print(u"{0:25} - {1:25} : {2}".format(ev_start, ev_end, event["summary"]))


class GCMSettings(dict):
    def __init__(self):
        self.m_data = {}
        self.m_saveable = {}
        self.m_translate = {}

    def __getattr__(self, name):
        if name in self.m_data:
            return self.m_data[name]
        else:
            gcm_fatal("GCMSettings.__getattr__(): No such attribute '"+ name +"'.")

    def mtranslate(self, name, value):
        if name in self.m_translate and self.m_translate[name]:
            return self.m_translate[name](value)
        else:
            return value

    def mdef(self, name, saveable, validate, translate, value):
        self.m_saveable[name] = saveable
        self.m_data[name] = self.mtranslate(name, value)

    def mset(self, name, value):
        if name in self.m_data:
            self.m_data[name] = self.mtranslate(name, value)
        else:
            gcm_fatal("GCMSettings.mset(): No such attribute '"+ name +"'.")

    def mget(self, name):
        if name in self.m_data:
            return self.m_data[name]
        else:
            return None


###
### Main program starts
###
gcm_msgbuf = []
signal.signal(signal.SIGINT, gcm_signal_handler)


## Settings
cfg = GCMSettings()

cfg.mdef("debug", True, gcm_is_bool, gcm_trans_bool, False)

cfg.mdef("source_regex", True, gcm_is_string, None, "^R:\s*(.*?)\s*\(\s*(.+?)\s*\)\s*$")
cfg.mdef("source_regmap", False, gcm_is_list, gcm_trans_list, [1, 2])
cfg.mdef("source_regmap_len", False, None, None, len(cfg.source_regmap))

cfg.mdef("dest_name", True, gcm_is_string, None, u"Raahen kansainvälisyystoiminta")
cfg.mdef("dest_id", True, gcm_is_string, None, None)

cfg.mdef("noauth_local_webserver", False, None, None, True)
#cfg.mdef("auth_host_name", False, None, None, "localhost")
#cfg.mdef("auth_host_port", False, None, None, [8080, 8090])
cfg.mdef("logging_level", True, gcm_is_log_level, gcm_trans_log_level, "ERROR")

# No need to touch these
cfg.mdef("app_name", False, None, None, "Google Calendar MultiMerge")
cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar")
#cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar.readonly")
cfg.mdef("secret_file", True, gcm_is_filename, None, "client_secret.json")
cfg.mdef("credential_file", True, gcm_is_filename, None, "client_credentials.json")

## Initialize and authorize API connection
credentials = gcm_get_credentials(cfg)
http = credentials.authorize(httplib2.Http())
service = discovery.build("calendar", "v3", http=http)


## Fetch complete calendar list
gcm_debug("Fetching available calendars ..")
calendars = []
calPageToken = None
while True:
    # We want everything except deleted and hidden calendars
    calResult = service.calendarList().list(
        showHidden=False,
        showDeleted=False,
        pageToken=calPageToken
        ).execute()

    calendars.extend(calResult.get("items", []))
    calPageToken = calResult.get("nextPageToken")
    if not calPageToken:
        break

if len(calendars) == 0:
    gcm_fatal("No calendars found?")