Skip to content

Commit 34bc223

Browse files
author
timwoj
committed
First commit
1 parent d99dd03 commit 34bc223

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+30834
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
raidgrpinfo
22
===========
3+
Simple tool for looking at raid groups for World of Warcraft.

app.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
application: raidgrpinfo
2+
version: 1
3+
runtime: python27
4+
api_version: 1
5+
threadsafe: yes
6+
7+
handlers:
8+
- url: /favicon\.ico
9+
static_files: favicon.ico
10+
upload: favicon\.ico
11+
12+
- url: /resources
13+
static_dir: resources
14+
15+
- url: .*
16+
script: main.app
17+
18+
libraries:
19+
- name: webapp2
20+
version: "2.5.2"

favicon.ico

1.12 KB
Binary file not shown.

grouploader.py

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# -*- coding: utf-8 -*-
2+
3+
#!/usr/bin/env python
4+
5+
import webapp2
6+
import json,math,sys,pprint
7+
from google.appengine.ext import ndb
8+
from google.appengine.api.memcache import Client
9+
from google.appengine.api import urlfetch
10+
from passlib.hash import sha256_crypt
11+
12+
class Group(ndb.Model):
13+
nrealm = ndb.StringProperty(indexed=True)
14+
ngroup = ndb.StringProperty(indexed=True)
15+
groupname = ndb.StringProperty()
16+
toons = ndb.StringProperty(repeated=True)
17+
password = ndb.StringProperty()
18+
19+
@staticmethod
20+
def normalize(realm):
21+
return realm.lower().replace('\'','').replace(' ','-')
22+
23+
class Loader(webapp2.RequestHandler):
24+
def get(self, nrealm, ngroup):
25+
26+
# try to load the group info from the database
27+
db_query = Group.query(Group.nrealm==nrealm, Group.ngroup==ngroup)
28+
results = db_query.fetch(5)
29+
30+
# if the group doesn't exist, drop into the interface to make a new
31+
# group
32+
if (len(results) == 0):
33+
self.redirect('/edit/%s/%s' % (nrealm, ngroup))
34+
35+
# if the group exists, load the group from the blizzard API and
36+
# display it.
37+
# if the group doesn't exist, show the page to create a new
38+
# group.
39+
else:
40+
self.loadGroup(results[0])
41+
42+
def post(self, nrealm, ngroup):
43+
44+
# try to load the group info from the database
45+
db_query = Group.query(Group.nrealm==nrealm, Group.ngroup==ngroup)
46+
results = db_query.fetch(5)
47+
48+
if ((len(results) != 0) and
49+
sha256_crypt.verify(self.request.get('pw'), results[0].password) != True):
50+
self.response.write('Password did not match for this group!')
51+
return
52+
53+
group = None
54+
if (len(results) != 0):
55+
group = results[0]
56+
else:
57+
group = Group()
58+
59+
group.nrealm = nrealm
60+
group.ngroup = ngroup
61+
group.groupname = self.request.get('group').strip()
62+
group.password = sha256_crypt.encrypt(self.request.get('pw'))
63+
toons = self.request.POST.getall('toons')
64+
print 'number of toons saved: %d' % len(toons)
65+
group.toons = sorted(self.request.POST.getall('toons'), key=unicode.lower)
66+
group.put()
67+
68+
self.loadGroup(group)
69+
70+
def loadGroup(self, results):
71+
72+
self.response.write('<!DOCTYPE html>\n')
73+
self.response.write('<html>\n')
74+
self.response.write('<head>\n')
75+
self.response.write('<title>%s</title>' % results.groupname)
76+
self.response.write('<link rel="stylesheet" type="text/css" href="/resources/raidgroup.css"/>\n')
77+
self.response.write('<script language="javascript" type="text/javascript" src="/resources/folder.js"></script>\n')
78+
self.response.write('<script language="javascript" type="text/javascript" src="/resources/creategroup.js"></script>\n')
79+
self.response.write('</head>\n')
80+
self.response.write('<body>\n')
81+
82+
# Fill this in with the list of toons in your raid group. It can include toon names with unicode characters
83+
toons = results.toons
84+
85+
# Fill this in with your realm name. Spaces should be replaced with '-'
86+
realm = results.nrealm
87+
88+
jsondata = dict()
89+
90+
totalilvl = 0
91+
totalilvleq = 0
92+
93+
for i in range(len(toons)):
94+
url = 'http://us.battle.net/api/wow/character/%s/%s?fields=items,guild,professions,progression' % (realm, toons[i]);
95+
print url.encode('utf-8')
96+
response = urlfetch.fetch(url)
97+
jsondata[i] = json.loads(response.content)
98+
99+
if 'status' in jsondata[i] and jsondata[i]['status'] == 'nok':
100+
print('Failed to find toon %s' % toons[i])
101+
jsondata[i]['toon'] = toons[i]
102+
else:
103+
totalilvl = totalilvl + jsondata[i]['items']['averageItemLevel'];
104+
totalilvleq = totalilvleq + jsondata[i]['items']['averageItemLevelEquipped']
105+
106+
self.response.write('<div style="font-size: 24px">%s\n' % results.groupname)
107+
self.response.write('<form action="/edit/%s/%s">' %
108+
(results.nrealm, results.ngroup))
109+
self.response.write('<input type="submit" value="Edit Group">\n')
110+
self.response.write('</form>')
111+
self.response.write('</div><br/>\n')
112+
self.response.write('Group Average ilvl: %d<br/>\n' % (totalilvl / len(toons)))
113+
self.response.write('Group Average equipped: %d<br/><br/>\n' % (totalilvleq / len(toons)))
114+
115+
halfgroup = math.ceil(len(jsondata) / 2.0)
116+
self.response.write('<div class="left">\n')
117+
118+
for u in range(len(jsondata)):
119+
120+
char = jsondata[u]
121+
122+
if (u == halfgroup):
123+
self.response.write('</div>')
124+
self.response.write('<div class="right">\n')
125+
126+
if 'status' in char and char['status'] == 'nok':
127+
self.response.write('Failed to find toon %s (name change? server transfer?)<br/>\n' % char['toon'])
128+
continue
129+
130+
self.response.write('<a href="http://us.battle.net/wow/en/character/%s/%s/simple">%s</a><br/>\n' % (realm.encode('utf-8'), char['name'].encode('utf-8'),char['name'].encode('utf-8')))
131+
132+
self.response.write('<div style="margin-left:30px">\n')
133+
self.response.write('%s<br/>\n' % char['guild']['name'])
134+
self.response.write('Average ilvl: %d<br/>\n' % char['items']['averageItemLevel'])
135+
self.response.write('Average equipped: %d<br/>\n' % char['items']['averageItemLevelEquipped'])
136+
137+
priprof = char['professions']['primary']
138+
139+
if (len(priprof) == 2):
140+
self.response.write('Profession #1: %s (%d)<br/>\n' % (priprof[0]['name'], priprof[0]['rank']))
141+
self.response.write('Profession #2: %s (%d)<br/>\n' % (priprof[1]['name'], priprof[1]['rank']))
142+
elif (len(priprof) == 1):
143+
self.response.write('Profession #1: %s (%d)<br/>\n' % (priprof[0]['name'], priprof[0]['rank']))
144+
self.response.write('Profession #2: none<br/>\n')
145+
else:
146+
self.response.write('Profession #1: none<br/>\n')
147+
self.response.write('Profession #2: none<br/>\n')
148+
149+
self.response.write('<div>\n')
150+
self.response.write('<div onclick="togglePanelStatus(\'%s\')" style="cursor: pointer">\n' % char['name'])
151+
self.response.write('<img src="/resources/arrow_right.png" id="slotsimg%s">' % char['name'])
152+
self.response.write('Gear Slot ilvls\n')
153+
self.response.write('</div>\n')
154+
self.response.write('<div id="slots%s" style="display: none;margin-left: 16px">\n' % char['name'])
155+
self.response.write('<div class="left">\n')
156+
self.response.write('Head: %d<br/>\n' % char['items']['head']['itemLevel'])
157+
self.response.write('Neck: %d<br/>\n' % char['items']['neck']['itemLevel'])
158+
self.response.write('Shoulder: %d<br/>\n' % char['items']['shoulder']['itemLevel'])
159+
self.response.write('Back: %d<br/>\n' % char['items']['back']['itemLevel'])
160+
self.response.write('Chest: %d<br/>\n' % char['items']['chest']['itemLevel'])
161+
self.response.write('Wrist: %d<br/>\n' % char['items']['wrist']['itemLevel'])
162+
self.response.write('Hands: %d<br/>\n' % char['items']['hands']['itemLevel'])
163+
self.response.write('Waist: %d<br/>\n' % char['items']['waist']['itemLevel'])
164+
self.response.write('</div>')
165+
self.response.write('<div class="left">\n')
166+
self.response.write('Legs: %d<br/>\n' % char['items']['legs']['itemLevel'])
167+
self.response.write('Feet: %d<br/>\n' % char['items']['feet']['itemLevel'])
168+
self.response.write('Ring 1: %d<br/>\n' % char['items']['finger1']['itemLevel'])
169+
self.response.write('Ring 2: %d<br/>\n' % char['items']['finger2']['itemLevel'])
170+
self.response.write('Trinket 1: %d<br/>\n' % char['items']['trinket1']['itemLevel'])
171+
self.response.write('Trinket 2: %d<br/>\n' % char['items']['trinket2']['itemLevel'])
172+
self.response.write('Main Hand: %d<br/>\n' % char['items']['mainHand']['itemLevel'])
173+
if ('offHand' in char['items']):
174+
self.response.write('Off Hand: %d<br/>\n' % char['items']['offHand']['itemLevel'])
175+
else:
176+
self.response.write('Off Hand: none<br/>\n')
177+
self.response.write('</div>\n')
178+
self.response.write('</div><br/>\n')
179+
self.response.write('</div>\n')
180+
self.response.write('</div>\n')
181+
182+
self.response.write('</div><p/>\n');
183+
self.response.write('</body>\n</html>')
184+
185+
class Editor(webapp2.RequestHandler):
186+
def get(self, nrealm, ngroup):
187+
self.editGroup(nrealm, ngroup)
188+
189+
def editGroup(self, nrealm, ngroup):
190+
191+
# try to load the group info from the database
192+
db_query = Group.query(Group.nrealm==nrealm, Group.ngroup==ngroup)
193+
queryresults = db_query.fetch(5)
194+
195+
results = None
196+
if (len(queryresults) != 0):
197+
results = queryresults[0]
198+
199+
self.response.write('<!DOCTYPE html>\n')
200+
self.response.write('<html>\n')
201+
self.response.write('<head>\n')
202+
203+
title = "Editing Group"
204+
if (results == None):
205+
title = "Creating New Group"
206+
207+
self.response.write('<title>%s</title>\n' % title)
208+
self.response.write('<script language="javascript" type="text/javascript" src="/resources/creategroup.js"></script>')
209+
self.response.write('</head>\n\n')
210+
self.response.write('<body>\n')
211+
self.response.write('<h1>%s</h1>\n' % title)
212+
213+
self.response.write('<form action="/%s/%s" method="post" autocomplete="off" onsubmit="selectAllToons();">\n' % (nrealm, ngroup))
214+
if (results == None):
215+
self.response.write('Group name: <input type="text" name="group" id="group"><p/>\n')
216+
else:
217+
self.response.write('Group name: <input type="text" name="group" id="group"value="%s"><p/>\n' % results.groupname)
218+
219+
self.response.write('Group members:<br>\n')
220+
self.response.write('<select size="10" multiple="multiple" style="width: 300px" name="toons" id="toons">\n')
221+
222+
if (results != None):
223+
for toon in results.toons:
224+
self.response.write('<option id="opt%s">%s\n' % (toon,toon))
225+
226+
self.response.write('</select><br>\n')
227+
self.response.write('Add Toon: <input type="text" name="newtoon" id="newtoon"><br>\n')
228+
self.response.write('<input type="button" onclick="addToList()" value="Add">')
229+
self.response.write('<input type="button" onclick="removeFromList()" value="Remove" id="removebutton"><p/>\n')
230+
if (results == None):
231+
self.response.write('Enter a password to enable editing the group later:<br>\n')
232+
else:
233+
self.response.write('Enter password to save group:<br>\n')
234+
self.response.write('Password:')
235+
self.response.write('<input type="password" name="pw"><p/>\n')
236+
self.response.write('<input type="submit" value="Save">\n')
237+
self.response.write('</form>\n')
238+
self.response.write('</body>\n')
239+
self.response.write('</html>')

