예제 #1
0
파일: github.py 프로젝트: wanyaland/easycla
def notify_project_managers(repositories):
    if repositories is None:
        return

    project_repos = {}
    for ghrepo in repositories:
        project_id = ghrepo.get_repository_project_id()
        if project_id in project_repos:
            project_repos[project_id].append(ghrepo.get_repository_url())
        else:
            project_repos[project_id] = [ghrepo.get_repository_url()]

    for project_id in project_repos:
        managers = cla.controllers.project.get_project_managers("", project_id, enable_auth=False)
        project = get_project_instance()
        try:
            project.load(project_id=str(project_id))
        except DoesNotExist as err:
            cla.log.warning('notify_project_managers - unable to load project (cla_group) by '
                            f'project_id: {project_id}, error: {err}')
            return {'errors': {'project_id': str(err)}}
        repositories = project_repos[project_id]
        subject, body, recipients = unable_to_do_cla_check_email_content(
            project, managers, repositories)
        get_email_service().send(subject, body, recipients)
        cla.log.debug('github.activity - sending unable to perform CLA Check email'
                      f' to managers: {recipients}'
                      f' for project {project} with '
                      f' repositories: {repositories}')
예제 #2
0
def delete_project_document(project_id,
                            document_type,
                            major_version,
                            minor_version,
                            username=None):
    """
    Deletes the document from the specified project.

    :param project_id: The ID of the project in question.
    :type project_id: string
    :param document_type: The type of document to remove (individual or corporate).
    :type document_type: string
    :param major_version: The document major version number to remove.
    :type major_version: integer
    :param minor_version: The document minor version number to remove.
    :type minor_version: integer
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    document = cla.utils.get_project_document(project, document_type,
                                              major_version, minor_version)
    if document is None:
        return {'errors': {'document': 'Document version not found'}}
    if document_type == 'individual':
        project.remove_project_individual_document(document)
    else:
        project.remove_project_corporate_document(document)
    project.save()
    return {'success': True}
예제 #3
0
def create_project(project_external_id, project_name, project_icla_enabled,
                   project_ccla_enabled, project_ccla_requires_icla_signature,
                   project_acl_username):
    """
    Creates a project and returns the newly created project in dict format.

    :param project_external_id: The project's external ID.
    :type project_external_id: string
    :param project_name: The project's name.
    :type project_name: string
    :param project_icla_enabled: Whether or not the project supports ICLAs.
    :type project_icla_enabled: bool
    :param project_ccla_enabled: Whether or not the project supports CCLAs.
    :type project_ccla_enabled: bool
    :param project_ccla_requires_icla_signature: Whether or not the project requires ICLA with CCLA.
    :type project_ccla_requires_icla_signature: bool
    :return: dict representation of the project object.
    :rtype: dict
    """
    project = get_project_instance()
    project.set_project_id(str(uuid.uuid4()))
    project.set_project_external_id(str(project_external_id))
    project.set_project_name(project_name)
    project.set_project_icla_enabled(project_icla_enabled)
    project.set_project_ccla_enabled(project_ccla_enabled)
    project.set_project_ccla_requires_icla_signature(
        project_ccla_requires_icla_signature)
    project.set_project_acl(project_acl_username)
    project.save()

    return project.to_dict()
예제 #4
0
파일: github.py 프로젝트: wanyaland/easycla
def notify_project_managers_auto_enabled(organization_name, repositories):
    if repositories is None:
        return

    project_repos = {}
    for repo in repositories:
        project_id = repo.get_repository_project_id()
        if project_id in project_repos:
            project_repos[project_id].append(repo.get_repository_url())
        else:
            project_repos[project_id] = [repo.get_repository_url()]

    for project_id in project_repos:
        managers = cla.controllers.project.get_project_managers("", project_id, enable_auth=False)
        project = get_project_instance()
        try:
            project.load(project_id=str(project_id))
        except DoesNotExist as err:
            cla.log.warning('notify_project_managers_auto_enabled - unable to load project (cla_group) by '
                            f'project_id: {project_id}, error: {err}')
            return {'errors': {'project_id': str(err)}}

        repositories = project_repos[project_id]
        subject, body, recipients = auto_enabled_repository_email_content(
            project, managers, organization_name, repositories)
        get_email_service().send(subject, body, recipients)
        cla.log.debug('notify_project_managers_auto_enabled - sending auto-enable email '
                      f' to managers: {recipients}'
                      f' for project {project} for '
                      f' GitHub Organization {organization_name} with '
                      f' repositories: {repositories}')
예제 #5
0
def get_project_companies(project_id):
    """
    Get a project's associated companies (via CCLA link).

    :param project_id: The ID of the project.
    :type project_id: string
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}

    # Get all reference_ids of signatures that match project_id AND are of reference type 'company'.
    # Return all the companies matching those reference_ids.
    signature = Signature()
    signatures = signature.get_signatures_by_project(str(project_id),
                                                     signature_signed=True,
                                                     signature_approved=True,
                                                     signature_reference_type='company')
    company_ids = list(set([signature.get_signature_reference_id() for signature in signatures]))
    company = Company()
    all_companies = [comp.to_dict() for comp in company.all(company_ids)]
    all_companies = sorted(all_companies, key=lambda i: i['company_name'].casefold())

    return all_companies
