Ejemplo n.º 1
0
def add_resource():

    form = forms.ResourceForm(request.form)
    if request.method == "POST" and form.validate():
        # Escape user input using Markup
        title = Markup.escape(form.title.data)
        link = urllib.parse.unquote(Markup.escape(form.link.data))
        note = Markup.escape(form.note.data)
        timestamp = datetime.datetime.fromtimestamp(
            time()).strftime("%Y-%m-%d %H:%M:%S")

        tags = Markup.escape(form.tags.data)
        # If not empty format for proper insertion into postgresql
        if tags:
            tags = "{" + str(tags).lower() + "}"
        else:
            tags = None

        user_id = session["user_id"]

        cur = conn.cursor()
        cur.execute(
            ("""INSERT INTO resources(user_id,title,link,note,tags,date_of_posting) VALUES (%s,%s,%s,%s,%s,%s)"""
             ),
            (user_id, title, link, note, tags, timestamp),
        )
        cur.close()
        conn.commit()

        flash("Resource created successfully.", "success")
        return redirect(url_for("resources"))
    else:
        user_id = session["user_id"]
        cur = conn.cursor()
        cur.execute(
            ("""SELECT DISTINCT unnest(tags) FROM resources WHERE user_id = %s"""
             ),
            (user_id, ),
        )

        tags_raw = cur.fetchall()

        # 'Unpack' tags_raw into one array
        all_tags = []
        for tag_arr in tags_raw:
            all_tags.append(tag_arr[0])

        cur.close()
        return render_template("add_resource.html", form=form, tags=all_tags)
Ejemplo n.º 2
0
def delacc():
    # Check if user is logged in
    if helpers.logged_in():
        # Extract user_id from the current session
        user_id = session["user_id"]

        cur = conn.cursor()
        try:
            # First delete from `resources` so as not to violate foreign key constraints
            cur.execute("DELETE FROM resources WHERE user_id = %s",
                        (user_id, ))

            # Delete from `trash` as not to violate foreign key constraints
            cur.execute("DELETE FROM trash WHERE user_id = %s", (user_id, ))

            # Finally, remove the user from `users`
            cur.execute("DELETE FROM users WHERE id = %s", (user_id, ))

            cur.close()
            conn.commit()

        except DatabaseError:
            cur.rollback()

        session.clear()
        flash("Account deleted. Sad to see you go :(", "danger")
        return redirect("/")
    else:
        flash("You are not logged in.", "danger")
        return redirect(url_for("login"))
Ejemplo n.º 3
0
def undo_trash_res():
    res_id = request.form.get("res_id")
    user_id = session["user_id"]
    cur = conn.cursor()

    # Undo single resource
    if res_id != "*":

        cur.execute(
            ("""INSERT INTO resources SELECT * FROM trash WHERE user_id = %s and re_id = %s"""
             ),
            (user_id, res_id),
        )

        cur.execute(
            ("""DELETE FROM trash WHERE user_id = %s and re_id = %s"""),
            (user_id, res_id),
        )

    # Undo all resources
    else:

        cur.execute(
            ("""INSERT INTO RESOURCES SELECT * FROM trash WHERE user_id = %s"""
             ),
            (user_id, ),
        )

        cur.execute(("""DELETE FROM trash WHERE user_id = %s"""), (user_id, ))

    cur.close()
    conn.commit()

    return redirect(url_for("deleted_res"))
Ejemplo n.º 4
0
    def validate(self):

        # Validate as is and then go ahead with the other checks
        validation = Form.validate(self)
        if not validation:
            return False

        cur = conn.cursor()

        # If username exists
        cur.execute("SELECT username FROM users WHERE username=%s",
                    (self.username.data, ))

        exists = cur.fetchall()

        if exists:
            self.username.errors.append("Username already exists.")
            return False

        # If email exists
        cur.execute("SELECT email FROM users WHERE email=%s",
                    (self.email.data, ))

        exists = cur.fetchall()

        if exists:
            self.email.errors.append("Email is already registered.")
            return False
        return True
