示例#1
0
    def ProcessFormData(self, mr, post_data):
        """Process the posted form."""
        # 1. Parse and validate user input.
        summary, description = self._ParseMeta(post_data, mr.errors)
        access = project_helpers.ParseProjectAccess(mr.project,
                                                    post_data.get('access'))

        only_owners_remove_restrictions = ('only_owners_remove_restrictions'
                                           in post_data)
        only_owners_see_contributors = 'only_owners_see_contributors' in post_data

        issue_notify = post_data['issue_notify']
        if issue_notify and not validate.IsValidEmail(issue_notify):
            mr.errors.issue_notify = _MSG_INVALID_EMAIL_ADDRESS

        process_inbound_email = 'process_inbound_email' in post_data
        home_page = post_data.get('project_home')
        if home_page and not (home_page.startswith('http:')
                              or home_page.startswith('https:')):
            mr.errors.project_home = 'Home page link must start with http: or https:'
        docs_url = post_data.get('docs_url')
        if docs_url and not (docs_url.startswith('http:')
                             or docs_url.startswith('https:')):
            mr.errors.docs_url = 'Documentation link must start with http: or https:'
        source_url = post_data.get('source_url')
        if source_url and not (source_url.startswith('http:')
                               or source_url.startswith('https:')):
            mr.errors.source_url = 'Source link must start with http: or https:'

        logo_gcs_id = ''
        logo_file_name = ''
        if 'logo' in post_data and not isinstance(post_data['logo'],
                                                  basestring):
            item = post_data['logo']
            logo_file_name = item.filename
            try:
                logo_gcs_id = gcs_helpers.StoreLogoInGCS(
                    logo_file_name, item.value, mr.project.project_id)
            except gcs_helpers.UnsupportedMimeType, e:
                mr.errors.logo = e.message
    def testStoreLogoInGCS(self):
        file_name = 'test_file.png'
        mime_type = 'image/png'
        content = 'test content'
        project_id = 100
        object_id = 123

        self.mox.StubOutWithMock(filecontent, 'GuessContentTypeFromFilename')
        filecontent.GuessContentTypeFromFilename(file_name).AndReturn(
            mime_type)

        self.mox.StubOutWithMock(gcs_helpers, 'StoreObjectInGCS')
        gcs_helpers.StoreObjectInGCS(
            content,
            mime_type,
            project_id,
            thumb_width=gcs_helpers.LOGO_THUMB_WIDTH,
            thumb_height=gcs_helpers.LOGO_THUMB_HEIGHT).AndReturn(object_id)

        self.mox.ReplayAll()

        ret_id = gcs_helpers.StoreLogoInGCS(file_name, content, project_id)
        self.mox.VerifyAll()
        self.assertEquals(object_id, ret_id)
