Exemple #1
0
def CompetitionToWcif(competition, schedule):
    output_dict = {}
    output_dict['formatVersion'] = '1.0'
    output_dict['id'] = competition.key.id()
    output_dict['name'] = competition.name
    wca_competition = competition.wca_competition.get()

    # TODO: add people

    rounds_by_event_id = collections.defaultdict(list)
    for r in ScheduleRound.query(ScheduleRound.schedule == schedule.key):
        rounds_by_event_id[r.event.id()].append(r)
    output_dict['events'] = []
    for event_id, rounds in rounds_by_event_id.iteritems():
        output_dict['events'].append(EventToWcif(event_id, rounds))

    if schedule:
        output_dict['schedule'] = ScheduleToWcif(schedule, competition,
                                                 wca_competition)

    extension_dict = {}
    extension_dict['datastoreId'] = competition.key.id()
    if competition.staff_signup_deadline:
        extension_dict['staffSignupDeadline'] = (
            competition.staff_signup_deadline.strftime('%Y-%m-%d'))
    AddExtension('ScheduleCompetition', extension_dict, output_dict)

    return output_dict
 def get(self, schedule_version):
     if not self.SetSchedule(int(schedule_version)):
         return
     template = JINJA_ENVIRONMENT.get_template(
         'scheduling/edit_schedule.html')
     event_keys = set([
         r.event for r in ScheduleRound.query(
             ScheduleRound.schedule == self.schedule.key).iter()
     ])
     events = [
         e.get() for e in sorted(event_keys, key=lambda e: e.get().rank)
     ]
     stages = (ScheduleStage.query(
         ScheduleRound.schedule == self.schedule.key).order(
             ScheduleRound.number).fetch())
     self.response.write(
         template.render({
             'c': common.Common(self),
             'competition': self.competition,
             'schedule': self.schedule,
             'events': events,
             'stages': stages,
             'new_stage_id': random.randint(2**4, 2**10),
             'colors': sorted(Colors.keys()),
         }))
Exemple #3
0
    def GetImpl(handler, schedule, event):
        rounds = ScheduleRound.query(
            ndb.AND(ScheduleRound.schedule == schedule.key,
                    ScheduleRound.event == event.key)).order(
                        ScheduleRound.number).fetch()
        time_blocks_by_round = collections.defaultdict(list)
        for time_block in (ScheduleTimeBlock.query(
                ScheduleTimeBlock.schedule == schedule.key).order(
                    ScheduleTimeBlock.start_time).iter()):
            time_blocks_by_round[time_block.round].append(time_block)

        stages = (ScheduleStage.query(
            ScheduleStage.schedule == schedule.key).order(
                ScheduleStage.number).fetch())
        competition_days = []
        current_date = schedule.start_date
        while current_date <= schedule.end_date:
            competition_days.append(current_date)
            current_date += datetime.timedelta(days=1)

        template = JINJA_ENVIRONMENT.get_template(
            'scheduling/event_details.html')
        return template.render({
            'c': common.Common(handler),
            'rounds': rounds,
            'event': event,
            'time_blocks': time_blocks_by_round,
            'new_ids': {
                r.key: '%s_%d' % (r.key.id(), random.randint(2**4, 2**32))
                for r in rounds
            },
            'stages': stages,
            'competition_days': competition_days,
        })
    def get(self, schedule_version, event_id):
        if not self.SetSchedule(int(schedule_version)):
            return
        event = Event.get_by_id(event_id)
        if not event:
            self.response.set_code(400)
            return
        rounds = ScheduleRound.query(
            ndb.AND(ScheduleRound.schedule == self.schedule.key,
                    ScheduleRound.event == event.key)).order(
                        ScheduleRound.number).fetch()
        time_blocks_by_round = collections.defaultdict(list)
        for time_block in (ScheduleTimeBlock.query(
                ScheduleTimeBlock.schedule == self.schedule.key).order(
                    ScheduleTimeBlock.start_time).iter()):
            time_blocks_by_round[time_block.round].append(time_block)
        # Immediately after adding a TimeBlock, it may not have propagated to the datastore.
        # So we force retrieval of the just-added TimeBlock.
        if 'include_time_block' in self.request.GET:
            time_block = ScheduleTimeBlock.get_by_id(
                self.request.GET['include_time_block'])
            found = False
            for old_time_block in time_blocks_by_round[time_block.round]:
                if old_time_block.key == time_block.key:
                    found = True
            if not found:
                time_blocks_by_round[time_block.round].append(time_block)
                time_blocks_by_round[time_block.round].sort(
                    key=lambda tb: tb.GetStartTime())

        stages = (ScheduleStage.query(
            ScheduleStage.schedule == self.schedule.key).order(
                ScheduleStage.number).fetch())
        competition_days = []
        current_date = self.schedule.start_date
        while current_date <= self.schedule.end_date:
            competition_days.append(current_date)
            current_date += datetime.timedelta(days=1)

        template = JINJA_ENVIRONMENT.get_template(
            'scheduling/event_details.html')
        self.response.write(
            template.render({
                'c': common.Common(self),
                'rounds': rounds,
                'event': event,
                'time_blocks': time_blocks_by_round,
                'new_ids': {
                    r.key: '%s_%d' % (r.key.id(), random.randint(2**4, 2**32))
                    for r in rounds
                },
                'stages': stages,
                'competition_days': competition_days,
            }))
