Пример #1
0
 def test_user_info(self):
     with test_data.Database.WithTestData() as data:
         response = self.app.get('/api/user')
         self.assertIsNone(json.loads(response.data))
         self.assertEqual(response.status_code, 200)
         self.login(data.school['fragment'], data.user['email'],
                    data.user['clearpw'])
         response = self.app.get('/api/user')
         self.assertEqual(response.status_code, 200)
         user = util.User(data.user, data.school)
         self.assertEqual(
             {
                 'name':
                 user.name(),
                 'first':
                 user['first'],
                 'middle':
                 user['middle'],
                 'last':
                 user['last'],
                 'email':
                 user['email'],
                 'roles': {},
                 'secret':
                 user['secret'],
                 'schedules': [
                     user._formatSchedule(util.project_term(data.term),
                                          data.user['schedules'][0])
                 ],
             }, json.loads(response.data))
Пример #2
0
def shared_schedule(school):
    """Get a user by the secret on one of their schedules and return just
    that schedule's info."""
    school = app.mongo.db.schools.find_one_or_404({'fragment': school},
                                                  {'_id': False})
    c = mongo.SchoolCollections(school['fragment'])
    user = util.User(
        c.user.find_one_or_404(
            {'schedules.secret': flask.request.args['secret']},
            {
                'email': True,  # For linking to instructors - do not print
                'first': True,
                'middle': True,
                'last': True,
                'schedules.$': True,
            },
        ),
        school)
    sch = user['schedules'][0]
    sch['sections'] = [
        sect for sect in sch['sections'] if sect['status'] != 'no'
    ]
    addInstructorCourses(c, user, term=sch['term'])
    schedules = user.formatSchedules()
    return flask.jsonify(name=user.name(), schedules=schedules)
Пример #3
0
def main(args):
    parser = argparse.ArgumentParser(description='Add a user.')
    parser.add_argument('--school', required=True)
    parser.add_argument('--email', required=True, action='append')
    parser.add_argument('--first')
    parser.add_argument('--middle')
    parser.add_argument('--last')
    parser.add_argument('--password')
    parser.add_argument('--passhash')
    parser.add_argument('--role', default=[], action='append')
    args = parser.parse_args(args)
    school = app.mongo.db.schools.find_one({'fragment': args.school})
    if not school:
        sys.stderr.write('School %s does not exist.\n' % args.school)
        sys.exit(1)
    user = util.User(
        {
            'email': args.email,
            'first': args.first,
            'middle': args.middle,
            'last': args.last,
            'schedules': [],
            'secret': util.generate_secret(),
            'roles': args.role,
        }, school)
    if args.password and not args.passhash:
        user.set_password(args.password)
    elif args.passhash:
        user['passhash'] = args.passhash
    else:
        sys.stderr.write(
            'Exactly one of --passhash, --password must be provided.\n')
        sys.exit(1)
    c = mongo.SchoolCollections(school['fragment'])
    c.user.insert(user.user)
Пример #4
0
def reset_password(school):
    request = flask.request.json
    school = app.mongo.db.schools.find_one_or_404({'fragment': school},
                                                  {'_id': False})
    c = mongo.SchoolCollections(school['fragment'])
    user = c.user.find_one_or_404({
        'email': request['email'],
    }, {
        '_id': True,
        'email': True,
        'first': True,
        'middle': True,
        'last': True,
    })
    user = util.User(user, school)
    user['name'] = user.name()
    secret = util.create_verification(c, 'reset_password', user=user['_id'])
    msg = flask_mail.Message(
        "Password Reset",
        recipients=user['email'][0:1],
    )
    msg.html = flask.render_template(
        'email/reset_password.html',
        school=school,
        user=user.user,
        secret=secret,
    )
    msg.body = flask.render_template(
        'email/reset_password.txt',
        school=school,
        user=user.user,
        secret=secret,
    )
    app.mail.send(msg)
    return flask.jsonify()
Пример #5
0
 def test_login_succeed(self):
     with test_data.Database.WithTestData() as data:
         response = self.login(data.school['fragment'], data.user['email'],
                               data.user['clearpw'])
         user = util.User(data.user, data.school)
         self.assertEqual(
             {
                 'name':
                 user.name(),
                 'first':
                 user['first'],
                 'middle':
                 user['middle'],
                 'last':
                 user['last'],
                 'email':
                 user['email'],
                 'roles': {},
                 'secret':
                 user['secret'],
                 'schedules': [
                     user._formatSchedule(util.project_term(data.term),
                                          data.user['schedules'][0])
                 ],
             }, json.loads(response.data))
     self.assertEqual(response.status_code, 200)
     self.assertEqual(flask_login.current_user['id'], data.user['id'])
     self.assertTrue(flask_login.current_user.is_active)
     self.assertTrue(flask_login.current_user.is_authenticated)
     self.assertFalse(flask_login.current_user.is_anonymous)
     self.assertIsNotNone(flask_login.current_user.get_id())
