Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ftr convert repo #494

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file added DEVELOP
Empty file.
17 changes: 17 additions & 0 deletions knowledge_repo/app/app.py
Expand Up @@ -172,6 +172,7 @@ def handle_insufficient_permissions(error):
self.register_blueprint(routes.editor.blueprint)
self.register_blueprint(routes.groups.blueprint)
self.register_blueprint(routes.auth.blueprint)
self.register_blueprint(routes.polly_api.blueprint)
KnowledgeAuthProvider.register_auth_provider_blueprints(self)

if self.config['DEBUG']:
Expand Down Expand Up @@ -273,6 +274,22 @@ def format_date(date):
except:
return date

def test(self):
self.repository.test()
return ''
def append_repo(self,name,uri):
temp = self.repository
self.repository = knowledge_repo.KnowledgeRepository.append_for_uri(name,uri,temp)
self.db_update_index(check_timeouts=False, force=True )
return self.repository


def append_repo_obj(self,name,obj):
temp = self.repository
self.repository = knowledge_repo.KnowledgeRepository.append_obj(name,obj,temp)
self.db_update_index(check_timeouts=False, force=True)
return self.repository

@property
def repository(self):
return getattr(self, '_repository')
Expand Down
10 changes: 6 additions & 4 deletions knowledge_repo/app/auth_providers/oauth2.py
Expand Up @@ -156,15 +156,17 @@ def extract_from_dict(d, key):
if isinstance(key, (list, tuple)):
if len(key) == 1:
key = key[0]
else:
return extract_from_dict(d[key[0]], key[1:])
if isinstance(key, six.string_types):
elif d[key[0]] is None:
return extract_from_dict(d, key[1:])
else:
return extract_from_dict(d, key[0])
if isinstance(key, str):
return d[key]
raise RuntimeError("Invalid key type: {}.".format(key))

response = self.oauth_client.get(self.get_endpoint_url(self.user_info_endpoint), verify=self.verify_ssl_certs)
try:
response_dict = json.loads(response.content)
response_dict = json.loads(request.content.decode('utf-8'))
identifier = extract_from_dict(response_dict, self.user_info_mapping['identifier'])
if identifier is None:
raise ValueError("identifier '{}' not found in authentication response".format(self.user_info_mapping['identifier']))
Expand Down
2 changes: 1 addition & 1 deletion knowledge_repo/app/config_defaults.py
Expand Up @@ -40,7 +40,7 @@
# ---------------------------------------------------
# Database configuration
# ---------------------------------------------------
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
SQLALCHEMY_DATABASE_URI = 'mysql://abhi:1234@localhost/knowledgeapp'
SQLALCHEMY_ECHO = False
SQLALCHEMY_TRACK_MODIFICATIONS = False

Expand Down
1 change: 1 addition & 0 deletions knowledge_repo/app/routes/__init__.py
Expand Up @@ -9,3 +9,4 @@
from . import editor
from . import groups
from . import debug
from . import polly_api
11 changes: 10 additions & 1 deletion knowledge_repo/app/routes/index.py
Expand Up @@ -51,6 +51,15 @@ def render_index():
return redirect('/feed')


@blueprint.route('/testupload')
@PageView.logged
def test_upload():
global current_repo,current_app
#repo = current_app.append_repo("3","kr-test")
#current_repo = repo
current_app.test()
return redirect('/feed')

@blueprint.route('/favorites')
@PageView.logged
@login_required
Expand Down Expand Up @@ -82,11 +91,11 @@ def render_favorites():
@permissions.index_view.require()
def render_feed():
""" Renders the index-feed view """
global current_repo,current_app
feed_params = from_request_get_feed_params(request)
posts, post_stats = get_posts(feed_params)
for post in posts:
post.tldr = render_post_tldr(post)