Exemple #5
0
    def post(self, schedule_version):
        if not self.SetSchedule(int(schedule_version)):
            return
        r = ScheduleRound.get_by_id(self.request.POST['round-id'])
        if not r:
            self.response.set_status(400)
            return
        r.num_groups = int(self.request.POST['num-groups'])
        r.num_staff_groups = int(self.request.POST['num-staff-groups'])
        r.put()

        self.response.write(
            EventDetailsHandler.GetImpl(self, self.schedule, r.event.get()))
Exemple #6
0
def ScheduleToWcif(schedule, competition, wca_competition):
    output_dict = {}
    if schedule.start_date:
        output_dict['startDate'] = schedule.start_date.strftime('%Y-%m-%d')
        output_dict['numberOfDays'] = (
            (schedule.end_date - schedule.start_date).days + 1)
    # The CubingUSA scheduling system is not designed to support competitions
    # with more than one venue.
    venue_dict = {}
    venue_dict['id'] = 0
    # TODO: pass along the venue information from the WCA export.
    if wca_competition:
        venue_dict['latitude'] = wca_competition.latitude / 1000000.
        venue_dict['longitude'] = wca_competition.longitude / 1000000.
    venue_dict['timezone'] = competition.timezone

    all_stages = ScheduleStage.query(
        ScheduleStage.schedule == schedule.key).fetch()
    all_rounds = ScheduleRound.query(
        ScheduleRound.schedule == schedule.key).fetch()

    time_blocks_by_stage = collections.defaultdict(list)
    for t in (ScheduleTimeBlock.query(
            ScheduleTimeBlock.schedule == schedule.key).order(
                ScheduleTimeBlock.start_time).iter()):
        time_blocks_by_stage[t.stage.id()].append(t)

    groups_by_stage_and_time_block = (
        collections.defaultdict(lambda: collections.defaultdict(list)))
    for g in (ScheduleGroup.query(
            ScheduleGroup.schedule == schedule.key).order(
                ScheduleGroup.start_time).iter()):
        groups_by_stage_and_time_block[g.stage.id()][g.time_block.id()].append(
            g)

    venue_dict['rooms'] = []
    for stage in all_stages:
        venue_dict['rooms'].append(
            StageToWcif(stage, time_blocks_by_stage[stage.key.id()],
                        groups_by_stage_and_time_block[stage.key.id()]))
    output_dict['venues'] = [venue_dict]

    extension_dict = {}
    extension_dict['datastoreId'] = schedule.key.id()
    extension_dict['creationTime'] = (ToLocalizedTime(
        schedule.creation_time, competition.timezone).isoformat())
    extension_dict['lastUpdateTime'] = (ToLocalizedTime(
        schedule.last_update_time, competition.timezone).isoformat())
    AddExtension('Schedule', extension_dict, output_dict)

    return output_dict