grouploader.pyc

9.42 KB
Binary file not shown.

index.yaml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
indexes:
2+
3+
# AUTOGENERATED
4+
5+
# This index.yaml is automatically updated whenever the dev_appserver
6+
# detects that a new type of query is run. If you want to manage the
7+
# index.yaml file manually, remove the above marker line (the line
8+
# saying "# AUTOGENERATED"). If you want to manage some indexes
9+
# manually, move them above the marker line. The index.yaml file is
10+
# automatically uploaded to the admin console when you next deploy
11+
# your application using appcfg.py.
12+
13+
- kind: Group
14+
ancestor: yes
15+
properties:
16+
- name: groupname
17+
direction: desc

main.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# -*- coding: utf-8 -*-
2+
#!/usr/bin/env python
3+
4+
import cgi
5+
import webapp2
6+
import grouploader
7+
from webapp2_extras import sessions
8+
9+
MAIN_PAGE_HTML = """\
10+
<html>
11+
<body>
12+
<form action="/groups" method="post">
13+
<div>Realm: <input type="text" name="realm"></div>
14+
<div>Guild or Group name: <input type="text" name="group"></div>
15+
<div><input type="submit" value="Load Group"></div>
16+
</form>
17+
</body>
18+
</html>
19+
"""
20+
21+
class MainHandler(webapp2.RequestHandler):
22+
def get(self):
23+
self.response.write(MAIN_PAGE_HTML)
24+
25+
# This class redirects using the input from the form to the right page
26+
# for the group.
27+
class GroupRedir(webapp2.RequestHandler):
28+
def post(self):
29+
# normalize the group name and realm name to make them simple strings
30+
# without spaces. this makes it easier to work with them.
31+
realm = self.request.get('realm').strip()
32+
group = self.request.get('group').strip()
33+
nrealm = grouploader.Group.normalize(realm)
34+
ngroup = grouploader.Group.normalize(group)
35+
36+
# TODO: validate the realm against the armory
37+
38+
self.redirect('/%s/%s' % (nrealm, ngroup))
39+
40+
app = webapp2.WSGIApplication([
41+
('/', MainHandler),
42+
('/groups', GroupRedir),
43+
webapp2.Route('/edit/<:([^/]+)>/<:([^/]+)>', grouploader.Editor),
44+
webapp2.Route('/<:([^/]+)>/<:([^/]+)>', grouploader.Loader),
45+
], debug=True)

main.pyc

1.71 KB
Binary file not shown.

passlib/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""passlib - suite of password hashing & generation routinges"""
2+
3+
__version__ = '1.6.1'

passlib/__init__.pyc

250 Bytes
Binary file not shown.

passlib/_setup/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""passlib.setup - helpers used by passlib's setup.py script"""

0 commit comments

Comments
 (0)