コード例 #1
0
    def test_protocol_default_values(self):
        # Test that retry_policy and auth_type always get a value regardless of how we create an Account
        c = Credentials(self.settings["username"], self.settings["password"])
        a = Account(
            self.account.primary_smtp_address,
            autodiscover=False,
            config=Configuration(
                server=self.settings["server"],
                credentials=c,
            ),
        )
        self.assertIsNotNone(a.protocol.auth_type)
        self.assertIsNotNone(a.protocol.retry_policy)

        a = Account(
            self.account.primary_smtp_address,
            autodiscover=True,
            config=Configuration(
                server=self.settings["server"],
                credentials=c,
            ),
        )
        self.assertIsNotNone(a.protocol.auth_type)
        self.assertIsNotNone(a.protocol.retry_policy)

        a = Account(self.account.primary_smtp_address, autodiscover=True, credentials=c)
        self.assertIsNotNone(a.protocol.auth_type)
        self.assertIsNotNone(a.protocol.retry_policy)
コード例 #2
0
    def setUpClass(cls):
        # There's no official Exchange server we can test against, and we can't really provide credentials for our
        # own test server to everyone on the Internet. Travis-CI uses the encrypted settings.yml.enc for testing.
        #
        # If you want to test against your own server and account, create your own settings.yml with credentials for
        # that server. 'settings.yml.sample' is provided as a template.
        try:
            with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'settings.yml')) as f:
                settings = safe_load(f)
        except FileNotFoundError:
            print('Skipping %s - no settings.yml file found' % cls.__name__)
            print('Copy settings.yml.sample to settings.yml and enter values for your test server')
            raise unittest.SkipTest('Skipping %s - no settings.yml file found' % cls.__name__)

        cls.settings = settings
        cls.verify_ssl = settings.get('verify_ssl', True)
        if not cls.verify_ssl:
            # Allow unverified TLS if requested in settings file
            BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter

        # Create an account shared by all tests
        tz = zoneinfo.ZoneInfo('Europe/Copenhagen')
        cls.retry_policy = FaultTolerance(max_wait=600)
        config = Configuration(
            server=settings['server'],
            credentials=Credentials(settings['username'], settings['password']),
            retry_policy=cls.retry_policy,
        )
        cls.account = Account(primary_smtp_address=settings['account'], access_type=DELEGATE, config=config,
                              locale='da_DK', default_timezone=tz)
コード例 #3
0
 def get_account(cls):
     return Account(
         primary_smtp_address=cls.settings["account"],
         access_type=DELEGATE,
         config=cls.config,
         locale="da_DK",
         default_timezone=cls.tz,
     )
コード例 #4
0
ファイル: test_autodiscover.py プロジェクト: zha0/exchangelib
 def test_autodiscover_from_account(self, m):
     # Test that autodiscovery via account creation works
     # Mock the default endpoint that we test in step 1 of autodiscovery
     m.post(self.dummy_ad_endpoint,
            status_code=200,
            content=self.dummy_ad_response)
     # Also mock the EWS URL. We try to guess its auth method as part of autodiscovery
     m.post(self.dummy_ews_endpoint,
            status_code=200,
            content=self.dummy_ews_response)
     self.assertEqual(len(autodiscover_cache), 0)
     account = Account(
         primary_smtp_address=self.account.primary_smtp_address,
         config=Configuration(
             credentials=self.account.protocol.credentials,
             retry_policy=self.retry_policy,
         ),
         autodiscover=True,
         locale='da_DK',
     )
     self.assertEqual(account.primary_smtp_address,
                      self.account.primary_smtp_address)
     self.assertEqual(account.protocol.service_endpoint.lower(),
                      self.dummy_ews_endpoint.lower())
     # Make sure cache is full
     self.assertEqual(len(autodiscover_cache), 1)
     self.assertTrue((account.domain, self.account.protocol.credentials,
                      True) in autodiscover_cache)
     # Test that autodiscover works with a full cache
     account = Account(
         primary_smtp_address=self.account.primary_smtp_address,
         config=Configuration(
             credentials=self.account.protocol.credentials,
             retry_policy=self.retry_policy,
         ),
         autodiscover=True,
         locale='da_DK',
     )
     self.assertEqual(account.primary_smtp_address,
                      self.account.primary_smtp_address)
     # Test cache manipulation
     key = (account.domain, self.account.protocol.credentials, True)
     self.assertTrue(key in autodiscover_cache)
     del autodiscover_cache[key]
     self.assertFalse(key in autodiscover_cache)