return render_template("index-feed.html",
feed_params=feed_params,
posts=posts,
Expand Down
43 changes: 43 additions & 0 deletions knowledge_repo/app/routes/polly_api.py
@@ -0,0 +1,43 @@
"""
APIs for polly and their routes
Includes:
- /api/uploadkr
- /api/uploadpost

"""

import os
import json
from builtins import str
from collections import namedtuple
from flask import request, render_template, redirect, Blueprint, current_app, make_response
from flask_login import login_required
from sqlalchemy import case, desc

from .. import permissions
from ..proxies import db_session, current_repo
from ..utils.posts import get_posts
from ..models import Post, Tag, User, PageView
from ..utils.requests import from_request_get_feed_params
from ..utils.render import render_post_tldr
from ..utils.s3_talk import download_dir,download_from_s3
blueprint = Blueprint('api', __name__, template_folder='../templates', static_folder='../static')

@blueprint.route('/api/uploadkr')
@PageView.logged
def upload_kr():
"""
API to upload a KR to the server
args:
S3-Path
"""
global current_repo,current_app
path = request.args.get('path')
dir_name,dir_path = download_dir(path)

db_path = current_app.config['KR_REPO_DB_PATH'] + ':' + dir_name
dbobj = current_repo.migrate_to_dbrepo(dir_path,db_path)
current_repo = current_app.append_repo_obj(dir_name,dbobj)
return redirect('/feed')


4 changes: 3 additions & 1 deletion knowledge_repo/app/utils/render.py
Expand Up @@ -91,7 +91,9 @@ def intra_knowledge_urlmapper(name, url):
if name == 'a' and url.startswith('knowledge:'):
return url_for('posts.render', path=url.split('knowledge:')[1]).replace('%2F', '/') # Temporary fix before url revamp
return None


print("AB:",post)
print("AB:",post.kp)
md, html = HTMLConverter(post if isinstance(post, KnowledgePost) else post.kp)._render_markdown(skip_headers=True, urlmappers=[intra_knowledge_urlmapper])

html = render_post_header(post) + html
Expand Down
70 changes: 70 additions & 0 deletions knowledge_repo/app/utils/s3_talk.py
@@ -0,0 +1,70 @@
"""
Given S3 path download to local and trigger upload to database repository
"""
import os
import boto3,botocore
import tempfile
import errno

BUCKET_NAME = os.environ['KR_BUCKET_NAME']
S3 = boto3.resource('s3')
CLIENT = boto3.client('s3')

def assert_dir(path):
"""
Checks if directory tree in path exists. :param path: the path to check if it exists
"""
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise

def _extract_name(path):
# Internal function to return name of the folder/file to use downstream
if path.endswith('/'):
return path.split('/')[-2]
else:
return path.split('/')[-1]

def download_dir(path):
"""
Downloads recursively the given S3 path to the target directory.
arg path: The S3 directory to download.
"""

# Handle missing / at end of prefix
if not path.endswith('/'):
path += '/'

dir_name = _extract_name(path)
target = "/tmp/%s/"%dir_name

paginator = CLIENT.get_paginator('list_objects_v2')
for result in paginator.paginate(Bucket=BUCKET_NAME, Prefix=path):
# Download each file individually
for key in result['Contents']:
# Calculate relative path
rel_path = key['Key'][len(path):]
# Skip paths ending in /
if not key['Key'].endswith('/'):
local_file_path = os.path.join(target, rel_path)
# Make sure directories exist
local_file_dir = os.path.dirname(local_file_path)
assert_dir(local_file_dir)
CLIENT.download_file(BUCKET_NAME, key['Key'], local_file_path)
return dir_name,target




def download_from_s3(path):
try:
fname = _extract_path(path)
temp_name = '/tmp/%s'%fname
S3.Bucket(BUCKET_NAME).download_file(path,temp_name)
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
return -1

return fname,temp_name
2 changes: 1 addition & 1 deletion knowledge_repo/repositories/dbrepository.py
Expand Up @@ -45,7 +45,7 @@ def init(self, auto_create=True):
Column('revision', Integer, default=0),
Column('status', Integer, default=self.PostStatus.DRAFT.value),
Column('ref', String(512)),
Column('data', LargeBinary))
Column('data', LargeBinary(length=(2**32)-1))) # Increased length to support large notebooks
self.engine = create_engine(engine_uri, pool_recycle=3600)
self.session = scoped_session(sessionmaker(bind=self.engine))
if auto_create:
Expand Down
52 changes: 52 additions & 0 deletions knowledge_repo/repository.py
Expand Up @@ -58,6 +58,58 @@ def for_uris(cls, uri):
krs = {name: cls.for_uri(uri) for name, uri in list(uris.items())}
return MetaKnowledgeRepository(krs)


