<repo_name>Regoradin/Seminar<file_sep>/placement.py
import random, sqlite3

class Seminar:
    def __init__(self, id, capacity, session, no_random):
        self.id = id
        self.capacity = capacity
        self.students = []
        self.session = session
        self.no_random = no_random

    def AddStudent(self, student, keep_capacity = True):
        self.students.append(student)

        if keep_capacity:
            self.RemoveStudents()

    def RemoveStudents(self):
        while len(self.students) > self.capacity:
            min_benefit = 100
            min_student = None
            for student in self.students:
                if self.session == 1:
                    rankings = student.first_rankings
                if self.session == 2:
                    rankings = student.second_rankings
                for i in range(0,len(rankings)):
                    if rankings[i][0] == self:
                        #benefit is calculated as (the weight assigned to this seminar - the next best seminar)
                        found_next_best = False
                        #Loops to the next highest ranked seminar with open seats
                        for j in range(i,len(rankings)):
                            next_best_seminar = rankings[j][0]
                            if next_best_seminar.capacity > len(next_best_seminar.students):
                                benefit = rankings[i][1] - rankings[j][1]
                                found_next_best = True
                        #If that doesn't exist, benefit is just the benefit of being in the current seminar
                        if not found_next_best:
                            benefit = rankings[i][1]
                        #Minor bias towards upperclassmen here
                        if benefit < min_benefit or (benefit == min_benefit and student.grade < min_student.grade):
                            min_benefit = benefit
                            min_student = student
                        break
                    #only gets to here if this seminar isn't even on their list, in which case it's impossible to get benefit
                    min_student = student
                    min_benefit = 0
                    
            #Kicks the student out, and moves them to their highest ranked seminar with open seats
            self.students.remove(min_student)
            placed = False
            if self.session == 1:
                rankings = min_student.first_rankings
            if self.session == 2:
                rankings = min_student.second_rankings
            if self.session == 3:
                rankings = min_student.double_rankings

            for ranking in rankings:
                if ranking[0].capacity > len(ranking[0].students):
                    ranking[0].AddStudent(min_student)
                    placed = True
            if not placed:
                if self.session == 1:
                    PlaceRandomly(all_first_seminars, student)
                if self.session == 2:
                    PlaceRandomly(all_second_seminars, student)
                if self.session == 3:
                    min_student.first_rankings[0][0].AddStudent(student)
                    min_student.second_rankings[0][0].AddStudent(student)

        return
            
    def PrintStudents(self):
        print("Students in seminar " + str(self.id))
        for student in self.students:
            print(student.id)


class Student:
    def __init__(self, id, grade):
        self.id = id
        self.first_rankings = []
        self.second_rankings = []
        self.double_rankings = []
        self.grade = grade

    def AddRanking(self, sem, ranking):
        if sem.session == 1:
            rankings = self.first_rankings
        if sem.session == 2:
            rankings = self.second_rankings
        if sem.session == 3:
            rankings = self.double_rankings

        #places the new ranking in the appropriate list in order
        if len(rankings) == 0:
            rankings.append((sem, ranking))
        else:
            for i in range(0, len(self.rankings)):
                if rankings[i][1] < ranking:
                    rankings.insert(i, (sem, ranking))
        
def PlaceRandomly(seminars, student):
    seminar = seminars.values()[random.randint(0, len(all_seminars.values())-1)]
    while seminar.no_random == True:
        seminar = seminars.values()[random.randint(0, len(all_seminars.values())-1)]
    seminar.AddStudent(student)
                    