Ejemplo n.º 5
0
def options():

    if helpers.logged_in():
        sort = request.cookies.get("sort")
        criteria = request.cookies.get("criteria")
        view = request.cookies.get("view")

        # Get all tags
        cur = conn.cursor()
        user_id = session["user_id"]

        cur.execute(
            ("""SELECT DISTINCT unnest(tags) FROM resources WHERE user_id = %s"""
             ),
            (user_id, ),
        )

        tags_raw = cur.fetchall()

        # 'Unpack' tags_raw into one array
        all_tags = []
        for tag_arr in tags_raw:
            all_tags.append(tag_arr[0])

        return render_template("options.html",
                               sort=sort,
                               criteria=criteria,
                               tags=all_tags,
                               view=view)
    else:
        flash("You must be logged in to access the options page.", "warning")
        return redirect(url_for("login"))
Ejemplo n.º 6
0
def renametag():

    tag = request.form.get("tag")
    replacement = request.form.get("replacement")
    print(replacement)
    if tag:
        if helpers.characters_valid(
                replacement
        ) and not helpers.list_contains_duplicates(replacement):
            cur = conn.cursor()
            cur.execute(
                "UPDATE resources SET tags = array_replace(tags,%s,%s)",
                (tag, replacement),
            )

            cur.close()
            conn.commit()

            flash("Tag renamed successfully.", "success")
        else:
            flash(
                "Invalid tags were given. Check for invalid characters or duplicate tags.",
                "danger",
            )

    return redirect(url_for("options"))
Ejemplo n.º 7
0
def register():

    form = forms.RegisterForm(request.form)
    if request.method == "POST" and form.validate():
        username = form.username.data
        email = form.email.data

        # Encrypt the password using sha256
        password = sha256_crypt.encrypt(str(form.password.data))
        timestamp = datetime.datetime.fromtimestamp(
            time()).strftime("%Y-%m-%d %H:%M:%S")

        if not conn:
            flash("Could not connect to database.", "error")
        else:
            cur = conn.cursor()
            cur.execute(
                ("""INSERT INTO users(email,username,password,date_of_reg) VALUES (%s,%s,%s,%s)"""
                 ),
                (email, username, password, timestamp),
            )

            cur.close()
            conn.commit()
            flash("You are now registered.", "success")
            return redirect(url_for("login"))

    return render_template("register.html", form=form)
Ejemplo n.º 8
0
def fildel():
    # Check if user is logged in
    if helpers.logged_in():

        tags_to_del = request.form.get("tags")
        user_id = session["user_id"]

        tags_array = "{" + tags_to_del + "}"
        cur = conn.cursor()

        # Add to trash
        cur.execute(
            ("""INSERT INTO trash SELECT * FROM resources WHERE user_id = %s AND tags @> %s"""
             ),
            (user_id, tags_array),
        )

        # Then Delete
        cur.execute(
            ("""DELETE FROM resources WHERE user_id = %s AND tags @> %s"""),
            (user_id, tags_array),
        )

        cur.close()
        conn.commit()

        flash("Resources deleted successfully.", "danger")
        return redirect(url_for("options"))
    else:
        flash("You are not logged in.", "danger")
        return redirect(url_for("login"))
Ejemplo n.º 9
0
def remtag():

    tags = request.form.get("tags")

    if tags:
        tags_to_rem = tags.split(",")

        for tag in tags_to_rem:
            cur = conn.cursor()
            cur.execute("UPDATE resources SET tags = array_remove(tags, %s )",
                        (tag, ))

        cur.close()
        conn.commit()

    flash("Tag(s) removed successfully.", "danger")
    return redirect(url_for("options"))
Ejemplo n.º 10
0
    def validate(self):
        validation = Form.validate(self)
        if not validation:
            return False

        cur = conn.cursor()

        # If email exists
        cur.execute("SELECT email FROM users WHERE email=%s",
                    (self.email.data, ))

        exists = cur.fetchall()

        if not exists:
            self.email.errors.append("Invalid email address.")
            return False
        return True
