コード例 #1
0
ファイル: ImageResizer.py プロジェクト: tumeme/tumeme
def delete_invalid_pics(directory=config.IMG_DIR):
    pic_names = Database.read(config.DB_PATH, "SELECT pic_url FROM img", fetch_number=config.MAX_FRONTPAGE_LEN)
    pic_names = [name[0] for name in pic_names]
    invalid_pic_names = list()
    for name in pic_names:
        try: 
            with Image.open(os.path.join(config.IMG_DIR, name)) as img:
                continue
        except:
            print("invalid pic detected")
            invalid_pic_names.append(name)

    if len(invalid_pic_names) > 0:
        Database.apply_query(config.DB_PATH, "DELETE FROM img WHERE pic_url IN (" + ("?,"*len(invalid_pic_names))[:-1] + ")", payload=tuple(invalid_pic_names) )
        for name in invalid_pic_names:
            os.remove(os.path.join(config.IMG_DIR, name)) # TODO: this might be exploited if the secure_filename function of tumeme.py fails, but what the hell
コード例 #2
0
ファイル: kackcha.py プロジェクト: tumeme/tumeme
def clean():
    kackchas = Database.read(config.DB_PATH,
                             "SELECT name, date FROM kackchas",
                             fetch_number=config.NUMBER_OF_KACKCHAS)
    for kackcha in kackchas:
        # delete kackcha if older than two minutes
        if (datetime.datetime.now() - datetime.datetime.strptime(
                kackcha[1], "%Y-%m-%dT%H:%M:%S.%f")).total_seconds() >= 120:
            _delete(kackcha[0])
コード例 #3
0
    def _promote_memes(self, to_promote):
        """ used by the update frontpage method """
        # TODO: make less stupid
        for meme in to_promote:
            payload = tuple([meme[key] for key in meme])
            assert len(
                payload
            ) == 7, "invalid payload length, should be 7 but is " + str(
                len(payload))
            Database.apply_query(
                config.DB_PATH,
                "INSERT INTO img VALUES (?, ?, ?, ?, ?, ?, ?)",
                payload=payload)

            # move the file
            os.rename(os.path.join(config.QUEUE_DIR, meme["pic_url"]),
                      os.path.join(config.IMG_DIR, meme["pic_url"]))

        # now delete the old data base entries
        self._delete_memes("queue", to_promote)
コード例 #4
0
    def _delete_memes(self, table: str, to_delete: list):
        """ deletes memes from db """
        payload = tuple([meme["pic_url"] for meme in to_delete])
        # kind of hacky/borderline stupid
        payload_string = ("?," * len(to_delete))[:-1]
        Database.apply_query(
            config.DB_PATH, "DELETE FROM " + table + " WHERE pic_url IN (" +
            payload_string + ")", payload)

        # determine the directory-path we have to delete from
        delete_dir = ""
        if table == "queue":
            delete_dir = config.QUEUE_DIR
        else:
            delete_dir = config.IMG_DIR

        for meme in to_delete:
            if os.path.isfile(
                    os.path.abspath(os.path.join(delete_dir,
                                                 meme["pic_url"]))):
                os.remove(os.path.join(delete_dir, meme["pic_url"]))
コード例 #5
0
    def calculate_memerank(self):
        def _calculate_rank(meme_dict: OrderedDict) -> float:
            """ high rank <=> dank meme; low rank <=> stale meme"""
            meme_time = datetime.datetime.strptime(meme["date"],
                                                   "%Y-%m-%dT%H:%M:%S.%f")
            now_time = datetime.datetime.now()
            age_in_secs = abs((now_time - meme_time).total_seconds()) + 1
            upvotes, downvotes = int(meme_dict["upvotes"]), int(
                meme_dict["downvotes"])

            # TODO: for very high upvote-counts modify the equation with log() or something
            return round(
                5 + upvotes - downvotes - age_in_secs / (1200 * 6), 3
            )  # one new upvote reverts the loss of meme-value that occurs in 120 minutes

        # TODO: this has horrible implications in terms of performance, but what the f**k
        img_memes = self._get_n_memes("img")
        for meme in img_memes:
            rank = _calculate_rank(meme)
            # every meme has an unigque pic_url. what could possibly go wrong?
            Database.apply_query(config.DB_PATH,
                                 "UPDATE img SET rank = ? WHERE pic_url=?",
                                 payload=(rank, meme["pic_url"]))