def SortStudents(students, seminars, unranked_students):
    total_students = len(students) + len(unranked_students)
    seminar_slots = 0
    for seminar in seminars:
        seminar_slots += seminar.capacity
    if (seminar_slots/2) < total_students:
        #there is a slight chance that this will fire even if there are enough spots because double period seminars should count double.
        print("\x1b[1;31;40mThere are more students than their are available seminars!\x1b[0m")
        
    #Adds all students into their first choice seminar
    for student in students:
        if len(student.double_rankings) != 0:
            student.double_rankings[0][0].AddStudent(student, False)
        else:
            if len(student.first_rankings) != 0:
                student.first_rankings[0][0].AddStudent(student, False)
            else:
                PlaceRandomly(all_first_seminars, student)
            if len(student.second_rankings) != 0:
                student.second_rankings[0][0].AddStudent(student, False)
            else:
                PlaceRandomly(all_second_seminars, student)

    #Places students who did not make a selection into a random seminar
    for student in unranked_students:
        PlaceRandomly(all_first_seminars, student)
        PlaceRandomly(all_second_seminars, student)

    for seminar in seminars:
        seminar.RemoveStudents()
    #All seminars should now be at or under capacity and students should be properly sorted
    conn.execute('''DROP TABLE if exists assignments''')
    conn.execute('''CREATE TABLE assignments(
                 id INTEGER PRIMARY KEY,
                 sems_id INTEGER NOT NULL,
                 student_id INTEGER NOT NULL,
                 FOREIGN KEY (sems_id) REFERENCES seminar_semester(id),
                 FOREIGN KEY (student_id) REFERENCES students(id))''')

    for seminar in seminars:
        for student in seminar.students:
            c.execute('''INSERT INTO assignments (sems_id, student_id) VALUES (?, ?)''',(seminar.id, student.id))

    conn.commit()


conn = sqlite3.connect('seminars.db')
c = conn.cursor()

#Builds seminar items
all_first_seminars = {}
all_second_seminars = {}
all_double_seminars = {}
c.execute('''SELECT sems.id, semi.capacity, sems.session, semi.sign_up, semi.no_random  FROM seminar_semester sems
           INNER JOIN seminars semi ON semi.id = sems.seminar_id
           INNER JOIN semesters seme ON seme.id = sems.semester_id WHERE seme.is_current = 1''')
results = c.fetchall()
for result in results:
    if result[3] == 1 or result[4] == 1:
        no_random = True
    new_seminar = Seminar(result[0], result[1], result[2], no_random)
    if int(result[2]) == 1:
        all_first_seminars[result[0]] = new_seminar
    if int(result[2]) == 2:
        all_second_seminars[result[0]] = new_seminar
    if int(result[2]) == 3:
        all_double_seminars[result[0]] = new_seminar

all_seminars = all_first_seminars
all_seminars.update(all_second_seminars)
all_seminars.update(all_double_seminars)
#Builds student items
all_ranked_students = []
created_ids = []
c.execute('''SELECT choices.student_id, choices.rank, choices.sems_id, students.grade FROM student_choices choices
          INNER JOIN students students ON choices.student_id = students.id''')
results = c.fetchall()
for result in results:
    #matches sems_id to seminar object
    seminar = all_seminars[result[2]]
    
    if result[0] not in created_ids:
        student = Student(result[0], int(result[3]))
        all_ranked_students.append(student)
        created_ids.append(result[0])
        student.AddRanking(seminar, result[1])
    else:
        for student in all_ranked_students:
            if student.id == result[0]:
                student.AddRanking(seminar, result[1])
                break

#creating students who did not put a ranking
all_unranked_students = []
c.execute('''SELECT id,grade FROM students WHERE id NOT IN (SELECT student_id FROM student_choices)''')
unranked_students = c.fetchall()
for student in unranked_students:
    new_student = Student(student[0], int(student[1]))
    all_unranked_students.append(new_student)
          
SortStudents(all_ranked_students, all_seminars.values(), all_unranked_students)

# sem1 = Seminar(1, 0)
# sem2 = Seminar(2, 1)
# sem3 = Seminar(3, 2)

# stud1 = Student(1, [(sem2, 10), (sem1, 4)])
# stud2 = Student(2, [(sem2, 10), (sem1, 6), (sem3, 2)])

# all_seminars = [sem1, sem2, sem3]

# sem2.AddStudent(stud1)
# sem2.AddStudent(stud2)