Ejemplo n.º 11
0
def chpass():

    form = forms.ChangePassForm(request.form)
    if request.method == "POST" and form.validate():
        new_password = sha256_crypt.encrypt(str(form.password.data))
        user_id = session["user_id"]

        cur = conn.cursor()
        cur.execute(
            ("""UPDATE users SET password = %s WHERE id = %s"""),
            (new_password, user_id),
        )

        cur.close()
        conn.commit()

        flash("Password changed successfully.", "success")
        return redirect(url_for("options"))
    return render_template("chng_password.html", form=form)
Ejemplo n.º 12
0
def delete_res(user_id, re_id):

    if helpers.logged_in(user_id):
        cur = conn.cursor()

        # First add resource to trash bin
        cur.execute(
            ("""INSERT INTO trash SELECT * FROM resources WHERE user_id = %s and re_id = %s"""
             ),
            (user_id, re_id),
        )

        # And then delete it
        cur.execute(
            ("""DELETE FROM resources WHERE user_id = %s and re_id = %s"""),
            (user_id, re_id),
        )

        cur.close()
        conn.commit()
    return redirect(url_for("resources"))
Ejemplo n.º 13
0
def deleted_res():
    if not helpers.logged_in():
        flash("You must be logged in to access your deleted resources page.",
              "warning")
        return redirect(url_for("login"))
    else:

        user_id = session["user_id"]
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

        # Show in reverse order
        cur.execute(
            ("""SELECT * FROM trash WHERE user_id = %s ORDER BY ctid ASC"""),
            (user_id, ))

        del_resources = cur.fetchall()

        is_empty = False if del_resources else True

        return render_template("deleted_resources.html",
                               del_resources=del_resources,
                               is_empty=is_empty)
Ejemplo n.º 14
0
def export_to_json():
    # Get all of the user's resources
    cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
    user_id = session["user_id"]

    cur.execute(
        ("""SELECT title, link, tags FROM resources WHERE user_id = %s ORDER BY tags"""
         ),
        (user_id, ),
    )

    user_resources_json = json.dumps(cur.fetchall(), indent=2)

    # Save text to byte object
    strIO = BytesIO()
    strIO.write(str.encode(user_resources_json))
    strIO.seek(0)

    # Send html file to client
    return send_file(strIO,
                     attachment_filename="3RStore_export.json",
                     as_attachment=True)
Ejemplo n.º 15
0
def reset_w_token(token):

    # Get email from token
    try:
        pwd_reset_serializer = URLSafeTimedSerializer(app.config["SECRET_KEY"])
        email = pwd_reset_serializer.loads(token,
                                           salt="password-reset-salt",
                                           max_age=3600)
    except:
        flash("The password reset link is invalid or has expired.", "danger")
        return redirect(url_for("login"))

    form = forms.ChangePassForm(request.form)
    if request.method == "POST" and form.validate():

        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        cur.execute(("""SELECT * FROM users WHERE email=%s"""), (email, ))

        user = cur.fetchall()[0]

        if not user:
            flash("Invalid email address!", "danger")
            return redirect(url_for("login"))

        new_password = sha256_crypt.encrypt(str(form.password.data))

        cur.execute(
            ("""UPDATE users SET password = %s WHERE email = %s"""),
            (new_password, email),
        )

        cur.close()
        conn.commit()

        flash("Password changed successfully.", "success")
        return redirect(url_for("login"))

    return render_template("chng_password.html", form=form)
Ejemplo n.º 16
0
def delall():
    # Check if user is logged in
    if helpers.logged_in():
        user_id = session.get("user_id")
        cur = conn.cursor()

        # Add to trash
        cur.execute(
            """INSERT INTO trash SELECT * FROM resources WHERE user_id = %s""",
            ([user_id]),
        )

        # Then Delete
        cur.execute("""DELETE FROM resources WHERE user_id = %s""",
                    ([user_id]))

        cur.close()
        conn.commit()

        flash("All resources were deleted successfully.", "danger")
        return redirect(url_for("resources"))
    else:
        flash("You are not logged in.", "danger")
        return redirect(url_for("login"))