コード例 #6
0
    def _get_n_memes(self, table: str, num_of_memes=None) -> list:
        if not num_of_memes:
            if table == "queue": num_of_memes = config.MAX_QUEUE_LEN
            else: num_of_memes = config.MAX_FRONTPAGE_LEN

        # CREATE table queue (title text, memetype text, pic_url text, date text, upvotes integer, downvotes integer, rank integer) (structure of our db)
        result_abstraction = OrderedDict([("text", ""), ("memetype", ""),
                                          ("pic_url", ""), ("date", ""),
                                          ("upvotes", ""), ("downvotes", ""),
                                          ("rank", "")])
        # gotta catch em all
        return Database.read(config.DB_PATH,
                             "SELECT * FROM " + table,
                             fetch_number=num_of_memes,
                             result_abstraction=result_abstraction)
コード例 #7
0
def create_app(setup=False):
    if setup:
        Database.apply_query(
            config.DB_PATH,
            "CREATE table queue (title text, memetype text, pic_url text, date text, upvotes integer, downvotes integer, rank integer)"
        )  # for our img-queue, used to store file-uploads temporarily before visible
        Database.apply_query(
            config.DB_PATH,
            "CREATE table img (title text, memetype text, pic_url text, date text, upvotes integer, downvotes integer, rank integer)"
        )  # for theimages that made it past the queue
        Database.apply_query(
            config.DB_PATH,
            "CREATE table cookiejar (uid text, pic_url text, upvoted integer, downvoted integer, identity text)"
        )
        Database.apply_query(
            config.DB_PATH,
            "CREATE table cookiejar (uid text, pic_url text, upvoted integer, downvoted integer, identity text)"
        )

    # limit the file-upload size to 10mb
    BaseRequest.max_content_length = 10 * 1024 * 1024
    BaseRequest.max_from_memory_size = 10 * 1024 * 1024

    class Request(BaseRequest):
        pass

    app = Tumeme()
    app.wsgi_app = SharedDataMiddleware(
        app.wsgi_app, {
            "/static": os.path.join(os.path.dirname(__file__), "static"),
            "/img": os.path.join(os.path.dirname(__file__), "img"),
            "/kackchas": os.path.join(os.path.dirname(__file__), "kackchas")
        })

    # apply the requestEntityTooLarge connection reset fix
    #app.wsgi_app = StreamConsumingMiddleware(app.wsgi_app)
    return app
