Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f89b402
Implementing Phase-id to Bracket Name send to frontend.
Jul 17, 2016
a800262
Added some frontend to handle the array of brackets
Jul 17, 2016
b595926
Added api url endpoint, resource, angular frontend to handle bracket …
Jul 23, 2016
cf542ba
Quick change to the frontend
Jul 23, 2016
6ae17e6
Added JS for adding discluded phases to POST parameters.
Jul 25, 2016
02446b4
Renamed variables. Rearranged code. Needing to add js that gets all c…
Jul 27, 2016
df0f0ad
Added function to fire when checkbox is changed. Added attribute on i…
Jul 27, 2016
3184885
Set everything to be checked off the bat. Add tournament phase id to …
Jul 27, 2016
b77246f
Altering test code to work for additional parameter in SmashGGScraper…
Jul 31, 2016
9611243
API for excluding phases from smashgg event should be fixed.
Jul 31, 2016
d08a5bd
Merge remote-tracking branch 'origin/master' into SmashGG
Jul 31, 2016
b6c489c
Critical JS fix for the frontend.
Aug 1, 2016
83f0771
Altered Server and JS to handle GET parameters for getting the SmashG…
Aug 1, 2016
918b9fc
Added parser arguments for the Tournaments URL in the server to accep…
Aug 3, 2016
162bf74
Successfully populating the phases on the Garpr GUI on SmashGG tourna…
Aug 3, 2016
a49a53f
On checkbox of smashgg phase we either add or remove it from list of …
Aug 4, 2016
8973351
Included some debug messages to run when hit
Aug 20, 2016
ca608a8
Merge branch 'master' into SmashGG
Aug 21, 2016
e785c59
Changed logic. Get all groups. Get excluded Phases. Get groups from e…
Aug 21, 2016
8a05161
Bug Fix: On cancel clears the smash GG brackets.
Aug 21, 2016
f5780ef
Feature: Added message to indicate to user that Phases are being impo…
Aug 21, 2016
6b16597
Added dynamic message changing based on user input. Might want to add…
Aug 21, 2016
5970bf5
Bug Fix: Now removes smash gg phases and data when the modal loses fo…
Aug 21, 2016
65a54ae
Merge branch 'master' into SmashGG
Aug 22, 2016
7c87dec
Merge branch 'master' into SmashGG
Aug 22, 2016
23fd210
Reengineered Scraper to accept INCLUDED phases as opposed to Excluded…
Aug 23, 2016
c670daa
Refactored SmashGg instances to SmashGG
Aug 23, 2016
98b7a21
Merge branch 'master' into SmashGG
Aug 23, 2016
3a6ab68
Made necessary naming convention edits.
Aug 23, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions scraper/smashgg.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ def check_for_200(response):
return response

class SmashGGScraper(object):
def __init__(self, path):
def __init__(self, path, included_phases):
"""
:param path: url to go to the bracket
"""
self.path = path

# DATA STRUCTURE TO INCLUDE PHASES USER WANTS TO IMPORT
self.included_phases = included_phases
for p in self.included_phases:
print p

#GET IMPORTANT DATA FROM THE URL
self.event_id = SmashGGScraper.get_tournament_event_id_from_url(self.path)
self.name = SmashGGScraper.get_tournament_name_from_url(self.path)
Expand All @@ -36,7 +41,16 @@ def __init__(self, path):
# JSON DUMPED FROM THE API

self.event_dict = SmashGGScraper.get_event_dict(self.event_id)
self.group_ids = self.get_group_ids()

self.group_sets = []
for phase in self.included_phases:
self.group_sets.append(SmashGGScraper.get_group_ids_from_phase(phase))

self.group_ids = []
for group_set in self.group_sets:
for group_id in group_set:
self.group_ids.append(group_id)

self.group_dicts = [SmashGGScraper.get_group_dict(group_id) for group_id in self.group_ids]
self.group_dicts = [dict for dict in self.group_dicts if dict is not None] #REMOVE EMPTY PHASES FROM IMPORT

Expand Down Expand Up @@ -161,6 +175,10 @@ def get_smashgg_matches(self):
smashgg_match = SmashGGMatch(round_name, winner_id, loser_id, round_num, best_of)
self.matches.append(smashgg_match)