Пример #6
0
def load_user(user_id):
    try:
        school, user_id = user_id.split(':', 1)
    except ValueError:
        return None
    try:
        user_id = objectid.ObjectId(user_id)
    except objectid.InvalidId:
        return None
    school = app.mongo.db.schools.find_one({'fragment': school})
    c = mongo.SchoolCollections(school['fragment'])
    user = c.user.find_one({'_id': user_id})
    if user:
        return util.User(user, school)
Пример #7
0
def verify(school):
    request = flask.request.json
    school = app.mongo.db.schools.find_one_or_404({'fragment': school},
                                                  {'_id': False})
    c = mongo.SchoolCollections(school['fragment'])
    verification = c.email_verification.find_one_or_404({
        'secret':
        request['secret'],
    })
    type_ = verification['type']
    # Check that it's still valid
    if verification.get('used'):
        return flask.jsonify(type=type_, status='used')
    elif (verification['expiration'].replace(tzinfo=None) <
          datetime.datetime.utcnow()):
        return flask.jsonify(type=type_, status='expired')
    if type_ == 'new_user':
        try:
            c.user.insert(verification['user'], w=1)
        except pymongo.errors.DuplicateKeyError:
            return flask.jsonify(type=type_, status='account_exists')
    elif type_ == 'reset_password':
        if 'password' not in request:
            return flask.jsonify(type=type_, status='need_password')
        user = util.User({}, school)
        user.set_password(request['password'])
        c.user.update({
            '_id': verification['user'],
        }, {
            '$set': {
                'passhash': user['passhash']
            },
        },
                      w=1)
    elif type_ == 'add_email':
        c.user.update({
            '_id': verification['user'],
        }, {'$addToSet': {
            'email': verification['email']
        }})
    else:
        raise ValueError('Unknown verification type %s' % type_)
    c.email_verification.update({
        '_id': verification['_id'],
    }, {
        '$set': {
            'used': True
        },
    })
    return flask.jsonify(type=type_, status='success')
Пример #8
0
def ical(school, secret):
    school = app.mongo.db.schools.find_one_or_404({'fragment': school},
                                                  {'_id': False})
    c = mongo.SchoolCollections(school['fragment'])
    user = util.User(c.user.find_one_or_404({'secret': secret}), school)
    users.addInstructorCourses(c, user)
    schedules = user.formatSchedules(timestamps=True)
    cal = icalendar.Calendar()
    cal.add('prodid', '-//schdl/schdl//NONSGML v2.0//EN')
    cal.add('version', '2.0')
    # TODO(eitan): get timezone from school
    tz = pytz.timezone('America/New_York')
    cal.add('x-wr-calname;value=text', 'Schdl: %s' % user.name())
    cal.add('x-wr-timezone', 'America/New_York')
    # TODO(eitan): include link to this schedule
    cal.add('x-wr-caldesc', 'Generated by Schdl')
    if schedules:
        cal.add_component(icalTimezone(tz, schedules))
    oneday = datetime.timedelta(days=1)
    for sch in schedules:
        term = sch['term']
        start = parseDate(term['start']).replace(tzinfo=tz)
        end = parseDate(term['end']).replace(tzinfo=tz) + oneday
        for sect in sch['course_sections']:
            if sect['user_status'] not in ('instructor', 'official'):
                continue
            for time in sect['times']:
                sha1 = hashlib.sha1()
                sha1.update(
                    json.dumps(
                        dict(school=school['fragment'],
                             user=str(user['_id']),
                             start=start,
                             end=end,
                             sect=sect,
                             time=time)))
                uid = '%s@%s' % (sha1.hexdigest(), flask.request.host)
                cal.add_component(makeEvent(start, end, sect, time, uid))
    filename = '%s - %s.ics' % (user.school['name'], user.name())
    response = flask.Response(
        response=cal.to_ical(),
        mimetype=b'text/calendar',
    )
    response.headers.add(b'Content-Description', b'File Transfer')
    response.headers.add(b'Content-Disposition',
                         b'attachment',
                         filename=filename.encode('utf-8'))
    return response
