Esempio n. 1
0
class Page(Model, db.Model):
    __tablename__ = 'pages'
    # type = 'local'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))
    sha = db.Column(db.String(128))
    wiki = db.Column(db.String())

    @staticmethod
    def create(name, sha, wiki):
        u = Page()
        u.name = name
        u.sha = sha
        u.wiki = wiki
        u.save()
        db.session.commit()

    @staticmethod
    def update(name, sha, wiki):
        try:
            u = db.session.query(Page).filter(Page.name == name).one()

            u.name = name
            u.sha = sha
            u.wiki = wiki
            u.save()
            db.session.commit()

        except:
            # Create Item
            print 'Failed to update'
            Page.create(name, sha, wiki)
Esempio n. 2
0
class Commit(Model, db.Model):
    __tablename__ = 'commits'
    # type = 'local'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))
    filename = db.Column(db.String(128))
    sha = db.Column(db.String(128))
    wiki = db.Column(db.String())
    username = db.Column(db.String(128))
    email = db.Column(db.String(128))
    message = db.Column(db.String(128))
    approved = db.Column(db.Boolean())
    approved_by = db.Column(db.String(128))
    commited = db.Column(db.Boolean())

    @staticmethod
    def create(name, filename, sha, diff, username, email, message):
        u = Commit()
        u.name = name
        u.filename = filename
        u.sha = sha
        u.diff = diff
        u.username = username
        u.email = email
        u.message = message
        u.save()
        db.session.commit()
Esempio n. 3
0
class User(Model, BaseUser):
    __tablename__ = 'users'
    type = 'local'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(128), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(60))
    admin = False

    hidden_fields = ['password']
    readonly_fields = ['email', 'password']

    @property
    def auth_token_id(self):
        return self.password

    @staticmethod
    def load_user(*args, **kwargs):
        return User.get_by_id(args[0])

    @staticmethod
    def create(username, email, password):
        u = User()
        u.username = username
        u.email = email
        u.password = User.hash_password(password)
        u.save()

    @staticmethod
    def get_by_username(username):
        return User.query().filter_by(username=username).first()

    @staticmethod
    def get_by_email(email):
        return User.query().filter_by(email=email).first()

    @staticmethod
    def signer(salt):
        return URLSafeSerializer(current_app.config['SECRET_KEY'] + salt)

    @staticmethod
    def auth(email, password):
        user = User.get_by_email(email)

        if not user:
            # User doesn't exist
            return False

        if User.check_password(password, user.password):
            # Password is good, log in user
            login_user(user, remember=True)
            return user
        else:
            # Password check failed
            return False

    @classmethod
    def logout(cls):
        logout_user()

    @staticmethod
    def login_form():
        form = LoginForm()
        return render_template('auth/local/login.html', form=form)