# sem1.PrintStudents()
# sem2.PrintStudents()
# sem3.PrintStudents()
<file_sep>/js/scripts.js
function AddTeacher(teachers, selected_teacher = false){
    
    var div  = document.getElementById("teacher_select");
    var select = document.createElement("select");
    select.name = "teacher"
    div.appendChild(select);
    
    for (var i in teachers){
	var option = document.createElement("option");
	
	option.id = teachers[i][0];
	option.value = teachers[i][0];
	option.text = teachers[i][1];
	if(selected_teacher == teachers[i][0]){
	    option.selected = true;
	}
	select.appendChild(option);
    }
	
}
function RemoveTeacher(teacher_id){
    var div = document.getElementById("teacher_remove");
    var remove = document.createElement("button");
    div.appendChild(remove);

    remove.onclick = function(){RemoveElement(teacher_id);};
    remove.innerHTML = "Remove";
}

function RemoveElement(id){
    console.log("Removing " + id);
    var elem = document.getElementById(id);
    elem.parentNode.removeChild(elem);
}
<file_sep>/tutorial.py
from bottle import route, run, template, static_file, error, response, redirect, request, template

@route('/hello')
def hello_again():
    if request.get_cookie("visited"):
        return "Welcome back! Nice to see you again"
    else:
        response.set_cookie("visited", "yes")
        return "Hello there! Nice to meet you"

@route('/')
@route('/hello/<name>/<i:int>')
def greet(i = 1, name = 'Stranger'):
    response.set_header("Content-language", "en")
    
    return (template('Hello {{name}}, how are you?\n', name = name)) * i
        
@route('/static/<filename>')
def server_static(filename):
    return static_file(filename, root = './static')

@error(404)
def error(error):
    return 'Error! Alert! Everything is breaking!'

@route('/wrong')
def wrong():
    if request.get_cookie("wronged"):
       return "you have wronged twice. no redirect for you."
    response.set_cookie("wronged", "yes")
    redirect("/hello/errorer/2")