Exemple #7
0
    def get(self, schedule_version):
        if not self.SetSchedule(int(schedule_version)):
            return

        existing_groups = ScheduleGroup.query(
            ScheduleGroup.schedule == self.schedule.key).fetch(keys_only=True)

        time_blocks_by_round = collections.defaultdict(list)
        rounds = {}

        for time_block in ScheduleTimeBlock.query(
                ScheduleTimeBlock.schedule == self.schedule.key).iter():
            time_blocks_by_round[time_block.round].append(time_block)

        for r in ScheduleRound.query(
                ScheduleRound.schedule == self.schedule.key).iter():
            rounds[r.key] = r

        groups_to_put = []

        for round_key in rounds:
            r = rounds[round_key]
            if not r.num_groups:
                continue
            time_blocks = time_blocks_by_round[round_key]
            time_blocks_by_staff_only = collections.defaultdict(list)
            for time_block in time_blocks:
                time_blocks_by_staff_only[time_block.staff_only].append(
                    time_block)
            num_by_stage = collections.defaultdict(lambda: 0)
            round_groups = CreateGroups(
                self.schedule, time_blocks_by_staff_only[False], r,
                num_by_stage, r.num_groups - (r.num_staff_groups or 0))
            if time_blocks_by_staff_only[True]:
                num_by_stage = collections.defaultdict(lambda: 0)
                round_groups.extend(
                    CreateGroups(self.schedule,
                                 time_blocks_by_staff_only[True], r,
                                 num_by_stage, r.num_staff_groups))
            groups_to_put.extend(round_groups)

        ndb.delete_multi(existing_groups)
        ndb.put_multi(groups_to_put)

        self.schedule.last_update = datetime.datetime.now()
        self.schedule.put()
        self.redirect(
            webapp2.uri_for('edit_schedule',
                            competition_id=self.competition.key.id(),
                            schedule_version=self.schedule.key.id()))
Exemple #8
0
    def __init__(self, user, competition, schedule=None):
        self.user = user
        self.competition = competition
        if schedule:
            self.schedule = schedule
        else:
            self.schedule = Schedule.query(
                ndb.AND(Schedule.competition == competition.key,
                        Schedule.is_live == True)).get()
        if not self.schedule:
            return

        self.events = {}
        self.event_keys = []
        self.stage_ids = set()
        for r in ScheduleRound.query(
                ScheduleRound.schedule == self.schedule.key).iter():
            if r.event.id() not in self.events:
                self.events[r.event.id()] = EventDetails(r.event)
                self.event_keys.append(r.event)
            self.events[r.event.id()].AddRound(r)

        for t in (ScheduleTimeBlock.query(
                ndb.AND(ScheduleTimeBlock.schedule == self.schedule.key,
                        ScheduleTimeBlock.staff_only == False)).order(
                            ScheduleTimeBlock.start_time).iter()):
            self.events[t.round.get().event.id()].AddTimeBlock(t)
            self.stage_ids.add(t.stage.id())
        if user and user.wca_person:
            self.ranks_single = {
                r.event.id(): r
                for r in RankSingle.query(
                    RankSingle.person == user.wca_person).iter()
            }
            self.ranks_average = {
                r.event.id(): r
                for r in RankAverage.query(
                    RankAverage.person == user.wca_person).iter()
            }
        else:
            self.ranks_single = {}
            self.ranks_average = {}

        self.has_qualifying_number = False
Exemple #9
0
    def get(self):
        OAuthBaseHandler.get(self)
        if not self.auth_token:
            return

        competition_id = self.handler_data
        if not self.SetCompetition(competition_id):
            return

        response = self.GetWcaApi('/api/v0/competitions/%s/wcif' %
                                  competition_id)
        if response.status != 200:
            self.redirect(webapp2.uri_for('index', unknown=1))
            return
        response_json = json.loads(response.read())

        objects_to_put = []
        schedule = Schedule()
        schedule.competition = self.competition.key
        schedule.creation_time = datetime.datetime.now()
        schedule.last_update_time = schedule.creation_time
        schedule.is_live = False
        schedule.put()
        for event in response_json['events']:
            event_key = ndb.Key(Event, event['id'])
            round_num = 0
            next_round_count = 0
            for round_json in event['rounds']:
                round_num += 1
                round_object = ScheduleRound(id=ScheduleRound.Id(
                    schedule.key.id(), event['id'], round_num))
                round_object.schedule = schedule.key
                round_object.event = event_key
                round_object.number = round_num
                round_object.is_final = len(event['rounds']) == round_num
                round_object.format = ndb.Key(Format, round_json['format'])
                if round_json['cutoff']:
                    round_object.cutoff = round_json['cutoff']['attemptResult']
                if round_json['timeLimit'] and round_json['timeLimit'][
                        'centiseconds']:
                    round_object.time_limit = round_json['timeLimit'][
                        'centiseconds']
                round_object.wcif = json.dumps(round_json)
                if next_round_count:
                    round_object.num_competitors = next_round_count

                objects_to_put.append(round_object)
                advancement_condition = round_json['advancementCondition']
                if advancement_condition and advancement_condition[
                        'type'] == 'ranking':
                    next_round_count = advancement_condition['level']
                else:
                    next_round_count = 0

        ndb.put_multi(objects_to_put)
        self.redirect(
            webapp2.uri_for('edit_schedule',
                            schedule_version=schedule.key.id()))