Ejemplo n.º 17
0
def export_to_html():
    def base_html():
        """
        This function creates the following HTML structure:

            <!DOCTYPE NETSCAPE-Bookmark-file-1>
            <META CONTENT="text/html; charset=UTF-8" HTTP-EQUIV="Content-Type"></META>
            <TITLE>3RStore Resources</TITLE>
            <H1>3RStore</H1>
            <DL>
            <P TYPE="Main"></P>
            </DL><P></P>

        After the tag cleanup later on, what remains is the appropriate
        parsable form

            <!DOCTYPE NETSCAPE-Bookmark-file-1>
            <META CONTENT="text/html; charset=UTF-8" HTTP-EQUIV="Content-Type">
            <TITLE>3RStore Resources</TITLE>
            <H1>3RStore</H1>
            <DL><P TYPE="Main">
                {folder contents}
            </DL><P>
        """

        soup = BeautifulSoup("<!DOCTYPE NETSCAPE-Bookmark-file-1>",
                             "html.parser")
        meta_tag = soup.new_tag("META")
        meta_tag["HTTP-EQUIV"] = "Content-Type"
        meta_tag["CONTENT"] = "text/html; charset=UTF-8"
        soup.append(meta_tag)

        title_tag = soup.new_tag("TITLE")
        title_tag.string = "3RStore Resources"
        soup.append(title_tag)

        header_tag = soup.new_tag("H1")
        header_tag.string = "3RStore"
        soup.append(header_tag)

        dl_tag = soup.new_tag("DL")
        p_tag = soup.new_tag("P")
        p_tag["TYPE"] = "Main"
        dl_tag.append(p_tag)
        soup.append(dl_tag)

        soup.append(soup.new_tag("P"))  # <P> closing the final </DL>

        return soup

    def new_bkmrk_folder(main_tag, folder_name, depth):
        """
        This functions creates an HTML structure like so:


            <DT><H3> {folder name} </H3></DT>
            <DL><P></P>
            </DL><P></P>

        After the tag cleanup later on, what remains is the appropriate
        parsable form

            <DT><H3> {folder name} </H3>
            <DL><P>
            </DL><P>
        """

        dt_tag = soup.new_tag("DT", ident=depth)
        h3_tag = soup.new_tag("H3", ident=depth)
        dl_tag = soup.new_tag("DL", ident=depth)
        p_tag = soup.new_tag("P", ident=depth)

        h3_tag.string = folder_name

        dt_tag.append(h3_tag)
        dl_tag.append(p_tag)

        main_tag.append(dt_tag)
        main_tag.append(dl_tag)
        main_tag.append(soup.new_tag(
            "P", ident=depth))  # To close each folder we created

        return p_tag

    def new_bkmrk_link(main_tag, title, link, depth):
        """
        This function creates an HTML structure like so:

            <DT><A {href = link}> {title} </A></DT>

        After the tag cleanup later on, what remains is the appropriate
        parsable form

            <DT><A {href = link}> {title} </A>

        """

        dt_tag = soup.new_tag("DT", ident=depth)

        a_tag = soup.new_tag("A", ident=depth)
        a_tag["HREF"] = link
        a_tag.string = title

        dt_tag.append(a_tag)
        main_tag.append(dt_tag)

    # Get all of the user's resources
    cur = conn.cursor()
    user_id = session["user_id"]

    cur.execute(
        ("""SELECT title, link, tags FROM resources WHERE user_id = %s ORDER BY tags"""
         ),
        (user_id, ),
    )

    user_resources = cur.fetchall()

    # Build relevant structure
    def_folder = Node(name="def", parent=None)  # Tree Root

    for res in user_resources:
        # Build a new node for each resource
        cur_res = cc.MixinResource(res[0], res[1], res[2], res[0], 0,
                                   0)  # Set name same as title
        tags = res[2]

        # If a resource has no tags, put it in the root folder
        if not tags:
            cur_res.parent = def_folder
            continue
        else:

            # Build every subfolder of the resource
            # Which means creating a new node for every tag
            prev_folder = def_folder
            for tag in tags:

                # Check if folder/node already exists
                potential_folder = find(def_folder,
                                        lambda node: node.name == tag)
                if not potential_folder:
                    new_folder = Node(name=tag)
                    new_folder.parent = (
                        prev_folder  # In the first iter this will be def_folder
                    )
                    prev_folder = new_folder
                else:
                    # So that despite not creating a new node the prev_folder
                    # Still holds the previous node/subfolder correctly
                    prev_folder = potential_folder

            # Add resource to the last Node/Folder
            cur_res.parent = find(def_folder,
                                  lambda node: node.name == tags[-1])

    # Handle the actual exporting
    soup = base_html()

    main_tag = soup.find("P", {"TYPE": "Main"})
    prev_folder = main_tag
    prev_was_res = False

    # Build the HTML string/file
    for node in PreOrderIter(def_folder):

        if type(node) == cc.MixinResource:
            new_bkmrk_link(prev_folder, node.title, node.link,
                           (node.depth + 1))

            if not prev_was_res:
                prev_was_res = True
        else:
            if prev_was_res:
                prev_folder = main_tag

            prev_folder = new_bkmrk_folder(prev_folder, node.name,
                                           (node.depth + 1))

    # Remove unecessary tags and add newlines
    final_text = (str(soup).replace("</META>", "\n").replace(
        "</TITLE>", "</TITLE>\n").replace("</H1>", "</H1>\n").replace(
            "<DT",
            "\n<DT").replace("<DL", "\n<DL").replace("</P>", "").replace(
                "</DT>", "").replace("</DL><P", "\n</DL><P"))

    # Add proper identation
    split_text = final_text.splitlines()
    for idx, line in enumerate(split_text):
        res = r.search(r"(?<=.ident=\")\d+", line)

        if res:
            tabs = int(res.group(0))
            split_text[idx] = "\t" * tabs + line

            # Remove the custom"ident" property
            split_text[idx] = r.sub(r" ident=\"\d+\"", "", split_text[idx])

    final_text = "\n".join(split_text)

    # Save text to byte object
    strIO = BytesIO()
    strIO.write(str.encode(final_text))
    strIO.seek(0)

    # Send html file to client
    return send_file(strIO,
                     attachment_filename="3RStore_export.html",
                     as_attachment=True)
