You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.6KB

  1. #!/usr/bin/env python3
  2. import csv
  3. import argparse
  4. import configparser
  5. from datetime import datetime, timedelta
  6. from O365 import (Account, Connection, FileSystemTokenBackend,
  7. MSOffice365Protocol)
  8. parser = argparse.ArgumentParser(prog='seatingplan', description="Script to generate a seating plan via Office365 Calendars")
  9. parser.add_argument("-i", "--client-id", type=str, dest='client_id', default="",
  10. help='Client ID for registered azure application')
  11. parser.add_argument("-s", "--client-secret", type=str, dest='client_secret', default="",
  12. help='Client secret for registered azure application')
  13. parser.add_argument("-t", "--tenant-id", type=str, dest='tenant_id', default="",
  14. help='Tenant ID for registered azure application')
  15. parser.add_argument("-c", "--config", type=str, dest="config_path", default="",
  16. help="Path to a config file to read settings from.")
  17. # TODO: DATETIME FORMATTING, MAKE THIS AVALIABLE FOR THE OUTPUT PATH SO THAT YOU CAN DO THE COOL SCRIPT THINGS
  18. parser.add_argument("-o", "--output", type=str, dest="output_path", default="Seating Plan.csv",
  19. help="Path of the outputted csv file.")
  20. # TODO: Setup providing config file via commandline args
  21. def read_config_file(config_path):
  22. """
  23. Reads config file and sets up variables foo
  24. :return: credentials: ('client_id', 'client_secret') and tenant: str
  25. """
  26. config = configparser.ConfigParser()
  27. config.read(config_path)
  28. credentials = (config["client"]["id"], config["client"]["secret"])
  29. tenant = config["client"]["tenant"]
  30. return credentials, tenant
  31. def parse_args():
  32. """
  33. Parses arguments from the commandline.
  34. :return: exits or returns (client_id, client_secret) and tenant_id
  35. """
  36. # TODO: Maybe the prints before exit could be a lil better at explaining the error.
  37. args = parser.parse_args()
  38. using_args = False
  39. using_conf = False
  40. if args.client_id and args.tenant_id and args.client_secret:
  41. using_args = True
  42. if args.config_path:
  43. using_conf = True
  44. if using_args and using_conf:
  45. # Using both types of config input. Confusing so dump it
  46. print("Cannot use both command-line arguments and config file. Please only use one.")
  47. exit(1)
  48. elif using_conf:
  49. # Read the file provided and return the required config
  50. return read_config_file(args.config_path), args.output_path
  51. elif using_args:
  52. # Just grab the config from the command line args
  53. return (args.client_id, args.client_secret), args.tenant_id, args.output_path
  54. else:
  55. # If the code has gotten here, then a config can't be parsed so we must close the program
  56. print("Cannot login. No config/partial was provided.")
  57. exit(1)
  58. def create_session(credentials, tenant_id):
  59. """
  60. Create a session with the API and save the token for later use.
  61. :param credentials: tuple of (client_id, client_secret)
  62. :param tentant_id: str of tenant_id
  63. :return: Account class and email: str
  64. """
  65. my_protocol = MSOffice365Protocol(api_version='v2.0')
  66. token_backend = FileSystemTokenBackend(token_filename='access_token')
  67. return Account(
  68. credentials,
  69. protocol=my_protocol,
  70. tenant_id=tenant_id,
  71. token_backend=token_backend
  72. )
  73. def authenticate_session(session: Account):
  74. """
  75. Authenticates account session object with oauth. Uses the default auth flow that comes with the library
  76. It could be merged with oauth wrapper but this works too.
  77. :param session: Account object
  78. :return:
  79. """
  80. try:
  81. session.con.oauth_request("https://outlook.office.com/api/v2.0/me/calendar", "get")
  82. except RuntimeError: # Not authenticated. Need to ask user for url
  83. session.authenticate(scopes=['basic', 'address_book', 'users', 'calendar_shared'])
  84. session.con.oauth_request("https://outlook.office.com/api/v2.0/me/calendar", "get")
  85. def oauth_request(connection: Connection, url: str):
  86. """
  87. Wrapper for Connection.oauth_request to provide some error handling
  88. :param connection:
  89. :param url:
  90. :return:
  91. """
  92. request = connection.oauth_request(url, "get")
  93. if request.status_code != 200:
  94. print(f"Request failed: GET request to {url} failed with {request.status_code} error")
  95. else:
  96. return request
  97. def get_week_datetime():
  98. """
  99. Gets the current week's Monday and Friday to be used to filter a calendar.
  100. If this script is ran during the work week (Monday-Friday), it will be the current week. If it is ran on the weekend, it will generate for next week.
  101. :return: Monday and Friday: Datetime object
  102. """
  103. today = datetime.now()
  104. weekday = today.weekday()
  105. # If this script is run during the week
  106. if weekday <= 4: # 0 = Monday, 6 = Sunday
  107. monday = today - timedelta(days=weekday) # Monday = 0-0, Friday = 4-4
  108. friday = today + timedelta(days=4 - weekday) # Fri to Fri 4 + (4 - 4), Tues to Fri = 2 + (4 - 2)
  109. return monday, friday
  110. else:
  111. monday = today - timedelta(days=weekday) + timedelta(days=7) # Monday = 0-0, Friday = 4-4
  112. friday = today + timedelta(days=4 - weekday) + timedelta(
  113. days=7) # Fri to Fri 4 + (4 - 4), Tues to Fri = 2 + (4 - 2)
  114. return monday, friday
  115. def create_csv(output_path):
  116. with open(output_path, 'w', newline='') as csvfile:
  117. fieldnames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
  118. writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
  119. pass
  120. # TODO: https://docs.python.org/3.7/library/csv.html#csv.DictWriter Need to finish this when we actually get some data to input.
  121. def main():
  122. """
  123. Main function that is ran on start up. Script is ran from here.
  124. """
  125. credentials, tenant_id, output_path = parse_args()
  126. session = create_session(credentials, tenant_id)
  127. authenticate_session(session)
  128. r = session.con.oauth_request("https://outlook.office.com/api/v2.0/users/{email}/calendar/events", "get")
  129. # request = account.con.oauth_request("https://outlook.office.com/api/v2.0/users/EMAIL/calendar/events?$filter=Start/DateTime ge '2019-09-04T08:00' AND End/Datetime le '2019-09-05T08:00'&$top=50", "get")
  130. print(r.text)
  131. # setup csv
  132. # API request events from out of office email
  133. # loop over events
  134. # find out who the event is talking about
  135. # insert into csv
  136. # output csv
  137. monday, friday = get_week_datetime()
  138. print(f"Monday is {monday}, Friday is {friday}")
  139. create_csv(output_path)
  140. if __name__ == "__main__":
  141. main()