Exemple #10
0
def ImportTimeBlock(activity_data, schedule, stage, out, time_blocks, groups):
    if 'id' not in activity_data:
        out.errors.append('activityCode missing from Activity.')
        return
    if 'activityCode' not in activity_data:
        out.errors.append('activityCode missing from Activity %d.' %
                          activity_data['id'])
        return
    try:
        activity_code = ActivityCode.ParseCode(activity_data['activityCode'])
    except Exception as e:
        out.errors.append(e.message)
        return

    if activity_code.other_string:
        # TODO: support non-event Activities.
        return

    if not activity_code.event_id:
        out.errors.append('Missing event ID for activity %s' %
                          activity_data['activityCode'])
        return
    if not activity_code.round_id:
        # We ignore Activities that are not specific to a round.
        return

    if 'startTime' not in activity_data:
        out.errors.append('Missing startTime for activity %s' %
                          activity_data['activityCode'])
        return
    if 'endTime' not in activity_data:
        out.errors.append('Missing endTime for activity %s' %
                          activity_data['activityCode'])
        return

    extension = GetExtension('ScheduleTimeBlock', activity_data)

    round_id = ScheduleRound.Id(schedule.key.id(), activity_code.event_id,
                                activity_code.round_id)
    time_block_id = '%s_%d' % (round_id, activity_data['id'])

    if time_block_id in time_blocks:
        time_block = time_blocks.pop(time_block_id)
    else:
        time_block = ScheduleTimeBlock(id=time_block_id)

    time_block.schedule = schedule.key
    time_block.round = ndb.Key(ScheduleRound, round_id)
    time_block.stage = stage.key
    if activity_code.attempt:
        time_block.attempt = activity_code.attempt

    time_block.start_time = timezones.StripTimezone(
        dateutil.parser.parse(activity_data['startTime']))
    time_block.end_time = timezones.StripTimezone(
        dateutil.parser.parse(activity_data['endTime']))

    if 'staffOnly' in extension:
        time_block.staff_only = extension['staffOnly']

    if 'childActivities' in activity_data:
        for child_activity in activity_data['childActivities']:
            ImportData(child_activity, time_block, out, groups)

    out.entities_to_put.append(time_block)