예제 #6
0
def delete_project(project_id, username=None):
    """
    Deletes an project based on ID.

    :TODO: Need to also delete the documents saved with the storage provider.

    :param project_id: The ID of the project.
    :type project_id: string
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    # Create audit trail
    event_data = 'Project-{} deleted'.format(project.get_project_name())
    Event.create_event(
        event_type=EventType.DeleteProject,
        event_project_id=project_id,
        event_data=event_data,
        contains_pii=False,
    )
    project.delete()

    return {'success': True}
예제 #7
0
파일: project.py 프로젝트: geva/easycla
def _get_project_document(project_id,
                          document_type,
                          major_version=None,
                          minor_version=None):
    """
    See documentation for get_project_document().
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    if document_type == 'individual':
        try:
            document = project.get_project_individual_document(
                major_version, minor_version)
        except DoesNotExist as err:
            return {'errors': {'document': str(err)}}
    else:
        try:
            document = project.get_project_corporate_document(
                major_version, minor_version)
        except DoesNotExist as err:
            return {'errors': {'document': str(err)}}
    return document
예제 #8
0
def get_projects():
    """
    Returns a list of projects in the CLA system.

    :return: List of projects in dict format.
    :rtype: [dict]
    """
    return [project.to_dict() for project in get_project_instance().all()]
예제 #9
0
파일: github.py 프로젝트: geva/easycla
def handle_installation_repositories_removed_event(action: str, body: dict):
    func_name = 'github.activity.handle_installation_repositories_removed_event'
    # Who triggered the event
    user_login = body['sender']['login']
    cla.log.debug(
        f'{func_name} - processing github [installation_repositories] '
        f'activity {action} callback created by GitHub user {user_login}.')
    repository_removed = body['repositories_removed']
    repositories = []
    for repo in repository_removed:
        repository_external_id = repo['id']
        ghrepo = Repository().get_repository_by_external_id(
            repository_external_id, 'github')
        if ghrepo is not None:
            repositories.append(ghrepo)

    # Notify the Project Managers that the following list of repositories were removed
    notify_project_managers(repositories)

    # The following list of repositories were deleted/removed from GitHub - we need to remove
    # the repo entry from our repos table
    for repo in repositories:

        project_model = get_project_instance()
        try:
            project_model.load(project_id=repo.get_repository_project_id())
        except DoesNotExist as err:
            cla.log.warning(
                f'{func_name} - unable to load project (cla_group) by '
                f'project_id: {repo.get_repository_project_id()}, error: {err}'
            )

        msg = (
            f'Disabling repository {repo.get_repository_name()} '
            f'from GitHub organization : {repo.get_repository_organization_name()} '
            f'with URL: {repo.get_repository_url()} '
            'from the CLA configuration.')
        cla.log.debug(msg)
        # Disable the repo and add a note
        repo.set_enabled(False)
        repo.add_note(f'{datetime.now()}  - Disabling repository due to '
                      'GitHub installation_repositories delete event '
                      f'for CLA Group {project_model.get_project_name()}')
        repo.save()

        # Log the event
        Event.create_event(
            event_type=EventType.RepositoryDisable,
            event_project_id=repo.get_repository_project_id(),
            event_project_name=project_model.get_project_name(),
            event_company_id=None,
            event_data=msg,
            event_summary=msg,
            event_user_id=user_login,
            contains_pii=False,
        )
