示例#1
0
文件: utils.py 项目: TeMbl4/rophako
def handle_exception(error):
    """Send an e-mail to the site admin when an exception occurs."""
    if current_app.config.get("DEBUG"):
        print(traceback.format_exc())
        raise

    import rophako.jsondb as JsonDB

    # Don't spam too many e-mails in a short time frame.
    cache = JsonDB.get_cache("exception_catcher")
    if cache:
        last_exception = int(cache)
        if int(time.time()) - last_exception < 120:
            # Only one e-mail per 2 minutes, minimum
            logger.error("RAPID EXCEPTIONS, DROPPING")
            return
    JsonDB.set_cache("exception_catcher", int(time.time()))

    username = "******"
    try:
        if hasattr(
                g, "info"
        ) and "session" in g.info and "username" in g.info["session"]:
            username = g.info["session"]["username"]
    except:
        pass

    # Get the timestamp.
    timestamp = time.ctime(time.time())

    # Exception's traceback.
    error = str(error.__class__.__name__) + ": " + str(error)
    stacktrace = error + "\n\n" \
        + "==== Start Traceback ====\n" \
        + traceback.format_exc() \
        + "==== End Traceback ====\n\n" \
        + "Request Information\n" \
        + "-------------------\n" \
        + "Address: " + remote_addr() + "\n" \
        + "User Agent: " + request.user_agent.string + "\n" \
        + "Referrer: " + request.referrer

    # Construct the subject and message
    subject = "Internal Server Error on {} - {} - {}".format(
        Config.site.site_name,
        username,
        timestamp,
    )
    message = "{} has experienced an exception on the route: {}".format(
        username,
        request.path,
    )
    message += "\n\n" + stacktrace

    # Send the e-mail.
    send_email(
        to=Config.site.notify_address,
        subject=subject,
        message=message,
    )
示例#2
0
文件: jsondb.py 项目: kirsle/rophako
def read_json(path):
    """Slurp, decode and return the data from a JSON document."""
    path = str(path)
    if not os.path.isfile(path):
        raise Exception("Can't read JSON file {}: file not found!".format(path))

    # Don't allow any fishy looking paths.
    if ".." in path:
        logger.error("ERROR: JsonDB tried to read a path with two dots: {}".format(path))
        raise Exception()

    # Open and lock the file.
    fh = codecs.open(path, 'r', 'utf-8')
    flock(fh, LOCK_SH)
    text = fh.read()
    flock(fh, LOCK_UN)
    fh.close()

    # Decode.
    try:
        data = json.loads(text)
    except:
        logger.error("Couldn't decode JSON data from {}".format(path))
        handle_exception(Exception("Couldn't decode JSON from {}\n{}".format(
            path,
            text,
        )))
        data = None

    return data
示例#3
0
def catch_exception(error):
    """Catch unexpected Python exceptions and e-mail them out."""
    logger.error("INTERNAL SERVER ERROR: {}".format(str(error)))

    # E-mail it out.
    rophako.utils.handle_exception(error)
    return rophako.utils.template("errors/500.html")
示例#4
0
文件: app.py 项目: kirsle/rophako
def catch_exception(error):
    """Catch unexpected Python exceptions and e-mail them out."""
    logger.error("INTERNAL SERVER ERROR: {}".format(str(error)))

    # E-mail it out.
    rophako.utils.handle_exception(error)
    return rophako.utils.template("errors/500.html")
示例#5
0
文件: jsondb.py 项目: TeMbl4/rophako
def read_json(path):
    """Slurp, decode and return the data from a JSON document."""
    path = str(path)
    if not os.path.isfile(path):
        raise Exception(
            "Can't read JSON file {}: file not found!".format(path))

    # Don't allow any fishy looking paths.
    if ".." in path:
        logger.error(
            "ERROR: JsonDB tried to read a path with two dots: {}".format(
                path))
        raise Exception()

    # Open and lock the file.
    fh = codecs.open(path, 'r', 'utf-8')
    flock(fh, LOCK_SH)
    text = fh.read()
    flock(fh, LOCK_UN)
    fh.close()

    # Decode.
    try:
        data = json.loads(text)
    except:
        logger.error("Couldn't decode JSON data from {}".format(path))
        handle_exception(
            Exception("Couldn't decode JSON from {}\n{}".format(
                path,
                text,
            )))
        data = None

    return data
