Пример #1
0
def load_product_data():
    new_product_data = {}
    categories = fireClient.collection("categories").stream()
    for category_obj in categories:
        category = category_obj.to_dict()
        category_id = category["category_id"]
        new_product_data[category_id] = category.copy()
        # make a copy of keys to prevent concurrent modification, reason being we need to convert string key to numbers
        prices = list(new_product_data[category_id]["prices"].keys())
        for price in prices:
            new_product_data[category_id]["prices"][float(
                price)] = new_product_data[category_id]["prices"][price]
            new_product_data[category_id]["prices"].pop(price)
        new_product_data[category_id]["products"] = {}

        products = fireClient.collection("categories").document(
            category_id).collection("products").stream()
        for product_obj in products:
            product = product_obj.to_dict()
            product_id = product["product_id"]
            new_product_data[category_id]["products"][
                product_id] = product.copy()

    global product_data
    product_data = new_product_data
    return product_data
Пример #2
0
def create_template():
    if "user" not in session or "uid" not in session["user"]:
        return redirect(
            url_for("auth.login", redirect=url_for("sms.create_template")))
    user_obj = fireClient.collection("users").document(session["uid"]).get()
    if not user_obj.exists or user_obj.to_dict().get("tier", "") != "director":
        abort(401)
    if request.method == "GET":
        return render_template("create_template.html",
                               available_data=access_property)
    template = {
        "template": request.form["template"],
        "author": {
            "uid": session["user"]["uid"],
            "name": session["user"]["display_name"]
        },
        "generated": False,
        "recipients": {
            user.uid: False
            for user in firebase_auth.list_users().iterate_all()
            if user.uid not in director_uids
        },
        "UTC_timestamp": str(datetime.utcnow())
    }
    template_obj = fireClient.collection("message_templates").document()
    fireClient.collection("message_templates").document(
        template_obj.id).set(template)
    return redirect(url_for("sms.view_template", template_id=template_obj.id))
Пример #3
0
def display_directory():
    directory_ref = fireClient.collection("info").document("directory")
    directory = directory_ref.get().to_dict()
    directors = [(firebase_auth.get_user(directory["directors"][role]), role) for role in director_roles if role in directory["directors"]]
    chapters_dict = fireClient.collection("info").document("chapter_info").get().to_dict()["chapters"]
    chapters = sorted(chapters_dict.items(), key=lambda entry: entry[1])

    return render_template("directory.html", directors=directors, director_names=director_titles, chapters=chapters)
Пример #4
0
def admin_delivered_view():
    delivered_orders = [
        order.to_dict() for order in fireClient.collection("orders").where(
            "status.delivered", "==", True).order_by("UTC_timestamp").stream()
    ]
    return render_template("admin_delivered_view.html",
                           delivered=delivered_orders)
Пример #5
0
def edit_profile():
    if "uid" not in session:
        return redirect(url_for("auth.login"))
    
    uid = session["uid"]
    user = firebase_auth.get_user(session["uid"])
    if request.method == "GET":
        return render_template("edit_profile.html", user=user)
    
    try:
        if session["uid"] != request.form["uid"]:
            abort(400, "UID does not match session")
        phone = ''.join(c for c in request.form["phone"] if c.isdigit() or c == '+')
        if "+" not in phone:
            phone = "+1" + phone
        if user.display_name and request.form["name"] != user.display_name:
            user_ref = fireClient.collection("users").document(user.uid)
            user_dict = user_ref.get().to_dict()
            user_dict["name_array"] = request.form["name"].lower().split()
            user_ref.set(user_dict)
        firebase_auth.update_user(
            uid=session["uid"],
            display_name=request.form["name"],
            email=request.form["email"],
            phone_number=phone
        )
    except Exception as e:
        abort(400, "Malformed edit profile request: " + str(e))
        
    return redirect(url_for("info.view_profile", uid=session["uid"]))
Пример #6
0
def deliver_item():
    if "uid" not in session:
        return redirect(url_for("auth.login"))
    if request.method == "GET":
        return render_template("delivery_form.html",
                               orderID=request.args.get("orderID"),
                               address=request.args.get("address"),
                               price=request.args.get("price"))

    orderID = request.form["orderID"]
    uid = session["uid"]
    # simply mark as delivered
    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")

    order_dict = order_obj.to_dict()
    order_dict["status"]["delivered"] = True

    order_dict["delivery"] = {
        "deliveredBy": {
            "uid": uid,
            "name": session["name"]
        },
        "UTC_timestamp": str(datetime.utcnow())
    }

    order_ref.set(order_dict)
    return redirect(url_for("bakesale.delivery_view"))
