def get(self, event_key): self._require_admin() event = Event.get_by_id(event_key) if not event: self.abort(404) event.prepAwardsMatchesTeams() api_keys = ApiAuthAccess.query( ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch() event_medias = Media.query(Media.references == event.key).fetch(500) self.template_values.update({ "event": event, "medias": event_medias, "cache_key": event_controller.EventDetail('2016nyny').cache_key.format( event.key_name), "flushed": self.request.get("flushed"), "playoff_types": PlayoffType.type_names, "write_auths": api_keys, }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html') self.response.out.write(template.render(path, self.template_values))
def post(self, event_key): event_key = event_key.lower( ) # Normalize keys to lower case (TBA convention) # Start by allowing admins to edit any event user_has_auth = (self._user_bundle.user and self._user_bundle.is_current_user_admin) if not user_has_auth and self._user_bundle.user: # See if this user has any auth keys granted to its account now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query( ApiAuthAccess.owner == self._user_bundle.account.key, ApiAuthAccess.event_list == ndb.Key(Event, event_key), ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch() user_has_auth = any( self._validate_auth(auth, event_key) is None for auth in auth_tokens) if not user_has_auth: # If not, check if auth id/secret were passed as headers auth_id = self.request.headers.get('X-TBA-Auth-Id') if not auth_id: self._errors = json.dumps({ "Error": "Must provide a request header parameter 'X-TBA-Auth-Id'" }) self.abort(400) auth_sig = self.request.headers.get('X-TBA-Auth-Sig') if not auth_sig: self._errors = json.dumps({ "Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'" }) self.abort(400) auth = ApiAuthAccess.get_by_id(auth_id) expected_sig = md5.new('{}{}{}'.format( auth.secret if auth else None, self.request.path, self.request.body)).hexdigest() if not auth or expected_sig != auth_sig: logging.info("Auth sig: {}, Expected sig: {}".format( auth_sig, expected_sig)) self._errors = json.dumps( {"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"}) self.abort(401) # Checks event key is valid, correct auth types, and expiration error = self._validate_auth(auth, event_key) if error: self._errors = json.dumps({"Error": error}) self.abort(401) try: self._process_request(self.request, event_key) except ParserInputException, e: self._errors = json.dumps({"Error": e.message}) self.abort(400)
def get(self, event_key): self._require_admin() event = Event.get_by_id(event_key) if not event: self.abort(404) event.prepAwardsMatchesTeams() reg_sitevar = Sitevar.get_by_id("cmp_registration_hacks") api_keys = ApiAuthAccess.query(ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch() event_medias = Media.query(Media.references == event.key).fetch(500) self.template_values.update({ "event": event, "medias": event_medias, "cache_key": event_controller.EventDetail('2016nyny').cache_key.format(event.key_name), "flushed": self.request.get("flushed"), "playoff_types": PlayoffType.type_names, "write_auths": api_keys, "event_sync_disable": reg_sitevar and event_key in reg_sitevar.contents.get('divisions_to_skip', []), "set_start_day_to_last": reg_sitevar and event_key in reg_sitevar.contents.get('set_start_to_last_day', []), "skip_eventteams": reg_sitevar and event_key in reg_sitevar.contents.get('skip_eventteams', []), "event_name_override": next(iter(filter(lambda e: e.get("event") == event_key, reg_sitevar.contents.get("event_name_override", []))), {}).get("name", "") }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html') self.response.out.write(template.render(path, self.template_values))
def _ids_and_events(cls, suggestion): event_key = suggestion.contents['event_key'] account = suggestion.author.get() existing_keys = ApiAuthAccess.query( ApiAuthAccess.event_list == ndb.Key(Event, event_key)) existing_users = [ key.owner.get() if key.owner else None for key in existing_keys ] return suggestion.key.id(), Event.get_by_id(event_key), account, zip( existing_keys, existing_users), suggestion
def get(self): self._require_admin() auths = ApiAuthAccess.query().fetch(None) self.template_values.update({ 'auths': auths, }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/api_manage_auth.html') self.response.out.write(template.render(path, self.template_values))
def get(self): self._require_registration() push_sitevar = Sitevar.get_by_id('notifications.enable') if push_sitevar is None or not push_sitevar.values_json == "true": ping_enabled = "disabled" else: ping_enabled = "" # Compute myTBA statistics user = self.user_bundle.account.key num_favorites = Favorite.query(ancestor=user).count() num_subscriptions = Subscription.query(ancestor=user).count() # Compute suggestion statistics submissions_pending = Suggestion.query( Suggestion.review_state == Suggestion.REVIEW_PENDING, Suggestion.author == user).count() submissions_accepted = Suggestion.query( Suggestion.review_state == Suggestion.REVIEW_ACCEPTED, Suggestion.author == user).count() # Suggestion review statistics review_permissions = False num_reviewed = 0 total_pending = 0 if AccountPermissions.REVIEW_MEDIA in self.user_bundle.account.permissions: review_permissions = True num_reviewed = Suggestion.query( Suggestion.reviewer == user).count() total_pending = Suggestion.query( Suggestion.review_state == Suggestion.REVIEW_PENDING).count() # Fetch trusted API keys trusted_keys = ApiAuthAccess.query(ApiAuthAccess.owner == user).fetch() self.template_values['status'] = self.request.get('status') self.template_values[ 'webhook_verification_success'] = self.request.get( 'webhook_verification_success') self.template_values['ping_enabled'] = ping_enabled self.template_values['num_favorites'] = num_favorites self.template_values['num_subscriptions'] = num_subscriptions self.template_values['submissions_pending'] = submissions_pending self.template_values['submissions_accepted'] = submissions_accepted self.template_values['review_permissions'] = review_permissions self.template_values['num_reviewed'] = num_reviewed self.template_values['total_pending'] = total_pending self.template_values['trusted_keys'] = trusted_keys self.template_values['auth_type_names'] = AuthType.type_names self.response.out.write( jinja2_engine.render('account_overview.html', self.template_values))
def get(self): self._require_admin() auths = ApiAuthAccess.query().fetch() write_auths = filter(lambda auth: auth.is_write_key, auths) read_auths = filter(lambda auth: auth.is_read_key, auths) self.template_values.update({ 'write_auths': write_auths, 'read_auths': read_auths, }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/api_manage_auth.html') self.response.out.write(template.render(path, self.template_values))
def get(self): self._require_registration() notifications_enabled = NotificationsEnable.notifications_enabled() if not notifications_enabled: ping_enabled = "disabled" else: ping_enabled = "" # Compute myTBA statistics user = self.user_bundle.account.key num_favorites = Favorite.query(ancestor=user).count() num_subscriptions = Subscription.query(ancestor=user).count() # Compute suggestion statistics submissions_pending = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_PENDING, Suggestion.author==user).count() submissions_accepted = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_ACCEPTED, Suggestion.author==user).count() # Suggestion review statistics review_permissions = False num_reviewed = 0 total_pending = 0 if self.user_bundle.account.permissions: review_permissions = True num_reviewed = Suggestion.query(Suggestion.reviewer==user).count() total_pending = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_PENDING).count() # Fetch trusted API keys api_keys = ApiAuthAccess.query(ApiAuthAccess.owner == user).fetch() write_keys = filter(lambda key: key.is_write_key, api_keys) write_keys.sort(key=lambda key: key.event_list[0]) read_keys = filter(lambda key: key.is_read_key, api_keys) self.template_values['status'] = self.request.get('status') self.template_values['webhook_verification_success'] = self.request.get('webhook_verification_success') self.template_values['ping_sent'] = self.request.get('ping_sent') self.template_values['ping_enabled'] = ping_enabled self.template_values['num_favorites'] = num_favorites self.template_values['num_subscriptions'] = num_subscriptions self.template_values['submissions_pending'] = submissions_pending self.template_values['submissions_accepted'] = submissions_accepted self.template_values['review_permissions'] = review_permissions self.template_values['num_reviewed'] = num_reviewed self.template_values['total_pending'] = total_pending self.template_values['read_keys'] = read_keys self.template_values['write_keys'] = write_keys self.template_values['auth_write_type_names'] = AuthType.write_type_names self.response.out.write(jinja2_engine.render('account_overview.html', self.template_values))
def testRejectSuggestion(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm(suggestion_id) response = form.submit('verdict', value='reject').follow() self.assertEqual(response.status_int, 200) auths = ApiAuthAccess.query().fetch() self.assertEqual(len(auths), 0) # Make sure we mark the Suggestion as REJECTED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_REJECTED)
def get(self): self._require_registration() push_sitevar = Sitevar.get_by_id("notifications.enable") if push_sitevar is None or not push_sitevar.values_json == "true": ping_enabled = "disabled" else: ping_enabled = "" # Compute myTBA statistics user = self.user_bundle.account.key num_favorites = Favorite.query(ancestor=user).count() num_subscriptions = Subscription.query(ancestor=user).count() # Compute suggestion statistics submissions_pending = Suggestion.query( Suggestion.review_state == Suggestion.REVIEW_PENDING, Suggestion.author == user ).count() submissions_accepted = Suggestion.query( Suggestion.review_state == Suggestion.REVIEW_ACCEPTED, Suggestion.author == user ).count() # Suggestion review statistics review_permissions = False num_reviewed = 0 total_pending = 0 if self.user_bundle.account.permissions: review_permissions = True num_reviewed = Suggestion.query(Suggestion.reviewer == user).count() total_pending = Suggestion.query(Suggestion.review_state == Suggestion.REVIEW_PENDING).count() # Fetch trusted API keys trusted_keys = ApiAuthAccess.query(ApiAuthAccess.owner == user).fetch() self.template_values["status"] = self.request.get("status") self.template_values["webhook_verification_success"] = self.request.get("webhook_verification_success") self.template_values["ping_enabled"] = ping_enabled self.template_values["num_favorites"] = num_favorites self.template_values["num_subscriptions"] = num_subscriptions self.template_values["submissions_pending"] = submissions_pending self.template_values["submissions_accepted"] = submissions_accepted self.template_values["review_permissions"] = review_permissions self.template_values["num_reviewed"] = num_reviewed self.template_values["total_pending"] = total_pending self.template_values["trusted_keys"] = trusted_keys self.template_values["auth_type_names"] = AuthType.type_names self.response.out.write(jinja2_engine.render("account_overview.html", self.template_values))
def post(self, event_key): event_key = event_key.lower() # Normalize keys to lower case (TBA convention) # Start by allowing admins to edit any event user_has_auth = self._user_bundle.user and self._user_bundle.is_current_user_admin if not user_has_auth and self._user_bundle.user: # See if this user has any auth keys granted to its account now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query( ApiAuthAccess.owner == self._user_bundle.account.key, ApiAuthAccess.event_list == ndb.Key(Event, event_key), ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now), ).fetch() user_has_auth = any(self._validate_auth(auth, event_key) is None for auth in auth_tokens) if not user_has_auth: # If not, check if auth id/secret were passed as headers auth_id = self.request.headers.get("X-TBA-Auth-Id") if not auth_id: self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"}) self.abort(400) auth_sig = self.request.headers.get("X-TBA-Auth-Sig") if not auth_sig: self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"}) self.abort(400) auth = ApiAuthAccess.get_by_id(auth_id) expected_sig = md5.new( "{}{}{}".format(auth.secret if auth else None, self.request.path, self.request.body) ).hexdigest() if not auth or expected_sig != auth_sig: logging.info("Auth sig: {}, Expected sig: {}".format(auth_sig, expected_sig)) self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"}) self.abort(401) # Checks event key is valid, correct auth types, and expiration error = self._validate_auth(auth, event_key) if error: self._errors = json.dumps({"Error": error}) self.abort(401) try: self._process_request(self.request, event_key) except ParserInputException, e: self._errors = json.dumps({"Error": e.message}) self.abort(400)
def get(self): self._require_registration() push_sitevar = Sitevar.get_by_id('notifications.enable') if push_sitevar is None or not push_sitevar.values_json == "true": ping_enabled = "disabled" else: ping_enabled = "" # Compute myTBA statistics user = self.user_bundle.account.key num_favorites = Favorite.query(ancestor=user).count() num_subscriptions = Subscription.query(ancestor=user).count() # Compute suggestion statistics submissions_pending = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_PENDING, Suggestion.author==user).count() submissions_accepted = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_ACCEPTED, Suggestion.author==user).count() # Suggestion review statistics review_permissions = False num_reviewed = 0 total_pending = 0 if self.user_bundle.account.permissions: review_permissions = True num_reviewed = Suggestion.query(Suggestion.reviewer==user).count() total_pending = Suggestion.query(Suggestion.review_state==Suggestion.REVIEW_PENDING).count() # Fetch trusted API keys api_keys = ApiAuthAccess.query(ApiAuthAccess.owner == user).fetch() write_keys = filter(lambda key: key.is_write_key, api_keys) read_keys = filter(lambda key: key.is_read_key, api_keys) self.template_values['status'] = self.request.get('status') self.template_values['webhook_verification_success'] = self.request.get('webhook_verification_success') self.template_values['ping_sent'] = self.request.get('ping_sent') self.template_values['ping_enabled'] = ping_enabled self.template_values['num_favorites'] = num_favorites self.template_values['num_subscriptions'] = num_subscriptions self.template_values['submissions_pending'] = submissions_pending self.template_values['submissions_accepted'] = submissions_accepted self.template_values['review_permissions'] = review_permissions self.template_values['num_reviewed'] = num_reviewed self.template_values['total_pending'] = total_pending self.template_values['read_keys'] = read_keys self.template_values['write_keys'] = write_keys self.template_values['auth_write_type_names'] = AuthType.write_type_names self.response.out.write(jinja2_engine.render('account_overview.html', self.template_values))
def get(self): if not self.user_bundle.user: self.response.out.write(json.dumps([])) return now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query(ApiAuthAccess.owner == self.user_bundle.account.key, ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch() event_keys = [] for token in auth_tokens: event_keys.extend(token.event_list) events = ndb.get_multi(event_keys) details = [] for event in events: details.append({'value': event.key_name, 'label': "{} {}".format(event.year, event.name)}) self.response.out.write(json.dumps(details))
def get(self): if not self.user_bundle.user: self.response.out.write(json.dumps([])) return now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query(ApiAuthAccess.owner == self.user_bundle.account.key, ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch() event_keys = [] for token in auth_tokens: event_keys.extend(token.event_list) events = ndb.get_multi(event_keys) details = {} for event in events: details[event.key_name] = "{} {}".format(event.year, event.name) self.response.out.write(json.dumps(details))
def testExistingAuthKeys(self): self.loginUser() self.givePermission() existing_auth = ApiAuthAccess(id='tEsT_id_0', secret='321tEsTsEcReT', description='test', event_list=[ndb.Key(Event, '2016necmp')], auth_types_enum=[AuthType.EVENT_TEAMS]) existing_auth.put() suggestion_id = self.createSuggestion() form = self.getSuggestionForm(suggestion_id) response = form.submit('verdict', value='accept').follow() self.assertEqual(response.status_int, 200) auths = ApiAuthAccess.query().fetch() self.assertTrue(len(auths), 2)
def testAcceptSuggestionWithDifferentAuthTypes(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm(suggestion_id) form.get('auth_types', index=0).checked = True # MATCH_VIDEO form.get('auth_types', index=1).checked = True # EVENT_TEAMS form.get('auth_types', index=2).checked = False # EVENT_MATCHES response = form.submit('verdict', value='accept').follow() self.assertEqual(response.status_int, 200) # Make sure the ApiWrite object gets created auth = ApiAuthAccess.query().fetch()[0] self.assertIsNotNone(auth) self.assertEqual(auth.owner, self.account.key) self.assertListEqual(auth.event_list, [self.event.key]) self.assertSetEqual(set(auth.auth_types_enum), {AuthType.EVENT_TEAMS, AuthType.MATCH_VIDEO}) self.assertIsNotNone(auth.secret) self.assertIsNotNone(auth.expiration)
def testAcceptSuggestion(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm(suggestion_id) response = form.submit('verdict', value='accept').follow() self.assertEqual(response.status_int, 200) # Make sure the ApiWrite object gets created auth = ApiAuthAccess.query().fetch()[0] self.assertIsNotNone(auth) self.assertEqual(auth.owner, self.account.key) self.assertListEqual(auth.event_list, [self.event.key]) self.assertListEqual(auth.auth_types_enum, [AuthType.EVENT_MATCHES]) self.assertIsNotNone(auth.secret) self.assertIsNotNone(auth.expiration) # Make sure we mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_ACCEPTED)
def get(self, event_key): self._require_admin() event = Event.get_by_id(event_key) if not event: self.abort(404) event.prepAwardsMatchesTeams() api_keys = ApiAuthAccess.query(ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch() event_medias = Media.query(Media.references == event.key).fetch(500) self.template_values.update({ "event": event, "medias": event_medias, "cache_key": event_controller.EventDetail('2016nyny').cache_key.format(event.key_name), "flushed": self.request.get("flushed"), "playoff_types": PlayoffType.type_names, "write_auths": api_keys, }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html') self.response.out.write(template.render(path, self.template_values))
def _ids_and_events(cls, suggestion): event_key = suggestion.contents['event_key'] account = suggestion.author.get() existing_keys = ApiAuthAccess.query(ApiAuthAccess.event_list == ndb.Key(Event, event_key)) existing_users = [key.owner.get() if key.owner else None for key in existing_keys] return suggestion.key.id(), Event.get_by_id(event_key), account, zip(existing_keys, existing_users), suggestion
def get(self, event_key): self._require_admin() event = Event.get_by_id(event_key) if not event: self.abort(404) event.prepAwardsMatchesTeams() reg_sitevar = Sitevar.get_by_id("cmp_registration_hacks") api_keys = ApiAuthAccess.query( ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch() event_medias = Media.query(Media.references == event.key).fetch(500) playoff_template = PlayoffAdvancementHelper.getPlayoffTemplate(event) elim_bracket_html = jinja2_engine.render( "bracket_partials/bracket_table.html", { "bracket_table": event.playoff_bracket, "event": event }) advancement_html = jinja2_engine.render( "playoff_partials/{}.html".format(playoff_template), { "event": event, "playoff_advancement": event.playoff_advancement, "playoff_advancement_tiebreakers": PlayoffAdvancementHelper.ROUND_ROBIN_TIEBREAKERS.get( event.year), "bracket_table": event.playoff_bracket }) if playoff_template else "None" self.template_values.update({ "event": event, "medias": event_medias, "cache_key": event_controller.EventDetail('2016nyny').cache_key.format( event.key_name), "flushed": self.request.get("flushed"), "playoff_types": PlayoffType.type_names, "write_auths": api_keys, "event_sync_disable": reg_sitevar and event_key in reg_sitevar.contents.get('divisions_to_skip', []), "set_start_day_to_last": reg_sitevar and event_key in reg_sitevar.contents.get( 'set_start_to_last_day', []), "skip_eventteams": reg_sitevar and event_key in reg_sitevar.contents.get('skip_eventteams', []), "event_name_override": next( iter( filter(lambda e: e.get("event") == event_key, reg_sitevar.contents.get("event_name_override", []))), {}).get("name", ""), "elim_bracket_html": elim_bracket_html, "advancement_html": advancement_html, }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html') self.response.out.write(template.render(path, self.template_values))
def get(self, event_key): self._require_admin() event = Event.get_by_id(event_key) if not event: self.abort(404) event.prepAwardsMatchesTeams() reg_sitevar = Sitevar.get_by_id("cmp_registration_hacks") api_keys = ApiAuthAccess.query( ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch() event_medias = Media.query(Media.references == event.key).fetch(500) playoff_template = PlayoffAdvancementHelper.getPlayoffTemplate(event) elim_bracket_html = jinja2_engine.render( "bracket_partials/bracket_table.html", { "bracket_table": event.playoff_bracket, "event": event }) advancement_html = jinja2_engine.render( "playoff_partials/{}.html".format(playoff_template), { "event": event, "playoff_advancement": event.playoff_advancement, "playoff_advancement_tiebreakers": PlayoffAdvancementHelper.ROUND_ROBIN_TIEBREAKERS.get( event.year), "bracket_table": event.playoff_bracket }) if playoff_template else "None" organized_matches = MatchHelper.organizeMatches(event.matches) match_stats = [] for comp_level in Match.COMP_LEVELS: level_matches = organized_matches[comp_level] if not level_matches: continue match_stats.append({ 'comp_level': comp_level, 'level_name': Match.COMP_LEVELS_VERBOSE_FULL[comp_level], 'total': len(level_matches), 'played': len(filter(lambda m: m.has_been_played, level_matches)), 'unplayed': len(filter(lambda m: not m.has_been_played, level_matches)), }) self.template_values.update({ "event": event, "medias": event_medias, "flushed": self.request.get("flushed"), "playoff_types": PlayoffType.type_names, "write_auths": api_keys, "event_sync_disable": reg_sitevar and event_key in reg_sitevar.contents.get('divisions_to_skip', []), "set_start_day_to_last": reg_sitevar and event_key in reg_sitevar.contents.get( 'set_start_to_last_day', []), "skip_eventteams": reg_sitevar and event_key in reg_sitevar.contents.get('skip_eventteams', []), "event_name_override": next( iter( filter(lambda e: e.get("event") == event_key, reg_sitevar.contents.get("event_name_override", []))), {}).get("name", ""), "elim_bracket_html": elim_bracket_html, "advancement_html": advancement_html, 'match_stats': match_stats, 'deleted_count': self.request.get('deleted'), }) path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html') self.response.out.write(template.render(path, self.template_values))
def post(self, event_key): event_key = event_key.lower() # Normalize keys to lower case (TBA convention) # Make sure we are processing for a valid event first # (it's fine to do this before auth, since leaking the existence of an # event isn't really that big a deal) self.event = Event.get_by_id(event_key) if not self.event: self._errors = json.dumps({"Error": "Event {} not found".format(event_key)}) self.abort(404) # Start by allowing admins to edit any event user_is_admin = (self._user_bundle.user and self._user_bundle.is_current_user_admin) # Also grant access if the user as the EVENTWIZARD permission and this # is a current year offseason event account = self._user_bundle.account current_year = datetime.datetime.now().year user_has_permission = (self.event.event_type_enum == EventType.OFFSEASON and self.event.year == current_year and account is not None and AccountPermissions.OFFSEASON_EVENTWIZARD in account.permissions) user_has_auth = (user_is_admin or user_has_permission) if not user_has_auth and self._user_bundle.user: # See if this user has any auth keys granted to its account now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query(ApiAuthAccess.owner == account.key, ApiAuthAccess.event_list == ndb.Key(Event, event_key), ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch() user_has_auth = any(self._validate_auth(auth, event_key) is None for auth in auth_tokens) if not user_has_auth: # If not, check if auth id/secret were passed as headers auth_id = self.request.headers.get('X-TBA-Auth-Id') if not auth_id: self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"}) self.abort(400) auth_sig = self.request.headers.get('X-TBA-Auth-Sig') if not auth_sig: self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"}) self.abort(400) auth = ApiAuthAccess.get_by_id(auth_id) expected_sig = md5.new('{}{}{}'.format(auth.secret if auth else None, self.request.path, self.request.body)).hexdigest() if not auth or expected_sig != auth_sig: logging.info("Auth sig: {}, Expected sig: {}".format(auth_sig, expected_sig)) self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"}) self.abort(401) # Checks event key is valid, correct auth types, and expiration error = self._validate_auth(auth, event_key) if error: self._errors = json.dumps({"Error": error}) self.abort(401) try: self._process_request(self.request, event_key) except ParserInputException, e: self._errors = json.dumps({"Error": e.message}) self.abort(400)
def post(self, event_key): event_key = event_key.lower( ) # Normalize keys to lower case (TBA convention) # Make sure we are processing for a valid event first # (it's fine to do this before auth, since leaking the existence of an # event isn't really that big a deal) self.event = Event.get_by_id(event_key) if not self.event: self._errors = json.dumps( {"Error": "Event {} not found".format(event_key)}) self.abort(404) # Start by allowing admins to edit any event user_is_admin = (self._user_bundle.user and self._user_bundle.is_current_user_admin) # Also grant access if the user as the EVENTWIZARD permission and this # is a current year offseason event account = self._user_bundle.account current_year = datetime.datetime.now().year user_has_permission = (self.event.event_type_enum == EventType.OFFSEASON and self.event.year == current_year and account is not None and AccountPermissions.OFFSEASON_EVENTWIZARD in account.permissions) user_has_auth = (user_is_admin or user_has_permission) if not user_has_auth and self._user_bundle.user: # See if this user has any auth keys granted to its account now = datetime.datetime.now() auth_tokens = ApiAuthAccess.query( ApiAuthAccess.owner == account.key, ApiAuthAccess.event_list == ndb.Key(Event, event_key), ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch() user_has_auth = any( self._validate_auth(auth, event_key) is None for auth in auth_tokens) if not user_has_auth: # If not, check if auth id/secret were passed as headers auth_id = self.request.headers.get('X-TBA-Auth-Id') if not auth_id: self._errors = json.dumps({ "Error": "Must provide a request header parameter 'X-TBA-Auth-Id'" }) self.abort(400) auth_sig = self.request.headers.get('X-TBA-Auth-Sig') if not auth_sig: self._errors = json.dumps({ "Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'" }) self.abort(400) auth = ApiAuthAccess.get_by_id(auth_id) expected_sig = md5.new('{}{}{}'.format( auth.secret if auth else None, self.request.path, self.request.body)).hexdigest() if not auth or expected_sig != auth_sig: logging.info("Auth sig: {}, Expected sig: {}".format( auth_sig, expected_sig)) self._errors = json.dumps( {"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"}) self.abort(401) # Checks event key is valid, correct auth types, and expiration error = self._validate_auth(auth, event_key) if error: self._errors = json.dumps({"Error": error}) self.abort(401) try: self._process_request(self.request, event_key) except ParserInputException, e: self._errors = json.dumps({"Error": e.message}) self.abort(400)