Пример #1
0
    def fetch_next(self, count=1):
        """ Fetch the next n messages after the previous fetch, where n is the specified count

		:param count: no.of messages to fetch
		"""
        skip_count = self.fetched_count
        if self._search:
            params = {
                '$filter': self._filter,
                '$top': count,
                '$search': '"{}"'.format(self._search)
            }
        else:
            params = {
                '$filter': self._filter,
                '$top': count,
                '$skip': skip_count
            }

        response = Connection.get_response(self.url,
                                           verify=self.verify,
                                           params=params)
        self.fetched_count += count

        messages = []
        for message in response:
            messages.append(Message(message, Connection().auth))

        return messages
Пример #2
0
    def getEvents(self, start=None, end=None, eventCount=10):
        '''
		Pulls events in for this calendar. default range is today to a year now.

		Keyword Arguments:
		start -- The starting date from where you want to begin requesting events. The expected
		type is a struct_time. Default is today.
		end -- The ending date to where you want to end requesting events. The expected
		type is a struct_time. Default is a year from start.
		'''

        # If no start time has been supplied, it is assumed you want to start as of now.
        if not start:
            start = time.strftime(self.time_string)

        # If no end time has been supplied, it is assumed you want the end time to be a year
        # from what ever the start date was.
        if not end:
            end = time.time()
            end += 3600 * 24 * 365
            end = time.gmtime(end)
            end = time.strftime(self.time_string, end)

        connection = Connection()

        # Change URL if we use Oauth
        if connection.is_valid() and connection.oauth != None:
            self.events_url = self.events_url.replace(
                "outlook.office365.com/api", "graph.microsoft.com")

        # This is where the actual call to Office365 happens.
        response = connection.get_response(self.events_url.format(
            self.json['Id'], start, end, eventCount),
                                           auth=self.auth,
                                           verify=self.verify)
        log.info('Response from O365: %s', str(response))

        #This takes that response and then parses it into individual calendar events.
        for event in response:
            try:
                duplicate = False

                # checks to see if the event is a duplicate. if it is local changes are clobbered.
                for i, e in enumerate(self.events):
                    if e.json['Id'] == event['id']:
                        self.events[i] = Event(event, self.auth, self)
                        duplicate = True
                        break

                if not duplicate:
                    self.events.append(Event(event, self.auth, self))

                log.debug('appended event: %s', event['subject'])
            except Exception as e:
                log.info('failed to append calendar: %', str(e))

        log.debug('all events retrieved and put in to the list.')
        return True
Пример #3
0
def creds() -> Account:
    """Load or obtain credentials for user."""

    credentials = "8da780f3-5ea0-4d97-ab13-9e7976370624"
    protocol = MSGraphProtocol(timezone="Europe/Stockholm")
    scopes = protocol.get_scopes_for(SCOPES)
    token_backend = FileSystemTokenBackend(
        token_path=os.path.dirname(__file__), token_filename="o365_token.txt")
    connection = Connection(credentials,
                            auth_flow_type="public",
                            token_backend=token_backend)
    account = Account(
        credentials,
        auth_flow_type="public",
        protocol=protocol,
        token_backend=token_backend,
    )

    if (not os.path.exists("kronoxToGCalendar/logic/o365_token.txt")
            and not account.is_authenticated):
        print("AUTH TRIGGERED")
        auth_url = connection.get_authorization_url(
            requested_scopes=scopes,
            redirect_uri=
            "https://kronox-client-api.herokuapp.com/return_token_url",
        )

        webbrowser.open_new(auth_url[0])

        token_req = lambda: requests.get(
            "https://kronox-client-api.herokuapp.com/get_token_url")

        while token_req().text == "None":
            continue

        token_res_arr = token_req().text.split("&")
        print(token_res_arr)
        token_code = token_res_arr[0].split("?")[1][5:]
        token_state = token_res_arr[1][6:]

        token_url = (
            "https://login.microsoftonline.com/common/oauth2/nativeclient?code="
            + token_code + "&state=" + token_state)

        connection.request_token(token_url)

    print("AUTH PASSED")
    account.is_authenticated

    return account
Пример #4
0
    def _get_url(key):
        """ Fetches the url for specified key as per the connection version configured

		:param key: the key for which url is required
		:return: URL to use for requests
		"""
        return FluentInbox.url_dict[key][Connection().api_version]
Пример #5
0
    def __init__(self,
                 credentials,
                 *,
                 protocol=None,
                 main_resource=ME_RESOURCE,
                 **kwargs):
        """ Creates an object which is used to access resources related to the
        specified credentials

        :param tuple credentials: a tuple containing the client_id
         and client_secret
        :param Protocol protocol: the protocol to be used in this account
        :param str main_resource: the resource to be used by this account
         ('me' or 'users')
        :param kwargs: any extra args to be passed to the Connection instance
        :raises ValueError: if an invalid protocol is passed
        """

        protocol = protocol or MSGraphProtocol  # Defaults to Graph protocol
        self.protocol = protocol(
            default_resource=main_resource, **kwargs) if isinstance(
                protocol, type) else protocol

        if not isinstance(self.protocol, Protocol):
            raise ValueError("'protocol' must be a subclass of Protocol")

        self.con = Connection(credentials, **kwargs)
        self.main_resource = main_resource