Ejemplo n.º 18
0
def resources():

    if not helpers.logged_in():
        flash("You must be logged in to access your resources page.",
              "warning")
        return redirect(url_for("login"))
    else:
        user_id = session["user_id"]

        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

        sort = request.cookies.get("sort")
        criteria = request.cookies.get("criteria")
        if criteria == "title":
            if sort == "asc" or not sort:
                cur.execute(
                    ("""SELECT * FROM resources WHERE user_id = %s ORDER BY title ASC"""
                     ),
                    (user_id, ),
                )
            else:
                cur.execute(
                    ("""SELECT * FROM resources WHERE user_id = %s ORDER BY title DESC"""
                     ),
                    (user_id, ),
                )
        elif criteria == "time" or not criteria:
            if sort == "asc" or not sort:
                cur.execute(
                    ("""SELECT * FROM resources WHERE user_id = %s ORDER BY date_of_posting ASC"""
                     ),
                    (user_id, ),
                )
            else:
                cur.execute(
                    ("""SELECT * FROM resources WHERE user_id = %s ORDER BY date_of_posting DESC"""
                     ),
                    (user_id, ),
                )

        data = cur.fetchall()

        try:
            cur.execute(
                ("""SELECT DISTINCT unnest(tags) FROM resources WHERE user_id = %s"""
                 ),
                (user_id, ),
            )
        except DatabaseError:
            conn.rollbal()

        tags_raw = cur.fetchall()

        # 'Unpack' tags_raw into one array
        all_tags = []
        for tag_arr in tags_raw:
            all_tags.append(tag_arr[0])

        cur.close()
        conn.commit()

        for res in data:
            res["title"] = unescape(res["title"])

        view = request.cookies.get("view")
        if view == "full":
            return render_template(
                "resources.html", resources=data, tags=all_tags, view=view
            )  # Pass 'view' attribute to use the correct .css file
        else:
            return render_template("resources_cmpct.html",
                                   resources=data,
                                   tags=all_tags,
                                   view=view)

    return render_template("resources.html")