Пример #7
0
def invoice_item():
    if "uid" not in session:
        return redirect(url_for("auth.login"))

    if request.method == "GET":
        return render_template("invoice_form.html",
                               orderID=request.args.get("orderID"),
                               price=request.args.get("price"))

    orderID = request.form["orderID"]
    invoiceLink = request.form["invoiceLink"]

    financeID = session["uid"]

    if not orderID or not financeID:
        abort(400, "Invoice request must include order ID and login")

    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")

    order_dict = order_obj.to_dict()

    if order_dict["status"]["invoiced"] or "invoice" in order_dict:
        abort(400, "Order already invoiced")

    order_dict["invoice"] = {"link": invoiceLink, "creator": financeID}

    order_dict["status"]["invoiced"] = True

    order_ref.set(order_dict)
    return redirect(url_for("bakesale.finance_view"))
Пример #8
0
def report_issue():
    if request.method == "GET":
        return render_template("issue_form.html",
                               orderID=request.args.get("orderID"),
                               view=request.args.get("view"))

    issue = {
        "description": request.form["description"],
        "UTC_timestamp": str(datetime.utcnow()),
        "resolved": False
    }

    orderID = request.form["orderID"]
    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")

    order_dict = order_obj.to_dict()
    if "issues" in order_dict:
        order_dict["issues"].append(issue)
    else:
        order_dict["issues"] = [issue]
    order_dict["has_unresolved_issues"] = True

    order_ref.set(order_dict)
    flash(
        "We are sorry that you had an issue with this order, a member of the SCAN team will look at it as soon as possible. Thank you."
    )
    return redirect(
        url_for("bakesale.show_order",
                orderID=orderID,
                view=request.form["view"]))
Пример #9
0
def view_templates():
    message_templates = [
        template
        for template in fireClient.collection("message_templates").order_by(
            "UTC_timestamp", direction=firestore.Query.DESCENDING).stream()
    ]
    return render_template("view_templates.html", templates=message_templates)
Пример #10
0
def view_chapter(chapter_id):
    chapter_ref = fireClient.collection("info").document("chapter_info").collection("chapters").document(chapter_id)
    chapter_obj = chapter_ref.get()
    if not chapter_obj.exists:
        abort(404, "Chapter not found")
    officers = [(firebase_auth.get_user(chapter_obj.get("officers")[role]), role) for role in officer_roles]
    
    return render_template("chapter_directory.html", chapter=chapter_obj.to_dict(), chapter_id=chapter_id, officers=officers, officer_titles=officer_titles)
Пример #11
0
def generate_template(template_id):
    template_ref = fireClient.collection("message_templates").document(
        template_id)
    template_obj = template_ref.get()
    if not template_obj.exists:
        abort(404, "Template not found")
    template = template_obj.to_dict()
    if template["generated"]:
        abort(410, "Template's messages have already been generated")
    new_messages_batch = fireClient.batch()
    num_errors = 0
    error_threshold = 0.05
    ctx = {
        "leaderboard":
        fireClient.collection("statistics").document("sales").get().get(
            "leaderboard")
    }
    for uid in template["recipients"]:
        # If the error rate for message generation exceeds 5%, stop it
        if num_errors / len(template["recipients"]) > error_threshold:
            break
        try:
            msg_ref = fireClient.collection("messages").document()
            user = firebase_auth.get_user(uid)
            msg = {
                "content": render_message(template["template"], user, ctx),
                "sender": random.choice(director_uids),
                "recipient": uid,
                "phone": user.phone_number,
                "sent": False,
                "template_id": template_id
            }
            new_messages_batch.set(msg_ref, msg)
        except:
            num_errors += 1
    if num_errors / len(template["recipients"]) > error_threshold:
        abort(
            400,
            "The error rate for generating messages exceeded %0.2f%%, generation cancelled"
            % (100 * error_threshold))
    else:
        new_messages_batch.commit()
        template["generated"] = True
        template_ref.set(template)
        return redirect(
            url_for("sms.view_template", template_id=template_obj.id))
Пример #12
0
def view_profile(uid):
    user_ref = fireClient.collection("users").document(uid)
    user_obj = user_ref.get()
    if not user_obj.exists:
        abort(404, "User not found")
    user_dict = user_obj.to_dict()
    return render_template("view_profile.html",
                           user=user_dict,
                           rolenames=role_names)
Пример #13
0
def view_template(template_id):
    template_ref = fireClient.collection("message_templates").document(
        template_id)
    template_obj = template_ref.get()
    if not template_obj.exists:
        abort(404, "Template not found")
    return render_template("view_template.html",
                           template=template_obj.to_dict(),
                           template_obj=template_obj)
