"""Módulo que contiene toda la estructura de la ventana principal del programa"""
import customtkinter
import os
import ttkbootstrap as ttk
from PIL import Image
from tools.Usos import reader_image
from tools.Usos import center
from tools.Usos import set_font
from tablesetting.data_base_user import new_data
from system_vars.Vars import *
from entry_classes.income import IncomeFrame
from entry_classes.spend import GastosFrame
from entry_classes.budget import PresupuestoFrame
from graph_classes.graph_choice import GraphChoice
from Download.descarga import DescargaChoice
from pathlib import Path
#path_image =path_image= os.path.join(os.path.dirname(os.path.realpath("Documents")),r"./Imagenes")
import system_vars.config  as config
global path_image
path_image=Path('.') / "Imagenes"

class MainWindow(customtkinter.CTk):
    """Clase que controla la ventana principal

    :param customtkinter: Clase padre de la biblioteca
    :type customtkinter: Class
    """
    def __init__(self, currentuser):
        """Constructora de la clase, se encarga de aspectos de la configuracion

        :param currentuser: Usuario actual que hizo login en el sistema
        :type currentuser: str
        """
        super().__init__()
        #Configurar la principal
        self.title("Presupuesto Mensual")
        self.iconbitmap(os.path.join(path_image,"icon.ico"))
        weight = 1000
        height = 600
        center(self,weight,height)
        self.resizable(False,False)
        self.user = currentuser
        config.currentuser = currentuser
        self.sections()

    def sections(self):
        """Funcion donde se crean las instancias de las diferentes secciones del programa

        :param up_panel: Panel superior
        :type up_panel: UpperBar
        :param menu_panel: Panel del menu
        :type menu_panel: MenuFrame
        :param body_panel: Panel de la seccion de display del programa
        :type body_panel:BodyFrame
        """
        #Frames de las secciones principales
        self.up_panel= UpperBar(self,self.user)
        #La declaracion de este widget sucede en esta seccion para acceder a la funcion que contrae y despliega el menu
        self.side_menu_image=reader_image(path_image,"sidemenu.png",(10,10))
        #Boton de abrir y cerrar menu
        self._menu_bottom= customtkinter.CTkButton(self.up_panel,
                                                   text=" ",
                                                   border_width=0,width=20,
                                                   fg_color=COLOR_SUPERIOR,
                                                   hover_color=HOVER_COLOR,
                                                   text_color=TEXT_COLOR,
                                                   image=self.side_menu_image,
                                                   compound="left",
                                                   command=self.toggle_panel)
        self._menu_bottom.pack(side=ttk.LEFT)
        self.menu_panel= MenuFrame(self)
        self.body_panel=BodyFrame(self)

        #Metodos para desplegar widgets
        self.up_panel.widgets_upper_bar()
        self.menu_panel.widgets_menu(self.body_panel,self)

    def toggle_panel(self):
        """
        funcion para contraer o desplegar el menu lateral
        """
        if self.menu_panel.winfo_ismapped():
            self.menu_panel.pack_forget()
        else:
            self.menu_panel.pack(side=ttk.LEFT,fill='y')
"""
Definicion de los Frames de cada seccion
Heredan de customtkinter.CTkFrame
Necesitan que se les pase el Master
"""
class BodyFrame(customtkinter.CTkFrame):
    """Clase que configura la ventana principal"""
    def __init__(self,master):
        super().__init__(master)
        self.configure(master,fg_color=COLOR_BODY,width=150)
        self.pack(side=ttk.RIGHT, fill='both', expand=True)

        self.grid_columnconfigure(2, weight=1)
class UpperBar(customtkinter.CTkFrame):
    """Clase de la barra superior
    """
    def __init__(self,master,User):
        """Constructora de la clase, configura aspectos del Frame

        :param master: Ventana superior donde va la barra
        :type master: CTk
        :param User: Usuario actual
        :type User: str
        """
        super().__init__(master)
        self.configure(master, height=50,fg_color=FG_COLOR2,border_width=0)
        self.pack(side=ttk.TOP, fill ='both')
        self.User = User
    def widgets_upper_bar(self):
        #Display barra superior
        self.title=customtkinter.CTkLabel(self,
                                          text_color=TEXT_COLOR,
                                          text="Presupuesto digital",
                                          font=("Cascadia Mono SemiBold",15),
                                          fg_color='transparent',padx=10,
                                          pady=10,
                                          width=16)
        self.title.pack(side=ttk.LEFT)
        #Usuario actual
        self._current_user= customtkinter.CTkLabel(self,
                                                    text=self.User,pady=10, padx=10,
                                                    text_color=TEXT_COLOR,
                                                    font=("Cascadia Mono SemiBold",12))
        self._current_user.pack(side=ttk.RIGHT)

class MenuFrame(customtkinter.CTkFrame):
    """Clase que define al menu lateral

    """
    def __init__(self,master):
        """Constructora de la clase, configura las imagenes

        :param master: Ventana principal donde se quiere posicionar el frame
        :type master: CTK
        """
        super().__init__(master)
        self.menu_icon=reader_image(path_image,"menu.png",(40,40))
        self.image2=reader_image(path_image,"salary.png",(20,20))
        self.image3=reader_image(path_image,"line-chart.png",(20,20))
        self.image4=reader_image(path_image,"file.png",(20,20))
        self.configure(master,width=400,fg_color=FG_COLOR2)
        self.pack(side=ttk.LEFT, fill='both', expand=False)
        self.grid_rowconfigure(5,weight=1)

    def widgets_menu(self,body,root):
        """Funcion que maneja los widgets del menu

        :param body: Frame donde se quieren posicionar los widgets
        :type body: CTkFrame
        :param root: Ventana Principal
        :type root: CTk
        :param data_user: Boton que despliega las opciones para la entrada del usuario
        :type data_user: CTkButtom
        :param _analisis: Boton que despliega las opciones para graficacion
        :type _analisis: CTkButtom
        :param exportar_datos: Boton que despliega las opciones para exportar
        :type exportar_datos: CTkButtom
        """
        self.Main=root
       #Opciones del menu lateral
        self.menu_label=customtkinter.CTkLabel(self, text = " ",compound="top",image=self.menu_icon)
        self.menu_label.grid(row=0, column=0,padx=20,pady=20,sticky="nsew")
        self.master=body
        self.data_user= customtkinter.CTkButton(self, text ="Datos del usuario",
                                                corner_radius=0,
                                                height=30,
                                                font=set_font(),
                                                border_spacing=10,
                                                fg_color='transparent',
                                                text_color=("gray10", "gray90"),
                                                hover_color=("gray70", "gray30"),
                                                image=self.image2,
                                                anchor="w",
                                                command=self.evento_data_user)
        self.data_user.grid(row=2,column=0, sticky="nsew")
        self._analisis= customtkinter.CTkButton(self, text ="Visualizacion de datos",
                                            corner_radius=0,font=set_font(),
                                            height=30,
                                            border_spacing=10,
                                            fg_color='transparent',
                                            text_color=("gray10", "gray90"),
                                            hover_color=("gray70", "gray30"),
                                            anchor="w",
                                            image=self.image3,
                                            command=self.evento_analisis)
        self._analisis.grid(row=3,column=0, sticky="nsew")
        self.exportar_datos= customtkinter.CTkButton(self, text ="Exportar Datos",
                                            corner_radius=0,
                                            height=30,font=set_font(),
                                            border_spacing=10,
                                            fg_color='transparent',
                                            text_color=("gray10", "gray90"),
                                            hover_color=("gray70", "gray30"),
                                            anchor="w",
                                            image=self.image4,
                                            command=self.evento3)
        self.exportar_datos.grid(row=4,column=0, sticky="nsew")
        #self.menu_display= customtkinter.CTkOptionMenu(master=self,values = ['blue','dark-blue','green'], command=self.evento_color)
        #self.menu_display.grid(row =6, column=0,padx=20,pady=20 ,sticky = "s")
        self.logout=customtkinter.CTkButton(master=self,text='Log Out', font=set_font(),command=self.evento_logout)
        self.logout.grid(row=6,column=0,padx=20,pady=20,sticky='s')
        self.menu_display= customtkinter.CTkOptionMenu(master=self,
                                                       values = ['dark','system','light'],
                                                       command=self.evento_apariencia,fg_color=BORDER_COLOR,dropdown_fg_color=BORDER_COLOR,
                                                       button_color=BORDER_COLOR,
                                                       button_hover_color=HOVER_COLOR,
                                                       font=set_font(),
                                                       dropdown_font=set_font())
        self.menu_display.grid(row =5, column=0,padx=20,pady=20 ,sticky = "s")
        self.change_window("data_user")
    def evento_apariencia(self,op):
        #Definir eventos para los botones y menus
        customtkinter.set_appearance_mode(op)
    def evento_logout(self):
        #Evento para logout
        self.Main.destroy()

    def evento_data_user(self):
        #Al clickear entrada de datos
        self.change_window("data_user")
    def evento_analisis(self):
        #Evento para analisis
        self.change_window("analisis")
    def evento3(self):
        #evento para exportar datos
        self.change_window("export")

    def change_window(self,buttom:str):
        """Esta es la funcion que se encarga de cambiar lo que se ve en el panel principal

        :param buttom: Boton seleccionado
        :type buttom:str
        """
        #Esto es para que quede marcada la opcion que se muestra en el momento en pantalla
        if buttom == "analisis":
            self._analisis.configure(fg_color=BUTTOM_HOVER)
        else:
            self._analisis.configure(fg_color="transparent")
        if buttom == "data_user":
            self.data_user.configure(fg_color=BUTTOM_HOVER)
        else:
            self.data_user.configure(fg_color="transparent")
        if buttom == "export":
            self.exportar_datos.configure(fg_color=BUTTOM_HOVER)
        else:
            self.exportar_datos.configure(fg_color="transparent")
        #Creo las instancias de los frames
        data = EntradaDatosFrame(self.master)
        analisis= Analisis(self.master)
        export = Exportardatos(self.master)
        #Posiciono los Frames
        if buttom == "data_user":
            data.get_frame().grid(row=0, column=2, sticky = "nsew")
        else:
            data.get_frame().grid_forget()
        if buttom == "analisis":
            analisis.get_frame().grid(row=0, column=2, sticky = "nsew")
        else:
            analisis.get_frame().grid_forget()
        if buttom == "export":
            export.get_frame().grid(row=0, column=2, sticky = "nsew")
        else:
            export.get_frame().grid_forget()