Exemple #11
0
def ImportEvents(wcif_data, schedule_key, out):
    existing_rounds = {
        e.key.id(): e
        for e in ScheduleRound.query(
            ScheduleRound.schedule == schedule_key).iter()
    }

    all_event_ids = set([e.key.id() for e in Event.query().iter()])
    all_formats = set([f.key.id() for f in Format.query().iter()])

    for event in wcif_data['events']:
        if 'id' not in event:
            out.errors.append(
                'Malformed WCIF: missing \'id\' field for event.')
            continue
        if event['id'] not in all_event_ids:
            out.errors.append('Unrecognized event ID \'%s\'' % event['id'])
            continue
        event_key = ndb.Key(Event, event['id'])
        round_num = 0
        next_round_count = 0
        for round_json in event['rounds']:
            round_num += 1
            round_id = ScheduleRound.Id(schedule_key.id(), event['id'],
                                        round_num)
            if round_id in existing_rounds:
                round_object = existing_rounds.pop(round_id)
            else:
                round_object = ScheduleRound(id=round_id)
            round_object.schedule = schedule_key
            round_object.event = event_key
            round_object.number = round_num
            round_object.is_final = len(event['rounds']) == round_num
            if 'format' not in round_json:
                out.errors.append(
                    'Malformed WCIF: missing \'format\' field for %s' %
                    round_id)
                continue
            if round_json['format'] not in all_formats:
                out.errors.append('Unrecognized format ID \'%s\'' %
                                  round_json['format'])
                continue
            round_object.format = ndb.Key(Format, round_json['format'])
            if 'cutoff' in round_json and round_json['cutoff']:
                round_object.cutoff = round_json['cutoff']['attemptResult']
            if ('timeLimit' in round_json and round_json['timeLimit']
                    and 'centiseconds' in round_json['timeLimit']
                    and round_json['timeLimit']['centiseconds']):
                round_object.time_limit = round_json['timeLimit'][
                    'centiseconds']
            round_object.wcif = json.dumps(round_json)
            if next_round_count:
                round_object.num_competitors = next_round_count

            next_round_count = 0
            if 'advancementCondition' in round_json:
                advancement_condition = round_json['advancementCondition']
                if (advancement_condition and 'type' in advancement_condition
                        and advancement_condition['type'] == 'ranking'):
                    next_round_count = advancement_condition['level']
            out.entities_to_put.append(round_object)
    out.entities_to_delete.extend([r for r in existing_rounds.itervalues()])

    # Also look for time blocks and groups that are now unused.
    for obj_class in (ScheduleTimeBlock, ScheduleGroup):
        for obj in obj_class.query(obj_class.schedule == schedule_key).iter():
            if obj.round.id() in existing_rounds:
                out.entities_to_delete.append(obj)
Exemple #12
0
    def get(self, competition_id):
        # Unlike most scheduling handlers, it's okay here if the competition doesn't
        # exist, because that may just mean the user is creating the competition
        # here for the first time.  In this case redirect to /update.
        if not ScheduleCompetition.get_by_id(competition_id):
            self.redirect_to('update_competition',
                             competition_id=competition_id)
            return
        if not self.SetCompetition(competition_id):
            return
        timezones_and_times = [
            (timezone, datetime.datetime.now(
                pytz.timezone(timezone)).strftime('%I:%M %p'))
            for timezone in pytz.country_timezones('us')
        ]
        schedule_versions = Schedule.query(
            Schedule.competition == self.competition.key).fetch()

        # We look at the live schedule, or the most-recently updated one, and make
        # sure that it has events and start/end dates.
        schedule_for_staff_signup = None
        has_live_schedule = False
        if schedule_versions:
            for schedule in schedule_versions:
                if schedule.is_live:
                    schedule_for_staff_signup = schedule
                    has_live_schedule = True
            if not schedule_for_staff_signup:
                schedule_for_staff_signup = sorted(
                    schedule_versions, key=lambda s: s.last_update_time)[-1]
            has_rounds = (ScheduleRound.query(
                ScheduleRound.schedule ==
                schedule_for_staff_signup.key).iter().has_next())

        championships = Championship.query(Championship.competition == ndb.Key(
            Competition, competition_id)).fetch()
        if championships:
            if championships[0].residency_deadline:
                residency_deadline = timezones.ToLocalizedTime(
                    championships[0].residency_deadline,
                    self.competition.timezone or 'America/New_York')
            else:
                # If the residency deadline hasn't been set, use the day before the
                # competition starts.
                residency_deadline = (
                    datetime.datetime.combine(
                        championships[0].competition.get().start_date,
                        datetime.time(0, 0, 0)) -
                    datetime.timedelta(days=1)).replace(tzinfo=pytz.timezone(
                        self.competition.timezone or 'America/New_York'))
        else:
            residency_deadline = None

        template = JINJA_ENVIRONMENT.get_template(
            'scheduling/edit_competition.html')
        self.response.write(
            template.render({
                'c':
                common.Common(self),
                'competition':
                self.competition,
                'timezones_and_times':
                timezones_and_times,
                'schedule_versions':
                schedule_versions,
                'staff_signup_enabled':
                schedule_for_staff_signup
                and schedule_for_staff_signup.start_date and has_rounds,
                'has_live_schedule':
                has_live_schedule,
                'residency_deadline':
                residency_deadline
            }))