示例#6
0
文件: utils.py 项目: TeMbl4/rophako
def handle_exception(error):
    """Send an e-mail to the site admin when an exception occurs."""
    if current_app.config.get("DEBUG"):
        print(traceback.format_exc())
        raise

    import rophako.jsondb as JsonDB

    # Don't spam too many e-mails in a short time frame.
    cache = JsonDB.get_cache("exception_catcher")
    if cache:
        last_exception = int(cache)
        if int(time.time()) - last_exception < 120:
            # Only one e-mail per 2 minutes, minimum
            logger.error("RAPID EXCEPTIONS, DROPPING")
            return
    JsonDB.set_cache("exception_catcher", int(time.time()))

    username = "******"
    try:
        if hasattr(g, "info") and "session" in g.info and "username" in g.info["session"]:
            username = g.info["session"]["username"]
    except:
        pass

    # Get the timestamp.
    timestamp = time.ctime(time.time())

    # Exception's traceback.
    error = str(error.__class__.__name__) + ": " + str(error)
    stacktrace = error + "\n\n" \
        + "==== Start Traceback ====\n" \
        + traceback.format_exc() \
        + "==== End Traceback ====\n\n" \
        + "Request Information\n" \
        + "-------------------\n" \
        + "Address: " + remote_addr() + "\n" \
        + "User Agent: " + request.user_agent.string + "\n" \
        + "Referrer: " + request.referrer

    # Construct the subject and message
    subject = "Internal Server Error on {} - {} - {}".format(
        Config.site.site_name,
        username,
        timestamp,
    )
    message = "{} has experienced an exception on the route: {}".format(
        username,
        request.path,
    )
    message += "\n\n" + stacktrace

    # Send the e-mail.
    send_email(
        to=Config.site.notify_address,
        subject=subject,
        message=message,
    )
示例#7
0
文件: photo.py 项目: TeMbl4/rophako
def edit_album(album, data):
    """Update an album's settings (description, format, etc.)"""
    album = sanitize_name(album)
    index = get_index()
    if not album in index["albums"]:
        logger.error("Failed to edit album: not found!")
        return

    index["settings"][album].update(data)
    write_index(index)
示例#8
0
文件: photo.py 项目: TeMbl4/rophako
def set_album_cover(album, key):
    """Change the album's cover photo."""
    album = sanitize_name(album)
    index = get_index()
    logger.info("Changing album cover for {} to {}".format(album, key))
    if album in index["albums"] and key in index["albums"][album]:
        index["covers"][album] = key
        write_index(index)
        return
    logger.error("Failed to change album index! Album or photo not found.")
示例#9
0
文件: photo.py 项目: TeMbl4/rophako
def edit_album(album, data):
    """Update an album's settings (description, format, etc.)"""
    album = sanitize_name(album)
    index = get_index()
    if not album in index["albums"]:
        logger.error("Failed to edit album: not found!")
        return

    index["settings"][album].update(data)
    write_index(index)
示例#10
0
文件: photo.py 项目: TeMbl4/rophako
def set_album_cover(album, key):
    """Change the album's cover photo."""
    album = sanitize_name(album)
    index = get_index()
    logger.info("Changing album cover for {} to {}".format(album, key))
    if album in index["albums"] and key in index["albums"][album]:
        index["covers"][album] = key
        write_index(index)
        return
    logger.error("Failed to change album index! Album or photo not found.")
示例#11
0
文件: photo.py 项目: TeMbl4/rophako
def get_photo(key):
    """Look up a photo by key. Returns None if not found."""
    index = get_index()
    photo = None
    if key in index["map"]:
        album = index["map"][key]
        if album in index["albums"] and key in index["albums"][album]:
            photo = index["albums"][album][key]
        else:
            # The map is wrong!
            logger.error(
                "Photo album map is wrong; key {} not found in album {}!".
                format(key, album))
            del index["map"][key]
            write_index(index)

    if not photo:
        return None

    # Inject additional information about the photo:
    # What position it's at in the album, how many photos total, and the photo
    # IDs of its siblings.
    siblings = index["photo-order"][album]
    i = 0
    for pid in siblings:
        if pid == key:
            # We found us! Find the siblings.
            sprev, snext = None, None
            if i == 0:
                # We're the first photo. So previous is the last!
                sprev = siblings[-1]
                if len(siblings) > i + 1:
                    snext = siblings[i + 1]
                else:
                    snext = key
            elif i == len(siblings) - 1:
                # We're the last. So next is first!
                sprev = siblings[i - 1]
                snext = siblings[0]
            else:
                # Right in the middle.
                sprev = siblings[i - 1]
                snext = siblings[i + 1]

            # Inject.
            photo["album"] = album
            photo["position"] = i + 1
            photo["siblings"] = len(siblings)
            photo["previous"] = sprev
            photo["next"] = snext
        i += 1

    return photo