예제 #10
0
파일: project.py 프로젝트: geva/easycla
def update_project(project_id,
                   project_name=None,
                   project_icla_enabled=None,
                   project_ccla_enabled=None,
                   project_ccla_requires_icla_signature=None,
                   username=None):
    """
    Updates a project and returns the newly updated project in dict format.
    A value of None means the field should not be updated.

    :param project_id: ID of the project to update.
    :type project_id: string
    :param project_name: New project name.
    :type project_name: string | None
    :param project_icla_enabled: Whether or not the project supports ICLAs.
    :type project_icla_enabled: bool | None
    :param project_ccla_enabled: Whether or not the project supports CCLAs.
    :type project_ccla_enabled: bool | None
    :param project_ccla_requires_icla_signature: Whether or not the project requires ICLA with CCLA.
    :type project_ccla_requires_icla_signature: bool | None
    :return: dict representation of the project object.
    :rtype: dict
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    updated_string = " "
    if project_name is not None:
        project.set_project_name(project_name)
        updated_string += f"project_name changed to {project_name} \n"
    if project_icla_enabled is not None:
        project.set_project_icla_enabled(project_icla_enabled)
        updated_string += f"project_icla_enabled changed to {project_icla_enabled} \n"
    if project_ccla_enabled is not None:
        project.set_project_ccla_enabled(project_ccla_enabled)
        updated_string += f"project_ccla_enabled changed to {project_ccla_enabled} \n"
    if project_ccla_requires_icla_signature is not None:
        project.set_project_ccla_requires_icla_signature(
            project_ccla_requires_icla_signature)
        updated_string += f"project_ccla_requires_icla_signature changed to {project_ccla_requires_icla_signature} \n"
    project.save()

    # Create audit trail
    event_data = f'Project- {project_id} Updates: ' + updated_string
    Event.create_event(
        event_type=EventType.UpdateProject,
        event_project_id=project.get_project_id(),
        event_data=event_data,
        event_summary=event_data,
        contains_pii=False,
    )
    return project.to_dict()
예제 #11
0
def get_project(project_id, user_id=None):
    """
    Returns the CLA project requested by ID.

    :param project_id: The project's ID.
    :type project_id: string
    :return: dict representation of the project object.
    :rtype: dict
    """
    project = get_project_instance()
    try:
        project.load(project_id=str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    return project.to_dict()
예제 #12
0
파일: gerrit.py 프로젝트: geva/easycla
def get_agreement_html(gerrit_id, contract_type):
    console_v1_endpoint = cla.conf['CONTRIBUTOR_BASE_URL']
    console_v2_endpoint = cla.conf['CONTRIBUTOR_V2_BASE_URL']
    console_url = ''

    try:
        gerrit = get_gerrit_instance()
        cla.log.debug(f'get_agreement_html - {contract_type} - '
                      f'Loading gerrit record by gerrit id: {str(gerrit_id)}')
        gerrit.load(str(gerrit_id))
        cla.log.debug(
            f'get_agreement_html - {contract_type} - Loaded gerrit record: {str(gerrit)}'
        )
    except DoesNotExist as err:
        return {'errors': {'gerrit_id': str(err)}}

    try:
        project = get_project_instance()
        cla.log.debug(
            f'get_agreement_html - {contract_type} - '
            f'Loading project record by cla group id: {str(gerrit.get_project_id())}'
        )
        project.load(str(gerrit.get_project_id()))
        cla.log.debug(
            f'get_agreement_html - {contract_type} - Loaded project record: {str(project)}'
        )
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}

    # Temporary condition until all CLA Groups are ready for the v2 Contributor Console
    if project.get_version() == 'v2':
        # Generate url for the v2 console
        # Note: we pass the CLA Group (project_id) in the v2 API call, not the gerrit_id value
        console_url = (f'https://{console_v2_endpoint}/'
                       f'#/cla/gerrit/project/{gerrit.get_project_id()}/'
                       f'{contract_type}?redirect={gerrit.get_gerrit_url()}')
    else:
        # Generate url for the v1 contributor console
        # Note: we pass the Gerrit ID in the v1 API call, not the CLA Group (project_id) value
        console_url = (f'https://{console_v1_endpoint}/'
                       f'#/cla/gerrit/project/{gerrit.get_project_id()}/'
                       f'{contract_type}?redirect={gerrit.get_gerrit_url()}')

    cla.log.debug(f'redirecting user to: {console_url}')
    contract_type_title = contract_type.title()

    return f"""
예제 #13
0
def delete_project(project_id, username=None):
    """
    Deletes an project based on ID.

    :TODO: Need to also delete the documents saved with the storage provider.

    :param project_id: The ID of the project.
    :type project_id: string
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    project.delete()
    return {'success': True}
예제 #14
0
파일: project.py 프로젝트: geva/easycla
def delete_project_document(project_id,
                            document_type,
                            major_version,
                            minor_version,
                            username=None):
    """
    Deletes the document from the specified project.

    :param project_id: The ID of the project in question.
    :type project_id: string
    :param document_type: The type of document to remove (individual or corporate).
    :type document_type: string
    :param major_version: The document major version number to remove.
    :type major_version: integer
    :param minor_version: The document minor version number to remove.
    :type minor_version: integer
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    document = cla.utils.get_project_document(project, document_type,
                                              major_version, minor_version)
    if document is None:
        return {'errors': {'document': 'Document version not found'}}
    if document_type == 'individual':
        project.remove_project_individual_document(document)
    else:
        project.remove_project_corporate_document(document)
    project.save()

    event_data = (
        f'Project {project.get_project_name()} with {document_type} :' +
        f'document type , minor version : {minor_version}, major version : {major_version}  deleted'
    )

    Event.create_event(
        event_data=event_data,
        event_summary=event_data,
        event_project_id=project_id,
        event_type=EventType.DeleteProjectDocument,
        contains_pii=False,
    )
    return {'success': True}