class SubFrames(customtkinter.CTkFrame):
    #Clase abstracta para definir caracteristicas de las otras subclases de la ventana
    def __init__(self, master):
        super().__init__(master)
        self._layout= customtkinter.CTkFrame(master, corner_radius=0,fg_color="transparent")
        self._layout.grid_columnconfigure(0, weight=1)
    def get_frame(self):
         #Devuelve el Frame
         return self._layout

class EntradaDatosFrame(SubFrames):
    """Clase para el boton que permite la entrada de datos

    :param SubFrames: Clase con las caracteristicas de las subventanas
    :type SubFrames: CTkFrame
    """
    def __init__(self,master):
        """Clase constructora se encarga de inicializar la ventana

        :param master: se le pasa el principal de la padre
        :type master: CTk
        :param buttom_ingresos: Boton que permite acceder a la ventana de ingresos
        :type buttom_ingresos: CTkButton
        :param buttom_gastos: Boton que permite acceder a la ventana de gastos
        :type buttom_gastos: CTkButton
        :param buttom_budget: Boton que permite acceder a la ventana de presupuesto
        :type buttom_budget: CTkButton
        :param new_frame_income: ventana de los ingresos
        :type new_frame_income: Subframe
        :param new_frame_gastos: ventana de los gastos
        :type new_frame_gastos: Subframe
        :param new_frame_budget: ventana del presupuesto
        :type new_frame_budget: Subframe
        """
        super().__init__(master)
        self.image_ingresos=customtkinter.CTkImage(Image.open(os.path.join(path_image,"profits.png")), size=(40,40))
        self.buttom_ingresos= customtkinter.CTkButton(master=self._layout,
                                                      text="Ingresos",
                                                      image=self.image_ingresos,
                                                      compound="top",font=set_font(),
                                                      command=self.event_boton1)
        self.buttom_ingresos.grid(row=0 , column= 0, padx=20,pady=10, sticky ="nsew")
        # Boton 2
        self.image_gastos=customtkinter.CTkImage(Image.open(os.path.join(path_image,"expense.png")), size=(40,40))
        self.buttom_gastos =customtkinter.CTkButton(master=self._layout,
                                                    text="Gastos",fg_color=BORDER_COLOR,
                                                    image=self.image_gastos,hover_color=HOVER_COLOR,
                                                    compound="top",font=set_font(),
                                                    command=self.event_boton2)
        self.buttom_gastos.grid(row=1 , column= 0, padx=20,pady=10, sticky ="nsew")

        #Boton 3
        self.image_presupuesto= customtkinter.CTkImage(Image.open(os.path.join(path_image,"budget.png")), size=(40,40))
        self.buttom_budget=customtkinter.CTkButton(master=self._layout,
                                                   text="Presupuesto",font=set_font(),
                                                   image=self.image_presupuesto,
                                                   compound="top",
                                                   command=self.event_boton3)
        self.buttom_budget.grid(row=2 , column= 0, padx=20,pady=10, sticky ="nsew")
        #Nuevo frame
        self.new_frame_income=SubFrames(master)
        self.new_frame_gastos= SubFrames(master)
        self.new_frame_budget = SubFrames(master)
    def event_boton1(self):
        #Para entrar un nuevo Frame de ingresos
        self._layout.grid_forget()
        self.new_frame_income._layout.grid(row=0, column=2, sticky = "nsew")
        self.new_frame_income._layout.columnconfigure(0, weight=1)
        self.new_frame_income._layout.rowconfigure(0,weight=1)
        IncomeFrame(self.new_frame_income._layout)
    def event_boton2(self):
        #Para entrar al nuevo frame de ingreso de gastos
        self._layout.grid_forget()
        self.new_frame_gastos._layout.grid(row=0,column=2,sticky='nsew')
        self.new_frame_gastos._layout.columnconfigure(0,weight=1)
        self.new_frame_gastos._layout.rowconfigure(0,weight=1)
        GastosFrame(self.new_frame_gastos._layout)
    def event_boton3(self):
        #Para entrar al nuevo frame de ingreso de presupuesto
        self._layout.grid_forget()
        self.new_frame_budget._layout.grid(row=0,column=2,sticky='nsew')
        self.new_frame_budget._layout.columnconfigure(0,weight=1)
        self.new_frame_budget._layout.rowconfigure(0,weight=1)
        PresupuestoFrame(self.new_frame_budget._layout)

class Analisis(SubFrames):
    """Clase para el boton analisis

    :param SubFrames: Clase padre las subventanas
    :type SubFrames: CTkFrame
    """
    def __init__(self,master):
        """Constructor del marco para las opciones de graficacion

        :param master: _description_
        :type master: _type_
        """
        super().__init__(master)
        GraphChoice(self._layout)
   #Prueba
    def get_option_menu_choice(self,choice):
        print(choice)