Пример #14
0
def is_verified(uid):
    try:
        firebase_auth.get_user(uid)
    except:
        return False
    try:
        return fireClient.collection("users").document(uid).get().get("tier") == "director"
    except:
        return False
Пример #15
0
def display_leaderboard():
    leaderboard = fireClient.collection("statistics").document(
        "sales").get().to_dict()["leaderboard"]
    return render_template("leaderboard.html",
                           leaderboard={
                               referral: leaderboard[referral]
                               for referral in leaderboard
                               if referral.lower() not in exec_referral_links
                           })
Пример #16
0
def delivery_view():
    if "uid" not in session:
        return redirect(url_for("auth.login"))

    baked_orders = fireClient.collection("orders").where(
        "status.baked", "==",
        True).where("status.delivered", "==",
                    False).order_by("UTC_timestamp").stream()
    return render_template("delivery_view.html",
                           baked=[order.to_dict() for order in baked_orders])
Пример #17
0
def finance_view():
    if "uid" not in session:
        return redirect(url_for("auth.login"))

    not_invoiced_orders = fireClient.collection("orders").where(
        "status.invoiced", "==", False).order_by("UTC_timestamp").stream()

    return render_template(
        "finance_view.html",
        not_invoiced_orders=[order.to_dict() for order in not_invoiced_orders])
Пример #18
0
def admin_view():
    if "uid" not in session or session["uid"] not in admin_uids:
        return redirect(url_for("auth.login"))

    issue_orders = [
        order.to_dict() for order in fireClient.collection("orders").where(
            "has_unresolved_issues", "==", True).order_by(
                "UTC_timestamp").stream()
    ]
    return render_template("admin_view.html", issue_orders=issue_orders)
Пример #19
0
def view_messages():
    if "uid" not in session:
        return redirect(
            url_for("auth.login", redirect=url_for("sms.view_messages")))

    my_messages = {
        message.id: message.to_dict()
        for message in fireClient.collection("messages").where(
            "sender", "==", session["uid"]).where("sent", "==",
                                                  False).stream()
    }
    return render_template("messages.html", messages=my_messages)
Пример #20
0
def add_vegan_products():
    for category_obj in fireClient.collection("categories").stream():
        category = category_obj.to_dict()
        category_id = category["category_id"]
        if category_id.startswith("r_"):
            continue
        # copying gluten free products: gf_
        new_category_id = "p_" + category_id[3:]

        new_category_data = {
            "name": category["name"].replace("Gluten Free", "Vegan"),
            "category_id": new_category_id,
            "prices": category["prices"].copy()
        }
        
        # fireClient.collection("categories").document(new_category_id).set(new_category_data)
        # print(new_category_id)

        for product_obj in fireClient.collection("categories").document(category_id).collection("products").stream():
            product = product_obj.to_dict()
            new_product = product.copy()
            new_product["product_id"] = "p_" + new_product["product_id"][3:]
Пример #21
0
def mark_sent():
    sent_messages = request.form.getlist("sent")
    if len(sent_messages) < 1:
        return redirect(url_for("sms.view_messages"))
    for message_id in sent_messages:
        message_ref = fireClient.collection("messages").document(message_id)
        message_obj = message_ref.get()
        if not message_obj.exists:
            continue
        message = message_obj.to_dict()
        message["sent"] = True
        message_ref.set(message)

        template_ref = fireClient.collection("message_templates").document(
            message["template_id"])
        template_obj = template_ref.get()
        if not template_obj.exists:
            continue
        template = template_obj.to_dict()
        template["recipients"][message["recipient"]] = True
        template_ref.set(template)

    return redirect(url_for("sms.view_messages"))
Пример #22
0
def baker_view():
    # check login
    if "uid" not in session:
        return redirect(url_for("auth.login"))

    # load in all pending orders
    pending_orders = fireClient.collection("orders").where(
        "status.invoiced", "==",
        True).where("status.baked", "==",
                    False).order_by("UTC_timestamp").stream()

    return render_template(
        "baker_view.html",
        product_data=product_data,
        pending=[order.to_dict() for order in pending_orders])
