Пример #1
0
def updatePassword():
    # Takes in a json of the form {email : '', password : ''}

    # Validate that the user calling this has access
    # Either that they are the same user or that they are an admin
    if request.json is None:
        abort(400)

    for x in ['email', 'password']:
        if x not in request.json:
            abort(400)

    emailSess = mailsane.normalize(session['email'])
    if emailSess.error:
        abort(400)

    email = mailsane.normalize(request.json['email'])
    if email.error:
        abort(400)

    if dbworker.validateAccess(dbworker.userTypeMap['admin']):
        pass
    else:
        abort(401)

    if dbworker.getUser(str(email)) is None:
        abort(404)

    dbworker.setPassword(str(email), request.json['password'])
    return jsonify({'success': True})
Пример #2
0
def createUser():
    """
    Takes in a JSON of the structure
    {
    "email": "*****@*****.**",
    "password": "******",
    "userType": 1,
    "firstName": "Test",
    "lastName": "Admin",
    "phoneNumber": "555-555-5555",
    "birthday": "YYYY-MM-DD",
    "parentEmail" : "",
    "parentName" : ""
    }


    Returns {'success' : Boolean}
    """
    if not dbworker.validateAccess(dbworker.userTypeMap['admin']):
        abort(403)

    if request.json is None:
        abort(400)

    for x in [
            'email', 'password', 'userType', 'firstName', 'lastName',
            'phoneNumber', 'birthday', 'parentEmail', 'parentName'
    ]:
        if x not in request.json:
            abort(400)

    email = mailsane.normalize(request.json['email'])
    if email.error:
        abort(400)

    # Verify no duplicate email here or in the dbworker method
    # likely better to do it there

    parentEmail = mailsane.normalize(request.json['parentEmail'])
    if parentEmail.error:
        abort(400)

    try:
        validate(instance=request.json, schema=SchemaFactory.create_user)
    except exceptions.ValidationError:
        abort(400)

    if dbworker.getUser(str(email)) is not None:
        abort(400)

    dbworker.createUser(
        str(email), str(parentEmail), request.json['firstName'],
        request.json['lastName'], request.json['password'],
        request.json['userType'], request.json['phoneNumber'],
        datetime.datetime.strptime(request.json['birthday'],
                                   '%Y-%m-%d'), request.json['parentName'])

    return jsonify({'success': True})
Пример #3
0
def getStudentDashboardInfo():
    if 'email' not in session or session['email'] is None:
        abort(401)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    studentDashboardDict = {}
    classes = dbworker.getClasses(str(email), filt={'ongoing': True})
    thisStudent = dbworker.getCurrentUser()

    studentDashboardDict['firstName'] = thisStudent['firstName'][:]
    studentDashboardDict['lastName'] = thisStudent['lastName'][:]
    studentDashboardDict['Classes'] = []
    studentDashboardDict[
        'Classes'] = studentDashboardDict['Classes'] + classes['student']

    classReports = dbworker.mclient[dbworker.database]['reports']

    for c in studentDashboardDict['Classes']:
        foundClass = False
        r = 0
        while not foundClass and r < classReports.size():
            if classReports[r]['classId'] == c['id']:
                foundClass = True
            else:
                r += 1
        if foundClass:
            c['nextCourse'] = classReports[r]['nextCourse']
            c['marks'] = classReports[r]['marks']

    return jsonify(studentDashboardDict)