def get_phase_ids(self):
group_ids = [str(group['phaseId']).strip() for group in self.event_dict['entities']['groups']]
return list(set(group_ids))

def get_group_ids(self):
group_ids = [str(group['id']).strip() for group in self.event_dict['entities']['groups']]
return list(set(group_ids))
Expand Down Expand Up @@ -226,6 +244,15 @@ def get_phase_bracket_name(phase_id):
phase_name = phase_raw['entities']['phase']['name']
return phase_name

@staticmethod
def get_group_ids_from_phase(phase_id):
phase_ids = []
phase_raw = check_for_200(requests.get(PHASE_URL % phase_id)).json()
groups = phase_raw['entities']['groups']
for group in groups:
phase_ids.append(group['id'])
return phase_ids

@staticmethod
def get_phase_ids(event_id):
ids = []
Expand All @@ -244,8 +271,6 @@ def get_phasename_id_map(event_id):
map[phase_id] = SmashGGScraper.get_phase_bracket_name(phase_id)
return map



class SmashGGPlayer(object):
def __init__(self, smashgg_id, entrant_id, name, smash_tag, region, country, state, final_placement):
"""
Expand Down Expand Up @@ -291,6 +316,14 @@ def __init__(self, roundName, winner_id, loser_id, roundNumber, bestOf):
self.roundNumber = roundNumber
self.bestOf = bestOf

class SmashGGEvent(object):
"""
This is currently unused
"""
def __init__(self, event_id, phase_map):
self.event_id = event_id
self.phase_map = phase_map

class SmashGGException(Exception):
def __init__(self, message):
self.message = message
25 changes: 22 additions & 3 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
tournament_put_parser.add_argument('regions', type=list)
tournament_put_parser.add_argument('pending', type=bool)

smashGGMap_get_parser = reqparse.RequestParser()
smashGGMap_get_parser.add_argument('bracket_url', type=str)

merges_put_parser = reqparse.RequestParser()
merges_put_parser.add_argument('source_player_id', type=str)
merges_put_parser.add_argument('target_player_id', type=str)
Expand All @@ -74,6 +77,7 @@
tournament_import_parser.add_argument('challonge_url', type=str)
tournament_import_parser.add_argument('tio_file', type=str)
tournament_import_parser.add_argument('tio_bracket_name', type=str)
tournament_import_parser.add_argument('included_phases', type=list)

pending_tournament_put_parser = reqparse.RequestParser()
pending_tournament_put_parser.add_argument('name', type=str)
Expand Down Expand Up @@ -353,6 +357,7 @@ def post(self, region):
parser.add_argument('type', type=str, location='json')
parser.add_argument('data', type=unicode, location='json')
parser.add_argument('bracket', type=str, location='json')
parser.add_argument('included_phases', type=list, location='json')
args = parser.parse_args()

if args['data'] is None:
Expand All @@ -366,6 +371,7 @@ def post(self, region):

type = args['type']
data = args['data']
included_phases = args['included_phases']
pending_tournament = None

try:
Expand All @@ -379,12 +385,12 @@ def post(self, region):
elif type == 'challonge':
scraper = ChallongeScraper(data)
elif type == 'smashgg':
scraper = SmashGGScraper(data)
scraper = SmashGGScraper(data, included_phases)
else:
return "Unknown type", 400
pending_tournament = PendingTournament.from_scraper(type, scraper, region)
except:
return 'Scraper encountered an error', 400
except Exception as ex:
return 'Scraper encountered an error ' + str(ex), 400

if not pending_tournament:
return 'Scraper encountered an error', 400
Expand Down Expand Up @@ -818,6 +824,14 @@ def get(self, region, id):

return return_dict

class SmashGGMappingResource(restful.Resource):
def get(self):
args = smashGGMap_get_parser.parse_args()
url = args['bracket_url']

event_id = SmashGGScraper.get_tournament_event_id_from_url(url)
id_map = SmashGGScraper.get_phasename_id_map(event_id)
return id_map

class MergeListResource(restful.Resource):
def get(self, region):
Expand Down Expand Up @@ -1015,6 +1029,11 @@ def add_cors(resp):
api.add_resource(PendingTournamentResource, '/<string:region>/pending_tournaments/<string:id>')
api.add_resource(FinalizeTournamentResource, '/<string:region>/tournaments/<string:id>/finalize')

# THIS CALL TAKES A SMASHGG BRACKET URL AND RETURNS A MAP OF BRACKETS IN THE SMASHGG EVENT TO THEIR PHASE IDS
# THIS IS USEFUL FOR DISPLAYING THE INFORMATION TO THE USER SO THEY CAN CHOOSE ANY BRACKETS THEY DO NOT WISH
# TO IMPORT
api.add_resource(SmashGGMappingResource, '/smashGgMap')

api.add_resource(PendingTournamentListResource, '/<string:region>/tournaments/pending')
api.add_resource(RankingsResource, '/<string:region>/rankings')

Expand Down
22 changes: 17 additions & 5 deletions test/test_scraper/test_smashgg.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
TEST_URL_1 = 'https://smash.gg/tournament/htc-throwdown/brackets/10448/2096/6529'
TEST_URL_2 = 'https://smash.gg/tournament/tiger-smash-4/brackets/11097/21317/70949'
TEST_URL_3 = 'https://smash.gg/tournament/ceo-2016/brackets/11789/45259/150418'
TEST_URL_4 = 'https://smash.gg/tournament/nebulous-prime-melee-47/brackets/14172/49705/164217'
TEST_DATA1 = os.path.abspath('test' + os.sep + 'test_scraper' + os.sep + 'data' + os.sep + 'smashgg.json')
TEST_DATA2 = os.path.abspath('test' + os.sep + 'test_scraper' + os.sep + 'data' + os.sep + 'smashgg2.json')
TEST_EVENT_ID_1 = 10448
Expand Down Expand Up @@ -34,6 +35,9 @@ class TestSmashGGScraper(unittest.TestCase):
def setUp(self):
self.tournament1 = TestSmashGGScraper.tournament1
self.tournament2 = TestSmashGGScraper.tournament2
#self.tournament3 = TestSmashGGScraper.tournament3
self.tournament4 = TestSmashGGScraper.tournament4
#self.excluded_phases3 = [49706]
#self.tournament3 = SmashGGScraper(TEST_URL_3)
#list = self.tournament3.get_matches()
#print 'hello'
Expand All @@ -43,13 +47,17 @@ def setUp(self):
def setUpClass(cls):
print 'Pulling tournaments from smash.gg ...'
super(TestSmashGGScraper, cls).setUpClass()
cls.tournament1 = SmashGGScraper(TEST_URL_1)
cls.tournament2 = SmashGGScraper(TEST_URL_2)
cls.tournament1 = SmashGGScraper(TEST_URL_1, [1511, 2095, 2096])
cls.tournament2 = SmashGGScraper(TEST_URL_2, [3930, 21317])
#cls.tournament3 = SmashGGScraper(TEST_URL_3, [])
cls.tournament4 = SmashGGScraper(TEST_URL_4, [49153, 49705])


def tearDown(self):
self.tournament1 = None
self.tournament2 = None
#self.tournament3 = None
self.tournament4 = None

@unittest.skip('skipping test_get_raw1 until api is complete')
def test_get_raw1(self):
Expand Down Expand Up @@ -81,7 +89,7 @@ def test_get_raw_sub(self):

self.assertTrue('event' in raw)
self.assertTrue('groups' in raw)
self.assertEqual(len(raw['groups']), 10)
self.assertEqual(len(raw['groups']), 9)

entrants = raw['event']['entities']['entrants']
for entrant in entrants:
Expand Down Expand Up @@ -110,7 +118,7 @@ def test_get_matches(self):
print mango_count
self.assertEqual(2, mango_count, msg="mango didnt get double elim'd?")

self.assertEquals(len(self.tournament2.get_matches()), 436)
self.assertEquals(len(self.tournament2.get_matches()), 361)
# spot check that Druggedfox was only in 5 matches, and that he won all of them
sami_count = 0
for m in self.tournament2.get_matches():
Expand Down Expand Up @@ -164,4 +172,8 @@ def test_get_phase_name(self):

def test_get_phasename_id_map(self):
self.assertEqual(len(SmashGGScraper.get_phasename_id_map(TEST_EVENT_ID_1)), 3)
self.assertEqual(len(SmashGGScraper.get_phasename_id_map(TEST_EVENT_ID_2)), 3)
self.assertEqual(len(SmashGGScraper.get_phasename_id_map(TEST_EVENT_ID_2)), 3)

def test_included_phases(self):
self.assertEqual(len(self.tournament2.group_dicts), 9)
self.assertEqual(len(self.tournament4.group_dicts), 9)
2 changes: 1 addition & 1 deletion tournament_import_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

##Upload bracket:
- `POST /[region]/tournaments/`
- Body: Tourney name; Bracket type; Challonge link or (TIO file contents and bracket name)
- Body: Tourney name; Bracket type; SmashGG Bracket link, Challonge link or (TIO file contents and bracket name)
- Create `PendingTournament` from relevant `Scraper`; save this in the `pending_tournaments` collection
- return success

Expand Down
4 changes: 2 additions & 2 deletions tournament_import_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def import_tournament_from_challonge(region, path, name, dao):

return dao.insert_pending_tournament(pending)

def import_tournament_from_smashgg(region, path, name, dao):
scraper = SmashGGScraper(path)
def import_tournament_from_smashgg(region, path, included_phases, name, dao):
scraper = SmashGGScraper(path, included_phases)
pending = PendingTournament.from_scraper('smashgg', scraper, region)
if name:
pending.name = name
Expand Down
2 changes: 1 addition & 1 deletion webapp/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h4>Where can I find out more about how Trueskill works?</h4>
<a href="http://trueskill.org/">Trueskill Python implementation (the one used by GAR PR)</a>
</p>
<h4>What tournament programs do you support?</h4>
<p>Tio or Challonge (with SmashGG in the works)</p>
<p>Tio, Challonge, or SmashGG</p>
<h4>How do you handle inactive players?</h4>
<p>A region determines activity criteria, which are X tournaments in the past Y days. If a player becomes inactive they become hidden from the rankings list. They will still maintain the same rating they had before they became inactive. Once they enter enough tournaments to become active again, their old rating will be used to calculate their new rating and they will reappear on the rankings. Note that there is no rating decay of any kind.</p>
<h4>How do you handle the same player entering multiple tournaments with different tags?</h4>
Expand Down
17 changes: 15 additions & 2 deletions webapp/import_tournament_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,24 @@ <h3 class="modal-title">Import Tournament</h3>
</form>
</tab>
<tab heading="SmashGG" select="setBracketType('smashgg')">
<p>Enter the URL to your SmashGG bracket (e.g. <a href = https://smash.gg/tournament/genesis-3/brackets/10617/3860/15833>https://smash.gg/tournament/genesis-3/brackets/10617/3860/15833</a>):</p>
<p>Enter the URL to your SmashGG bracket (e.g. <a href = https://smash.gg/tournament/genesis-3/brackets/10617/3860/15833>https://smash.gg/tournament/genesis-3/brackets/10617/3860/15833</a>)
<br/>(One bracket will suffice. You will see all the brackets from your event populate below):</p>
<form ng-submit="submit()">
<div class="form-group">
<label for="bracket">SmashGG Bracket URL</label>
<input type="text" class="form-control" ng-model="postParams.data">
<input type="text" class="form-control" ng-model="postParams.data" ng-change="smashGG_populateBrackets()">
<br/>
<p ng-model="smashGGImportMessage" id="smashGGImportMessage"></p>
<ul style="list-style: none;">
<li ng-repeat="bracket in smashGG_brackets" >
<input type="checkbox" class="smashGG_bracket_checkbox"
bracket-id="{{ bracket.id }}"
ng-checked="checkSmashggBracket(bracket)"
id="{{ bracket.id }}_checkbox" >
{{ bracket.name }} <i>( {{ bracket.id }} )</i>
</li>
</ul>
<br/>
</div>
<button type="submit" class="btn btn-primary" ng-disabled="disableButtons">Submit</button>
<p class="text-danger" ng-show="errorMessage"><strong>There was an error. Please make sure everything is spelled correctly and try again.</strong></p>
Expand Down
Loading