def follow(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if any(m.id == mod.id for m in current_user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = 1 event.events = 1 db.add(event) db.flush() db.commit() mod.follow_events.append(event) else: event.delta += 1 event.events += 1 mod.follower_count += 1 current_user.following.append(mod) return {"success": True}
def unfollow(mod_id): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not any(m.id == mod.id for m in user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = -1 event.events = 1 mod.follow_events.append(event) db.add(event) else: event.delta -= 1 event.events += 1 mod.follower_count -= 1 user.following = [m for m in user.following if m.id == mod_id] db.commit() return {"success": True}
def feature(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) game = Game.query.filter(Game.id == mod.game_id).first() session['game'] = game.id; session['gamename'] = game.name; session['gameshort'] = game.short; session['gameid'] = game.id; if not mod or not game: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by(desc(Game.id)).first() session['game'] = ga.id; session['gamename'] = ga.name; session['gameshort'] = ga.short; session['gameid'] = ga.id; abort(404) else: session['game'] = game.id; session['gamename'] = game.name; session['gameshort'] = game.short; session['gameid'] = game.id; if any(Featured.query.filter(Featured.mod_id == mod_id).all()): abort(409) feature = Featured() feature.mod = mod db.add(feature) return { "success": True }
def download(mod_id, mod_name, version): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not mod.published and (not current_user or current_user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, \ ModVersion.friendly_version == version).first() if not version: abort(404) download = DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id)\ .order_by(desc(DownloadEvent.created))\ .first() if not os.path.isfile(os.path.join(_cfg('storage'), version.download_path)): abort(404) # Events are aggregated hourly if not download or ((datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 mod.downloads.append(download) db.add(download) else: download.downloads += 1 mod.download_count += 1 return send_file(os.path.join(_cfg('storage'), version.download_path), as_attachment = True)
def register_with_oauth_authorized(): ''' This endpoint should be called after authorizing with oauth, by the user. ''' email = request.form.get('email') username = request.form.get('username') provider = request.form.get('provider') remote_user = request.form.get('remote_user') good = True if check_username_for_registration(username): good = False if check_email_for_registration(email): good = False if good: password = binascii.b2a_hex(os.urandom(99)) user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.flush() # to get an ID. auth = UserAuth(user.id, remote_user, provider) db.add(auth) db.commit() # Commit before trying to email send_confirmation(user) return redirect("/account-pending") return render_register_with_oauth(provider, remote_user, username, email)
def unfollow(mod_id): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not any(m.id == mod.id for m in user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = -1 event.events = 1 mod.follow_events.append(event) db.add(event) else: event.delta -= 1 event.events += 1 mod.follower_count -= 1 user.following = [m for m in user.following if m.id == mod_id] db.commit() return { "success": True }
def feature(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) game = Game.query.filter(Game.id == mod.game_id).first() session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if not mod or not game: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by( desc(Game.id)).first() session['game'] = ga.id session['gamename'] = ga.name session['gameshort'] = ga.short session['gameid'] = ga.id abort(404) else: session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if any(Featured.query.filter(Featured.mod_id == mod_id).all()): abort(409) feature = Featured() feature.mod = mod db.add(feature) return {"success": True}
def download(mod_id, mod_name, version): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not mod.published and (not user or user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, \ ModVersion.friendly_version == version).first() if not version: abort(404) download = DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id)\ .order_by(desc(DownloadEvent.created))\ .first() # Events are aggregated hourly if not download or ((datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 mod.downloads.append(download) db.add(download) else: download.downloads += 1 mod.download_count += 1 db.commit() return send_file(os.path.join(_cfg('storage'), version.download_path), as_attachment = True)
def register_with_oauth_authorized(): ''' This endpoint should be called after authorizing with oauth, by the user. ''' email = request.form.get('email') username = request.form.get('username') provider = request.form.get('provider') remote_user = request.form.get('remote_user') good = True if check_username_for_registration(username): good = False if check_email_for_registration(email): good = False if good: password = binascii.b2a_hex(os.urandom(99)) user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.flush() # to get an ID. auth = UserAuth(user.id, remote_user, provider) db.add(auth) db.commit() # Commit before trying to email send_confirmation(user) return redirect("/account-pending") return render_register_with_oauth(provider, remote_user, username, email)
def follow(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if any(m.id == mod.id for m in current_user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = 1 event.events = 1 db.add(event) db.flush() db.commit() mod.follow_events.append(event) else: event.delta += 1 event.events += 1 mod.follower_count += 1 current_user.following.append(mod) return { "success": True }
def edit_media(mod_id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not editable: abort(401) screenshots = request.form.get('screenshots') videos = request.form.get('videos') background = request.form.get('backgroundMedia') bgOffsetX = request.form.get('bg-offset-x') bgOffsetY = request.form.get('bg-offset-y') screenshot_list = screenshots.split(',') video_list = videos.split(',') if len(screenshot_list) > 5 \ or len(video_list) > 2 \ or len(background) > 32: abort(400) [db.delete(m) for m in mod.media] for screenshot in screenshot_list: if screenshot: r = requests.get('https://mediacru.sh/' + screenshot + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'image': for f in j['files']: if f['type'] == 'image/jpeg' or f['type'] == 'image/png': data = f['file'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) for video in video_list: if video: r = requests.get('https://mediacru.sh/' + video + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'video': data = j['hash'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) db.add(m) mod.background = background try: mod.bgOffsetX = int(bgOffsetX) mod.bgOffsetY = int(bgOffsetY) except: pass # Do not modify background in this case return redirect('/mod/' + str(mod.id) + '/' + secure_filename(mod.name)[:64])
def register(): if request.method == 'POST': # Validate kwargs = dict() followMod = request.form.get('follow-mod') email = request.form.get('email') username = request.form.get('username') password = request.form.get('password') confirmPassword = request.form.get('repeatPassword') if not email: kwargs['emailError'] = 'Email is required.' else: if not re.match(r"^[^@]+@[^@]+\.[^@]+$", email): kwargs['emailError'] = 'Please specify a valid email address.' elif db.query(User).filter(User.email == email).first(): kwargs['emailError'] = 'A user with this email already exists.' if not username: kwargs['usernameError'] = 'Username is required.' else: if not re.match(r"^[A-Za-z0-9_]+$", username): kwargs[ 'usernameError'] = 'Please only use letters, numbers, and underscores.' if len(username) < 3 or len(username) > 24: kwargs[ 'usernameError'] = 'Usernames must be between 3 and 24 characters.' if db.query(User).filter(User.username.ilike(username)).first(): kwargs['usernameError'] = 'A user by this name already exists.' if not password: kwargs['passwordError'] = 'Password is required.' else: if password != confirmPassword: kwargs['repeatPasswordError'] = 'Passwords do not match.' if len(password) < 5: kwargs[ 'passwordError'] = 'Your password must be greater than 5 characters.' if len(password) > 256: kwargs[ 'passwordError'] = 'We admire your dedication to security, but please use a shorter password.' if not kwargs == dict(): if email is not None: kwargs['email'] = email if username is not None: kwargs['username'] = username return render_template("register.html", **kwargs) # All valid, let's make them an account user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.commit( ) # We do this manually so that we're sure everything's hunky dory before the email leaves if followMod: send_confirmation(user, followMod) else: send_confirmation(user) return redirect("/account-pending") else: return render_template("register.html")
def post_blog(): title = request.form.get('post-title') body = request.form.get('post-body') post = BlogPost() post.title = title post.text = body db.add(post) db.commit() return redirect("/blog/" + str(post.id))
def post_blog(): title = request.form.get('post-title') body = request.form.get('post-body') post = BlogPost() post.title = title post.text = body db.add(post) db.commit() return redirect("/blog/" + str(post.id))
def create_publisher(): name = request.form.get("pname") if not name: return redirect("/asdf") if any(Publisher.query.filter(Publisher.name == name)): return redirect("/fsda") gname = Publisher(name) db.add(gname) db.commit() return redirect("/admin")
def feature(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if any(Featured.query.filter(Featured.mod_id == mod_id).all()): abort(409) feature = Featured() feature.mod = mod db.add(feature) return { "success": True }
def feature(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if any(Featured.query.filter(Featured.mod_id == mod_id).all()): abort(409) feature = Featured() feature.mod = mod db.add(feature) return { "success": True }
def create_version(): friendly = request.form.get("friendly_version") if not friendly: return redirect("/asdf") if any(GameVersion.query.filter(GameVersion.friendly_version == friendly)): return redirect("/fsda") version = GameVersion(friendly) db.add(version) db.commit() return redirect("/admin")
def create_version(): friendly = request.form.get("friendly_version") if not friendly: return redirect("/asdf") if any(GameVersion.query.filter(GameVersion.friendly_version == friendly)): return redirect("/fsda") version = GameVersion(friendly) db.add(version) db.commit() return redirect("/admin")
def edit_list(list_id, list_name): mod_list = ModList.query.filter(ModList.id == list_id).first() if not mod_list: abort(404) editable = False if current_user: if current_user.admin: editable = True if current_user.id == mod_list.user_id: editable = True if not editable: abort(401) if request.method == 'GET': return render_template( "edit_list.html", **{ 'mod_list': mod_list, 'mod_ids': [m.mod.id for m in mod_list.mods], "site_name": _cfg('site-name'), "support_mail": _cfg('support-mail') }) else: description = request.form.get('description') background = request.form.get('background') bgOffsetY = request.form.get('bg-offset-y') mods = json.loads(request.form.get('mods')) mod_list.description = description if background and background != '': mod_list.background = background try: mod_list.bgOffsetY = int(bgOffsetY) except: pass # Remove mods removed_mods = [m for m in mod_list.mods if not m.mod_id in mods] for mod in removed_mods: mod_list.mods.remove(mod) # Add mods added_mods = [ m for m in mods if not m in [mod.mod.id for mod in mod_list.mods] ] for m in added_mods: mod = Mod.query.filter(Mod.id == m).first() mli = ModListItem() mli.mod_id = mod.id mli.mod_list = mod_list mod_list.mods.append(mli) db.add(mli) db.commit() for mod in mod_list.mods: mod.sort_index = mods.index(mod.mod.id) return redirect( url_for("lists.view_list", list_id=mod_list.id, list_name=mod_list.name))
def register(): if request.method == 'POST': # Validate kwargs = dict() followMod = request.form.get('follow-mod') email = request.form.get('email') username = request.form.get('username') password = request.form.get('password') confirmPassword = request.form.get('repeatPassword') if not email: kwargs['emailError'] = 'Email is required.' else: if not re.match(r"^[^@]+@[^@]+\.[^@]+$", email): kwargs['emailError'] = 'Please specify a valid email address.' elif db.query(User).filter(User.email == email).first(): kwargs['emailError'] = 'A user with this email already exists.' elif _mailbans.isMailBanned(email): kwargs['emailError'] = 'This email host is banned, please use an alternative, this is to prevent botting, sorry.' if not username: kwargs['usernameError'] = 'Username is required.' else: if not re.match(r"^[A-Za-z0-9_]+$", username): kwargs['usernameError'] = 'Please only use letters, numbers, and underscores.' if len(username) < 3 or len(username) > 24: kwargs['usernameError'] = 'Usernames must be between 3 and 24 characters.' if db.query(User).filter(User.username.ilike(username)).first(): kwargs['usernameError'] = 'A user by this name already exists.' if not password: kwargs['passwordError'] = 'Password is required.' else: if password != confirmPassword: kwargs['repeatPasswordError'] = 'Passwords do not match.' if len(password) < 5: kwargs['passwordError'] = 'Your password must be greater than 5 characters.' if len(password) > 256: kwargs['passwordError'] = 'We admire your dedication to security, but please use a shorter password.' if not kwargs == dict(): if email is not None: kwargs['email'] = email if username is not None: kwargs['username'] = username return render_template("register.html", **kwargs) # All valid, let's make them an account user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.commit() # We do this manually so that we're sure everything's hunky dory before the email leaves if followMod: send_confirmation(user, followMod) else: send_confirmation(user) return redirect("/account-pending") else: return render_template("register.html")
def edit_media(mod_id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not editable: abort(401) screenshots = request.form.get('screenshots') videos = request.form.get('videos') background = request.form.get('backgroundMedia') screenshot_list = screenshots.split(',') video_list = videos.split(',') if len(screenshot_list) > 5 \ or len(video_list) > 2 \ or len(background) > 32: abort(400) [db.delete(m) for m in mod.media] for screenshot in screenshot_list: if screenshot: r = requests.get('https://mediacru.sh/' + screenshot + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'image': for f in j['files']: if f['type'] == 'image/jpeg' or f['type'] == 'image/png': data = f['file'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) for video in video_list: if video: r = requests.get('https://mediacru.sh/' + video + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'video': data = j['hash'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) db.add(m) mod.background = background db.commit() return redirect('/mod/' + str(mod.id) + '/' + secure_filename(mod.name)[:64])
def register(): if not _cfgb('registration'): return redirect("/") if request.method == 'POST': # Validate kwargs = dict() followMod = request.form.get('follow-mod') email = request.form.get('email') username = request.form.get('username') password = request.form.get('password') confirmPassword = request.form.get('repeatPassword') error = check_email_for_registration(email) if error: kwargs['emailError'] = error error = check_username_for_registration(username) if error: kwargs['usernameError'] = error if not password: kwargs['passwordError'] = 'Password is required.' else: if password != confirmPassword: kwargs['repeatPasswordError'] = 'Passwords do not match.' if len(password) < 5: kwargs['passwordError'] = 'Your password must be greater than 5 characters.' if len(password) > 256: kwargs['passwordError'] = 'We admire your dedication to security, but please use a shorter password.' if not kwargs == dict(): # Fill in config values kwargs['site_name'] = _cfg('site-name') kwargs['support_mail'] = _cfg('support-mail') if email is not None: kwargs['email'] = email if username is not None: kwargs['username'] = username kwargs['registration'] = registration = _cfgb('registration') print("test") return render_template("register.html", **kwargs) # All valid, let's make them an account user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.commit() # We do this manually so that we're sure everything's hunky dory before the email leaves if followMod: send_confirmation(user, followMod) else: send_confirmation(user) return redirect("/account-pending") else: return render_template("register.html", **{ "site_name": _cfg('site-name'), "support_mail": _cfg('support-mail'), "registration": _cfgb('registration') })
def register(): if not _cfgb('registration'): return redirect("/") if request.method == 'POST': # Validate kwargs = dict() followMod = request.form.get('follow-mod') email = request.form.get('email') username = request.form.get('username') password = request.form.get('password') confirmPassword = request.form.get('repeatPassword') error = check_email_for_registration(email) if error: kwargs['emailError'] = error error = check_username_for_registration(username) if error: kwargs['usernameError'] = error if not password: kwargs['passwordError'] = 'Password is required.' else: if password != confirmPassword: kwargs['repeatPasswordError'] = 'Passwords do not match.' if len(password) < 5: kwargs[ 'passwordError'] = 'Your password must be greater than 5 characters.' if len(password) > 256: kwargs[ 'passwordError'] = 'We admire your dedication to security, but please use a shorter password.' if not kwargs == dict(): if email is not None: kwargs['email'] = email if username is not None: kwargs['username'] = username kwargs['registration'] = registration = _cfgb('registration') print("test") return render_template("register.html", **kwargs) # All valid, let's make them an account user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.commit( ) # We do this manually so that we're sure everything's hunky dory before the email leaves if followMod: send_confirmation(user, followMod) else: send_confirmation(user) return redirect("/account-pending") else: return render_template("register.html", registration=_cfgb('registration'))
def update(mod_id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not editable: abort(401) version = request.form.get('version') changelog = request.form.get('changelog') ksp_version = request.form.get('ksp-version') notify = request.form.get('notify-followers') zipball = request.files.get('zipball') if not version \ or not ksp_version \ or not zipball: # Client side validation means that they're just being pricks if they # get here, so we don't need to show them a pretty error message abort(400) if notify == None: notify = False else: notify = notify.lower() == "on" filename = secure_filename(mod.name) + '-' + secure_filename(version) + '.zip' base_path = os.path.join(secure_filename(user.username) + '_' + str(user.id), secure_filename(mod.name)) full_path = os.path.join(_cfg('storage'), base_path) if not os.path.exists(full_path): os.makedirs(full_path) path = os.path.join(full_path, filename) if os.path.isfile(path): # We already have this version # TODO: Error message abort(400) zipball.save(path) if not zipfile.is_zipfile(path): os.remove(path) abort(400) # TODO: Error message version = ModVersion(secure_filename(version), ksp_version, os.path.join(base_path, filename)) version.changelog = changelog # Assign a sort index version.sort_index = max([v.sort_index for v in mod.versions]) + 1 mod.versions.append(version) if notify: send_update_notification(mod) db.add(version) db.commit() mod.default_version_id = version.id return redirect('/mod/' + mod_id + '/' + secure_filename(mod.name))
def create_game(): name = request.form.get("gname") sname = request.form.get("sname") pid = request.form.get("pname") if not name or not pid or not sname: return redirect("/asdf") if any(Game.query.filter(Game.name == name)): return redirect("/fsda") go = Game(name,pid,sname) db.add(go) db.commit() return redirect("/admin")
def update(mod_id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not editable: abort(401) if request.method == 'GET': return render_template("update.html", **{'mod': mod}) else: version = request.form.get('version') changelog = request.form.get('changelog') ksp_version = request.form.get('ksp-version') zipball = request.files.get('zipball') if not version \ or not ksp_version \ or not zipball: # Client side validation means that they're just being pricks if they # get here, so we don't need to show them a pretty error message abort(400) filename = secure_filename( mod.name) + '-' + secure_filename(version) + '.zip' base_path = os.path.join( secure_filename(user.username) + '_' + str(user.id), secure_filename(mod.name)) full_path = os.path.join(_cfg('storage'), base_path) if not os.path.exists(full_path): os.makedirs(full_path) path = os.path.join(full_path, filename) if os.path.isfile(path): # We already have this version # TODO: Error message abort(400) zipball.save(path) if not zipfile.is_zipfile(path): os.remove(path) abort(400) # TODO: Error message version = ModVersion(secure_filename(version), ksp_version, os.path.join(base_path, filename)) version.changelog = changelog mod.versions.append(version) send_update_notification(mod) db.add(version) db.commit() return redirect('/mod/' + mod_id + '/' + secure_filename(mod.name))
def edit_list(list_id, list_name): mod_list = ModList.query.filter(ModList.id == list_id).first() ga = Game.query.filter(Game.id == mod_list.game_id).first() if not mod_list: abort(404) editable = False if current_user: if current_user.admin: editable = True if current_user.id == mod_list.user_id: editable = True if not editable: abort(401) if request.method == 'GET': return render_template("edit_list.html", **{ 'mod_list': mod_list, 'mod_ids': [m.mod.id for m in mod_list.mods], 'ga': ga }) else: description = request.form.get('description') background = request.form.get('background') bgOffsetY = request.form.get('bg-offset-y') mods = json.loads(request.form.get('mods')) mod_list.description = description if background and background != '': mod_list.background = background try: mod_list.bgOffsetY = int(bgOffsetY) except: pass # Remove mods removed_mods = [m for m in mod_list.mods if not m.mod_id in mods] for mod in removed_mods: mod_list.mods.remove(mod) # Add mods added_mods = [m for m in mods if not m in [mod.mod.id for mod in mod_list.mods]] for m in added_mods: mod = Mod.query.filter(Mod.id == m).first() mli = ModListItem() mli.mod_id = mod.id mli.mod_list = mod_list mod_list.mods.append(mli) db.add(mli) db.commit() for mod in mod_list.mods: mod.sort_index = mods.index(mod.mod.id) return redirect(url_for("lists.view_list", list_id=mod_list.id, list_name=mod_list.name))
def download(mod_id, mod_name, version): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not mod.published and (not current_user or current_user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, \ ModVersion.friendly_version == version).first() if not version: abort(404) download = DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id)\ .order_by(desc(DownloadEvent.created))\ .first() if not os.path.isfile(os.path.join(_cfg('storage'), version.download_path)): abort(404) if not 'Range' in request.headers: # Events are aggregated hourly if not download or ((datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 db.add(download) db.flush() db.commit() mod.downloads.append(download) else: download.downloads += 1 mod.download_count += 1 if _cfg("cdn-domain"): return redirect("http://" + _cfg("cdn-domain") + '/' + version.download_path, code=302) response = None if _cfg("use-x-accel") == 'nginx': response = make_response("") response.headers['Content-Type'] = 'application/zip' response.headers['Content-Disposition'] = 'attachment; filename=' + os.path.basename(version.download_path) response.headers['X-Accel-Redirect'] = '/internal/' + version.download_path if _cfg("use-x-accel") == 'apache': response = make_response("") response.headers['Content-Type'] = 'application/zip' response.headers['Content-Disposition'] = 'attachment; filename=' + os.path.basename(version.download_path) response.headers['X-Sendfile'] = os.path.join(_cfg('storage'), version.download_path) if response is None: response = make_response(send_file(os.path.join(_cfg('storage'), version.download_path), as_attachment = True)) return response
def register(): if request.method == 'POST': # Validate kwargs = dict() email = request.form.get('email') username = request.form.get('username') password = request.form.get('password') confirmPassword = request.form.get('repeatPassword') if not email: kwargs['emailError'] = 'Email is required.' else: if not re.match(r"[^@]+@[^@]+\.[^@]+", email): kwargs['emailError'] = 'Please specify a valid email address.' elif db.query(User).filter(User.email == email).first(): kwargs['emailError'] = 'A user with this email already exists.' if not username: kwargs['usernameError'] = 'Username is required.' else: if not re.match(r"[A-Za-z0-9_]+", username): kwargs['usernameError'] = 'Please only use letters, numbers, and underscores.' if len(username) < 3 or len(username) > 12: kwargs['usernameError'] = 'Usernames must be between 3 and 12 characters.' if db.query(User).filter(User.username == username).first(): kwargs['usernameError'] = 'A user by this name already exists.' if not password: kwargs['passwordError'] = 'Password is required.' else: if password != confirmPassword: kwargs['repeatPasswordError'] = 'Passwords do not match.' if len(password) < 5: kwargs['passwordError'] = 'Your password must be greater than 5 characters.' if len(password) > 256: kwargs['passwordError'] = 'We admire your dedication to security, but please use a shorter password.' if not kwargs == dict(): if email is not None: kwargs['email'] = email if username is not None: kwargs['username'] = username return render_template("register.html", **kwargs) # All valid, let's make them an account user = User(username, email, password) user.confirmation = binascii.b2a_hex(os.urandom(20)).decode("utf-8") db.add(user) db.commit() send_confirmation(user) return redirect("/account-pending") else: return render_template("register.html")
def update(mod_id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not editable: abort(401) if request.method == 'GET': return render_template("update.html", **{ 'mod': mod }) else: version = request.form.get('version') changelog = request.form.get('changelog') ksp_version = request.form.get('ksp-version') zipball = request.files.get('zipball') if not version \ or not ksp_version \ or not zipball: # Client side validation means that they're just being pricks if they # get here, so we don't need to show them a pretty error message abort(400) filename = secure_filename(mod.name) + '-' + secure_filename(version) + '.zip' base_path = os.path.join(secure_filename(user.username) + '_' + str(user.id), secure_filename(mod.name)) full_path = os.path.join(_cfg('storage'), base_path) if not os.path.exists(full_path): os.makedirs(full_path) path = os.path.join(full_path, filename) if os.path.isfile(path): # We already have this version # TODO: Error message abort(400) zipball.save(path) if not zipfile.is_zipfile(path): os.remove(path) abort(400) # TODO: Error message version = ModVersion(secure_filename(version), ksp_version, os.path.join(base_path, filename)) version.changelog = changelog mod.versions.append(version) send_update_notification(mod) db.add(version) db.commit() return redirect('/mod/' + mod_id + '/' + secure_filename(mod.name))
def download(mod_id, mod_name, version): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not mod.published and (not current_user or current_user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, \ ModVersion.friendly_version == version).first() if not version: abort(404) download = DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id)\ .order_by(desc(DownloadEvent.created))\ .first() if not os.path.isfile(os.path.join(_cfg('storage'), version.download_path)): abort(404) if not 'Range' in request.headers: # Events are aggregated hourly if not download or ( (datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 db.add(download) db.flush() db.commit() mod.downloads.append(download) else: download.downloads += 1 mod.download_count += 1 response = make_response( send_file(os.path.join(_cfg('storage'), version.download_path), as_attachment=True)) if _cfg("use-x-accel") == 'true': response = make_response("") response.headers['Content-Type'] = 'application/zip' response.headers[ 'Content-Disposition'] = 'attachment; filename=' + os.path.basename( version.download_path) response.headers[ 'X-Accel-Redirect'] = '/internal/' + version.download_path return response
def unfollow(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) game = Game.query.filter(Game.id == mod.game_id).first() session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if not mod or not game: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by( desc(Game.id)).first() session['game'] = ga.id session['gamename'] = ga.name session['gameshort'] = ga.short session['gameid'] = ga.id abort(404) else: session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if not any(m.id == mod.id for m in current_user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = -1 event.events = 1 mod.follow_events.append(event) db.add(event) else: event.delta -= 1 event.events += 1 mod.follower_count -= 1 current_user.following = [ m for m in current_user.following if m.id != int(mod_id) ] return {"success": True}
def follow(mod_id): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) game = Game.query.filter(Game.id == mod.game_id).first() session['game'] = game.id; session['gamename'] = game.name; session['gameshort'] = game.short; session['gameid'] = game.id; if not mod or not game: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by(desc(Game.id)).first() session['game'] = ga.id; session['gamename'] = ga.name; session['gameshort'] = ga.short; session['gameid'] = ga.id; abort(404) else: session['game'] = game.id; session['gamename'] = game.name; session['gameshort'] = game.short; session['gameid'] = game.id; if any(m.id == mod.id for m in current_user.following): abort(418) event = FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .order_by(desc(FollowEvent.created))\ .first() # Events are aggregated hourly if not event or ((datetime.now() - event.created).seconds / 60 / 60) >= 1: event = FollowEvent() event.mod = mod event.delta = 1 event.events = 1 db.add(event) db.flush() db.commit() mod.follow_events.append(event) else: event.delta += 1 event.events += 1 mod.follower_count += 1 current_user.following.append(mod) return { "success": True }
def _connect_with_oauth_finalize(remote_user, provider): if not current_user: return 'Trying to associate an account, but not logged in?' auth = UserAuth.query.filter(UserAuth.provider == provider, UserAuth.remote_user == remote_user).first() if auth: if auth.user_id == current_user.id: # You're already set up. return redirect('/profile/%s/edit' % current_user.username) # This account is already connected with some user. full_name = list_defined_oauths()[provider]['full_name'] return 'Your %s account is already connected to a SpaceDock account.' % full_name auth = UserAuth(current_user.id, remote_user, provider) db.add(auth) db.flush() # So that /profile will display currectly return redirect('/profile/%s/edit' % current_user.username)
def _connect_with_oauth_finalize(remote_user, provider): if not current_user: return 'Trying to associate an account, but not logged in?' auth = UserAuth.query.filter(UserAuth.provider == provider, UserAuth.remote_user == remote_user).first() if auth: if auth.user_id == current_user.id: # You're already set up. return redirect('/profile/%s/edit' % current_user.username) # This account is already connected with some user. full_name = list_defined_oauths()[provider]['full_name'] return 'Your %s account is already connected to a KerbalStuff account.' % full_name auth = UserAuth(current_user.id, remote_user, provider) db.add(auth) db.flush() # So that /profile will display currectly return redirect('/profile/%s/edit' % current_user.username)
def get_or_create(mod: 'Mod') -> Optional[str]: protocol = _cfg('protocol') cdn_domain = _cfg('cdn-domain') if not mod.thumbnail: storage = _cfg('storage') if not mod.background: return None if not storage: return mod.background_url(protocol, cdn_domain) thumb_path = thumb_path_from_background_path(mod.background) thumb_disk_path = os.path.join(storage, thumb_path) background_disk_path = os.path.join(storage, mod.background) logging.debug("Checking file system for thumbnail") if not os.path.isfile(thumb_disk_path): if not os.path.isfile(background_disk_path): site_logger.warning( 'Background image does not exist, clearing path from db') mod.background = None db.add(mod) db.commit() return None try: logging.debug("Creating thumbnail") create(background_disk_path, thumb_disk_path) except Exception as e: site_logger.exception(e) return mod.background_url(protocol, cdn_domain) mod.thumbnail = thumb_path db.add(mod) db.commit() # Directly return the CDN path if we have any, so we don't have a redirect that breaks caching. if protocol and cdn_domain: return f'{protocol}://{cdn_domain}/{mod.thumbnail}' else: return url_for('mods.mod_thumbnail', mod_id=mod.id, mod_name=mod.name)
def download(mod_id, mod_name, version): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) if not mod.published and (not current_user or current_user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, ModVersion.friendly_version == version).first() if not version: abort(404) download = ( DownloadEvent.query.filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id) .order_by(desc(DownloadEvent.created)) .first() ) if not os.path.isfile(os.path.join(_cfg("storage"), version.download_path)): abort(404) if not "Range" in request.headers: # Events are aggregated hourly if not download or ((datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 db.add(download) db.flush() db.commit() mod.downloads.append(download) else: download.downloads += 1 mod.download_count += 1 response = make_response(send_file(os.path.join(_cfg("storage"), version.download_path), as_attachment=True)) if _cfg("use-x-accel") == "true": response = make_response("") response.headers["Content-Type"] = "application/zip" response.headers["Content-Disposition"] = "attachment; filename=" + os.path.basename(version.download_path) response.headers["X-Accel-Redirect"] = "/internal/" + version.download_path return response
def test_api_mod(client: 'FlaskClient[Response]') -> None: # Arrange game = Game( name='Kerbal Space Program', publisher=Publisher(name='SQUAD', ), short='kerbal-space-program', active=True, ) mod = Mod( name='Test Mod', short_description='A mod for testing', description='A mod that we will use to test the API', user=User( username='******', description='Test author of a test mod', email='*****@*****.**', forumUsername='******', public=True, ), license='MIT', game=game, ckan=False, default_version=ModVersion( friendly_version="1.0.0.0", gameversion=GameVersion( friendly_version='1.2.3', game=game, ), download_path='/tmp/blah.zip', created=datetime.now(), ), published=True, ) mod.default_version.mod = mod db.add(game) db.add(mod) db.commit() # Act publishers_resp = client.get('/api/publishers') games_resp = client.get('/api/games') kspversions_resp = client.get('/api/kspversions') gameversions_resp = client.get('/api/1/versions') mod_resp = client.get('/api/mod/1') mod_version_resp = client.get('/api/mod/1/latest') user_resp = client.get('/api/user/TestModAuthor') typeahead_resp = client.get('/api/typeahead/mod?game_id=1&query=Test') search_mod_resp = client.get('/api/search/mod?query=Test&page=1') search_user_resp = client.get('/api/search/user?query=Test&page=0') # Assert assert mod_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_mod(mod_resp.json) # Not returned by all APIs assert mod_resp.json[ 'description'] == 'A mod that we will use to test the API', 'Short description should match' assert kspversions_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_game_version(kspversions_resp.json[0]) assert gameversions_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_game_version(gameversions_resp.json[0]) assert games_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_game(games_resp.json[0]) assert publishers_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_publisher(publishers_resp.json[0]) assert mod_version_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_mod_version(mod_version_resp.json) assert user_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_user(user_resp.json) assert typeahead_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_mod(typeahead_resp.json[0]) assert search_mod_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_mod(search_mod_resp.json[0]) assert search_user_resp.status_code == status.HTTP_200_OK, 'Request should succeed' check_user(search_user_resp.json[0])
def create_mod(): if request.method == 'GET': return render_template("create.html") else: user = get_user() if not user.public: # Only public users can create mods # /create tells users about this return redirect("/create/mod") name = request.form.get('name') description = request.form.get('description') short_description = request.form.get('short-description') version = request.form.get('version') ksp_version = request.form.get('ksp-version') external_link = request.form.get('external-link') license = request.form.get('license') source_link = request.form.get('source-code') donation_link = request.form.get('donation') screenshots = request.form.get('screenshots') videos = request.form.get('videos') background = request.form.get('backgroundMedia') zipball = request.files.get('zipball') # Validate if not name \ or not short_description \ or not description \ or not version \ or not ksp_version \ or not license \ or not zipball: # Client side validation means that they're just being pricks if they # get here, so we don't need to show them a pretty error message abort(400) screenshot_list = screenshots.split(',') video_list = videos.split(',') # Validation, continued if len(name) > 100 \ or len(description) > 100000 \ or len(donation_link) > 512 \ or len(external_link) > 512 \ or len(license) > 128 \ or len(source_link) > 256 \ or len(background) > 32 \ or len(screenshot_list) > 5 \ or len(video_list) > 2: abort(400) mod = Mod() mod.user = user mod.name = name mod.description = description mod.short_description = short_description mod.external_link = external_link mod.license = license mod.source_link = source_link mod.donation_link = donation_link mod.background = background # Do media for screenshot in screenshot_list: if screenshot: r = requests.get('https://mediacru.sh/' + screenshot + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'image': for f in j['files']: if f['type'] == 'image/jpeg' or f['type'] == 'image/png': data = f['file'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) for video in video_list: if video: r = requests.get('https://mediacru.sh/' + video + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'video': data = j['hash'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) db.add(m) # Save zipball filename = secure_filename(name) + '-' + secure_filename(version) + '.zip' base_path = os.path.join(secure_filename(user.username) + '_' + str(user.id), secure_filename(name)) full_path = os.path.join(_cfg('storage'), base_path) if not os.path.exists(full_path): os.makedirs(full_path) path = os.path.join(full_path, filename) if os.path.isfile(path): # We already have this version # TODO: Error message abort(400) zipball.save(path) if not zipfile.is_zipfile(path): os.remove(path) abort(400) # TODO: Error message version = ModVersion(secure_filename(version), ksp_version, os.path.join(base_path, filename)) mod.versions.append(version) db.add(version) # Save database entry db.add(mod) db.commit() return redirect('/mod/' + str(mod.id) + '/' + secure_filename(mod.name)[:64])
def mod(id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == id).first() if not mod: abort(404) editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not mod.published and not editable: abort(401) videos = list() screens = list() latest = mod.versions[0] screenshot_list = ",".join([s.data for s in mod.media if s.type == 'image']) video_list = ",".join([s.data for s in mod.media if s.type == 'video']) for m in mod.medias: if m.type == 'video': videos.append(m) else: screens.append(m) referral = request.referrer if referral: host = urllib.parse.urlparse(referral).hostname event = ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .filter(ReferralEvent.host == host)\ .first() if not event: event = ReferralEvent() event.mod = mod event.events = 1 event.host = host mod.referrals.append(event) db.add(event) else: event.events += 1 db.commit() download_stats = None follower_stats = None referrals = None json_versions = None thirty_days_ago = datetime.now() - timedelta(days=30) if editable: referrals = list() for r in ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .order_by(desc(ReferralEvent.events)): referrals.append( { 'host': r.host, 'count': r.events } ) download_stats = list() for d in DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id)\ .filter(DownloadEvent.created > thirty_days_ago)\ .order_by(DownloadEvent.created): download_stats.append(dumb_object(d)) follower_stats = list() for f in FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .filter(FollowEvent.created > thirty_days_ago)\ .order_by(FollowEvent.created): follower_stats.append(dumb_object(f)) json_versions = list() for v in mod.versions: json_versions.append({ 'name': v.friendly_version, 'id': v.id }) return render_template("mod.html", **{ 'mod': mod, 'videos': videos, 'screens': screens, 'latest': latest, 'safe_name': secure_filename(mod.name)[:64], 'featured': any(Featured.query.filter(Featured.mod_id == mod.id).all()), 'editable': editable, 'screenshot_list': screenshot_list, 'video_list': video_list, 'download_stats': download_stats, 'follower_stats': follower_stats, 'referrals': referrals, 'json_versions': json_versions, 'thirty_days_ago': thirty_days_ago })
def mod(id, mod_name): games = Game.query.filter(Game.active == True).order_by(desc( Game.id)).all() if session.get('gameid'): if session['gameid']: ga = Game.query.filter(Game.id == session['gameid']).order_by( desc(Game.id)).first() else: ga = Game.query.filter( Game.short == 'kerbal-space-program').order_by(desc( Game.id)).first() else: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by( desc(Game.id)).first() session['game'] = ga.id session['gamename'] = ga.name session['gameshort'] = ga.short session['gameid'] = ga.id mod = Mod.query.filter(Mod.id == id, Mod.game_id == ga.id).first() if not mod: abort(404) if not mod or not ga: abort(404) editable = False if current_user: if current_user.admin: editable = True if current_user.id == mod.user_id: editable = True if not mod.published and not editable: abort(401) latest = mod.default_version() referral = request.referrer if referral: host = urllib.parse.urlparse(referral).hostname event = ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .filter(ReferralEvent.host == host)\ .first() if not event: event = ReferralEvent() event.mod = mod event.events = 1 event.host = host db.add(event) db.flush() db.commit() mod.referrals.append(event) else: event.events += 1 download_stats = None follower_stats = None referrals = None json_versions = None thirty_days_ago = datetime.now() - timedelta(days=30) referrals = list() for r in ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .order_by(desc(ReferralEvent.events)): referrals.append({'host': r.host, 'count': r.events}) download_stats = list() for d in DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id)\ .filter(DownloadEvent.created > thirty_days_ago)\ .order_by(DownloadEvent.created): download_stats.append(dumb_object(d)) follower_stats = list() for f in FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .filter(FollowEvent.created > thirty_days_ago)\ .order_by(FollowEvent.created): follower_stats.append(dumb_object(f)) json_versions = list() for v in mod.versions: json_versions.append({'name': v.friendly_version, 'id': v.id}) if request.args.get('noedit') != None: editable = False forumThread = False if mod.external_link != None: try: u = urlparse(mod.external_link) if u.netloc == 'forum.kerbalspaceprogram.com': forumThread = True except e: print(e) pass total_authors = 1 pending_invite = False owner = editable for a in mod.shared_authors: if a.accepted: total_authors += 1 if current_user: if current_user.id == a.user_id and not a.accepted: pending_invite = True if current_user.id == a.user_id and a.accepted: editable = True games = Game.query.filter(Game.active == True).order_by(desc( Game.id)).all() game_versions = GameVersion.query.filter( GameVersion.game_id == mod.game_id).order_by(desc( GameVersion.id)).all() outdated = False if latest: outdated = latest.gameversion.id != game_versions[ 0].id and latest.gameversion.friendly_version != '1.0.5' return render_template( "mod.html", **{ 'mod': mod, 'latest': latest, 'safe_name': secure_filename(mod.name)[:64], 'featured': any(Featured.query.filter(Featured.mod_id == mod.id).all()), 'editable': editable, 'owner': owner, 'pending_invite': pending_invite, 'download_stats': download_stats, 'follower_stats': follower_stats, 'referrals': referrals, 'json_versions': json_versions, 'thirty_days_ago': thirty_days_ago, 'share_link': urllib.parse.quote_plus( _cfg("protocol") + "://" + _cfg("domain") + "/mod/" + str(mod.id)), 'game_versions': game_versions, 'games': games, 'outdated': outdated, 'forum_thread': forumThread, 'new': request.args.get('new') != None, 'stupid_user': request.args.get('stupid_user') != None, 'total_authors': total_authors, "site_name": _cfg('site-name'), "support_mail": _cfg('support-mail'), 'ga': ga })
def download(mod_id, mod_name, version): mod = Mod.query.filter(Mod.id == mod_id).first() if not mod: abort(404) game = Game.query.filter(Game.id == mod.game_id).first() session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if not mod or not game: ga = Game.query.filter(Game.short == 'kerbal-space-program').order_by( desc(Game.id)).first() session['game'] = ga.id session['gamename'] = ga.name session['gameshort'] = ga.short session['gameid'] = ga.id abort(404) else: session['game'] = game.id session['gamename'] = game.name session['gameshort'] = game.short session['gameid'] = game.id if not mod.published and (not current_user or current_user.id != mod.user_id): abort(401) version = ModVersion.query.filter(ModVersion.mod_id == mod_id, \ ModVersion.friendly_version == version).first() if not version: abort(404) download = DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id and DownloadEvent.version_id == version.id)\ .order_by(desc(DownloadEvent.created))\ .first() if not os.path.isfile(os.path.join(_cfg('storage'), version.download_path)): abort(404) if not 'Range' in request.headers: # Events are aggregated hourly if not download or ( (datetime.now() - download.created).seconds / 60 / 60) >= 1: download = DownloadEvent() download.mod = mod download.version = version download.downloads = 1 db.add(download) db.flush() db.commit() mod.downloads.append(download) else: download.downloads += 1 mod.download_count += 1 if _cfg("cdn-domain"): return redirect("http://" + _cfg("cdn-domain") + '/' + version.download_path, code=302) response = None if _cfg("use-x-accel") == 'nginx': response = make_response("") response.headers['Content-Type'] = 'application/zip' response.headers[ 'Content-Disposition'] = 'attachment; filename=' + os.path.basename( version.download_path) response.headers[ 'X-Accel-Redirect'] = '/internal/' + version.download_path if _cfg("use-x-accel") == 'apache': response = make_response("") response.headers['Content-Type'] = 'application/zip' response.headers[ 'Content-Disposition'] = 'attachment; filename=' + os.path.basename( version.download_path) response.headers['X-Sendfile'] = os.path.join(_cfg('storage'), version.download_path) if response is None: response = make_response( send_file(os.path.join(_cfg('storage'), version.download_path), as_attachment=True)) return response
def mod(id, mod_name): mod = Mod.query.filter(Mod.id == id).first() if not mod: abort(404) editable = False if current_user: if current_user.admin: editable = True if current_user.id == mod.user_id: editable = True if not mod.published and not editable: abort(401) latest = mod.default_version() referral = request.referrer if referral: host = urllib.parse.urlparse(referral).hostname event = ReferralEvent.query.filter(ReferralEvent.mod_id == mod.id).filter(ReferralEvent.host == host).first() if not event: event = ReferralEvent() event.mod = mod event.events = 1 event.host = host db.add(event) db.flush() db.commit() mod.referrals.append(event) else: event.events += 1 download_stats = None follower_stats = None referrals = None json_versions = None thirty_days_ago = datetime.now() - timedelta(days=30) referrals = list() for r in ReferralEvent.query.filter(ReferralEvent.mod_id == mod.id).order_by(desc(ReferralEvent.events)): referrals.append({"host": r.host, "count": r.events}) download_stats = list() for d in ( DownloadEvent.query.filter(DownloadEvent.mod_id == mod.id) .filter(DownloadEvent.created > thirty_days_ago) .order_by(DownloadEvent.created) ): download_stats.append(dumb_object(d)) follower_stats = list() for f in ( FollowEvent.query.filter(FollowEvent.mod_id == mod.id) .filter(FollowEvent.created > thirty_days_ago) .order_by(FollowEvent.created) ): follower_stats.append(dumb_object(f)) json_versions = list() for v in mod.versions: json_versions.append({"name": v.friendly_version, "id": v.id}) if request.args.get("noedit") != None: editable = False forumThread = False if mod.external_link != None: try: u = urlparse(mod.external_link) if u.netloc == "forum.kerbalspaceprogram.com": forumThread = True except e: print(e) pass total_authors = 1 pending_invite = False owner = editable for a in mod.shared_authors: if a.accepted: total_authors += 1 if current_user: if current_user.id == a.user_id and not a.accepted: pending_invite = True if current_user.id == a.user_id and a.accepted: editable = True game_versions = GameVersion.query.order_by(desc(GameVersion.id)).all() outdated = False if latest: outdated = game_versions[0].friendly_version != latest.ksp_version return render_template( "mod.html", **{ "mod": mod, "latest": latest, "safe_name": secure_filename(mod.name)[:64], "featured": any(Featured.query.filter(Featured.mod_id == mod.id).all()), "editable": editable, "owner": owner, "pending_invite": pending_invite, "download_stats": download_stats, "follower_stats": follower_stats, "referrals": referrals, "json_versions": json_versions, "thirty_days_ago": thirty_days_ago, "share_link": urllib.parse.quote_plus(_cfg("protocol") + "://" + _cfg("domain") + "/mod/" + str(mod.id)), "game_versions": game_versions, "outdated": outdated, "forum_thread": forumThread, "new": request.args.get("new") != None, "stupid_user": request.args.get("stupid_user") != None, "total_authors": total_authors, } )
def create_mod(): if request.method == 'GET': return render_template("create.html") else: user = get_user() if not user.public: # Only public users can create mods # /create tells users about this return redirect("/create/mod") name = request.form.get('name') description = request.form.get('description') short_description = request.form.get('short-description') version = request.form.get('version') ksp_version = request.form.get('ksp-version') external_link = request.form.get('external-link') license = request.form.get('license') source_link = request.form.get('source-code') donation_link = request.form.get('donation') screenshots = request.form.get('screenshots') videos = request.form.get('videos') background = request.form.get('backgroundMedia') zipball = request.files.get('zipball') # Validate if not name \ or not short_description \ or not description \ or not version \ or not ksp_version \ or not license \ or not zipball: # Client side validation means that they're just being pricks if they # get here, so we don't need to show them a pretty error message abort(400) screenshot_list = screenshots.split(',') video_list = videos.split(',') # Validation, continued if len(name) > 100 \ or len(description) > 100000 \ or len(donation_link) > 512 \ or len(external_link) > 512 \ or len(license) > 128 \ or len(source_link) > 256 \ or len(background) > 32 \ or len(screenshot_list) > 5 \ or len(video_list) > 2: abort(400) mod = Mod() mod.user = user mod.name = name mod.description = description mod.short_description = short_description mod.external_link = external_link mod.license = license mod.source_link = source_link mod.donation_link = donation_link mod.background = background # Do media for screenshot in screenshot_list: if screenshot: r = requests.get('https://mediacru.sh/' + screenshot + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'image': for f in j['files']: if f['type'] == 'image/jpeg' or f[ 'type'] == 'image/png': data = f['file'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) for video in video_list: if video: r = requests.get('https://mediacru.sh/' + video + '.json') if r.status_code != 200: abort(400) j = r.json() data = '' if j['blob_type'] == 'video': data = j['hash'] else: abort(400) m = Media(j['hash'], j['blob_type'], data) mod.medias.append(m) db.add(m) # Save zipball filename = secure_filename(name) + '-' + secure_filename( version) + '.zip' base_path = os.path.join( secure_filename(user.username) + '_' + str(user.id), secure_filename(name)) full_path = os.path.join(_cfg('storage'), base_path) if not os.path.exists(full_path): os.makedirs(full_path) path = os.path.join(full_path, filename) if os.path.isfile(path): # We already have this version # TODO: Error message abort(400) zipball.save(path) if not zipfile.is_zipfile(path): os.remove(path) abort(400) # TODO: Error message version = ModVersion(secure_filename(version), ksp_version, os.path.join(base_path, filename)) mod.versions.append(version) db.add(version) # Save database entry db.add(mod) db.commit() return redirect('/mod/' + str(mod.id) + '/' + secure_filename(mod.name)[:64])
def mod(id, mod_name): mod = Mod.query.filter(Mod.id == id).first() if not mod: abort(404) editable = False if current_user: if current_user.admin: editable = True if current_user.id == mod.user_id: editable = True if not mod.published and not editable: abort(401) latest = mod.default_version() referral = request.referrer if referral: host = urllib.parse.urlparse(referral).hostname event = ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .filter(ReferralEvent.host == host)\ .first() if not event: event = ReferralEvent() event.mod = mod event.events = 1 event.host = host db.add(event) db.flush() db.commit() mod.referrals.append(event) else: event.events += 1 download_stats = None follower_stats = None referrals = None json_versions = None thirty_days_ago = datetime.now() - timedelta(days=30) referrals = list() for r in ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .order_by(desc(ReferralEvent.events)): referrals.append( { 'host': r.host, 'count': r.events } ) download_stats = list() for d in DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id)\ .filter(DownloadEvent.created > thirty_days_ago)\ .order_by(DownloadEvent.created): download_stats.append(dumb_object(d)) follower_stats = list() for f in FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .filter(FollowEvent.created > thirty_days_ago)\ .order_by(FollowEvent.created): follower_stats.append(dumb_object(f)) json_versions = list() for v in mod.versions: json_versions.append({ 'name': v.friendly_version, 'id': v.id }) if request.args.get('noedit') != None: editable = False forumThread = False if mod.external_link != None: try: u = urlparse(mod.external_link) if u.netloc == 'forum.kerbalspaceprogram.com': forumThread = True except e: print(e) pass total_authors = 1 pending_invite = False owner = editable for a in mod.shared_authors: if a.accepted: total_authors += 1 if current_user: if current_user.id == a.user_id and not a.accepted: pending_invite = True if current_user.id == a.user_id and a.accepted: editable = True game_versions = GameVersion.query.order_by(desc(GameVersion.id)).all() outdated = False if latest: outdated = game_versions[0].friendly_version != latest.ksp_version return render_template("mod.html", **{ 'mod': mod, 'latest': latest, 'safe_name': secure_filename(mod.name)[:64], 'featured': any(Featured.query.filter(Featured.mod_id == mod.id).all()), 'editable': editable, 'owner': owner, 'pending_invite': pending_invite, 'download_stats': download_stats, 'follower_stats': follower_stats, 'referrals': referrals, 'json_versions': json_versions, 'thirty_days_ago': thirty_days_ago, 'share_link': urllib.parse.quote_plus(_cfg("protocol") + "://" + _cfg("domain") + "/mod/" + str(mod.id)), 'game_versions': game_versions, 'outdated': outdated, 'forum_thread': forumThread, 'new': request.args.get('new') != None, 'stupid_user': request.args.get('stupid_user') != None, 'total_authors': total_authors, "site_name": _cfg('site-name'), "support_mail": _cfg('support-mail') })
from alembic import command from KerbalStuff.objects import * from KerbalStuff.database import db # Make sure tables are created alembic_cfg = Config("alembic.ini") command.stamp(alembic_cfg, "head") command.upgrade(alembic_cfg, "head") # Create admin user if doesn't exist if not User.query.filter(User.username.ilike("admin")).first(): admin = User("admin", "*****@*****.**", "development") admin.admin = True user.public = True admin.confirmation = None db.add(admin) db.commit() # Create normal user if doesn't exist if not User.query.filter(User.username.ilike("user")).first(): user = User("user", "*****@*****.**", "development") user.public = True user.confirmation = None db.add(user) db.commit() if not Publisher.query.first(): pub = Publisher("Squad") db.add(pub) db.commit()
def mod(id, mod_name): user = get_user() mod = Mod.query.filter(Mod.id == id).first() if not mod: abort(404) editable = False if user: if user.admin: editable = True if user.id == mod.user_id: editable = True if not mod.published and not editable: abort(401) videos = list() screens = list() latest = mod.versions[0] screenshot_list = ",".join( [s.data for s in mod.media if s.type == 'image']) video_list = ",".join([s.data for s in mod.media if s.type == 'video']) for m in mod.medias: if m.type == 'video': videos.append(m) else: screens.append(m) referral = request.referrer if referral: host = urllib.parse.urlparse(referral).hostname event = ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .filter(ReferralEvent.host == host)\ .first() if not event: event = ReferralEvent() event.mod = mod event.events = 1 event.host = host mod.referrals.append(event) db.add(event) else: event.events += 1 db.commit() download_stats = None follower_stats = None referrals = None json_versions = None thirty_days_ago = datetime.now() - timedelta(days=30) if editable: referrals = list() for r in ReferralEvent.query\ .filter(ReferralEvent.mod_id == mod.id)\ .order_by(desc(ReferralEvent.events)): referrals.append({'host': r.host, 'count': r.events}) download_stats = list() for d in DownloadEvent.query\ .filter(DownloadEvent.mod_id == mod.id)\ .filter(DownloadEvent.created > thirty_days_ago)\ .order_by(DownloadEvent.created): download_stats.append(dumb_object(d)) follower_stats = list() for f in FollowEvent.query\ .filter(FollowEvent.mod_id == mod.id)\ .filter(FollowEvent.created > thirty_days_ago)\ .order_by(FollowEvent.created): follower_stats.append(dumb_object(f)) json_versions = list() for v in mod.versions: json_versions.append({'name': v.friendly_version, 'id': v.id}) return render_template( "mod.html", **{ 'mod': mod, 'videos': videos, 'screens': screens, 'latest': latest, 'safe_name': secure_filename(mod.name)[:64], 'featured': any(Featured.query.filter(Featured.mod_id == mod.id).all()), 'editable': editable, 'screenshot_list': screenshot_list, 'video_list': video_list, 'download_stats': download_stats, 'follower_stats': follower_stats, 'referrals': referrals, 'json_versions': json_versions, 'thirty_days_ago': thirty_days_ago })
from alembic.config import Config from alembic import command from KerbalStuff.objects import * from KerbalStuff.database import db # Make sure tables are created alembic_cfg = Config("alembic.ini") command.stamp(alembic_cfg, "head") command.upgrade(alembic_cfg, "head") # Create admin user if doesn't exist if not User.query.filter(User.username.ilike("admin")).first(): admin = User("admin", "*****@*****.**", "development") admin.admin = True admin.confirmation = None db.add(admin) db.commit() # Create normal user if doesn't exist if not User.query.filter(User.username.ilike("user")).first(): user = User("user", "*****@*****.**", "development") user.confirmation = None db.add(user) db.commit()