Пример #4
0
def updateReport():
    """
    Takes in a json of the form {'classId' : '123', 'email' : student_email, 'mark' : 90.00, 'comment' : "Great!"}

    Returns a "success" json
    """

    if request.json is None:
        abort(400)

    try:
        validate(instance=request.json, schema=SchemaFactory.report_update)
    except exceptions.ValidationError:
        abort(400)

    if not dbworker.validateAccessList(
        [dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor']]):
        abort(403)

    studentEmail = mailsane.normalize(request.json['email'])

    if studentEmail.error:
        abort(400)
    convClassId = ObjectId(request.json['classId'])
    dbworker.updateReport(
        convClassId,
        str(studentEmail),
        mark={} if 'mark' not in request.json else request.json['mark'],
        comments=''
        if 'comments' not in request.json else request.json['comments'],
        nextCourse=''
        if 'nextCourse' not in request.json else request.json['nextCourse'])

    return jsonify({'success': True})
Пример #5
0
def getUserClasses(email):
    if not dbworker.validateAccessList([
            dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor'],
            dbworker.userTypeMap['student']
    ]):
        abort(403)

    email = mailsane.normalize(email)
    if email.error:
        abort(400)

    classes = {'instructor': [], 'student': []}
    for i in dbworker.mclient[dbworker.database]['classes'].find(
        {'instructors': str(email)}):
        tmp_id = i['_id']
        classes['instructor'].append({
            "id": str(tmp_id),
            "name": i['courseTitle'],
            "ongoing": i['ongoing']
        })

    for j in dbworker.mclient[dbworker.database]['classes'].find(
        {"students": str(email)}):
        tmp_id = j['_id']
        classes['student'].append({
            "id": str(tmp_id),
            "name": j['courseTitle'],
            "ongoing": j['ongoing']
        })
    return jsonify(classes)
Пример #6
0
def removeStudent():
    """
    Takes in a JSON of the structure {'email', 'classId'}

    Removes <email> from <classId> as a student

    Returns {'success' : Boolean}
    """
    if not dbworker.validateAccess(dbworker.userTypeMap['admin']):
        abort(403)

    if request.json is None or 'email' not in request.json or 'classId' not in request.json:
        abort(400)

    email = mailsane.normalize(request.json['email'])
    if email.error:
        abort(400)

    convClassId = ObjectId(request.json['classId'])

    try:
        validate(instance=request.json, schema=SchemaFactory.move_user)
    except exceptions.ValidationError:
        abort(400)

    us = dbworker.getUser(str(email))
    cl = dbworker.getClass(convClassId)
    if us is None or cl is None:
        abort(404)

    if us['userType'] not in [dbworker.userTypeMap['student']]:
        abort(400)

    return jsonify(
        {'success': dbworker.removeStudent(convClassId, str(email))})
Пример #7
0
def deleteMarkingSection():
    """
    Takes in a JSON of the following format
    {classId, sectionTitle}

    Returns {success : Boolean}

    Deletes mark weights and marks for sectionTitle in <classId>
    """
    # Validate credentials here
    if 'email' not in session or session['email'] is None:
        abort(401)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    if request.json is None:
        abort(400)

    for x in ['classId', 'sectionTitle']:
        if x not in request.json:
            abort(400)

    convClassId = ObjectId(request.json['classId'])

    if not dbworker.validateAccess(
            dbworker.userTypeMap['admin']) and not dbworker.isClassInstructor(
                str(email), convClassId):
        abort(401)

    dbworker.deleteMarkingSection(convClassId, request.json['sectionTitle'])

    return jsonify({'success': True})
Пример #8
0
def getMyMarks():
    """
    Gets a student's marks

    If the logged in user is not a student, then it will return a 403

    Returned structure is {marks : {}, success : Boolean}

    The keys for marks and markingSections will be class _ids
    """
    if not dbworker.validateAccess(dbworker.userTypeMap['student']):
        abort(403)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    marks = dbworker.getReports({'studentEmail': str(email)})

    classList = []
    marksDict = {}

    for m in marks:
        # This is to hide the internal report _ids
        m.pop('_id', None)
        tmpId = m['classId']
        m.pop('classId',
              None)  # This has to be done as ObjectIds not serializable
        m.pop('studentEmail', None)

        classList.append(tmpId)
        marksDict[str(tmpId)] = m

    markingSections = dbworker.getMarkingSectionInformation(
        filt={'_id': {
            '$in': classList
        }})

    for cl in classList:
        stredCl = str(cl)
        tmp = {}
        for sectionTitle in markingSections[stredCl]:
            tmp[sectionTitle] = {}

            tmp[sectionTitle]['weight'] = markingSections[stredCl][
                sectionTitle]['weight']
            tmp[sectionTitle]['index'] = markingSections[stredCl][
                sectionTitle]['index']

            if sectionTitle in marksDict[stredCl]['marks']:
                # This is to handle the case where a 'None' mark exists
                tmp[sectionTitle]['mark'] = marksDict[stredCl]['marks'][
                    sectionTitle]
            else:
                tmp[sectionTitle]['mark'] = None

        marksDict[stredCl]['marks'] = tmp

    return jsonify({'marks': marksDict, 'success': True})
Пример #9
0
def getCurrentUser():
    """
    Get the current user associated with whatever email is stored in session
    """
    if 'email' not in session:
        return None

    email = mailsane.normalize(session['email'])
    if email.error:
        return None

    return getUser(str(email))
Пример #10
0
def getClasses():
    """
    Returns a list of class ids from the database
    """
    if 'email' not in session or session['email'] is None:
        abort(401)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    return jsonify({
        'classList': dbworker.getClasses(str(email)),
        'success': True
    })
Пример #11
0
def addSampleUser(username):
    if not ENABLE_DEBUG_ROUTES:
        abort(404)

    email = mailsane.normalize(username + '@mcode.club')
    if email.error:
        abort(400)

    if dbworker.getUser(str(username + '@mcode.club')) is not None:
        abort(400)

    dbworker.createUser(str(email), str(email), 'Sample', 'User',
                        'I love rock and roll', 1, '647-111-1111',
                        datetime.datetime.strptime('1970-01-01',
                                                   '%Y-%m-%d'), 'Parent Name')
    return username
Пример #12
0
def getStudentReport(class_id, email):
    """
    Return a report for a student for a specific class.
    Expected json is {"email": [email protected], "classId":"5e5ab2f6e7179a5e7ee4e81b"}
    """

    # try:
    #     validate(instance={"email":email, "classId":class_id}, schema=SchemaFactory.report_student)
    # except exceptions.ValidationError:
    #     abort(400)

    email = mailsane.normalize(email)

    if email.error:
        abort(400)

    if not dbworker.validateAccessList(
        [dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor']]):
        abort(403)

    # Must first convert classId string in to a ObjectId before executing query
    convClassId = ObjectId(class_id)

    # Verify: 'email' is an existing user in DB and 'convClassId' is the idea of an existing class
    us = dbworker.getUser(str(email))
    cl = dbworker.getClass(convClassId)
    if us is None or cl is None:
        abort(404)

    if us['userType'] != dbworker.userTypeMap['student']:
        abort(400)

    filt = {"classId": convClassId, "studentEmail": str(email)}
    proj = {'_id': 0}

    report = dbworker.getStudentReport(filt=filt, proj=proj)

    if report is None:
        abort(400)

    # Must convert ObjectId 'classId' into a string before responding
    report['classId'] = str(report['classId'])

    return jsonify({"report": report})
Пример #13
0
def updateCourseInfo():
    """
    Takes in a JSON of the following format
    {classId, status : Boolean, newTitle : String}

    Returns {success : Boolean}

    Sets the <ongoing> of classId to <status>, and <courseTitle> to <newTitle>

    If <semesterInfo> is in request.json, it will update <semester> to <semesterInfo>
    """
    # Validate credentials here
    if 'email' not in session or session['email'] is None:
        abort(403)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    if request.json is None or 'classId' not in request.json or 'status' not in request.json or 'newTitle' not in request.json:
        abort(400)

    convClassId = ObjectId(request.json['classId'])
    if not dbworker.validateAccess(
            dbworker.userTypeMap['admin']) and not dbworker.isClassInstructor(
                str(email), convClassId):
        abort(401)

    try:
        validate(instance=request.json, schema=SchemaFactory.update_CI)
    except exceptions.ValidationError:
        abort(400)

    json = {
        'ongoing': request.json['status'],
        'courseTitle': request.json['newTitle']
    }

    if 'semesterInfo' in request.json:
        json['semester'] = request.json['semesterInfo']

    dbworker.updateClassInfo(convClassId, json)

    return jsonify({'success': True})
Пример #14
0
def setMarkingSection():
    """
    Takes in a JSON of the following format
    {classId, sectionTitle, weightInfo : JSON}

    weightInfo will be of the form
    {'weight' : Int, 'index' : Int}

    Returns {success : Boolean}

    Sets the weight of sectionTitle in classId to <weight>
    This will override existing values
    """
    if request.json is None or 'classId' not in request.json or 'sectionTitle' not in request.json or 'weightInfo' not in request.json:
        abort(400)

    for x in ['weight', 'index']:
        if x not in request.json['weightInfo']:
            abort(400)

    # Validate credentials here
    if 'email' not in session or session['email'] is None:
        abort(401)

    email = mailsane.normalize(session['email'])
    if email.error:
        abort(400)

    try:
        validate(instance=request.json, schema=SchemaFactory.set_marking)
    except exceptions.ValidationError:
        abort(400)

    convClassId = ObjectId(request.json['classId'])

    if not dbworker.validateAccess(
            dbworker.userTypeMap['admin']) and not dbworker.isClassInstructor(
                str(email), convClassId):
        abort(401)

    dbworker.addMarkingSection(convClassId, request.json['sectionTitle'],
                               request.json['weightInfo'])

    return jsonify({'success': True})
Пример #15
0
def genHours():
    # request.json['hours'] is currently a string that gets converted server side

    valid_access = [
        dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor'],
        dbworker.userTypeMap['volunteer']
    ]

    if not dbworker.validateAccessList(valid_access):
        abort(403)

    if request.json is None:
        abort(400)

    for x in ['purpose', 'paid', 'hours', 'dateTime']:
        if x not in request.json:
            abort(400)

    correctedTime = datetime.datetime.strptime(request.json['dateTime'],
                                               "%Y-%m-%dT%H:%M:%S.%fZ")

    email = session['email']

    if 'email' in request.json:
        email = mailsane.normalize(request.json['email'])
        if email.error:
            abort(400)

    hours = 0
    try:
        # Handle conversion from a string to a float
        hours = float(request.json['hours'])
    except:
        abort(400)

    if hours <= 0:
        abort(400)

    dbworker.addHoursLog(str(email), request.json['purpose'],
                         request.json['paid'], correctedTime, hours)

    return jsonify({'success': True})
Пример #16
0
def validateAccessList(expectedUserTypes):
    """
    Validate that the user is logged in, use the information in the
    session data to determine if their username is valid and one of the
    expectedUserTypes, return boolean, True if valid, False if invalid
    """
    if 'email' not in session or session['email'] is None:
        return False

    email = mailsane.normalize(session['email'])
    if email.error:
        return False

    uType = getUserType(str(email))

    for x in expectedUserTypes:
        if uType == x:
            return True

    return False
Пример #17
0
def getHours():

    if not dbworker.validateAccessList([
            dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor'],
            dbworker.userTypeMap['volunteer']
    ]):
        abort(403)

    pre_email = request.args.get('user', default=None, type=str)

    email = None

    if pre_email is None:
        email = session.get('email')

        if email is None:
            abort(500)
    else:
        if not dbworker.validateAccessList([dbworker.userTypeMap['admin']]):
            abort(403)

        email = mailsane.normalize(pre_email)

        if email.error:
            abort(400)

    hours = dbworker.getHours(filt={"email": str(email)},
                              projection={
                                  '_id': 1,
                                  'dateTime': 1,
                                  'purpose': 1,
                                  'hours': 1,
                                  'paid': 1
                              })

    hours_list = []
    for doc in hours:
        doc['_id'] = str(doc['_id'])
        hours_list.append(doc)

    return jsonify({"hours": hours_list})
Пример #18
0
def checkEmail():
    """
    Takes in a json of the form {'email' : email_address}

    Returns a json of the form {'message' : error_message, 'valid' : Boolean}

    'message' will refer to the specific reason an email address is invalid
    """
    if request.json is None or 'email' not in request.json:
        abort(400)

    # Use the verification library to check that it is a valid email
    address = mailsane.normalize(request.json['email'])

    if address.error:
        return jsonify({'message': str(address), 'valid': False})

    if dbworker.getUser(str(address)) is None:
        return jsonify({'message': 'Email address not found', 'valid': False})

    return jsonify({'message': None, 'valid': True})
Пример #19
0
def authenticate():
    # Use this route to log in and get a token
    # Takes in a json of the form {email : '', password : ''}

    if request.json is None:
        abort(400)

    for x in ['email', 'password']:
        if x not in request.json:
            abort(400)

    email = mailsane.normalize(request.json['email'])
    if email.error:
        abort(400)

    if dbworker.validateCredentials(str(email), request.json['password']):
        userType = dbworker.getUserType(str(email))
        session['email'] = str(email)
        return jsonify({'userType': userType, 'success': True})

    abort(401)
Пример #20
0
def getUser():
    """
    Takes in a JSON of {'email'}

    Returns {'result' : {user information, no id or password}, 'success' : True}

    This method is not just usable by admins, but by instructors
    """
    if dbworker.validateAccessList(
        [dbworker.userTypeMap['admin'], dbworker.userTypeMap['instructor']]):
        pass
    else:
        abort(403)

    if request.json is None or 'email' not in request.json:
        abort(400)

    email = mailsane.normalize(request.json['email'])
    if email.error:
        abort(400)

    u = dbworker.getUser(str(email))
    if u is None:
        abort(405)

    u.pop('password')
    u.pop('_id')

    now = datetime.datetime.now()

    bday = now
    if 'birthday' in u:
        bday = u['birthday']

    delta = now - bday
    age = int(delta.total_seconds() / (31536000))

    u['age'] = age
    return jsonify({'result': u, 'success': True})
Пример #21
0
    def getStudentList(self, index):
        """
        Construct a list of students. Check to make sure each column and cell for the table is filled with valid data
        for a new student. All students that are already in the database only need their email.

        :param index: the sheet index in the table dictionary
        :return: list of student emails
       """
        global studentAttributes

        studentList = []
        self.failures['Students'][index] = []

        # For each row in the dict
        for user in self.tableDict['Students'][index]:
            fail = False
            newUser = True
            thisStudentInfo = []
            email = ''

            # Check if there is a username column
            if 'MCC Account' in self.tableDict['Students'][index][user] and \
                not pd.isnull(self.tableDict['Students'][index][user]['MCC Account']):

                email = self.tableDict['Students'][index][user]['MCC Account']
                checkEmail = mailsane.normalize(email)
                if checkEmail.error:
                    self.failures['Students'][index].append('Error at email for student at row ' + str(user+1))
                    fail = True

                # Check if Account already exists
                elif dbworker.mclient[dbworker.database]['users'].find_one({'userType': dbworker.userTypeMap['student'],
                                                                          'email': email}) is not None:
                    newUser = False
                    studentList.append(email)

                # If account doesn't exist, extract the student info from the table
                else:
                    attributeIndex = 1
                    while attributeIndex < len(studentAttributes) and not fail:
                        if studentAttributes[attributeIndex] in self.tableDict['Students'][index][user] and \
                                not pd.isnull(self.tableDict['Students'][index][user][studentAttributes[attributeIndex]]):

                            thisStudentInfo.append(self.tableDict['Students'][index][user][studentAttributes[attributeIndex]])

                        else:
                            self.failures['Students'][index].append('Error at ' + studentAttributes[attributeIndex] +
                                                                    ' for student at row ' + str(user+1))
                            fail = True

                        attributeIndex += 1

            else:
                self.failures['Students'][index].append('Error at MCC Account for student at row ' + str(user+1))
                fail = True

            # If all the parameters are met, add user info to the database
            if (not fail) and newUser:
                dbworker.createUser(email, thisStudentInfo[0], thisStudentInfo[1], thisStudentInfo[2],
                                    thisStudentInfo[3], 4, thisStudentInfo[4], thisStudentInfo[5], thisStudentInfo[6])
                studentList.append(email)

        return studentList
Пример #22
0
def editUser():
    """
    Takes in a json of the form
    {'currentEmail' : email, 'newAttributes' : {...}}

    It can change any attribute that is not the email
    """
    sys.stderr.write(str(request.json) + '\n')
    if not dbworker.validateAccess(dbworker.userTypeMap['admin']):
        abort(403)

    if request.json is None or 'currentEmail' not in request.json or 'newAttributes' not in request.json:
        abort(400)

    email = mailsane.normalize(request.json['currentEmail'])
    if email.error:
        abort(400)

    if dbworker.getUser(str(email)) is None:
        abort(404)

    if request.json['newAttributes'] == {} or 'email' in request.json[
            'newAttributes'] or '_id' in request.json['newAttributes']:
        # No changes requested or an attempt was made to change the email or _id
        abort(400)

    # Validate that all the changes made are valid
    # ie. ban changes to any invalid attributes

    try:
        validate(instance=request.json, schema=SchemaFactory.edit_user)
    except exceptions.ValidationError:
        abort(400)

    if 'birthday' in request.json[
            'newAttributes'] or 'password' in request.json['newAttributes']:
        # Convert birthday from string to datetime object
        # See https://stackoverflow.com/questions/969285/how-do-i-translate-an-iso-8601-datetime-string-into-a-python-datetime-object
        correctedTime = None
        try:
            if 'birthday' in request.json['newAttributes']:
                correctedTime = datetime.datetime.strptime(
                    request.json['newAttributes']['birthday'],
                    "%Y-%m-%dT%H:%M:%S.%fZ")
        except:
            abort(400)

        correctedDict = {}
        for x in request.json['newAttributes']:
            if x == 'birthday':
                correctedDict['birthday'] = correctedTime
            elif x == 'password':
                dbworker.setPassword(str(email),
                                     request.json['newAttributes']['password'])
            else:
                correctedDict[x] = request.json['newAttributes'][x]

        dbworker.editUser(str(email), correctedDict)
    else:
        dbworker.editUser(str(email), request.json['newAttributes'])

    return jsonify({'success': True})
Пример #23
0
def getReport():
    """
    Return a PDF containing all worked/volunteer hours
    """
    report_params = request.json

    if report_params is None:
        abort(400)

    if 'email' not in report_params:
        report_params['email'] = session['email']

    try:
        validate(instance=report_params, schema=SchemaFactory.report_hours)
    except exceptions.ValidationError:
        abort(400)

    email = mailsane.normalize(report_params['email'])

    if email.error:
        abort(400)

    if not dbworker.validateAccessList([dbworker.userTypeMap['admin']
                                        ]) and str(email) != session['email']:
        # Allows admins to see everyones reports, users to see their own
        abort(403)

    paid_hrs = None

    filt = {"email": str(email)}
    proj = {'_id': 0, 'hours': 1}

    if 'paid' in request.json:
        filt['paid'] = True if request.json['paid'] else False
        paid_hrs = False if request.json['paid'] == 0 else True

    # Convert date ranges into datetime objects and insert into filter
    # Note: to enforce a specific date/time pattern you can also use strptime method:
    # datetime.datetime.strptime(request.json['startRange'], '%Y-%m-%d') (complete pattern: "%Y-%m-%dT%H:%M:%S.%fZ")
    if 'startRange' in report_params and 'endRange' in report_params:
        start_time_stamp = parse(report_params['startRange'])
        end_time_stamp = parse(report_params['endRange'])
        filt["dateTime"] = {'$gte': start_time_stamp, '$lte': end_time_stamp}
    elif 'startRange' in report_params:
        start_time_stamp = parse(report_params['startRange'])
        filt["dateTime"] = {'$gte': start_time_stamp}
    elif 'endRange' in report_params:
        end_time_stamp = parse(report_params['endRange'])
        filt["dateTime"] = {'$lte': end_time_stamp}

    hours = dbworker.getHours(filt=filt, projection=proj)

    hours_list = []
    for doc in hours:
        hours_list.append(float(doc["hours"]))

    file_name = reportgen.hours(email, hours_list, paid_hrs)

    # Once generated, report PDFs are currently stored in the 'app' folder of docker container
    resp_file = send_file(file_name, attachment_filename=file_name)

    if os.path.exists("app/" + file_name):
        os.remove("app/" + file_name)
        return resp_file

    abort(500)