예제 #15
0
파일: project.py 프로젝트: geva/easycla
def create_project(project_external_id, project_name, project_icla_enabled,
                   project_ccla_enabled, project_ccla_requires_icla_signature,
                   project_acl_username):
    """
    Creates a project and returns the newly created project in dict format.

    :param project_external_id: The project's external ID.
    :type project_external_id: string
    :param project_name: The project's name.
    :type project_name: string
    :param project_icla_enabled: Whether or not the project supports ICLAs.
    :type project_icla_enabled: bool
    :param project_ccla_enabled: Whether or not the project supports CCLAs.
    :type project_ccla_enabled: bool
    :param project_ccla_requires_icla_signature: Whether or not the project requires ICLA with CCLA.
    :type project_ccla_requires_icla_signature: bool
    :return: dict representation of the project object.
    :rtype: dict
    """
    project = get_project_instance()
    project.set_project_id(str(uuid.uuid4()))
    project.set_project_external_id(str(project_external_id))
    project.set_project_name(project_name)
    project.set_project_icla_enabled(project_icla_enabled)
    project.set_project_ccla_enabled(project_ccla_enabled)
    project.set_project_ccla_requires_icla_signature(
        project_ccla_requires_icla_signature)
    project.set_project_acl(project_acl_username)
    project.save()

    # Create audit trail
    event_data = 'Project-{} created'.format(project_name)
    Event.create_event(
        event_type=EventType.CreateProject,
        event_project_id=project.get_project_id(),
        event_data=event_data,
        event_summary=event_data,
        contains_pii=False,
    )

    return project.to_dict()
예제 #16
0
def update_project(project_id,
                   project_name=None,
                   project_icla_enabled=None,
                   project_ccla_enabled=None,
                   project_ccla_requires_icla_signature=None,
                   username=None):
    """
    Updates a project and returns the newly updated project in dict format.
    A value of None means the field should not be updated.

    :param project_id: ID of the project to update.
    :type project_id: string
    :param project_name: New project name.
    :type project_name: string | None
    :param project_icla_enabled: Whether or not the project supports ICLAs.
    :type project_icla_enabled: bool | None
    :param project_ccla_enabled: Whether or not the project supports CCLAs.
    :type project_ccla_enabled: bool | None
    :param project_ccla_requires_icla_signature: Whether or not the project requires ICLA with CCLA.
    :type project_ccla_requires_icla_signature: bool | None
    :return: dict representation of the project object.
    :rtype: dict
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    if project_name is not None:
        project.set_project_name(project_name)
    if project_icla_enabled is not None:
        project.set_project_icla_enabled(project_icla_enabled)
    if project_ccla_enabled is not None:
        project.set_project_ccla_enabled(project_ccla_enabled)
    if project_ccla_requires_icla_signature is not None:
        project.set_project_ccla_requires_icla_signature(
            project_ccla_requires_icla_signature)
    project.save()
    return project.to_dict()
예제 #17
0
def test_create_event():
    """
    Test endpoint that creates event instance
    """
    url = "/v1/events"
    event_project_id = str(uuid.uuid4())
    event_company_id = str(uuid.uuid4())
    user_id = str(uuid.uuid4())

    payload = {
        "event_type": "cla",
        "event_company_id": event_company_id,
        "event_project_id": event_project_id,
        "user_id": user_id,
        "event_data": json.dumps({"foo": "bar"}),
    }

    response = hug.test.post(routes, url, payload)
    assert response.status == HTTP_400

    user = get_user_instance()
    user.set_user_id(user_id)
    user.save()
    company = get_company_instance()
    company.set_company_id(event_company_id)
    company.set_company_name("foobar")
    company.save()
    project = get_project_instance()
    project.set_project_name("project")
    project.set_project_external_id(str(uuid.uuid4()))
    project.set_project_id(event_project_id)
    project.save()
    response = hug.test.post(routes, url, payload)
    assert response.status == HTTP_200
    assert response.data["data"]["event_type"] == "cla"
    assert response.data["data"]["event_company_id"] == event_company_id
    assert response.data["data"]["event_project_id"] == event_project_id
    assert response.data["data"]["user_id"] == user_id
    assert response.data["data"]["event_data"] == json.dumps({"foo": "bar"})
예제 #18
0
# Copyright The Linux Foundation and each contributor to CommunityBridge.
# SPDX-License-Identifier: MIT

# Project external ID.
PROJECT_EXTERNAL_ID = 'a090t0000008DEiAAM'
# The GitHub user/org used for testing purposes.
GITHUB_ORGANIZATION_NAME = 'linuxfoundation'
GITHUB_INSTALLATION_ID = 74230  # NOT THE APP ID - find it in the webhook request JSON or URL when viewing installed apps.

import sys
sys.path.append('../')

import cla
from cla.utils import get_project_instance, get_github_organization_instance

# Organisation
project = get_project_instance().get_projects_by_external_id(
    PROJECT_EXTERNAL_ID)[0]
cla.log.info('Creating GitHub Organization: %s' % GITHUB_ORGANIZATION_NAME)
github_org = get_github_organization_instance()
github_org.set_organization_name(GITHUB_ORGANIZATION_NAME)
github_org.set_organization_project_id(project.get_project_id())
# This will be different everytime the CLA app is installed.
github_org.set_organization_installation_id(GITHUB_INSTALLATION_ID)
github_org.save()
예제 #19
0
def post_project_document_template(project_id,
                                   document_type,
                                   document_name,
                                   document_preamble,
                                   document_legal_entity_name,
                                   template_name,
                                   new_major_version=None,
                                   username=None):
    """
    Will create a new document for the project specified, using the existing template.

    :param project_id: The ID of the project to add this document to.
    :type project_id: string
    :param document_type: The type of document (individual or corporate).
    :type document_type: string
    :param document_name: The name of this new document.
    :type document_name: string
    :param document_preamble: The document preamble.
    :type document_preamble: string
    :param document_legal_entity_name: The legal entity name on the document.
    :type document_legal_entity_name: string
    :param template_name: The name of the template object to use.
    :type template_name: string
    :param new_major_version: Whether or not to bump up the major version.
    :type new_major_version: boolean
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    document = get_document_instance()
    document.set_document_name(document_name)
    document.set_document_preamble(document_preamble)
    document.set_document_legal_entity_name(document_legal_entity_name)
    if document_type == 'individual':
        major, minor = cla.utils.get_last_version(project.get_project_individual_documents())
        if new_major_version:
            document.set_document_major_version(major + 1)
            document.set_document_minor_version(0)
        else:
            document.set_document_minor_version(minor + 1)
        project.add_project_individual_document(document)
    else:
        major, minor = cla.utils.get_last_version(project.get_project_corporate_documents())
        if new_major_version:
            document.set_document_major_version(major + 1)
            document.set_document_minor_version(0)
        else:
            document.set_document_minor_version(minor + 1)
        project.add_project_corporate_document(document)
    # Need to take the template, inject the preamble and legal entity name, and add the tabs.
    tmplt = getattr(cla.resources.contract_templates, template_name)
    template = tmplt(document_type=document_type.capitalize(),
                     major_version=document.get_document_major_version(),
                     minor_version=document.get_document_minor_version())
    content = template.get_html_contract(document_legal_entity_name, document_preamble)
    pdf_generator = get_pdf_service()
    pdf_content = pdf_generator.generate(content)
    document.set_document_content_type('storage+pdf')
    document.set_document_content(pdf_content, b64_encoded=False)
    document.set_raw_document_tabs(template.get_tabs())
    project.save()

    # Create audit trail
    event_data = 'Project Document created for project {} created with template {}'.format(
        project.get_project_name(), template_name)
    Event.create_event(
        event_type=EventType.CreateProjectDocumentTemplate,
        event_project_id=project.get_project_id(),
        event_data=event_data,
        contains_pii=False,
    )
    return project.to_dict()