Пример #23
0
def add_chapter():
    if "uid" not in session or not is_verified(session["uid"]):
        return redirect(url_for("auth.login", redirect=url_for("info.add_chapter")))
    if request.method == "GET":
        return render_template("create_chapter.html")
    if not request.json or "name" not in request.json or "officers" not in request.json or any(role not in request.json["officers"] for role in officer_roles):
        abort(400, "Malformed chapter creation request")
    try:
        for role in officer_roles:
            firebase_auth.get_user(request.json["officers"][role])
    except:
        abort(404, "Officer UIDs not found")
    chapters_info_obj = fireClient.collection("info").document("chapter_info").get()
    chapter_id = chapters_info_obj.get("id_counter")
    chapter_id = str(chapter_id)
    while len(chapter_id) < 3:
        chapter_id = "0" + chapter_id
    
    chapter_dict = chapters_info_obj.get("chapters")
    chapter_dict[request.json["name"]] = chapter_id
    fireClient.collection("info").document("chapter_info").set(
        {
            "id_counter": int(chapter_id) + 1,
            "chapters": chapter_dict
        }
    )

    chapter_ref = fireClient.collection("info").document("chapter_info").collection("chapters").document(chapter_id)

    try:
        officers = request.json["officers"]
        chapter = {
            "name": request.json["name"],
            "officers": {
                role: officers[role] for role in officer_roles
            },
            "ambassadors": []
        }
    except KeyError:
        abort(400, "Malformed chapter creation request")
    batch_write = fireClient.batch()
    batch_write.set(chapter_ref, chapter)
    for uid in officers.values():
        user_ref = fireClient.collection("users").document(uid)
        old_user = user_ref.get().to_dict()
        old_user["tier"] = "officer"
        batch_write.set(fireClient.collection("users").document(uid), old_user)

    batch_write.commit()
    return redirect(url_for("info.view_chapter", chapter_id=chapter_id))
Пример #24
0
def show_order(orderID):
    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")

    view = request.args.get("view", default="customer")
    order_dict = order_obj.to_dict()

    if order_dict["status"]["delivered"]:
        order_dict["statusText"] = "Delivered"
    elif order_dict["status"]["baked"]:
        order_dict["statusText"] = "Baked"
    elif order_dict["status"]["invoiced"]:
        order_dict["statusText"] = "Invoiced"
    else:
        order_dict["statusText"] = "Received"

    if "uid" in session:
        if view == "finance":
            return render_template("single_order_finance.html",
                                   order=order_dict,
                                   product_data=product_data)
        elif view == "baker":
            return render_template("single_order_baker.html",
                                   order=order_dict,
                                   product_data=product_data)
        elif view == "delivery":
            return render_template("single_order_delivery.html",
                                   order=order_dict,
                                   product_data=product_data)
        elif view == "admin" and session["uid"] in admin_uids:
            return render_template("single_order_admin.html",
                                   order=order_dict,
                                   product_data=product_data)
    return render_template("single_order.html",
                           order=order_dict,
                           product_data=product_data)
Пример #25
0
def create_user():
    if not request.form:
        abort(400, "Request must include form data")
    try:
        new_user = {
            "email": request.form["email"],
            "first_name": request.form["first_name"],
            "last_name": request.form["last_name"],
            "grade": request.form["grade"],
            "school": request.form["school"],
            "phone": request.form["phone"]
        }
    except:
        abort(400, "Malformed form data")
    if not new_user["phone"]:
        new_user.pop("phone")
    elif "+" not in new_user["phone"]:
        new_user["phone"] = "+1" + new_user["phone"]

    try:
        firebase_user = firebase_auth.create_user(
            email=new_user["email"],
            email_verified=False,
            phone_number=new_user.get("phone", None),
            password="******",
            display_name=str("%s %s" %
                             (new_user["first_name"], new_user["last_name"])))

        user_ref = fireClient.collection("users").document(firebase_user.uid)
        user_ref.set({
            "name_array": firebase_user.display_name.lower().split(),
            "tier": "member"
        })
    except BaseException as e:
        abort(400, "User could not be created: %s" % str(e))
    return {"success": True}
Пример #26
0
def resolve_issue():
    if "uid" not in session or session["uid"] not in admin_uids:
        return redirect(url_for("auth.login"))

    if request.method == "GET":
        return render_template(
            "resolve_issue_form.html",
            orderID=request.args.get("orderID"),
            issue_description=request.args.get("issue_description"),
            issue_index=request.args.get("issue_index"))

    orderID = request.form["orderID"]
    issue_index = int(request.form["issue_index"])

    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")

    order = order_obj.to_dict()
    if issue_index < 0 or issue_index >= len(order["issues"]):
        abort(400, "Invalid issue index")
    order["issues"][issue_index]["resolved"] = True
    order["issues"][issue_index]["resolved_by"] = {
        "uid": session["uid"],
        "name": session["name"]
    }

    all_resolved = True
    for issue in order["issues"]:
        if not issue["resolved"]:
            all_resolved = False

    order["has_unresolved_issues"] = not all_resolved
    order_ref.set(order)
    return redirect(url_for("bakesale.admin_view"))