コード例 #8
0
    def upload_page(self, request):
        """ upload page logic - does what you‘d expect """
        def allowed_file(filename):
            ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
            """ see flask docs """
            return '.' in filename and \
            filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

        # detect "kackcha-spam"
        identity = str(request.remote_addr) + str(
            request.user_agent
        )  # not really secure, but might be good enough in many cases
        if len(
                Database.read(config.DB_PATH,
                              "SELECT * FROM kackchas WHERE identity=?",
                              payload=(identity, ),
                              fetch_number=10)) > 8:
            print("User spammy with the kackchas")
            kackcha.delete_by_id(identity)

        # first captcha stuff
        captcha_url = os.path.join("kackchas", kackcha.create_new(identity))
        if not captcha_url:
            return self.render_template(
                "upload.html",
                error=
                "Rolling out your own captcha: what could possibly go wrong? (sorry)"
            )

        # now the actual upload magic
        if request.method == "POST":
            # first: is the captcha solved at all, and if so, correctly?
            valid_captcha_names = [
                os.path.join("kackchas", kack[0]) for kack in Database.read(
                    config.DB_PATH,
                    "SELECT name FROM kackchas",
                    fetch_number=config.NUMBER_OF_KACKCHAS)
            ]
            print((request.form["kackcha-name"], ) in valid_captcha_names)

            # user tried to be smart, tell him/her/it to f**k off
            if "kackcha" not in request.form or "kackcha-name" not in request.form or request.form[
                    "kackcha-name"] not in valid_captcha_names:
                return self.render_template(
                    "upload.html",
                    error="You messed around with the captchas, didn‘t you?",
                    captcha_url=captcha_url)

            expected_result = Database.read(
                config.DB_PATH,
                "SELECT solution FROM kackchas WHERE name=?",
                payload=(request.form["kackcha-name"].replace(
                    "kackchas/", "", 1), ))  # TODO: less hacky

            if not expected_result:
                return self.render_template(
                    "upload.html",
                    error="I f****d something up with the captchas, sorry.",
                    captcha_url=captcha_url)

            # check if user entered the right solution for the captcha
            if str(expected_result[0][0]) != str(request.form["kackcha"]):
                kackcha._delete(request.form["kackcha-name"].replace(
                    "kackchas/", "", 1))  #TODO: less hacky
                return self.render_template(
                    "upload.html",
                    error=
                    "Captcha solution incorrect, so you‘re either brainlet or robot, can‘t tell.",
                    captcha_url=captcha_url)
            else:
                # user solved captcha, delet dis
                try:
                    kackcha._delete(request.form["kackcha-name"].replace(
                        "kackchas/", "", 1))  #TODO: less hacky
                except:
                    print("kakcha already ded")

            # now bunch of checks if form data seems valid
            if not "picture" in request.files or not allowed_file(
                    request.files["picture"].filename
            ):  # hey it‘s me ur de morgan
                return self.render_template(
                    "upload.html",
                    error="This does not look like a picture, m‘harald.",
                    captcha_url=captcha_url)
            elif not "title" in request.form or not "memetype" in request.form:
                print(request.form)
                return self.render_template(
                    "upload.html",
                    error=
                    "Your post needs a title and at least one keyword, m‘harald.",
                    captcha_url=captcha_url)
            elif len(request.form["title"]) == 0 or len(
                    request.form["title"]) > 42:  # check for too long words
                return self.render_template(
                    "upload.html",
                    error=
                    "Your title needs between one and 42 characters, m‘harald.",
                    captcha_url=captcha_url)
            elif len(request.form["memetype"]) > 16:
                return self.render_template(
                    "upload.html",
                    error=
                    "No more than 16 characters for the memetype, m‘harald.",
                    captcha_url=captcha_url)

            # okay, data seems kind of sane now, put the pic in our queue folder and save the metadata
            pic = request.files["picture"]
            filename = os.path.join(config.QUEUE_DIR,
                                    secure_filename(pic.filename))

            # make sure we don‘t overwrite existing files
            while os.path.isfile(os.path.abspath(filename)) or os.path.isfile(
                    os.path.abspath(
                        os.path.join(config.IMG_DIR,
                                     os.path.split(filename)[1]))):
                print(filename)
                filename = "".join(filename.split(".")[:-1]) + str(
                    random.randrange(0, 1000)) + "." + filename.split(".")[-1]

            pic.save(filename)

            # we insert the metadata of our image in the queue db, the MemeGatekeeper will keep track of which one‘s to actually deliver by putting them in /img and the corresponding img db
            metadata = (request.form["title"], request.form["memetype"],
                        os.path.split(filename)[1],
                        datetime.datetime.now().isoformat(), "0", "0", "0"
                        )  #    title, memetype, pic_url, date, upvotes
            Database.apply_query(
                config.DB_PATH,
                "INSERT INTO queue VALUES(?, ?, ?, ?, ?, ?, ?)",
                payload=metadata)

            # the user uploaded his image, back to the frontpage (we want the ones with the highest rank to be showed first)
            dankest_memes = Database.read(config.DB_PATH,
                                          "SELECT * FROM " +
                                          config.IMG_TABLE_NAME +
                                          " ORDER BY rank DESC",
                                          fetch_number=config.IMG_PER_PAGE)
            return redirect("/?success")

        return self.render_template("upload.html", captcha_url=captcha_url)