示例#12
0
文件: photo.py 项目: TeMbl4/rophako
def get_photo(key):
    """Look up a photo by key. Returns None if not found."""
    index = get_index()
    photo = None
    if key in index["map"]:
        album = index["map"][key]
        if album in index["albums"] and key in index["albums"][album]:
            photo = index["albums"][album][key]
        else:
            # The map is wrong!
            logger.error("Photo album map is wrong; key {} not found in album {}!".format(key, album))
            del index["map"][key]
            write_index(index)

    if not photo:
        return None

    # Inject additional information about the photo:
    # What position it's at in the album, how many photos total, and the photo
    # IDs of its siblings.
    siblings = index["photo-order"][album]
    i = 0
    for pid in siblings:
        if pid == key:
            # We found us! Find the siblings.
            sprev, snext = None, None
            if i == 0:
                # We're the first photo. So previous is the last!
                sprev = siblings[-1]
                if len(siblings) > i+1:
                    snext = siblings[i+1]
                else:
                    snext = key
            elif i == len(siblings)-1:
                # We're the last. So next is first!
                sprev = siblings[i-1]
                snext = siblings[0]
            else:
                # Right in the middle.
                sprev = siblings[i-1]
                snext = siblings[i+1]

            # Inject.
            photo["album"] = album
            photo["position"] = i+1
            photo["siblings"] = len(siblings)
            photo["previous"] = sprev
            photo["next"] = snext
        i += 1

    return photo
示例#13
0
文件: jsondb.py 项目: kirsle/rophako
def set_cache(key, value, expires=None):
    """Set a key in the Redis cache."""
    key = Config.db.redis_prefix + key
    client = get_redis()
    if not client:
        return

    try:
        client.set(key, json.dumps(value))

        # Expiration date?
        if expires:
            client.expire(key, expires)
    except:
        logger.error("Redis exception: couldn't set_cache {}".format(key))
示例#14
0
def check_auth(username, password):
    """Check the authentication credentials for the username and password.

    Returns a boolean true or false. On error, an error is logged."""
    # Check if the username exists.
    if not exists(username=username):
        logger.error("User authentication failed: username {} not found!".format(username))
        return False

    # Get the user's file.
    db = get_user(username=username)

    # Check the password.
    test = bcrypt.hashpw(str(password).encode("utf-8"), str(db["password"]).encode("utf-8")).decode("utf-8")
    return test == db["password"]
示例#15
0
文件: jsondb.py 项目: TeMbl4/rophako
def set_cache(key, value, expires=None):
    """Set a key in the Redis cache."""
    key = Config.db.redis_prefix + key
    client = get_redis()
    if not client:
        return

    try:
        client.set(key, json.dumps(value))

        # Expiration date?
        if expires:
            client.expire(key, expires)
    except:
        logger.error("Redis exception: couldn't set_cache {}".format(key))
示例#16
0
文件: jsondb.py 项目: kirsle/rophako
def get_redis():
    """Connect to Redis or return the existing connection."""
    global redis_client
    global disable_redis

    if not redis_client and not disable_redis:
        try:
            redis_client = redis.StrictRedis(
                host = Config.db.redis_host,
                port = Config.db.redis_port,
                db   = Config.db.redis_db,
            )
            redis_client.ping()
        except Exception as e:
            logger.error("Couldn't connect to Redis; memory caching will be disabled! {}".format(e))
            redis_client  = None
            disable_redis = True
    return redis_client