def test(self):
c = 0
pat = self.path
for post in self.posts():
s = post.src_paths
pat = pat + '/' +post.path
#p = KnowledgePost.from_file(pat + '/'+s[0])
print(s)
# self.add(p,path='testpath%d'%c)
# c+=1
#print(s[0])

@classmethod
def migrate_to_dbrepo(cls,gitpath,newpath):
# A new (supposedly) git repository is going to be uploaded
# That must be migrated to the database.
# Inputs :
# gitpath
# newpath

from .repositories.dbrepository import DbKnowledgeRepository
#newpath = "mysql://abhi:1234@localhost/knowledgerepo:%s"%newpath
db_obj = DbKnowledgeRepository(newpath)
gitkr = cls.for_uri(gitpath)

for post in gitkr.posts():
post_path = gitpath + '/' + post.path
post_src_path = post_path + '/' + post.src_paths[0]
new_post = KnowledgePost.from_file(post_src_path)
new_post = db_obj.add(new_post,path=post.path,update=True)
db_obj.submit(new_post.path)
db_obj.accept(new_post.path)
db_obj.publish(new_post.path)
return db_obj

@classmethod
def append_obj(cls,name,new_obj,meta_repo):
from .repositories.meta import MetaKnowledgeRepository
krs = meta_repo.uri
krs[name] = new_obj
meta_repo = MetaKnowledgeRepository(krs)
return meta_repo

@classmethod
def append_for_uri(cls,name,uri,meta_repo):
from .repositories.meta import MetaKnowledgeRepository
krs = meta_repo.uri
krs[name] = cls.for_uri(uri)
meta_repo = MetaKnowledgeRepository(krs)
return meta_repo

@classmethod
def from_uri(cls, url, *args, **kwargs):
return cls(url, *args, **kwargs)
Expand Down
16 changes: 15 additions & 1 deletion scripts/knowledge_repo
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import print_function
from __future__ import unicode_literals

Expand Down Expand Up @@ -42,6 +42,13 @@ if os.path.exists(os.path.join(contrib_dir, '__init__.py')):
# we finish constructing the entire parser so that the syntax and arguments can change
# from version to version of this script.

# Repeating what the argparse already does
def parse_repo_string(repo_str):
prefix_pattern = re.compile('^(?:\{(?P<name>[a-zA-Z_0-9]*)\})?(?P<uri>.*)$')

prefix = prefix_pattern.match(repo_str)
return prefix.groups()

class ParseRepositories(argparse.Action):

def __init__(self, **kwargs):
Expand Down Expand Up @@ -177,6 +184,10 @@ submit = subparsers.add_parser('submit', help='Submit a knowledge post for revie
submit.set_defaults(action='submit')
submit.add_argument('path', help='The path of the knowledge post to submit for review.')

submit = subparsers.add_parser('accept', help='accept a knowledge post')
submit.set_defaults(action='accept')
submit.add_argument('path', help='The path of the knowledge post to accept')

push = subparsers.add_parser('push', help='DEPRECATED: Use `submit` instead.')
push.set_defaults(action='push')
push.add_argument('path', help='The path of the knowledge post to submit for review.')
Expand Down Expand Up @@ -296,6 +307,9 @@ if args.action in ['submit', 'push'] or (args.action == 'add' and args.submit):
repo.submit(path=args.path)
sys.exit(0)

if args.action == 'accept' :
repo.accept(args.path)
repo.publish(args.path)
# Everything below this point has to do with running and/or managing the web app
from knowledge_repo.app.deploy import KnowledgeDeployer, get_app_builder

Expand Down