コード例 #9
0
    def vote(self, request):
        """ implementation of up/downvotes: the client sends an asynchronous POST-request """

        if request.method == "POST" and "vote" in request.form and "post" in request.form and request.cookies.get(
                "user-id"):
            #print("vote: " + request.form["vote"] + "\n post: " + request.form["post"])

            uid = request.cookies.get("user-id")
            pic_url = request.form["post"]
            vote = request.form["vote"]

            identity = str(request.remote_addr) + str(
                request.user_agent
            )  # not really secure, but might be good enough in many cases
            evil_user = len(
                Database.read(
                    config.DB_PATH,
                    "SELECT identity FROM cookiejar WHERE identity=? AND uid != ?",
                    payload=(identity, uid))) != 0
            if evil_user:
                print("evil user detected")
                return redirect("/")  # just do nothing

            # does the given meme even exist?
            if Database.read(config.DB_PATH,
                             "SELECT * FROM img WHERE pic_url=?",
                             payload=(pic_url, )):
                user_history = Database.read(
                    config.DB_PATH,
                    "SELECT * FROM cookiejar WHERE uid=? AND pic_url=?",
                    payload=(uid, pic_url),
                    result_abstraction=OrderedDict([("uid", ""), ("post", ""),
                                                    ("upvoted", ""),
                                                    ("downvoted", ""),
                                                    ("identity", "")]))

                # user has not voted on the meme given by pic_url
                if not user_history:
                    # check if still space
                    stored_cookies = Database.read(
                        config.DB_PATH,
                        "SELECT uid FROM cookiejar",
                        fetch_number=config.MAX_COOKIEJAR_ENTRIES)
                    # if not, delete the 40 first cookies
                    if len(stored_cookies) == config.MAX_COOKIEJAR_ENTRIES:
                        for i in range(40):
                            Database.apply_query(
                                config.DB_PATH,
                                "DELETE FROM cookiejar WHERE uid=?",
                                payload=(stored_cookies[i][0], ))

                    payload = (uid, pic_url, int(vote == "up"),
                               int(vote == "down"), identity)
                    Database.apply_query(
                        config.DB_PATH,
                        "INSERT INTO cookiejar VALUES(?, ?, ?, ?, ?)", payload)
                    if vote == "up":
                        Database.apply_query(
                            config.DB_PATH,
                            "UPDATE img SET upvotes=upvotes+1 WHERE pic_url=?",
                            payload=(pic_url, ))
                    elif vote == "down":
                        Database.apply_query(
                            config.DB_PATH,
                            "UPDATE img SET downvotes=downvotes+1 WHERE pic_url=?",
                            payload=(pic_url, ))

                # user wants to upvote, but has already downvoted the same meme
                elif request.form["vote"] == "up" and user_history[0][
                        "upvoted"] == 0:
                    Database.apply_query(
                        config.DB_PATH,
                        "UPDATE img SET downvotes=downvotes-1, upvotes=upvotes+1 WHERE pic_url=?",
                        payload=(pic_url, ))
                    Database.apply_query(
                        config.DB_PATH,
                        "UPDATE cookiejar SET upvoted=1, downvoted=0 WHERE pic_url=? AND uid=?",
                        payload=(pic_url, uid))

                # user wants to downvote, but has already upvoted the same meme
                elif request.form["vote"] == "down" and user_history[0][
                        "downvoted"] == 0:
                    Database.apply_query(
                        config.DB_PATH,
                        "UPDATE img SET upvotes=upvotes-1, downvotes=downvotes+1 WHERE pic_url=?",
                        payload=(pic_url, ))
                    Database.apply_query(
                        config.DB_PATH,
                        "UPDATE cookiejar SET upvoted=0, downvoted=1 WHERE pic_url=? AND uid=?",
                        payload=(pic_url, uid))

        votes = Database.read(
            config.DB_PATH,
            "SELECT upvotes, downvotes FROM img WHERE pic_url=?",
            payload=(request.form["post"], ))
        if not votes or len(votes[0]) != 2:
            votes = (0, 0)
        return Response(str(votes[0][0]) + " " + str(votes[0][1]),
                        mimetype="text/plain")