コード例 #5
0
 def test_failed_login_via_account(self):
     with self.assertRaises(AutoDiscoverFailed):
         Account(
             primary_smtp_address=self.account.primary_smtp_address,
             access_type=DELEGATE,
             credentials=Credentials(self.account.protocol.credentials.username, "WRONG_PASSWORD"),
             autodiscover=True,
             locale="da_DK",
         )
コード例 #6
0
ファイル: test_account.py プロジェクト: zha0/exchangelib
 def test_validation(self):
     with self.assertRaises(ValueError) as e:
         # Must have valid email address
         Account(primary_smtp_address='blah')
     self.assertEqual(str(e.exception), "primary_smtp_address 'blah' is not an email address")
     with self.assertRaises(AttributeError) as e:
         # Non-autodiscover requires a config
         Account(primary_smtp_address='*****@*****.**', autodiscover=False)
     self.assertEqual(str(e.exception), 'non-autodiscover requires a config')
     with self.assertRaises(ValueError) as e:
         # access type must be one of ACCESS_TYPES
         Account(primary_smtp_address='*****@*****.**', access_type=123)
     self.assertEqual(str(e.exception), "'access_type' 123 must be one of ('impersonation', 'delegate')")
     with self.assertRaises(ValueError) as e:
         # locale must be a string
         Account(primary_smtp_address='*****@*****.**', locale=123)
     self.assertEqual(str(e.exception), "Expected 'locale' to be a string, got 123")
     with self.assertRaises(ValueError) as e:
         # default timezone must be an EWSTimeZone
         Account(primary_smtp_address='*****@*****.**', default_timezone=123)
     self.assertEqual(str(e.exception), "Expected 'default_timezone' to be an EWSTimeZone, got 123")
     with self.assertRaises(ValueError) as e:
         # config must be a Configuration
         Account(primary_smtp_address='*****@*****.**', config=123)
     self.assertEqual(str(e.exception), "Expected 'config' to be a Configuration, got 123")
コード例 #7
0
 def test_validation(self):
     with self.assertRaises(ValueError) as e:
         # Must have valid email address
         Account(primary_smtp_address="blah")
     self.assertEqual(str(e.exception), "primary_smtp_address 'blah' is not an email address")
     with self.assertRaises(AttributeError) as e:
         # Non-autodiscover requires a config
         Account(primary_smtp_address="*****@*****.**", autodiscover=False)
     self.assertEqual(str(e.exception), "non-autodiscover requires a config")
     with self.assertRaises(ValueError) as e:
         Account(primary_smtp_address="*****@*****.**", access_type=123)
     self.assertEqual(str(e.exception), "'access_type' 123 must be one of ['delegate', 'impersonation']")
     with self.assertRaises(TypeError) as e:
         # locale must be a string
         Account(primary_smtp_address="*****@*****.**", locale=123)
     self.assertEqual(str(e.exception), "'locale' 123 must be of type <class 'str'>")
     with self.assertRaises(TypeError) as e:
         # default timezone must be an EWSTimeZone
         Account(primary_smtp_address="*****@*****.**", default_timezone=123)
     self.assertEqual(
         str(e.exception), "'default_timezone' 123 must be of type <class 'exchangelib.ewsdatetime.EWSTimeZone'>"
     )
     with self.assertRaises(TypeError) as e:
         # config must be a Configuration
         Account(primary_smtp_address="*****@*****.**", config=123)
     self.assertEqual(
         str(e.exception), "'config' 123 must be of type <class 'exchangelib.configuration.Configuration'>"
     )
コード例 #8
0
 def test_tzlocal_failure(self, m):
     a = Account(
         primary_smtp_address=self.account.primary_smtp_address,
         access_type=DELEGATE,
         config=Configuration(
             service_endpoint=self.account.protocol.service_endpoint,
             credentials=Credentials(self.account.protocol.credentials.username, "WRONG_PASSWORD"),
             version=self.account.version,
             auth_type=self.account.protocol.auth_type,
             retry_policy=self.retry_policy,
         ),
         autodiscover=False,
     )
     self.assertEqual(a.default_timezone, UTC)
