text: """wiki class
  """
  
  import os
  import re
  
  from flask import url_for, redirect
  
  from loris.app.wiki.page import Page
  from loris.app.wiki.utils import clean_url
  
  
  class Wiki(object):
      def __init__(self, root):
          self.root = root
  
      def path(self, url):
          return os.path.join(self.root, url + '.md')
  
      def exists(self, url):
          path = self.path(url)
          return os.path.exists(path)
  
      def get(self, url):
          path = os.path.join(self.root, url + '.md')
          if self.exists(url):
              return Page(path, url)
          return None
  
      def get_bare(self, url):
          path = self.path(url)
          if self.exists(url):
              return False
          return Page(path, url, new=True)
  
      def move(self, url, newurl):
          source = os.path.join(self.root, url) + '.md'
          target = os.path.join(self.root, newurl) + '.md'
          # normalize root path (just in case somebody defined it absolute,
          # having some '../' inside) to correctly compare it to the target
          root = os.path.normpath(self.root)
          # get root path longest common prefix with normalized target path
          common = os.path.commonprefix((root, os.path.normpath(target)))
          # common prefix length must be at least as root length is
          # otherwise there are probably some '..' links in target path leading
          # us outside defined root directory
          if len(common) < len(root):
              raise RuntimeError(
                  'Possible write attempt outside content directory: '
                  '%s' % newurl)
          # create folder if it does not exists yet
          folder = os.path.dirname(target)
          if not os.path.exists(folder):
              os.makedirs(folder)
          os.rename(source, target)
  
      def delete(self, url):
          path = self.path(url)
          if not self.exists(url):
              return False
          os.remove(path)
          return True
  
      def index(self):
          """
              Builds up a list of all the available pages.
  
              :returns: a list of all the wiki pages
              :rtype: list
          """
          # make sure we always have the absolute path for fixing the
          # walk path
          pages = []
          root = os.path.abspath(self.root)
          for cur_dir, _, files in os.walk(root):
              # get the url of the current directory
              cur_dir_url = cur_dir[len(root)+1:]
              for cur_file in files:
                  path = os.path.join(cur_dir, cur_file)
                  if cur_file.endswith('.md'):
                      url = clean_url(os.path.join(cur_dir_url, cur_file[:-3]))
                      page = Page(path, url)
                      pages.append(page)
          return sorted(pages, key=lambda x: x.title.lower())
  
      def index_dict(self):
          """
          Builds nested directionary of all available pages
          """
  
          index_dict = {}
  
          for page in self.index():
              page = page.url.split('/')
              current_dict = index_dict
              for subpage in page:
                  if subpage not in current_dict:
                      current_dict[subpage] = {}
                  current_dict = current_dict[subpage]
  
          return index_dict
  
      def index_by(self, key):
          """
              Get an index based on the given key.
  
              Will use the metadata value of the given key to group
              the existing pages.
  
              :param str key: the attribute to group the index on.
  
              :returns: Will return a dictionary where each entry holds
                  a list of pages that share the given attribute.
              :rtype: dict
          """
          pages = {}
          for page in self.index():
              value = getattr(page, key)
              pre = pages.get(value, [])
              pages[value] = pre.append(page)
          return pages
  
      def get_by_title(self, title):
          pages = self.index(attr='title')
          return pages.get(title)
  
      def get_tags(self):
          pages = self.index()
          tags = {}
          for page in pages:
              pagetags = page.tags.split(',')
              for tag in pagetags:
                  tag = tag.strip()
                  if tag == '':
                      continue
                  elif tags.get(tag):
                      tags[tag].append(page)
                  else:
                      tags[tag] = [page]
          return tags
  
      def index_by_tag(self, tag):
          pages = self.index()
          tagged = []
          for page in pages:
              if tag in page.tags:
                  tagged.append(page)
          return sorted(tagged, key=lambda x: x.title.lower())
  
      def search(self, term, ignore_case=True, attrs=['title', 'tags', 'body']):
          pages = self.index()
          regex = re.compile(term, re.IGNORECASE if ignore_case else 0)
          matched = []
          for page in pages:
              for attr in attrs:
                  if regex.search(getattr(page, attr)):
                      matched.append(page)
                      break
          return matched
  