Пример #27
0
def bake_item():
    if "uid" not in session:
        return redirect(url_for("auth.login"))

    if request.method == "GET":
        return render_template("bake_form.html",
                               product_data=product_data,
                               orderID=request.args.get("orderID"),
                               itemCategory=request.args.get("itemCategory"),
                               itemID=request.args.get("itemID"),
                               qtyMax=request.args.get("qtyMax"))
    orderID = request.form["orderID"]
    itemCategory = request.form["itemCategory"]
    itemID = request.form["itemID"]
    quantity = int(request.form["quantity"])
    bakerID = session["uid"]

    if orderID is None or itemCategory is None or itemID is None or quantity is None \
        or itemCategory not in product_data or not any([itemID in products for category in product_data for products in product_data[category]["products"]]):
        abort(
            400,
            "Bake request must include order ID, category, item, and quantity")

    order_ref = fireClient.collection("orders").document(orderID)
    order_obj = order_ref.get()
    if not order_obj.exists:
        abort(404, "Order not found")
    order_dict = order_obj.to_dict()
    if itemID not in order_dict["fulfillment"][itemCategory]:
        abort(400, "Item not in order")

    if quantity <= 0 or quantity > (
            order_dict["quantities"][itemCategory][itemID] -
            order_dict["fulfillment"][itemCategory][itemID]["count"]):
        abort(400, "Quantity is invalid")

    order_dict["fulfillment"][itemCategory][itemID]["count"] += quantity
    if bakerID in order_dict["fulfillment"][itemCategory][itemID]["bakers"]:
        order_dict["fulfillment"][itemCategory][itemID]["bakers"][bakerID][
            "count"] += quantity
    else:
        user_name = session["name"]
        order_dict["fulfillment"][itemCategory][itemID]["bakers"][bakerID] = {
            "count": quantity,
            "name": user_name
        }

    # check to see if all quantities are met
    allMet = True
    for category in order_dict["quantities"]:
        for item in order_dict["quantities"][category]:
            if order_dict["fulfillment"][category][item]["count"] < order_dict[
                    "quantities"][category][item]:
                allMet = False
                break

    if allMet:
        order_dict["status"]["baked"] = allMet
        order_dict["baking"] = {
            "UTC_timestamp": str(datetime.utcnow()),
        }

    order_ref.set(order_dict)
    return redirect(url_for("bakesale.baker_view"))
Пример #28
0
def update_leaderboard(referral_link, amount):
    leaderboard_ref = fireClient.collection("statistics").document("sales")
    sales = leaderboard_ref.get().to_dict()
    sales["leaderboard"][referral_link] = sales["leaderboard"].get(
        referral_link, 0.0) + amount
    leaderboard_ref.set(sales)
Пример #29
0
    "finance",
    "operations"
]

officer_roles = [
    "communications",
    "publicity",
    "executive",
    "finance",
    "operations"
]

user_lookup_methods = {
    "phone": lambda phone: [firebase_auth.get_user_by_phone_number(phone if "+" in phone else "+1" + phone)],
    "email": lambda email: [firebase_auth.get_user_by_email(email)],
    "name": lambda name: [firebase_auth.get_user(user.id) for user in fireClient.collection("users").where("name_array", "array_contains_any", name.lower().split()).stream()]
}

def is_verified(uid):
    try:
        firebase_auth.get_user(uid)
    except:
        return False
    try:
        return fireClient.collection("users").document(uid).get().get("tier") == "director"
    except:
        return False

@info.route("/")
def index():
    return redirect(url_for("info.display_directory"))
Пример #30
0
import random
from flask import Blueprint, request, abort, jsonify, render_template, redirect, url_for, session
import firebase_admin.auth as firebase_auth
import firebase_admin.firestore as firestore
from scan_web import fireClient
from datetime import datetime

sms = Blueprint("sms", __name__, template_folder="sms_templates")

ambassador_uids = [
    ambassador.id for ambassador in fireClient.collection("users").where(
        "tier", "==", "ambassador").stream()
]
officer_uids = [
    officer.id for officer in fireClient.collection("users").where(
        "tier", "==", "officer").stream()
]
director_uids = [
    director.id for director in fireClient.collection("users").where(
        "tier", "==", "director").stream()
]


@sms.route("/")
def index():
    return redirect(url_for("sms.view_messages"))


@sms.route("/messages")
def view_messages():
    if "uid" not in session: