text: from __future__ import unicode_literals
  
  import base64
  import json
  
  from django.conf import settings
  from django.contrib.auth import authenticate, login
  from django.http import HttpResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotFound
  from django.shortcuts import get_object_or_404
  from django.views.decorators.csrf import csrf_exempt
  from django.views.decorators.http import require_http_methods
  
  from courses.models import Course
  from issues.models import Issue
  from users.models import UserProfile
  
  ISSUE_FILTER = {
      'student': 'student__username',
      'responsible': 'responsible__username'
  }
  
  
  def login_required_basic_auth(view):
      def get_401_response():
          response = HttpResponse()
          response.status_code = 401
          response['WWW-Authenticate'] = 'Basic realm="AnyTask API"'
          return response
  
      def check_auth(request, *args, **kwargs):
          if 'HTTP_AUTHORIZATION' not in request.META:
              return get_401_response()
  
          auth_str = request.META['HTTP_AUTHORIZATION']
          auth_str_parts = auth_str.split()
  
          if auth_str_parts[0].lower() != "basic":
              return get_401_response()
  
          username, password = base64.b64decode(auth_str_parts[1]).split(":", 1)
          user = authenticate(username=username, password=password)
          if user is None or not user.is_active:
              return get_401_response()
  
          login(request, user)
          request.user = user
          return view(request, *args, **kwargs)
  
      return check_auth
  
  
  def unpack_user(user):
      profile = user.get_profile()
      return {
          "id": user.id,
          "name": user.get_full_name(),
          "first_name": user.first_name,
          "last_name": user.last_name,
          "username": user.username,
          "middle_name": profile.middle_name,
      }
  
  
  def unpack_task(task, lang=settings.API_LANGUAGE_CODE):
      return {
          "id": task.id,
          "title": task.get_title(lang),
      }
  
  
  def unpack_issue(issue, add_events=False, request=None, lang=settings.API_LANGUAGE_CODE):
      task = issue.task
      ret = {
          "id": issue.id,
          "mark": issue.mark,
          "create_time": issue.create_time.isoformat() + "Z",
          "update_time": issue.update_time.isoformat() + "Z",
          "responsible": None,
          "followers": map(lambda x: unpack_user(x), issue.followers.all()),
          "status": unpack_status(issue.status_field, lang),
          "student": unpack_user(issue.student),
          "task": unpack_task(task)
      }
  
      if issue.responsible:
          ret["responsible"] = unpack_user(issue.responsible)
  
      if add_events and request:
          ret["events"] = map(lambda x: unpack_event(request, x), issue.get_history())
  
      return ret
  
  
  def unpack_file(request, f):
      return {
          "id": f.id,
          "filename": f.filename(),
          "path": f.file.url,
          "url": request.build_absolute_uri(f.file.url),
      }
  
  
  def has_access(user, issue):
      if user in (issue.student,
                  issue.responsible):
          return True
  
      if issue.followers.filter(id=user.id).exists():
          return True
  
      course = issue.task.course
      if course.user_is_teacher(user):
          return True
  
      return False
  
  
  def unpack_event(request, event):
      ret = {
          "id": event.id,
          "timestamp": event.timestamp.isoformat() + "Z",
          "author": unpack_user(event.author),
          "message": event.get_message(),
          # "files": list(event.file_set.all())
          "files": map(lambda x: unpack_file(request, x), event.file_set.filter(deleted=False)),
      }
  
      return ret
  
  
  def unpack_status(status, lang=settings.API_LANGUAGE_CODE):
      return {
          "id": status.id,
          "name": status.get_name(lang),
          "tag": status.tag,
          "color": status.color,
      }
  
  
  def unpack_statuses(course, lang=settings.API_LANGUAGE_CODE):
      ret = []
  
      for status in course.issue_status_system.statuses.all():
          ret.append(unpack_status(status, lang))
  
      return ret
  
  
  def get_issue_filter(data):
      filter_args = {}
      if 'status' in data:
          status_arg = data['status']
          filter_args['status_field__id' if status_arg.isdigit() else 'status_field__tag'] = status_arg
  
      for arg, qs_arg in ISSUE_FILTER.iteritems():
          if arg in data:
              filter_args[qs_arg] = data[arg]
  
      return filter_args
  
  
  @login_required_basic_auth
  @require_http_methods(['GET'])
  def get_issues(request, course_id):
      course = get_object_or_404(Course, id=course_id)
      user = request.user
      if not course.user_is_teacher(user):
          return HttpResponseForbidden()
  
      add_events = bool(request.GET.get("add_events", False))
      filter_args = get_issue_filter(request.GET)
  
      ret = []
      issues = Issue.objects \
          .filter(task__course=course, **filter_args) \
          .select_related("task") \
          .prefetch_related("followers")
      lang = request.GET.get('lang', settings.API_LANGUAGE_CODE)
      for issue in issues:
          ret.append(unpack_issue(issue, add_events=add_events, request=request, lang=lang))
  
      return HttpResponse(json.dumps(ret),
                          content_type="application/json")
  
  
  def get_issue(request, issue):
      lang = request.GET.get('lang', settings.API_LANGUAGE_CODE)
      ret = unpack_issue(issue, add_events=True, request=request, lang=lang)
  
      return HttpResponse(json.dumps(ret),
                          content_type="application/json")
  
  
  def post_issue(request, issue):
      user = request.user
  
      if issue.task.course.user_is_teacher(user):
          status = request.POST.get('status')
          if status:
              if status.isdigit():
                  issue.set_status_by_id(status, user)
              else:
                  issue.set_status_by_tag(status, user)
  
          mark = request.POST.get('mark')
          if mark:
              try:
                  issue.set_byname('mark', float(mark))
              except ValueError:
                  return HttpResponseBadRequest()
  
      comment = request.POST.get('comment')
      if comment:
          issue.add_comment(comment, author=user)
  
      lang = request.POST.get('lang', settings.API_LANGUAGE_CODE)
      ret = unpack_issue(get_object_or_404(Issue, id=issue.id), add_events=True, request=request, lang=lang)
  
      return HttpResponse(json.dumps(ret),
                          content_type="application/json")
  
  
  @csrf_exempt
  @login_required_basic_auth
  @require_http_methods(['GET', 'POST'])
  def get_or_post_issue(request, issue_id):
      issue = get_object_or_404(Issue, id=issue_id)
  
      if not has_access(request.user, issue):
          return HttpResponseForbidden()
  
      if request.method == 'POST':
          return post_issue(request, issue)
      return get_issue(request, issue)
  
  
  @csrf_exempt
  @login_required_basic_auth
  @require_http_methods(['POST'])
  def add_comment(request, issue_id):
      comment = request.POST.get('comment')
      if not comment:
          return HttpResponseBadRequest()
  
      user = request.user
      issue = get_object_or_404(Issue, id=issue_id)
  
      if not has_access(user, issue):
          return HttpResponseForbidden()
  
      issue.add_comment(comment, author=user)
  
      return HttpResponse(status=201)
  
  
  @login_required_basic_auth
  @require_http_methods(['GET'])
  def get_issue_statuses(request, course_id):
      user = request.user
      course = get_object_or_404(Course, id=course_id)
  
      if not course.user_is_teacher(user):
          return HttpResponseForbidden()
  
      ret = unpack_statuses(course)
  
      return HttpResponse(json.dumps(ret),
                          content_type="application/json")
  
  
  @require_http_methods(['GET'])
  def check_user(request):
      ya_login = request.GET.get('ya_login')
      if not ya_login:
          return HttpResponseBadRequest()
  
      try:
          profile = UserProfile.objects.select_related('user').get(ya_passport_login=ya_login)
      except UserProfile.DoesNotExist:
          return HttpResponseNotFound('No profile found')
  
      user = profile.user
  
      return HttpResponse(json.dumps({
          'id': user.id,
          'ya_passport_login': ya_login,
          'active': user.is_active,
          'is_staff': user.is_staff or user.is_superuser,
          'is_teacher': user.course_teachers_set.exists(),
      }), content_type="application/json")
  