Exemple #1
0
  def post(self):
    user = current_user()

    if not user or not user.is_admin:
      return '', 403

    school = user.school

    sponsor_name = api.payload['name']

    logo_name = '{}-{}'.format(slugify(sponsor_name, separator='-', to_lower=True), uuid4().hex)

    try:
      # TODO: Once you have apscheduler, run this as a delayed job
      logo = upload_image(
        data=api.payload['logo'],
        name=logo_name,
        location='sponsors/'
      )
    except BaseException:
      logger.error('Error uploading image to S3')
      return 'Error uploading provided image', 500

    dbi.create(Sponsor, {
      'school': school,
      'name': sponsor_name,
      'logo': logo,
      'url': api.payload['url']
    })

    sponsors = format_sponsors(school.sponsors)

    return sponsors, 201
Exemple #2
0
    def get(self, week_num):
        user = current_user()

        if not user:
            return '', 403

        challenges = sorted(user.school.active_challenges(),
                            key=attrgetter('start_date'))

        curr_week_num = current_week_num(challenges)
        challenge = challenges[week_num - 1]

        # If requesting future check_in or
        # requesting first check_in but challenges haven't started yet, error out
        if week_num > curr_week_num or (
                week_num == 1 and date.today() < challenge.start_date.date()):
            return '', 403

        # Get the CheckIn from the Challenge
        check_in = challenge.check_in

        # Get formatted question-answers for this user
        questions = format_questions(check_in, user)

        return {
            'id': check_in.id,
            'challengeName': challenge.name,
            'questions': questions
        }
