def get_namespace(self, resource, context): # Find out broken links base = resource.abspath # Search only within the given resource query = get_base_path_query(base, min_depth=0) results = context.search(query) # Find out the broken links root = context.root broken = {} for link in context.database.catalog.get_unique_values('links'): if root.get_resource(link, soft=True) is not None: continue sub_results = results.search(PhraseQuery('links', link)) link = str(base.get_pathto(Path(link))) for brain in sub_results.get_documents(): broken.setdefault(brain.abspath, []).append(link) # Build the namespace items = [] total = 0 keys = broken.keys() keys.sort() for path in keys: links = broken[path] path = str(base.get_pathto(Path(path))) n = len(links) items.append({'path': path, 'links': links, 'n': n}) total += n return {'items': items, 'total': total}
def http_get(self): n = len(Path(self.mount_path)) path = Path(self.path)[n:] path = '%s%s' % (self.local_path, path) # 404 Not Found if not isfile(path): return set_response(self.soup_message, 404) # 304 Not Modified mtime = getmtime(path) mtime = datetime.utcfromtimestamp(mtime) mtime = mtime.replace(microsecond=0) mtime = fixed_offset(0).localize(mtime) since = self.get_header('If-Modified-Since') if since and since >= mtime: return set_response(self.soup_message, 304) # 200 Ok # FIXME Check we set the encoding for text files mimetype = get_mimetype(basename(path)) data = open(path).read() self.soup_message.set_status(200) self.soup_message.set_response(mimetype, data) self.set_header('Last-Modified', mtime)
def update_links(self, source, target): base = self.get_canonical_path() resources_new2old = get_context().database.resources_new2old base = str(base) old_base = resources_new2old.get(base, base) old_base = Path(old_base) new_base = Path(base) handler = self.handler get_value = handler.get_record_value for record in handler.get_records_in_order(): path = get_value(record, 'name') if not path: continue ref = get_reference(path) if ref.scheme: continue # Strip the view path = ref.path name = path.get_name() if name and name[0] == ';': view = '/' + name path = path[:-1] else: view = '' path = str(old_base.resolve2(path)) if path == source: # Hit the old name # Build the new reference with the right path new_ref = deepcopy(ref) new_ref.path = str(new_base.get_pathto(target)) + view handler.update_record(record.id, **{'name': str(new_ref)}) get_context().server.change_resource(self)
def get_fallback(self, resource, context): n = len(Path(self.mount_path)) path = Path(context.path)[n:] path = '%s%s' % (self.local_path, path) # 404 Not Found if not isfile(path): return context.set_default_response(404) # 304 Not Modified mtime = getmtime(path) mtime = datetime.utcfromtimestamp(mtime) mtime = mtime.replace(microsecond=0) mtime = fixed_offset(0).localize(mtime) since = context.get_header('If-Modified-Since') if since and since >= mtime: raise NotModified # 200 Ok # FIXME Check we set the encoding for text files mimetype = get_mimetype(basename(path)) # Get data with open(path, 'r') as f: data = f.read() # Response context.status = 200 context.set_content_type(mimetype) context.set_header('Last-Modified', mtime) return data
def copy_resource(self, source_path, target_path, exclude_patterns=None, check_if_authorized=True): # Find out the source and target absolute URIs source_path, target_path = self._resolve_source_target(source_path, target_path) # Exclude patterns if exclude_patterns is None: exclude_patterns = [] for exclude_pattern in exclude_patterns: if fnmatch.fnmatch(str(source_path), exclude_pattern): return # Get the source and target resources source = self.get_resource(source_path) childs = list(source.get_resources()) parent_path = target_path.resolve2('..') target_parent = self.get_resource(parent_path) # Check compatibility if (check_if_authorized and (not target_parent.can_paste(source) or not source.can_paste_into(target_parent))): message = u'resource type "{0}" cannot be copied into type "{1}"' message = message.format(source.class_title.gettext(), target_parent.class_title.gettext()) raise ConsistencyError(message) # Copy the metadata folder = self.handler folder.copy_handler('%s.metadata' % source_path, '%s.metadata' % target_path) # Copy the content database = self.database new_name = target_path.get_name() for old_name, new_name in source.rename_handlers(new_name): if old_name is None: continue src_key = Path(source_path).resolve(old_name) dst_key = Path(target_path).resolve(new_name) if folder.has_handler(src_key): folder.copy_handler(src_key, dst_key, exclude_patterns) # Events, add resource = self.get_resource(target_path) database.add_resource(resource) # Set ctime and mtime context = get_context() now = context.timestamp resource.set_uuid() resource.set_value('ctime', now) resource.set_value('mtime', now) # Childs for child in childs: source_path_child = source_path.resolve2(child.name) target_path_child = target_path.resolve2(child.name) self.copy_resource(source_path_child, target_path_child, exclude_patterns, check_if_authorized=False) # Ok return resource
def move_resource(self, source_path, target_path, check_if_authorized=True): # Find out the source and target absolute URIs source_path, target_path = self._resolve_source_target(source_path, target_path) # Get the source and target resources source = self.get_resource(source_path) parent_path = target_path.resolve2('..') target_parent = self.get_resource(parent_path) # Cannot move a resource to a subdirectory of itself abspath = self.abspath aux = source.abspath if aux.get_prefix(abspath) == aux: message = 'cannot move a resource to a subdirectory of itself' raise ConsistencyError, message # Check compatibility if (check_if_authorized and (not target_parent.can_paste(source) or not source.can_paste_into(target_parent))): message = 'resource type "%r" cannot be moved into type "%r"' raise ConsistencyError, message % (source, target_parent) # Events, remove database = self.database new_path = self.abspath.resolve2(target_path) database.move_resource(source, new_path) # Get childs childs = list(source.get_resources()) # Move the metadata folder = self.handler folder.move_handler('%s.metadata' % source_path, '%s.metadata' % target_path) # Move the content new_name = target_path.get_name() for old_name, new_name in source.rename_handlers(new_name): if old_name is None: continue src_key = Path(source_path).resolve(old_name) dst_key = Path(target_path).resolve(new_name) if folder.has_handler(src_key): folder.move_handler(src_key, dst_key) # Childs for child in childs: source_path_child = source_path.resolve2(child.name) target_path_child = target_path.resolve2(child.name) self.move_resource(source_path_child, target_path_child, check_if_authorized=False)
def get_resource(self, abspath, soft=False): if type(abspath) is str: path = abspath[1:] abspath = Path(abspath) else: path = str(abspath)[1:] path_to_metadata = '%s.metadata' % path metadata = self.get_handler(path_to_metadata, Metadata, soft=soft) if metadata is None: return None # 2. Class class_id = metadata.format cls = self.get_resource_class(class_id) if cls is None: if self.fs.exists(path): is_file = self.fs.is_file(path) else: # FIXME This is just a guess, it may fail. is_file = '/' in format if is_file: cls = self.get_resource_class('application/octet-stream') else: cls = self.get_resource_class('application/x-not-regular-file') # Ok resource = cls(metadata) resource.abspath = abspath return resource
def _resolve_source_target(self, source_path, target_path): if type(source_path) is not Path: source_path = Path(source_path) if type(target_path) is not Path: target_path = Path(target_path) # Load the handlers so they are of the right class, for resources # like that define explicitly the handler class. This fixes for # instance copy&cut&paste of a tracker in a just started server. # TODO this is a work-around, there should be another way to define # explicitly the handler class. source = self.get_resource(source_path) for resource in source.traverse_resources(): resource.load_handlers() return source_path, target_path
def update_links(self, source, target): super(CSS, self).update_links(source, target) resources_new2old = get_context().database.resources_new2old base = str(self.abspath) old_base = resources_new2old.get(base, base) old_base = Path(old_base) new_base = Path(base) def my_func(matchobj): uri = matchobj.group(1) reference = css_get_reference(uri) # Skip empty links, external links and links to '/ui/' if reference.scheme or reference.authority: return matchobj.group(0) path = reference.path if not path or path[0] == 'ui': return matchobj.group(0) # Strip the view name = path.get_name() if name and name[0] == ';': view = '/' + name path = path[:-1] else: view = '' # Resolve the path # Absolute path are relative to site root if not path.is_absolute(): path = old_base.resolve2(path) # Match ? if path == source: path = str(new_base.get_pathto(target)) + view new_path = Reference('', '', path, reference.query.copy(), reference.fragment) return "url('%s')" % new_path return matchobj.group(0) data = self.to_text().encode('utf-8') new_data = css_uri_expr.sub(my_func, data) self.handler.load_state_from_string(new_data) get_context().database.change_resource(self)
def get_metadata(self, abspath, soft=False): if type(abspath) is str: path = abspath[1:] abspath = Path(abspath) else: path = str(abspath)[1:] path_to_metadata = '%s.metadata' % path return self.get_handler(path_to_metadata, Metadata, soft=soft)
def update_links(self, source, target): """The resource identified by 'source' is going to be moved to 'target'. Update our links to it. The parameters 'source' and 'target' are absolute 'Path' objects. """ base = str(self.abspath) old_base = self.database.resources_new2old.get(base, base) old_base = Path(old_base) new_base = Path(base) languages = self.get_resource('/').get_value('website_languages') for field_name in self.fields: field = self.get_field(field_name) if field: field.update_links(self, field_name, source, target, languages, old_base, new_base) self.reindex()
def normalize_key(self, path, __root=Path('/')): # Performance is critical so assume the path is already relative to # the repository. key = __root.resolve(path) if key and key[0] == '.git': err = "bad '%s' path, access to the '.git' folder is denied" raise ValueError, err % path return '/'.join(key)
def test_simplenorm(self): """ Test the simple path normalization: - 'a/./b' = 'a/b' - 'a//b' = 'a/b' - './a' = 'a' - 'a/' = 'a' """ path = Path('./a/./b//c/') self.assertEqual(str(path), 'a/b/c/')
def get_resource(self, path, soft=False): if type(path) is not Path: path = Path(path) # 1. Get the metadata if path.is_absolute(): abspath = path else: abspath = self.abspath.resolve2(path) return self.database.get_resource(abspath, soft=soft)
def get_options(self): context = get_context() items = [] for doc in context.search(base_classes='folder').get_documents(): path = Path(doc.abspath) title = '/' if not path else ('%s/' % path) items.append({'name': path, 'value': title, 'selected': False}) items.sort(key=lambda x: x['value']) return items
def get_resource(self, abspath, soft=False): abspath = Path(abspath) # Get metadata metadata = self.get_metadata(abspath, soft) if metadata is None: return None # Get associated class class_id = metadata.format cls = self.get_cls(class_id) # Ok return cls(abspath=abspath, database=self, metadata=metadata)
def set_prefix(stream, prefix, ns_uri=xhtml_uri, uri=None): if isinstance(prefix, str): prefix = Path(prefix) ref = None if uri: ref = Reference(scheme=uri.scheme, authority=uri.authority, path='/', query={}) rewrite = partial(resolve_pointer, prefix, ref) return rewrite_uris(stream, rewrite, ns_uri)
class PathDataType(DataType): # TODO Do like URI, do not decode (just an string), and use 'is_valid' # instead default = Path('') @staticmethod def decode(value): return Path(value) @staticmethod def encode(value): return str(value)
def get_item_value(self, resource, context, item, column): if column == 'checkbox': if self.is_folder(item): return None proxy = super(AddImage_BrowseContent, self) return proxy.get_item_value(resource, context, item, column) elif column == 'icon': if self.is_folder(item): # icon path_to_icon = item.get_resource_icon(48) if path_to_icon.startswith(';'): path_to_icon = Path('%s/' % item.name).resolve(path_to_icon) else: path = item.abspath path_to_icon = ";thumb?width=48&height=48" if path: path_to_resource = Path(str(path) + '/') path_to_icon = path_to_resource.resolve(path_to_icon) return path_to_icon else: proxy = super(AddImage_BrowseContent, self) return proxy.get_item_value(resource, context, item, column)
def init_context(self): soup_message = self.soup_message path = self.path # The request method self.method = soup_message.get_method() # The query query = soup_message.get_query() self.query = decode_query(query) # The URI as it was typed by the client xfp = soup_message.get_header('X_FORWARDED_PROTO') src_scheme = xfp or 'http' xff = soup_message.get_header('X-Forwarded-Host') if xff: xff = xff.split(',', 1)[0].strip() hostname = soup_message.get_host() src_host = xff or soup_message.get_header('Host') or hostname if query: uri = '%s://%s%s?%s' % (src_scheme, src_host, path, query) else: uri = '%s://%s%s' % (src_scheme, src_host, path) self.uri = get_reference(uri) # Split the path into path and method ("a/b/c/;view") path = path if type(path) is Path else Path(path) name = path.get_name() if name and name[0] == ';': self.path = path[:-1] self.view_name = name[1:] else: self.path = path self.view_name = None # Cookies self.cookies = {} # Media files (CSS, javascript) # Set the list of needed resources. The method we are going to # call may need external resources to be rendered properly, for # example it could need an style sheet or a javascript file to # be included in the html head (which it can not control). This # attribute lets the interface to add those resources. self.styles = [] self.scripts = [] # The authenticated user self.authenticate() # The Site Root self.find_site_root() self.site_root.before_traverse(self) # Hook
def launch_npm_install(self): done = False for path in self.manifest: filename = get_uri_name(path) if filename == 'package.json': print '***' * 25 print '*** Run $ npm install on ', path print '***' * 25 path = str(Path(path)[:-1]) + '/' p = Popen(['npm', 'install'], cwd=path) p.wait() if p.returncode == 1: print '***' * 25 print '*** Error running npm install ', path print '***' * 25 sys.exit(1) done = True return done
def launch_gulp_build(self): done = False for path in self.manifest: filename = get_uri_name(path) if filename == 'package.json': print '***' * 25 print '*** Run $ gulp build on ', path print '***' * 25 path = str(Path(path)[:-1]) + '/' p = Popen(['gulp', 'build'], cwd=path) p.wait() if p.returncode == 1: print '***' * 25 print '*** Error running gulp ', path print '***' * 25 sys.exit(1) done = True return done
def launch_webpack(self): done = False for path in self.manifest: filename = get_uri_name(path) if filename == 'webpack.config.js': print '***'*25 print '*** Run $ webpack ', path print '***'*25 path = str(Path(path)[:-1]) + '/' p = Popen(['./node_modules/.bin/webpack', '--mode=production'], cwd=path) p.wait() if p.returncode == 1: print '***'*25 print '*** Error running webpack ', path print '***'*25 sys.exit(1) done = True return done
def get_template(self, web_path): warning = None web_path_object = Path(normalize_path(web_path)) skin_name = web_path_object[1] try: skin = skin_registry[skin_name] except KeyError: warning = 'WARNING: web_path {} is obsolete use /ui/ikaaro/' warning = warning.format(web_path) web_path = web_path.replace('/ui/', '/ui/ikaaro/') skin = skin_registry['ikaaro'] # 1) Try with envionment skin skin_key = skin.get_environment_key(self.server) web_path = web_path.replace(skin.base_path, '') template = self.get_template_from_skin_key(skin_key, web_path, warning) if template: return template # 2) Try with standard skin return self.get_template_from_skin_key(skin.key, web_path, warning)
def get_item_value(self, resource, context, item, column): if column == 'checkbox': # checkbox parent = item.parent if parent is None: return None if item.name in parent.__fixed_handlers__: return None resource_id = str(item.abspath) return resource_id, False elif column == 'icon': # icon path_to_icon = item.get_resource_icon(16) if not path_to_icon: return None if path_to_icon.startswith(';'): path_to_icon = Path('%s/' % item.name).resolve(path_to_icon) return path_to_icon elif column == 'abspath': # Name resource_id = str(item.abspath) view = item.get_view(None) if view is None: return resource_id return resource_id, context.get_link(item) elif column == 'format': # Type return item.class_title.gettext() elif column == 'mtime': # Last Modified mtime = item.get_value('mtime') if mtime: return context.format_datetime(mtime) return None elif column == 'last_author': # Last author author = item.get_value('last_author') return context.root.get_user_title(author) if author else None elif column == 'row_css': return None # Default return item.get_value_title(column)
def get_available_languages(self): """Returns the language codes for the user interface. """ source = itools_source_language target = itools_target_languages # A package based on itools cls = self.__class__ if cls is not Root: exec('import %s as pkg' % cls.__module__.split('.', 1)[0]) config = Path(pkg.__path__[0]).resolve_name('setup.conf') config = ConfigFile(str(config)) source = config.get_value('source_language', default=source) target = config.get_value('target_languages', default=target) target = target.split() if source in target: target.remove(source) target.insert(0, source) return target
def _on_move_resource(self, source): """This method updates the links from/to other resources. It is called when the resource has been moved and/or renamed. This method is called by 'Database._before_commit', the 'source' parameter is the place the resource has been moved from. """ # (1) Update links to other resources self.update_incoming_links(Path(source)) # (2) Update resources that link to me database = self.database target = self.abspath query = PhraseQuery('links', source) results = database.search(query).get_documents() for result in results: path = result.abspath path = database.resources_old2new.get(path, path) resource = self.get_resource(path) resource.update_links(source, target)
def send_confirm_url(self, context, email, subject, text, view): # XXX We override send_confirm_url to send mail # without setting subject with host, to use shop_uri # and not backoffice_uri (Since webmaster click from backoffice uri) # and to use good from_addr # Set the confirmation key if self.has_property('user_must_confirm'): key = self.get_property('user_must_confirm') else: key = generate_password(30) self.set_property('user_must_confirm', key) # Build the confirmation link shop = get_shop(context.resource) base_uri = shop.get_property('shop_uri') confirm_url = get_reference(base_uri) path = '/users/%s/%s' % (self.name, view) confirm_url.path = Path(path) confirm_url.query = {'key': key, 'username': self.get_login_name()} confirm_url = str(confirm_url) text = text.gettext(uri=confirm_url, key=key) # Get from_addr site_root = context.site_root if site_root.get_property('emails_from_addr'): user_name = site_root.get_property('emails_from_addr') user = self.get_resource('/users/%s' % user_name) from_addr = user.get_title(), user.get_property('email') else: from_addr = context.server.smtp_from # Subject subject = u'[%s] %s' % (base_uri, subject.gettext()) # Send email context.root.send_email(email, subject, from_addr=from_addr, text=text, subject_with_host=False)
def send_register_confirmation(self, context, need_email_validation=False): # Get group group = self.get_group(context) # Get mail subject and body subject = group.get_register_mail_subject() text = group.get_register_mail_body() # Registration need validation ? if need_email_validation: key = generate_password(30) self.set_property('user_must_confirm', key) # Build the confirmation link confirm_url = deepcopy(context.uri) path = '/users/%s/;confirm_registration' % self.name confirm_url.path = Path(path) confirm_url.query = {'key': key, 'username': self.get_login_name()} confirm_url = str(confirm_url) text += '\n\n' text += self.confirmation_txt.gettext(uri=confirm_url, key=key) # Send mail context.root.send_email(to_addr=self.get_property('email'), subject=subject, text=text)
def get_resource(self, path, soft=False): if type(path) is not Path: path = Path(path) if path.is_absolute(): here = self.get_root() else: here = self while path and path[0] == '..': here = here.parent path = path[1:] for name in path: resource = here._get_resource(name) if resource is None: if soft is True: return None raise LookupError, 'resource "%s" not found' % path resource.parent = here resource.name = name here = resource return here