def auth_me():
    """"
        Get the collaborator information from the database. (First Name, Last Name, Email and id)

        Returns
        -------
            ApiResult
                the response object containing a JSON Object with the collaborators first name, last name, email
                and id.

            TellSpaceAuthError
                Exception class for authentication errors.

    """
    # Use DAOs to look for user in the database.
    email = get_jwt_identity()
    collab: Collaborator = get_me(email)

    if (not collab.banned) and collab.approved:
        return ApiResult(first_name=collab.first_name,
                         last_name=collab.last_name,
                         email=collab.email)

    raise TellSpaceAuthError(
        msg=
        'Authorization Error. Collaborator is banned or has not been approved by the admin.'
    )
def remove_document(doc_id: str):
    """
        Removes a document using the document id from the route parameters.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object containing the id of the removed document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    # Get user identity
    email = get_jwt_identity()

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned and collab.approved:
        doc = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        doc.delete()

        return ApiResult(id=str(doc.id))

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def get_document_by_id(doc_id: str):
    """
        Get the information from a specific document using the document id.

        Parameters
        ----------
            doc_id
                the document id string to be searched for

        Returns
        -------
            Response
                JSON object with all the information from a document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """
    email = get_jwt_identity()
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned and collab.approved:
        doc = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))

        return json.loads(doc.to_json()), 200

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def create_document_section(doc_id: str):
    """
        Append new document section using doc_id. Section is appended at the end of document with empty values.
        Return the new section number.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message of the updated document id and the new number of sections.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """
    email = get_jwt_identity()
    collab: Collaborator = Collaborator.objects.get(email=email)
    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        new_section = Section()
        new_section.secTitle = f'Section No. {len(doc.section) + 1}'
        new_section.content = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod...'
        doc.section.append(new_section)
        doc.save()
        return ApiResult(message=f'Created new section for {doc.id}. Total No. of sections {len(doc.section)}')

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_title(doc_id: str):
    """
        Edit the document title using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message of the updated document with the new title.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    email = get_jwt_identity()
    body = TitleValidator().load(request.json)

    collab: Collaborator = Collaborator.objects.get(email=email)
    if not collab.banned and collab.approved:
        doc = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))

        doc.title = body['title']
        doc.save()
        return ApiResult(message=f'Updated document {doc.id} title to: {doc.title}')

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def get_tokens(google_token: str):
    """
        Verify if the given param string is a valid Google idToken issued by Google and made with the projects
        credentials. If the user is NOT banned and is approved, proceed with token generation.

        Parameters
        ----------
            google_token
                the JWT Google generated token to be evaluated.

        Returns
        -------
            ApiResult
                the response object containing a JSON Object with two tokens: access_token and refresh_token,
            respectively.

            TellSpaceAuthError
                Exception Class.

    """
    id_info = id_token.verify_oauth2_token(
        google_token, requests.Request(),
        current_app.config['GOOGLE_OAUTH_CLIENT_ID'])

    # Verify that the token was indeed issued by google accounts.
    if id_info['iss'] != 'accounts.google.com':
        raise TellSpaceAuthError(
            msg="Wrong issuer. Token issuer is not Google.")

    collab: Collaborator = get_me(id_info['email'])
    if (not collab.banned) and collab.approved:
        return ApiResult(
            # access_token=create_access_token(identity=id_info['email'], expires_delta=timedelta(hours=30),
            access_token=create_access_token(identity=collab.email,
                                             expires_delta=timedelta(days=30)),
            refresh_token=create_refresh_token(
                identity=collab.email, expires_delta=timedelta(days=30)))

    raise TellSpaceAuthError(
        msg=
        'Authorization Error. Collaborator is banned or has not been approved by the admin'
    )
def auth_main():
    """Generate a new access token for the user. Client must sign in to Google oAuth to get a valid token.
        Client must be approved and NOT banned.
    """
    if not google.authorized:
        raise TellSpaceAuthError(msg="Client is not unauthorized. Please login at /google", status=401)

    # Get user email from Google Credentials to use as identity
    user = google.get("/oauth2/v2/userinfo").json()

    return bp.token['access_token']