Пример #6
0
    def from_folder(self, folder_name):
        """ Configure to use this folder for fetching the mails

        :param folder_name: name of the outlook folder
        """
        self._reset()
        response = Connection.get_response(FluentInbox._get_url('folders'),
                                           verify=self.verify,
                                           params={'$top': 100})

        folder_id = None
        all_folders = []

        for folder in response:
            if folder['displayName'] == folder_name:
                folder_id = folder['id']
                break

            all_folders.append(folder['displayName'])

        if not folder_id:
            raise RuntimeError('Folder "{}" is not found, available folders '
                               'are {}'.format(folder_name, all_folders))

        self.url = FluentInbox._get_url('folder').format(folder_id=folder_id)

        return self
Пример #7
0
    def list_folders(self, parent_id=None, user_id=None):
        """
		:param parent_id: Id of parent folder to list.  Default to top folder
		:return: List of all folder data
		"""
        if parent_id and user_id:
            folders_url = FluentInbox._get_url('user_child_folders').format(
                folder_id=parent_id, user_id=user_id)
        elif parent_id:
            folders_url = FluentInbox._get_url('child_folders').format(
                folder_id=parent_id)
        elif user_id:
            folders_url = FluentInbox._get_url('user_folders').format(
                user_id=user_id)
        else:
            folders_url = FluentInbox._get_url('folders')

        response = Connection.get_response(folders_url,
                                           verify=self.verify,
                                           params={'$top': 100})

        folders = []
        for folder in response:
            folders.append(folder)

        return folders
Пример #8
0
    def update(self):
        '''Updates an event that already exists in a calendar.'''

        connection = Connection()

        # Change URL if we use Oauth
        if connection.is_valid() and connection.oauth != None:
            self.update_url = self.update_url.replace(
                "outlook.office365.com/api", "graph.microsoft.com")

        elif not self.auth:
            return False

        if self.calendar:
            calId = self.calendar.calendarId
        else:
            return False

        headers = {
            'Content-type': 'application/json',
            'Accept': 'application/json'
        }

        data = json.dumps(self.json)

        response = None
        print(data)
        try:
            response = connection.patch_data(self.update_url.format(
                self.json['id']),
                                             data,
                                             headers=headers,
                                             auth=self.auth,
                                             verify=self.verify)
            log.debug('sending patch request now')
        except Exception as e:
            if response:
                log.debug('response to event creation: %s', str(response))
            else:
                log.error(
                    'No response, something is very wrong with update: %s',
                    str(e))
            return False

        log.debug('response to event creation: %s', str(response))

        return Event(json.dumps(response), self.auth)
Пример #9
0
    def getCalendars(self):
        '''Begin the process of downloading calendar metadata.'''

        connection = Connection()

        # Change URL if we use Oauth
        if connection.is_valid() and connection.oauth != None:
            self.cal_url = self.cal_url.replace("outlook.office365.com/api",
                                                "graph.microsoft.com")

        log.debug('fetching calendars.')
        response = connection.get_response(self.cal_url,
                                           auth=self.auth,
                                           verify=self.verify)
        log.info('response from O365 for retriving message attachments: %s',
                 str(response))

        for calendar in response:
            try:
                duplicate = False
                log.debug('Got a calendar with name: {0} and id: {1}'.format(
                    calendar['Name'], calendar['Id']))
                for i, c in enumerate(self.calendars):
                    if c.json['id'] == calendar['Id']:
                        c.json = calendar
                        c.name = calendar['Name']
                        c.calendarid = calendar['Id']
                        duplicate = True
                        log.debug('Calendar: {0} is a duplicate',
                                  calendar['Name'])
                        break

                if not duplicate:
                    self.calendars.append(Calendar(calendar, self.auth))
                    log.debug('appended calendar: %s', calendar['Name'])

                log.debug('Finished with calendar {0} moving on.'.format(
                    calendar['Name']))

            except Exception as e:
                log.info('failed to append calendar: {0}'.format(str(e)))

        log.debug('all calendars retrieved and put in to the list.')
        return True
Пример #10
0
    def delete(self):
        '''
		Delete's an event from the calendar it is in.

		But leaves you this handle. You could then change the calendar and transfer the event to
		that new calendar. You know, if that's your thing.
		'''

        connection = Connection()

        # Change URL if we use Oauth
        if connection.is_valid() and connection.oauth != None:
            self.delete_url = self.delete_url.replace(
                "outlook.office365.com/api", "graph.microsoft.com")

        elif not self.auth:
            return False

        headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}

        response = None
        try:
            log.debug('sending delete request')
            response = connection.delete_data(self.delete_url.format(
                self.json['id']),
                                              headers=headers,
                                              auth=self.auth,
                                              verify=self.verify)

        except Exception as e:
            if response:
                log.debug('response to deletion: %s', str(response))
            else:
                log.error(
                    'No response, something is very wrong with delete: %s',
                    str(e))
            return False

        return response