コード例 #9
0
ファイル: test_account.py プロジェクト: zha0/exchangelib
    def test_login_failure_and_credentials_update(self):
        # Create an account that does not need to create any connections
        account = Account(
            primary_smtp_address=self.account.primary_smtp_address,
            access_type=DELEGATE,
            config=Configuration(
                service_endpoint=self.account.protocol.service_endpoint,
                credentials=Credentials(self.account.protocol.credentials.username, 'WRONG_PASSWORD'),
                version=self.account.version,
                auth_type=self.account.protocol.auth_type,
                retry_policy=self.retry_policy,
            ),
            autodiscover=False,
            locale='da_DK',
        )
        # Should fail when credentials are wrong, but UnauthorizedError is caught and retried. Mock the needed methods
        import exchangelib.util

        _orig1 = exchangelib.util._may_retry_on_error
        _orig2 = exchangelib.util._raise_response_errors

        def _mock1(response, retry_policy, wait):
            if response.status_code == 401:
                return False
            return _orig1(response, retry_policy, wait)

        def _mock2(response, protocol):
            if response.status_code == 401:
                raise UnauthorizedError('Invalid credentials for %s' % response.url)
            return _orig2(response, protocol)

        exchangelib.util._may_retry_on_error = _mock1
        exchangelib.util._raise_response_errors = _mock2
        try:
            with self.assertRaises(UnauthorizedError):
                account.root.refresh()
        finally:
            exchangelib.util._may_retry_on_error = _orig1
            exchangelib.util._raise_response_errors = _orig2

        # Cannot update from Configuration object
        with self.assertRaises(AttributeError):
            account.protocol.config.credentials = self.account.protocol.credentials
        # Should succeed after credentials update
        account.protocol.credentials = self.account.protocol.credentials
        account.root.refresh()
コード例 #10
0
    def test_login_failure_and_credentials_update(self):
        # Create an account that does not need to create any connections
        account = Account(
            primary_smtp_address=self.account.primary_smtp_address,
            access_type=DELEGATE,
            config=Configuration(
                service_endpoint=self.account.protocol.service_endpoint,
                credentials=Credentials(
                    self.account.protocol.credentials.username,
                    'WRONG_PASSWORD'),
                version=self.account.version,
                auth_type=self.account.protocol.auth_type,
                retry_policy=self.retry_policy,
            ),
            autodiscover=False,
            locale='da_DK',
        )

        # Should fail when credentials are wrong, but UnauthorizedError is caught and retried. Mock the needed methods
        class Mock1(FaultTolerance):
            def may_retry_on_error(self, response, wait):
                if response.status_code == 401:
                    return False
                return super().may_retry_on_error(response, wait)

            def raise_response_errors(self, response):
                if response.status_code == 401:
                    raise UnauthorizedError('Invalid credentials for %s' %
                                            response.url)
                return super().raise_response_errors(response)

        try:
            account.protocol.config.retry_policy = Mock1()
            with self.assertRaises(UnauthorizedError):
                account.root.refresh()
        finally:
            account.protocol.config.retry_policy = self.retry_policy

        # Cannot update from Configuration object
        with self.assertRaises(AttributeError):
            account.protocol.config.credentials = self.account.protocol.credentials
        # Should succeed after credentials update
        account.protocol.credentials = self.account.protocol.credentials
        account.root.refresh()
コード例 #11
0
def initEventStorage():
    # Open sqlite database, up to now it is used to store calendarNames / Outlook categories and Mattermost groups in which calendar events should be posted.
    # The calendar events are stored in an Outlook calendar and also in the sqlite database up to now.
    try:
        conn = sqlite3.connect(calendarSettings['DatabaseName'])
        cursor = conn.cursor()
    except Exception as e:
        print(
            "Could not open sqlite database due to following exception:\n {0} \n {1}"
            .format(e.__doc__, e.message))

    # Open outlook calendar
    try:
        config = Configuration(username=outlookSettings['Username'],
                               password=outlookSettings['Password'])
        account = Account(primary_smtp_address=outlookSettings['Email'],
                          config=config,
                          autodiscover=True,
                          access_type=DELEGATE)
    except Exception as e:
        print(
            "Could not open Outlook calendar due to following exception:\n {0} \n {1}"
            .format(e.__doc__, e.message))

    # Set timezone needed later, note: only Copenhagen is mapped but it is the same timezone as Berlin
    tz = EWSTimeZone.timezone('Europe/Copenhagen')

    # Create table which contains subcalendars
    # calendarName: Name which is refered to add an event, calendarMattermostGroup: group in which events should be published
    # calendarName is rewritten in an Outlook calendar category to be stored in Outlook calendar
    try:
        createCalendarTable = "CREATE TABLE IF NOT EXISTS 'calendarTable' (id INTEGER PRIMARY KEY AUTOINCREMENT, calendarName TEXT, calendarMattermostGroup TEXT)"
        conn.execute(createCalendarTable)
    except Exception as e:
        print(
            "Could not access / create sqlite calendar due to following exception:\n {0} \n {1}"
            .format(e.__doc__, e.message))

    return conn, cursor, tz, account