def edit_document_timeline(doc_id: str):
    """
        Edit the document timeline using doc_id and valid request body values. Verifies if for all given timeline pairs
        the start date is NOT larger than the end-date.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message of the updated document and its id.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """
    email = get_jwt_identity()

    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body = TimelineValidator().load(request.json)

    # Check that event_start_date is NOT larger than event_end_date
    for time_pair in body['timeline']:
        if time_pair['event_start_date'] > time_pair['event_end_date']:
            raise TellSpaceApiError(
                msg='Invalid Timeline Pair. '
                    'Start Date is larger than the end date. One of the dates is larger than today.',
                status=500
            )

    collab: Collaborator = Collaborator.objects.get(email=email)

    # If collaborator is NOT banned and its approved, then do the thing
    if not collab.banned and collab.approved:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        new_timeline = []
        new_time_pair = Timeline()
        for time_pair in body['timeline']:
            new_time_pair.eventStartDate = str(time_pair['event_start_date'])
            new_time_pair.eventEndDate = str(time_pair['event_end_date'])
            new_time_pair.event = time_pair['event']
            new_timeline.append(new_time_pair)
        doc.timeline = new_timeline
        doc.save()

        return ApiResult(message=f'Updated document {doc.id} timeline.')

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_section(doc_id, section_nbr):
    """
        Edit the document section with valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

            section_nbr
                the document section number to be removed

        Returns
        -------
            ApiResult
                JSON Object with message of the updated section and the document id.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    # No such thing as section 0 or negative
    if int(section_nbr) <= 0:
        raise TellSpaceApiError(msg='No section found.')

    email = get_jwt_identity()
    body: EditSectionValidator = EditSectionValidator().load(request.json)
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))

        # Create section to replace existent one
        section = Section()
        section.secTitle = body['section_title']
        section.content = body['section_text']

        # Remember that lists start with index 0
        doc.section[int(section_nbr) - 1] = section
        doc.save()

        return ApiResult(
            message=f'Edited section {section_nbr} from the document {doc.id}.'
        )

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def create_document():
    """
        Create a new document using the information from the request body.

        Returns
        -------
            ApiResult
                JSON object with the id of the newly created document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """

    if not (request.method == 'POST'):
        raise TellSpaceApiError(msg='Method not allowed.', status=400)

    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body: CreateDocumentValidator = CreateDocumentValidator().load(request.json)
    email = get_jwt_identity()
    collab: Collaborator = Collaborator.objects.get(email=email)

    # TODO: Verify that the infrastrucutres and damage types exist in the database
    # TODO: Verify if tags exist in the database, if not... add them and create document.

    if not collab.banned and collab.approved:
        doc = DocumentCase()
        doc.title = body['title']
        doc.creatoriD = str(collab.id)
        doc.location = []
        doc.description = body['description']
        doc.incidentDate = str(body['incident_date'])
        doc.creationDate = datetime.today().strftime('%Y-%m-%d')
        doc.lastModificationDate = datetime.today().strftime('%Y-%m-%d')
        doc.language = body['language']
        doc.tagsDoc = []
        doc.infrasDocList = body['infrastructure_type']
        doc.damageDocList = []
        doc.author = []
        doc.actor = []
        doc.section = []
        doc.timeline = []
        doc.published = True
        doc.save()

        return ApiResult(docId=str(doc.id))

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_authors(doc_id: str):
    """
        Edit the document authors using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message containing the id of the updated document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    # Get user identity
    email = get_jwt_identity()

    # Verify request parameters
    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body = AuthorsValidator().load(request.json)

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        authors_list = []
        for a in body['authors']:
            new_author = Author()
            new_author.author_FN = a['first_name']
            new_author.author_LN = a['last_name']
            new_author.author_email = a['email']
            new_author.author_faculty = a['faculty']
            authors_list.append(new_author)

        doc.author = authors_list
        doc.save()
        return ApiResult(id=str(doc.id))

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_tags(doc_id: str):
    """
        Edit the document tags using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message containing the id of the updated document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """

    # Get user identity
    email = get_jwt_identity()

    # Verify request parameters
    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body = TagsValidator().load(request.json)

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))

        # If tags exists DO NOT exist in the tags collection, add it
        for tag in body['tags']:
            if not Tag.objects(tagItem=tag):
                newTag = Tag(tagItem=tag)
                newTag.save()

        doc.tagsDoc = body['tags']
        doc.save()
        return ApiResult(message=f'Edited tags of the document {doc.id}.')

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_infrastructure_types(doc_id: str):
    """
        Edit the document infrastructure_types using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message containing the id of the updated document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """

    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    # Get user identity
    email = get_jwt_identity()

    # Verify request parameters
    body = InfrastructureTypesValidator().load(request.json)

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    # Double check if the given infrastrucutres are in the Infrastrucutre Collection
    for infra in body['infrastructure_types']:
        Infrastructure.objects.get(infrastructureType=infra)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        doc.infrasDocList = body['infrastructure_types']
        doc.save()

        return ApiResult(
            message=f'Edited infrastructure types of the document {doc.id}.'
        )

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_incident_date(doc_id: str):
    """
        Edit the document tags using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message containing the id of the updated document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    # Get user identity
    email = get_jwt_identity()

    # Verify request parameters
    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body = IncidentDateValidator().load(request.json)

    # Verify that the date of the incident date is not in the future
    today = datetime.today().strftime('%Y-%m-%d')
    if str(body['incident_date']) > today:
        raise TellSpaceApiError(msg='Incident date is in the future.')

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        doc.incidentDate = str(body['incident_date'])
        doc.save()
        return ApiResult(message=f'Edited incident date of the document {doc.id}.')

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def remove_document_section(doc_id: str, section_nbr: str):
    """
        Remove a section from a document using doc_id and section number. Section number must be 1 <= x <= len(sections)

        Parameters
        ----------
            doc_id
                the document id string

            section_nbr
                the document section number to be removed

        Returns
        -------
            ApiResult
                JSON Object with message that show the removed section number, the document id and the number of
                sections left.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """
    email = get_jwt_identity()
    collab: Collaborator = Collaborator.objects.get(email=email)

    # No such thing as a negative section or section 0

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))

        # Check if section to pop is larger that the total number of sections
        if int(section_nbr) > len(doc.section) or int(section_nbr) <= 0:
            raise TellSpaceApiError(msg='Section No. does not exist.')

        # Remember that lists start with index 0
        doc.section.pop(int(section_nbr) - 1)
        doc.save()
        return ApiResult(
            message=f'Removed section {section_nbr} from {doc.id}. Total No. of sections left {len(doc.section)}'
        )

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def edit_document_locations(doc_id: str):
    """
        Edit the document locations using doc_id and valid request body values.

        Parameters
        ----------
            doc_id
                the document id string

        Returns
        -------
            ApiResult
                JSON Object with message containing the id of the updated document.

            TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.
    """

    # Get user identity
    email = get_jwt_identity()

    # Verify request parameters
    if request.json == {}:
        raise TellSpaceApiError(msg='No request body data.', status=400)

    body = LocationsValidator().load(request.json)

    # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if not collab.banned:
        doc: DocumentCase = DocumentCase.objects.get(id=doc_id, creatoriD=str(collab.id))
        doc.location = body.get('locations')
        doc.save()
        return ApiResult(
            message=f'Edited locations of the document {doc.id}.'
        )

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')
def get_documents():
    """
        Return a list of documents' metadata belonging to a collaborator. The collaborator ID is extracted from the
        access token.

        Returns
        -------
             Response
                JSON object with the list of documents belonging to the collaborator.

             TellSpaceAuthError
                Exception Class with authorization error message. Raised when the collaborator is banned or not
                approved.

    """

    # Get user identity
    email = get_jwt_identity()

    # # Extract collaborator with identity
    collab: Collaborator = Collaborator.objects.get(email=email)

    if (not collab.banned) and collab.approved:
        documents = DocumentCase.objects.filter(creatoriD=str(collab.id))
        response = []
        for doc in documents:
            doc: DocumentCase
            response.append({
                "id": str(doc.id),
                "title": doc.title,
                "description": doc.description,
                "published": doc.published,
                "incidentDate": doc.incidentDate,
                "creationDate": doc.creationDate,
                "lastModificationDate": doc.lastModificationDate
            })

        return jsonify(response)

    raise TellSpaceAuthError(msg='Authorization Error. Collaborator is banned or has not been approved by the admin.')