예제 #20
0
# Copyright The Linux Foundation and each contributor to CommunityBridge.
# SPDX-License-Identifier: MIT

# Project external ID.
PROJECT_EXTERNAL_ID1 = 'a090t0000008DEiAAM'
PROJECT_EXTERNAL_ID2 = 'a090t0000008E7iAAE'

import sys

sys.path.append('../')

import uuid
import cla
from cla.utils import get_project_instance

## Project
cla.log.info('Creating first project for %s', PROJECT_EXTERNAL_ID1)
github_project = get_project_instance()
github_project.set_project_id(str(uuid.uuid4()))
github_project.set_project_external_id(PROJECT_EXTERNAL_ID1)
github_project.set_project_name('Test Project One')
github_project.set_project_ccla_requires_icla_signature(False)
github_project.save()
cla.log.info('Creating second project for %s', PROJECT_EXTERNAL_ID2)
github_project = get_project_instance()
github_project.set_project_id(str(uuid.uuid4()))
github_project.set_project_external_id(PROJECT_EXTERNAL_ID2)
github_project.set_project_name('Test Project Two')
github_project.set_project_ccla_requires_icla_signature(True)
github_project.save()
예제 #21
0
def post_project_document(project_id,
                          document_type,
                          document_name,
                          document_content_type,
                          document_content,
                          document_preamble,
                          document_legal_entity_name,
                          new_major_version=None,
                          username=None):
    """
    Will create a new document for the project specified.

    :param project_id: The ID of the project to add this document to.
    :type project_id: string
    :param document_type: The type of document (individual or corporate).
    :type document_type: string
    :param document_name: The name of this new document.
    :type document_name: string
    :param document_content_type: The content type of this document ('pdf', 'url+pdf',
        'storage+pdf', etc).
    :type document_content_type: string
    :param document_content: The content of the document (or URL to content if content type
        starts with 'url+'.
    :type document_content: string or binary data
    :param document_preamble: The document preamble.
    :type document_preamble: string
    :param document_legal_entity_name: The legal entity name on the document.
    :type document_legal_entity_name: string
    :param new_major_version: Whether or not to bump up the major version.
    :type new_major_version: boolean
    """
    project = get_project_instance()
    try:
        project.load(str(project_id))
    except DoesNotExist as err:
        return {'errors': {'project_id': str(err)}}
    project_acl_verify(username, project)
    document = get_document_instance()
    document.set_document_name(document_name)
    document.set_document_content_type(document_content_type)
    document.set_document_content(document_content)
    document.set_document_preamble(document_preamble)
    document.set_document_legal_entity_name(document_legal_entity_name)
    if document_type == 'individual':
        major, minor = cla.utils.get_last_version(project.get_project_individual_documents())
        if new_major_version:
            document.set_document_major_version(major + 1)
            document.set_document_minor_version(0)
        else:
            if major == 0:
                major = 1
            document.set_document_major_version(major)
            document.set_document_minor_version(minor + 1)
        project.add_project_individual_document(document)
    else:
        major, minor = cla.utils.get_last_version(project.get_project_corporate_documents())
        if new_major_version:
            document.set_document_major_version(major + 1)
            document.set_document_minor_version(0)
        else:
            if major == 0:
                major = 1
            document.set_document_major_version(major)
            document.set_document_minor_version(minor + 1)
        project.add_project_corporate_document(document)
    project.save()

    # Create audit trail
    event_data = 'Created new document for Project-{} '.format(project.get_project_name())
    Event.create_event(
        event_type=EventType.CreateProjectDocument,
        event_project_id=project.get_project_id(),
        event_data=event_data,
        contains_pii=False,
    )
    return project.to_dict()