示例#3
0
class ProjectCreate(servlet.Servlet):
    """Shows a page with a simple form to create a project."""

    _PAGE_TEMPLATE = 'sitewide/project-create-page.ezt'

    def AssertBasePermission(self, mr):
        """Assert that the user has the permissions needed to view this page."""
        super(ProjectCreate, self).AssertBasePermission(mr)

        if not permissions.CanCreateProject(mr.perms):
            raise permissions.PermissionException(
                'User is not allowed to create a project')

    def GatherPageData(self, _mr):
        """Build up a dictionary of data values to use when rendering the page."""
        available_access_levels = project_helpers.BuildProjectAccessOptions(
            None)
        offer_access_level = len(available_access_levels) > 1
        if settings.default_access_level:
            access_view = project_views.ProjectAccessView(
                settings.default_access_level)
        else:
            access_view = None

        return {
            'initial_name': '',
            'initial_summary': '',
            'initial_description': '',
            'initial_project_home': '',
            'initial_docs_url': '',
            'initial_source_url': '',
            'initial_logo_gcs_id': '',
            'initial_logo_file_name': '',
            'logo_view': tracker_views.LogoView(None),
            'labels': [],
            'max_project_name_length':
            framework_constants.MAX_PROJECT_NAME_LENGTH,
            'offer_access_level': ezt.boolean(offer_access_level),
            'initial_access': access_view,
            'available_access_levels': available_access_levels,
        }

    def ProcessFormData(self, mr, post_data):
        """Process the posted form."""
        # 1. Parse and validate user input.
        # Project name is taken from post_data because we are creating it.
        project_name = post_data.get('projectname')
        if not project_name:
            mr.errors.projectname = _MSG_MISSING_PROJECT_NAME
        elif not framework_bizobj.IsValidProjectName(project_name):
            mr.errors.projectname = _MSG_INVALID_PROJECT_NAME

        summary = post_data.get('summary')
        if not summary:
            mr.errors.summary = _MSG_MISSING_PROJECT_SUMMARY
        description = post_data.get('description', '')

        access = project_helpers.ParseProjectAccess(None,
                                                    post_data.get('access'))
        home_page = post_data.get('project_home')
        if home_page and not (home_page.startswith('http://')
                              or home_page.startswith('https://')):
            mr.errors.project_home = 'Home page link must start with http(s)://'
        docs_url = post_data.get('docs_url')
        if docs_url and not (docs_url.startswith('http:')
                             or docs_url.startswith('https:')):
            mr.errors.docs_url = 'Documentation link must start with http: or https:'

        # These are not specified on via the ProjectCreate form,
        # the user must edit the project after creation to set them.
        committer_ids = []
        contributor_ids = []

        # Validate that provided logo is supported.
        logo_provided = 'logo' in post_data and not isinstance(
            post_data['logo'], string_types)
        if logo_provided:
            item = post_data['logo']
            try:
                gcs_helpers.CheckMimeTypeResizable(
                    filecontent.GuessContentTypeFromFilename(item.filename))
            except gcs_helpers.UnsupportedMimeType, e:
                mr.errors.logo = e.message

        # 2. Call services layer to save changes.
        if not mr.errors.AnyErrors():
            with work_env.WorkEnv(mr, self.services) as we:
                try:
                    project_id = we.CreateProject(project_name,
                                                  [mr.auth.user_id],
                                                  committer_ids,
                                                  contributor_ids,
                                                  summary,
                                                  description,
                                                  access=access,
                                                  home_page=home_page,
                                                  docs_url=docs_url)

                    config = tracker_bizobj.MakeDefaultProjectIssueConfig(
                        project_id)
                    self.services.config.StoreConfig(mr.cnxn, config)
                    # Note: No need to store any canned queries or rules yet.
                    self.services.issue.InitializeLocalID(mr.cnxn, project_id)

                    # Update project with  logo if specified.
                    if logo_provided:
                        item = post_data['logo']
                        logo_file_name = item.filename
                        logo_gcs_id = gcs_helpers.StoreLogoInGCS(
                            logo_file_name, item.value, project_id)
                        we.UpdateProject(project_id,
                                         logo_gcs_id=logo_gcs_id,
                                         logo_file_name=logo_file_name)

                except exceptions.ProjectAlreadyExists:
                    mr.errors.projectname = _MSG_PROJECT_NAME_NOT_AVAIL

        # 3. Determine the next page in the UI flow.
        if mr.errors.AnyErrors():
            access_view = project_views.ProjectAccessView(access)
            self.PleaseCorrect(mr,
                               initial_summary=summary,
                               initial_description=description,
                               initial_name=project_name,
                               initial_access=access_view)
        else:
            # Go to the new project's introduction page.
            return framework_helpers.FormatAbsoluteURL(
                mr, urls.ADMIN_INTRO, project_name=project_name)