コード例 #12
0
def main():
    parser = argparse.ArgumentParser(parents=[tools.argparser])
    parser.add_argument(
        '--date',
        help=
        'What date to start looking at the calendar? Use format YYYY-MM-DD.')
    parser.add_argument(
        '--look_ahead_days',
        help='How many days to look ahead from the starting date?')
    parser.add_argument('--name', help='Which person are you?')
    parser.add_argument('--google_calendar', action='store_true')
    parser.add_argument('--outlook_calendar', action='store_true')
    parser.add_argument(
        '--spreadsheet_id',
        help='The ID of the ECBU Luminate Support Weekly Schedule spreadsheet',
        default='1RgDgDRcyAFDdkEyRH7m_4QOtJ7e-kv324hEWE4JuwgI')
    parser.add_argument(
        '--exchange_username',
        help=
        'The username you use in Outlook, should be [email protected]'
    )
    parser.add_argument(
        '--primary_smtp_address',
        help=
        'Your Outlook email address, should be [email protected]'
    )
    parser.add_argument('--exchange_password',
                        help='The password you use in Outlook')

    flags = parser.parse_args()

    print("Running with args: " + str(sys.argv))

    if not flags.google_calendar or flags.outlook_calendar:
        print(
            "You need to specify --google_calendar and/or --outlook_calendar")
        return

    today = arrow.get(flags.date, 'YYYY-MM-DD')
    dates = [
        today.replace(days=+n) for n in range(0, int(flags.look_ahead_days))
    ]

    credentials = get_credentials(flags)

    http = credentials.authorize(httplib2.Http())
    sheets_service = discovery.build('sheets', 'v4', http=http)

    google_calendar_service = None
    if flags.google_calendar:
        google_calendar_service = discovery.build('calendar', 'v3', http=http)

    exchange_account = None
    if flags.outlook_calendar:
        exchange_credentials = Credentials(username=flags.exchange_username,
                                           password=flags.exchange_password)
        exchange_account = Account(
            primary_smtp_address=flags.primary_smtp_address,
            credentials=exchange_credentials,
            autodiscover=True,
            access_type=DELEGATE)

    for date in dates:
        row = row_for_name(sheets_service, flags.spreadsheet_id, flags.name,
                           date)
        if not row:
            print(
                "Could not find row for {name} on {date}, will skip to next day"
                .format(name=flags.name, date=date))
            continue

        midnight = arrow.Arrow(date.year,
                               date.month,
                               date.day,
                               tzinfo='America/Chicago')
        appointments = appointments_from_google_sheet(sheets_service,
                                                      flags.spreadsheet_id,
                                                      row, midnight)

        if google_calendar_service:
            events_made = create_google_calendar_events(
                appointments, google_calendar_service)
            if events_made == 0:
                print("No shifts found for {0}".format(date))

        if exchange_account:
            events_made = create_outlook_calendar_events(
                appointments, exchange_account)
            if events_made == 0:
                print("No shifts found for {0}".format(date))