예제 #22
0
def return_url(signature_id, event=None):  # pylint: disable=unused-argument
    """
    Handle the GET request from the user once they have successfully signed.

    :param signature_id: The ID of the signature they have just signed.
    :type signature_id: string
    :param event: The event GET flag sent back from the signing service provider.
    :type event: string | None
    """
    fn = 'return_url'
    try:  # Load the signature based on ID.
        signature = get_signature_instance()
        signature.load(str(signature_id))
    except DoesNotExist as err:
        cla.log.error('%s - Invalid signature_id provided when trying to send user back to their ' + \
                      'return_url after signing: %s', fn, signature_id)
        return {'errors': {'signature_id': str(err)}}
    # Ensure everything went well on the signing service provider's side.
    if event is not None:
        # Expired signing URL - the user was redirected back immediately but still needs to sign.
        if event == 'ttl_expired' and not signature.get_signature_signed():
            # Need to re-generate a sign_url and try again.
            cla.log.info(
                'DocuSign URL used was expired, re-generating sign_url')
            callback_url = signature.get_signature_callback_url()
            get_signing_service().populate_sign_url(signature, callback_url)
            signature.save()
            raise falcon.HTTPFound(signature.get_signature_sign_url())
        if event == 'cancel':
            return canceled_signature_html(signature=signature)
    ret_url = signature.get_signature_return_url()
    if ret_url is not None:
        cla.log.info('%s- Signature success - sending user to return_url: %s',
                     fn, ret_url)
        try:
            project = get_project_instance()
            project.load(str(signature.get_signature_project_id()))
        except DoesNotExist as err:
            cla.log.error('%s - Invalid project_id provided when trying to send user back to'\
                        'their return_url : %s', fn, signature.get_signature_project_id())

        if project.get_version() == 'v2':
            if signature.get_signature_reference_type() == 'company':
                cla.log.info('%s - Getting company instance : %s ', fn,
                             signature.get_signature_reference_id())
                try:
                    company = get_company_instance()
                    company.load(str(signature.get_signature_reference_id()))
                except DoesNotExist as err:
                    cla.log.error('%s - Invalid company_id provided : err: %s',
                                  fn, signature.get_signature_reference_id)
                user_service = UserService
                cla.log.info(
                    '%s - Checking if cla managers have cla-manager role permission',
                    fn)
                num_tries = 10
                i = 1
                cla.log.info(
                    f'{fn} - checking if managers:{signature.get_signature_acl()} have roles with {num_tries} tries'
                )
                while i <= num_tries:
                    cla.log.info(f'{fn} - check try #: {i}')
                    assigned = {}
                    for manager in signature.get_signature_acl():
                        cla.log.info(
                            f'{fn}- Checking {manager} for {CLA_MANAGER_ROLE} for company: {company.get_company_external_id()}, cla_group_id: {signature.get_signature_project_id()}'
                        )
                        assigned[manager] = user_service.has_role(
                            manager, CLA_MANAGER_ROLE,
                            company.get_company_external_id(),
                            signature.get_signature_project_id())
                    cla.log.info(f'{fn} - Assigned status : {assigned}')
                    #Ensure that assigned list doesnt have any False values -> All Managers have role assigned
                    if all(list(assigned.values())):
                        cla.log.info(
                            f'All managers have cla-manager role for company: {company.get_company_external_id()} and cla_group_id: {signature.get_signature_project_id()}'
                        )
                        break
                    time.sleep(0.5)
                    i += 1

        raise falcon.HTTPFound(ret_url)
    cla.log.info('No return_url set for signature - returning success message')
    return {'success': 'Thank you for signing'}
