def admin(board_id): if get_slip() and get_slip().is_admin: board = db.session.query(Board).filter(Board.id == board_id).one() return render_template("board-admin.html", board=board) else: flash("Only admins can access board administration!") return redirect(url_for("boards.catalog", board_id=board_id))
def delete(thread_id): if not get_slip() or not (get_slip().is_admin or get_slip().is_mod): flash("Only moderators and admins can delete threads!") return redirect(url_for("threads.view", thread_id=thread_id)) thread = db.session.query(Thread).filter(Thread.id == thread_id).one() board_id = thread.board ThreadPosts().delete(thread_id) flash("Thread deleted!") return redirect(url_for("boards.catalog", board_id=board_id))
def delete_post(post_id): if not get_slip() or not (get_slip().is_admin or get_slip().is_mod): flash("Only moderators and admins can delete posts!") return redirect(url_for_post(post_id)) thread = db.session.query(Thread).filter(Thread.posts.any(Post.id == post_id)).one() thread_id = thread.id PostRemoval().delete(post_id) flash("Post deleted!") return redirect(url_for("threads.view", thread_id=thread_id))
def admin_update(board_id): if get_slip() is None or get_slip().is_admin is False: flash("Only admins can access board administration!") return redirect(url_for("boards.catalog", board_id=board_id)) board = db.session.query(Board).filter(Board.id == board_id).one() parser = reqparse.RequestParser() parser.add_argument("name", type=str, required=True) parser.add_argument("rules", type=str, required=True) args = parser.parse_args() board.name = args["name"] board.rules = args["rules"] db.session.add(board) db.session.commit() return redirect(url_for("boards.catalog", board_id=board_id))
def move_submit(thread_id): if not get_slip() or not (get_slip().is_admin or get_slip().is_mod): flash("Only moderators and admins can move threads!") return redirect(url_for("threads.view", thread_id=thread_id)) thread = Thread.query.get(thread_id) old_board = thread.board new_board = Board.query.filter(Board.name == request.form["board"]).one() thread.board = new_board.id db.session.add(thread) db.session.commit() invalidate_board_cache(old_board) invalidate_board_cache(new_board) flash("Thread moved!") return redirect(url_for("threads.view", thread_id=thread_id))
def update_poster_slip(poster: Poster, args: dict) -> None: "Updates the current poster with a slip if necessary." if args.get("useslip") is True: slip = get_slip() if slip and (slip.is_admin or slip.is_mod): poster.slip = slip.id db.session.add(poster)
def post(self, thread_id): parser = reqparse.RequestParser() parser.add_argument("subject", type=str) parser.add_argument("body", type=str, required=True) parser.add_argument("useslip", type=inputs.boolean) parser.add_argument("spoiler", type=inputs.boolean) # check captcha cooldown on_cooldown = cooldown.on_captcha_cooldown() # only check of captcha if the client is not on cooldown if on_cooldown is False: if app.config.get("CAPTCHA_METHOD") == "RECAPTCHA": parser.add_argument("recaptcha-token", type=str, required=True) elif app.config.get("CAPTCHA_METHOD") == "CAPTCHOULI": parser.add_argument("captchouli-id", type=str, required=True) for img_num in range(0, 9): # don't bother validating too closely since captchouli takes care of # that for us parser.add_argument("captchouli-%d" % img_num, type=str, default=False) args = parser.parse_args() ip = None # reverse proxy support if 'X-Forwarded-For' in request.headers: ip = request.headers.getlist("X-Forwarded-For")[0].rpartition( ' ')[-1] else: ip = request.environ["REMOTE_ADDR"] # check captcha if necessary board_id = db.session.query(Thread).filter_by(id=thread_id).one().board if on_cooldown is False: if app.config.get("CAPTCHA_METHOD") == "RECAPTCHA": google_response = requests.post( "https://www.google.com/recaptcha/api/siteverify", data={ "secret": app.config["RECAPTCHA_SECRET_KEY"], "response": args["recaptcha-token"] }).json() if google_response["success"] is False: raise CaptchaError("Problem getting reCAPTCHA", board_id) if google_response["score"] < app.config["RECAPTCHA_THRESHOLD"]: raise CaptchaError("reCAPTCHA threshold too low", board_id) elif app.config.get("CAPTCHA_METHOD") == "CAPTCHOULI": captchouli_form = {"captchouli-id": args["captchouli-id"]} for img_num in range(0, 9): key = "captchouli-%d" % img_num captchouli_form[key] = args[key] if not captchouli.valid_solution(captchouli_form): raise CaptchaError("Incorrect CAPTCHA response", board_id) cooldown.refresh_captcha_cooldown() poster = db.session.query(Poster).filter_by(thread=thread_id, ip_address=ip).first() body = args["body"] should_bump = False if poster is None: poster_hex = gen_poster_id() poster = Poster(hex_string=poster_hex, ip_address=ip, thread=thread_id) db.session.add(poster) db.session.flush() # bump thread if the poster hasn't posted in this thread before should_bump = True else: # bump thread if this poster isn't the same as the one who posted last in the thread last_post = db.session.query(Post).filter_by( thread=thread_id).order_by(Post.id.desc()).first() if last_post.poster != poster.id: should_bump = True if args.get("useslip") is True: slip = get_slip() if slip and (slip.is_admin or slip.is_mod): poster.slip = slip.id db.session.add(poster) media_id = None if "media" in request.files and request.files["media"].filename: uploaded_file = request.files["media"] mimetype = uploaded_file.content_type board = db.session.query(Board).filter_by(id=board_id).one() expected_mimetypes = board.mimetypes if re.match(expected_mimetypes, mimetype) is None: db.session.rollback() raise InvalidMimeError(mimetype, board_id) media = storage.save_attachment(uploaded_file) media_id = media.id post = Post(body=body, subject=args["subject"], thread=thread_id, poster=poster.id, media=media_id, spoiler=args["spoiler"]) db.session.add(post) db.session.flush() replying = re.finditer(REPLY_REGEXP, body) replies = set() if replying: for match in replying: raw_reply_id = match.group(2) reply_id = int(raw_reply_id) replies.add(reply_id) for reply_id in replies: reply = Reply(reply_from=post.id, reply_to=reply_id) db.session.add(reply) if should_bump: thread = db.session.query(Thread).filter_by(id=thread_id).one() thread.last_updated = post.datetime db.session.add(thread) db.session.flush() db.session.commit() pubsub_client = keystore.Pubsub() pubsub_client.publish( "new-post", json.dumps({ "thread": thread_id, "post": post.id })) for reply_id in replies: pubsub_client.publish( "new-reply", json.dumps({ "post": post.id, "thread": post.thread, "reply_to": reply_id }))
def post(self, thread_id): parser = reqparse.RequestParser() parser.add_argument("subject", type=str) parser.add_argument("body", type=str, required=True) parser.add_argument("useslip", type=inputs.boolean) parser.add_argument("spoiler", type=inputs.boolean) args = parser.parse_args() ip = ip_to_int(request.environ["REMOTE_ADDR"]) poster = db.session.query(Poster).filter_by(thread=thread_id, ip_address=ip).first() body = args["body"] should_bump = False if poster is None: poster_hex = gen_poster_id() poster = Poster(hex_string=poster_hex, ip_address=ip, thread=thread_id) db.session.add(poster) db.session.commit() # bump thread if the poster hasn't posted in this thread before should_bump = True if args.get("useslip") is True: slip = get_slip() if slip and (slip.is_admin or slip.is_mod): poster.slip = slip.id db.session.add(poster) db.session.commit() media_id = None if "media" in request.files and request.files["media"].filename: uploaded_file = request.files["media"] file_ext = uploaded_file.filename.rsplit('.', 1)[1].lower() media = Media(ext=file_ext) db.session.add(media) db.session.commit() media_id = media.id full_path = os.path.join(app.config["UPLOAD_FOLDER"], "%d.%s" % (media_id, file_ext)) uploaded_file.save(full_path) if file_ext != "webm": # non-webm thumbnail generation thumb = Image.open(full_path) if thumb.mode in ("RGBA", "LA"): background = Image.new(thumb.mode[:-1], thumb.size, (255, 255, 255)) background.paste(thumb, thumb.split()[-1]) thumb = background size = thumb.size scale_factor = 0 # width > height if size[0] > size[1]: scale_factor = 500 / size[0] else: scale_factor = 500 / size[1] new_width = int(thumb.width * scale_factor) new_height = int(thumb.height * scale_factor) thumb = thumb.resize((new_width, new_height), Image.LANCZOS) thumb.convert("RGB").save( os.path.join(app.config["THUMB_FOLDER"], "%d.jpg" % media_id), "JPEG") else: # FIXME: webm thumbnail generation pass post = Post(body=body, subject=args["subject"], thread=thread_id, poster=poster.id, media=media_id, spoiler=args["spoiler"]) db.session.add(post) db.session.commit() replying = re.finditer(REPLY_REGEXP, body) if replying: for match in replying: for raw_reply_id in match.groups(): reply_id = int(raw_reply_id) reply = Reply(reply_from=post.id, reply_to=reply_id) db.session.add(reply) db.session.commit() if should_bump: thread = db.session.query(Thread).filter_by(id=thread_id).one() thread.last_updated = post.datetime db.session.commit()
def move(thread_id): if not get_slip() or not (get_slip().is_admin or get_slip().is_mod): flash("Only moderators and admins can move threads!") return redirect(url_for("threads.view", thread_id=thread_id)) return render_template("thread-move.html", thread_id=thread_id)
def index(): if get_slip() and get_slip().is_admin: boards = db.session.query(Board).all() slips = db.session.query(Slip).all() if (request.method == "POST"): for slip in slips: admin_status = request.form.getlist(slip.name + "_grant_admin") mod_status = request.form.getlist(slip.name + "_grant_mod") revoke_slip = request.form.getlist(slip.name + "_revoke_slip") new_board_name = request.form.getlist("board_name") # editing mod/admin status if (len(admin_status) > 0 and admin_status[0] == "on"): slip.is_admin = True else: slip.is_admin = False if (len(mod_status) > 0 and mod_status[0] == "on"): slip.is_mod = True else: slip.is_mod = False old_slip = db.session.query(Slip).filter( Slip.name == slip.name).one() old_slip.is_admin = slip.is_admin old_slip.is_mod = slip.is_mod # revoking slip if (len(revoke_slip) > 0 and revoke_slip[0] == "on"): db.session.query(Slip).filter( Slip.name == slip.name).delete() # add board if (len(new_board_name) > 0 and len(new_board_name[0]) > 0): # check to see that board already exists existing_boards = db.session.query(Board).filter( Board.name == new_board_name[0]).all() if (len(existing_boards) == 0): new_board = Board(name=new_board_name[0], max_threads=50, mimetypes="", rules="", subreddits="") db.session.add(new_board) # Delete board for board in boards: delete_board = request.form.getlist(board.name + "_delete_board") if (len(delete_board) > 0 and delete_board[0] == "on"): boards_to_delete = db.session.query(Board).filter( Board.name == board.name).all() for tmp_board in boards_to_delete: threads_to_delete = db.session.query(Thread).filter( Thread.board == tmp_board.id).all() for thread in threads_to_delete: posts_to_delete = db.session.query(Post).filter( Post.thread == thread.id).all() for post in posts_to_delete: db.session.query(Post).filter( Post.id == post.id).delete() db.session.query(Thread).filter( Thread.id == thread.id).delete() db.session.query(Board).filter( Board.id == tmp_board.id).delete() db.session.commit() # edit FAQ faq = request.form.getlist("faq") if (len(faq) > 0): faq = faq[0] # edit rules rules = request.form.getlist("rules") if (len(rules) > 0): rules = rules[0] elif (request.method == "GET"): print("doing nothing") return render_template("site-admin.html", boards=boards, slips=slips, faq=render_template("faq.html"), rules=render_template("rules.html")) else: flash("Only admins can access board administration!") return redirect(url_for("main.faq"))