示例#17
0
文件: blog.py 项目: TeMbl4/rophako
def resolve_id(fid):
    """Resolve a friendly ID to the blog ID number."""
    index = get_index()

    # If the ID is all numeric, it's the blog post ID directly.
    if re.match(r'^\d+$', fid):
        if fid in index:
            return int(fid)
        else:
            logger.error("Tried resolving blog post ID {} as an EntryID, but it wasn't there!".format(fid))
            return None

    # It's a friendly ID. Scan for it.
    for post_id, data in index.items():
        if data["fid"] == fid:
            return int(post_id)

    logger.error("Friendly post ID {} wasn't found!".format(fid))
    return None
示例#18
0
文件: jsondb.py 项目: TeMbl4/rophako
def get_redis():
    """Connect to Redis or return the existing connection."""
    global redis_client
    global disable_redis

    if not redis_client and not disable_redis:
        try:
            redis_client = redis.StrictRedis(
                host=Config.db.redis_host,
                port=Config.db.redis_port,
                db=Config.db.redis_db,
            )
            redis_client.ping()
        except Exception as e:
            logger.error(
                "Couldn't connect to Redis; memory caching will be disabled! {}"
                .format(e))
            redis_client = None
            disable_redis = True
    return redis_client
示例#19
0
文件: photo.py 项目: TeMbl4/rophako
def rename_album(old_name, new_name):
    """Rename an existing photo album.

    Returns True on success, False if the new name conflicts with another
    album's name."""
    old_name = sanitize_name(old_name)
    new_name = sanitize_name(new_name)
    index = get_index()

    # New name is unique?
    if new_name in index["albums"]:
        logger.error("Can't rename album: new name already exists!")
        return False

    def transfer_key(obj, old_key, new_key):
        # Reusable function to do a simple move on a dict key.
        obj[new_key] = obj[old_key]
        del obj[old_key]

    # Simple moves.
    transfer_key(index["albums"], old_name, new_name)
    transfer_key(index["covers"], old_name, new_name)
    transfer_key(index["photo-order"], old_name, new_name)
    transfer_key(index["settings"], old_name, new_name)

    # Update the photo -> album maps.
    for photo in index["map"]:
        if index["map"][photo] == old_name:
            index["map"][photo] = new_name

    # Fix the album ordering.
    new_order = list()
    for name in index["album-order"]:
        if name == old_name:
            name = new_name
        new_order.append(name)
    index["album-order"] = new_order

    # And save.
    write_index(index)
    return True
示例#20
0
文件: photo.py 项目: TeMbl4/rophako
def rename_album(old_name, new_name):
    """Rename an existing photo album.

    Returns True on success, False if the new name conflicts with another
    album's name."""
    old_name = sanitize_name(old_name)
    new_name = sanitize_name(new_name)
    index = get_index()

    # New name is unique?
    if new_name in index["albums"]:
        logger.error("Can't rename album: new name already exists!")
        return False

    def transfer_key(obj, old_key, new_key):
        # Reusable function to do a simple move on a dict key.
        obj[new_key] = obj[old_key]
        del obj[old_key]

    # Simple moves.
    transfer_key(index["albums"], old_name, new_name)
    transfer_key(index["covers"], old_name, new_name)
    transfer_key(index["photo-order"], old_name, new_name)
    transfer_key(index["settings"], old_name, new_name)

    # Update the photo -> album maps.
    for photo in index["map"]:
        if index["map"][photo] == old_name:
            index["map"][photo] = new_name

    # Fix the album ordering.
    new_order = list()
    for name in index["album-order"]:
        if name == old_name:
            name = new_name
        new_order.append(name)
    index["album-order"] = new_order

    # And save.
    write_index(index)
    return True
示例#21
0
文件: blog.py 项目: TeMbl4/rophako
def resolve_id(fid):
    """Resolve a friendly ID to the blog ID number."""
    index = get_index()

    # If the ID is all numeric, it's the blog post ID directly.
    if re.match(r'^\d+$', fid):
        if fid in index:
            return int(fid)
        else:
            logger.error(
                "Tried resolving blog post ID {} as an EntryID, but it wasn't there!"
                .format(fid))
            return None

    # It's a friendly ID. Scan for it.
    for post_id, data in index.items():
        if data["fid"] == fid:
            return int(post_id)

    logger.error("Friendly post ID {} wasn't found!".format(fid))
    return None