Ejemplo n.º 19
0
def open_share(token):

    use_filters = False
    all_tags = False
    try:
        serializer = URLSafeTimedSerializer(app.config["SECRET_KEY"])
        data = serializer.loads(token, salt="share-salt",
                                max_age=259200)  # 3 days
        user_id = data[0]

        if data[1] == "*":
            all_tags = True
            tags = "*"
        else:
            tags = "{" + data[1] + "}"

        if data[2]:
            use_filters = True
            filters = "{" + data[2] + "}"

    except:
        flash("The share  link is invalid or has expired.", "danger")
        return render_template("home.html")

    cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

    if use_filters:
        if all_tags:
            cur.execute(
                """SELECT * FROM resources
                        WHERE user_id= %s
                            AND NOT tags @> %s
                            AND tags IS NOT NULL
                        ORDER BY date_of_posting DESC""",
                (user_id, filters),
            )
        else:
            cur.execute(
                """SELECT * FROM resources
                        WHERE user_id= %s
                            AND tags @> %s
                            AND NOT tags @> %s
                            AND tags IS NOT NULL
                        ORDER BY date_of_posting DESC""",
                (user_id, tags, filters),
            )

    else:
        if all_tags:
            cur.execute(
                """SELECT * FROM resources
                        WHERE user_id= %s
                        ORDER BY date_of_posting DESC""",
                (user_id, ),
            )
        else:
            cur.execute(
                """SELECT * FROM resources
                        WHERE user_id= %s
                            AND tags @> %s
                        ORDER BY date_of_posting DESC""",
                (user_id, tags),
            )

    resources = cur.fetchall()

    cur.close()
    conn.commit()

    return render_template("resources_public.html",
                           resources=resources,
                           tags=tags,
                           view="full")
Ejemplo n.º 20
0
def import_resources():
    cur = conn.cursor()

    # res = cc.BaseResource
    def add_res_to_db(res):

        # Transform tags to all lowercase
        tags = [tag.lower() for tag in res.tags]

        link = urllib.parse.unquote(res.link)

        if res.title:
            title = res.title[0:99]
        else:
            title = res.link[0:50] + "..."

        timestamp = datetime.datetime.fromtimestamp(
            time()).strftime("%Y-%m-%d %H:%M:%S")
        user_id = session["user_id"]

        try:
            cur.execute(
                ("""INSERT INTO resources(user_id,title,link,tags,date_of_posting) VALUES (%s,%s,%s,%s,%s)"""
                 ),
                (user_id, title, link, tags, timestamp),
            )
        except DatabaseError:
            conn.rollback()

    def search_and_insert(filters=None, incl=None):

        tags = []
        prev_was_res = False

        if filters:
            filters = [f.lower()
                       for f in filters]  # Transform into all lowercase

        for cur_el in soup.find_all():

            # Detect folders, aka <DT><H3> {folder name} </H3>
            if cur_el.name == "h3":

                if prev_was_res and tags:
                    tags.pop()
                tags.append(cur_el.string.lower())

            # Detect resources/links aka <DT><A {href}> {title} </A>
            if cur_el.name == "a":
                new_resource = cc.BaseResource(cur_el.string,
                                               cur_el.get("href"), tags)

                if ((not incl and not filters)
                        or (incl and any(f in tags for f in filters))
                        or (not incl and all(f not in tags for f in filters))):
                    add_res_to_db(new_resource)

                if not prev_was_res:
                    prev_was_res = True

    if request.method == "POST":

        if "file" not in request.files:
            flash("No file selected.", "warning")
            return redirect(request.url)
        else:

            file = request.files["file"]
            if file.filename == "":
                flash("No file selected.", "warning")
                return redirect(request.url)

            if file:

                soup = BeautifulSoup(file, "html.parser")

                incl = request.form.get("incl")
                excl = request.form.get("excl")

                if not incl and not excl:  # Default import
                    search_and_insert()

                elif incl and not excl:  # Include only
                    incl_items = incl.split(",")
                    search_and_insert(incl_items, incl=True)

                elif not incl and excl:  # Exclude only
                    excl_items = excl.split(",")
                    search_and_insert(excl_items, incl=False)

                cur.close()
                conn.commit()
                flash("Resources imported successfully.", "success")

    return redirect(url_for("resources"))
