text: from django.views.decorators.csrf import csrf_exempt
  from django.core.cache import cache
  import sys
  from datetime import timedelta
  from uqx_api import settings
  from rest_framework.permissions import AllowAny
  
  # APIs
  from rest_framework.response import Response
  from rest_framework.reverse import reverse
  
  # Endpoints
  from api.apis.meta import *
  from api.apis.students import *
  from api.apis.discussions import *
  from api.apis.downloads import *
  from api.apis.videos import *
  from api.apis.person import *
  
  # Logging
  import logging
  logger = logging.getLogger(__name__)
  
  
  @csrf_exempt
  @api_view(('GET',))
  @permission_classes((AllowAny, ))
  def api_index(request, theformat=None):
      """
      Lists the currently available API endpoints.
      """
      endpointlist = OrderedDict()
      the_endpoints = endpoints()
      for endpoint_key in the_endpoints:
          firstlevel = str(endpoint_key).split('_')[0]
          if firstlevel not in endpointlist:
              endpointlist[firstlevel] = OrderedDict()
          endpoint = the_endpoints[endpoint_key]
          if 'requirevar' not in endpoint or 'requirevar' == False:
              endpointlist[firstlevel][endpoint['path']] = reverse(endpoint_key, request=request, format=theformat)
          if "option" in endpoint:
              optionname = "<"+endpoint['option']+">"
              endpointlist[firstlevel][endpoint['path']+"/"+optionname] = reverse(endpoint_key+"_"+endpoint['option'], request=request, format=theformat, kwargs={endpoint['option']: ''+endpoint['option']})
              pass
      return Response(endpointlist)
  
  
  @csrf_exempt
  @api_view(('GET',))
  @permission_classes((AllowAny, ))
  def endpointlist(request, theformat=None):
      """
      Lists the currently available API endpoints.
      """
      courses = []
      for db in uqx_api.courses.EDX_DATABASES:
          if db == 'default' or db == 'personcourse' or db == 'Course_Event':
              continue
          courses.append(db)
      endpointlist = OrderedDict()
      the_endpoints = endpoints()
      for endpoint_key in the_endpoints:
          endpoint = the_endpoints[endpoint_key]
          if 'requirevar' not in endpoint or 'requirevar' == False:
              endpointlist[endpoint['path']] = {
                  'url': reverse(endpoint_key, request=request, format=theformat),
                  'lastcache': cache_get_time("/api/"+endpoint['path']),
                  'status': 'refresh'
              }
          if "option" in endpoint:
              if endpoint['option'] == 'course_id':
                  for course in courses:
                      optionname = course
                      endpointlist[endpoint['path']+"/"+optionname] = {
                          'url': reverse(endpoint_key+"_"+endpoint['option'], request=request, format=theformat, kwargs={endpoint['option']: ''+optionname}),
                          'lastcache': cache_get_time("/api/"+endpoint['path']+"/"+optionname),
                          'status': 'refresh'
                      }
              pass
      return Response(endpointlist)
  
  
  # The list of endpoints available
  def endpoints():
      points = OrderedDict()
  
      points['student_genders'] = {'path': 'students/genders', 'option': 'course_id'}
      points['student_ages'] = {'path': 'students/ages', 'option': 'course_id'}
      points['student_fullages'] = {'path': 'students/fullages', 'option': 'course_id'}
      points['student_educations'] = {'path': 'students/educations', 'option': 'course_id'}
      points['student_countries'] = {'path': 'students/countries', 'option': 'course_id'}
      points['student_modes'] = {'path': 'students/modes', 'option': 'course_id'}
      points['student_dates'] = {'path': 'students/dates', 'option': 'course_id'}
      points['student_active'] = {'path': 'students/active', 'option': 'course_id'}
      #points['student_activity'] = {'path': 'students/student_activity', 'option': 'course_id', 'requirevar': True}
      points['student_personcourse'] = {'path': 'students/personcourse', 'option': 'course_id', 'requirevar': True}
      points['student_in_age_range'] = {'path': 'students/inagerange', 'option': 'course_id'}
      points['student_in_age_range_together'] = {'path': 'students/inagerangetogether'}
  
      points['discussion_countries'] = {'path': 'discussions/countries', 'option': 'course_id'}
      points['discussion_dates'] = {'path': 'discussions/dates', 'option': 'course_id', 'requirevar': True}
      points['discussion_popular'] = {'path': 'discussions/popular', 'option': 'course_id'}
      points['discussion_top'] = {'path': 'discussions/top', 'option': 'course_id'}
      points['discussion_category'] = {'path': 'discussions/category', 'option': 'course_id', 'requirevar': True}
  
      points['download_os'] = {'path': 'downloads/os'}
      points['download_browsers'] = {'path': 'downloads/browsers'}
      points['download_countries'] = {'path': 'downloads/countries'}
  
      points['meta_courses'] = {'path': 'meta/courses'}
      points['meta_courseinfo'] = {'path': 'meta/courseinfo'}
      points['meta_uniques'] = {'path': 'meta/uniques'}
      points['meta_structure'] = {'path': 'meta/structure', 'option': 'course_id', 'requirevar': True}
      points['meta_coursestructure'] = {'path': 'meta/coursestructure', 'option': 'course_id', 'requirevar':True}
      points['meta_countries'] = {'path': 'meta/countries'}
      points['meta_modes'] = {'path': 'meta/modes'}
      points['meta_courseevents'] = {'path': 'meta/courseevents', 'option': 'course_id', 'requirevar': True}
      points['meta_courseprofile'] = {'path': 'meta/courseprofile', 'option': 'course_id'}
      points['meta_enrolcount'] = {'path': 'meta/enrolcount'}
      points['meta_lastingest'] = {'path': 'meta/lastingest'}
      points['meta_ingeststatus'] = {'path': 'meta/ingeststatus'}
  
      points['videos_views'] = {'path': 'videos/views', 'option': 'course_id', 'requirevar': True}
  
      points['person_profile'] = {'path': 'person/profile', 'option': 'user_id', 'requirevar': True}
      points['person_lookup'] = {'path': 'person/lookup', 'option': 'details', 'requirevar': True}
      logger.info("Getting endpoints")
      return points
  
  @api_view(('GET',))
  def refresh_cache(request):
      response = {'refreshed': 'true'}
      the_endpoints = endpoints()
      virtual_request = request
      virtual_request.refreshcache = True
      basepath = request.path.replace("refresh_cache","")
      for endpoint in the_endpoints:
          #if endpoint == 'student_genders':
          if 'requirevar' not in endpoint or 'requirevar' is False:
              request.path = basepath + the_endpoints[endpoint]['path']
              getattr(sys.modules[__name__], endpoint)(virtual_request)
              break
          if "option" in the_endpoints[endpoint]:
              if the_endpoints[endpoint]['option'] == 'course_id':
                  courses = get_all_courses()
                  for course in courses:
                      request.path = basepath + the_endpoints[endpoint]['path']+"/"+course
                      getattr(sys.modules[__name__], endpoint)(virtual_request)
      response['cachetime'] = settings.CACHES['default']['TIMEOUT']
      now = datetime.now()
      response['nextrefresh'] = now + timedelta(0, settings.CACHES['default']['TIMEOUT'])
      return Response(response)
  
  # Internal Methods (not endpoints)
  
  def api_render(request, data, response_status=status.HTTP_200_OK):
      if not is_cached(request):
          cache_save(cache_path(request), data)
      return Response(data, response_status)
  
  
  def api_cacherender(request):
      return api_render(request, cache_get(cache_path(request)), status.HTTP_200_OK)
  
  
  def is_cached(request):
      if cache.get(cache_path(request)):
          if 'refreshcache' in request.QUERY_PARAMS or hasattr(request, 'refreshcache') and request.refreshcache:
              logger.info("Refreshing Cache")
              return False
          return True
      return False
  
  
  def get_course(course_id):
      if course_id in uqx_api.courses.EDX_DATABASES:
          return uqx_api.courses.EDX_DATABASES[course_id]
      return None
  
  
  def get_all_courses():
      courses = dict(uqx_api.courses.EDX_DATABASES)
      del courses['default']
      del courses['personcourse']
      del courses['Course_Event']
      return courses
  
  
  def cache_save(path, data):
      logger.info("Saving cache for path "+fixpath(path)+", times out in "+str(settings.CACHES['default']['TIMEOUT']))
      cache.set(fixpath(path), data, settings.CACHES['default']['TIMEOUT'])
      cache_update_time(path)
      pass
  
  def cache_update_time(path):
      cache.set('expiry_'+fixpath(path), datetime.now().strftime("%Y-%m-%d %H:%M:%S"), settings.CACHES['default']['TIMEOUT'])
  
  
  def cache_get(path):
      logger.info("Retrieving cache for path "+fixpath(path)+", times out in "+str(settings.CACHES['default']['TIMEOUT']))
      return cache.get(fixpath(path))
  
  
  def cache_get_time(path):
      logger.info("Retrieving cache expiry time for path "+fixpath(path))
      if cache.get('expiry_'+fixpath(path)):
          return cache.get('expiry_'+fixpath(path))
      else:
          return ""
  
  
  def db_table_exists(db, table):
          from django.db import connections
          table_names = connections[db].introspection.get_table_list(connections[db].cursor())
          print table_names
          return table in table_names
  
  
  def cache_path(request):
      get = ""
      for param in request.GET:
          print param
          if param != 'refreshcache' and param != 'format':
              paramval = request.GET[param]
              paramval = paramval.replace(" ", "").replace("%20", "")
              get += param+":"+paramval
      if get != "":
          get = "?"+get
      request_path = request.path.replace(" ", "").replace("%20", "")
      return str(fixpath(request_path+get))
  
  
  def fixpath(path):
      return path.rstrip('\/')
  