コード例 #13
0
def main():
    parser = argparse.ArgumentParser(parents=[tools.argparser])
    parser.add_argument(
        '--date',
        help=
        'What date to start looking at the calendar? Use format YYYY-MM-DD.')
    parser.add_argument(
        '--look_ahead_days',
        help='How many days to look ahead from the starting date?')
    parser.add_argument('--first_name',
                        help='Name of first person on lunch date')
    parser.add_argument('--second_name',
                        help='Name of second person on lunch date')
    parser.add_argument('--google_calendar', action='store_true')
    parser.add_argument('--outlook_calendar', action='store_true')
    parser.add_argument(
        '--spreadsheet_id',
        help='The ID of the ECBU Luminate Support Weekly Schedule spreadsheet',
        default='1RgDgDRcyAFDdkEyRH7m_4QOtJ7e-kv324hEWE4JuwgI')
    parser.add_argument(
        '--exchange_username',
        help=
        'The username you use in Outlook, should be [email protected]'
    )
    parser.add_argument(
        '--primary_smtp_address',
        help=
        'Your Outlook email address, should be [email protected]'
    )
    parser.add_argument('--exchange_password',
                        help='The password you use in Outlook')

    flags = parser.parse_args()

    print("Running with args: " + str(sys.argv))

    if not flags.google_calendar or flags.outlook_calendar:
        print(
            "You need to specify --google_calendar and/or --outlook_calendar")
        return

    today = arrow.get(flags.date, 'YYYY-MM-DD')
    dates = [
        today.replace(days=+n) for n in range(0, int(flags.look_ahead_days))
    ]

    credentials = get_credentials(flags)

    http = credentials.authorize(httplib2.Http())
    sheets_service = discovery.build('sheets', 'v4', http=http)

    google_calendar_service = None
    if flags.google_calendar:
        google_calendar_service = discovery.build('calendar', 'v3', http=http)

    exchange_account = None
    if flags.outlook_calendar:
        exchange_credentials = Credentials(username=flags.exchange_username,
                                           password=flags.exchange_password)
        exchange_account = Account(
            primary_smtp_address=flags.primary_smtp_address,
            credentials=exchange_credentials,
            autodiscover=True,
            access_type=DELEGATE)

    for date in dates:
        midnight = arrow.Arrow(date.year,
                               date.month,
                               date.day,
                               tzinfo='America/Chicago')

        first_row = row_for_name(sheets_service, flags.spreadsheet_id,
                                 flags.first_name, date)
        if not first_row:
            print(
                "Could not find row for {name} on {date}, will skip to next day"
                .format(name=flags.first_name, date=date))
            continue

        second_row = row_for_name(sheets_service, flags.spreadsheet_id,
                                  flags.second_name, date)
        if not second_row:
            print(
                "Could not find row for {name} on {date}, will skip to next day"
                .format(name=flags.second_name, date=date))
            continue

        first_appointments = appointments_from_google_sheet(
            sheets_service, flags.spreadsheet_id, first_row, midnight)
        second_appointments = appointments_from_google_sheet(
            sheets_service, flags.spreadsheet_id, second_row, midnight)

        if date.weekday() in [5, 6]:  # skip weekends
            continue

        # if no appointments are found, don't try to schedule lunch
        if not first_appointments or not second_appointments:
            print("No schedule yet defined for {0}".format(date))
            continue

        lunch_ranges = [Range(LUNCH_EARLIEST, LUNCH_LATEST)]
        for appointment in first_appointments + second_appointments:
            if appointment.appointment_type in ['F', 'C', 'PTO']:
                new_lunch_ranges = []
                appointment_range = Range(
                    fractional_hour(appointment.start_time),
                    fractional_hour(appointment.end_time))
                for lunch_range in lunch_ranges:
                    new_lunch_ranges.extend(
                        lunch_range.subtract(appointment_range))
                lunch_ranges = new_lunch_ranges

        # cut out ranges that are too short
        lunch_ranges = [r for r in lunch_ranges if r.length() >= 1.5]

        lunch_appointments = [
            Appointment(
                midnight.replace(
                    hour=hour_minute_from_fractional_hour(r.start)[0],
                    minute=hour_minute_from_fractional_hour(r.start)[1]),
                midnight.replace(
                    hour=hour_minute_from_fractional_hour(r.end)[0],
                    minute=hour_minute_from_fractional_hour(r.end)[1]), LUNCH)
            for r in lunch_ranges
        ]

        if google_calendar_service:
            events_made = create_google_calendar_events(
                lunch_appointments, google_calendar_service)
            if events_made == 0:
                print("No shifts found for {0}".format(date))

        if exchange_account:
            events_made = create_outlook_calendar_events(
                lunch_appointments, exchange_account)
            if events_made == 0:
                print("No shifts found for {0}".format(date))
コード例 #14
0
def library():
    lib = Exchange()
    lib.account = Account(primary_smtp_address="*****@*****.**")
    return lib