Ejemplo n.º 21
0
def login():
    # Check if user is not logged in
    if not helpers.logged_in():

        if request.method == "POST":
            # Grab the fields from the form
            username = request.form["username"]
            password_candidate = request.form["password"]

            # And get the user from the db
            # Treat result as a dictionary
            cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
            try:
                cur.execute(
                    ("""
                SELECT * FROM users WHERE username = %s
                """),
                    (username, ),
                )  # Comma for single element tuple
            except DatabaseError:
                cur.rollback()

            # If we find a user with that username
            data = cur.fetchone()
            if data:
                password = data["password"]

                # Validate pass
                if sha256_crypt.verify(password_candidate, password):
                    session["logged_in"] = True
                    session["username"] = username
                    session["user_id"] = data["id"]

                    # Set default cookies if they don't exist
                    # Build default response
                    resp = make_response(redirect(url_for("resources")))

                    # Sorting cookies
                    sort = request.cookies.get("sort")
                    criteria = request.cookies.get("criteria")
                    if not sort or not criteria:  # If any of them have not been set
                        resp.set_cookie(
                            "sort",
                            "desc",
                            expires=datetime.datetime.now() +
                            datetime.timedelta(days=30),
                        )

                        resp.set_cookie(
                            "criteria",
                            "time",
                            expires=datetime.datetime.now() +
                            datetime.timedelta(days=30),
                        )

                    # View cookies
                    view = request.cookies.get("view")
                    if not view:
                        resp.set_cookie(
                            "view",
                            "full",
                            expires=datetime.datetime.now() +
                            datetime.timedelta(days=30),
                        )

                    flash("You are now logged in.", "success")
                    return resp
                else:
                    error = "Username or password are incorrect"
                    return render_template("login.html", error=error)
            else:
                error = "Username or password are incorrect"
                return render_template("login.html", error=error)

            cur.close()
        else:
            return render_template("login.html")
    else:
        # Otherwise redirect to the `resources` page
        flash("You are already logged in.", "success")
        return redirect(url_for("resources"))
