class PlayerInfoForm(forms.Form): id = forms.IntegerField(required=True) name = StrippedCharField(required=False, label=_('Name')) romanized_name = StrippedCharField( required=False, label=_('Romanized name') ) birthday = forms.DateField(required=False, label=_('Birthday')) country = forms.ChoiceField( choices=data.countries, required=False, label=_('Country') ) def commit(self): data = dict(self.cleaned_data) player = Player.objects.get(id=data['id']) for k, v in data.items(): if getattr(player, k) != v: setattr(player, k, v) print(k, v) player.save() return player
class ReorderForm(forms.Form): order = StrippedCharField(max_length=10000, required=True) # {{{ Constructor def __init__(self, request=None, event=None): if request is not None: super(ReorderForm, self).__init__(request.POST) else: super(ReorderForm, self).__init__() # }}} # {{{ Custom validation def clean_order(self): try: ids = [int(s) for s in self.cleaned_data['order'].split(',') if s.strip() != ''] events = Event.objects.in_bulk(ids) except: raise ValidationError(_('Unable to get these events.')) return [events[i] for i in ids] # }}} # {{{ update_event: Pushes changes def update_event(self, event): ret = [] if not self.is_valid(): ret.append(Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append(Message(error=error, field=self.fields[field].label)) return ret if len(self.cleaned_data['order']) != event.get_immediate_children().count(): # Translate: Order as in an ordering, e.g. 2, 7, 5… return [Message(_('Order invalid, try again?'), type=Message.ERROR)] for e in self.cleaned_data['order']: if e.parent != event: return [Message(_('Non-child event found. This should never happen.'), type=Message.ERROR)] min_idx = min([e.idx for idx in self.cleaned_data['order']]) for idx, e in enumerate(self.cleaned_data['order']): e.set_idx(min_idx + idx) return [Message(_( # Translators: Children as in sub-events. 'Successfully reordered %i children. Any inconsistencies will be fixed next update ' '(no more than six hours away).' ) % len(self.cleaned_data['order']), type=Message.SUCCESS)]
class AddForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label=_('Name')) type = forms.ChoiceField(choices=EVENT_TYPES, required=True, label=_('Type')) noprint = forms.BooleanField(required=False, label=_('No Print')) closed = forms.BooleanField(required=False, label=_('Closed')) # {{{ Constructor def __init__(self, request=None, event=None): if request is not None: super(AddForm, self).__init__(request.POST) else: super(AddForm, self).__init__( initial={ 'type': TYPE_EVENT if event.type == TYPE_CATEGORY else TYPE_ROUND, 'noprint': False, 'closed': event.closed }) self.label_suffix = '' # }}} # {{{ update_event: Pushes changes def update_event(self, event): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret event.add_child( self.cleaned_data['name'], self.cleaned_data['type'], self.cleaned_data['noprint'], self.cleaned_data['closed'], ) ret.append(Message(_('Added a subevent.'), type=Message.SUCCESS)) return ret
class StoryModForm(forms.Form): player = forms.ChoiceField(required=True, label=_('Player')) date = forms.DateField(required=True, label=_('Date')) text = StrippedCharField(max_length=200, required=True, label=_('Text')) # {{{ Constructor def __init__(self, request=None, event=None): if request is not None: super(StoryModForm, self).__init__(request.POST) else: super(StoryModForm, self).__init__(initial={'date': event.latest}) matches = event.get_immediate_matchset() players = Player.objects.filter( Q(id__in=matches.values('pla')) | Q(id__in=matches.values('plb'))) self.fields['player'].choices = [(str(p.id), str(p)) for p in players] self.label_suffix = '' self.existing_stories = Player.objects.filter(story__event=event) # }}} # {{{ update_event: Pushes changes def update_event(self, event): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret story = Story( event=event, player_id=self.cleaned_data['player'], date=self.cleaned_data['date'], text=self.cleaned_data['text'], ) story.save() # Translators: Stories are the dots on a player's rating chart ret.append(Message(_('Added a story.'), type=Message.SUCCESS)) return ret
class APIKeyForm(forms.Form): organization = StrippedCharField(max_length=200, required=True, label=_('Name/organization')) contact = forms.EmailField(max_length=200, required=True, label=_('Contact')) # {{{ Constructor def __init__(self, request=None, player=None): if request is not None: super(APIKeyForm, self).__init__(request.POST) else: super(APIKeyForm, self).__init__() self.label_suffix = '' # }}} # {{{ add_key: Adds key if valid, returns messages def add_key(self): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret key = APIKey(organization=self.cleaned_data['organization'], contact=self.cleaned_data['contact'], requests=0) key.generate_key() key.save() ret.append( Message( _("Your API key is <code>%s</code>. Please keep it safe.") % key.key, type=Message.SUCCESS)) return ret
class AddEventsForm(forms.Form): parent_id = forms.IntegerField(required=True, label=_('Parent ID')) predef_names = forms.ChoiceField(choices=[ ('other', _('Other')), ('Group Stage, Playoffs', _('Group stage and playoffs')), ('Group A,Group B,Group C,Group D', _('Groups A through D')), ('Group A,Group B,Group C,Group D,Group E,Group F,Group G,Group H', _('Groups A through H')), ('Ro64,Ro32,Ro16,Ro8,Ro4,Final', _('Ro64→Final')), ('Ro32,Ro16,Ro8,Ro4,Final', _('Ro32→Final')), ('Ro16,Ro8,Ro4,Final', _('Ro16→Final')), ('Ro8,Ro4,Final', _('Ro8→Final')), ('Ro4,Final', _('Ro4→Final')), ('Ro64,Ro32,Ro16,Ro8,Ro4,Third place match,Final', _('Ro64→Final + 3rd place')), ('Ro32,Ro16,Ro8,Ro4,Third place match,Final', _('Ro32→Final + 3rd place')), ('Ro16,Ro8,Ro4,Third place match,Final', _('Ro16→Final + 3rd place')), ('Ro8,Ro4,Third place match,Final', _('Ro8→Final + 3rd place')), ('Ro4,Third place match,Final', _('Ro4→Final + 3rd place')), ('Early rounds,Ro64,Ro32,Ro16,Ro8,Ro4,Final', _('Ro64→Final + early rounds')), ('Early rounds,Ro32,Ro16,Ro8,Ro4,Final', _('Ro32→Final + early rounds')), ('Early rounds,Ro16,Ro8,Ro4,Final', _('Ro16→Final + early rounds')), ('Early rounds,Ro8,Ro4,Final', _('Ro8→Final + early rounds')), ('Early rounds,Ro4,Final', _('Ro4→Final + early rounds')), ('Early rounds,Ro64,Ro32,Ro16,Ro8,Ro4,Third place match,Final', _('Ro64→Final + 3rd place and early rounds')), ('Early rounds,Ro32,Ro16,Ro8,Ro4,Third place match,Final', _('Ro32→Final + 3rd place and early rounds')), ('Early rounds,Ro16,Ro8,Ro4,Third place match,Final', _('Ro16→Final + 3rd place and early rounds')), ('Early rounds,Ro8,Ro4,Third place match,Final', _('Ro8→Final + 3rd place and early rounds')), ('Early rounds,Ro4,Third place match,Final', _('Ro4→Final + 3rd place and early rounds')), ('WB,LB,Final', _('WB, LB, Final')), ('Round 1,Round 2', _('LB: Round 1->Round 2')), ('Round 1,Round 2,Round 3,Round 4', _('LB: Round 1->Round 4')), ('Round 1,Round 2,Round 3,Round 4,Round 5,Round 6', _('LB: Round 1->Round 6')), ('Round 1,Round 2,Round 3,Round 4,Round 5,Round 6,Round 7,Round 8', _('LB: Round 1->Round 8')), ], required=True, label=_('Predefined names')) custom_names = StrippedCharField(max_length=400, required=False, label=_('Custom names')) type = forms.ChoiceField(choices=EVENT_TYPES, required=True, label=_('Type')) big = forms.BooleanField(required=False, label=_('Big'), initial=False) noprint = forms.BooleanField(required=False, label=_('No print'), initial=False) def __init__(self, request=None): if request is None: super(AddEventsForm, self).__init__() else: super(AddEventsForm, self).__init__(request.POST) if 'commit' in request.POST: self.action = 'add' else: self.action = 'close' self.label_suffix = '' # Custom validation def clean_parent_id(self): try: if int(self.cleaned_data['parent_id']) != -1: return Event.objects.get( id=int(self.cleaned_data['parent_id'])) return None except: raise ValidationError( _('Could not find event ID %s.') % self.cleaned_data['parent_id']) def clean(self): if self.action != 'add': if self.cleaned_data['parent_id'] is None: raise ValidationError(_('Must specify an event to close.')) return self.cleaned_data if self.cleaned_data['predef_names'] == 'other' and self.cleaned_data[ 'custom_names'] in ['', None]: raise ValidationError(_('No event names specified.')) names = (self.cleaned_data['predef_names'] if self.cleaned_data['predef_names'] != 'other' else self.cleaned_data['custom_names']) self.cleaned_data['names'] = [ s.strip() for s in names.split(',') if s.strip() != '' ] return self.cleaned_data # Commit changes def commit(self): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: if field == '__all__': ret.append(Message(error, type=Message.ERROR)) else: ret.append( Message(error=error, field=self.fields[field].label)) return ret if self.action == 'add': adder = (self.cleaned_data['parent_id'].add_child if self.cleaned_data['parent_id'] is not None else Event.add_root) for name in self.cleaned_data['names']: adder( name=name, type=self.cleaned_data['type'], big=self.cleaned_data['big'], noprint=self.cleaned_data['noprint'], ) ret.append( Message(ungettext_lazy('Successfully created %i new event.', 'Successfully created %i new events.', len(self.cleaned_data['names'])) % len(self.cleaned_data['names']), type=Message.SUCCESS)) elif self.action == 'close': self.cleaned_data['parent_id'].close() ret.append( Message(_('Successfully closed event.'), type=Message.SUCCESS)) return ret
class AddMatchesForm(forms.Form): eventtext = StrippedCharField(max_length=200, required=False, label=_('Event')) date = forms.DateField(required=True, label=_('Date')) game = forms.ChoiceField(choices=GAMES, label=_('Game version'), initial=LOTV) offline = forms.BooleanField(required=False, label=_('Offline'), initial=False) source = StrippedCharField(max_length=1000, required=False, label=_('Source')) contact = StrippedCharField(max_length=1000, required=False, label=_('Contact')) notes = forms.CharField(max_length=10000, required=False, label=_('Notes'), initial='') matches = forms.CharField(max_length=10000, required=True, label=_('Matches'), initial='') def __init__(self, is_adm, request=None): if request is not None: super(AddMatchesForm, self).__init__(request.POST) self.close_after = 'commit_close' in request.POST self.eobj = etn(lambda: request.POST['eventobj']) else: super(AddMatchesForm, self).__init__(initial={'date': date.today()}) self.close_after = False self.requested_close_after = self.close_after self.label_suffix = '' self.is_adm = is_adm self.fields['eventobj'] = forms.ChoiceField( choices=[(e['id'], e['fullname']) for e in Event.objects.filter( closed=False, type__in=(TYPE_ROUND, TYPE_EVENT)).annotate( num_downlinks=Count('downlink')).filter( num_downlinks=1).order_by('idx').values( 'id', 'fullname')], required=False, label=_('Event'), ) # Validation def clean_eventtext(self): if self.is_adm: return self.cleaned_data['eventtext'] if self.cleaned_data['eventtext'] in [None, '']: raise ValidationError(_('This field is required.')) return self.cleaned_data['eventtext'] def clean_source(self): if self.is_adm: return self.cleaned_data['source'] if self.cleaned_data['source'] in [None, '']: raise ValidationError(_('This field is required.')) return self.cleaned_data['source'] def clean(self): if self.is_adm: try: self.cleaned_data['eventobj'] = Event.objects.get( id=int(self.eobj)) except: raise ValidationError(_('Could not find this event object.')) return self.cleaned_data # Parse the matches def parse_matches(self, submitter): self.messages = [] if not self.is_valid(): self.messages.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: self.messages.append( Message(error=error, field=self.fields[field].label)) return [] if not self.is_adm: self.prematchgroup = PreMatchGroup( date=self.cleaned_data['date'], event=self.cleaned_data['eventtext'], source=self.cleaned_data['source'], contact=self.cleaned_data['contact'], notes=self.cleaned_data['notes'], game=self.cleaned_data['game'], offline=self.cleaned_data['offline'], ) self.prematchgroup.save() error_lines, matches = [], [] for line in self.cleaned_data['matches'].splitlines(): if line.strip() == '': continue try: parse_results = parse_match(line.strip(), allow_archon=False) pla_query = parse_results['pla'] plb_query = parse_results['plb'] sca = parse_results['sca'] scb = parse_results['scb'] make_flag = 'MAKE' in parse_results['flags'] dup_flag = 'DUP' in parse_results['flags'] except pyparsing.ParseException as e: self.messages.append( Message(_("Could not parse '%(line)s' (%(error)s).") % { 'line': line, 'error': str(e) }, type=Message.ERROR)) self.close_after = False error_lines.append(line) continue pla_race_override = find_race_override(pla_query) plb_race_override = find_race_override(plb_query) try: match = self.make_match( pla_query, plb_query, pla_race_override, plb_race_override, sca, scb, make_flag, dup_flag, ) if match is None: error_lines.append(line) continue except Exception as e: self.messages.append( Message(_("Error creating match '%(line)s' (%(error)s).") % { 'line': line, 'error': str(e) }, type=Message.ERROR)) self.close_after = False error_lines.append(line) continue if self.is_adm: match.submitter = submitter matches.append(match) for m in matches: m.save() if len(matches) > 0: self.messages.append( Message(ungettext_lazy('Successfully added %i match.', 'Successfully added %i matches.', len(matches)) % len(matches), type=Message.SUCCESS)) if self.close_after: self.cleaned_data['eventobj'].close() self.messages.append( Message(_("Closed '%s'.") % self.cleaned_data['eventobj'].fullname, type=Message.SUCCESS)) elif self.requested_close_after: self.messages.append( Message(_("Did not close '%s'.") % self.cleaned_data['eventobj'].fullname, type=Message.INFO)) self.data = self.data.copy() self.data['matches'] = '\n'.join(error_lines) return matches # Auxiliary function for searching for players def get_player(self, query, make_flag): players = find_player(lst=query, make=make_flag, soft=False) printable = ' '.join(str(x) for x in query) if players.count() != 1: if self.is_adm: if players.count() == 0: self.messages.append( Message(_("Could not find player: '%s'.") % printable, type=Message.ERROR)) self.close_after = False elif players.count() > 1: self.messages.append( Message(_("Ambiguous player: '%s'.") % printable, type=Message.ERROR)) self.close_after = False return None return players.first() # Make matches (called from parse_matches). DOES NOT SAVE THEM. def make_match(self, pla_query, plb_query, pla_race_or, plb_race_or, sca, scb, make_flag, dup_flag): pla = self.get_player(pla_query, make_flag) plb = self.get_player(plb_query, make_flag) if (pla is None or plb is None) and self.is_adm: return None if not self.is_adm: match = PreMatch( group=self.prematchgroup, pla=pla, plb=plb, pla_string=' '.join(pla_query), plb_string=' '.join(plb_query), sca=sca, scb=scb, date=self.cleaned_data['date'], rca=pla_race_or, rcb=plb_race_or, ) return match else: match = Match( pla=pla, plb=plb, sca=sca, scb=scb, rca=pla_race_or or (pla.race if pla.race != 'S' else 'R'), rcb=plb_race_or or (plb.race if plb.race != 'S' else 'R'), date=self.cleaned_data['date'], treated=False, eventobj=self.cleaned_data['eventobj'], game=self.cleaned_data['game'], offline=self.cleaned_data['offline'], ) if check_duplicates(match, dup_flag): self.messages.append( Message( _("Could not make match %(pla)s vs %(plb)s: possible duplicate found." ) % { 'pla': pla.tag, 'plb': plb.tag }, type=Message.ERROR, )) self.close_after = False return None if 'R' in [match.rca, match.rcb]: self.messages.append( Message( _("Unknown race in %(pla)s vs %(plb)s: set to random.") % { 'pla': pla.tag, 'plb': plb.tag }, type=Message.WARNING, )) match.set_period() match.set_ratings() return match
class PlayerModForm(forms.Form): tag = StrippedCharField(max_length=30, required=True, label=_('Tag')) race = forms.ChoiceField(choices=RACES, required=True, label=_('Race')) name = StrippedCharField(max_length=100, required=False, label=_('Name')) romanized_name = StrippedCharField(max_length=100, required=False, label=_('Romanized Name')) akas = forms.CharField(max_length=200, required=False, label=_('AKAs')) birthday = forms.DateField(required=False, label=_('Birthday')) tlpd_id = forms.IntegerField(required=False, label=_('TLPD ID')) tlpd_db = forms.MultipleChoiceField(required=False, choices=TLPD_DBS, label=_('TLPD DB'), widget=forms.CheckboxSelectMultiple) lp_name = StrippedCharField(max_length=200, required=False, label=_('Liquipedia title')) sc2e_id = forms.IntegerField(required=False, label=_('SC2Earnings.com ID')) country = forms.ChoiceField(choices=data.countries, required=False, label=_('Country')) # {{{ Constructor def __init__(self, request=None, player=None): if request is not None: super(PlayerModForm, self).__init__(request.POST) else: super(PlayerModForm, self).__init__( initial={ 'tag': player.tag, 'race': player.race, 'country': player.country, 'name': player.name, 'romanized_name': player.romanized_name, 'akas': ', '.join(player.get_aliases()), 'birthday': player.birthday, 'sc2e_id': player.sc2e_id, 'lp_name': player.lp_name, 'tlpd_id': player.tlpd_id, 'tlpd_db': filter_flags(player.tlpd_db if player.tlpd_db else 0), }) self.label_suffix = '' # }}} # {{{ update_player: Pushes updates to player, responds with messages def update_player(self, player): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret def update(value, attr, setter, label): if value != getattr(player, attr): getattr(player, setter)(value) # Translators: Changed something (a noun). ret.append( Message(_('Changed %s.') % label, type=Message.SUCCESS)) update(self.cleaned_data['tag'], 'tag', 'set_tag', _('tag')) update(self.cleaned_data['race'], 'race', 'set_race', _('race')) update(self.cleaned_data['country'], 'country', 'set_country', _('country')) update(self.cleaned_data['name'], 'name', 'set_name', _('name')) update(self.cleaned_data['romanized_name'], 'romanized_name', 'set_romanized_name', _('romanized name')) update(self.cleaned_data['birthday'], 'birthday', 'set_birthday', _('birthday')) update(self.cleaned_data['tlpd_id'], 'tlpd_id', 'set_tlpd_id', _('TLPD ID')) update(self.cleaned_data['lp_name'], 'lp_name', 'set_lp_name', _('Liquipedia title')) update(self.cleaned_data['sc2e_id'], 'sc2e_id', 'set_sc2e_id', _('SC2Earnings.com ID')) update(sum([int(a) for a in self.cleaned_data['tlpd_db']]), 'tlpd_db', 'set_tlpd_db', _('TLPD DBs')) if player.set_aliases([ x for x in self.cleaned_data['akas'].split(',') if x.strip() != '' ]): ret.append(Message(_('Changed aliases.'), type=Message.SUCCESS)) return ret
class TeamModForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label=_('Name')) akas = forms.CharField(max_length=200, required=False, label=_('AKAs')) shortname = StrippedCharField(max_length=100, required=False, label=_('Name')) homepage = StrippedCharField(max_length=200, required=False, label=_('Homepage')) lp_name = StrippedCharField(max_length=200, required=False, label=_('Liquipedia title')) # {{{ Constructor def __init__(self, request=None, team=None): if request is not None: super(TeamModForm, self).__init__(request.POST) else: super(TeamModForm, self).__init__( initial={ 'name': team.name, 'akas': ', '.join(team.get_aliases()), 'shortname': team.shortname, 'homepage': team.homepage, 'lp_name': team.lp_name, }) self.label_suffix = '' # }}} # {{{ update_player: Pushes updates to player, responds with messages def update_team(self, team): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret def update(value, attr, setter, label): if value != getattr(team, attr): getattr(team, setter)(value) ret.append( Message(_('Changed %s.') % label, type=Message.SUCCESS)) update(self.cleaned_data['name'], 'name', 'set_name', _('name')) update(self.cleaned_data['lp_name'], 'lp_name', 'set_lp_name', _('Liquipedia title')) update(self.cleaned_data['shortname'], 'shortname', 'set_shortname', _('short name')) update(self.cleaned_data['homepage'], 'homepage', 'set_homepage', _('homepage')) if team.set_aliases(self.cleaned_data['akas'].split(',')): ret.append(Message(_('Changed aliases.'), type=Message.SUCCESS)) return ret
class EventModForm(forms.Form): name = StrippedCharField(max_length=100, required=True, label='Name') date = forms.DateField(required=False, label='Date') game = forms.ChoiceField(choices=[('nochange', _('No change'))] + GAMES, required=True, label=_('Game version')) offline = forms.ChoiceField(choices=[('nochange', _('No change')), ('online', _('Online')), ('offline', _('Offline'))], required=True, label=_('On/offline')) type = forms.ChoiceField( choices=[('nochange', _('No change'))] + EVENT_TYPES, # Translators: Type as in event type required=True, label=_('Type')) # Translators: Apply (changes) to… same_level = forms.BooleanField( required=False, label=_('Apply to all events on the same level')) homepage = StrippedCharField(max_length=200, required=False, label=_('Homepage')) tlpd_id = forms.IntegerField(required=False, label=_('TLPD ID')) tlpd_db = forms.MultipleChoiceField(required=False, choices=TLPD_DBS, label=_('TLPD DB'), widget=forms.CheckboxSelectMultiple) tl_thread = forms.IntegerField(required=False, label=_('TL thread')) lp_name = StrippedCharField(max_length=200, required=False, label=_('Liquipedia title')) # {{{ Constructor def __init__(self, request=None, event=None): if request is not None: super(EventModForm, self).__init__(request.POST) else: super(EventModForm, self).__init__( initial={ 'name': event.name, 'date': None, 'game': 'nochange', 'offline': 'nochange', 'type': event.type, 'same_level': False, 'homepage': event.homepage, 'tlpd_id': event.tlpd_id, 'tlpd_db': filter_flags( event.tlpd_db if event.tlpd_db else 0), 'tl_thread': event.tl_thread, 'lp_name': event.lp_name, }) self.label_suffix = '' # }}} # {{{ update_event: Pushes updates to event, responds with messages def update_event(self, event): ret = [] if not self.is_valid(): ret.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: ret.append( Message(error=error, field=self.fields[field].label)) return ret if self.cleaned_data['name'] != event.name: event.update_name(self.cleaned_data['name']) for e in event.get_children(id=False): e.update_name() ret.append(Message(_('Changed event name.'), type=Message.SUCCESS)) if self.cleaned_data['date'] is not None: nchanged = event.get_matchset().update( date=self.cleaned_data['date']) ret.append( Message( ungettext_lazy('Changed date for %i match.', 'Changed date for %i matches.', nchanged) % nchanged, type=Message.SUCCESS)) if self.cleaned_data['game'] != 'nochange': nchanged = event.get_matchset().update( game=self.cleaned_data['game']) ret.append( Message(ungettext_lazy('Changed game version for %i match.', 'Changed game version for %i matches.', nchanged) % nchanged, type=Message.SUCCESS)) if self.cleaned_data['offline'] != 'nochange': nchanged = event.get_matchset().update( offline=(self.cleaned_data['offline'] == 'offline')) ret.append( Message(ungettext_lazy('Changed on/offline for %i match.', 'Changed on/offline for %i matches.', nchanged) % nchanged, type=Message.SUCCESS)) events = [event] if not self.cleaned_data[ 'same_level'] else event.parent.get_immediate_children() nchanged = 0 for e in events: if e.type != self.cleaned_data['type']: e.change_type(self.cleaned_data['type']) nchanged += 1 if nchanged > 0: ret.append( Message( ungettext_lazy('Changed type for %i event.', 'Changed type for %i events.', nchanged) % nchanged, type=Message.SUCCESS)) def update(value, attr, setter, label): if value != getattr(event, attr): getattr(event, setter)(value) ret.append( Message(_('Changed %s.') % label, type=Message.SUCCESS)) update(self.cleaned_data['homepage'], 'homepage', 'set_homepage', _('homepage')) update(self.cleaned_data['tlpd_id'], 'tlpd_id', 'set_tlpd_id', _('TLPD ID')) update(self.cleaned_data['lp_name'], 'lp_name', 'set_lp_name', _('Liquipedia title')) update(self.cleaned_data['tl_thread'], 'tl_thread', 'set_tl_thread', _('TL thread')) update(sum([int(a) for a in self.cleaned_data['tlpd_db']]), 'tlpd_db', 'set_tlpd_db', _('TLPD DBs')) return ret
class SearchForm(forms.Form): after = forms.DateField(required=False, label=_('After'), initial=None) before = forms.DateField(required=False, label=_('Before'), initial=None) players = forms.CharField(max_length=10000, required=False, label=_('Involving players'), initial='') event = StrippedCharField(max_length=200, required=False, label=_('Event'), initial='') # Translators: Unassigned as in not assigned to an event. unassigned = forms.BooleanField(required=False, label=_('Only show unassigned matches')) bestof = forms.ChoiceField(choices=[ ('all', _('All')), ('3', _('Best of 3+')), ('5', _('Best of 5+')), ], required=False, label=_('Match format'), initial='all') offline = forms.ChoiceField( choices=[ ('both', _('Both')), ('offline', _('Offline')), ('online', _('Online')), ], required=False, label=_('On/offline'), initial='both', ) game = forms.ChoiceField(choices=[('all', _('All'))] + GAMES, required=False, label=_('Game version'), initial='all') # {{{ Constructor def __init__(self, request=None): if request is not None: super(SearchForm, self).__init__(request.GET) else: super(SearchForm, self).__init__() self.label_suffix = '' # }}} # {{{ search: Performs a search, returns a dict with results to be added to the rendering context def search(self, adm): # {{{ Check validity (lol) if not self.is_valid(): msgs = [] msgs.append( Message(_('Entered data was invalid, no changes made.'), type=Message.ERROR)) for field, errors in self.errors.items(): for error in errors: msgs.append( Message(error=error, field=self.fields[field].label)) return {'messages': msgs} # }}} matches = (Match.objects.all().prefetch_related( 'message_set').prefetch_related('pla', 'plb', 'period', 'eventobj').annotate( Count('eventobj__match'))) # {{{ All the easy filtering if self.cleaned_data['after'] is not None: matches = matches.filter(date__gte=self.cleaned_data['after']) if self.cleaned_data['before'] is not None: matches = matches.filter(date__lte=self.cleaned_data['before']) if self.cleaned_data['unassigned'] and adm: matches = matches.filter(eventobj__isnull=True) if self.cleaned_data['bestof'] == '3': matches = matches.filter(Q(sca__gte=2) | Q(scb__gte=2)) elif self.cleaned_data['bestof'] == '5': matches = matches.filter(Q(sca__gte=3) | Q(scb__gte=3)) if self.cleaned_data['offline'] != 'both': matches = matches.filter( offline=(self.cleaned_data['offline'] == 'offline')) if self.cleaned_data['game'] != 'all': matches = matches.filter(game=self.cleaned_data['game']) # }}} # {{{ Filter by event if self.cleaned_data['event'] != None: lex = shlex.shlex(self.cleaned_data['event'], posix=True) lex.wordchars += "'" lex.quotes = '"' terms = [s.strip() for s in list(lex) if s.strip() != ''] no_eventobj_q = Q(eventobj__isnull=True) for term in terms: no_eventobj_q &= Q(event__icontains=term) matches = matches.filter(no_eventobj_q | Q(eventobj__isnull=False, eventobj__fullname__iregex=( r"\s".join(r".*{}.*".format(term) for term in terms)))) # }}} ret = {'messages': []} # {{{ Filter by players lines = self.cleaned_data['players'].splitlines() lineno, ok, players = -1, True, [] for line in lines: lineno += 1 if line.strip() == '': continue pls = find_player(query=line, make=False) if not pls.exists(): ret['messages'].append( Message( # Translators: Matches here as in search matches. _("No matches found: '%s'.") % line.strip(), type=Message.ERROR)) ok = False else: if pls.count() > 1: ret['messages'].append( NotUniquePlayerMessage(line.strip(), pls, update=self['players'].auto_id, updateline=lineno, type=Message.WARNING)) players.append(list(pls)) if not ok: return ret pls = [] for p in players: pls += p if len(pls) > 1: matches = matches.filter(pla__in=pls, plb__in=pls) elif len(pls) == 1: matches = matches.filter(Q(pla__in=pls) | Q(plb__in=pls)) # }}} # {{{ Collect data ret['count'] = matches.count() if ret['count'] > 1000: ret['messages'].append( Message(_('Too many results (%i). Please add restrictions.') % ret['count'], type=Message.ERROR)) return ret matches = matches.order_by('-eventobj__latest', '-eventobj__idx', '-date', 'event', 'id') if 1 <= len(pls) <= 2: ret['matches'] = display_matches(matches, date=True, fix_left=pls[0], eventcount=True) ret['sc_my'], ret['sc_op'] = ( sum([m['pla']['score'] for m in ret['matches']]), sum([m['plb']['score'] for m in ret['matches']]), ) ret['msc_my'], ret['msc_op'] = ( sum([ 1 if m['pla']['score'] > m['plb']['score'] else 0 for m in ret['matches'] ]), sum([ 1 if m['plb']['score'] > m['pla']['score'] else 0 for m in ret['matches'] ]), ) ret['left'] = pls[0] if len(pls) == 2: ret['right'] = pls[1] else: ret['matches'] = display_matches(matches, date=True, eventcount=True) return ret
class PredictForm(forms.Form): format = forms.ChoiceField( choices=[(i, f['name']) for i, f in enumerate(FORMATS)], required=True, label=_('Format'), initial=0, ) bestof = StrippedCharField(max_length=100, required=True, label=_('Best of'), initial='1') players = forms.CharField(max_length=10000, required=True, label=_('Players'), initial='') # {{{ Constructor def __init__(self, request=None): self.messages = [] if request is not None: super(PredictForm, self).__init__(request.GET) else: super(PredictForm, self).__init__() self.label_suffix = '' # }}} # {{{ Custom validation of bestof and players def clean_bestof(self): try: ret = [] for a in map(int, self.cleaned_data['bestof'].split(',')): ret.append(a) assert (a > 0 and a % 2 == 1) return ret except: raise ValidationError( _("Must be a comma-separated list of positive odd integers (1,3,5,…)." )) def clean_players(self): lines = self.cleaned_data['players'].splitlines() lineno, ok, players = -1, True, [] self.messages = [] for line in lines: lineno += 1 if line.strip() == '': continue if line.strip() == '-' or line.strip().lower() == 'bye': players.append(None) continue pls = find_player(query=line, make=False) if not pls.exists(): # Translators: Matches as in search matches self.messages.append( Message(_("No matches found: '%s'.") % line.strip(), type=Message.ERROR)) ok = False elif pls.count() > 1: self.messages.append( NotUniquePlayerMessage(line.strip(), pls, update=self['players'].auto_id, updateline=lineno, type=Message.ERROR)) ok = False else: players.append(pls.first()) if not ok: raise ValidationError( _('One or more errors found in player list.')) return players # }}} # {{{ Combined validation of format, bestof and players def clean(self): self.cleaned_data['format'] = min( max(int(self.cleaned_data['format']), 0), len(FORMATS)) fmt = FORMATS[self.cleaned_data['format']] if 'players' in self.cleaned_data and not fmt['np-check'](len( self.cleaned_data['players'])): raise ValidationError(fmt['np-errmsg']) if 'bestof' in self.cleaned_data and not fmt['bo-check'](len( self.cleaned_data['bestof'])): raise ValidationError(fmt['bo-errmsg']) return self.cleaned_data # }}} # {{{ get_messages: Returns a list of messages after validation def get_messages(self): if not self.is_valid(): ret = [] for field, errors in self.errors.items(): for error in errors: if field == '__all__': ret.append(Message(error, type=Message.ERROR)) else: ret.append( Message(error=error, field=self.fields[field].label)) return self.messages + ret return self.messages # }}} # {{{ generate_url: Returns an URL to continue to (assumes validation has passed) def generate_url(self): return '/inference/%s/?bo=%s&ps=%s' % ( FORMATS[self.cleaned_data['format']]['url'], '%2C'.join([str(b) for b in self.cleaned_data['bestof']]), '%2C'.join([ str(p.id) if p is not None else '0' for p in self.cleaned_data['players'] ]), )