@route('/login')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="<PASSWORD>" type="<PASSWORD>" />
            <input value="Login" type = "submit" />
        </form>
    '''

@route("/login", method="POST")
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('<PASSWORD>')
    return(str(username) + " " + str(password))

@route("/template")
def hello():
    return template("hello_template", name = "world")
    
run(host='localhost', port=8080, debug = True)

<file_sep>/seminar.py
import sqlite3, json
from bottle import route, run, debug, template, request, static_file,redirect


conn = sqlite3.connect('seminars.db')
c = conn.cursor()

#seminars table creation
conn.execute('''CREATE TABLE IF NOT EXISTS seminars (
            id INTEGER PRIMARY KEY,
            title TEXT NOT NULL,
            description TEXT NOT NULL,
            first_day_note TEXT NOT NULL,
            capacity INTEGER NOT NULL,
            cost INTEGER NOT NULL,
            sign_up INT NOT NULL DEFAULT 0 CHECK (sign_up IN (0, 1)),
            no_random INT NOT NULL DEFAULT 0 CHECK(no_random IN (0, 1)))''')
            
#semesters table creation
conn.execute('''CREATE TABLE IF NOT EXISTS semesters (
             id INTEGER PRIMARY KEY,
             name TEXT NOT NULL,
             is_current INTEGER NOT NULL CHECK(is_current IN (0,1)))''')

#room table creation
conn.execute('''CREATE TABLE IF NOT EXISTS rooms (
             id INTEGER PRIMARY KEY,
             name TEXT NOT NULL)''')

#seminar_semester table creation
conn.execute('''CREATE TABLE IF NOT EXISTS seminar_semester (
            id INTEGER PRIMARY KEY,
            seminar_id INTEGER NOT NULL,
            semester_id INTEGER NOT NULL,
            session INTEGER NOT NULL,
            room_id INTEGER NOT NULL,
            FOREIGN KEY (semester_id) REFERENCES semesters(id),
            FOREIGN KEY(seminar_id) REFERENCES seminars(id),
            FOREIGN KEY (room_id) REFERENCES rooms(id),
            CHECK (session in (1, 2, 3)),
            UNIQUE (semester_id, room_id, session))''')

#teachers table creation
conn.execute('''CREATE TABLE IF NOT EXISTS teachers (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL)''')

#teacher_sems table creation
conn.execute('''CREATE TABlE IF NOT EXISTS teacher_sems (
            id INTEGER PRIMARY KEY,
            teacher_id INTEGER NOT NULL,
            sems_id INTEGER NOT NULL,
            is_primary INTEGER NOT NULL CHECK(is_primary IN (0,1)),
            FOREIGN KEY (teacher_id) REFERENCES teachers(id),
            FOREIGN KEY(sems_id) REFERENCES semester_seminar(id))''')

#student table creation
conn.execute('''CREATE TABLE IF NOT EXISTS students (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            grade INT NOT NULL CHECK(grade IN (1, 2, 3, 4)))''')

#student_choices table creation
conn.execute('''CREATE TABLE IF NOT EXISTS student_choices (
             id INTEGER PRIMARY KEY,
             student_id INTEGER NOT NULL,
             sems_id INTEGER NOT NULL,
             rank INTEGER NOT NULL,
             FOREIGN KEY (student_id) REFERENCES students(id),
             FOREIGN KEY (sems_id) REFERENCES seminar_semester(id))''')

#Semester system will remain janky for now
# c.execute("INSERT INTO semesters (name, is_current) VALUES ('Fall 2017', 0)")
# c.execute("INSERT INTO semesters (name, is_current) VALUES ('Spring 2018', 1)")
# c.execute('INSERT INTO teachers (name) VALUES ("Hyman"), ("Catlin"), ("Cristiano"), ("Tolias"), ("Person");')
# c.execute('INSERT INTO rooms (name) VALUES ("101"), ("102"), ("103"), ("104"), ("105"), ("106"), ("107"), ("108"), ("109"), ("110"), ("111");')
# conn.commit()


def CheckboxToInt(input):
    if input != None:
        return 1
    else:
        return 0

@route('/js/<filename:path>')
def send_js(filename):
    return static_file(filename, root='js')
@route('/css/<filename:path>')
def send_css(filename):
    return static_file(filename, root='css')

#TEACHER SIDE

@route('/teacher')
def teacher_home():
    return template('templates/teacher_home.tpl')

@route('/teacher/add', method="GET")
def add_page():
    c.execute("SELECT id, name FROM teachers")
    teachers = json.dumps(c.fetchall())
    #This will select all rooms that do not have any seminars in them this semester.
    #c.execute('''SELECT id, name FROM rooms WHERE id NOT IN(
    #             SELECT room_id FROM seminar_semester semx
    #             INNER JOIN semesters seme ON semx.semester_id = seme.id
    #             WHERE is_current = 1)''')
    c.execute('''SELECT id, name FROM rooms''')
    rooms = json.dumps(c.fetchall())
        
    return template('templates/add_seminar.tpl', teachers=teachers, rooms=rooms)

@route('/teacher/add', method="POST")
def add_page():
    title = request.forms.get('title')
    description = request.forms.get('description')
    teachers = request.forms.getall('teacher')
    first_day_note = request.forms.get('first_day_note')
    capacity = request.forms.get('capacity')
    cost = request.forms.get('cost')
    sign_up = CheckboxToInt(request.forms.get('sign_up'))
    no_random = CheckboxToInt(request.forms.get('no_random'))
    session = request.forms.get('session')
    room_id = request.forms.get('room_id')

    
    c.execute("INSERT INTO seminars (title, description, first_day_note, capacity, cost, sign_up, no_random) VALUES (?, ?, ?, ?, ?, ?, ?)",(title, description, first_day_note, capacity, cost, sign_up, no_random))

    seminar_id = c.lastrowid
    c.execute("SELECT id FROM semesters WHERE is_current = 1")
    semester_id = c.fetchone()[0]
    c.execute("INSERT INTO seminar_semester (seminar_id, semester_id, session, room_id) VALUES (?,?,?, ?)", (seminar_id, semester_id, session, room_id))
    sems_id = c.lastrowid

    for teacher in teachers:
        c.execute("INSERT INTO teacher_sems (teacher_id, sems_id, is_primary) VALUES (?,?, 1)", (teacher, sems_id))
        
    conn.commit()
        
    redirect('/teacher')

@route('/teacher/add_old', method = "GET")
def add_old():
    #selects seminars that were offered in previous semester but are NOT offered this semester
    c.execute('''SELECT semi.id, semi.title, semi.description FROM seminars semi
    INNER JOIN seminar_semester sems ON sems.seminar_id = semi.id
    INNER JOIN semesters seme ON sems.semester_id = seme.id AND seme.is_current = 0
    WHERE semi.id NOT IN(
    SELECT semi.id FROM seminars semi
    INNER JOIN seminar_semester sems ON sems.seminar_id = semi.id
    INNER JOIN semesters seme ON sems.semester_id = seme.id AND seme.is_current = 1)''')
    old_seminars = json.dumps(c.fetchall())

    #This will select all rooms without any seminars in them this semester.
    #c.execute('''SELECT id, name FROM rooms WHERE id NOT IN(
    #             SELECT room_id FROM seminar_semester semx
    #             INNER JOIN semesters seme ON semx.semester_id = seme.id
    #             WHERE is_current = 1)''')
    c.execute('''SELECT id, name FROM rooms''')
    rooms = json.dumps(c.fetchall())
    
    return template('templates/add_old_seminar.tpl', old_seminars=old_seminars, rooms = rooms)
@route('/teacher/add_old', method = "POST")
def add_old_save():
    sem_id = request.forms.get('sem_id')
    session = request.forms.get('session')
    room_id = request.forms.get('room_id')

    c.execute("SELECT id FROM semesters WHERE is_current = 1")
    semester_id = c.fetchone()[0]
    
    c.execute("INSERT INTO seminar_semester (seminar_id, semester_id, session, room_id) VALUES (?, ?, ?, ?)", (sem_id, semester_id, session, room_id))
    conn.commit()
    print("Adding old")
    redirect("/teacher/add_old")

@route('/teacher/edit/select', method="GET")
def edit_select():
    #Edit select page: picks a seminar to edit from the seminar table that is linked to the currently active semester
    c.execute('''SELECT sems.id,  semi.title FROM seminar_semester sems
    INNER JOIN seminars semi ON sems.seminar_id = semi.id
    INNER JOIN semesters seme ON sems.semester_id = seme.id WHERE seme.is_current =1''')
        
    results = json.dumps(c.fetchall())

    return template('templates/edit_select.tpl', results = results)

@route('/teacher/edit/seminar', method = "POST")
def edit():
    
    #Actual editing page
    sems_id = request.forms.get('sems_id')
    print("SEMS ID: %s" %sems_id)
    #This gets unpacked inside edit_seminar.tpl    
    c.execute('SELECT id, title, description, first_day_note, capacity, cost, sign_up, no_random FROM seminars WHERE id IN (SELECT seminar_id FROM seminar_semester WHERE id = ?)', (sems_id,))
    seminar = c.fetchone()

    c.execute('SELECT room_id, session FROM seminar_semester WHERE id = ?', (sems_id,))
    result = c.fetchone()
    room_id = result[0]
    session = result[1]
    #This will select only rooms that have no seminars in them at all this semester.
    #c.execute('''SELECT id, name FROM rooms WHERE (id = ?) OR (id NOT IN(
    #             SELECT room_id FROM seminar_semester semx
    #             INNER JOIN semesters seme ON semx.semester_id = seme.id
    #             WHERE is_current = 1))''', (room_id,))
    c.execute('''SELECT id, name FROM rooms''')
    all_rooms = json.dumps(c.fetchall())
    
    c.execute("SELECT id, name FROM teachers")
    teachers = json.dumps(c.fetchall())

    c.execute("SELECT teacher_id, name FROM teacher_sems INNER JOIN teachers ON teacher_sems.teacher_id = teachers.id WHERE sems_id = ?", (sems_id,))
    selected_teachers = json.dumps(c.fetchall())
        
    return template('templates/edit_seminar.tpl', seminar = seminar, teachers=teachers, sems_id = sems_id, selected_teachers = selected_teachers, room_id = room_id, all_rooms = all_rooms, session = session)

@route('/teacher/edit/save', method="POST")
def edit_save():
    #Saves the edits to the seminars table
    sem_id = request.forms.get('sem_id')
    title = request.forms.get('title')
    description = request.forms.get('description')
    first_day_note = request.forms.get('first_day_note')
    capacity = request.forms.get('capacity')
    cost = request.forms.get('cost')
    sign_up = CheckboxToInt(request.forms.get('sign_up'))
    no_random = CheckboxToInt(request.forms.get('no_random'))
    session = request.forms.get('session')
    room = request.forms.get('room')

    print("SIGN UP: %s" %sign_up)
    print("NO_RAND: %s" %no_random)
    
    c.execute('UPDATE seminars SET title = ?, description = ?, capacity = ?, cost = ?, sign_up = ?, no_random = ? WHERE id = ?', (title, description, capacity, cost, sign_up, no_random, sem_id))

    #Resets links in the teacher_sems table
    sems_id = request.forms.get('sems_id')
    
    c.execute("DELETE FROM teacher_sems WHERE sems_id = ?", (sems_id))
    added_teachers = []
    for teacher in request.forms.getall('teacher'):
        if teacher not in added_teachers:
            added_teachers.append(teacher)
            c.execute("INSERT INTO teacher_sems (teacher_id, sems_id, is_primary) VALUES (?, ?, 0)", (teacher, sems_id))

    c.execute('UPDATE seminar_semester SET session = ?, room_id = ? WHERE id = ?', (session, room, sems_id))
            
    conn.commit()

        
    redirect("/teacher/edit/select", code=303)

        
@route('/teacher/remove', method="GET")
def remove():
    c.execute('''SELECT sems.id,  semi.title FROM seminar_semester sems
        INNER JOIN seminars semi ON sems.seminar_id = semi.id
        INNER JOIN semesters seme ON sems.semester_id = seme.id WHERE seme.is_current =1''')

    seminars = json.dumps(c.fetchall())
    
    return template('templates/remove_seminar.tpl', seminars = seminars)
@route('/teacher/remove', method="POST")
def remove_submit():
    for sems_id in request.forms.getall("removed"):
        c.execute("DELETE FROM seminars WHERE id = (SELECT seminar_id FROM seminar_semester WHERE ID = ?)",(sems_id))
        c.execute("DELETE FROM seminar_semester WHERE id = ?",(sems_id))
        
    conn.commit()
    redirect("/teacher")

#STUDENT SIDE

@route('/student', method="GET")
def student():

    c.execute('''SELECT sems.id,  semi.title, semi.description, sems.session FROM seminar_semester sems
        INNER JOIN seminars semi ON sems.seminar_id = semi.id
        INNER JOIN semesters seme ON sems.semester_id = seme.id WHERE seme.is_current =1 and semi.sign_up = 0''')
    seminars = c.fetchall()

    first_seminars = []
    second_seminars = []
    double_seminars = []
    for seminar in seminars:
        if seminar[3] == 1:
            first_seminars.append(seminar)
        if seminar[3] == 2:
            second_seminars.append(seminar)
        if seminar[3] == 3:
            double_seminars.append(seminar)
    
    return template('templates/student_home.tpl', first_seminars = json.dumps(first_seminars), second_seminars = json.dumps(second_seminars), double_seminars = json.dumps(double_seminars))

@route('/student/submit', method="POST")
def submit():
    student_id = request.forms.get("student_id")
#    chosen_seminars = request.forms.getall("chosen_seminars")
    for key, value in request.forms.items():
        if key.startswith('seminar_'):
            x, seminar_id = key.split("_")
            if value != "0":
                c.execute("INSERT INTO student_choices (student_id, sems_id, rank) VALUES (?, ?, ?)", (student_id, seminar_id, value))

    conn.commit()
    return "Seminars chosen!"

run(debug = True, reloader = True)
#because for some reason the reloader doesn't work on my laptop because everything is terrible.
#run(debug =True)