Пример #9
0
def register(school):
    # If logged in, just return current user
    if not flask_login.current_user.is_anonymous:
        return current_user()
    request = flask.request.json
    school = app.mongo.db.schools.find_one_or_404({'fragment': school},
                                                  {'_id': False})
    c = mongo.SchoolCollections(school['fragment'])
    email_in_use = c.user.find_one({'email': request['email']})
    if email_in_use:
        return flask.jsonify(), 409  # Conflict
    user = util.User(
        {
            'first': request['first'],
            'middle': '',
            'last': request['last'],
            'email': [request['email']],
            'schedules': [],
            'secret': util.generate_secret(),
            'roles': [],
        }, school)
    user.set_password(request['password'])
    ttl = datetime.timedelta(days=1)
    secret = util.create_verification(c, 'new_user', user=user.user, ttl=ttl)
    user['name'] = user.name()
    msg = flask_mail.Message(
        "Confirm Your Email Address",
        # User must have exactly one email address at account creation
        recipients=user['email'],
    )
    msg.html = flask.render_template(
        'email/new_user_verify_email.html',
        school=school,
        user=user.user,
        secret=secret,
    )
    msg.body = flask.render_template(
        'email/new_user_verify_email.txt',
        school=school,
        user=user.user,
        secret=secret,
    )
    app.mail.send(msg)
    return flask.jsonify()
Пример #10
0
def user_login(school):
    school = app.mongo.db.schools.find_one({'fragment': school})
    c = mongo.SchoolCollections(school['fragment'])
    email = request.json['email']
    password = request.json['password']
    user = c.user.find_one({'email': email})
    if user is None:
        return jsonify(reason='noaccount'), 403
    if app.bcrypt.check_password_hash(user['passhash'], password):
        if flask_login.login_user(util.User(user, school)):
            c.user.update({'_id': user['_id']}, {
                '$set': {
                    'last_login': datetime.datetime.utcnow()
                },
            })
            return users.current_user()
        else:
            return jsonify(reason='unverified'), 403
    else:
        return jsonify(reason='password'), 403
Пример #11
0
 def test_PUT(self):
     with test_data.Database.WithTestData() as data:
         c = mongo.SchoolCollections(data.school['fragment'])
         user = c.user.find_one({'id': data.user['id']})
         self.assertEqual(data.schedule['sections'][0]['status'],
                          user['schedules'][0]['sections'][0]['status'])
         self.login(data.school['fragment'], data.user['email'],
                    data.user['clearpw'])
         response = self.app.put(
             '/api/schedules/%s/%s/%s' %
             (data.school['fragment'], data.term['fragment'],
              util.encode_section_id(data.course_section['id'])),
             data=json.dumps(dict(status='no')),
             content_type='application/json')
         self.assertEqual(response.status_code, 200)
         user = util.User(c.user.find_one({'id': data.user['id']}),
                          data.school)
         self.assertEqual('no',
                          user['schedules'][0]['sections'][0]['status'])
         self.assertEqual(
             {
                 'name':
                 user.name(),
                 'first':
                 user['first'],
                 'middle':
                 user['middle'],
                 'last':
                 user['last'],
                 'email':
                 user['email'],
                 'roles': {},
                 'secret':
                 user['secret'],
                 'schedules': [
                     user._formatSchedule(util.project_term(data.term),
                                          user['schedules'][0])
                 ],
             }, json.loads(response.data))
Пример #12
0
 def test_DELETE(self):
     with test_data.Database.WithTestData() as data:
         c = mongo.SchoolCollections(data.school['fragment'])
         user = util.User(c.user.find_one({'id': data.user['id']}),
                          data.school)
         self.assertTrue(user['schedules'][0]['sections'])
         self.login(data.school['fragment'], data.user['email'],
                    data.user['clearpw'])
         # Delete a fake section
         response = self.app.delete(
             '/api/schedules/%s/%s/%s' %
             (data.school['fragment'], data.term['fragment'],
              util.encode_section_id('fake-section')))
         self.assertEqual(response.status_code, 200)
         self.assertEqual(
             {
                 'name':
                 user.name(),
                 'first':
                 user['first'],
                 'middle':
                 user['middle'],
                 'last':
                 user['last'],
                 'email':
                 user['email'],
                 'roles': {},
                 'secret':
                 user['secret'],
                 'schedules': [
                     user._formatSchedule(util.project_term(data.term),
                                          data.user['schedules'][0])
                 ],
             }, json.loads(response.data))
         # Delete a real section
         response = self.app.delete(
             '/api/schedules/%s/%s/%s' %
             (data.school['fragment'], data.term['fragment'],
              util.encode_section_id(data.course_section['id'])))
         self.assertEqual(response.status_code, 200)
         user['schedules'][0]['sections'] = []
         self.assertEqual(
             {
                 'name':
                 user.name(),
                 'first':
                 user['first'],
                 'middle':
                 user['middle'],
                 'last':
                 user['last'],
                 'email':
                 user['email'],
                 'roles': {},
                 'secret':
                 user['secret'],
                 'schedules': [
                     user._formatSchedule(util.project_term(data.term),
                                          user['schedules'][0])
                 ],
             }, json.loads(response.data))
         user = util.User(c.user.find_one({'id': data.user['id']}),
                          data.school)
         self.assertFalse(user['schedules'][0]['sections'])