all repos — myprecious @ 841bbbc4384b5ef741729464115a0dd54fa717cb

A lightweight web service to backup precious game saves.

myprecious/__main__.py (view raw)

  1from flask import Flask, request, render_template, url_for, redirect
  2from flask_login import LoginManager, UserMixin, login_user, logout_user, current_user
  3from werkzeug.utils import secure_filename
  4from contextlib import suppress
  5from Db import init_db, get_user_from_username, get_user_from_id, add_user_to_queue
  6import os, json, base64
  7import Constants as c
  8if c.DEBUG_SWITCH:
  9    from GamesApiTest import search_game
 10else:
 11    from GamesApi import search_game
 12
 13app = Flask(__name__)
 14login_manager = LoginManager(app)
 15
 16class User(UserMixin):
 17    def __init__(self, user_id, username, password, email):
 18        self.id = user_id
 19        self.username = username
 20        self.password = password
 21        self.email = email
 22
 23def construct_user(id, username, password, email):
 24    try:
 25        return User(int(id), username, password, email)
 26    except TypeError:
 27        return None
 28    
 29def render(template):
 30    return render_template(template, user=current_user)
 31
 32def handle_platform(game, platform):
 33    try:
 34        game_cover = "https:" + game["cover"]["url"]
 35    except KeyError:
 36        game_cover = c.MISSING_COVER_URL
 37    temp_obj = {
 38        "game_id": game["id"],
 39        "platform_id": platform["id"],
 40        "cover": game_cover,
 41        "title": game["name"],
 42        "platform": platform["name"]
 43    }
 44    temp_json = json.dumps(temp_obj)
 45    temp_bytes = temp_json.encode("utf-8")
 46    temp_base64 = base64.b64encode(temp_bytes)
 47    temp_obj["info"] = temp_base64.decode("utf-8")
 48    return temp_obj
 49
 50def handle_response(response):
 51    return [ [ handle_platform(game, platform) for platform in game["platforms"] ] for game in response ]
 52
 53def collapse_list_of_lists(l):
 54    return [ item for sublist in l for item in sublist ]
 55
 56@login_manager.user_loader
 57def load_user(user_id):
 58    lu = get_user_from_id(user_id)
 59    if lu is None:
 60        return None
 61    return construct_user(lu[0], lu[1], lu[2], lu[3])
 62
 63@app.route('/')
 64def route_index():
 65    return render("index.html")
 66
 67@app.route('/login', methods=['GET', 'POST'])
 68def route_login():
 69    if current_user.is_authenticated:
 70        return redirect('/')
 71    
 72    if request.method == "GET":
 73        return render("login.html")
 74    
 75    form = request.form
 76    username = form["username"].lower()
 77    password = form["password"]
 78    try:
 79        remember = bool(form["remember"])
 80    except KeyError:
 81        remember = False
 82
 83    r = get_user_from_username(username)
 84    if r is None:
 85        return render_template("login.html", user=current_user, last_user=username)
 86    user = construct_user(r[0], r[1], r[2], r[3])
 87
 88    if user is None:
 89        return redirect(url_for("login"))
 90    
 91    if user.password == password:
 92        login_user(user, remember=remember)
 93        return redirect("/")
 94    else:
 95        return render_template("login.html", user=current_user, last_user=username)
 96
 97@app.route('/register', methods=['GET', 'POST'])
 98def route_register():
 99    if current_user.is_authenticated:
100        return redirect('/')
101    
102    if request.method == "GET":
103        return render("register.html")
104    
105    form = request.form
106    username = form["username"].lower()
107    email = form["email"].lower()
108    password = form["password"]
109
110    if len(password) < c.MIN_PW_LENGTH or len(username) < c.MIN_USERNAME_LENGTH:
111        return render_template("register.html", user=current_user, error="Your username or password is too short.")
112    
113    if len(password) > c.MAX_LENGTH or len(username) > c.MAX_LENGTH:
114        return render_template("register.html", user=current_user, error="Your username or password is too long.")
115    
116    res = add_user_to_queue(username, password, email)
117    if res == None:
118        return render_template("register.html", user=current_user, error="This username is already registered.")
119    return render("register_done.html")
120
121@app.route('/logout')
122def route_logout():
123    logout_user()
124    return redirect("/")
125
126@app.route('/search', methods=['GET', 'POST'])
127def route_search():
128    if not current_user.is_authenticated:
129        return redirect('/login')
130    if request.method == 'GET':
131        return render("search.html")
132    
133    query = request.form["query"]
134    search_response = search_game(query)
135    
136    games = collapse_list_of_lists(handle_response(search_response))
137    return render_template("search.html", user=current_user, games=games, query=query)
138
139@app.route('/upload', methods=['GET', 'POST'])
140def route_upload():
141    if not current_user.is_authenticated:
142        return redirect('/login')
143    if request.method == 'GET':
144        info = request.args.get("info")
145        if info is None:
146            return render_template("upload.html", user=current_user, game=c.NO_GAME)
147        # info = base64
148        base64_bytes = info.encode('utf-8')
149        message_bytes = base64.b64decode(base64_bytes)
150        message = message_bytes.decode('utf-8')
151        game = json.loads(message)
152        return render_template("upload.html", user=current_user, game=game)
153        
154    f = request.files['file']
155    try:
156        game_id = int(request.form['game_id'])
157        platform_id = int(request.form['platform_id'])
158    except ValueError:
159        return redirect("/upload")
160    
161    # TODO: use IGDB api to validate game_id, platform_id and title before adding
162    # TODO: save game in DB
163
164    save_folder = os.path.join(c.BASE_DIRECTORY, c.CONTENT_DIRECTORY, str(current_user.id), str(game_id), str(platform_id))
165    with suppress(FileExistsError):
166        os.makedirs(save_folder)
167    if f.filename is None:
168        return redirect("/upload")
169    save_file = os.path.join(save_folder, secure_filename(f.filename))
170    f.save(save_file)
171    return render("index.html")
172
173
174@app.route('/admin', methods=['GET', 'POST'])
175def route_admin():
176    if not current_user.is_authenticated:
177        return redirect('/')
178    
179    if current_user.id != 1:
180        return redirect('/')
181    
182    if request.method == "GET":
183        return render("admin.html")
184    
185    return render("admin.html")
186
187@app.route('/about')
188def route_about():
189    return render("about.html")
190
191if __name__ == "__main__":
192    app.debug=c.DEBUG_SWITCH
193    app.secret_key = c.SECRET_KEY
194    app.config['SESSION_TYPE'] = 'filesystem'
195    init_db()
196    app.run(port=1111)