src/browser/views.py
import json
import urllib
import uuid
import hashlib
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.core import serializers
from django.http import HttpResponse, \
HttpResponseRedirect, \
HttpResponseForbidden, \
HttpResponseNotAllowed
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from thrift.protocol import TBinaryProtocol
from thrift.protocol import TJSONProtocol
from thrift.transport.TTransport import TMemoryBuffer
from config import settings
from oauth2_provider.models import get_application_model
from oauth2_provider.views import ApplicationUpdate
from inventory.models import App, Annotation
from account.utils import grant_app_permission
from core.db.manager import DataHubManager
from core.db.rlsmanager import RowLevelSecurityManager
from core.db.licensemanager import LicenseManager
from core.db.rls_permissions import RLSPermissionsParser
from datahub import DataHub
from datahub.account import AccountService
from service.handler import DataHubHandler
from utils import post_or_get
'''
Datahub Web Handler
'''
handler = DataHubHandler()
core_processor = DataHub.Processor(handler)
account_processor = AccountService.Processor(handler)
def home(request):
username = request.user.get_username()
if username:
return HttpResponseRedirect(reverse('browser-user', args=(username,)))
else:
return HttpResponseRedirect(reverse('www:index'))
def about(request):
return HttpResponseRedirect(reverse('www:index'))
'''
APIs and Services
'''
@csrf_exempt
def service_core_binary(request):
# Catch CORS preflight requests
if request.method == 'OPTIONS':
resp = HttpResponse('')
resp['Content-Type'] = 'text/plain charset=UTF-8'
resp['Content-Length'] = 0
resp.status_code = 204
else:
try:
iprot = TBinaryProtocol.TBinaryProtocol(
TMemoryBuffer(request.body))
oprot = TBinaryProtocol.TBinaryProtocol(TMemoryBuffer())
core_processor.process(iprot, oprot)
resp = HttpResponse(oprot.trans.getvalue())
except Exception as e:
resp = HttpResponse(
json.dumps({'error': str(e)}),
content_type="application/json")
try:
resp['Access-Control-Allow-Origin'] = request.META['HTTP_ORIGIN']
except:
pass
resp['Access-Control-Allow-Methods'] = "POST, PUT, GET, DELETE, OPTIONS"
resp['Access-Control-Allow-Credentials'] = "true"
resp['Access-Control-Allow-Headers'] = ("Authorization, Cache-Control, "
"If-Modified-Since, Content-Type")
return resp
@csrf_exempt
def service_account_binary(request):
# Catch CORS preflight requests
if request.method == 'OPTIONS':
resp = HttpResponse('')
resp['Content-Type'] = 'text/plain charset=UTF-8'
resp['Content-Length'] = 0
resp.status_code = 204
else:
try:
iprot = TBinaryProtocol.TBinaryProtocol(
TMemoryBuffer(request.body))
oprot = TBinaryProtocol.TBinaryProtocol(TMemoryBuffer())
account_processor.process(iprot, oprot)
resp = HttpResponse(oprot.trans.getvalue())
except Exception as e:
resp = HttpResponse(
json.dumps({'error': str(e)}),
content_type="application/json")
try:
resp['Access-Control-Allow-Origin'] = request.META['HTTP_ORIGIN']
except:
pass
resp['Access-Control-Allow-Methods'] = "POST, PUT, GET, DELETE, OPTIONS"
resp['Access-Control-Allow-Credentials'] = "true"
resp['Access-Control-Allow-Headers'] = ("Authorization, Cache-Control, "
"If-Modified-Since, Content-Type")
return resp
@csrf_exempt
def service_core_json(request):
# Catch CORS preflight requests
if request.method == 'OPTIONS':
resp = HttpResponse('')
resp['Content-Type'] = 'text/plain charset=UTF-8'
resp['Content-Length'] = 0
resp.status_code = 204
else:
try:
iprot = TJSONProtocol.TJSONProtocol(TMemoryBuffer(request.body))
oprot = TJSONProtocol.TJSONProtocol(TMemoryBuffer())
core_processor.process(iprot, oprot)
resp = HttpResponse(
oprot.trans.getvalue(),
content_type="application/json")
except Exception as e:
resp = HttpResponse(
json.dumps({'error': str(e)}),
content_type="application/json")
try:
resp['Access-Control-Allow-Origin'] = request.META['HTTP_ORIGIN']
except:
pass
resp['Access-Control-Allow-Methods'] = "POST, PUT, GET, DELETE, OPTIONS"
resp['Access-Control-Allow-Credentials'] = "true"
resp['Access-Control-Allow-Headers'] = ("Authorization, Cache-Control, "
"If-Modified-Since, Content-Type")
return resp
'''
Repository Base
'''
def public(request):
"""browse public repos. Login not required"""
username = request.user.get_username()
public_repos = DataHubManager.list_public_repos()
# This should really go through the api... like everything else
# in this file.
public_repos = serializers.serialize('json', public_repos)
return render_to_response("public-browse.html", {
'login': username,
'repo_base': 'repo_base',
'repos': [],
'public_repos': public_repos,
})
def user(request, repo_base=None):
username = request.user.get_username()
repo_base = username or 'public'
with DataHubManager(user=username, repo_base=repo_base) as manager:
repos = manager.list_repos()
visible_repos = []
public_role = settings.PUBLIC_ROLE
for repo in repos:
collaborators = manager.list_collaborators(repo)
collaborators = [c.get('username') for c in collaborators]
collaborators = filter(
lambda x: x != '' and x != repo_base, collaborators)
non_public_collaborators = filter(
lambda x: x != public_role, collaborators)
visible_repos.append({
'name': repo,
'owner': repo_base,
'public': True if public_role in collaborators else False,
'collaborators': non_public_collaborators,
})
collaborator_repos = manager.list_collaborator_repos()
return render_to_response("user-browse.html", {
'login': username,
'repo_base': repo_base,
'repos': visible_repos,
'collaborator_repos': collaborator_repos})
'''
Repository
'''
def repo(request, repo_base, repo):
'''
forwards to repo_tables method
'''
return HttpResponseRedirect(
reverse('browser-repo_tables', args=(repo_base, repo)))
def repo_tables(request, repo_base, repo):
'''
shows the tables and views under a repo.
'''
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
# get the base tables and views of the user's repo
with DataHubManager(user=username, repo_base=repo_base) as manager:
base_tables = manager.list_tables(repo)
views = manager.list_views(repo)
rls_table = 'policy'
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'base_tables': base_tables,
'views': views,
'rls-table': rls_table}
res.update(csrf(request))
return render_to_response("repo-browse-tables.html", res)
def repo_files(request, repo_base, repo):
'''
shows thee files in a repo
'''
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
with DataHubManager(user=username, repo_base=repo_base) as manager:
uploaded_files = manager.list_repo_files(repo)
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'files': uploaded_files}
res.update(csrf(request))
return render_to_response("repo-browse-files.html", res)
def repo_cards(request, repo_base, repo):
'''
shows the cards in a repo
'''
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
with DataHubManager(user=username, repo_base=repo_base) as manager:
cards = manager.list_repo_cards(repo)
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'cards': cards}
res.update(csrf(request))
return render_to_response("repo-browse-cards.html", res)
@login_required
def repo_create(request, repo_base):
'''
creates a repo (POST), or returns a page for creating repos (GET)
'''
username = request.user.get_username()
if username != repo_base:
message = (
'Error: Permission Denied. '
'%s cannot create new repositories in %s.'
% (username, repo_base)
)
return HttpResponseForbidden(message)
if request.method == 'POST':
repo = request.POST['repo']
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.create_repo(repo)
return HttpResponseRedirect(reverse('browser-user', args=(username,)))
elif request.method == 'GET':
res = {'repo_base': repo_base, 'login': username}
res.update(csrf(request))
return render_to_response("repo-create.html", res)
@login_required
def repo_delete(request, repo_base, repo):
'''
deletes a repo in the current database (repo_base)
'''
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_repo(repo=repo, force=True)
return HttpResponseRedirect(reverse('browser-user-default'))
@login_required
def repo_settings(request, repo_base, repo):
'''
returns the settings page for a repo.
'''
username = request.user.get_username()
public_role = settings.PUBLIC_ROLE
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo)
# if the public role is in collaborators, note that it's already added
repo_is_public = next(
(True for c in collaborators if
c['username'] == settings.PUBLIC_ROLE), False)
# remove the current user, public user from the collaborator list
collaborators = [c for c in collaborators if c['username']
not in ['', username, settings.PUBLIC_ROLE]]
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'collaborators': collaborators,
'public_role': public_role,
'repo_is_public': repo_is_public}
res.update(csrf(request))
return render_to_response("repo-settings.html", res)
@login_required
def repo_licenses(request, repo_base, repo):
'''
returns the licenses linked to a particular repo.
'''
username = request.user.get_username()
repo_licenses = LicenseManager.find_licenses_by_repo(repo_base, repo)
license_applied = []
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo)
for license in repo_licenses:
all_applied = manager.license_applied_all(repo, license.license_id)
license_applied.append(all_applied)
collaborators = [c for c in collaborators if c['username']
not in ['', username, settings.PUBLIC_ROLE]]
license_info_tuples = zip(repo_licenses, license_applied)
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'collaborators': collaborators,
'license_info_tuples': license_info_tuples,
'repo_licenses': repo_licenses,
'all_licenses': LicenseManager.find_licenses(),
}
res.update(csrf(request))
return render_to_response("repo-licenses.html", res)
@login_required
def repo_license_manage(request, repo_base, repo, license_id):
'''
shows all the tables for a repo,
and checks if the given license is applied to each one
'''
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
license_applied = []
license_views = []
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo, -1)
# collaborators = None
base_tables = manager.list_tables(repo)
license_views = manager.list_license_views(repo, license_id)
for table in base_tables:
# check if license view exists for this license_id
applied = manager.check_license_applied(table, repo, license_id)
license_applied.append(applied)
license = LicenseManager.find_license_by_id(license_id)
table_info_tuples = [(x, y) for x in base_tables for y in license_applied]
rls_table = 'policy'
res = {
'license': license,
'login': username,
'repo_base': repo_base,
'repo': repo,
'table_info_tuples': table_info_tuples,
'license_views': license_views,
'rls-table': rls_table,
'collaboratoes': collaborators,
}
res.update(csrf(request))
return render_to_response("repo-license-manage.html", res)
@csrf_exempt
@login_required
def link_license(request, repo_base, repo, license_id):
'''
links a license with a particular repo
'''
username = request.user.get_username()
public_role = settings.PUBLIC_ROLE
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo)
# remove the current user, public user from the collaborator list
collaborators = [c for c in collaborators if c['username']
not in ['', username, settings.PUBLIC_ROLE]]
LicenseManager.create_license_link(repo_base, repo, license_id)
repo_licenses = LicenseManager.find_licenses_by_repo(repo_base, repo)
all_licenses = LicenseManager.find_licenses()
return HttpResponseRedirect(reverse('browser-repo_licenses',
args=(repo_base, repo)))
@csrf_exempt
@login_required
def license_create(request):
username = request.user.get_username()
public_role = settings.PUBLIC_ROLE
if request.method == 'POST':
# creates a new license
pii_anonymized = False
pii_removed = False
license_name = request.POST['license_name'] or None
pii_def = request.POST['pii_def'] or None
pii_anonymized = 'anonymized' in request.POST.getlist('pii_properties')
pii_removed = 'removed' in request.POST.getlist('pii_properties')
if not license_name:
raise ValueError("Request missing \'license_name\' parameter.")
if not pii_def:
raise ValueError("Request missing \'pii definition\' parameter.")
LicenseManager.create_license(
license_name=license_name,
pii_def=pii_def,
pii_anonymized=pii_anonymized,
pii_removed=pii_removed)
return HttpResponseRedirect(reverse('browser-user', args=(username,)))
elif request.method == 'GET':
# returns page for creating a license
res = {
'login': username,
'public_role': public_role,
}
res.update(csrf(request))
return render_to_response("license-create.html", res)
@csrf_exempt
@login_required
def license_view_create(request, repo_base, repo, table, license_id):
'''
creates a new license view for a given table and license_id
'''
username = request.user.get_username()
public_role = settings.PUBLIC_ROLE
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo)
if username != repo_base:
raise PermissionDenied("User does not have access to this repo")
if request.method == 'POST':
# collect parameters that will be used to create the view of the table
removed_columns = request.POST.getlist('removed_columns[]')
view_params = {}
view_params['removed-columns'] = removed_columns
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.create_license_view(
repo=repo,
table=table,
view_params=view_params,
license_id=license_id)
return HttpResponseRedirect(
reverse('browser-repo_licenses', args=(repo_base, repo)))
elif request.method == 'GET':
collaborators = [c for c in collaborators if c['username']
not in ['', username, settings.PUBLIC_ROLE]]
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'collaborators': collaborators,
'public_role': public_role}
res.update(csrf(request))
return render_to_response("license-create.html", res)
@csrf_exempt
@login_required
def license_view_delete(request, repo_base, repo, table,
license_view, license_id):
'''
Deletes license view for table and given license_id
'''
username = request.user.get_username()
public_role = settings.PUBLIC_ROLE
with DataHubManager(user=username, repo_base=repo_base) as manager:
collaborators = manager.list_collaborators(repo)
if username != repo_base:
raise PermissionDenied("User does not have access to this repo")
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_license_view(
repo=repo,
table=table,
license_view=license_view,
license_id=license_id)
return HttpResponseRedirect(reverse('browser-repo_licenses',
args=(repo_base, repo)))
@login_required
def repo_collaborators_add(request, repo_base, repo):
'''
adds a user as a collaborator in a repo
'''
username = request.user.get_username()
collaborator_username = request.POST['collaborator_username']
db_privileges = request.POST.getlist('db_privileges')
file_privileges = request.POST.getlist('file_privileges')
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.add_collaborator(
repo, collaborator_username,
db_privileges=db_privileges,
file_privileges=file_privileges
)
return HttpResponseRedirect(
reverse('browser-repo_settings', args=(repo_base, repo,)))
@login_required
def repo_license_collaborators_add(request, repo_base, repo, license_id):
'''
adds a user as a collaborator in a repo
'''
username = request.user.get_username()
collaborator_username = request.POST['collaborator_username']
db_privileges = request.POST.getlist('db_privileges')
file_privileges = request.POST.getlist('file_privileges')
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.add_collaborator(
repo, collaborator_username,
db_privileges=db_privileges,
file_privileges=file_privileges,
license_id=license_id
)
collaborators = manager.list_collaborators(repo)
base_tables = manager.list_tables(repo)
views = manager.list_views(repo)
rls_table = 'policy'
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'base_tables': base_tables,
'views': views,
'rls-table': rls_table,
'collaboratoes': collaborators,
}
res.update(csrf(request))
return HttpResponseRedirect(
reverse('repo-license-manage.html', res))
@login_required
def repo_collaborators_remove(request, repo_base, repo, collaborator_username):
'''
removes a user from a repo
'''
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_collaborator(
repo=repo, collaborator=collaborator_username)
# if the user is removing someone else, return the repo-settings page.
# otherwise, return the browse page
if username == repo_base:
return HttpResponseRedirect(
reverse('browser-repo_settings', args=(repo_base, repo,)))
else:
return HttpResponseRedirect(reverse('browser-user-default'))
'''
Tables & Views
'''
def table(request, repo_base, repo, table):
'''
return a page indicating how many
'''
current_page = 1
if request.POST.get('page'):
current_page = request.POST.get('page')
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
url_path = reverse('browser-table', args=(repo_base, repo, table))
with DataHubManager(user=username, repo_base=repo_base) as manager:
query = manager.select_table_query(repo, table)
res = manager.paginate_query(
query=query, current_page=current_page, rows_per_page=50)
# get annotation to the table:
annotation, created = Annotation.objects.get_or_create(url_path=url_path)
annotation_text = annotation.annotation_text
data = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'table': table,
'annotation': annotation_text,
'current_page': current_page,
'next_page': current_page + 1, # the template should relaly do this
'prev_page': current_page - 1, # the template should relaly do this
'url_path': url_path,
'column_names': res['column_names'],
'tuples': res['rows'],
'total_pages': res['total_pages'],
'pages': range(res['start_page'], res['end_page'] + 1), # template
'num_rows': res['num_rows'],
'time_cost': res['time_cost']
}
data.update(csrf(request))
# and then, after everything, hand this off to table-browse. It turns out
# that this is all using DataTables anyhow, so the template doesn't really
# use all of the data we prepared. ARC 2016-01-04
return render_to_response("table-browse.html", data)
@login_required
def table_clone(request, repo_base, repo, table):
username = request.user.get_username()
new_table = request.GET.get('var_text', None)
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.clone_table(repo, table, new_table)
return HttpResponseRedirect(
reverse('browser-repo_tables', args=(repo_base, repo)))
@login_required
def table_export(request, repo_base, repo, table_name):
username = request.user.get_username()
file_name = request.GET.get('var_text', table_name)
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.export_table(
repo=repo, table=table_name, file_name=file_name,
file_format='CSV', delimiter=',', header=True)
return HttpResponseRedirect(
reverse('browser-repo_files', args=(repo_base, repo)))
@login_required
def table_delete(request, repo_base, repo, table_name):
"""
Deletes the given table.
Does not currently allow the user the option to cascade in the case of
dependencies, though the delete_table method does allow cascade (force) to
be passed.
"""
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_table(repo, table_name)
return HttpResponseRedirect(
reverse('browser-repo_tables', args=(repo_base, repo)))
@login_required
def view_delete(request, repo_base, repo, view_name):
"""
Deletes the given view.
Does not currently allow the user the option to cascade in the case of
dependencies, though the delete_table method does allow cascade (force) to
be passed.
"""
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_view(repo, view_name)
return HttpResponseRedirect(
reverse('browser-repo_tables', args=(repo_base, repo)))
'''
Files
'''
@login_required
def file_upload(request, repo_base, repo):
username = request.user.get_username()
data_file = request.FILES['data_file']
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.save_file(repo, data_file)
return HttpResponseRedirect(
reverse('browser-repo_files', args=(repo_base, repo)))
@login_required
def file_import(request, repo_base, repo, file_name):
username = request.user.get_username()
delimiter = str(request.GET['delimiter'])
if delimiter == '':
delimiter = str(request.GET['other_delimiter'])
header = False
if request.GET['has_header'] == 'true':
header = True
quote_character = request.GET['quote_character']
if quote_character == '':
quote_character = request.GET['other_quote_character']
DataHubManager.import_file(
username=username,
repo_base=repo_base,
repo=repo,
table='',
file_name=file_name,
delimiter=delimiter,
header=header,
quote_character=quote_character)
return HttpResponseRedirect(
reverse('browser-repo', args=(repo_base, repo)))
@login_required
def file_delete(request, repo_base, repo, file_name):
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_file(repo, file_name)
return HttpResponseRedirect(
reverse('browser-repo_files', args=(repo_base, repo)))
def file_download(request, repo_base, repo, file_name):
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
file_to_download = manager.get_file(repo, file_name)
response = HttpResponse(file_to_download,
content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="%s"' % (file_name)
return response
'''
Query
'''
def query(request, repo_base, repo):
query = post_or_get(request, key='q', fallback=None)
username = request.user.get_username()
# if this is a shared link, redirect them to the table view
# with the SQL to be executed pre-populated
if repo_base.lower() == 'user':
repo_base = username
if not username:
repo_base = 'public'
data = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'query': query}
return render_to_response("query-preview-statement.html", data)
# if the user is just requesting the query page
with DataHubManager(user=username, repo_base=repo_base) as manager:
cards = manager.list_repo_cards(repo)
if not query:
data = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'cards': json.dumps(cards),
'select_query': False,
'query': query}
return render_to_response("query-browse-results.html", data)
# if the user is actually executing a query
current_page = 1
if request.POST.get('page'):
current_page = request.POST.get('page')
url_path = reverse('browser-query', args=(repo_base, repo))
with DataHubManager(user=username, repo_base=repo_base) as manager:
res = manager.paginate_query(
query=query, current_page=current_page, rows_per_page=50)
# get annotation to the table:
annotation, created = Annotation.objects.get_or_create(url_path=url_path)
annotation_text = annotation.annotation_text
data = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'annotation': annotation_text,
'current_page': current_page,
'next_page': current_page + 1, # the template should relaly do this
'prev_page': current_page - 1, # the template should relaly do this
'url_path': url_path,
'query': query,
'cards': json.dumps(cards),
'select_query': res['select_query'],
'column_names': res['column_names'],
'tuples': res['rows'],
'total_pages': res['total_pages'],
'pages': range(res['start_page'], res['end_page'] + 1), # template
'num_rows': res['num_rows'],
'time_cost': res['time_cost']
}
data.update(csrf(request))
return render_to_response("query-browse-results.html", data)
'''
Annotations
'''
@login_required
def create_annotation(request):
url = request.POST['url']
annotation, created = Annotation.objects.get_or_create(url_path=url)
annotation.annotation_text = request.POST['annotation']
annotation.save()
return HttpResponseRedirect(url)
'''
Cards
'''
def card(request, repo_base, repo, card_name):
username = request.user.get_username()
if repo_base.lower() == 'user':
repo_base = username
# if the user is actually executing a query
current_page = 1
if request.POST.get('page'):
current_page = request.POST.get('page')
with DataHubManager(user=username, repo_base=repo_base) as manager:
card = manager.get_card(repo=repo, card_name=card_name)
res = manager.paginate_query(
query=card.query, current_page=current_page, rows_per_page=50)
# get annotation to the table:
annotation, created = Annotation.objects.get_or_create(
url_path=request.path)
annotation_text = annotation.annotation_text
data = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'card': card,
'annotation': annotation_text,
'current_page': current_page,
'next_page': current_page + 1, # the template should relaly do this
'prev_page': current_page - 1, # the template should relaly do this
'select_query': res['select_query'],
'column_names': res['column_names'],
'tuples': res['rows'],
'total_pages': res['total_pages'],
'pages': range(res['start_page'], res['end_page'] + 1), # template
'num_rows': res['num_rows'],
'time_cost': res['time_cost']
}
data.update(csrf(request))
return render_to_response("card-browse.html", data)
@login_required
def card_create(request, repo_base, repo):
username = request.user.get_username()
card_name = request.POST['card-name']
query = request.POST['query']
url = reverse('browser-card', args=(repo_base, repo, card_name))
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.create_card(repo, card_name, query)
return HttpResponseRedirect(url)
@require_POST
@login_required
def card_update_public(request, repo_base, repo, card_name):
username = request.user.get_username()
if 'public' in request.POST:
public = request.POST['public'] == 'True'
else:
raise ValueError("Request missing \'public\' parameter.")
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.update_card(repo, card_name, public=public)
return HttpResponseRedirect(
reverse('browser-card', args=(repo_base, repo, card_name)))
@login_required
def card_export(request, repo_base, repo, card_name):
username = request.user.get_username()
file_name = request.GET.get('var_text', card_name)
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.export_card(repo, file_name, card_name)
return HttpResponseRedirect(
reverse('browser-repo_files', args=(repo_base, repo)))
@login_required
def card_delete(request, repo_base, repo, card_name):
username = request.user.get_username()
with DataHubManager(user=username, repo_base=repo_base) as manager:
manager.delete_card(repo, card_name)
return HttpResponseRedirect(
reverse('browser-repo_cards', args=(repo_base, repo)))
'''
Developer Apps
'''
@login_required
def apps(request):
username = request.user.get_username()
user = User.objects.get(username=username)
thrift_apps = App.objects.filter(user=user)
oauth_apps = get_application_model().objects.filter(user=request.user)
c = {
'login': username,
'thrift_apps': thrift_apps,
'oauth_apps': oauth_apps}
return render_to_response('apps.html', c)
@login_required
def thrift_app_detail(request, app_id):
username = request.user.get_username()
user = User.objects.get(username=username)
app = App.objects.get(user=user, app_id=app_id)
c = RequestContext(request, {
'login': request.user.get_username(),
'app': app
})
return render_to_response('thrift_app_detail.html', c)
@login_required
def app_register(request):
username = request.user.get_username()
if request.method == "POST":
try:
user = User.objects.get(username=username)
app_id = request.POST["app-id"].lower()
app_name = request.POST["app-name"]
app_token = str(uuid.uuid4())
app = App(
app_id=app_id, app_name=app_name,
user=user, app_token=app_token)
app.save()
try:
hashed_password = hashlib.sha1(app_token).hexdigest()
DataHubManager.create_user(
username=app_id, password=hashed_password, create_db=False)
except Exception as e:
app.delete()
raise e
return HttpResponseRedirect('/developer/apps')
except Exception as e:
c = {
'login': username,
'errors': [str(e)]}
c.update(csrf(request))
return render_to_response('app-create.html', c)
else:
c = {'login': username}
c.update(csrf(request))
return render_to_response('app-create.html', c)
@login_required
def app_remove(request, app_id):
if request.method != 'POST':
return HttpResponseNotAllowed(['POST'])
try:
DataHubManager.remove_app(app_id=app_id)
return HttpResponseRedirect(reverse('browser-apps'))
except Exception as e:
c = {'errors': [str(e)]}
c.update(csrf(request))
return render_to_response('apps.html', c)
@login_required
def app_allow_access(request, app_id, repo_name):
username = request.user.get_username()
try:
app = None
try:
app = App.objects.get(app_id=app_id)
except App.DoesNotExist:
raise Exception("Invalid app_id")
app = App.objects.get(app_id=app_id)
redirect_url = post_or_get(request, key='redirect_url', fallback=None)
if request.method == "POST":
access_val = request.POST['access_val']
if access_val == 'allow':
grant_app_permission(
username=username,
repo_name=repo_name,
app_id=app_id,
app_token=app.app_token)
if redirect_url:
redirect_url = redirect_url + \
urllib.unquote_plus('?auth_user=%s' % (username))
return HttpResponseRedirect(redirect_url)
else:
if access_val == 'allow':
return HttpResponseRedirect(
'/settings/%s/%s' % (username, repo_name))
else:
res = {
'msg_title': "Access Request",
'msg_body':
"Permission denied to the app {0}.".format(app_id)
}
return render_to_response('confirmation.html', res)
else:
res = {
'login': username,
'repo_name': repo_name,
'app_id': app_id,
'app_name': app.app_name}
if redirect_url:
res['redirect_url'] = redirect_url
res.update(csrf(request))
return render_to_response('app-allow-access.html', res)
except Exception as e:
return HttpResponse(
json.dumps(
{'error': str(e)}),
content_type="application/json")
'''
Row Level Security Policies
'''
@login_required
def security_policies(request, repo_base, repo, table):
'''
Shows the security policies defined for a table.
'''
username = request.user.get_username()
# get the security policies on a given repo.table
try:
policies = RowLevelSecurityManager.find_security_policies(
repo_base=repo_base, repo=repo, table=table, grantor=username,
safe=True)
except LookupError:
policies = []
# repack the named tuples. This is a bit of a hack, (since we could just
# get the view to display named tuples)
# but is happening for expediency
policies = [(p.id, p.policy, p.policy_type, p.grantee, p.grantor)
for p in policies]
res = {
'login': username,
'repo_base': repo_base,
'repo': repo,
'table': table,
'policies': policies}
res.update(csrf(request))
return render_to_response("security-policies.html", res)
@login_required
def security_policy_delete(request, repo_base, repo, table, policy_id):
'''
Deletes a security policy defined for a table given a policy_id.
'''
username = request.user.get_username()
policy_id = int(policy_id)
try:
RowLevelSecurityManager.remove_security_policy(
policy_id, username)
except Exception as e:
return HttpResponse(
json.dumps(
{'error': str(e)}),
content_type="application/json")
return HttpResponseRedirect(
reverse('browse-security_policies', args=(repo_base, repo, table)))
@login_required
def security_policy_create(request, repo_base, repo, table):
'''
Creates a security policy for a table.
'''
username = request.user.get_username()
try:
policy = request.POST['security-policy']
policy_type = request.POST['policy-type']
grantee = request.POST['policy-grantee']
RowLevelSecurityManager.create_security_policy(policy=policy,
policy_type=policy_type,
grantee=grantee,
grantor=username,
repo_base=repo_base,
repo=repo,
table=table
)
except Exception as e:
return HttpResponse(
json.dumps(
{'error': str(e)}),
content_type="application/json")
return HttpResponseRedirect(
reverse('browse-security_policies', args=(repo_base, repo, table)))
@login_required
def security_policy_edit(request, repo_base, repo, table, policyid):
'''
Edits a security policy defined for a table given a policy_id.
'''
username = request.user.get_username()
try:
policy = request.POST['security-policy-edit']
policy_type = request.POST['policy-type-edit']
grantee = request.POST['policy-grantee-edit']
RowLevelSecurityManager.update_security_policy(
policyid, policy, policy_type, grantee, username)
except Exception as e:
return HttpResponse(
json.dumps(
{'error': str(e)}),
content_type="application/json")
return HttpResponseRedirect(
reverse('browse-security_policies', args=(repo_base, repo, table)))
@login_required
def security_policy_query(request, repo_base, repo, table):
'''
Converts a SQL permissions statement into a new security policy.
'''
username = request.user.get_username()
query = post_or_get(request, key='q', fallback=None)
try:
permissions_parser = RLSPermissionsParser(repo_base, username)
permissions_parser.process_permissions(query)
except Exception as e:
return HttpResponse(
json.dumps(
{'error': str(e)}),
content_type="application/json")
return HttpResponseRedirect(
reverse('browse-security_policies', args=(repo_base, repo, table)))
class OAuthAppUpdate(ApplicationUpdate):
"""
Customized form for updating a Django OAuth Toolkit client app.
Reorders some fields and ignores modifications to other fields.
Extends https://github.com/evonove/django-oauth-toolkit/blob/master/
oauth2_provider/views/application.py
"""
fields = ['name', 'client_id', 'client_secret', 'client_type',
'authorization_grant_type', 'redirect_uris']
def form_valid(self, form):
# Make sure registrants can't disable the authorization step.
# Only site admins can do that.
original_object = get_application_model().objects.get(
pk=form.instance.pk)
form.instance.skip_authorization = original_object.skip_authorization
return super(OAuthAppUpdate, self).form_valid(form)