def expand_macro(self, formatter, name, content, args=None): """ Returns the outcome from macro. Supported arguments: - count: Number of entries to show """ req = formatter.req papi = Projects() userstore = get_userstore() # Parse optional arguments if args is None: args = parse_args(content) if len(args) > 1: args = args[1] featured_projects = papi.get_projects_for_rss('FEATURED', limit_count=args.get( 'count', 5)) data = {'featured_projects': featured_projects} return Chrome(self.env).render_template(req, 'multiproject_featured.html', data, fragment=True)
def process_request(self, req): """ Render welcome page """ # Prepare data for template prjs = Projects() data = {} data['baseurl'] = conf.url_projects_path if req.authname == 'anonymous': conf.redirect(req) # Get project count data['project_count'] = prjs.project_count() user = get_userstore().getUser(req.authname) global_timeline = GlobalTimeline() data['show_explore'] = self.env[FindProjectsModule].has_explore_perm(req) data['latest_events'] = global_timeline.get_latest_events(req.authname, 5) # Check if user is allowed to create project data['can_create_project'] = user.can_create_project() # Configuration values the welcome page wants data['site_name'] = conf.site_name data['site_title_text'] = conf.site_title_text data['site_punch_line'] = conf.punch_line data['site_theme_path'] = conf.getThemePath() wiki_welcome = self._get_welcome_page(req) if wiki_welcome: data['wiki_welcome'] = wiki_welcome return "welcome.html", data, None
def expand_macro(self, formatter, name, content, args=None): """ Returns the outcome from macro. Supported arguments: - count: Number of entries to show """ req = formatter.req papi = Projects() userstore = get_userstore() projects = [] # Parse optional arguments if args is None: args = parse_args(content) if len(args) > 1: args = args[1] projects = papi.get_projects_for_rss('MOSTACTIVE', limit_count=args.get('count', 5), limit_activity=self.min_activity) return Chrome(self.env).render_template(req, 'multiproject_active.html', {'active_projects': projects}, fragment=True)
def test_get_enabled_services(self): p = Projects() services = p.getEnabledServices(self) self.assertTrue(len(services) >= 3) self.assertIn('versioncontrol|svn|false|Subversion', services) self.assertIn('documenting|wiki|true|Wiki', services) self.assertIn('tasks|trac|true|Task management system', services)
def render_admin_panel(self, req, cat, page, path_info): """ Returns the admin view and handles the form actions """ req.perm.require('TRAC_ADMIN') project = Project.get(self.env) if req.method == 'POST': myprojects_url = conf.url_home_path + "/myprojects" conf.log.exception("Redirect URL: %s" % myprojects_url) thisurl = Href(req.base_path)(req.path_info) context = Context.from_request(req) # Handle project remove if 'remove' in req.args: # Don't allow removing home if project.env_name == conf.sys_home_project_name: add_warning(req, 'Cannot remove home project') return req.redirect(thisurl) # Archive the project before removal archive = ProjectArchive() archived = archive.archive(project) if not archived: add_warning(req, 'Could not archive project "%s". Will not remove the project' % project.project_name) return req.redirect(thisurl) # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: listener.project_archived(project) # Do the actual project removal projects = Projects() if projects.remove_project(project): # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: listener.project_deleted(project) # NOTE: We no longer have project tables/session etc available req.redirect(myprojects_url) else: add_warning(req, 'Could not remove project "%s". Try again later' % project.project_name) return req.redirect(thisurl) add_script(req, 'multiproject/js/jquery-ui.js') add_script(req, 'multiproject/js/multiproject.js') add_script(req, 'multiproject/js/admin_system.js') add_stylesheet(req, 'multiproject/css/jquery-ui.css') # NOTE: Trac automatically puts 'project' dict in chrome thus it cannot be used data = {'multiproject': { 'project':project, 'home_url':conf.url_home_path }} return 'admin_system.html', data
def remove_project(self, req): """ Handler for removing project :param Request req: Trac request Handler expects to have following arguments in it: - project: Name of the project env - goto: Optional URL where to go after project removal. Defaults to /home/myprojects """ backurl = req.args.get('goto', ProjectListModule.home('myprojects')) short_name = req.args.get('project') if not short_name: return self.remove_failure(req) if req.args.get('cancel'): add_notice(req, 'Project deletion cancelled') return self.remove_failure(req) author = req.authname project = Project.get(env_name=short_name) if project is None: add_warning(req, 'Specified project does not exist!') return self.remove_failure(req) # Don't allow removing home if project.env_name == conf.sys_home_project_name: add_warning(req, 'Cannot remove home project') return self.remove_failure(req) if req.method != 'POST': return self.remove_failure(req, project=project) try: project.validate() except ProjectValidationException: req.redirect(backurl) # Check the permissions and method prjs = Projects() if ('TRAC_ADMIN' in req.perm or prjs.is_project_owner(project.env_name, author)) and req.method == 'POST': archive = ProjectArchive() # Archive the project before removal if not archive.archive(project): add_warning(req, 'Could not archive project "%s". Will not remove the project' % project.project_name) elif prjs.remove_project(project): # Notify listeners for listener in self.project_change_listeners: listener.project_deleted(project) # Notify end user add_notice(req, 'Project "%s" removed' % project.project_name) else: add_warning(req, 'Could not remove project "%s". Try again later' % project.project_name) else: add_warning(req, 'You are not allowed to remove project "%s" (check permissions and method)' % project.project_name) req.redirect(backurl)
def test_project_environment_does_not_exist(self): dbStub.addResult([[0]]) p = Projects() self.assertFalse(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed) dbStub.setExceptions(True) self.assertFalse(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed)
def get_child_projects(self): """ Returns projects that have repository of this project """ from multiproject.common.projects import Projects query = "SELECT * FROM projects WHERE parent_id = %d" % safe_int(self.id) api = Projects() return api.queryProjectObjects(query)
def test_project_environment_does_not_exist(self): dbStub.addResult([ [0] ]) p = Projects() self.assertFalse(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed) dbStub.setExceptions(True) self.assertFalse(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed)
def _list_mostactive_public_projects(self, req): prjs = Projects() page_size = 25 data = {} limit_start, page_size = self._add_rss_pagination(req, data, page_size) data['projects'] = prjs.get_projects_for_rss('MOSTACTIVE', limit_start=limit_start, limit_count=page_size) return 'rss_list.html', data, None
def get_child_projects(self): """ Returns projects that have repository of this project """ from multiproject.common.projects import Projects query = "SELECT * FROM projects WHERE parent_id = %d" % safe_int( self.id) api = Projects() return api.queryProjectObjects(query)
def test_get_my_tasks(self): dbStub.addResult(project_tasks_result) p = Projects() project_list = [ Project(1, "project1", "project1", "Project 1", 1, "2010-01-01"), Project(2, "project2", "project2", "Project 2", 2, "2010-01-02") ] tasks = p.get_all_user_tasks("username", project_list) self.assertEquals(len(tasks), 6) self.assertTrue(dbStub.closed)
def _list_recent_public_projects(self, req): prjs = Projects() page_size = 25 data = {} limit_start, page_size = self._add_rss_pagination(req, data, page_size) min_activity = self.config.getint('multiproject-projects', 'min_activity') data['projects'] = prjs.get_projects_for_rss('NEWEST', limit_start=limit_start, limit_count=page_size, limit_activity=min_activity) return 'rss_list.html', data, None
def test_search_user_projects(self): dbStub.addResult(project_search_result) p = Projects() userstoreStub.user.username = "******" projects = p.searchUserProjects("name1 name2 name3","user") self.assertEquals(len(projects), 3) self.assertEquals(projects[0].env_name, 'project1') self.assertEquals(projects[0].project_name, 'Project 1') self.assertEquals(projects[0].author_id, 10) self.assertEquals(projects[0].created, '2009-01-01') self.assertTrue(dbStub.closed)
def test_search_user_projects(self): dbStub.addResult(project_search_result) p = Projects() userstoreStub.user.username = "******" projects = p.searchUserProjects("name1 name2 name3", "user") self.assertEquals(len(projects), 3) self.assertEquals(projects[0].env_name, 'project1') self.assertEquals(projects[0].project_name, 'Project 1') self.assertEquals(projects[0].author_id, 10) self.assertEquals(projects[0].created, '2009-01-01') self.assertTrue(dbStub.closed)
def _show_regular_page(self, req): req_data = {} # Resolve some static data needed on page (categories and project count) cs = CQDECategoryStore() all_categories = cs.get_all_categories() all_contexts = cs.get_contexts() combined_context_ids, combined_contexts, non_combined_contexts = self.get_combined_contexts( all_contexts) # Total count of projects and count of projects in categories direct_category_counts = Projects().get_project_counts_per_category( req.authname) req_data['direct_category_counts'] = direct_category_counts req_data['combined_context_ids'] = combined_context_ids req_data['non_combined_contexts'] = non_combined_contexts self.set_category_data_into_request_data(all_categories, req_data) add_stylesheet(req, 'multiproject/css/multiproject.css') add_script(req, 'multiproject/js/jquery.ba-bbq.js') add_script(req, 'multiproject/js/explore.js') return "find.html", { 'top_categories': req_data['top_categories'], 'categories': req_data['root_categories_of_combined_contexts'], 'nonbrowsable_cntxt': req_data['non_empty_non_combined_contexts'], 'selected_tab': self.DEFAULT_TAB, 'tabs': self.TABS}, \ None
def _list_recent_public_projects(self, req): prjs = Projects() page_size = 25 data = {} limit_start, page_size = self._add_rss_pagination(req, data, page_size) min_activity = self.config.getint('multiproject-projects', 'min_activity') data['projects'] = prjs.get_projects_for_rss( 'NEWEST', limit_start=limit_start, limit_count=page_size, limit_activity=min_activity) return 'rss_list.html', data, None
def __init__(self, verbose=False): """ If verbose = None, be absolutely quiet """ self.verbose = verbose self.policy = CQDEPermissionPolicy(MockEnvironment()) self.papi = Projects() self.batch_size = conf.visibility_db_batch_size self.required_permission = 'PROJECT_VIEW'
def _add_rss_pagination(self, req, data, page_size): prjs = Projects() # Read selected page selected_page = req.args.get('page') if not selected_page: selected_page = 1 selected_page = int(selected_page) data['selected_page'] = selected_page count = prjs.public_project_count() # Create array of page numbers that will be used on view page_count = int(math.ceil((float(count) / page_size))) data['pages'] = range(1, page_count + 1) # Create start point for limit and get all projects limit_start = (selected_page - 1) * page_size return limit_start, page_size
def process_request(self, req): """ Process request for listing, creating and removing projects """ prjs = Projects() data = {} data['home'] = conf.url_home_path.rstrip('/') + "/rss" data['tracurl'] = conf.url_home_path.rstrip('/') # Having url_service here is probably a good idea. Otherwise RSS readers have no idea # where to fetch the relative path /project from. data['projroot'] = conf.url_service.rstrip('/') data['host'] = conf.domain_name data['url'] = req.path_info.rstrip('/').lstrip('/') if re.match (r'/rss/mostactive.xml$', req.path_info): data['projects'] = prjs.get_projects_for_rss('MOSTACTIVE', limit_count=50) data['title'] = 'Most active public projects' elif re.match (r'/rss/newest.xml$', req.path_info): min_activity = self.config.getint('multiproject-projects', 'min_activity', 0) data['projects'] = prjs.get_projects_for_rss('NEWEST', limit_count=50, limit_activity=min_activity) data['title'] = 'Newest public projects' elif re.match (r'/rss/featured.xml$', req.path_info): data['projects'] = prjs.get_projects_for_rss('FEATURED', limit_count=50) data['title'] = 'Featured projects' elif re.match(r'/rss/projects/.*.xml', req.path_info): username = req.path_info[req.path_info.rfind('/') + 1:-4] # username is validated in get_participated_public_projects data['projects'] = prjs.get_participated_public_projects(username) data['title'] = '%s\'s projects' % username else: data['projects'] = None # Support for both RSS 2.0 (default) and RSS 1.0 formats if 'rss10' == req.args.get('format', 'notset'): return "rss_feed_template.rss10", data, 'application/rss+xml' return "rss_feed_template.rss", data, 'application/rss+xml'
def expand_macro(self, formatter, name, content, args=None): """ Returns the outcome from macro. Supported arguments: - count: Number of entries to show """ req = formatter.req papi = Projects() userstore = get_userstore() projects = [] # Parse optional arguments if args is None: args = parse_args(content) if len(args) > 1: args = args[1] min_activity = self.config.getint('multiproject-projects', 'min_activity') projects = papi.get_projects_for_rss('NEWEST', limit_count=args.get('count', 5), limit_activity=min_activity) return Chrome(self.env).render_template(req, 'multiproject_recent.html', {'recent_projects': projects}, fragment=True)
def process_request(self, req): """ Create a simple RSS feed based on this structure that shows the number of active projects and members. In the future we will add more details. """ prjs = Projects() # create a list items = [] # append tuples containing items to show items.append(("PROJECT_COUNT", "Project count", prjs.project_count())) items.append(("ACTIVE_MEMBER_COUNT", "Active member count", get_userstore().getMemberCountInProjects())) pubdate = datetime.now() data = {} data["items"] = items data["site"] = conf.url_statistics # pubDate format: Wed, 12 Jan 2011 11:47:29 GMT data["pubdate"] = pubdate.strftime("%a, %d %B %Y %H:%M:%S %Z") return "service_statistics.rss", data, "application/rss+xml"
def process_request(self, req): """ Render welcome page """ # Prepare data for template prjs = Projects() data = {} data['baseurl'] = conf.url_projects_path if req.authname == 'anonymous': conf.redirect(req) # Get project count data['project_count'] = prjs.project_count() user = get_userstore().getUser(req.authname) global_timeline = GlobalTimeline() data['show_explore'] = self.env[FindProjectsModule].has_explore_perm( req) data['latest_events'] = global_timeline.get_latest_events( req.authname, 5) # Check if user is allowed to create project data['can_create_project'] = user.can_create_project() # Configuration values the welcome page wants data['site_name'] = conf.site_name data['site_title_text'] = conf.site_title_text data['site_punch_line'] = conf.punch_line data['site_theme_path'] = conf.getThemePath() wiki_welcome = self._get_welcome_page(req) if wiki_welcome: data['wiki_welcome'] = wiki_welcome return "welcome.html", data, None
def expand_macro(self, formatter, name, content, args=None): """ Returns the outcome from macro. Supported arguments: - count: Number of entries to show """ req = formatter.req papi = Projects() userstore = get_userstore() # Parse optional arguments if args is None: args = parse_args(content) if len(args) > 1: args = args[1] featured_projects = papi.get_projects_for_rss('FEATURED', limit_count=args.get('count', 5)) data = { 'featured_projects': featured_projects } return Chrome(self.env).render_template(req, 'multiproject_featured.html', data, fragment=True)
def render_admin_panel(self, req, cat, page, path_info): """ Renders updates admin panel page """ req.perm.require('TRAC_ADMIN') papi = Projects() selected = [] if req.method == 'POST': if req.args.get('searchprojects'): selected = papi.get_featured_projects() projectids = [] for project in selected: projectid = project.id projectids.append(projectid) rawsearch = papi.search_project(req.args.get('pattern'), None, 1, 50) for project in rawsearch: if not project.id in projectids: project.priority = None selected.append(project) elif req.args.get('update'): selection = req.args.get('projects') selection = isinstance(selection, list) and selection or [ selection ] projects = [] for project in selection: value = req.args.get(project) if value is not None and value != "remove": projects.append((project, value)) papi.update_featured_projects(projects) selected = papi.get_featured_projects() else: selected = papi.get_featured_projects() data = {'selected': selected, 'maxvalue': 20} return 'multiproject_featured_admin.html', data
def activities_to_classes(self, activities): """ Changes project activity into activity css classes of l,ql,qh,h (High, Quite High, Quite low, Low) """ bounds = Projects().get_activity_quartals() project_classes = {} classes = ['l', 'ql', 'qh', 'h'] # For each project_id, activity pair find correct css class for id, activity in activities.items(): # low as default. Go through bounds until match index = 0 for idx, bound in enumerate(bounds): if bound > activity: break index = idx project_classes[id] = classes[index] return project_classes
def createProject(self, req, projectid, projectname, description, project_visibility, serviceslist): """ Request to create a new project """ services = {} if str(projectid).strip() == '': e = exceptions.Exception raise e("Incorrect project identification name") if str(projectname).strip() == '': e = exceptions.Exception raise e("Incorrect project name") users = get_userstore() author = users.getUser(req.authname) if not author.can_create_project(): raise Exception("You are not allowed to create projects") public = False published = None if project_visibility == "on" or project_visibility == "true": public = True published = datetime.now() # Create project class project = Project(id=None, env_name=unicode(projectid), project_name=projectname, description=description, author_id=author.id, created=None, public=public, published=published) if project_visibility == "on" or project_visibility == "true": services['project_visibility'] = 'on' else: services['project_visibility'] = 'off' projects = Projects() projects.getServices(services, serviceslist) # Create project try: projects.create_project(project, services) return self.get_scm_repository_url(project.env_name) except ProjectValidationException as exc: raise Exception(exc.value) except: raise Exception("Creating project failed. Try again later.")
def render_admin_panel(self, req, cat, page, path_info): """ Renders updates admin panel page """ req.perm.require('TRAC_ADMIN') papi = Projects() selected = [] if req.method == 'POST': if req.args.get('searchprojects'): selected = papi.get_featured_projects() projectids = [] for project in selected: projectid = project['project_id'] projectids.append(projectid) rawsearch = papi.search_project(req.args.get('pattern'), None, 1, 50) for project in rawsearch: if not project['project_id'] in projectids: project['priority'] = None selected += tuple([project]) elif req.args.get('update'): selection = req.args.get('projects') selection = isinstance(selection, list) and selection or [selection] projects = [] for project in selection: value = req.args.get(project) if value is not None and value != "remove": projects.append((project, value)) papi.update_featured_projects(projects) selected = papi.get_featured_projects() else: selected = papi.get_featured_projects() data = { 'selected': selected, 'maxvalue': 20 } return 'multiproject_featured_admin.html', data
def searchProjects(self, req, namelike, categories): """ Returns project list, what user owns or have access to """ namelike = namelike.strip() if namelike == '' or namelike == '*' or namelike is None: namelike = None else: namelike = namelike.replace('%', '\%') namelike = namelike.replace('_', '\_') namelike = namelike.replace('\\', '\\\\') if categories == '': categories = None myprojects = Projects().get_projects_with_params(req.authname, "VERSION_CONTROL_VIEW", namelike, categories) projectlist = [] for project in myprojects: projectlist.append(project.env_name + '|' + project.project_name) return projectlist
def render_admin_panel(self, req, cat, page, path_info): """ Renders updates admin panel page """ req.perm.require("TRAC_ADMIN") papi = Projects() selected = [] if req.method == "POST": if req.args.get("searchprojects"): selected = papi.get_featured_projects() projectids = [] for project in selected: projectid = project.id projectids.append(projectid) rawsearch = papi.search_project(req.args.get("pattern"), None, 1, 50) for project in rawsearch: if not project.id in projectids: project.priority = None selected.append(project) elif req.args.get("update"): selection = req.args.get("projects") selection = isinstance(selection, list) and selection or [selection] projects = [] for project in selection: value = req.args.get(project) if value is not None and value != "remove": projects.append((project, value)) papi.update_featured_projects(projects) selected = papi.get_featured_projects() else: selected = papi.get_featured_projects() data = {"selected": selected, "maxvalue": 20} return "multiproject_featured_admin.html", data
def process_request(self, req): """ Process request for listing, creating and removing projects """ prjs = Projects() data = {} data['home'] = conf.url_home_path.rstrip('/') + "/rss" data['tracurl'] = conf.url_home_path.rstrip('/') # Having url_service here is probably a good idea. Otherwise RSS readers have no idea # where to fetch the relative path /project from. data['projroot'] = conf.url_service.rstrip('/') data['host'] = conf.domain_name data['url'] = req.path_info.rstrip('/').lstrip('/') if re.match(r'/rss/mostactive.xml$', req.path_info): data['projects'] = prjs.get_projects_for_rss('MOSTACTIVE', limit_count=50) data['title'] = 'Most active public projects' elif re.match(r'/rss/newest.xml$', req.path_info): min_activity = self.config.getint('multiproject-projects', 'min_activity', 0) data['projects'] = prjs.get_projects_for_rss( 'NEWEST', limit_count=50, limit_activity=min_activity) data['title'] = 'Newest public projects' elif re.match(r'/rss/featured.xml$', req.path_info): data['projects'] = prjs.get_projects_for_rss('FEATURED', limit_count=50) data['title'] = 'Featured projects' elif re.match(r'/rss/projects/.*.xml', req.path_info): username = req.path_info[req.path_info.rfind('/') + 1:-4] # username is validated in get_participated_public_projects data['projects'] = prjs.get_participated_public_projects(username) data['title'] = '%s\'s projects' % username else: data['projects'] = None # Support for both RSS 2.0 (default) and RSS 1.0 formats if 'rss10' == req.args.get('format', 'notset'): return "rss_feed_template.rss10", data, 'application/rss+xml' return "rss_feed_template.rss", data, 'application/rss+xml'
def test_is_project_owner_error(self): dbStub.addResult([[1]]) # user id userstoreStub.user.id = 0 p = Projects() self.assertFalse(p.is_project_owner("project", "nobody")) self.assertTrue(dbStub.closed)
def _list_forkable_projects(self, req): projects = Projects() projects = projects.get_forkable_projects(req.authname) return 'project_select_box.html', {'projects': projects}, None
def create_project(self, req): """ Handler for creating project request """ req.perm.require("PROJECT_CREATE") if req.method != 'POST': return self.create_failure(req, 'POST request needed when creating a new project') author = get_context(req)['author'] # If agreement needed but not getting it, show failure if conf.project_requires_agreed_terms and not self._is_active_user(req): return self.create_failure(req, 'You need to approve legal text to create a project!') # Read and transform some variables vcs_type = req.args.get('vcstype') parent_project = None if "_project_" in req.args: parent_project = Project.get(env_name=req.args.get('_project_')) self.__require_permissions_for_cloning(req.authname, parent_project) vcs_type = conf.getVersionControlType(parent_project.env_name) # TODO: expensive call, probably needed # Read settings settings = {} if vcs_type: settings['vcs_type'] = vcs_type identifier = req.args.get('prj_short_name') name = req.args.get('prj_long_name') public = 'prj_is_public' in req.args published = None if public: published = datetime.now() # Create project object project = Project( id = None, env_name = identifier, project_name = name, description = req.args.get('prj_description'), author_id = author.id, created = None, # Use default which is now() published = published ) # Create project environment projects = Projects() try: projects.create_project(project, settings) except ProjectValidationException as exc: self.log.warning('Project creation failed due the validation: {0}'.format(exc.value)) return self.create_failure(req, exc.value) except: self.log.exception('Project creation failed') return self.create_failure(req, _("Creating project failed. Try again later.")) if public: projects.add_public_project_visibility(project.id) # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: listener.project_created(project) if public: listener.project_set_public(project) return self.create_success(req, project)
def _filtered_resultset_partial(self, req, rss=False): # Fetch request arguments filter, category_id_list, sub_page = self.fetch_req_args(req) # Which tab is requested tab = self.resolve_tab(req) # Get optional number of results per page. # If not set, or bigger than max, default to MAX_RESULTS_TO_DISPLAY numresults = req.args.get('numresults', '') if not numresults or not numresults.isdigit(): numresults = self.DEFAULT_RESULTS_TO_DISPLAY elif int(numresults) > self.MAX_RESULTS_TO_DISPLAY: numresults = self.MAX_RESULTS_TO_DISPLAY numresults = int(numresults) # Fetch projects based on tab if tab == "download": projects = Projects().searchMostDownloaded() activities = None if projects is None: project_count = 0 else: project_count = len(projects) else: projects, activities, project_count = Projects().search( filter, category_id_list, req.authname, tab, sub_page, numresults) # Some calculations for pagination # NOTE: math.ceil returns a float total_page_count = int(math.ceil(float(project_count) / numresults)) range_center_point = sub_page if range_center_point <= self.SUBPAGE_RANGE: range_center_point = 1 + self.SUBPAGE_RANGE if range_center_point + 1 >= total_page_count: range_center_point = total_page_count - self.SUBPAGE_RANGE start_page = range_center_point - self.SUBPAGE_RANGE if start_page < 1: start_page = 1 end_page = range_center_point + self.SUBPAGE_RANGE if end_page > total_page_count: end_page = total_page_count if projects or len(projects) > 0: # Activity css classes for activity meters if activities: activity_classes = self.activities_to_classes(activities) else: activity_classes = {} # Get categories for projects that was searched project_categories = self.get_project_categories(projects) # Get number of project watchers project_watchers = self.get_project_watchers(projects) else: activity_classes = {} project_categories = "" project_watchers = "" if project_count: if tab == 'recent': showing_clause = _( "Showing %(start)s - %(end)s most recent projects out of %(total)s", start=(sub_page - 1) * numresults + 1, end=min(sub_page * numresults, project_count), total=project_count) elif tab == 'download': showing_clause = _( "Showing %(start)s - %(end)s most recent projects out of %(total)s", start=(sub_page - 1) * numresults + 1, end=min(sub_page * numresults, project_count), total=project_count) else: showing_clause = _( "Showing %(start)s - %(end)s active projects out of %(total)s", start=(sub_page - 1) * numresults + 1, end=min(sub_page * numresults, project_count), total=project_count) else: showing_clause = _("No results") if not rss: return "projects_partial.html", { 'projects': projects, 'project_categories': project_categories, 'project_watchers': project_watchers, 'selected_categories': category_id_list, 'selected_tab': tab, 'tabs': self.TABS, 'total_pages': total_page_count, 'start_page': start_page, 'end_page': end_page, 'sub_page': sub_page, 'showing_clause': showing_clause, 'activity_classes': activity_classes, 'search_filter': filter or 'Search Projects' }, None else: data = {} data['projects'] = projects data['projroot'] = conf.url_service data['host'] = conf.domain_name if tab == 'active': data['sorting'] = "most active" elif tab == 'recent': data['sorting'] = "most recent" else: data['sorting'] = "" # TODO: optimize find_categories categories = self._find_categories(category_id_list) cat_string = "" sec_string = "" if len(categories) == 1: cat_string = "in " + categories[0] + " category" sec_string = "in " + categories[0] + " section" elif len(categories) > 1: cat_string = "in " + ", ".join(categories) + " categories" sec_string = "in " + ", ".join(categories) + " sections" data['category_string'] = cat_string data['section_string'] = sec_string data['resultslink'] = conf.url_service + req.href( ) + req.path_info + "#" + req.query_string return "project_list.rss", data, 'application/rss+xml'
def test_is_project_owner(self): dbStub.addResult([[1]]) # user id userstoreStub.user.id = 1 p = Projects() self.assertTrue(p.is_project_owner("project", "user")) self.assertTrue(dbStub.closed)
def getTracServices(self, req): """ Returns available services """ prjs = Projects() return prjs.getEnabledServices(self.env)
def render_admin_panel(self, req, cat, page, path_info): """ Overrides BasicsAdminPanel rendering function. Handle project info update (update global db) and then delegate handling back to BasicsAdminPanel """ req.perm.require('TRAC_ADMIN') userstore = get_userstore() user = userstore.getUser(req.authname) project = Project.get(self.env) # Update database if form posted if req.method == 'POST': papi = Projects() # Set public pressed if 'makepublic' in req.args: if conf.allow_public_projects: self._make_public(req, project) papi.add_public_project_visibility(project.id) else: raise TracError("Public projects are disabled", "Error!") # Set private pressed if 'makeprivate' in req.args: self._make_private(req, project) papi.remove_public_project_visibility(project.id) # Remove icon if requested if 'reset' in req.args: # NOTE: Icon is removed from filesystem already at this point self._unset_icon(req, project) project.icon_name = None # Update icon if set if not isinstance(req.args.get('icon', ''), basestring): icon_name = self._set_icon(req, project) if icon_name: # If image is changed if icon_name != project.icon_name: self._unset_icon(req, project) project.icon_name = icon_name else: add_warning(req, 'Failed to set the project icon') # Save changes in database if 'apply' in req.args: self._apply_changes(req, project) # Reload page return req.redirect(req.href(req.path_info)) data = { 'user': user, 'icon_size': self.icon_size, 'mproject': project, 'is_public': project.public, 'allow_public_projects': conf.allow_public_projects } # Add javascript libraries for datepicker and autocomplete add_script(req, 'multiproject/js/jquery-ui.js') add_stylesheet(req, 'multiproject/css/jquery-ui.css') add_script(req, 'multiproject/js/multiproject.js') add_script(req, 'multiproject/js/admin_basics.js') Chrome(self.env).add_textarea_grips(req) return 'admin_basics_replacement.html', data
def render_admin_panel(self, req, cat, page, path_info): """ Returns the admin view and handles the form actions """ req.perm.require('TRAC_ADMIN') project = Project.get(self.env) if req.method == 'POST': myprojects_url = conf.url_home_path + "/myprojects" conf.log.exception("Redirect URL: %s" % myprojects_url) thisurl = Href(req.base_path)(req.path_info) context = Context.from_request(req) # Handle project remove if 'remove' in req.args: # Don't allow removing home if project.env_name == conf.sys_home_project_name: add_warning(req, 'Cannot remove home project') return req.redirect(thisurl) # Archive the project before removal archive = ProjectArchive() archived = archive.archive(project) if not archived: add_warning( req, 'Could not archive project "%s". Will not remove the project' % project.project_name) return req.redirect(thisurl) # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: listener.project_archived(project) # Do the actual project removal projects = Projects() if projects.remove_project(project): # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: listener.project_deleted(project) # NOTE: We no longer have project tables/session etc available req.redirect(myprojects_url) else: add_warning( req, 'Could not remove project "%s". Try again later' % project.project_name) return req.redirect(thisurl) add_script(req, 'multiproject/js/jquery-ui.js') add_script(req, 'multiproject/js/multiproject.js') add_script(req, 'multiproject/js/admin_system.js') add_stylesheet(req, 'multiproject/css/jquery-ui.css') # NOTE: Trac automatically puts 'project' dict in chrome thus it cannot be used data = { 'multiproject': { 'project': project, 'home_url': conf.url_home_path } } return 'admin_system.html', data
def _list_forkable_projects(self, req): projects = Projects() projects = projects.get_forkable_projects(req.authname) return 'project_select_box.html', {'projects':projects}, None
def test_project_environment_exists(self): dbStub.addResult([ [1] ]) p = Projects() self.assertTrue(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed)
def test_project_count(self): dbStub.addResult([ [3] ]) p = Projects() self.assertEquals(p.project_count(), 3) self.assertTrue(dbStub.closed)
def getCount(self, req): """ Returns project count from server """ prjs = Projects() return prjs.project_count()
def projectExists(self, req, short_name): """ Returns True / False depending if project exists """ prjs = Projects() return prjs.project_environment_exists(short_name)
def test_project_count(self): dbStub.addResult([[3]]) p = Projects() self.assertEquals(p.project_count(), 3) self.assertTrue(dbStub.closed)
def create_project(self, req): """ Handler for creating project request """ req.perm.require("PROJECT_CREATE") if req.method != 'POST': return self.create_failure(req, 'POST request needed when creating a new project') author = get_context(req)['author'] # If agreement needed but not getting it, show failure if conf.project_requires_agreed_terms and not self._is_active_user(req): return self.create_failure(req, 'You need to approve legal text to create a project!') # Read and transform some variables vcs_type = req.args.get('vcstype') vcs_name = req.args.get('vcs_name') if not self.validate_repository_name(vcs_name): return self.create_failure(req, 'Check repository name.') parent_project = None if "_project_" in req.args: parent_project = Project.get(env_name=req.args.get('_project_')) self.__require_permissions_for_cloning(req.authname, parent_project) vcs_type = conf.getVersionControlType(parent_project.env_name) # TODO: expensive call, probably needed # Read settings settings = {} if vcs_type: settings['vcs_type'] = vcs_type if vcs_name: settings['vcs_name'] = vcs_name identifier = req.args.get('prj_short_name') name = req.args.get('prj_long_name') project_visibility = 'prj_is_public' in req.args public = False published = None if project_visibility: public = True published = datetime.now() # Create project object project = Project( id = None, env_name = identifier, project_name = name, description = req.args.get('prj_description'), author_id = author.id, created = None, # Use default which is now() public = public, published = published ) # Create project environment projects = Projects() try: projects.create_project(project, settings) except ProjectValidationException as exc: self.log.warning('Project creation failed due the validation: {0}'.format(exc.value)) return self.create_failure(req, exc.value) except: self.log.exception('Project creation failed') return self.create_failure(req, _("Creating project failed. Try again later.")) if public: projects.add_public_project_visibility(project.id) #Add author to follow project watch_store = CQDEWatchlistStore() watch_store.watch_project(author.id, project.id) #Change project trac.ini to support multiple repositories project_env_path = conf.getEnvironmentSysPath(project.env_name) repo_env_path = conf.getEnvironmentVcsPath(project.env_name, vcs_type, vcs_name) os.rename(project_env_path + '/conf/trac.ini', project_env_path + '/conf/trac.ini.bak') oldfile = open(project_env_path + '/conf/trac.ini.bak', 'r') newfile = open(project_env_path + '/conf/trac.ini', 'w') lines = oldfile.readlines() for line in lines: newfile.write(line) if line.startswith('database ='): break newfile.write('repository_dir =\nrepository_type = svn\n\n[repositories]\n') newfile.write('%s.dir = %s\n' % (vcs_name, repo_env_path)) newfile.write('%s.type = %s\n' % (vcs_name, vcs_type)) newfile.close() oldfile.close() os.remove(project_env_path + '/conf/trac.ini.bak') # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: try: listener.project_created(project) listener.project_watchers(project) if public: listener.project_set_public(project) except: pass return self.create_success(req, project)
def test_is_project_owner(self): dbStub.addResult([ [1] ]) # user id userstoreStub.user.id = 1 p = Projects() self.assertTrue(p.is_project_owner("project", "user")) self.assertTrue(dbStub.closed)
def test_is_project_owner_error(self): dbStub.addResult([ [1] ]) # user id userstoreStub.user.id = 0 p = Projects() self.assertFalse(p.is_project_owner("project", "nobody")) self.assertTrue(dbStub.closed)
def test_get_services(self): p = Projects() res={} p.getServices(res,"test, dummy, Subversion, Perforce, test") self.assertEquals(res['vcs_type'], "perforce") p.getServices(res,"test, dummy, Subversion, test") self.assertEquals(res['vcs_type'], "svn") p.getServices(res,"another test, Versioncontrol|Mercurial, test") self.assertEquals(res['vcs_type'], "hg") p.getServices(res," versioncontrol|git ") self.assertEquals(res['vcs_type'], "git") res['vcs_type']=None p.getServices(res,"test, test") self.assertEquals(res['vcs_type'], None) res['vcs_type']=None p.getServices(res,"") self.assertEquals(res['vcs_type'], None) p.getServices(res," versioncontrol|svn,versioncontrol|something") self.assertEquals(res['vcs_type'], "svn") res['vcs_type']=None
def create_project(self, req): """ Handler for creating project request """ req.perm.require("PROJECT_CREATE") if req.method != 'POST': return self.create_failure( req, 'POST request needed when creating a new project') author = get_context(req)['author'] # If agreement needed but not getting it, show failure if conf.project_requires_agreed_terms and not self._is_active_user( req): return self.create_failure( req, 'You need to approve legal text to create a project!') # Read and transform some variables vcs_type = req.args.get('vcstype') vcs_name = req.args.get('vcs_name') if not self.validate_repository_name(vcs_name): return self.create_failure(req, 'Check repository name.') parent_project = None if "_project_" in req.args: parent_project = Project.get(env_name=req.args.get('_project_')) self.__require_permissions_for_cloning(req.authname, parent_project) vcs_type = conf.getVersionControlType( parent_project.env_name ) # TODO: expensive call, probably needed # Read settings settings = {} if vcs_type: settings['vcs_type'] = vcs_type if vcs_name: settings['vcs_name'] = vcs_name identifier = req.args.get('prj_short_name') name = req.args.get('prj_long_name') project_visibility = 'prj_is_public' in req.args public = False published = None if project_visibility: public = True published = datetime.now() # Create project object project = Project( id=None, env_name=identifier, project_name=name, description=req.args.get('prj_description'), author_id=author.id, created=None, # Use default which is now() public=public, published=published) # Create project environment projects = Projects() try: projects.create_project(project, settings) except ProjectValidationException as exc: self.log.warning( 'Project creation failed due the validation: {0}'.format( exc.value)) return self.create_failure(req, exc.value) except: self.log.exception('Project creation failed') return self.create_failure( req, _("Creating project failed. Try again later.")) if public: projects.add_public_project_visibility(project.id) #Add author to follow project watch_store = CQDEWatchlistStore() watch_store.watch_project(author.id, project.id) #Change project trac.ini to support multiple repositories project_env_path = conf.getEnvironmentSysPath(project.env_name) repo_env_path = conf.getEnvironmentVcsPath(project.env_name, vcs_type, vcs_name) os.rename(project_env_path + '/conf/trac.ini', project_env_path + '/conf/trac.ini.bak') oldfile = open(project_env_path + '/conf/trac.ini.bak', 'r') newfile = open(project_env_path + '/conf/trac.ini', 'w') lines = oldfile.readlines() for line in lines: newfile.write(line) if line.startswith('database ='): break newfile.write( 'repository_dir =\nrepository_type = svn\n\n[repositories]\n') newfile.write('%s.dir = %s\n' % (vcs_name, repo_env_path)) newfile.write('%s.type = %s\n' % (vcs_name, vcs_type)) newfile.close() oldfile.close() os.remove(project_env_path + '/conf/trac.ini.bak') # Notify listeners. The project object still exists, but database does not for listener in self.project_change_listeners: try: listener.project_created(project) listener.project_watchers(project) if public: listener.project_set_public(project) except: pass return self.create_success(req, project)
def remove_project(self, req): """ Handler for removing project :param Request req: Trac request Handler expects to have following arguments in it: - project: Name of the project env - goto: Optional URL where to go after project removal. Defaults to /home/myprojects """ backurl = req.args.get('goto', ProjectListModule.home('myprojects')) short_name = req.args.get('project') if not short_name: return self.remove_failure(req) if req.args.get('cancel'): add_notice(req, 'Project deletion cancelled') return self.remove_failure(req) author = req.authname project = Project.get(env_name=short_name) if project is None: add_warning(req, 'Specified project does not exist!') return self.remove_failure(req) # Don't allow removing home if project.env_name == conf.sys_home_project_name: add_warning(req, 'Cannot remove home project') return self.remove_failure(req) if req.method != 'POST': return self.remove_failure(req, project=project) try: project.validate() except ProjectValidationException: req.redirect(backurl) # Check the permissions and method prjs = Projects() if ('TRAC_ADMIN' in req.perm or prjs.is_project_owner( project.env_name, author)) and req.method == 'POST': archive = ProjectArchive() # Archive the project before removal if not archive.archive(project): add_warning( req, 'Could not archive project "%s". Will not remove the project' % project.project_name) elif prjs.remove_project(project): # Notify listeners for listener in self.project_change_listeners: listener.project_deleted(project) # Notify end user add_notice(req, 'Project "%s" removed' % project.project_name) else: add_warning( req, 'Could not remove project "%s". Try again later' % project.project_name) else: add_warning( req, 'You are not allowed to remove project "%s" (check permissions and method)' % project.project_name) req.redirect(backurl)
def test_get_services(self): p = Projects() res = {} p.getServices(res, "test, dummy, Subversion, Perforce, test") self.assertEquals(res['vcs_type'], "perforce") p.getServices(res, "test, dummy, Subversion, test") self.assertEquals(res['vcs_type'], "svn") p.getServices(res, "another test, Versioncontrol|Mercurial, test") self.assertEquals(res['vcs_type'], "hg") p.getServices(res, " versioncontrol|git ") self.assertEquals(res['vcs_type'], "git") res['vcs_type'] = None p.getServices(res, "test, test") self.assertEquals(res['vcs_type'], None) res['vcs_type'] = None p.getServices(res, "") self.assertEquals(res['vcs_type'], None) p.getServices(res, " versioncontrol|svn,versioncontrol|something") self.assertEquals(res['vcs_type'], "svn") res['vcs_type'] = None
def test_project_environment_exists(self): dbStub.addResult([[1]]) p = Projects() self.assertTrue(p.project_environment_exists("testi")) self.assertTrue(dbStub.closed)