def render_timeline_event(self, context, field, event): # Decompose event data. title, description, path = event[3] # Return apropriate content. if field == 'url': if not path: # method is DELETE return '' files_core = FilesCoreComponent(self.env) req = None try: req = context.req except AttributeError as e: pass download_config = files_core.files_download_config(req=req) node = FileSystemNode(download_config.base_path) node.populate_file_data( get_normalized_relative_path(node.base_path, path, assume_relative_path=True)) if node.exists(): return context.href.files(node.relative_path) else: return "" elif field == 'title': return tag(title) elif field == 'description': return tag(description)
def render_timeline_event(self, context, field, event): # Decompose event data. title, description, path = event[3] # Return apropriate content. if field == 'url': if not path: # method is DELETE return '' files_core = FilesCoreComponent(self.env) req = None try: req = context.req except AttributeError as e: pass download_config = files_core.files_download_config(req=req) node = FileSystemNode(download_config.base_path) node.populate_file_data(get_normalized_relative_path(node.base_path, path, assume_relative_path=True)) if node.exists(): return context.href.files(node.relative_path) else: return "" elif field == 'title': return tag(title) elif field == 'description': return tag(description)
def _handle_change(self, command, downloads_dir_name, can_be_moved): try: env_name = self.env.project_identifier except AttributeError as e: # In case of trac admin commands, project_identifier is not found env_name = self.env.path.split('/')[-1] self.env.project_identifier = env_name download_config = FilesDownloadConfig(env_name) if downloads_dir_name is None: files_core = FilesCoreComponent(self.env) downloads_dir_name = files_core.default_downloads_directory node_factory = FileSystemNode(download_config.base_path) old_node, old_dir_exists = self.get_dir_data(download_config, node_factory) if command == 'downloads-dir-create': if old_dir_exists: raise AdminCommandError( _('Project already has existing downloads directory')) node = FileSystemNode.from_path(downloads_dir_name, node_factory) if node.exists(): raise AdminCommandError( _('The given downloads directory already exists')) msg_handler = lambda msg: printout(msg) try: self.handle_change(download_config, downloads_dir_name, can_be_moved, node_factory, msg_handler, msg_handler) except TracError as e: raise AdminCommandError(str(e)) if command == 'downloads-dir-create': files_core = FilesCoreComponent(self.env) mapped_node_factory, mapped_download_config = files_core.files_node_factory_and_config( ) created_node = MappedFileNode.from_path( download_config.downloads_dir, mapped_node_factory) files_notifier = FilesEventNotifier(self.env) files_notifier.node_created('trac', created_node)
def handle_change(self, download_config, new_downloads_dir, can_be_moved, node_factory, warning, notice): """ :param FilesDownloadConfig download_config: download_configuration configuration :returns: True if new """ old_node, old_dir_exists = self.get_dir_data(download_config, node_factory) try: download_config.downloads_dir = new_downloads_dir except DownloadDirValidationException as e: raise TracError(_("New downloads directory is not valid: ") + str(e)) new_node = FileSystemNode.from_path(download_config.downloads_dir, node_factory) if new_node.exists() and not new_node.is_dir(): raise TracError(_("Error: Destination path exists and is a file")) elif new_node.exists() and can_be_moved: raise TracError(_("Error: Destination path already exists")) try: download_config.save() notice(_("Your changes have been saved.")) except Exception as e: self.log.exception("Failed to save downloads directory") raise TracError(_("Saving new value failed")) was_created = False if old_dir_exists and can_be_moved: try: old_node.move(new_node.relative_path) notice(_("Moved old downloads directory to be new one")) was_created = True except Exception as e: self.log.exception("Exception while moving old directory to new one") warning(_("Error while moving the old directory.")) elif not new_node.exists(): try: new_node.get_parent_dir().create_dir(new_node.filename) notice(_("Created new downloads directory")) was_created = True except Exception as e: self.log.exception("Creating new downloads directory failed.") warning(_("Creating new downloads directory failed.")) else: # not can_be_moved if old_dir_exists: try: for entry in ProjectDownloadEntry.get_all_download_entries(node_factory.project_id): entry.delete() except Exception as e: warning(_("Marking files as deleted failed")) notice(_("Set the new downloads directory to be the directory chosen.")) return was_created
def _downloads_dir_check(self): try: env_name = self.env.project_identifier except AttributeError as e: # In case of trac admin commands, project_identifier is not found env_name = self.env.path.split('/')[-1] self.env.project_identifier = env_name download_config = FilesDownloadConfig(env_name) node_factory = FileSystemNode(download_config.base_path) node, dir_exists = self.get_dir_data(download_config, node_factory) if dir_exists: printout("[+] {0:<30} '{1:}'".format( env_name, download_config.downloads_dir)) else: printout("[-] {0:<30} '{1:}'".format( env_name, download_config.downloads_dir))
def get_dir_data(self, download_config, node_factory): """ If there is a file (not dir) corresponding the current download_config.downloads_dir, resets the downloads dir to '' :returns: (old_node, old_dir_exists) """ old_node = None old_dir_exists = False if download_config.downloads_dir: old_node = FileSystemNode.from_path(download_config.downloads_dir, node_factory) if old_node.exists(): if not old_node.is_dir(): # Don't allow the download config to be a file, ever! download_config.reset_downloads_dir() else: old_dir_exists = True return old_node, old_dir_exists
def _handle_change(self, command, downloads_dir_name, can_be_moved): try: env_name = self.env.project_identifier except AttributeError as e: # In case of trac admin commands, project_identifier is not found env_name = self.env.path.split("/")[-1] self.env.project_identifier = env_name download_config = FilesDownloadConfig(env_name) if downloads_dir_name is None: files_core = FilesCoreComponent(self.env) downloads_dir_name = files_core.default_downloads_directory node_factory = FileSystemNode(download_config.base_path) old_node, old_dir_exists = self.get_dir_data(download_config, node_factory) if command == "downloads-dir-create": if old_dir_exists: raise AdminCommandError(_("Project already has existing downloads directory")) node = FileSystemNode.from_path(downloads_dir_name, node_factory) if node.exists(): raise AdminCommandError(_("The given downloads directory already exists")) msg_handler = lambda msg: printout(msg) try: self.handle_change( download_config, downloads_dir_name, can_be_moved, node_factory, msg_handler, msg_handler ) except TracError as e: raise AdminCommandError(str(e)) if command == "downloads-dir-create": files_core = FilesCoreComponent(self.env) mapped_node_factory, mapped_download_config = files_core.files_node_factory_and_config() created_node = MappedFileNode.from_path(download_config.downloads_dir, mapped_node_factory) files_notifier = FilesEventNotifier(self.env) files_notifier.node_created("trac", created_node)
def import_files(self, dry_run=False): dry_run = True if dry_run in ['-n', '--dry-run'] else False try: env_name = self.env.project_identifier except AttributeError: # Since open_environment is not used in trac-admin commands # we need to manually set the project_identifier env_name = self.env.path.split('/')[-1] self.env.project_identifier = env_name download_data_list = self.get_download_data() path = conf.getEnvironmentDownloadsPath(self.env) if download_data_list is None: printout("env:%(env_name)s, download table was not found" % {'env_name': self.env.project_identifier}) return files_core = FilesCoreComponent(self.env) node_factory, download_config = files_core.files_node_factory_and_config( ) env_name = download_config.env_name project_files = {} first_file = {} for download_data in download_data_list: filename = download_data['file'] id_ = download_data['id'] if filename not in project_files: project_files[filename] = [] first_file[filename] = id_ project_files[filename].append(id_) for download_data in download_data_list: filename = download_data['file'] id_ = download_data['id'] if not download_data['author_id']: printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "The author %(author)s of download %(download)s was not found." % { 'env_name': env_name, 'download': filename, 'id_': id_, 'author': download_data['author'] }) continue base_downloads_path = filesystem.safe_path(path, to_unicode(id_)) original_node = FileSystemNode(base_downloads_path) original_node.populate_file_data(filename) from_path = original_node._abs_path_encoded existing_node = MappedFileNode.from_download_path( filename, node_factory, True) download_path = filename if len(project_files[filename]) > 1: download_path = get_download_path(id_, filename) to_node = MappedFileNode.from_download_path( download_path, node_factory, True) else: # No duplicate downloads, put it into root to_node = existing_node if not to_node.is_download(): printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: Download information is incorrect" % { 'env_name': env_name, 'download': filename, 'id_': id_, 'rel_path': to_node.relative_path }) continue if to_node.download().is_available(): printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: The download information is already available" % { 'env_name': env_name, 'download': filename, 'id_': id_, 'rel_path': to_node.relative_path }) continue elif to_node.exists(): printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: The download already exists" % { 'env_name': env_name, 'download': filename, 'id_': id_, 'rel_path': to_node.relative_path }) continue can_be_removed = False download = self.populate_new_download(to_node.download(), original_node, download_data) if len(project_files[filename]) > 1: # If there were duplicate filenames, special handling for them is needed if (existing_node.exists() and existing_node.is_file() and existing_node.is_download()): old_download = existing_node.download() if (old_download.is_available() and old_download.hash == download.hash and old_download.version == 1 and download.uploader_id == old_download.uploader_id and download.created == old_download.created): # Copy all information, which might be changed download.clone_user_values(old_download) download.count = old_download.count can_be_removed = True else: # Else, we just accept that there has been changes # Download count might be duplicated. In that case, manual work # could be done. printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "Cannot remove download because it is not original or has changed, " "download count was %(count)s" % { 'env_name': env_name, 'id_': id_, 'download': filename, 'count': download.count }) if not dry_run: if os.path.sep in download_path: parent_dir = to_node.get_parent_dir() if not parent_dir.exists(): data = {'type': 'dir'} FileSystemNode.create_check(parent_dir, data) FileSystemNode.create_do(parent_dir, data) FileSystemNode.create_post_process(parent_dir, data) shutil.copy2(from_path, to_node._abs_path_encoded) to_node.chmod() self.save_new_download(download) if can_be_removed: existing_node.download().delete_completely() existing_node.remove_do({}) else: printout( "env:%(env_name)s file:%(download)s id:%(id_)s: " "Would copy file to %(download_path)s%(other)s" % { 'env_name': env_name, 'id_': id_, 'download': filename, 'download_path': to_node.download().download_path, 'other': can_be_removed and ', and would also remove original' or '' }) was_enabled = False if not self.env.is_component_enabled(DOWNLOADS_GLUE_COMPONENT): if not dry_run: self.env.config.set('components', DOWNLOADS_GLUE_COMPONENT, 'enabled') self.env.config.save() was_enabled = True if download_data_list: if was_enabled: printout( "env:%(env_name)s: downloads handled, component %(component)s enabled." % { 'env_name': env_name, 'component': DOWNLOADS_GLUE_COMPONENT }) else: printout("env:%(env_name)s: downloads handled." % {'env_name': env_name}) else: printout( "env:%(env_name)s: no downloads found, component %(component)s enabled." % { 'env_name': env_name, 'component': DOWNLOADS_GLUE_COMPONENT })
def import_files(self, dry_run=False): dry_run = True if dry_run in ['-n', '--dry-run'] else False try: env_name = self.env.project_identifier except AttributeError: # Since open_environment is not used in trac-admin commands # we need to manually set the project_identifier env_name = self.env.path.split('/')[-1] self.env.project_identifier = env_name download_data_list = self.get_download_data() path = conf.getEnvironmentDownloadsPath(self.env) if download_data_list is None: printout("env:%(env_name)s, download table was not found" % {'env_name': self.env.project_identifier}) return files_core = FilesCoreComponent(self.env) node_factory, download_config = files_core.files_node_factory_and_config() env_name = download_config.env_name project_files = {} first_file = {} for download_data in download_data_list: filename = download_data['file'] id_ = download_data['id'] if filename not in project_files: project_files[filename] = [] first_file[filename] = id_ project_files[filename].append(id_) for download_data in download_data_list: filename = download_data['file'] id_ = download_data['id'] if not download_data['author_id']: printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "The author %(author)s of download %(download)s was not found." % {'env_name':env_name, 'download': filename, 'id_': id_, 'author':download_data['author']}) continue base_downloads_path = filesystem.safe_path(path, to_unicode(id_)) original_node = FileSystemNode(base_downloads_path) original_node.populate_file_data(filename) from_path = original_node._abs_path_encoded existing_node = MappedFileNode.from_download_path(filename, node_factory, True) download_path = filename if len(project_files[filename]) > 1: download_path = get_download_path(id_, filename) to_node = MappedFileNode.from_download_path(download_path, node_factory, True) else: # No duplicate downloads, put it into root to_node = existing_node if not to_node.is_download(): printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: Download information is incorrect" % {'env_name':env_name, 'download': filename, 'id_': id_, 'rel_path':to_node.relative_path}) continue if to_node.download().is_available(): printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: The download information is already available" % {'env_name':env_name, 'download': filename, 'id_': id_, 'rel_path':to_node.relative_path}) continue elif to_node.exists(): printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "With %(rel_path)s: The download already exists" % {'env_name':env_name, 'download': filename, 'id_': id_, 'rel_path':to_node.relative_path}) continue can_be_removed = False download = self.populate_new_download(to_node.download(), original_node, download_data) if len(project_files[filename]) > 1: # If there were duplicate filenames, special handling for them is needed if (existing_node.exists() and existing_node.is_file() and existing_node.is_download()): old_download = existing_node.download() if (old_download.is_available() and old_download.hash == download.hash and old_download.version == 1 and download.uploader_id == old_download.uploader_id and download.created == old_download.created): # Copy all information, which might be changed download.clone_user_values(old_download) download.count = old_download.count can_be_removed = True else: # Else, we just accept that there has been changes # Download count might be duplicated. In that case, manual work # could be done. printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "Cannot remove download because it is not original or has changed, " "download count was %(count)s" % {'env_name':env_name, 'id_': id_, 'download': filename, 'count': download.count}) if not dry_run: if os.path.sep in download_path: parent_dir = to_node.get_parent_dir() if not parent_dir.exists(): data = {'type': 'dir'} FileSystemNode.create_check(parent_dir, data) FileSystemNode.create_do(parent_dir, data) FileSystemNode.create_post_process(parent_dir, data) shutil.copy2(from_path, to_node._abs_path_encoded) to_node.chmod() self.save_new_download(download) if can_be_removed: existing_node.download().delete_completely() existing_node.remove_do({}) else: printout("env:%(env_name)s file:%(download)s id:%(id_)s: " "Would copy file to %(download_path)s%(other)s" % {'env_name':env_name, 'id_': id_, 'download': filename, 'download_path': to_node.download().download_path, 'other': can_be_removed and ', and would also remove original' or ''}) was_enabled = False if not self.env.is_component_enabled(DOWNLOADS_GLUE_COMPONENT): if not dry_run: self.env.config.set('components', DOWNLOADS_GLUE_COMPONENT, 'enabled') self.env.config.save() was_enabled = True if download_data_list: if was_enabled: printout("env:%(env_name)s: downloads handled, component %(component)s enabled." %{'env_name': env_name, 'component': DOWNLOADS_GLUE_COMPONENT}) else: printout("env:%(env_name)s: downloads handled." % {'env_name': env_name}) else: printout("env:%(env_name)s: no downloads found, component %(component)s enabled." %{'env_name': env_name, 'component': DOWNLOADS_GLUE_COMPONENT})
def render_admin_panel(self, req, category, page, path_info): req.perm.require('FILES_DOWNLOADS_ADMIN') env_name = self.env.project_identifier download_config = FilesDownloadConfig(env_name) node_factory = FileSystemNode(download_config.base_path) files_console = FilesConsoleAdmin(self.env) old_node, old_dir_exists = files_console.get_dir_data( download_config, node_factory) self.log.debug('downloads directory is "%s"', download_config.downloads_dir) new_dir_name = '' if req.method == 'POST': req.perm.require('FILES_DOWNLOADS_ADMIN') new_dir_name = req.args.get('new_dir_name') old_dir_select = req.args.get('old_dir_select') old_downloads_dir = req.args.get('old_downloads_dir') do_update = True if old_downloads_dir: if download_config.downloads_dir != old_downloads_dir: add_warning( req, _('The downloads directory has been changed. ' ' Check the new directory and try again, if needed.') ) do_update = False if do_update: can_be_moved = bool(req.args.get('move_also')) warning = lambda msg: add_warning(req, msg) notice = lambda msg: add_notice(req, msg) if old_dir_select and new_dir_name: add_warning( req, _('Cannot decide, what to do: ' 'Both old directory selected and new directory name given.' )) elif not old_dir_select: if old_dir_exists and new_dir_name == old_downloads_dir: add_notice( req, _('Old downloads dir was the required one.')) elif new_dir_name: # Create new directory files_console.handle_change(download_config, new_dir_name, can_be_moved, node_factory, warning, notice) req.redirect(req.href.admin(category, page)) else: add_warning(req, _('No new directory name given.')) else: if old_dir_exists and old_dir_select == old_downloads_dir: add_notice( req, _('Old downloads dir was the required one.')) elif old_dir_select == '__delete__': if old_dir_exists: files_console.handle_unset(warning, notice) req.redirect(req.href.admin(category, page)) else: add_notice( req, _('Old downloads dir was already unset.')) else: files_console.handle_change(download_config, old_dir_select, False, node_factory, warning, notice) req.redirect(req.href.admin(category, page)) root_node = FileSystemNode.from_path('.', node_factory) dirs, files = root_node.get_dirs_and_files() default_downloads_directory = FilesCoreComponent( self.env).default_downloads_directory data = { 'downloads_dir': download_config.downloads_dir, 'available_dirs': dirs, 'old_dir_exists': old_dir_exists, 'show_confirm': False, 'public_downloads_default': default_downloads_directory, 'new_dir_name': new_dir_name } return 'multiproject_admin_files.html', data
def handle_change(self, download_config, new_downloads_dir, can_be_moved, node_factory, warning, notice): """ :param FilesDownloadConfig download_config: download_configuration configuration :returns: True if new """ old_node, old_dir_exists = self.get_dir_data(download_config, node_factory) try: download_config.downloads_dir = new_downloads_dir except DownloadDirValidationException as e: raise TracError( _('New downloads directory is not valid: ') + str(e)) new_node = FileSystemNode.from_path(download_config.downloads_dir, node_factory) if new_node.exists() and not new_node.is_dir(): raise TracError(_('Error: Destination path exists and is a file')) elif new_node.exists() and can_be_moved: raise TracError(_("Error: Destination path already exists")) try: download_config.save() notice(_('Your changes have been saved.')) except Exception as e: self.log.exception('Failed to save downloads directory') raise TracError(_('Saving new value failed')) was_created = False if old_dir_exists and can_be_moved: try: old_node.move(new_node.relative_path) notice(_('Moved old downloads directory to be new one')) was_created = True except Exception as e: self.log.exception( 'Exception while moving old directory to new one') warning(_('Error while moving the old directory.')) elif not new_node.exists(): try: new_node.get_parent_dir().create_dir(new_node.filename) notice(_('Created new downloads directory')) was_created = True except Exception as e: self.log.exception('Creating new downloads directory failed.') warning(_('Creating new downloads directory failed.')) else: # not can_be_moved if old_dir_exists: try: for entry in ProjectDownloadEntry.get_all_download_entries( node_factory.project_id): entry.delete() except Exception as e: warning(_("Marking files as deleted failed")) notice( _('Set the new downloads directory to be the directory chosen.' )) return was_created
def render_admin_panel(self, req, category, page, path_info): req.perm.require("FILES_DOWNLOADS_ADMIN") env_name = self.env.project_identifier download_config = FilesDownloadConfig(env_name) node_factory = FileSystemNode(download_config.base_path) files_console = FilesConsoleAdmin(self.env) old_node, old_dir_exists = files_console.get_dir_data(download_config, node_factory) self.log.debug('downloads directory is "%s"', download_config.downloads_dir) new_dir_name = "" if req.method == "POST": req.perm.require("FILES_DOWNLOADS_ADMIN") new_dir_name = req.args.get("new_dir_name") old_dir_select = req.args.get("old_dir_select") old_downloads_dir = req.args.get("old_downloads_dir") do_update = True if old_downloads_dir: if download_config.downloads_dir != old_downloads_dir: add_warning( req, _( "The downloads directory has been changed. " " Check the new directory and try again, if needed." ), ) do_update = False if do_update: can_be_moved = bool(req.args.get("move_also")) warning = lambda msg: add_warning(req, msg) notice = lambda msg: add_notice(req, msg) if old_dir_select and new_dir_name: add_warning( req, _("Cannot decide, what to do: " "Both old directory selected and new directory name given."), ) elif not old_dir_select: if old_dir_exists and new_dir_name == old_downloads_dir: add_notice(req, _("Old downloads dir was the required one.")) elif new_dir_name: # Create new directory files_console.handle_change( download_config, new_dir_name, can_be_moved, node_factory, warning, notice ) req.redirect(req.href.admin(category, page)) else: add_warning(req, _("No new directory name given.")) else: if old_dir_exists and old_dir_select == old_downloads_dir: add_notice(req, _("Old downloads dir was the required one.")) elif old_dir_select == "__delete__": if old_dir_exists: files_console.handle_unset(warning, notice) req.redirect(req.href.admin(category, page)) else: add_notice(req, _("Old downloads dir was already unset.")) else: files_console.handle_change( download_config, old_dir_select, False, node_factory, warning, notice ) req.redirect(req.href.admin(category, page)) root_node = FileSystemNode.from_path(".", node_factory) dirs, files = root_node.get_dirs_and_files() default_downloads_directory = FilesCoreComponent(self.env).default_downloads_directory data = { "downloads_dir": download_config.downloads_dir, "available_dirs": dirs, "old_dir_exists": old_dir_exists, "show_confirm": False, "public_downloads_default": default_downloads_directory, "new_dir_name": new_dir_name, } return "multiproject_admin_files.html", data