예제 #23
0
import sys

sys.path.append('../')

import uuid
import cla
from cla.utils import get_project_instance, get_user_instance, get_document_instance, get_github_organization_instance, get_project_instance, get_pdf_service, get_company_instance, get_signature_instance
from cla.resources.contract_templates import CNCFTemplate

# Project external ID.
PROJECT_EXTERNAL_ID = 'a0941000002wByZAAU'

## Project
cla.log.info('Creating first project for %s', PROJECT_EXTERNAL_ID)
project = get_project_instance()
project.set_project_id(str(uuid.uuid4()))
project.set_project_external_id(PROJECT_EXTERNAL_ID)
project.set_project_name('Test Project One')
project.set_project_ccla_requires_icla_signature(False)
project.save()

## Create CCLA Document
corporate_template = CNCFTemplate(document_type='Corporate',
                                  major_version=1,
                                  minor_version=0)
content = corporate_template.get_html_contract("", "")
pdf_generator = get_pdf_service()
pdf_content = pdf_generator.generate(content)

## CCLA
예제 #24
0
파일: github.py 프로젝트: wanyaland/easycla
def handle_installation_repositories_added_event(action: str, body: dict):
    func_name = 'github.activity.handle_installation_repositories_added_event'
    # Who triggered the event
    user_login = body['sender']['login']
    cla.log.debug(f'{func_name} - processing github [installation_repositories] '
                  f'activity {action} callback created by GitHub user {user_login}.')
    # Grab the list of repositories added from the event model
    repository_added = body.get('repositories_added', [])
    # Create a unique list of repositories for the email that we need to send out
    repository_list = set([repo.get('full_name', None) for repo in repository_added])
    # All the repos in the message should be under the same GitHub Organization
    organization_name = ''
    for repo in repository_added:
        # Grab the information
        repository_external_id = repo['id']  # example: 271841254
        repository_name = repo['name']  # example: PyImath
        repository_full_name = repo['full_name']  # example: AcademySoftwareFoundation/PyImath
        organization_name = repository_full_name.split('/')[0]  # example: AcademySoftwareFoundation
        # repository_private = repo['private']      # example: False

        # Lookup the GitHub Organization in our table - should be there already
        cla.log.debug(f'{func_name} - Locating organization using name: {organization_name}')
        org_model = get_organization_model(organization_name)

        if org_model is None:
            # Should we create since it's missing?
            cla.log.warning(f'Unable to locate GitHub Organization {organization_name} in our database')
            continue

        # Should we update to ensure the installation_id is set?
        if org_model.get_organization_installation_id() is None:
            # Update the installation ID
            org_model.set_organization_installation_id(body.get('installation', {}).get('id', None))
            org_model.save()

        # Check to see if the auto enabled flag is set
        if org_model.get_auto_enabled():
            # We need to check that we only have 1 CLA Group - auto-enable only works when the entire
            # Organization falls under a single CLA Group - otherwise, how would we know which CLA Group
            # to add them to? First we query all the existing repositories associated with this Github Org -
            # they should all point the the single CLA Group - let's verify this...
            existing_github_repositories = Repository().get_repositories_by_organization(organization_name)
            cla_group_ids = set(())  # hoping for only 1 unique value - set collection discards duplicates
            cla_group_repo_sfids = set(())  # keep track of the existing SFDC IDs from existing repos
            for existing_repo in existing_github_repositories:
                cla_group_ids.add(existing_repo.get_repository_project_id())
                cla_group_repo_sfids.add(existing_repo.get_repository_sfdc_id())

            # We should only have one...
            if len(cla_group_ids) != 1 or len(cla_group_repo_sfids) != 1:
                cla.log.warning(f'{func_name} - Auto Enabled set for Organization {organization_name}, '
                                f'but we found repositories or SFIDs that belong to multiple CLA Groups. '
                                'Auto Enable only works when all repositories under a given '
                                'GitHub Organization are associated with a single CLA Group. This '
                                f'organization is associated with {len(cla_group_ids)} CLA Groups and '
                                f'{len(cla_group_repo_sfids)} SFIDs.')
                return

            cla_group_id = cla_group_ids.pop()

            project_model = get_project_instance()
            try:
                project_model.load(project_id=cla_group_id)
            except DoesNotExist as err:
                cla.log.warning(f'{func_name} - unable to load project (cla_group) by '
                                f'project_id: {cla_group_id}, error: {err}')

            cla.log.debug(f'{func_name} - Organization {organization_name} has auto_enabled set - '
                          f'adding repository: {repository_name} to '
                          f'CLA Group: {project_model.get_project_name()}')
            try:
                # Create the new repository entry and associate it with the CLA Group
                new_repository = Repository(
                    repository_id=str(uuid.uuid4()),
                    repository_project_id=cla_group_id,
                    repository_name=repository_full_name,
                    repository_type='github',
                    repository_url='https://github.com/' + repository_full_name,
                    repository_organization_name=organization_name,
                    repository_external_id=repository_external_id,
                    repository_sfdc_id=cla_group_repo_sfids.pop(),
                )
                new_repository.set_enabled(True)
                new_repository.save()

                # Log the event
                msg = (f'Adding repository {repository_full_name} '
                       f'from GitHub organization : {organization_name} '
                       f'with URL: https://github.com/{repository_full_name} '
                       'to the CLA configuration. GitHub organization was set to auto-enable.')
                Event.create_event(
                    event_type=EventType.RepositoryAdded,
                    event_project_id=cla_group_id,
                    event_project_name=project_model.get_project_name(),
                    event_company_id=None,
                    event_data=msg,
                    event_summary=msg,
                    event_user_id=user_login,
                    contains_pii=False,
                )
            except Exception as err:
                cla.log.warning(f'{func_name} - Could not create GitHub repository: {err}')
                return

        else:
            cla.log.debug(f'{func_name} - Auto enabled NOT set for GitHub Organization {organization_name} - '
                          f'not auto-adding repository: {repository_full_name}')
            return

    # Notify the Project Managers
    notify_project_managers_auto_enabled(organization_name, repository_list)
