def testAccessViews(self): anyone_view = project_views.ProjectAccessView( project_pb2.ProjectAccess.ANYONE) self.assertEqual(anyone_view.key, int(project_pb2.ProjectAccess.ANYONE)) members_only_view = project_views.ProjectAccessView( project_pb2.ProjectAccess.MEMBERS_ONLY) self.assertEqual(members_only_view.key, int(project_pb2.ProjectAccess.MEMBERS_ONLY))
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 GatherPageData(self, mr): """Build up a dictionary of data values to use when rendering the page.""" with mr.profiler.Phase('getting project star count'): num_stars = self.services.project_star.CountItemStars( mr.cnxn, mr.project_id) plural = '' if num_stars == 1 else 's' page_data = { 'admin_tab_mode': self.PROCESS_TAB_SUMMARY, 'formatted_project_description': markdown.Markdown(mr.project.description), 'access_level': project_views.ProjectAccessView(mr.project.access), 'num_stars': num_stars, 'plural': plural, 'home_page': mr.project.home_page, 'docs_url': mr.project.docs_url, 'source_url': mr.project.source_url, } return page_data
def GatherPageData(self, mr): """Build up a dictionary of data values to use when rendering the page.""" available_access_levels = project_helpers.BuildProjectAccessOptions( mr.project) offer_access_level = len(available_access_levels) > 1 access_view = project_views.ProjectAccessView(mr.project.access) return { 'admin_tab_mode': self.ADMIN_TAB_META, 'initial_summary': mr.project.summary, 'initial_project_home': mr.project.home_page, 'initial_docs_url': mr.project.docs_url, 'initial_source_url': mr.project.source_url, 'initial_logo_gcs_id': mr.project.logo_gcs_id, 'initial_logo_file_name': mr.project.logo_file_name, 'logo_view': tracker_views.LogoView(mr.project), 'initial_description': mr.project.description, 'issue_notify': mr.project.issue_notify_address, 'process_inbound_email': ezt.boolean( mr.project.process_inbound_email), 'email_from_addr': emailfmt.FormatFromAddr(mr.project), 'only_owners_remove_restrictions': ezt.boolean( mr.project.only_owners_remove_restrictions), 'only_owners_see_contributors': ezt.boolean( mr.project.only_owners_see_contributors), 'offer_access_level': ezt.boolean(offer_access_level), 'initial_access': access_view, 'available_access_levels': available_access_levels, }
def BuildProjectAccessOptions(project): """Return a list of project access values for use in an HTML menu. Args: project: current Project PB, or None when creating a new project. Returns: A list of ProjectAccessView objects that can be used in EZT. """ access_levels = [ project_pb2.ProjectAccess.ANYONE, project_pb2.ProjectAccess.MEMBERS_ONLY ] access_views = [] for access in access_levels: # Offer the allowed access levels. When editing an existing project, # its current access level may always be kept, even if it is no longer # in the list of allowed access levels for new projects. if (access in settings.allowed_access_levels or (project and access == project.access)): access_views.append(project_views.ProjectAccessView(access)) return access_views
summary=summary, description=description, only_owners_remove_restrictions=only_owners_remove_restrictions, only_owners_see_contributors=only_owners_see_contributors, process_inbound_email=process_inbound_email, access=access, home_page=home_page, docs_url=docs_url, source_url=source_url, logo_gcs_id=logo_gcs_id, logo_file_name=logo_file_name, ) # 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_access=access_view) else: return framework_helpers.FormatAbsoluteURL(mr, urls.ADMIN_META, saved=1, ts=int(time.time())) def _ParseMeta(self, post_data, errors): """Process a POST on the project metadata section of the admin page.""" summary = None description = None
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)
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)