Exemple #3
0
    def put(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        prize = dbi.find_one(Prize, {'id': api.payload['id']})

        if not prize:
            return 'Can\'t find prize to update :/', 500

        sponsor = dbi.find_one(Sponsor, {'id': api.payload['sponsorId']})

        if not sponsor:
            return 'Sponsor required to update prize', 500

        dbi.update(
            prize, {
                'sponsor': sponsor,
                'name': api.payload['name'],
                'count': api.payload['count'] or 1
            })

        prizes = format_prizes(prize.challenge.active_prizes())

        return prizes, 200
Exemple #4
0
    def post(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        challenge = dbi.find_one(Challenge, {'id': api.payload['challengeId']})

        if not challenge:
            return 'Challenge required to create prize', 500

        sponsor = dbi.find_one(Sponsor, {'id': api.payload['sponsorId']})

        if not sponsor:
            return 'Sponsor required to create prize', 500

        dbi.create(
            Prize, {
                'challenge': challenge,
                'sponsor': sponsor,
                'name': api.payload['name'],
                'count': api.payload['count'] or 1
            })

        return format_prizes(challenge.active_prizes())
  def get(self, week_index):
    user = current_user()

    if not user or not user.is_admin:
      return '', 403

    args = dict(request.args.items())
    resp_data = {}

    if args.get('withWeeks') == 'true':
      challenges = sorted(user.school.active_challenges(), key=attrgetter('start_date'))
      weeks = []

      i = 0
      for c in challenges:
        weeks.append({
          'title': 'Week {} - {}'.format(i + 1, c.name),
          'value': i
        })
        i += 1

      resp_data['weeks'] = weeks

    # Get email template for WeeklyEmail, as well as model attrs. Add to resp_data['week']
    resp_data['week'] = {}

    return resp_data, 200
Exemple #6
0
    def put(self):
        user = current_user()

        if not user:
            return '', 403

        payload = api.payload or {}

        check_in_id = payload.get('id')
        if not check_in_id:
            return 'CheckInId required to save user\'s answers', 500

        questions = payload.get('questions') or []
        if not questions:
            return 'Questions list required to save user\'s answers', 500

        check_in = dbi.find_one(CheckIn, {'id': check_in_id})

        if not check_in:
            logger.error('No CheckIn for id: {}'.format(check_in_id))
            return 'CheckIn Not Found', 500

        for q in questions:
            question = q.get('question')
            answer = q.get('answer')

            if not question or not answer or \
              not question.get('id') or not question.get('text') or 'text' not in answer:
                return 'Invalid question/answer format', 500

            answer_id = answer.get('id')

            # If answer already has been created, find and update it
            if answer_id:
                check_in_answer = dbi.find_one(CheckInAnswer,
                                               {'id': answer_id})

                if not check_in_answer:
                    logger.error(
                        'No CheckInAnswer for id: {}'.format(answer_id))
                    return 'Answer doesn\'t exist', 500

                dbi.update(check_in_answer, {'text': answer['text']})

            else:  # otherwise, create a new answer
                dbi.create(
                    CheckInAnswer, {
                        'user': user,
                        'check_in_question_id': question['id'],
                        'text': answer['text']
                    })

        questions = format_questions(check_in, user)

        return questions
Exemple #7
0
    def get(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        challenges = sorted(user.school.active_challenges(),
                            key=attrgetter('start_date'))

        data = formatted_winners(challenges)

        return data
Exemple #8
0
    def get(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        challenges = sorted(user.school.active_challenges(),
                            key=attrgetter('start_date'))

        resp = format_response_overviews(challenges)

        return resp
Exemple #9
0
    def get(self):
        user = current_user()

        if not user:
            return '', 403

        challenges = sorted(user.school.active_challenges(),
                            key=attrgetter('start_date'))
        challenge_ids = [c.id for c in challenges]

        curr_week_num = current_week_num(challenges)

        # TODO: Eager-load all of this
        check_ins = dbi.find_all(CheckIn, {'challenge_id': challenge_ids})
        check_ins_map = {c.challenge_id: c for c in check_ins}

        check_in_answers_map = {
            a.check_in_question_id: a
            for a in user.check_in_answers
        }

        formatted_check_ins = []
        i = 1
        for c in challenges:
            check_in = check_ins_map[c.id]
            check_in_questions = check_in.check_in_questions
            num_questions = len(check_in_questions)

            num_answers = 0
            for q in check_in_questions:
                if check_in_answers_map.get(q.id):
                    num_answers += 1

            data = {
                'challengeName': c.name,
                'weekNum': i,
                'numQuestions': num_questions,
                'numAnswers': num_answers
            }

            formatted_check_ins.append(data)
            i += 1

        launched = True
        if date.today() < challenges[0].start_date.date():
            launched = False

        return {
            'checkIns': formatted_check_ins,
            'weekNum': curr_week_num,
            'launched': launched
        }
Exemple #10
0
  def get(self):
    user = current_user()

    if not user or not user.is_admin:
      return '', 403

    csv_data = format_school_users_csv(user.school)

    resp = {
      'content': csv_data,
      'filename': 'all-users.csv'
    }

    return resp
Exemple #11
0
    def get(self):
        # How you would validate the request came from an authed user
        user = current_user()

        # Error out if unauthorized request
        if not user:
            return UNAUTHORIZED

        # Parse our payload from args
        payload = dict(request.args.items())

        # Get resource

        return {}, 200
Exemple #12
0
    def put(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        try:
            start_date = datetime.strptime(api.payload['startDate'],
                                           '%m/%d/%y')
        except:
            return 'Invalid start date', 500

        challenge_slugs = [c['slug'] for c in api.payload['challenges']]

        school = user.school

        challenges = dbi.find_all(Challenge, {
            'school': user.school,
            'slug': challenge_slugs
        })

        i = 0
        for slug in challenge_slugs:
            challenge = [c for c in challenges if c.slug == slug][0]

            if i > 0:
                start_date = start_date + timedelta(days=7)

            end_date = start_date + timedelta(days=6)

            dbi.update(challenge, {
                'start_date': start_date,
                'end_date': end_date
            })

            i += 1

        challenges = sorted(school.active_challenges(),
                            key=attrgetter('start_date'))

        curr_week_num = current_week_num(challenges)

        challenges_data = format_challenges(challenges,
                                            user,
                                            curr_week_num=curr_week_num)

        resp = {'weekNum': curr_week_num, 'challenges': challenges_data}

        return resp
Exemple #13
0
  def post(self):
    from_user = current_user()

    if not from_user:
      return '', 403

    to_email = api.payload['email']
    to_user = dbi.find_one(User, {'email': to_email})

    if to_user:
      return 'User already on Quokka', 500

    user_mailer.invite_user(from_user, to_email)

    return '', 200
Exemple #14
0
  def put(self):
    user = current_user()

    if not user:
      return '', 403

    updates = {
      'hashed_pw': auth_util.hash_pw(api.payload['password'])
    }

    if user.school.slug == 'rice-university' and api.payload.get('dorm'):
      updates['meta'] = {'dorm': api.payload['dorm']}

    dbi.update(user, updates)

    return '', 200
Exemple #15
0
    def put(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        challenge = dbi.find_one(Challenge, {'id': api.payload['id']})

        if not challenge:
            logger.error('No challenge found for id: {}'.format(
                api.payload['id']))
            return 'Challenge required to update text and points', 500

        dbi.update(challenge, {'suggestions': api.payload['suggestions']})

        return {'suggestions': challenge.suggestions}
Exemple #16
0
    def delete(self):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        args = dict(request.args.items())
        prize = dbi.find_one(Prize, {'id': args.get('id')})

        if not prize:
            return 'Can\'t find prize to destroy :/', 500

        dbi.destroy(prize)

        prizes = format_prizes(prize.challenge.active_prizes())

        return prizes, 200
Exemple #17
0
    def get(self):
        user = current_user()

        if not user:
            return '', 403

        # Get challenges for school, sorted by date
        challenges = sorted(user.school.active_challenges(),
                            key=attrgetter('start_date'))

        curr_week_num = current_week_num(challenges)

        challenges_data = format_challenges(challenges,
                                            user,
                                            curr_week_num=curr_week_num)

        resp = {'weekNum': curr_week_num, 'challenges': challenges_data}

        return resp
Exemple #18
0
    def get(self, check_in_id):
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        check_in = dbi.find_one(CheckIn, {'id': check_in_id})

        if not check_in:
            return '', 404

        include_dorm = user.school.slug == 'rice-university'
        csv_data = format_csv_responses(check_in, include_dorm=include_dorm)

        resp = {
            'content': csv_data,
            'filename':
            'check-in-responses-{}.csv'.format(check_in.challenge.slug)
        }

        return resp
Exemple #19
0
    def post(self):
        # NOTE: Very aware this endpoint makes a shit-ton of queries and most everything should
        # be eager loaded, but I don't have time to figure all that syntax bullshit out right now for
        # properly eager loading. TODO: Refactor this
        user = current_user()

        if not user or not user.is_admin:
            return '', 403

        school = user.school
        challenges = sorted(school.active_challenges(),
                            key=attrgetter('start_date'))

        # Get challenge to assign winners for
        challenge = [
            c for c in challenges if c.id == api.payload['challenge_id']
        ]

        # Make sure challenge exists...
        if challenge:
            challenge = challenge[0]
        else:
            return 'Challenge Not Found', 404

        # If challenge hasn't started yet, error out
        if challenge.start_date.date() > date.today():
            return '', 401

        # Get prizes for this challenge
        prizes = sorted(dbi.find_all(Prize, {'challenge': challenge}),
                        key=attrgetter('id'))
        prize_ids = [p.id for p in prizes]

        # Error out if winners have already been chosen for this challenge
        if dbi.find_all(Winner, {'prize_id': prize_ids}):
            return 'Winners already chosen for this challenge', 500

        # Get reference to all prizes across all challenges for this school
        school_prizes = dbi.find_all(
            Prize, {'challenge_id': [c.id for c in challenges]})

        # Get list of all past winners for this school
        past_winners = []
        for p in school_prizes:
            past_winners += p.winners

        # Find user_ids for all past winners
        past_winner_user_ids = [
            u.id for u in dbi.find_all(
                User, {'id': [w.user_id for w in past_winners]})
        ]

        # Get all check_in_question_ids for this check_in and sort them
        question_ids = [q.id for q in challenge.check_in.check_in_questions]
        question_ids.sort()

        # Find ALL check_in_answers related to these check_in_questions
        answers = dbi.find_all(CheckInAnswer,
                               {'check_in_question_id': question_ids})

        # Create a map of user_id to list of check_in_question_ids that they answered for this check_in
        # Ex: {1: [2, 3, 4]} --> we'll then compare [2, 3, 4] to question_ids to see if they match
        user_ids_to_question_ids = {}
        for a in answers:
            if a.user_id not in user_ids_to_question_ids:
                user_ids_to_question_ids[a.user_id] = [a.check_in_question_id]
            else:
                user_ids_to_question_ids[a.user_id].append(
                    a.check_in_question_id)

        # Find users who:
        # (1) haven't been selected as winners in the past
        # (2) have answered all check_in_questions for this check_in
        potential_winner_user_ids = []
        for k, v in user_ids_to_question_ids.items():
            v.sort()
            if k not in past_winner_user_ids and v == question_ids:
                potential_winner_user_ids.append(k)

        if not potential_winner_user_ids:
            return 'No users currently eligible for prizes -- either everyone has already won or no one has filled out check-ins', 400

        potential_winning_users = dbi.find_all(
            User,
            {
                'id': potential_winner_user_ids,
                'is_admin': False  # admins can't win
            })

        prize_ids_for_winners = []
        for p in prizes:
            prize_ids_for_winners += ([p.id] * p.count)

        # Random prize assignment
        shuffle(prize_ids_for_winners)

        winning_users = random_subset(potential_winning_users,
                                      len(prize_ids_for_winners))

        i = 0
        for u in winning_users:
            winner = dbi.create(Winner, {
                'user': u,
                'prize_id': prize_ids_for_winners[i]
            })

            # Send the winner an email congratulating him/her
            challenge_mailer.congratulate_winner(challenge, winner.prize, u,
                                                 school)

            i += 1

        data = formatted_winners(challenges)

        return data
Exemple #20
0
    def get(self, week_num):
        user = current_user()

        if not user:
            return '', 403

        school = user.school
        week_index = week_num - 1

        # Get challenges for school, sorted by date
        challenges = sorted(school.active_challenges(),
                            key=attrgetter('start_date'))

        if week_num < 1 or week_num > len(challenges):
            return {
                'error': 'Challenge does not exist',
                'code': CHALLENGE_NOT_EXIST
            }, 400

        curr_week_num = current_week_num(challenges)

        # if this is a future week and the user isn't an admin, prevent access
        if week_num > curr_week_num and not user.is_admin:
            return {
                'error': 'Week not yet available to access',
                'code': INVALID_CHALLENGE_ACCESS
            }, 400

        # Find the challenge requested by week index
        challenge = challenges[week_index]

        if week_index == 0:
            prev_habit = None
            next_habit = {'weekNum': 2, 'name': challenges[1].name}
        elif week_index == len(challenges) - 1:
            prev_habit = {
                'weekNum': week_index,
                'name': challenges[week_index - 1].name
            }
            next_habit = None
        else:
            prev_habit = {
                'weekNum': week_index,
                'name': challenges[week_index - 1].name
            }
            next_habit = {
                'weekNum': week_num + 1,
                'name': challenges[week_num].name
            }

        # if this is the current week and the user isn't an admin, he/she shouldn't have a link to the next week yet
        if week_num == curr_week_num and not user.is_admin:
            next_habit = None

        universal_challenge = universal_challenge_info.get(challenge.slug)

        resp = {
            'id': challenge.id,
            'habit': {
                'name': challenge.name,
                'slug': challenge.slug,
                'icon': universal_challenge['icon'],
                'dates': {
                    'start': datetime.strftime(challenge.start_date,
                                               '%m/%d/%Y'),
                    'end': datetime.strftime(challenge.end_date, '%m/%d/%Y')
                }
            },
            'overview': universal_challenge['overview'],
            'challenge': {
                'text': challenge.text,
                'points': challenge.points
            },
            'prizes': format_prizes(challenge.active_prizes()),
            'sponsors': format_sponsors(school.sponsors),
            'suggestions': challenge.suggestions,
            'adjHabits': {
                'prev': prev_habit,
                'next': next_habit
            },
            'links': universal_challenge['links'],
            'extraInfo': universal_challenge['extra_info']
        }

        return resp