示例#22
0
文件: jsondb.py 项目: kirsle/rophako
def write_json(path, data):
    """Write a JSON document."""
    path = str(path)

    # Don't allow any fishy looking paths.
    if ".." in path:
        logger.error("ERROR: JsonDB tried to write a path with two dots: {}".format(path))
        raise Exception()

    logger.debug("JsonDB: WRITE > {}".format(path))

    # Open and lock the file.
    fh = codecs.open(path, 'w', 'utf-8')
    flock(fh, LOCK_EX)

    # Write it.
    fh.write(json.dumps(data, indent=4, separators=(',', ': ')))

    # Unlock and close.
    flock(fh, LOCK_UN)
    fh.close()
示例#23
0
def load_theme():
    """Pre-load and cache the emoticon theme. This happens on startup."""
    theme = Config.emoticons.theme
    global _cache

    # Cached?
    if _cache:
        return _cache

    # Only if the theme file exists.
    settings = os.path.join(Config.emoticons.root_private, theme,
                            "emoticons.json")
    if not os.path.isfile(settings):
        logger.error("Failed to load smiley theme {}: not found!")

        # Try the default (tango).
        theme = "tango"
        settings = os.path.join(Config.emoticons.root_private, theme,
                                "emoticons.json")
        if os.path.isfile(settings):
            logger.info("Falling back to default theme: tango")
        else:
            # Give up.
            return {}

    # Read it.
    fh = codecs.open(settings, "r", "utf-8")
    text = fh.read()
    fh.close()

    try:
        data = json.loads(text)
    except Exception as e:
        logger.error("Couldn't load JSON from emoticon file: {}".format(e))
        data = {}

    # Cache and return it.
    _cache = data
    return data
示例#24
0
文件: jsondb.py 项目: TeMbl4/rophako
def write_json(path, data):
    """Write a JSON document."""
    path = str(path)

    # Don't allow any fishy looking paths.
    if ".." in path:
        logger.error(
            "ERROR: JsonDB tried to write a path with two dots: {}".format(
                path))
        raise Exception()

    logger.debug("JsonDB: WRITE > {}".format(path))

    # Open and lock the file.
    fh = codecs.open(path, 'w', 'utf-8')
    flock(fh, LOCK_EX)

    # Write it.
    fh.write(json.dumps(data, indent=4, separators=(',', ': ')))

    # Unlock and close.
    flock(fh, LOCK_UN)
    fh.close()
示例#25
0
def load_theme():
    """Pre-load and cache the emoticon theme. This happens on startup."""
    theme = Config.emoticons.theme
    global _cache

    # Cached?
    if _cache:
        return _cache

    # Only if the theme file exists.
    settings = os.path.join(Config.emoticons.root_private, theme, "emoticons.json")
    if not os.path.isfile(settings):
        logger.error("Failed to load smiley theme {}: not found!")

        # Try the default (tango).
        theme = "tango"
        settings = os.path.join(Config.emoticons.root_private, theme, "emoticons.json")
        if os.path.isfile(settings):
            logger.info("Falling back to default theme: tango")
        else:
            # Give up.
            return {}

    # Read it.
    fh = codecs.open(settings, "r", "utf-8")
    text = fh.read()
    fh.close()

    try:
        data = json.loads(text)
    except Exception as e:
        logger.error("Couldn't load JSON from emoticon file: {}".format(e))
        data = {}

    # Cache and return it.
    _cache = data
    return data
示例#26
0
文件: blog.py 项目: kirsle/rophako
def resolve_id(fid, drafts=False):
    """Resolve a friendly ID to the blog ID number.

    Args:
        drafts (bool): Whether to allow draft IDs to be resolved (for
            logged-in users only).
    """
    index = get_index(drafts=drafts)

    # If the ID is all numeric, it's the blog post ID directly.
    if re.match(r'^\d+$', fid):
        if fid in index:
            return int(fid)
        else:
            logger.error("Tried resolving blog post ID {} as an EntryID, but it wasn't there!".format(fid))
            return None

    # It's a friendly ID. Scan for it.
    for post_id, data in index.items():
        if data["fid"] == fid:
            return int(post_id)

    logger.error("Friendly post ID {} wasn't found!".format(fid))
    return None