コード例 #10
0
    def main_page(self, request):
        """ the front page """

        info, error, already_voted = None, None, None  # should use attributes instead, but f**k oop
        if "success" in request.args:
            info = "Thanks for uploading dank memes, m‘harald."

        current_page = 0
        if "page" in request.args:
            try:
                current_page = abs(int(request.args["page"]))
                if current_page > config.MAX_FRONTPAGE_LEN:
                    current_page = 0
                    info = "You outreached the last page. Congrats for not being normie."

            except:
                print("unable to parse given page")

        dankest_memes = Database.read(
            config.DB_PATH,
            "SELECT * FROM " + config.IMG_TABLE_NAME +
            " ORDER BY rank DESC LIMIT " + str(config.IMG_PER_PAGE) +
            " OFFSET " + str(current_page * config.IMG_PER_PAGE),
            fetch_number=config.IMG_PER_PAGE)

        max_page = math.ceil(
            len(
                Database.read(config.DB_PATH,
                              "SELECT * FROM " + config.IMG_TABLE_NAME,
                              fetch_number=config.MAX_FRONTPAGE_LEN)) /
            config.IMG_PER_PAGE) - 1

        # check if user already has user-id, if not. create a new one (this is just a temporary soulution)
        if not request.cookies.get("user-id"):
            identity = str(request.remote_addr) + str(
                request.user_agent
            )  # not really secure, but might be good enough in many cases
            evil_user = len(
                Database.read(
                    config.DB_PATH,
                    "SELECT identity FROM cookiejar WHERE identity=?",
                    payload=(identity, ))) != 0
            if evil_user:
                error = "Don‘t delete cookies if you want to vote. Try again later."
                response = self.render_template("content.html",
                                                error=error,
                                                content=dankest_memes,
                                                current_page=current_page,
                                                max_page=max_page)
                return response
            else:
                response = self.render_template("content.html",
                                                error=error,
                                                content=dankest_memes,
                                                current_page=current_page,
                                                max_page=max_page)
                response.set_cookie(
                    "user-id",
                    os.urandom(32) + "(nsa-random)".encode("utf-8"),
                    max_age=60 * 60 * 8)  #  8h  cookie TODO: use secure cookie
                return response
        else:
            # used to change the style of the buttons which the user already voted on
            already_voted = Database.read(
                config.DB_PATH,
                "SELECT pic_url, upvoted, downvoted FROM cookiejar WHERE uid=?",
                payload=(request.cookies.get("user-id"), ),
                fetch_number=config.MAX_FRONTPAGE_LEN)
            print(already_voted)
            # add vote_info of already_voted to the memes in dankest_memes TODO: make less ugly
            for i, meme in enumerate(dankest_memes):
                # select the matching vote info
                meme = list(meme)
                meme.append(None)
                dankest_memes[
                    i] = meme  # we want an additional element to store the vote-info
                for vote_info in already_voted:
                    if vote_info[0] == meme[
                            2]:  # pic_url == pic_url (TODO: result abstraction!)
                        print("vote-info", end="")
                        print(vote_info)
                        dankest_memes[i][-1] = vote_info[
                            1:]  #add the vote-info
                        break

        uid = request.cookies.get("user-id")
        identity = str(request.remote_addr) + str(
            request.user_agent
        )  # not really secure, but might be good enough in many cases
        # identify user with same identity but other user-id-cookie -> fishy, probably just deleted his cookie -> cant post till identities get deleted (every 25 mins, see MemeGatekeeper)
        evil_user = len(
            Database.read(
                config.DB_PATH,
                "SELECT identity FROM cookiejar WHERE identity=? AND uid != ?",
                payload=(identity, uid))) != 0
        if evil_user:
            error = "Don‘t delete cookies if you want to vote. Try again later."
        return self.render_template("content.html",
                                    content=dankest_memes,
                                    info=info,
                                    error=error,
                                    current_page=current_page,
                                    max_page=max_page)
コード例 #11
0
 def _flush_identities(self):
     """ removes the cols used for the identification of users who delete cookies (if we didn‘t not do this, we might lock out users from upvoting) """
     Database.apply_query(config.DB_PATH,
                          "UPDATE cookiejar SET identity=''")
コード例 #12
0
ファイル: flush_dbs.py プロジェクト: tumeme/tumeme
#!/usr/bin/env python
from db_wrapper import Database
import config

