def user(site_id=""):
    if not site_id:
        flash("No site id given.", "error")
        return redirect(url_for("security.home"))
    else:
        site_id = site_id.strip()
        if request.form.get("action") == "refresh":
            auth_crest(site_id, True)
            api_key_db = g.mongo.db.api_keys.find_one({"_id": site_id})
            if api_key_db:
                caches.api_keys([(x["key_id"], x["vcode"]) for x in api_key_db["keys"]], False, site_id, False)

    error_list = []
    # Users
    if request.form.get("action") == "delete":
        if request.form.get("confirm") == site_id:
            g.mongo.db.users.delete_one({"_id": site_id})
            flash("Account Deleted", "success")
            return redirect(url_for("security.home"))
        else:
            flash("Site ID didn't match.", "error")
    user_info = g.mongo.db.users.find_one({"_id": site_id})
    # Vacation
    if request.form.get("action") == "vacation":
        vacation_db = g.mongo.db.personals.find_one_and_update(
            {"_id": site_id}, {"$unset": {"vacation": True, "vacation_date": True}},
            return_document=ReturnDocument.AFTER)
        flash("Vacation reset.", "success")
    else:
        vacation_db = g.mongo.db.personals.find_one({"_id": site_id})
    if not user_info:
        flash("No user found.", "error")
        return redirect(url_for("security.home"))
    # APIs
    if request.form.get("action") == "add":
        error_list = caches.api_keys([(request.form.get("key_id"), request.form.get("vcode"))],
                                     dashboard_id=site_id)
    if request.form.get("action") == "remove":
        user_apis = g.mongo.db.api_keys.find_one_and_update({"_id": site_id},
                                                            {
                                                                "$pull": {
                                                                    "keys": {"key_id": int(request.form.get("key_id"))}
                                                                }
                                                            },
                                                            return_document=ReturnDocument.AFTER)
        flash("Removed key id {0}".format(request.form.get("key_id")), "success")
    elif request.form.get("action") == "remove_old":
        user_apis = g.mongo.db.api_keys.find_one_and_update({"_id": site_id},
                                                            {
                                                                "$pull": {
                                                                    "old_keys": {
                                                                        "key_id": int(request.form.get("key_id"))}
                                                                }
                                                            }, return_document=ReturnDocument.AFTER)
        flash("Removed old key id {0}".format(request.form.get("key_id")), "success")
    else:
        user_apis = g.mongo.db.api_keys.find_one({"_id": site_id})

    api_table = []
    old_api_table = []
    id_list = []
    affiliation_table = []
    if user_apis:
        for api_key in user_apis["keys"]:
            api_table.append([api_key["character_name"], api_key["character_id"], api_key["key_id"], api_key["vcode"],
                              api_key["cached_str"], api_key.get("valid", True)])
            id_list.append(api_key["character_id"])
            affiliation_table.append([api_key["character_name"], api_key["corporation_name"], api_key["alliance_name"]])
        if user_apis.get("old_keys"):
            for key in user_apis["old_keys"]:
                old_api_table.append([key["key_id"], key["vcode"],
                                      time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(key["delete_time"]))])

    vacation_text = vacation_db.get("vacation") if vacation_db else None
    vacation_date = vacation_db.get("vacation_date") if vacation_db else None

    time_format = "%Y-%m-%d %H:%M:%S"

    location_table = []
    for security_character in g.mongo.db.security_characters.find({"_id": {"$in": id_list}}):
        location_table.append([security_character["name"], security_character["last_location_str"],
                               security_character["last_ship_str"],
                               time.strftime(time_format, time.gmtime(security_character["log_on_time"])),
                               time.strftime(time_format, time.gmtime(security_character["log_off_time"]))])

    user_table = [site_id, user_info["character_name"],
                  time.strftime(time_format, time.gmtime(user_info.get("last_sign_on", 0)))]

    with open("configs/base.json", "r") as base_config_file:
        base_config = json.load(base_config_file)
    image = base_config["image_server"] + "/Character/" + str(user_info["character_id"]) + "_256.jpg"

    return render_template("security_user.html", api_table=api_table, user_table=user_table, image=image,
                           site_log_in=time.strftime(time_format, time.gmtime(user_info.get("last_sign_on", 0))),
                           site_id=site_id, character_name=user_info["character_name"], location_table=location_table,
                           vacation_text=vacation_text, vacation_date=vacation_date,
                           affiliation_table=affiliation_table, error_list=error_list,
                           sso_alliance=user_info["alliance_name"], sso_corporation=user_info["corporation_name"],
                           old_api_table=old_api_table)