示例#4
0
class ProjectCreate(servlet.Servlet):
    """Shows a page with a simple form to create a project."""

    _PAGE_TEMPLATE = 'sitewide/project-create-page.ezt'

    _CAPTCHA_ACTION_TYPES = [actionlimit.PROJECT_CREATION]

    def AssertBasePermission(self, mr):
        """Assert that the user has the permissions needed to view this page."""
        super(ProjectCreate, self).AssertBasePermission(mr)

        if not permissions.CanCreateProject(mr.perms):
            raise permissions.PermissionException(
                'User is not allowed to create a project')

    def GatherPageData(self, _mr):
        """Build up a dictionary of data values to use when rendering the page."""
        available_access_levels = project_helpers.BuildProjectAccessOptions(
            None)
        offer_access_level = len(available_access_levels) > 1
        if settings.default_access_level:
            access_view = project_views.ProjectAccessView(
                settings.default_access_level)
        else:
            access_view = None

        return {
            'initial_name': '',
            'initial_summary': '',
            'initial_description': '',
            'initial_project_home': '',
            'initial_docs_url': '',
            'initial_source_url': '',
            'initial_logo_gcs_id': '',
            'initial_logo_file_name': '',
            'logo_view': tracker_views.LogoView(None),
            'labels': [],
            'max_project_name_length':
            framework_constants.MAX_PROJECT_NAME_LENGTH,
            'offer_access_level': ezt.boolean(offer_access_level),
            'initial_access': access_view,
            'available_access_levels': available_access_levels,
        }

    def GatherHelpData(self, mr, page_data):
        """Return a dict of values to drive on-page user help.

    Args:
      mr: common information parsed from the HTTP request.
      page_data: Dictionary of base and page template data.

    Returns:
      A dict of values to drive on-page user help, to be added to page_data.
    """
        help_data = super(ProjectCreate, self).GatherHelpData(mr, page_data)
        cue_remaining_projects = None

        (_period, _soft, _hard,
         life_max) = actionlimit.ACTION_LIMITS[actionlimit.PROJECT_CREATION]
        actionlimit_pb = actionlimit.GetLimitPB(mr.auth.user_pb,
                                                actionlimit.PROJECT_CREATION)
        if actionlimit_pb.get_assigned_value('lifetime_limit'):
            life_max = actionlimit_pb.lifetime_limit
        if life_max is not None:
            if (actionlimit_pb.lifetime_count + 10 >= life_max
                    and actionlimit_pb.lifetime_count < life_max):
                cue_remaining_projects = life_max - actionlimit_pb.lifetime_count

        help_data.update({
            'cue_remaining_projects': cue_remaining_projects,
        })
        return help_data

    def ProcessFormData(self, mr, post_data):
        """Process the posted form."""
        # 1. Parse and validate user input.
        # Project name is taken from post_data because we are creating it.
        project_name = post_data.get('projectname')
        if not project_name:
            mr.errors.projectname = _MSG_MISSING_PROJECT_NAME
        elif not framework_bizobj.IsValidProjectName(project_name):
            mr.errors.projectname = _MSG_INVALID_PROJECT_NAME

        summary = post_data.get('summary')
        if not summary:
            mr.errors.summary = _MSG_MISSING_PROJECT_SUMMARY
        description = post_data.get('description', '')

        access = project_helpers.ParseProjectAccess(None,
                                                    post_data.get('access'))
        home_page = post_data.get('project_home')
        if home_page and not (home_page.startswith('http://')
                              or home_page.startswith('https://')):
            mr.errors.project_home = 'Home page link must start with http(s)://'
        docs_url = post_data.get('docs_url')
        if docs_url and not (docs_url.startswith('http:')
                             or docs_url.startswith('https:')):
            mr.errors.docs_url = 'Documentation link must start with http: or https:'

        self.CheckCaptcha(mr, post_data)

        # These are not specified on via the ProjectCreate form,
        # the user must edit the project after creation to set them.
        committer_ids = []
        contributor_ids = []

        # Validate that provided logo is supported.
        logo_provided = 'logo' in post_data and not isinstance(
            post_data['logo'], basestring)
        if logo_provided:
            item = post_data['logo']
            try:
                gcs_helpers.CheckMimeTypeResizable(
                    filecontent.GuessContentTypeFromFilename(item.filename))
            except gcs_helpers.UnsupportedMimeType, e:
                mr.errors.logo = e.message

        # 2. Call services layer to save changes.
        if not mr.errors.AnyErrors():
            try:
                project_id = self.services.project.CreateProject(
                    mr.cnxn,
                    project_name, [mr.auth.user_id],
                    committer_ids,
                    contributor_ids,
                    summary,
                    description,
                    access=access,
                    home_page=home_page,
                    docs_url=docs_url)

                config = tracker_bizobj.MakeDefaultProjectIssueConfig(
                    project_id)
                self.services.config.StoreConfig(mr.cnxn, config)
                # Note: No need to store any canned queries or rules yet.
                self.services.issue.InitializeLocalID(mr.cnxn, project_id)

                # Update project with  logo if specified.
                if logo_provided:
                    item = post_data['logo']
                    logo_file_name = item.filename
                    logo_gcs_id = gcs_helpers.StoreLogoInGCS(
                        logo_file_name, item.value, project_id)
                    self.services.project.UpdateProject(
                        mr.cnxn,
                        project_id,
                        logo_gcs_id=logo_gcs_id,
                        logo_file_name=logo_file_name)

                self.CountRateLimitedActions(mr,
                                             {actionlimit.PROJECT_CREATION: 1})
            except project_svc.ProjectAlreadyExists:
                mr.errors.projectname = _MSG_PROJECT_NAME_NOT_AVAIL

        # 3. Determine the next page in the UI flow.
        if mr.errors.AnyErrors():
            access_view = project_views.ProjectAccessView(access)
            self.PleaseCorrect(mr,
                               initial_summary=summary,
                               initial_description=description,
                               initial_name=project_name,
                               initial_access=access_view)
        else:
            # Go to the new project's introduction page.
            return framework_helpers.FormatAbsoluteURL(
                mr, urls.ADMIN_INTRO, project_name=project_name)