def import_tool(self, project, user, project_name=None, mount_point=None, mount_label=None, user_name=None, **kw): """ Import a GitHub repo into a new Git Allura tool. """ project_name = "%s/%s" % (user_name, project_name) extractor = GitHubProjectExtractor(project_name, user=user) repo_url = extractor.get_repo_url() app = project.install_app("Git", mount_point=mount_point or 'code', mount_label=mount_label or 'Code', init_from_url=repo_url, import_id={ 'source': self.source, 'project_name': project_name, }) M.AuditLog.log('import tool %s from %s on %s' % ( app.config.options.mount_point, project_name, self.source, ), project=project, user=user, url=app.url) g.post_event('project_updated') return app
def import_tool(self, project, user, project_name=None, mount_point=None, mount_label=None, user_name=None, **kw): """ Import a GitHub repo into a new Git Allura tool. """ project_name = "%s/%s" % (user_name, project_name) extractor = GitHubProjectExtractor(project_name, user=user) repo_url = extractor.get_repo_url() app = project.install_app( "Git", mount_point=mount_point or 'code', mount_label=mount_label or 'Code', init_from_url=repo_url, import_id={ 'source': self.source, 'project_name': project_name, } ) M.AuditLog.log( 'import tool %s from %s on %s' % ( app.config.options.mount_point, project_name, self.source, ), project=project, user=user, url=app.url) g.post_event('project_updated') return app
def edit_screenshot(self, id=None, caption=None, **kw): require_access(c.project, 'update') if id is not None and id != '': M.ProjectFile.query.get( project_id=c.project._id, _id=ObjectId(id)).caption = caption g.post_event('project_updated') redirect('screenshots')
def success(self, app): with h.push_config(c, project=self.project, app=app): g.post_event( 'import_tool_task_succeeded', self.importer.source, self.importer.tool_label, )
def test_post_event_from_script(self): # simulate post_event being called from a paster script command: with mock.patch.dict(tg.request.environ, PATH_INFO='--script--'): g.post_event('my_event3') # event task is flushed to db right away: assert M.MonQTask.query.get( task_name='allura.tasks.event_tasks.event', args=['my_event3'])
def add_screenshot(self, screenshot=None, caption=None, **kw): require_access(c.project, 'update') screenshots = c.project.get_screenshots() if len(screenshots) >= 6: flash('You may not have more than 6 screenshots per project.', 'error') elif screenshot is not None and screenshot != '': future_bmp = False e_filename, e_fileext = os.path.splitext(screenshot.filename) for screen in screenshots: c_filename, c_fileext = os.path.splitext(screen.filename) if c_fileext == '.png' and e_fileext.lower() == '.bmp' and e_filename == c_filename: future_bmp = True # If both filename(without ext.) equals and exiting file ext. is png and given file ext is bmp, there will be two similar png files. if screen.filename == screenshot.filename or future_bmp: screenshot.filename = re.sub('(.*)\.(.*)', r'\1-' + str(randint(1000,9999)) + r'.\2', screenshot.filename) # if filename already exists append a random number break M.AuditLog.log('add screenshot') sort = 1 + max([ss.sort or 0 for ss in screenshots] or [0]) M.ProjectFile.save_image( screenshot.filename, screenshot.file, content_type=screenshot.type, save_original=True, original_meta=dict( project_id=c.project._id, category='screenshot', caption=caption, sort=sort), square=True, thumbnail_size=(150, 150), thumbnail_meta=dict(project_id=c.project._id, category='screenshot_thumb'), convert_bmp=True) g.post_event('project_updated') redirect('screenshots')
def test_post_event_explicit_flush(self): g.post_event('my_event1', flush_immediately=True) assert M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event1']) g.post_event('my_event2', flush_immediately=False) assert not M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event2']) ThreadLocalORMSession.flush_all() assert M.MonQTask.query.get(task_name='allura.tasks.event_tasks.event', args=['my_event2'])
def update_label(self, mount_label): """Handles POST to update the Application's ``mount_label``. """ require_access(self.app, 'configure') self.app.config.options['mount_label'] = mount_label g.post_event('project_menu_updated') redirect(six.ensure_text(request.referer or '/'))
def create(self, name=None, **kw): if M.ProjectRole.by_name(name): flash('%s already exists' % name, 'error') else: M.ProjectRole(project_id=c.project._id, name=name) M.AuditLog.log('create group %s', name) g.post_event('project_updated') redirect('.')
def delete_screenshot(self, id=None, **kw): require_access(c.project, 'update') if id is not None and id != '': M.AuditLog.log('remove screenshot') M.ProjectFile.query.remove( dict(project_id=c.project._id, _id=ObjectId(id))) g.post_event('project_updated') redirect('screenshots')
def import_project_info(project_name): from forgeimporters.github.project import GitHubProjectImporter importer = GitHubProjectImporter(None) with ImportErrorHandler(importer, project_name, c.project) as handler: extractor = GitHubProjectExtractor(project_name, user=c.user) c.project.summary = extractor.get_summary() c.project.external_homepage = extractor.get_homepage() ThreadLocalORMSession.flush_all() g.post_event('project_updated')
def import_project_info(project_name): from forgeimporters.github.project import GitHubProjectImporter importer = GitHubProjectImporter(None) with ImportErrorHandler(importer, project_name, c.project) as handler: extractor = GitHubProjectExtractor(project_name, user=c.user) c.project.summary = extractor.get_summary() c.project.external_homepage = extractor.get_homepage() ThreadLocalORMSession.flush_all() g.post_event('project_updated')
def delete_group(self, group_name, **kw): role = M.ProjectRole.by_name(group_name) if not role: flash('Group "%s" does not exist.' % group_name, 'error') else: role.delete() M.AuditLog.log('delete group %s', group_name) flash('Group "%s" deleted successfully.' % group_name) g.post_event('project_updated') redirect('.')
def import_tool(self, project, user, project_name, mount_point=None, mount_label=None, **kw): import_id_converter = ImportIdConverter.get() project_name = '%s/%s' % (kw['user_name'], project_name) extractor = GitHubProjectExtractor(project_name, user=user) if not extractor.has_tracker(): return app = project.install_app('tickets', mount_point, mount_label, EnableVoting=False, open_status_names='open', closed_status_names='closed', import_id={ 'source': self.source, 'project_name': project_name, }) self.github_markdown_converter = GitHubMarkdownConverter( kw['user_name'], project_name) ThreadLocalORMSession.flush_all() try: M.session.artifact_orm_session._get().skip_mod_date = True with h.push_config(c, user=M.User.anonymous(), app=app): for ticket_num, issue in extractor.iter_issues(): self.max_ticket_num = max(ticket_num, self.max_ticket_num) ticket = TM.Ticket(app_config_id=app.config._id, custom_fields=dict(), ticket_num=ticket_num, import_id=import_id_converter.expand( ticket_num, app)) self.process_fields(extractor, ticket, issue) self.process_comments(extractor, ticket, issue) self.process_events(extractor, ticket, issue) self.process_milestones(ticket, issue) session(ticket).flush(ticket) session(ticket).expunge(ticket) app.globals.custom_fields = self.postprocess_milestones() app.globals.last_ticket_num = self.max_ticket_num ThreadLocalORMSession.flush_all() M.AuditLog.log( 'import tool %s from %s on %s' % (app.config.options.mount_point, project_name, self.source), project=project, user=user, url=app.url) g.post_event('project_updated') app.globals.invalidate_bin_counts() return app finally: M.session.artifact_orm_session._get().skip_mod_date = False
def __exit__(self, exc_type, exc_val, exc_tb): if hasattr(self.importer, 'clear_pending'): self.importer.clear_pending(self.project) if exc_type: g.post_event('import_tool_task_failed', error=str(exc_val), traceback=traceback.format_exc(), importer_source=self.importer.source, importer_tool_label=self.importer.tool_label, project_name=self.project_name, )
def delete(self): require_access(self.neighborhood, 'admin') if self.award: grants = M.AwardGrant.query.find(dict(award_id=self.award._id)) for grant in grants: grant.delete() with h.push_context(grant.granted_to_project_id): g.post_event('project_updated') M.AwardFile.query.remove(dict(award_id=self.award._id)) self.award.delete() redirect(request.referer or '/')
def delete(self): require_access(self.neighborhood, 'admin') if self.award: grants = M.AwardGrant.query.find(dict(award_id=self.award._id)) for grant in grants: grant.delete() with h.push_context(grant.granted_to_project_id): g.post_event('project_updated') M.AwardFile.query.remove(dict(award_id=self.award._id)) self.award.delete() redirect(request.referer or '/')
def __exit__(self, exc_type, exc_val, exc_tb): if hasattr(self.importer, 'clear_pending'): self.importer.clear_pending(self.project) if exc_type: g.post_event( 'import_tool_task_failed', error=str(exc_val), traceback=traceback.format_exc(), importer_source=self.importer.source, importer_tool_label=self.importer.tool_label, project_name=self.project_name, )
def delete_trove(self, type, trove, **kw): require_access(c.project, 'update') trove_obj = M.TroveCategory.query.get(trove_cat_id=int(trove)) current_troves = getattr(c.project, 'trove_%s' % type) if trove_obj is not None and trove_obj._id in current_troves: M.AuditLog.log('remove trove %s: %s', type, trove_obj.fullpath) current_troves.remove(trove_obj._id) # just in case the event handling is super fast ThreadLocalORMSession.flush_all() c.project.last_updated = datetime.utcnow() g.post_event('project_updated') redirect('trove')
def configure_tool_grouping(self, grouping_threshold='1', **kw): try: grouping_threshold = int(grouping_threshold) if grouping_threshold < 1 or grouping_threshold > 10: raise exc.HTTPBadRequest('Invalid threshold. Expected a value between 1 and 10') c.project.set_tool_data( 'allura', grouping_threshold=grouping_threshold) except ValueError: raise exc.HTTPBadRequest('Invalid threshold. Expected a value between 1 and 10') M.AuditLog.log('Updated tool grouping threshold') g.post_event('project_menu_updated') return {'status': 'ok'}
def sort_screenshots(self, **kw): """Sort project screenshots. Called via ajax when screenshots are reordered via drag/drop on the Screenshots admin page. ``kw`` is a mapping of (screenshot._id, sort_order) pairs. """ for s in c.project.get_screenshots(): if str(s._id) in kw: s.sort = int(kw[str(s._id)]) g.post_event('project_updated')
def import_tool(self, project, user, project_name=None, mount_point=None, mount_label=None, trac_url=None, user_map=None, **kw): """ Import Trac tickets into a new Allura Tracker tool. """ mount_point = mount_point or 'tickets' app = project.install_app( 'Tickets', mount_point=mount_point, mount_label=mount_label or 'Tickets', open_status_names='new assigned accepted reopened', closed_status_names='closed', import_id={ 'source': self.source, 'trac_url': trac_url, }, ) session(app.config).flush(app.config) session(app.globals).flush(app.globals) try: with h.push_config(c, app=app): TracImportSupport().perform_import( json.dumps(export(trac_url), cls=DateJSONEncoder), json.dumps({ 'user_map': json.loads(user_map) if user_map else {}, 'usernames_match': self.usernames_match(trac_url), }), ) AuditLog.log( 'import tool %s from %s' % ( app.config.options.mount_point, trac_url, ), project=project, user=user, url=app.url, ) g.post_event('project_updated') return app except Exception: h.make_app_admin_only(app) raise
def update(self, card=None, **kw): """Handle POST to update permissions for the Application. """ old_acl = self.app.config.acl self.app.config.acl = [] for args in card: perm = args['id'] new_group_ids = args.get('new', []) del_group_ids = [] group_ids = args.get('value', []) if isinstance(new_group_ids, six.string_types): new_group_ids = [new_group_ids] if isinstance(group_ids, six.string_types): group_ids = [group_ids] for acl in old_acl: if (acl['permission'] == perm and str(acl['role_id']) not in group_ids and acl['access'] != model.ACE.DENY): del_group_ids.append(str(acl['role_id'])) def get_role(_id): return model.ProjectRole.query.get(_id=ObjectId(_id)) groups = list(map(get_role, group_ids)) new_groups = list(map(get_role, new_group_ids)) del_groups = list(map(get_role, del_group_ids)) def group_names(groups): return ', '.join( (role.name or '<Unnamed>') for role in groups if role) if new_groups or del_groups: model.AuditLog.log( 'updated "%s" permission: "%s" => "%s" for %s' % (perm, group_names(groups + del_groups), group_names(groups + new_groups), self.app.config.options['mount_point'])) role_ids = list(map(ObjectId, group_ids + new_group_ids)) self.app.config.acl += [model.ACE.allow(r, perm) for r in role_ids] # Add all ACEs for user roles back for ace in old_acl: if (ace.permission == perm) and (ace.access == model.ACE.DENY): self.app.config.acl.append(ace) g.post_event( 'project_menu_updated' ) # since 'read' permission changes can affect what is visible in menu redirect(six.ensure_text(request.referer or '/'))
def change_perm(self, role_id, permission, allow="true", **kw): if allow == "true": M.AuditLog.log('granted permission %s to group %s', permission, M.ProjectRole.query.get(_id=ObjectId(role_id)).name) c.project.acl.append(M.ACE.allow(ObjectId(role_id), permission)) else: admin_group_id = str(M.ProjectRole.by_name('Admin')._id) if admin_group_id == role_id and permission == 'admin': return dict(error='You cannot remove the admin permission from the admin group.') M.AuditLog.log('revoked permission %s from group %s', permission, M.ProjectRole.query.get(_id=ObjectId(role_id)).name) c.project.acl.remove(M.ACE.allow(ObjectId(role_id), permission)) g.post_event('project_updated') return self._map_group_permissions()
def clone(cloned_from_path, cloned_from_name, cloned_from_url): from allura import model as M try: c.app.repo.init_as_clone(cloned_from_path, cloned_from_name, cloned_from_url) M.Notification.post_user( c.user, c.app.repo, 'created', text='Repository %s/%s created' % (c.project.shortname, c.app.config.options.mount_point)) except Exception: g.post_event('repo_clone_task_failed', cloned_from_url, cloned_from_path, traceback.format_exc())
def clone(cloned_from_path, cloned_from_name, cloned_from_url): from allura import model as M try: c.app.repo.init_as_clone( cloned_from_path, cloned_from_name, cloned_from_url) M.Notification.post_user( c.user, c.app.repo, 'created', text='Repository %s/%s created' % ( c.project.shortname, c.app.config.options.mount_point)) except Exception: g.post_event('repo_clone_task_failed', cloned_from_url, cloned_from_path, traceback.format_exc())
def import_tool(self, project, user, project_name, mount_point=None, mount_label=None, **kw): import_id_converter = ImportIdConverter.get() project_name = '%s/%s' % (kw['user_name'], project_name) extractor = GitHubProjectExtractor(project_name, user=user) if not extractor.has_tracker(): return app = project.install_app('tickets', mount_point, mount_label, EnableVoting=False, open_status_names='open', closed_status_names='closed', import_id={ 'source': self.source, 'project_name': project_name, } ) self.github_markdown_converter = GitHubMarkdownConverter( kw['user_name'], project_name) ThreadLocalORMSession.flush_all() try: M.session.artifact_orm_session._get().skip_mod_date = True with h.push_config(c, user=M.User.anonymous(), app=app): for ticket_num, issue in extractor.iter_issues(): self.max_ticket_num = max(ticket_num, self.max_ticket_num) ticket = TM.Ticket( app_config_id=app.config._id, custom_fields=dict(), ticket_num=ticket_num, import_id=import_id_converter.expand(ticket_num, app) ) self.process_fields(extractor, ticket, issue) self.process_comments(extractor, ticket, issue) self.process_events(extractor, ticket, issue) self.process_milestones(ticket, issue) session(ticket).flush(ticket) session(ticket).expunge(ticket) app.globals.custom_fields = self.postprocess_milestones() app.globals.last_ticket_num = self.max_ticket_num ThreadLocalORMSession.flush_all() M.AuditLog.log( 'import tool %s from %s on %s' % ( app.config.options.mount_point, project_name, self.source), project=project, user=user, url=app.url) g.post_event('project_updated') app.globals.invalidate_bin_counts() return app finally: M.session.artifact_orm_session._get().skip_mod_date = False
def update(self, icon=None, short=None, full=None): require_access(self.neighborhood, 'admin') self.award.short = short self.award.full = full if hasattr(icon, 'filename'): if self.award.icon: self.award.icon.delete() M.AwardFile.save_image( icon.filename, icon.file, content_type=icon.type, square=True, thumbnail_size=(48, 48), thumbnail_meta=dict(award_id=self.award._id)) for grant in M.AwardGrant.query.find(dict(award_id=self.award._id)): with h.push_context(grant.granted_to_project_id): g.post_event('project_updated') flash('Award updated.') redirect(self.award.longurl())
def remove_user(self, role_id, username, **kw): group = M.ProjectRole.query.get(_id=ObjectId(role_id)) user = M.User.by_username(username.strip()) if group.name == 'Admin' and len(group.users_with_role()) == 1: return dict(error='You must have at least one user with the Admin role.') if not group: return dict(error='Could not find group with id %s' % role_id) if not user: return dict(error='User %s not found' % username) user_role = M.ProjectRole.by_user(user) if not user_role or group._id not in user_role.roles: return dict(error='%s (%s) is not in the group %s.' % (user.display_name, username, group.name)) M.AuditLog.log('remove user %s from %s', username, group.name) user_role.roles.remove(group._id) g.post_event('project_updated') return dict()
def update(self, icon=None, short=None, full=None): require_access(self.neighborhood, 'admin') self.award.short = short self.award.full = full if hasattr(icon, 'filename'): if self.award.icon: self.award.icon.delete() M.AwardFile.save_image( icon.filename, icon.file, content_type=icon.type, square=True, thumbnail_size=(48, 48), thumbnail_meta=dict(award_id=self.award._id)) for grant in M.AwardGrant.query.find(dict(award_id=self.award._id)): with h.push_context(grant.granted_to_project_id): g.post_event('project_updated') flash('Award updated.') redirect(self.award.longurl())
def reclone_repo(*args, **kwargs): from allura import model as M try: nbhd = M.Neighborhood.query.get(url_prefix='/%s/' % kwargs['prefix']) c.project = M.Project.query.get( shortname=kwargs['shortname'], neighborhood_id=nbhd._id) c.app = c.project.app_instance(kwargs['mount_point']) source_url = c.app.config.options.get('init_from_url') source_path = c.app.config.options.get('init_from_path') c.app.repo.init_as_clone(source_path, None, source_url) M.Notification.post_user( c.user, c.app.repo, 'created', text='Repository %s/%s created' % ( c.project.shortname, c.app.config.options.mount_point)) except Exception: g.post_event('repo_clone_task_failed', source_url, source_path, traceback.format_exc())
def reclone_repo(*args, **kwargs): from allura import model as M try: nbhd = M.Neighborhood.query.get(url_prefix='/%s/' % kwargs['prefix']) c.project = M.Project.query.get( shortname=kwargs['shortname'], neighborhood_id=nbhd._id) c.app = c.project.app_instance(kwargs['mount_point']) source_url = c.app.config.options.get('init_from_url') source_path = c.app.config.options.get('init_from_path') c.app.repo.init_as_clone(source_path, None, source_url) M.Notification.post_user( c.user, c.app.repo, 'created', text='Repository %s/%s created' % ( c.project.shortname, c.app.config.options.mount_point)) except Exception: g.post_event('repo_clone_task_failed', source_url, source_path, traceback.format_exc())
def grant(self, grant=None, recipient=None, url=None, comment=None): require_access(self.neighborhood, 'admin') grant_q = M.Award.query.find(dict(short=grant, created_by_neighborhood_id=self.neighborhood._id)).first() recipient_q = M.Project.query.find(dict( neighborhood_id=self.neighborhood._id, shortname=recipient, deleted=False)).first() if grant_q and recipient_q: app_config_id = ObjectId() award = M.AwardGrant(app_config_id=app_config_id) award.award_id = grant_q._id award.granted_to_project_id = recipient_q._id award.granted_by_neighborhood_id = self.neighborhood._id award.award_url = url award.comment = comment with h.push_context(recipient_q._id): g.post_event('project_updated') redirect(six.ensure_text(request.referer or '/'))
def grant(self, grant=None, recipient=None, url=None, comment=None): require_access(self.neighborhood, 'admin') grant_q = M.Award.query.find(dict(short=grant, created_by_neighborhood_id=self.neighborhood._id)).first() recipient_q = M.Project.query.find(dict( neighborhood_id=self.neighborhood._id, shortname=recipient, deleted=False)).first() if grant_q and recipient_q: app_config_id = ObjectId() award = M.AwardGrant(app_config_id=app_config_id) award.award_id = grant_q._id award.granted_to_project_id = recipient_q._id award.granted_by_neighborhood_id = self.neighborhood._id award.award_url = url award.comment = comment with h.push_context(recipient_q._id): g.post_event('project_updated') redirect(request.referer or '/')
def _add_trove(self, type, new_trove): current_troves = getattr(c.project, 'trove_%s' % type) trove_obj = M.TroveCategory.query.get(trove_cat_id=int(new_trove)) error_msg = None if type in ['license', 'audience', 'developmentstatus', 'language'] and len(current_troves) >= 6: error_msg = 'You may not have more than 6 of this category.' elif type in ['topic'] and len(current_troves) >= 3: error_msg = 'You may not have more than 3 of this category.' elif trove_obj is not None: if trove_obj._id not in current_troves: current_troves.append(trove_obj._id) M.AuditLog.log('add trove %s: %s', type, trove_obj.fullpath) # just in case the event handling is super fast ThreadLocalORMSession.flush_all() c.project.last_updated = datetime.utcnow() g.post_event('project_updated') else: error_msg = 'This category has already been assigned to the project.' return (trove_obj, error_msg)
def main(options): log.addHandler(logging.StreamHandler(sys.stdout)) log.setLevel(getattr(logging, options.log_level.upper())) nbhd = M.Neighborhood.query.get(name=options.neighborhood) if not nbhd: return 'Invalid neighborhood "%s".' % options.neighborhood admin_role = M.ProjectRole.by_name('Admin', project=nbhd.neighborhood_project) nbhd_admin = admin_role.users_with_role( project=nbhd.neighborhood_project)[0].user log.info('Making updates as neighborhood admin "%s"' % nbhd_admin.username) q = { 'neighborhood_id': nbhd._id, 'is_nbhd_project': False, 'deleted': False } private_count = public_count = 0 for projects in utils.chunked_find(M.Project, q): for p in projects: role_anon = M.ProjectRole.upsert(name='*anonymous', project_id=p.root_project._id) if M.ACE.allow(role_anon._id, 'read') not in p.acl: if options.test: log.info('Would be made public: "%s"' % p.shortname) else: log.info('Making public: "%s"' % p.shortname) p.acl.append(M.ACE.allow(role_anon._id, 'read')) with h.push_config(c, project=p, user=nbhd_admin): ThreadLocalORMSession.flush_all() g.post_event('project_updated') private_count += 1 else: log.info('Already public: "%s"' % p.shortname) public_count += 1 log.info('Already public: %s' % public_count) if options.test: log.info('Would be made public: %s' % private_count) else: log.info('Made public: %s' % private_count) return 0
def add_user(self, role_id, username, **kw): if not username or username == '*anonymous': return dict(error='You must choose a user to add.') group = M.ProjectRole.query.get(_id=ObjectId(role_id)) user = M.User.query.get(username=username.strip(), pending=False) if not group: return dict(error='Could not find group with id %s' % role_id) if not user: return dict(error='User %s not found' % username) user_role = M.ProjectRole.by_user(user, upsert=True) if group._id in user_role.roles: return dict(error='%s (%s) is already in the group %s.' % (user.display_name, username, group.name)) M.AuditLog.log('add user %s to %s', username, group.name) user_role.roles.append(group._id) if group.name == 'Admin': for ac in c.project.app_configs: c.project.app_instance(ac).subscribe(user) g.post_event('project_updated') return dict(username=username, displayname=user.display_name)
def mount_order(self, **kw): if not kw: raise exc.HTTPBadRequest('Expected kw params in the form of "ordinal: mount_point"') try: sorted_tools = sorted(list(kw.items()), key=lambda x: int(x[0])) except ValueError: raise exc.HTTPBadRequest('Invalid kw: expected "ordinal: mount_point"') for ordinal, mount_point in sorted_tools: try: c.project.app_config(mount_point).options.ordinal = int(ordinal) except AttributeError as e: # Handle sub project p = M.Project.query.get(shortname="{}/{}".format(c.project.shortname, mount_point), neighborhood_id=c.project.neighborhood_id) if p: p.ordinal = int(ordinal) M.AuditLog.log('Updated tool order') g.post_event('project_menu_updated') return {'status': 'ok'}
def import_tool(self, project, user, project_name=None, mount_point=None, mount_label=None, trac_url=None, user_map=None, **kw): """ Import Trac tickets into a new Allura Tracker tool. """ mount_point = mount_point or 'tickets' app = project.install_app( 'Tickets', mount_point=mount_point, mount_label=mount_label or 'Tickets', open_status_names='new assigned accepted reopened', closed_status_names='closed', import_id={ 'source': self.source, 'trac_url': trac_url, }, ) session(app.config).flush(app.config) session(app.globals).flush(app.globals) try: with h.push_config(c, app=app): TracImportSupport().perform_import( json.dumps(export(trac_url), cls=DateJSONEncoder), json.dumps({ 'user_map': json.loads(user_map) if user_map else {}, 'usernames_match': self.usernames_match(trac_url), }), ) AuditLog.log( 'import tool %s from %s' % ( app.config.options.mount_point, trac_url, ), project=project, user=user, url=app.url, ) g.post_event('project_updated') return app except Exception: h.make_app_admin_only(app) raise
def main(options): log.addHandler(logging.StreamHandler(sys.stdout)) log.setLevel(getattr(logging, options.log_level.upper())) nbhd = M.Neighborhood.query.get(name=options.neighborhood) if not nbhd: return 'Invalid neighborhood "%s".' % options.neighborhood admin_role = M.ProjectRole.by_name( 'Admin', project=nbhd.neighborhood_project) nbhd_admin = admin_role.users_with_role( project=nbhd.neighborhood_project)[0].user log.info('Making updates as neighborhood admin "%s"' % nbhd_admin.username) q = {'neighborhood_id': nbhd._id, 'is_nbhd_project': False, 'deleted': False} private_count = public_count = 0 for projects in utils.chunked_find(M.Project, q): for p in projects: role_anon = M.ProjectRole.upsert(name='*anonymous', project_id=p.root_project._id) if M.ACE.allow(role_anon._id, 'read') not in p.acl: if options.test: log.info('Would be made public: "%s"' % p.shortname) else: log.info('Making public: "%s"' % p.shortname) p.acl.append(M.ACE.allow(role_anon._id, 'read')) with h.push_config(c, project=p, user=nbhd_admin): ThreadLocalORMSession.flush_all() g.post_event('project_updated') private_count += 1 else: log.info('Already public: "%s"' % p.shortname) public_count += 1 log.info('Already public: %s' % public_count) if options.test: log.info('Would be made public: %s' % private_count) else: log.info('Made public: %s' % private_count) return 0
def update(self, card=None, **kw): permissions = self._index_permissions() old_permissions = dict(permissions) for args in card: perm = args['id'] new_group_ids = args.get('new', []) group_ids = args.get('value', []) if isinstance(new_group_ids, six.string_types): new_group_ids = [new_group_ids] if isinstance(group_ids, six.string_types): group_ids = [group_ids] # make sure the admin group has the admin permission if perm == 'admin': if c.project.is_root: pid = c.project._id else: pid = c.project.parent_id admin_group_id = str( M.ProjectRole.query.get(project_id=pid, name='Admin')._id) if admin_group_id not in group_ids + new_group_ids: flash( 'You cannot remove the admin group from the admin permission.', 'warning') group_ids.append(admin_group_id) permissions[perm] = [] role_ids = list(map(ObjectId, group_ids + new_group_ids)) permissions[perm] = role_ids c.project.acl = [] for perm, role_ids in six.iteritems(permissions): role_names = lambda ids: ','.join(sorted( pr.name for pr in M.ProjectRole.query.find(dict(_id={'$in': ids})))) old_role_ids = old_permissions.get(perm, []) if old_role_ids != role_ids: M.AuditLog.log('updated "%s" permissions: "%s" => "%s"', perm, role_names(old_role_ids), role_names(role_ids)) c.project.acl += [M.ACE.allow(rid, perm) for rid in role_ids] g.post_event('project_updated') redirect('.')
def import_tool( self, project, user, project_name=None, mount_point=None, mount_label=None, user_name=None, tool_option=None, **kw): """ Import a GitHub wiki into a new Wiki Allura tool. """ project_name = "%s/%s" % (user_name, project_name) extractor = GitHubProjectExtractor(project_name, user=user) wiki_avail = extractor.has_wiki() # has_wiki only indicates that wiki is enabled, but it does not mean # that it has any pages, so we should check if wiki repo actually # exists wiki_url = extractor.get_page_url('wiki_url') if not wiki_avail or not self.has_wiki_repo(wiki_url): return self.github_wiki_url = extractor.get_page_url( 'wiki_url').replace('.wiki', '/wiki') self.app = project.install_app( "Wiki", mount_point=mount_point or 'wiki', mount_label=mount_label or 'Wiki', import_id={ 'source': self.source, 'project_name': project_name, } ) with_history = tool_option == 'import_history' ThreadLocalORMSession.flush_all() self.github_markdown_converter = GitHubMarkdownConverter( user_name, project_name) try: M.session.artifact_orm_session._get().skip_mod_date = True with h.push_config(c, app=self.app): try: self.import_pages(wiki_url, history=with_history) except git.GitCommandError: log.error( 'Unable to clone GitHub wiki: ' 'wiki_url=%s; ' 'wiki_avail=%s; ' 'avail_url=%s', wiki_url, wiki_avail, extractor.get_page_url('project_info'), exc_info=True) raise ThreadLocalORMSession.flush_all() M.AuditLog.log( 'import tool %s from %s on %s' % ( self.app.config.options.mount_point, project_name, self.source), project=project, user=user, url=self.app.url) g.post_event('project_updated') return self.app except Exception: h.make_app_admin_only(self.app) raise finally: M.session.artifact_orm_session._get().skip_mod_date = False
def success(self, app): with h.push_config(c, project=self.project, app=app): g.post_event('import_tool_task_succeeded', self.importer.source, self.importer.tool_label, )
def revoke(self): require_access(self.neighborhood, 'admin') self.grant.delete() with h.push_context(self.project._id): g.post_event('project_updated') redirect(request.referer or '/')
project.tool_data.update(p.tool_data) for a in p.awards: M.AwardGrant(app_config_id=bson.ObjectId(), award_id=a._id, granted_to_project_id=project._id, granted_by_neighborhood_id=nbhd._id) if p.icon: with open(p.icon) as icon_file: project.save_icon(p.icon, icon_file) project.notifications_disabled = False with h.push_config(c, project=project, user=p.admin): ThreadLocalORMSession.flush_all() g.post_event('project_updated') session(project).clear() return 0 def create_projects(projects, nbhd, options): for p in projects: r = create_project(Object(p), nbhd, options) if r != 0: sys.exit(r) def main(options): log.addHandler(logging.StreamHandler(sys.stdout)) log.setLevel(getattr(logging, options.log_level.upper())) log.debug(options)
def import_tool(self, project, user, mount_point=None, mount_label=None, **kw): import_id_converter = ImportIdConverter.get() tracker_json = self._load_json(project) tracker_json['tracker_config']['options'].pop('ordinal', None) tracker_json['tracker_config']['options'].pop('mount_point', None) tracker_json['tracker_config']['options'].pop('mount_label', None) tracker_json['tracker_config']['options'].pop('import_id', None) app = project.install_app('tickets', mount_point, mount_label, import_id={ 'source': self.source, 'app_config_id': tracker_json['tracker_config']['_id'], }, open_status_names=tracker_json[ 'open_status_names'], closed_status_names=tracker_json[ 'closed_status_names'], **tracker_json['tracker_config']['options'] ) ThreadLocalORMSession.flush_all() try: M.session.artifact_orm_session._get().skip_mod_date = True for ticket_json in tracker_json['tickets']: reporter = self.get_user(ticket_json['reported_by']) owner = self.get_user(ticket_json['assigned_to']) with h.push_config(c, user=reporter, app=app): self.max_ticket_num = max( ticket_json['ticket_num'], self.max_ticket_num) ticket = TM.Ticket( app_config_id=app.config._id, import_id=import_id_converter.expand( ticket_json['ticket_num'], app), description=self.annotate( self.annotate( ticket_json['description'], owner, ticket_json[ 'assigned_to'], label=' owned'), reporter, ticket_json[ 'reported_by'], label=' created'), created_date=dateutil.parser.parse( ticket_json['created_date']), mod_date=dateutil.parser.parse( ticket_json['mod_date']), ticket_num=ticket_json['ticket_num'], summary=ticket_json['summary'], custom_fields=ticket_json['custom_fields'], status=ticket_json['status'], labels=ticket_json['labels'], votes_down=ticket_json['votes_down'], votes_up=ticket_json['votes_up'], votes=ticket_json['votes_up'] - ticket_json['votes_down'], assigned_to_id=owner._id, ) # add an attachment to the ticket ticket.add_multiple_attachments([File(a['url']) for a in ticket_json['attachments']]) # trigger the private property ticket.private = ticket_json['private'] self.process_comments( ticket, ticket_json['discussion_thread']['posts']) session(ticket).flush(ticket) session(ticket).expunge(ticket) app.globals.custom_fields = tracker_json['custom_fields'] self.process_bins(app, tracker_json['saved_bins']) app.globals.last_ticket_num = self.max_ticket_num M.AuditLog.log( 'import tool %s from exported Allura JSON' % ( app.config.options.mount_point, ), project=project, user=user, url=app.url, ) g.post_event('project_updated') app.globals.invalidate_bin_counts() ThreadLocalORMSession.flush_all() return app except Exception: h.make_app_admin_only(app) raise finally: M.session.artifact_orm_session._get().skip_mod_date = False
def refresh_repo(repo, all_commits=False, notify=True, new_clone=False, commits_are_new=None): if commits_are_new is None: commits_are_new = not all_commits and not new_clone all_commit_ids = commit_ids = list(repo.all_commit_ids()) if not commit_ids: # the repo is empty, no need to continue return new_commit_ids = unknown_commit_ids(commit_ids) stats_log = h.log_action(log, 'commit') for ci in new_commit_ids: stats_log.info( '', meta=dict( module='scm-%s' % repo.repo_id, read='0')) if not all_commits: # Skip commits that are already in the DB commit_ids = new_commit_ids log.info('Refreshing %d commits on %s', len(commit_ids), repo.full_fs_path) # Refresh commits seen = set() for i, oid in enumerate(commit_ids): repo.refresh_commit_info(oid, seen, not all_commits) if (i + 1) % 100 == 0: log.info('Refresh commit info %d: %s', (i + 1), oid) refresh_commit_repos(all_commit_ids, repo) # Refresh child references for i, oid in enumerate(commit_ids): ci = CommitDoc.m.find(dict(_id=oid), validate=False).next() refresh_children(ci) if (i + 1) % 100 == 0: log.info('Refresh child info %d for parents of %s', (i + 1), ci._id) # Clear any existing caches for branches/tags if repo.cached_branches: repo.cached_branches = [] session(repo).flush() if repo.cached_tags: repo.cached_tags = [] session(repo).flush() # The first view can be expensive to cache, # so we want to do it here instead of on the first view. repo.get_branches() repo.get_tags() if commits_are_new: for commit in commit_ids: new = repo.commit(commit) user = User.by_email_address(new.committed.email) if user is None: user = User.by_username(new.committed.name) if user is not None: g.statsUpdater.newCommit(new, repo.app_config.project, user) actor = user or TransientActor( activity_name=new.committed.name or new.committed.email) g.director.create_activity(actor, 'committed', new, related_nodes=[repo.app_config.project], tags=['commit', repo.tool.lower()]) from allura.webhooks import RepoPushWebhookSender by_branches, by_tags = _group_commits(repo, commit_ids) params = [] for b, commits in by_branches.iteritems(): ref = u'refs/heads/{}'.format(b) if b != '__default__' else None params.append(dict(commit_ids=commits, ref=ref)) for t, commits in by_tags.iteritems(): ref = u'refs/tags/{}'.format(t) params.append(dict(commit_ids=commits, ref=ref)) if params: RepoPushWebhookSender().send(params) log.info('Refresh complete for %s', repo.full_fs_path) g.post_event('repo_refreshed', len(commit_ids), all_commits, new_clone) # Send notifications if notify: send_notifications(repo, reversed(commit_ids))