gdritter repos bingo / 9949091
Basic bingo site Getty Ritter 7 years ago
2 changed file(s) with 132 addition(s) and 0 deletion(s). Collapse all Expand all
1 #!/usr/bin/env python3
2
3 import base64
4 import flask
5 import random
6 import openpyxl
7 import svgwrite
8
9 app = flask.Flask(__name__)
10
11 TEXT_STYLE = 'font-family: "Arial", "Helvetica", sans-serif;'
12
13 @app.route('/')
14 def index():
15 return flask.send_from_directory('.', 'page.html')
16
17
18 @app.route('/process', methods=['POST'])
19 def process():
20 if 'file' not in flask.request.files:
21 raise Exception('No file uploaded!')
22 f = flask.request.files['file']
23 if f.filename == '':
24 raise Exception('No file uploaded!')
25 choices = choices_from_excel(openpyxl.load_workbook(f.stream))
26 choice_str = base64.urlsafe_b64encode('\x1c'.join(choices).encode('utf-8'))
27 return flask.redirect('/bingo.svg?choices={0}'.format(choice_str.decode('utf-8')))
28
29
30 @app.route('/bingo.svg')
31 def generate():
32 choice_str = base64.urlsafe_b64decode(flask.request.args.get('choices'))
33 choices = choice_str.decode('utf-8').split('\x1c')
34 print(choices)
35 return mk_svg(choices)
36
37
38 def choices_from_excel(wb):
39 sheet = wb.get_sheet_by_name(wb.get_sheet_names()[0])
40 choices = []
41 for row in range(1, sheet.max_row + 1):
42 choices.append(sheet.cell(row=row, column=1).value)
43 return choices
44
45
46 def mk_svg(choices):
47 choices = list(choices)
48 if len(choices) < 24:
49 raise Exception('Must have at least 24 possible choices!')
50 random.shuffle(choices)
51 d = svgwrite.Drawing(size=('8.5in', '11in'))
52 # t = svgwrite.mixins.Transform.translate('0.25in', '0.25in')
53 for x in range(6):
54 d.add(d.line(('{0}in'.format(x*1.6), '0in'),
55 ('{0}in'.format(x*1.6), '8in'),
56 stroke=svgwrite.rgb(0, 0, 0))).translate(45, 45)
57 for y in range(6):
58 d.add(d.line(('0in', '{0}in'.format(y*1.6)),
59 ('8in', '{0}in'.format(y*1.6)),
60 stroke=svgwrite.rgb(0, 0, 0))).translate(45, 45)
61 for x in range(5):
62 for y in range(5):
63 if x == 2 and y == 2:
64 text = 'FREE\nSQUARE'
65 color = '#b00'
66 else:
67 text = choices.pop()
68 color = '#000'
69 d.add(d.text(text,
70 insert=
71 ('{0}in'.format(x*1.6 + 0.8),
72 '{0}in'.format(y*1.6 + 0.8)),
73 text_anchor='middle',
74 alignment_baseline='central',
75 style=TEXT_STYLE,
76 fill=color)).translate(45, 45)
77 return d.tostring()
78
79
80 if __name__ == '__main__':
81 app.run()
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Bingo Card Generator</title>
5
6 <meta charset="utf-8">
7 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
9 <style type="text/css" >
10 body { background-color: #eee; }
11 .main {
12 background-color: #fff;
13 width: 800px;
14 margin-left: auto;
15 margin-right: auto;
16 margin-top: 20px;
17 padding: 40px;
18 }
19 .help { padding: 10px; }
20 </style>
21 </head>
22 <body>
23 <div class="main">
24 <h1>Bingo Card Creator</h1>
25 <div class="help">
26 To use this, create an excel spreadsheet with all the possible
27 cells you want along the left-hand side, with each cell being
28 a different row but all in the first column, and then upload
29 it here.
30 </div>
31 <div class="help">
32 Once you get to the bingo card, you can refresh it to create a
33 new bingo card, or bookmark it to create more bingo cards
34 later without having to re-upload the spreadsheet.
35 </div>
36 <div>
37 <form id="mainform" enctype="multipart/form-data" action="/process" method="post">
38 <div class="form-group" id="bingo-fields">
39 <input name="file" type="file">
40 </div>
41 <button type="submit" class="btn btn-primary">Create Bingo Card</button>
42 </form>
43 </div>
44 </div>
45 <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
46 <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
47 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
48 <script>
49 </script>
50 </body>
51 </html>