class Exportardatos(SubFrames):
    # Clase para el boton de exportar datos
    def __init__(self,master):
        super().__init__(master)
        """self.title_frame3= customtkinter.CTkLabel(self._layout, text ="Opciones de descarga",font=customtkinter.CTkFont(family="Century Gothic", weight="bold"))
        self.title_frame3.grid(row=0, column=0, padx=20,pady=20, sticky="nsew",columnspan=2)
        #Radio buttoms
        self.radio_var = customtkinter.IntVar(value=0)
        self.op1=customtkinter.CTkRadioButton(self._layout, text="Excel",font=customtkinter.CTkFont(family="Century Gothic"),command=self.radio_event,variable=self.radio_var, value =1)
        self.op1.grid(row=1, column=0, padx=10, pady =(0,20),sticky="w")
        self.op2=customtkinter.CTkRadioButton(self._layout, text="Graficos",font=customtkinter.CTkFont(family="Century Gothic"),command=self.radio_event,variable=self.radio_var, value =2)
        self.op2.grid(row=1, column=1, padx=10, pady =(0,20), sticky="w")"""
        DescargaChoice(self._layout)

    def radio_event(self):
        pass
        print(f'radio var is {self.radio_var.get()}')


import numpy as np
import matplotlib.pyplot as plt

# -3.14 ~ 3.14 까지 256개의 값으로 표시해라.
x = np.linspace(-np.pi, np.pi, 256, endpoint=True) #256개 값
print(x.shape)

c = np.cos(x) # 256개 값
s = np.sin(x) # 256개 값

plt.plot(x, c)
plt.plot(x, s)
plt.show()


import urllib.request
import sys
import time
import termcolor
import colorama

import os
colorama.init()
def get_filename(url):
    return url.split("/")[-1]

if len(sys.argv) != 2:
    print("usage:   wget filename")
else:
    url =sys.argv[1]
    filname = get_filename(url)
    data = None
    start = time.time()
    try:
        while data==None or data.length == None:
            print("[+] Conecting with server.... ",end="\r",flush=True)
            data=urllib.request.urlopen(url)
            end = time.time()
            if end-start >20:
                termcolor.cprint("[-] Connection time out 400")
                sys.exit(1)
    except Exception as msg:
        print(msg)
        sys.exit(1)
    termcolor.cprint("[+] Contected with server\n",end="\r",color="green")
    total_length = data.length
    block = 512
    filesize = 0
    with open(filname,"wb") as fh:
        while True:
            buffer = data.read(block)
            # print(buffer)
            if not buffer:
                break
            filesize += len(buffer)
            fh.write(buffer)
            percent = filesize*100/total_length
            termcolor.cprint("Downloading.....   %.2f percent "%percent,end='\r',color="blue", flush=True)
        fh.close()


from datetime import datetime
from django.views import View
from django.db.models import Max, F, Q
from django.db.models.expressions import RawSQL
from django.db import connection
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.core.validators import validate_email, validate_ipv46_address
from django.http import HttpResponse, JsonResponse, HttpResponseNotAllowed, Http404, HttpResponse, HttpResponseForbidden
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.urls import path, include, reverse
from django.utils import timezone
from django.shortcuts import get_object_or_404, get_list_or_404
from rest_framework import status, generics, mixins
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
try:
    from django.utils import simplejson
except:
    import simplejson

import redis
import time
import logging
from uuid import uuid1, UUID

import oj_backend.backend.middleware_connector as mw_connector
from oj_backend.backend.utils import student_active_test, student_test, insturctor_test, student_taking_course_test, student_submit_assignment_test, instructor_giving_course_test, regrade_assignment
from oj_backend.backend.models import *
from oj_backend.backend.serializers import *
from oj_backend.backend.permissions import *
from oj_backend.settings import redisConnectionPool, OJ_SUBMISSION_TOKEN, OJ_ENFORCE_HTTPS
from oj_backend.backend.middleware_connector import *
from oj_backend.backend.celery_tasks import *

backend_logger = logging.getLogger('backend.main')

