text: 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)
  