Ejemplo n.º 22
0
def share():

    if request.method == "POST":
        search_str = request.form.get("tags")
        search_str = search_str.lower()

        filters = []
        filters_str = ""

        use_filters = False

        # Assuming standard form <tag1,tag2 -tag4,tag6> we separate filters from tags
        if "-" in search_str:
            use_filters = True
            filters_str = search_str[search_str.find("-") + 1:].strip()
            filters = [f.lower() for f in filters_str.split(",")]

            tags = [
                t.lower()
                for t in search_str[:search_str.find("-") - 1].split(",")
            ]

        else:
            tags = [t.lower() for t in search_str.split(",")]

        tags_str = ",".join(tags).strip()

        if not tags or not tags_str or tags_str == "":
            flash(f"No tags selected. Can't share.", "danger")
            return redirect(url_for("resources"))

        if use_filters and (filters == tags or all(fil in tags
                                                   for fil in filters)):
            flash("Tags and filters are the same. Can't share.", "danger")
            return redirect(url_for("resources"))

        cur = conn.cursor()
        cur.execute(
            ("""SELECT DISTINCT unnest(tags) FROM resources WHERE user_id = %s"""
             ),
            (session["user_id"], ),
        )

        tags_used = cur.fetchall()
        # 'Unpack' tags_raw into one array
        tags_used_clean = ["*"]
        for tag_arr in tags_used:
            tags_used_clean.append(tag_arr[0])

        cur.close()
        conn.commit()

        # If filters or search tags don't contain any actually used (aka existing) tags
        if any(tag not in tags_used_clean or fil not in tags_used_clean
               for tag in tags for fil in filters):

            flash("No such tag exists. Can't share.", "danger")
            return redirect(url_for("resources"))

        serializer = URLSafeTimedSerializer(app.config["SECRET_KEY"])

        share_url = url_for(
            "open_share",
            token=serializer.dumps([session["user_id"], tags_str, filters_str],
                                   salt="share-salt"),
            _external=True,
        )

        if use_filters:
            message = Markup(" \
            Resources containing {" + tags_str + " -" + filters_str +
                             "} can be publicly accessed for 3 days via the \
            following link: <a href=" + share_url + ">Link</a>")
        else:
            message = Markup("Resources containing {" + tags_str +
                             "} can be publicly accessed for 3 days via the \
            following link: <a href=" + share_url + ">Link</a>")

        flash(message, "info")

        return redirect(url_for("resources"))
    return redirect(url_for("resources"))
Ejemplo n.º 23
0
def edit_res(user_id, re_id):

    if request.method == "GET":
        if helpers.logged_in(user_id):

            # Fetch the data we want to edit
            cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
            cur.execute(
                ("""SELECT * FROM resources WHERE user_id = %s and re_id = %s"""
                 ),
                (user_id, re_id),
            )

            data = cur.fetchall()

            # Get the tags to suggest to the user
            cur.execute(
                ("""SELECT DISTINCT unnest(tags) FROM resources WHERE user_id = %s"""
                 ),
                (user_id, ),
            )

            tags_raw = cur.fetchall()

            # 'Unpack' tags_raw into one array
            all_tags = []
            for tag_arr in tags_raw:
                all_tags.append(Markup.escape(tag_arr[0]))

            cur.close()
            conn.commit()

            # Paranoid Mode: On. Escape user input even after we retrieve it from the database.
            # Fill the form with the data
            form = forms.ResourceForm()
            form.title.data = Markup.escape(data[0]["title"])
            form.link.data = Markup.escape(data[0]["link"])
            form.note.data = Markup.escape(data[0]["note"])
            if form.note.data:
                form.note.data = form.note.data.replace(
                    "</br>", "\n")  # Else the </br> tags will display as text

            if data[0]["tags"]:
                form.tags.data = ",".join(data[0]["tags"])  # Array to string
                form.tags.data = Markup.escape(form.tags.data.lower())
            else:
                form.tags.data = ""

            return render_template("edit_resource.html",
                                   title=data[0]["title"],
                                   form=form,
                                   tags=all_tags)

    elif request.method == "POST":

        form = forms.ResourceForm(request.form)
        if form.validate():

            # Grab the new form and its data
            title = form.title.data
            link = Markup.escape(form.link.data)
            note = Markup.escape(form.note.data)
            tags = Markup.escape(form.tags.data)

            # If not empty format for proper insertion into postgresql
            if tags:
                tags = "{" + str(tags).lower() + "}"
            else:
                tags = None

            # Update the row - keep date_of_posting, re_id and user_id the same
            cur = conn.cursor()
            cur.execute(
                ("""UPDATE resources SET title=%s,link=%s,note=%s,tags=%s WHERE user_id=%s AND re_id=%s"""
                 ),
                (title, link, note, tags, user_id, re_id),
            )
            cur.close()
            conn.commit()

            flash("Resource edited successfully.", "success")
            return redirect(url_for("resources"))
        else:
            return render_template("edit_resource.html", form=form)
    return redirect(url_for("resources"))