if __name__ == "__main__":
    print("delet dis")
    Database.apply_query(config.DB_PATH, "DELETE FROM img")
    Database.apply_query(config.DB_PATH, "DELETE FROM queue")
    Database.apply_query(config.DB_PATH, "DELETE FROM kackchas")
    Database.apply_query(config.DB_PATH, "DELETE FROM cookiejar")
コード例 #13
0
ファイル: kackcha.py プロジェクト: tumeme/tumeme
def delete_by_id(identity):
    to_delete = Database.read(config.DB_PATH,
                              "SELECT name FROM kackchas WHERE identity=?",
                              payload=(identity, ))
    for kack in to_delete:
        _delete(kack[0])
コード例 #14
0
ファイル: kackcha.py プロジェクト: tumeme/tumeme
def _delete(name):
    os.remove(os.path.join(config.KACKCHA_DIR, name))
    Database.apply_query(config.DB_PATH,
                         "DELETE FROM kackchas WHERE name=?",
                         payload=(name, ))
    print("deleted")
コード例 #15
0
ファイル: kackcha.py プロジェクト: tumeme/tumeme
def create_new(identity=None, setup=False) -> str:
    def generate_image():
        """ generates an image object of a random kackcha """
        img = Image.new("RGB", (128, 40), (255, 255, 255))
        img.background = (255, 244, 245)
        draw = ImageDraw.Draw(img)
        font = ImageFont.truetype("comic-sans.ttf", 24)  # do it for the memes

        draw.rectangle([0, 0, img.size[0], img.size[1]], fill=(255, 255, 254))

        params = [randrange(-200, 200), randrange(0, 200)]
        correct_result = params[0] + params[1]
        txt = "{}+{}".format(*params)
        draw.text((10, 0),
                  txt,
                  font=font,
                  fill=(randrange(5, 6), randrange(10, 100), randrange(0,
                                                                       255)))
        return img, correct_result

    if setup:
        Database.apply_query(
            config.DB_PATH,
            "CREATE TABLE kackchas (name text, solution integer, date text, identity text)"
        )
        Database.apply_query(config.DB_PATH, "DELETE FROM kackchas")

        # delete the old kaptchas (what could possibly go wrong is left as an exercice to the reader)
        Database.apply_query(config.DB_PATH, "DELETE FROM kackchas")
        to_delete = os.listdir(config.KACKCHA_DIR)
        for kackcha in to_delete:
            if kackcha[-3:] == "png":
                os.remove(os.path.join(config.KACKCHA_DIR, kackcha))

    if not identity:
        return

    # check if enough space for new kackchas
    kackchas = Database.read(config.DB_PATH,
                             "SELECT name FROM kackchas ORDER BY rowid ASC",
                             fetch_number=config.NUMBER_OF_KACKCHAS)
    while len(kackchas) >= config.NUMBER_OF_KACKCHAS:
        # the memeGatekeeper should clean the old kackchas.
        kackchas = Database.read(
            config.DB_PATH,
            "SELECT name FROM kackchas ORDER BY rowid ASC",
            fetch_number=config.NUMBER_OF_KACKCHAS)
        print("too many kackchas, wait")

# create a new  kackcha
    img, correct_result = generate_image()
    # the name we want to save our captcha to
    name = str(randrange(0,
                         100)) + datetime.datetime.now().isoformat() + ".png"
    # repeat till unique
    while os.path.isfile(os.path.join(config.KACKCHA_DIR, name)):
        name = str(randrange(
            0, 10000)) + datetime.datetime.now().isoformat() + ".png"

    # drop da gauss
    img = img.filter(ImageFilter.GaussianBlur(radius=1))
    img.save(os.path.join(config.KACKCHA_DIR, name), "PNG")

    # save the expected result in database along with the name of the captcha and the creation date (we want to delete captchas older than two minutes
    Database.apply_query(config.DB_PATH,
                         "INSERT INTO kackchas VALUES (?, ?, ?, ?)",
                         payload=(name, correct_result,
                                  datetime.datetime.now().isoformat(),
                                  identity))

    return name