예제 #25
0
"""
import uuid
import sys
sys.path.append('../')

import cla
from cla.utils import get_signature_instance, get_user_instance, get_project_instance, \
                      get_company_instance

PROJECT_EXTERNAL_ID1 = 'a090t0000008DEiAAM'
PROJECT_EXTERNAL_ID2 = 'a090t0000008E7iAAE'
COMPANY_EXTERNAL_ID = 'company-external-id'
USER_GITHUB_ID = 123

user = get_user_instance().get_user_by_github_id(USER_GITHUB_ID)
project1 = get_project_instance().get_projects_by_external_id(PROJECT_EXTERNAL_ID1)[0]
project2 = get_project_instance().get_projects_by_external_id(PROJECT_EXTERNAL_ID2)[0]
company = get_company_instance().get_company_by_external_id(COMPANY_EXTERNAL_ID)

# Test ICLA Agreement.
sig_id = str(uuid.uuid4())
cla.log.info('Creating ICLA signature for user %s and project %s: %s' \
             %(user.get_user_name(), project1.get_project_external_id(), sig_id))
signature = get_signature_instance()
signature.set_signature_id(sig_id)
signature.set_signature_project_id(project1.get_project_id())
signature.set_signature_signed(True)
signature.set_signature_approved(True)
signature.set_signature_type('cla')
signature.set_signature_reference_id(user.get_user_id())
signature.set_signature_reference_type('user')
예제 #26
0
def main(
    aws_region,
    rds_database,
    rds_host,
    rds_username,
    rds_password,
    rds_port,
    dry_run,
):
    """
    This script runs data migration from dynamodb to postgresql
    """

    if os.environ.get("STAGE") is None:
        logger.warning(
            "Please set the 'STAGE' environment varaible - typically one of: {dev, staging, prod}"
        )
        return

    stage = os.environ.get("STAGE")

    if dry_run:
        exit_cmd = input(
            "This is a dry run. "
            "You are running the script for the '{}' environment. "
            'Press <ENTER> to continue ("exit" to exit): '.format(stage))
    else:
        exit_cmd = input(
            "This is NOT a dry run. "
            "You are running the script for the '{}' environment. "
            'Press <ENTER> to continue ("exit" to exit): '.format(stage))
    if exit_cmd == "exit":
        return

    start_time = datetime.now()
    lock = threading.Lock()
    threads = []
    count = 0
    for _ in range(IMPORT_THREADS):
        connection = psycopg2.connect(
            database=rds_database,
            host=rds_host,
            user=rds_username,
            password=rds_password,
            port=rds_port,
        )
        cursor = connection.cursor()
        worker = Thread(target=import_to_pg,
                        args=(connection, cursor, tables_queues, dry_run))
        worker.start()
        threads.append(worker)

    # TODO: cla models for signature,company-invitations and user-permissions
    try:
        user = utils.get_user_instance()
        company = utils.get_company_instance()
        project = utils.get_project_instance()
        repository = utils.get_repository_instance()
        github_orgs = utils.get_github_organization_instance()
        gerrit = utils.get_gerrit_instance()
        #signature = utils.get_signature_instance()
        update_queue(user.all())
        update_queue(company.all())
        update_queue(project.all())
        #update_queue(signature.all())
        update_queue(repository.all())
        update_queue(gerrit.all())
        update_queue(github_orgs.all())
        # block until all tasks are done
        tables_queues.join()
    except Exception as err:
        logger.error(err)

    # End workers
    for _ in range(IMPORT_THREADS):
        tables_queues.put(None)
    for thread in threads:
        thread.join()

    duration = datetime.now() - start_time
    logger.info(
        "Data migration to the pg database run for a duration of {} ".format(
            duration))