def api_validation():
    # Check if something is running
    updates = g.mongo.db.preferences.find_one({"_id": "updates"})
    if not updates or not updates.get("api_validation") or not updates.get("api_validation", "").startswith("running"):
        g.mongo.db.preferences.update_one({"_id": "updates"}, {
            "$set": {"api_validation": "running. Started at: {0}".format(
                    datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))}}, upsert=True)
        # EVE:
        # General rate: 30 request / sec
        # Error rate: 300 requests / 3 minutes (avg. 100/min, 5/3sec = 1.67/sec)
        # Discord: 120 requests / minute (avg. 2/sec)
        counter = 0
        auth_crest_list = []
        api_keys_list = []

        for api_group in g.mongo.db.api_keys.find():
            try:
                user_api_list = set()
                if not api_group.get("keys") and api_group["_id"] == "unassociated":
                    pass
                else:
                    # Refresh Crest
                    try:
                        auth_crest_list.append([api_group["_id"], True, True])
                    except KeyError:
                        print("Failed at {0}".format(api_group["_id"]))

                    for api_key_item in api_group["keys"]:
                        user_api_list.add((api_key_item["key_id"], api_key_item["vcode"]))
                    api_keys_list.append([list(user_api_list), False, api_group["_id"], False])
            except requests.ConnectionError as e:
                print("Skipping {0} due to connection error".format(api_group["_id"]))
                print(e)
                continue

        # Run without database cursor connection
        if not auth_crest_list or not api_keys_list:
            print("Empty verification lists")
        for auth_crest_parameters, api_keys_parameters in zip(auth_crest_list, api_keys_list):
            counter += 1
            print("At user {0}".format(counter))
            try:
                auth_crest(*auth_crest_parameters)
                api_keys(*api_keys_parameters)
            except KeyError as unknown_error:
                print(unknown_error)
            time.sleep(60)

        print("Finished at user {0}.".format(counter))

        print("Forcing forum log outs")
        for user in g.mongo.db.users.find():
            if user.get("email"):
                try:
                    forum_edit(user, "log_out")
                    time.sleep(1)
                except requests.ConnectionError as e:
                    print("Failed forum logout for {0}".format(user["_id"]))
                    print(e)
                    continue
        print("Finished forcing forum log outs for all users")

        g.mongo.db.preferences.update_one({"_id": "updates"}, {
            "$set": {"api_validation": datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")}})
def user(site_id=""):
    if not site_id:
        flash("No site id given.", "error")
        return redirect(url_for("security.home"))
    else:
        site_id = site_id.strip()
        if request.form.get("action") == "refresh":
            auth_crest(site_id, True)
            api_key_db = g.mongo.db.api_keys.find_one({"_id": site_id})
            if api_key_db:
                caches.api_keys([(x["key_id"], x["vcode"])
                                 for x in api_key_db["keys"]], False, site_id,
                                False)

    error_list = []
    # Users
    if request.form.get("action") == "delete":
        if request.form.get("confirm") == site_id:
            g.mongo.db.users.delete_one({"_id": site_id})
            flash("Account Deleted", "success")
            return redirect(url_for("security.home"))
        else:
            flash("Site ID didn't match.", "error")
    user_info = g.mongo.db.users.find_one({"_id": site_id})
    # Vacation
    if request.form.get("action") == "vacation":
        vacation_db = g.mongo.db.personals.find_one_and_update(
            {"_id": site_id},
            {"$unset": {
                "vacation": True,
                "vacation_date": True
            }},
            return_document=ReturnDocument.AFTER)
        flash("Vacation reset.", "success")
    else:
        vacation_db = g.mongo.db.personals.find_one({"_id": site_id})
    if not user_info:
        flash("No user found.", "error")
        return redirect(url_for("security.home"))
    # APIs
    if request.form.get("action") == "add":
        error_list = caches.api_keys(
            [(request.form.get("key_id"), request.form.get("vcode"))],
            dashboard_id=site_id)
    if request.form.get("action") == "remove":
        user_apis = g.mongo.db.api_keys.find_one_and_update(
            {"_id": site_id},
            {"$pull": {
                "keys": {
                    "key_id": int(request.form.get("key_id"))
                }
            }},
            return_document=ReturnDocument.AFTER)
        flash("Removed key id {0}".format(request.form.get("key_id")),
              "success")
    elif request.form.get("action") == "remove_old":
        user_apis = g.mongo.db.api_keys.find_one_and_update(
            {"_id": site_id}, {
                "$pull": {
                    "old_keys": {
                        "key_id": int(request.form.get("key_id"))
                    }
                }
            },
            return_document=ReturnDocument.AFTER)
        flash("Removed old key id {0}".format(request.form.get("key_id")),
              "success")
    else:
        user_apis = g.mongo.db.api_keys.find_one({"_id": site_id})

    api_table = []
    old_api_table = []
    id_list = []
    affiliation_table = []
    if user_apis:
        for api_key in user_apis["keys"]:
            api_table.append([
                api_key["character_name"], api_key["character_id"],
                api_key["key_id"], api_key["vcode"], api_key["cached_str"],
                api_key.get("valid", True)
            ])
            id_list.append(api_key["character_id"])
            affiliation_table.append([
                api_key["character_name"], api_key["corporation_name"],
                api_key["alliance_name"]
            ])
        if user_apis.get("old_keys"):
            for key in user_apis["old_keys"]:
                old_api_table.append([
                    key["key_id"], key["vcode"],
                    time.strftime("%Y-%m-%d %H:%M:%S",
                                  time.gmtime(key["delete_time"]))
                ])

    vacation_text = vacation_db.get("vacation") if vacation_db else None
    vacation_date = vacation_db.get("vacation_date") if vacation_db else None

    time_format = "%Y-%m-%d %H:%M:%S"

    location_table = []
    for security_character in g.mongo.db.security_characters.find(
        {"_id": {
            "$in": id_list
        }}):
        location_table.append([
            security_character["name"],
            security_character["last_location_str"],
            security_character["last_ship_str"],
            time.strftime(time_format,
                          time.gmtime(security_character["log_on_time"])),
            time.strftime(time_format,
                          time.gmtime(security_character["log_off_time"]))
        ])

    user_table = [
        site_id, user_info["character_name"],
        time.strftime(time_format,
                      time.gmtime(user_info.get("last_sign_on", 0)))
    ]

    with open("configs/base.json", "r") as base_config_file:
        base_config = json.load(base_config_file)
    image = base_config["image_server"] + "/Character/" + str(
        user_info["character_id"]) + "_256.jpg"

    return render_template("security_user.html",
                           api_table=api_table,
                           user_table=user_table,
                           image=image,
                           site_log_in=time.strftime(
                               time_format,
                               time.gmtime(user_info.get("last_sign_on", 0))),
                           site_id=site_id,
                           character_name=user_info["character_name"],
                           location_table=location_table,
                           vacation_text=vacation_text,
                           vacation_date=vacation_date,
                           affiliation_table=affiliation_table,
                           error_list=error_list,
                           sso_alliance=user_info["alliance_name"],
                           sso_corporation=user_info["corporation_name"],
                           old_api_table=old_api_table)
def auth_crest_wait(code, refresh=False, discord_roles=True):
    print(">> Running Crest Auth")
    auth_crest(code, refresh, discord_roles)