Esempio n. 4
0
class WikiPage(HookMixin):
    __tablename__ = 'pages'
    # type = 'local'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))
    filename = db.Column(db.String(128))
    sha = db.Column(db.String(128))
    wiki = db.Column(db.String())

    def __init__(self, name, wiki, sha='HEAD'):
        self.name = name
        self.filename = cname_to_filename(name)
        self.sha = sha.encode('latin-1')
        self.wiki = wiki

    @property
    def data(self):
        cache_key = self._cache_key('data')
        cached = cache.get(cache_key)
        if cached:
            return cached

        mode, sha = tree_lookup_path(self.wiki.repo.get_object,
                                     self.wiki.repo[self.sha].tree,
                                     self.filename)
        data = self.wiki.repo[sha].data
        # print "cache_key"
        # print cache_key
        # print "data"
        # print data
        # print "e"
        cache.set(cache_key, data)
        return data

    @property
    def history(self):
        """Get page history.

        History can take a long time to generate for repositories with many commits.
        This returns an iterator to avoid having to load them all at once, and caches
        as it goes.

        :return: iter -- Iterator over dicts

        """
        cache_head = []
        cache_tail = cache.get(self._cache_key('history')) or [{
            '_cache_missing':
            True
        }]
        while True:
            if not cache_tail:
                return
            index = 0
            for index, cached_rev in enumerate(cache_tail):
                if cached_rev.get("_cache_missing"):
                    break
                else:
                    cache_head.append(cached_rev)
                    yield cached_rev
            cache_tail = cache_tail[index + 1:]

            start_sha = cached_rev.get('sha')
            end_sha = cache_tail[0].get('sha') if cache_tail else None
            for rev in self._iter_revs(start_sha=start_sha,
                                       end_sha=end_sha,
                                       filename=cached_rev.get('filename')):
                cache_head.append(rev)
                placeholder = {
                    '_cache_missing': True,
                    'sha': rev['sha'],
                    'filename': rev['new_filename']
                }
                cache.set(self._cache_key('history'),
                          cache_head + [placeholder] + cache_tail)
                yield rev
            cache.set(self._cache_key('history'), cache_head + cache_tail)

    def _iter_revs(self, start_sha=None, end_sha=None, filename=None):
        if end_sha:
            end_sha = [end_sha]
        if not len(self.wiki.repo.open_index()):
            # Index is empty, no commits
            return
        filename = filename or self.filename
        walker = iter(
            self.wiki.repo.get_walker(paths=[filename],
                                      include=start_sha,
                                      exclude=end_sha,
                                      follow=True))
        if start_sha:
            # If we are not starting from HEAD, we already have the start
            # commit
            next(walker)
        filename = self.filename
        for entry in walker:
            change_type = None
            for change in entry.changes():
                if change.new.path == filename:
                    filename = change.old.path
                    change_type = change.type
                    break

            author_name, author_email = entry.commit.author.rstrip('>').split(
                '<')
            r = dict(author=author_name.strip(),
                     author_email=author_email,
                     time=entry.commit.author_time,
                     message=entry.commit.message,
                     sha=entry.commit.id,
                     type=change_type,
                     new_filename=change.new.path,
                     old_filename=change.old.path)
            yield r

    @property
    def history_cache(self):
        """Get info about the history cache.

        :return: tuple -- (cached items, cache complete?)
        """
        cached_revs = cache.get(self._cache_key('history'))
        if not cached_revs:
            return 0, False
        elif any(rev.get('_cache_missing') for rev in cached_revs):
            return len(cached_revs) - 1, False
        return len(cached_revs), True

    @property
    def imports(self):
        """Names"""
        meta = self._get_meta(self.data) or {}
        return meta.get('import', [])

    @staticmethod
    def _get_meta(content):
        """Get metadata from page if any.

        :param content: Page content
        :return: dict

        """
        if not content.startswith("---"):
            return None

        meta_end = re.search("\n(\.{3}|\-{3})", content)

        if not meta_end:
            return None

        try:
            return yaml.safe_load(content[0:meta_end.start()])
        except Exception as e:
            return {'error': e.message}

    def _cache_key(self, property):
        return 'page/{0}[{1}].{2}'.format(self.name, self.sha, property)

    def _get_user(self, username, email):
        if not username:
            username = self.wiki.default_committer_name

        if not email:
            email = self.wiki.default_committer_email

        return username, email

    def _invalidate_cache(self, save_history=None):
        cache.delete(self._cache_key('data'))
        if save_history:
            if not save_history[0].get('_cache_missing'):
                save_history = [{'_cache_missing': True}] + save_history
            cache.set(self._cache_key('history'), save_history)
        else:
            cache.delete(self._cache_key('history'))

    def delete(self, username=None, email=None, message=None):
        """Delete page.
        :param username: Committer name
        :param email: Committer email
        :return: str -- Commit sha1

        """
        username, email = self._get_user(username, email)

        if not message:
            message = "Deleted %s" % self.name

        os.remove(os.path.join(self.wiki.path, self.filename))
        commit = self.wiki.commit(name=username,
                                  email=email,
                                  message=message,
                                  files=[self.filename])
        self._invalidate_cache()
        return commit

    def rename(self, new_name, username=None, email=None, message=None):
        """Rename page.

        :param new_name: New name of page.
        :param username: Committer name
        :param email: Committer email
        :return: str -- Commit sha1

        """
        assert self.sha == 'HEAD'
        old_filename, new_filename = self.filename, cname_to_filename(new_name)
        if old_filename not in self.wiki.repo.open_index():
            # old doesn't exist
            return None
        elif old_filename == new_filename:
            return None
        else:
            # file is being overwritten, but that is ok, it's git!
            pass

        username, email = self._get_user(username, email)

        if not message:
            message = "Moved %s to %s" % (self.name, new_name)

        os.rename(os.path.join(self.wiki.path, old_filename),
                  os.path.join(self.wiki.path, new_filename))
        commit = self.wiki.commit(name=username,
                                  email=email,
                                  message=message,
                                  files=[old_filename, new_filename])

        old_history = cache.get(self._cache_key('history'))
        self._invalidate_cache()
        self.name = new_name
        self.filename = new_filename
        # We need to clear the cache for the new name as well as the old
        self._invalidate_cache(save_history=old_history)

        return commit

    def write(self, content, message=None, username=None, email=None):
        # print self.sha
        """Write page to git repo

        :param content: Content of page.
        :param message: Commit message.
        :param username: Commit Name.
        :param email: Commit Email.
        :return: Git commit sha1.
        """
        assert self.sha == 'HEAD'
        dirname = posixpath.join(self.wiki.path,
                                 posixpath.dirname(self.filename))

        if not os.path.exists(dirname):
            os.makedirs(dirname)

        with open(self.wiki.path + "/" + self.filename, 'w') as f:
            f.write(content)

        if not message:
            message = "Updated %s" % self.name

        username, email = self._get_user(username, email)

        ret = self.wiki.commit(name=username,
                               email=email,
                               message=message,
                               files=[self.filename])
        Page.update(self.name, ret, content)
        Commit.create(self.name, None, ret, content, username, email, message)

        old_history = cache.get(self._cache_key('history'))
        self._invalidate_cache(save_history=old_history)
        return ret

    def revert(self, commit_sha, message, username, email):
        """Revert page to passed commit sha1

        :param commit_sha: Commit Sha1 to revert to.
        :param message: Commit message.
        :param username: Committer name.
        :param email: Committer email.
        :return: Git commit sha1

        """
        assert self.sha == 'HEAD'
        new_page = self.wiki.get_page(self.name, commit_sha)
        if not new_page:
            raise PageNotFound('Commit not found')

        if not message:
            message = "Revert '%s' to %s" % (self.name, commit_sha[:7])

        return self.write(new_page.data,
                          message=message,
                          username=username,
                          email=email)

    def compare(self, old_sha):
        """Compare two revisions of the same page.

        :param old_sha: Older sha.
        :return: str - Raw markup with styles

        """

        # TODO: This could be effectively done in the browser
        old = self.wiki.get_page(self.name, sha=old_sha)
        return ghdiff.diff(old.data, self.data)

    def __nonzero__(self):
        # Verify this file is in the tree for the given commit sha
        try:
            tree_lookup_path(self.wiki.repo.get_object,
                             self.wiki.repo[self.sha].tree, self.filename)
        except KeyError:
            # We'll get a KeyError if self.sha isn't in the repo, or if
            # self.filename isn't in the tree of our commit
            return False
        return True
Esempio n. 5
0
class User(Model, UserMixin):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(128), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(60))
    admin = False

    hidden_fields = ['password']
    readonly_fields = ['email', 'password']

    def get_auth_token(self):
        key = sha256(self.password).hexdigest()
        return User.signer(key).dumps(dict(id=self.id))

    @property
    def avatar(self):
        return gravatar_url(self.email)

    @staticmethod
    def create(username, email, password):
        u = User()
        u.username = username
        u.email = email
        u.password = User.hash_password(password)
        u.save()

    @staticmethod
    def get_by_username(username):
        return User.query().filter_by(username=username).first()

    @staticmethod
    def get_by_email(email):
        return User.query().filter_by(email=email).first()

    @staticmethod
    def signer(salt):
        return URLSafeSerializer(current_app.config['SECRET_KEY'] + salt)

    @staticmethod
    def auth(email, password):
        user = User.get_by_email(email)

        if not user:
            # User doesn't exist
            return False

        if User.check_password(password, user.password):
            # Password is good, log in user
            login_user(user, remember=True)
            return user
        else:
            # Password check failed
            return False

    @staticmethod
    def hash_password(password):
        return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(12))

    @staticmethod
    def check_password(password, hashed):
        return bcrypt.hashpw(password.encode('utf-8'),
                             hashed.encode('utf-8')) == hashed

    @classmethod
    def logout(cls):
        logout_user()