Пример #11
0
    def get_folder(self, value, by='Id', parent_id=None, user_id=None):
        """
		Return a folder by a given attribute.  If multiple folders exist by
		this attribute, only the first will be returned

		Example:
		   get_folder(by='DisplayName', value='Inbox')

		   or

		   get_folder(by='Id', value='AAKrWFG...')

		   Would both return the requested folder attributes

		:param value: Value that we are searching for
		:param by: Search on this key (default: Id)
		:param user_id: user id the folder belongs to (shared mailboxes)
		:returns: Single folder data
		"""
        if parent_id and user_id:
            folders_url = FluentInbox._get_url('user_child_folders').format(
                folder_id=parent_id, user_id=user_id)
        elif parent_id:
            folders_url = FluentInbox._get_url('child_folders').format(
                folder_id=parent_id)
        elif user_id:
            folders_url = FluentInbox._get_url('user_folders').format(
                user_id=user_id)
        else:
            folders_url = FluentInbox._get_url('folders')

        response = Connection.get_response(folders_url,
                                           verify=self.verify,
                                           params={'$top': 100})

        folder_id = None
        all_folders = []

        for folder in response:
            if folder[by] == value:
                return (folder)

            all_folders.append(folder['displayName'])

        if not folder_id:
            raise RuntimeError(
                'Folder "{}" is not found by "{}", available folders '
                'are {}'.format(value, by, all_folders))
Пример #12
0
    def __init__(self,
                 credentials,
                 *,
                 auth_method=AUTH_METHOD.OAUTH,
                 scopes=None,
                 protocol=None,
                 main_resource=ME_RESOURCE,
                 **kwargs):

        if isinstance(auth_method, str):
            try:
                auth_method = AUTH_METHOD(auth_method)
            except ValueError as e:
                raise e

        if auth_method is AUTH_METHOD.BASIC:
            protocol = protocol or BasicAuthProtocol  # using basic auth defaults to Office 365 protocol
            self.protocol = protocol(
                default_resource=main_resource, **kwargs) if isinstance(
                    protocol, type) else protocol
            if self.protocol.api_version != 'v1.0' or not isinstance(
                    self.protocol, BasicAuthProtocol):
                raise RuntimeError(
                    'Basic Authentication only works with Office 365 Api version v1.0 and until November 1 2018.'
                )
        elif auth_method is AUTH_METHOD.OAUTH:
            protocol = protocol or MSGraphProtocol  # using oauth auth defaults to Graph protocol
            self.protocol = protocol(
                default_resource=main_resource, **kwargs) if isinstance(
                    protocol, type) else protocol

        if not isinstance(self.protocol, Protocol):
            raise ValueError("'protocol' must be a subclass of Protocol")

        self.con = kwargs.get('connection') or Connection(
            credentials,
            auth_method=auth_method,
            scopes=self.protocol.get_scopes_for(scopes))

        self.main_resource = main_resource
Пример #13
0
 def test_blank_connection(self):
     with pytest.raises(TypeError):
         c1 = Connection()
Пример #14
0
    def create(self, calendar=None):
        '''
		This method creates an event on the calender passed.

		IMPORTANT: It returns that event now created in the calendar, if you wish
		to make any changes to this event after you make it, use the returned value
		and not this particular event any further.

		calendar -- a calendar class onto which you want this event to be created. If this is left
		empty then the event's default calendar, specified at instancing, will be used. If no
		default is specified, then the event cannot be created.

		'''
        connection = Connection()

        # Change URL if we use Oauth
        if connection.is_valid() and connection.oauth != None:
            self.create_url = self.create_url.replace(
                "outlook.office365.com/api", "graph.microsoft.com")

        elif not self.auth:
            log.debug('failed authentication check when creating event.')
            return False

        if calendar:
            calId = calendar.calendarId
            self.calendar = calendar
            log.debug('sent to passed calendar.')
        elif self.calendar:
            calId = self.calendar.calendarId
            log.debug('sent to default calendar.')
        else:
            log.debug('no valid calendar to upload to.')
            return False

        headers = {
            'Content-type': 'application/json',
            'Accept': 'application/json'
        }

        log.debug('creating json for request.')
        data = json.dumps(self.json)

        response = None
        try:
            log.debug('sending post request now')
            response = connection.post_data(self.create_url.format(calId),
                                            data,
                                            headers=headers,
                                            auth=self.auth,
                                            verify=self.verify)
            log.debug('sent post request.')
            if response.status_code > 399:
                log.error(
                    "Invalid response code [{}], response text: \n{}".format(
                        response.status_code, response.text))
                return False
        except Exception as e:
            if response:
                log.debug('response to event creation: %s', str(response))
            else:
                log.error(
                    'No response, something is very wrong with create: %s',
                    str(e))
            return False

        log.debug('response to event creation: %s', str(response))
        return Event(response.json(), self.auth, calendar)