class studentInformation(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
    '''
    `/student/<str:uid>`
    '''
    queryset = Student.objects.all()
    serializer_class = StudentInfoSerializer
    permission_classes = (userInfoReadWritePermission, IsAuthenticated)
    lookup_field = 'uid'

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(queryset, user__uid=self.kwargs['uid'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        response = self.update(request, *args, **kwargs)
        email = self.get_object().user.email
        user_key = self.get_object().user.rsa_pub_key
        try:
            MWUpdateUserKey(email, user_key)
        except (MWUpdateError, MiddlewareError):
            return JsonResponse({"cause": "server error"}, status=500)
        return response

class insturctorInformation(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
    '''
    `/instructor/<str:uid>/`
    '''
    queryset = Instructor.objects.all()
    serializer_class = InstructorInfoSerializer
    permission_classes = (userInfoReadWritePermission, IsAuthenticated)
    lookup_field = 'uid'

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(queryset, user__uid=self.kwargs['uid'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        response = self.update(request, *args, **kwargs)
        email = self.get_object().user.email
        user_key = self.get_object().user.rsa_pub_key
        try:
            MWUpdateUserKey(email, user_key)
        except (MWUpdateError, MiddlewareError):
            return JsonResponse({"cause": "server error"}, status=500)
        return response

class userRole(generics.GenericAPIView):
    '''
    `/user/role`

    And

    `/user/`
    '''

    def get(self, request):
        if not request.user.is_authenticated:
            return Response(status=401)
        data = {
            'uid': request.user.uid,
            'is_student': Student.objects.filter(user__uid=request.user.uid).exists(),
            'is_instructor': Instructor.objects.filter(user__uid=request.user.uid).exists()
        }
        return JsonResponse(data=data, status=200)

class userInstr(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/user/<str:uid>/instructor`
    '''
    serializer_class = InstructorBasicInfoSerializer
    permission_classes = (
        IsAuthenticated, studentinstrUserInfoReadWritePermission)

    def get_queryset(self):
        return Instructor.objects.filter(user__uid=self.kwargs['uid'])

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(queryset, user=self.request.user)
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return JsonResponse(data={'cuase': 'Unauthorized'}, status=401)
        try:
            uid = UUID(self.kwargs['uid'])
        except:
            return JsonResponse(data={'cuase': 'Bad request'}, status=400)
        if request.user.uid != uid:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        if Instructor.objects.filter(enroll_email=request.user.email, user=request.user).exists():
            return JsonResponse(data={'cause': 'Already exists.'}, status=409)
        this_instr = Instructor(
            enroll_email=request.user.email, user=request.user)
        this_instr.save()
        serializer = self.serializer_class(this_instr)
        return JsonResponse(serializer.data, status=201)

class userStudent(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/user/<str:uid>/student`
    '''
    serializer_class = StudentBasicInfoSerializer
    permission_classes = (
        IsAuthenticated, studentinstrUserInfoReadWritePermission)

    def get_queryset(self):
        return Student.objects.filter(user__uid=self.kwargs['uid'])

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(queryset, user=self.request.user)
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return JsonResponse(data={'cuase': 'Unauthorized'}, status=401)
        try:
            uid = UUID(self.kwargs['uid'])
        except:
            return JsonResponse(data={'cuase': 'Bad request'}, status=400)
        if request.user.uid != uid:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            nickname = self.request.data['nickname']
            student_id = self.request.data['student_id']
        except KeyError:
            return JsonResponse(data={'cause': 'Invalid request'}, status=400)
        if Student.objects.filter(enroll_email=request.user.email, user=request.user).exists():
            return JsonResponse(data={'cause': 'Already exists.'}, status=409)
        this_student = Student(enroll_email=request.user.email,
                               user=request.user, nickname=nickname, student_id=student_id)
        this_student.save()
        serializer = self.serializer_class(this_student)
        return JsonResponse(serializer.data, status=201)

class courseList4Students(generics.GenericAPIView, mixins.ListModelMixin):
    '''
    `/student/<str:uid>/course/`
    '''
    serializer_class = CoursesViewSerializer
    permission_classes = (courseReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        this_student = get_object_or_404(Student.objects.filter(
            user=self.request.user), user__uid=self.kwargs['uid'])
        return this_student.course_set.all()

    def get(self, request, *args, **kwargs):
        try:
            uid = UUID(self.kwargs['uid'])
        except:
            return JsonResponse(data={'cuase': 'Bad request'}, status=400)
        if request.user.uid != uid:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        return self.list(request, *args, **kwargs)

class courseList4Instr(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    '''
    `/insturctor/<str:uid>/course/`
    '''
    serializer_class = CoursesCreateSerializer
    permission_classes = (courseReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        this_instr = get_object_or_404(Instructor.objects.filter(
            user=self.request.user), user__uid=self.kwargs['uid'])
        return this_instr.course_set.all()

    def perform_create(self, serializer):
        serializer.save(creator=self.request.user.uid, uid=uuid1())

    def get(self, request, *args, **kwargs):
        try:
            uid = UUID(self.kwargs['uid'])
        except:
            return JsonResponse(data={'cuase': 'Bad request'}, status=400)
        if request.user.uid != uid:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        response = self.create(request, *args, **kwargs)
        this_course = Course.objects.get(uid=response.data['uid'])
        this_course.instructor.add(request.user.instructor)
        try:
            course_name = get_course_project_name(
                this_course.code, this_course.year, this_course.semester)
            MWUpdateCourse(course_name, str(this_course.uid))
        except (MiddlewareError, MWUpdateError):
            # rollback.
            this_course.delete()
            return JsonResponse(status=500, data={"cuase": "Git server error."})
        for instr in this_course.instructor.all():
            if not MW_if_user_exists(instr.enroll_email):
                try:
                    MWUpdateUser(instr.enroll_email)
                except (MiddlewareError, MWUpdateError):
                    return JsonResponse(data={'cause': 'Git server error.'}, status=500)
            try:
                MWCourseAddInstr(this_course.uid, instr.enroll_email)
            except (MiddlewareError, MWUpdateError):
                return JsonResponse(data={'cause': 'Git server error.'}, status=500)
        return response

class assignmentList4Student(generics.GenericAPIView):
    '''
    `/student/<str:student_id>/course/<str:course_id>/assignment/`
    '''

    def get(self, request, *args, **kwargs):
        this_student = get_object_or_404(
            Student, user__uid=self.kwargs['student_id'])
        this_course = get_object_or_404(
            this_student.course_set.all(), uid=self.kwargs['course_id'])
        this_assignment_set = this_course.assignment_set.all()

        BASE = """
            SELECT
                max(`oj_database_record`.`id`)
            FROM
                oj_database_student
            INNER JOIN `oj_database_record_student` ON `oj_database_record_student`.`student_id` = `oj_database_student`.`id`
            INNER JOIN `oj_database_record` ON `oj_database_record_student`.`record_id` = `oj_database_record`.`id`
            WHERE
                `oj_database_student`.`id` = {id}
            AND `oj_database_record`.`state` = 2
            GROUP BY
                `oj_database_record`.`assignment_id`
        """
        SQL = BASE.format(
            id=this_student.id
        )
        with connection.cursor() as cursor:
            cursor.execute(SQL)
            recids = [i[0]for i in cursor.fetchall()]

        last_rec = Record.objects.filter(id__in=recids)
        last_rec = {i['assignment_id']: i['grade']
                    for i in list(last_rec.values())}
        assignment_with_grade = list(this_assignment_set.values
                                     ('uid', 'course_id', 'name', 'descr_link', 'deadline',
                                      'release_date', 'deadline', 'short_name', overall_score=F('grade')))
        for i in range(len(assignment_with_grade)):
            try:
                assignment_with_grade[i]['score'] = last_rec[assignment_with_grade[i]['uid']]
            except KeyError:
                assignment_with_grade[i]['score'] = 0

        assignment_with_grade = sorted(
            assignment_with_grade,
            key=lambda x: (x["deadline"], x["release_date"], x["name"])
        )

        return JsonResponse(assignment_with_grade, safe=False)

class courseInformation(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin):
    '''
    `/course/<str:uid>`
    '''
    serializer_class = CoursesViewSerializer
    permission_classes = (courseReadWritePermission, IsAuthenticated)
    queryset = Course.objects.all()

    def get_object(self):
        course_uid = self.kwargs['uid']
        queryset = self.get_queryset()
        obj = get_object_or_404(
            queryset, uid=course_uid)
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

class assignmentList4Instr(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    '''
    `/course/<str:uid>/assignment/`
    '''
    serializer_class = AssignmentCreateSerializer
    permission_classes = (assignmentInfoReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        this_course = get_object_or_404(Course, uid=self.kwargs['uid'])
        return this_course.assignment_set.all().order_by("deadline", "release_date", "name")

    def perform_create(self, serializer):
        this_course = get_object_or_404(Course, uid=self.kwargs['uid'])
        serializer.save(course=this_course)

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        this_course = get_object_or_404(Course, uid=self.kwargs['uid'])
        if not this_course.instructor.filter(user=request.user):
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        response = self.create(request, *args, **kwargs)
        this_assignment = Assignment.objects.get(uid=response.data['uid'])
        deadline = this_assignment.deadline
        try:
            MWCourseAddAssignment(
                self.kwargs['uid'], this_assignment.short_name, str(this_assignment.uid))
            repo = MWCourseAddRepo(self.kwargs['uid'], str(this_assignment.uid), [
            ], deadline, repo_name='_grading_script', owner_uid=None)
            git_repo = repo.response.json().get('ssh_url_to_repo')
            this_assignment.git_org_addr = git_repo.split('_grading_script')[0]
            this_assignment.save()
        except (MiddlewareError, MWUpdateError):
            this_assignment.delete()
            return JsonResponse(data={"cuase": "Git server error."}, status=500)
        if isinstance(response, Response):
            response.data['ssh_url_to_repo'] = git_repo
            response.content = simplejson.dumps(response.data)
        try:
            for student in this_course.students.all():
                if student.user:
                    MWCourseAddRepoDelay.delay(this_course.uid, this_assignment.uid,
                                    student.enroll_email, str(deadline.date()), owner_uid=simplejson.dumps([str(student.user.uid)]))
        except:
            return JsonResponse(status=500, data={})
        return response

class assignmentDetail(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin):
    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>`
    '''
    serializer_class = AssignmentDetailSerializer
    permission_classes = (assignmentInfoReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        this_course = get_object_or_404(Course, uid=self.kwargs['course_id'])
        return this_course.assignment_set.all()

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(
            queryset, uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        this_course = Course.objects.get(uid=self.kwargs['course_id'])
        this_assignment = Assignment.objects.get(
            uid=self.kwargs['assignment_id'])
        MWCourseDelAssignment(this_course.uid, this_assignment.uid)
        return self.destroy(request, *args, **kwargs)

class courseInstrList(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    '''
     `/course/<str:uid>/instructor/`
    '''
    serializer_class = InstructorBasicInfoSerializer
    permission_classes = (courseInstrInfoReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        this_course = get_object_or_404(Course, uid=self.kwargs['uid'])
        return this_course.instructor.all()

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        this_course = Course.objects.get(uid=self.kwargs['uid'])
        if not request.user.is_authenticated:
            return JsonResponse(data={'cause': 'Unauthorized'}, status=401)
        if not this_course.instructor.filter(user__uid=request.user.uid).exists():
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            enroll_email = request.data['enroll_email']
        except KeyError:
            return JsonResponse(data={'cause': 'Bad Request.'})
        try:
            validate_email(request.data['enroll_email'])
        except ValidationError:
            return JsonResponse(status=400, data={'cause': 'Bad request'})
        try:
            this_instr = Instructor.objects.get(
                enroll_email=request.data['enroll_email'])
        except:
            this_instr = Instructor(
                enroll_email=request.data['enroll_email'], user=None)
            try:
                this_user = User.objects.get(
                    email=request.data['enroll_email'])
                this_instr.user = this_user
            except:
                pass
        this_instr.save()
        this_course.instructor.add(this_instr)
        try:
            MWCourseAddInstr(
                course_uid=self.kwargs['uid'], instr_email=request.data['enroll_email'])
        except:
            MWUpdateUser(request.data['enroll_email'])
            MWCourseAddInstr(
                course_uid=self.kwargs['uid'], instr_email=request.data['enroll_email'])
        return JsonResponse(data={}, status=201)

class courseInstrDetail(generics.GenericAPIView, mixins.RetrieveModelMixin, mixins.DestroyModelMixin):
    '''
    `/course/<str:course_id>/instructor/<str:instr_email>`
    '''
    serializer_class = InstructorBasicInfoSerializer
    permission_classes = (courseInstrInfoReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        this_course = get_object_or_404(Course, uid=self.kwargs['course_id'])
        return this_course.instructor.all()

    def get_object(self):
        obj = get_object_or_404(self.get_queryset(),
                                enroll_email=self.kwargs['instr_email'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        this_course = Course.objects.get(uid=self.kwargs['course_id'])
        if not this_course.instructor.filter(user__uid=request.user.uid).exists():
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            this_instr = this_course.instructor.get(
                enroll_email=self.kwargs['instr_email'])
        except:
            return JsonResponse(data={'cause': 'Not found'}, status=404)
        if this_instr.user:
            if this_instr.user.uid == UUID(this_course.creator):
                return JsonResponse(data={'cause': "You could not delete creator from a course's instructor list."}, status=400)
        this_course.instructor.remove(this_instr)
        return HttpResponse(content='', status=204)

class courseStudentList(generics.GenericAPIView, mixins.ListModelMixin):
    '''
    `/course/<str:course_id>/student/`
    '''
    serializer_class = StudentBasicInfoSerializer
    permission_classes = (
        courseStudentInfoReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(Course, uid=self.kwargs['course_id']).students.all()

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        this_course = Course.objects.get(uid=self.kwargs['course_id'])
        if not this_course.instructor.filter(user__uid=request.user.uid).exists():
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            enroll_email = request.data['enroll_email']
            student_id = request.data['student_id']
        except KeyError:
            return JsonResponse(data={'cause': 'Bad Request.'})
        try:
            validate_email(enroll_email)
        except ValidationError:
            return JsonResponse(status=400, data={'cause': 'invalid email'})
        try:
            this_student = Student.objects.get(
                enroll_email=enroll_email)
        except:
            this_student = Student(
                enroll_email=enroll_email, user=None, student_id=student_id)
            try:
                this_user = User.objects.get(email=enroll_email)
                this_student.user = this_user
            except:
                pass
            this_student.save()
            MWUpdateUser(enroll_email)
        this_course.students.add(this_student)
        if this_student.user:
            for assignment in this_course.assignment_set.all():
                MWCourseAddRepoDelay.delay(self.kwargs['course_id'], assignment.uid, enroll_email,
                                str(assignment.deadline.date()), owner_uid=simplejson.dumps([str(this_student.user.uid)]))
        return JsonResponse(data=StudentBasicInfoSerializer(this_student).data, status=201, safe=False)

class courseStudentDetail(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/course/<str:course_id>/student/<str:student_email>`
    '''

    serializer_class = StudentBasicInfoSerializer
    permission_classes = (
        courseStudentInfoReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(Course, uid=self.kwargs['course_id']).students.all()

    def get_object(self):
        queryset = self.get_queryset()
        obj = get_object_or_404(
            queryset, enroll_email=self.kwargs['student_email'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        this_course = Course.objects.get(uid=self.kwargs['course_id'])
        if not this_course.instructor.filter(user__uid=request.user.uid).exists():
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            this_student = this_course.students.get(
                enroll_email=self.kwargs['student_email'])
        except:
            return JsonResponse(data={'cause': 'Not found'}, status=404)
        this_course.students.remove(this_student)
        if this_student.user:
            for assignment in this_course.assignment_set.all():
                MWCourseDelRepoDelay.delay(this_course.uid, assignment.uid,
                                           this_student.enroll_email)
        return HttpResponse(content='', status=204)

class courseJudgeList(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    '''
    `/course/<str:course_id>/judge/`
    '''
    serializer_class = courseJudgeSerializer
    permission_classes = (courseJudgeReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(Course, uid=self.kwargs['course_id']).default_judge.all()

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        try:
            this_judge = Judge.objects.get(uid=request.data['uid'])
        except:
            return JsonResponse(data={'cause': 'Not Found'}, status=404)
        maintiainer = this_judge.maintainer.user
        if not maintiainer == request.user:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        try:
            this_course = Course.objects.get(uid=self.kwargs['course_id'])
        except:
            return JsonResponse(data={'cause': 'Not Found'}, status=404)
        try:
            this_course.instructor.get(user__uid=request.user.uid)
        except:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        this_course.default_judge.add(this_judge)
        return JsonResponse(JudgeSerializer(this_judge).data, safe=False, status=201)

class courseJudgeDetail(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/course/<str:course_id>/judge/<str:judge_id>`
    '''
    serializer_class = courseJudgeSerializer
    permission_classes = (courseJudgeReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(Course, uid=self.kwargs['course_id']).default_judge.all()

    def get_object(self):
        obj = get_object_or_404(self.get_queryset(),
                                uid=self.kwargs['judge_id'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        try:
            this_course = Course.objects.get(uid=self.kwargs['course_id'])
        except:
            return JsonResponse(data={'cause': 'Not Found'}, status=404)
        try:
            this_course.instructor.get(user__uid=request.user.uid)
        except:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        this_judge = get_object_or_404(
            Judge.objects.all(), uid=self.kwargs['judge_id'])
        this_course.default_judge.remove(this_judge)
        return HttpResponse(content='', status=204)

class assignmentJudgeList(generics.GenericAPIView, mixins.ListModelMixin):
    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>/judge/`
    '''
    serializer_class = courseJudgeSerializer
    permission_classes = (courseJudgeReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(
            Assignment, uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id']).judge.all()

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        try:
            uid = request.data['uid']
        except:
            return JsonResponse(data={'cause': 'missing parameter'}, status=400)

        try:
            this_judge = Judge.objects.get(uid=request.data['uid'])
        except:
            return JsonResponse(data={'cause': 'Not Found'}, status=404)

        try:
            this_assignment = Assignment.objects.get(
                uid=self.kwargs['assignment_id'])
        except:
            return JsonResponse(data={''}, status=404)

        if not this_assignment.course.instructor.filter(user__uid=request.user.uid).exists():
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)

        if (not this_assignment.course.default_judge.filter(uid=this_judge.uid).exists()) and \
                this_judge.maintainer.user != request.user:  # if the judge neither belongs to course nor the person
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)

        this_assignment.judge.add(this_judge)
        this_redis = redis.Redis(connection_pool=redisConnectionPool)
        backend_logger.info(
            'Published redis data to assignment_judge: {}'.format(request.data['uid']))
        this_redis.publish('assignment_judge', request.data['uid'])
        return JsonResponse(JudgeSerializer(this_judge).data, safe=False, status=201)

class assignmentJudgeDetail(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>/judge/<str:judge_id>`
    '''
    serializer_class = courseJudgeSerializer
    permission_classes = (courseJudgeReadWritePermisson, IsAuthenticated)

    def get_queryset(self):
        return get_object_or_404(
            Assignment, uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id']).judge.all()

    def get_object(self):
        obj = get_object_or_404(self.get_queryset(),
                                uid=self.kwargs['judge_id'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        try:
            this_assignment = Assignment.objects.get(
                uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id'])
        except:
            return JsonResponse(data={'cause': 'Not found'}, status=404)
        try:
            this_assignment.course.instructor.get(user__uid=request.user.uid)
        except:
            return JsonResponse(data={'cause': 'Forbidden'}, status=403)
        this_judge = Judge.objects.get(uid=self.kwargs['judge_id'])
        this_assignment.judge.reomve(this_judge)
        backend_logger.info(
            'Published redis data to assignment_judge: {}'.format(request.data['uid']))
        this_redis = redis.Redis(connection_pool=redisConnectionPool)
        this_redis.publish('assignment_judge', request.data['uid'])
        return HttpResponse(content='', status=204)

class submissionHistoryList(generics.GenericAPIView, mixins.ListModelMixin):
    '''
    `/student/<str:student_id>/course/<str:course_id>/assignment/<str:assignment_id>/history/`
    '''
    serializer_class = SubmissionRecordSerializer
    permission_classes = (submissionRecordReadPermission, IsAuthenticated)

    def get_queryset(self):
        this_student = get_object_or_404(
            Student, user__uid=self.kwargs['student_id'])
        this_assignment = get_object_or_404(
            Assignment, uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id'])
        return this_student.record_set.filter(assignment=this_assignment).order_by('-submission_time')

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

class submissionHistoryDetail(generics.GenericAPIView, mixins.RetrieveModelMixin):
    '''
    `/student/<str:student_id>/course/<str:course_id>/assignment/<str:assignment_id>/history/<str:git_commit_id>`
    '''
    serializer_class = SubmissionRecordSerializer
    permission_classes = (submissionRecordReadPermission, IsAuthenticated)

    def get_queryset(self):
        this_student = get_object_or_404(
            Student, uid=self.kwargs['student_id'])
        this_assignment = get_object_or_404(
            Assignment, uid=self.kwargs['assignment_id'], course__uid=self.kwargs['course_id'])
        return this_student.record_set.filter(assignment=this_assignment)

    def get_object(self):
        this_student = self.kwargs['student_id']
        this_assignment = self.kwargs['assignment_id']
        this_record = self.kwargs['git_commit_id']
        queryset = self.get_queryset()
        obj = queryset.get(student__user__uid=this_student,
                           assignment__uid=this_assignment, commit_tag=this_record)
        self.check_object_permissions(obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

class instrJudgeList(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
    '''
    `/judge/`
    '''
    serializer_class = JudgeSerializer
    permission_classes = (judgeReadWritePermission, IsAuthenticated)

    def get_queryset(self):
        this_instr = self.request.user.instructor
        if not this_instr:
            raise PermissionDenied
        return this_instr.judge_set.all()

    def perform_create(self, serializer):
        serializer.save(maintainer=self.request.user.instructor)

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class instrJudgeDetail(generics.GenericAPIView, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.RetrieveModelMixin):
    '''
    `/judge/<str:uid>`
    '''
    serializer_class = JudgeSerializer
    permission_classes = (judgeReadWritePermission, IsAuthenticated)

    def get_object(self):
        obj = get_object_or_404(Judge.objects.all(), uid=self.kwargs['uid'])
        self.check_object_permissions(self.request, obj)
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

class assignmentScoreboardDetail(generics.GenericAPIView):
    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>/scores/`
    '''
    permission_classes = (
        courseStudentInfoReadWritePermission, IsAuthenticated)

    def get(self, request, *args, **kwargs):
        this_course = self.kwargs['course_id']
        this_assignment = self.kwargs['assignment_id']
        this_course_student_list = get_object_or_404(Course, uid=this_course).students.all(
        ).values("id", "user_id", "nickname", "user__name", "student_id")

        BASE = """
        SELECT
            `odu`.`uid`,
            `ods`.`nickname`,
            `odu`.`name`,
            `ods`.`student_id`,
            `odr`.`grade`,
            `odr`.`delta`,
            `odr`.`submission_time`,
            `lastest_records`.`count`
        FROM
            `oj_database_student` `ods`
        INNER JOIN `oj_database_user` `odu` ON `ods`.`user_id` = `odu`.`uid`
        INNER JOIN `oj_database_record_student` `odrs` ON `odrs`.`student_id` = `ods`.`id`
        INNER JOIN `oj_database_record` `odr` ON `odrs`.`record_id` = `odr`.`id`
        INNER JOIN (
            SELECT
                MAX(`odr`.`id`) AS `id`,
                count(*) AS `count`
            FROM
                `oj_database_student` `ods`
            INNER JOIN `oj_database_record_student` `odrs` ON `odrs`.`student_id` = `ods`.`id`
            INNER JOIN `oj_database_record` `odr` ON `odrs`.`record_id` = `odr`.`id`
            WHERE
                `odr`.`assignment_id` = '{assignment_id}'
            AND `odr`.`state` = 2
            GROUP BY
                `ods`.`id`
        ) `lastest_records` ON `lastest_records`.`id` = `odr`.`id`
        WHERE
            `odr`.`assignment_id` = '{assignment_id}'
        ORDER BY
            `grade` DESC,
            `submission_time` ASC,
            `count` ASC;
        """
        SQL = BASE.format(
            assignment_id=this_assignment.replace("-", "")
        )
        with connection.cursor() as cursor:
            cursor.execute(SQL)
            res = cursor.fetchall()

        backend_logger.info('Searching scoreboard for: {}; last_rec: {}'.format(
                this_assignment, str(res)))
        oscore = get_object_or_404(Assignment,uid=this_assignment).grade

        student_with_grade = []
        stu_set=set()
        for i in res:
            stu_set.add(i[0])
            student_with_grade.append({
                'nickname': i[1],
                "name": i[2],
                "student_id": i[3],
                'overall_score': oscore,
                'score': i[4],
                'delta': i[5],
                'submission_time': timezone.make_aware(i[6]),
                'submission_count': i[7]
            })

        for i in this_course_student_list:
            if str(i['user_id']).replace("-","") not in stu_set:
                student_with_grade.append({
                    'nickname': i['nickname'],
                    "name": i["user__name"],
                    "student_id": i["student_id"],
                    'overall_score': oscore,
                    'score': 0,
                    'delta': None,
                    'submission_time': None,
                    'submission_count': 0
                })
        return JsonResponse(student_with_grade, safe=False)

class pendingAssignment(generics.GenericAPIView, mixins.ListModelMixin):
    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>/queue/`
    '''

    def get(self, request, course_id, assignment_id):
        if not request.user.is_authenticated:
            return Response(data={}, status=401)
        this_course = get_object_or_404(Course, uid=course_id)
        if not (this_course.instructor.filter(user__uid=request.user.uid).exists() or this_course.students.filter(user__uid=request.user.uid).exists()):
            return Response(data={}, status=403)
        redis_server = redis.Redis(
            connection_pool=redisConnectionPool)
        all_pending = redis_server.zrange(assignment_id, 0, -1)
        pending_list = []
        for submission in all_pending:
            submission = simplejson.loads(submission)
            display_submission = {}
            display_submission['submission_time'] = submission['receive_time']
            display_submission['submitter'] = ', '.join(Student.objects.get(
                user__uid=submitter).nickname for submitter in submission['owner_uids'])
            pending_list.append(display_submission)
        return JsonResponse(pending_list, status=200, safe=False)

class internalSubmissionInterface(generics.GenericAPIView):
    '''
    `/internal/subbmission/`
    '''

    def post(self, request, *args, **kwargs):
        auth_token = request.META.get("HTTP_AUTHORIZATION", None)
        if auth_token != OJ_SUBMISSION_TOKEN:
            remote = request.META.get(
                'HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR', None))
            backend_logger.error('Submission interface recieved an unauthorized submission. Token: {}; From {}; Payload: {}'.format(
                auth_token, remote, request.data))
            return JsonResponse(status=401, data={'cause': 'Invalid token.'})
        this_submission = simplejson.dumps(request.data)
        this_redis = redis.Redis(connection_pool=redisConnectionPool)
        now = int(time.time())
        try:
            upstream = request.data['upstream']
            try:
                owner_uids = simplejson.loads(
                    request.data['additional_data'])
            except:
                owner_uids = None
            assignment_uid = request.data["assignment_uid"]
        except KeyError:
            return JsonResponse(data={'cause': 'Missing parameter in request'}, status=400)
        if isinstance(owner_uids, str):
            owner_uids = [owner_uids]
        payload = {'upstream': upstream,
                   "owner_uids": owner_uids, 'receive_time': now}
        if upstream.endswith("_grading_script.git"):
            # The upstream stores the grading script.
            payload = simplejson.dumps(payload)
            channel = "grade_script_pushed"
            backend_logger.info('Submission relied. Payload: {}; Channel: {}'.format(
                payload, channel))
            this_redis.publish(channel, payload)
        else:
            # The upstream stores the student's submission.
            R = Record(assignment=Assignment.objects.get(uid=assignment_uid),
                       grade=0,
                       delta=0,
                       grade_time=timezone.make_aware(
                           datetime.fromtimestamp(0)),
                       submission_time=timezone.make_aware(
                           datetime.fromtimestamp(now)),
                       redis_message=simplejson.dumps(payload),
                       state=1)
            R.save()
            stuSet = Student.objects.filter(user__in=owner_uids)
            R.student.add(*stuSet)
            channel = assignment_uid
            payload['record_id'] = R.id
            payload = simplejson.dumps(payload)
            backend_logger.info('Submission relied. Payload: {}; Channel: {}; Weight: {}'.format(
                payload, channel, now))
            this_redis.zadd(channel, {payload: now})
        return Response(data=simplejson.loads(this_submission), status=201)

class OIDCLoginParam(generics.GenericAPIView):
    '''
    `/user/login/oauth/param`

    AND

    `/user/auth/openid/param`
    '''

    def get(self, request, *args, **kwargs):
        host = request.META.get('HTTP_HOST')
        scheme = "https://" if request.is_secure() else "http://"
        return JsonResponse(status=200, data={'login_url': scheme+host+reverse('oidc_auth_request'), 'logout_url': scheme+host+reverse('oidc_end_session')})

class assignmentScoreboardDetail4Student(generics.GenericAPIView):
    '''
    `/student/<str:student_id>/course/<str:course_id>/assignment/<str:assignment_id>/scores/`
    '''

    def get(self, request, *args, **kwargs):
        this_course = self.kwargs['course_id']
        this_assignment = self.kwargs['assignment_id']
        this_course_student_list = get_object_or_404(
            Course, uid=this_course).students.all().values("id", "user_id", "nickname")

        BASE = """
        SELECT
            `odu`.`uid`,
            `ods`.`nickname`,
            `odu`.`name`,
            `ods`.`student_id`,
            `odr`.`grade`,
            `odr`.`delta`,
            `odr`.`submission_time`,
            `lastest_records`.`count`
        FROM
            `oj_database_student` `ods`
        INNER JOIN `oj_database_user` `odu` ON `ods`.`user_id` = `odu`.`uid`
        INNER JOIN `oj_database_record_student` `odrs` ON `odrs`.`student_id` = `ods`.`id`
        INNER JOIN `oj_database_record` `odr` ON `odrs`.`record_id` = `odr`.`id`
        INNER JOIN (
            SELECT
                MAX(`odr`.`id`) AS `id`,
                count(*) AS `count`
            FROM
                `oj_database_student` `ods`
            INNER JOIN `oj_database_record_student` `odrs` ON `odrs`.`student_id` = `ods`.`id`
            INNER JOIN `oj_database_record` `odr` ON `odrs`.`record_id` = `odr`.`id`
            WHERE
                `odr`.`assignment_id` = '{assignment_id}'
            AND `odr`.`state` = 2
            GROUP BY
                `ods`.`id`
        ) `lastest_records` ON `lastest_records`.`id` = `odr`.`id`
        WHERE
            `odr`.`assignment_id` = '{assignment_id}'
        ORDER BY
            `grade` DESC,
            `submission_time` ASC,
            `count` ASC;
        """
        SQL = BASE.format(
            assignment_id=this_assignment.replace("-", "")
        )
        with connection.cursor() as cursor:
            cursor.execute(SQL)
            res = cursor.fetchall()

        backend_logger.info('Searching scoreboard for: {}; last_rec: {}'.format(
                this_assignment, str(res)))
        oscore = get_object_or_404(Assignment,uid=this_assignment).grade

        student_with_grade = []
        stu_set=set()
        for i in res:
            stu_set.add(i[0])
            student_with_grade.append({
                'nickname': i[1],
                'overall_score': oscore,
                'score': i[4],
                'delta': i[5],
                'submission_time': timezone.make_aware(i[6]),
                'submission_count': i[7]
            })

        for i in this_course_student_list:
            if str(i['user_id']).replace("-","") not in stu_set:
                student_with_grade.append({
                    'nickname': i['nickname'],
                    'overall_score': oscore,
                    'score': 0,
                    'delta': None,
                    'submission_time': None,
                    'submission_count': 0
                })
        return JsonResponse(student_with_grade, safe=False)

class assignmentSubmissionExportation(generics.GenericAPIView):

    '''
    `/course/<str:course_id>/assignment/<str:assignment_id>/export`
    '''

    guidance = """ <p>You could you the script for downloading all the students' submission to your local computer.</p>
    <p>Before you start, please meke sure you installed a working git client and make in your local computer. Also, please add your SSH public key to OJ. Then Switch to the directory you want to store the submissions, invoke the script and the download will start automatically.</p>
    """

    # TODO: Add error handling
    download_base = """
    echo "Downloading repo for {} from {}"
    if [ -d {} ]; then
        cd {} && git pull {} && cd ..;
    else
        git clone {};
    fi

    """

    script_header = """#!/bin/bash"""
    script_tail = """ """

    def get(self, request, *args, **kwargs):
        course_id = self.kwargs['course_id']
        assignment_id = self.kwargs['assignment_id']

        if not request.user.is_authenticated:
            return Response(data={}, status=401)
        this_course = get_object_or_404(Course, uid=course_id)
        if not this_course.instructor.filter(user__uid=request.user.uid).exists():
            return Response(data={}, status=403)

        all_students = get_object_or_404(Course, uid=course_id).students.all()
        this_assignment = get_object_or_404(
            Assignment, uid=assignment_id, course__uid=course_id)
        script = self.script_header
        for student in all_students:
            student_repo = "git@oj.geekpie.club:/{}-{}{}/{}/{}.git".format(
                this_course.code,
                this_course.year,
                this_course.semester,
                this_assignment.short_name,
                student.enroll_email.spilt("@")[0]
            )
            student_download_cmd = self.download_base.format(
                student.enroll_email,
                student_repo,
                student.enroll_emal,
                student.enroll_emal,
                student_repo,
                student_repo
            )
            script += student_download_cmd
        script += self.script_tail
        return JsonResponse(
            {
                "guidance": self.guidance,
                "script": script
            },
            safe=False,
            status=200
        )


from PIL import Image

# read in the image
image = Image.open('apple.jpg')

# display the image in its original perspective
image.show()

# flip the image on the vertical axis (mirror)
flip = image.transpose(Image.FLIP_LEFT_RIGHT)
flip.show()

# flip the image on the horizontal axis (upside down)
flip = image.transpose(Image.FLIP_TOP_BOTTOM)
flip.show()


import sys
from pathlib import Path

ROOT = Path(__file__).parent.parent.parent
sys.path.append(ROOT.as_posix())

import cv2
import lpips
import numpy as np
import pyiqa
import torch
from pytorch_msssim import ms_ssim, ssim
from skimage import feature

from src.tampering.utils import numpy2torch

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
cw_ssim = pyiqa.create_metric("cw_ssim", device=device, as_loss=False)

class LpipsLossSingleton:
    _instance = None

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = lpips.LPIPS(net="alex").to(device)
        return cls._instance

def compute_lpips(im1: np.ndarray, im2: np.ndarray):
    lpips_loss = LpipsLossSingleton.get_instance()
    res = (
        lpips_loss(
            numpy2torch(im1).int(),
            numpy2torch(im2).int(),
        )
        .squeeze()
        .detach()
        .cpu()
        .numpy()
    )
    return float(res)

def compute_msssim(im1: np.ndarray, im2: np.ndarray):
    res = ms_ssim(
        numpy2torch(im1), numpy2torch(im2), data_range=255, size_average=False
    )
    res = res.squeeze().detach().cpu().numpy()
    return float(res)

def compute_cwssim(im1: np.ndarray, im2: np.ndarray):
    res = cw_ssim(numpy2torch(im1 / 255), numpy2torch(im2 / 255))
    res = res.squeeze().detach().cpu().numpy()
    return float(res)

def compute_ssim(im1: np.ndarray, im2: np.ndarray):
    res = ssim(numpy2torch(im1), numpy2torch(im2), data_range=255, size_average=False)
    res = res.squeeze().detach().cpu().numpy()
    return float(res)

def compute_hog(im1: np.ndarray, im2: np.ndarray):
    im1 = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY).astype(np.uint8)
    im2 = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY).astype(np.uint8)

    # Define the parameters for HOG
    orientations = 9
    pixels_per_cell = (8, 8)
    cells_per_block = (2, 2)

    # Compute HOG features
    hog_features1 = feature.hog(
        im1,
        orientations=orientations,
        pixels_per_cell=pixels_per_cell,
        cells_per_block=cells_per_block,
        transform_sqrt=True,
        block_norm="L1",
    )

    hog_features2 = feature.hog(
        im2,
        orientations=orientations,
        pixels_per_cell=pixels_per_cell,
        cells_per_block=cells_per_block,
        transform_sqrt=True,
        block_norm="L1",
    )

    res = np.linalg.norm(hog_features1 - hog_features2)
    return res

def compute_mse(im1: np.ndarray, im2: np.ndarray):
    return np.mean((im1 / 255 - im2 / 255) ** 2)

def compute_mae(im1: np.ndarray, im2: np.ndarray):
    return np.mean(np.abs(im1 / 255 - im2 / 255))

def compute_sift(im1: np.ndarray, im2: np.ndarray):
    im1 = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY).astype(np.uint8)
    im2 = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY).astype(np.uint8)

    # Initialize SIFT detector
    sift = cv2.xfeatures2d.SIFT_create()

    # Detect keypoints and compute descriptors for both images
    keypoints1, descriptors1 = sift.detectAndCompute(im1, None)
    keypoints2, descriptors2 = sift.detectAndCompute(im2, None)

    # Create a brute-force matcher
    bf = cv2.BFMatcher()

    try:
        # Match the descriptors
        matches = bf.match(descriptors1, descriptors2)

        # Sort the matches by distance
        matches = sorted(matches, key=lambda x: x.distance)

        # Compute the similarity score as the average distance of the matches
        similarity_score = sum([match.distance for match in matches]) / len(matches)
    except:
        similarity_score = 0

    return similarity_score


#!/usr/bin/python3

import os
import sys
import requests
import msgpackrpc
import hashlib
import boto3
import time
import subprocess
import socket

def hash(str):
        print('HASH')
        return int(hashlib.md5(str.encode()).hexdigest(), 16) & ((1 << 32) - 1)

# get instances' id from suto-scaling group
autoscaling_client = boto3.client('autoscaling', region_name='eu-central-1')
response = autoscaling_client.describe_auto_scaling_groups(
        AutoScalingGroupNames=[
        'fuhming1468',
        'fuhming'
    ]
)
instances = response['AutoScalingGroups'][0]['Instances']
size = len(instances)

print(f'group size : {size}')
instance_ids = [i['InstanceId'] for i in instances]
print(instance_ids)

# get instances' ip
instance_ips = []
ec2_client = boto3.client('ec2', region_name='eu-central-1')
for i in instances:
    ip = ec2_client.describe_instances(
        InstanceIds = [
            i["InstanceId"]
        ]
    )['Reservations'][0]['Instances'][0]['PublicIpAddress']
    instance_ips.append(ip)

size = len(instance_ips)
print(f'group size : {size}')
print(instance_ips)


import json
import urllib.request, urllib.parse, urllib.error
from urllib.request import urlopen
import ssl

# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

# extracting & treating data from url
url = input('Enter-')
java = urllib.request.urlopen(url,context=ctx)
data = java.read().decode()

# creating dictionary by using json
js = json.loads(data)

# extracting & creating a list x from js
x = js['comments']

# extracting dictionary items embedded in a list
new_list = [i["count"] for i in x]

# adding the numbers
print("Sum:",sum(new_list))


import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

from sklearn import tree
from sklearn.metrics import confusion_matrix, classification_report

pd.set_option('max_columns', None)
pd.options.display.width = None
data = sns.load_dataset('titanic')

# ******************************************* section 01 - Logistic regression
data = data.drop(['who', 'adult_male', 'embark_town', 'alive', 'class', 'alone'], axis='columns')
X = data.drop(['survived'], axis='columns')
y = data['survived']

# cleaning data
numeric_features = ["age", "fare"]
numeric_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="median")),
                                      ("scaler", StandardScaler())])

categorical_features = ["embarked", "sex", "deck"]
categorical_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="constant")),
                                          ("ohe", OneHotEncoder(handle_unknown="ignore"))])

preprocessor = ColumnTransformer(transformers=[('num', numeric_transformer, numeric_features),
                                               ("cat", categorical_transformer, categorical_features)])

x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

# training
clf = Pipeline(steps=[("preprocessor", preprocessor),
                      ("classifier", LogisticRegression())])
fit_model = clf.fit(x_train, y_train)
score = clf.score(x_test, y_test)
y_pred = clf.predict(x_test)

# print('score:', score)
# print('mean squared error:', mean_squared_error(y_test, y_pred))
# print('r2 score:', r2_score(y_test, y_pred))

# ******************************************************* section 02 - tiping
sns.set_theme()
tips = sns.load_dataset('tips')
tips['ratio'] = tips['tip'] / tips['total_bill']
mean = tips.groupby('sex')['ratio'].mean()

sns.lmplot(data=tips, x="total_bill", y="ratio", hue='sex')
sns.relplot(data=tips, x="total_bill", y="ratio", hue='sex')
plt.axhline(mean['Male'], 0, 50)
plt.axhline(mean['Female'], 0, 50, color='orange')
plt.show()

# ************************************************ section 03 - Decision tree
data = sns.load_dataset('titanic')
data_2 = data.copy()
# cleaning data
data = data.drop(['who', 'adult_male', 'embark_town', 'alive', 'class', 'alone'], axis='columns')
print(data)
data = pd.concat([data, pd.get_dummies(data["sex"]),
                  pd.get_dummies(data["embarked"]),
                  pd.get_dummies(data["deck"])], axis=1)
data = data.drop(['sex', 'embarked', 'deck'], axis='columns')
data = data.fillna(method='bfill')
print(data)
x = data.drop(['survived'], axis='columns')
y = data['survived']

# training
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.20, random_state=42)
clf = tree.DecisionTreeClassifier().fit(x_train, y_train)
fig, axes = plt.subplots(dpi=300)
tree.plot_tree(clf, feature_names=list(data),
               class_names=["survived", "died"],
               filled=True)

print(classification_report(y_test, clf.predict(x_test)))
# ********************** another aproach
x = data_2.drop(['survived'], axis='columns')
y = data_2['survived']

numeric_features = ["age", "fare"]
numeric_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="mean")),
                                      ("scaler", StandardScaler())])

categorical_features = ["embarked", "sex", "deck"]
categorical_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="constant")),
                                          ("ohe", OneHotEncoder(handle_unknown="ignore"))])

preprocessor = ColumnTransformer(transformers=[('num', numeric_transformer, numeric_features),
                                               ("cat", categorical_transformer, categorical_features)])
# training
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.20, random_state=42)
clf = Pipeline(steps=[("preprocessor", preprocessor),
                      ("classifier", tree.DecisionTreeClassifier())])
clf.fit(x_train, y_train)
print(classification_report(y_test, clf.predict(x_test)))