Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def get_entry_id(entry, fullpath, assign_id) -> typing.Optional[int]:
""" Get or generate an entry ID for an entry """
other_entry: typing.Optional[model.Entry] = None
try:
entry_id = int(entry['Entry-ID']) if 'Entry-ID' in entry else None
except (ValueError, KeyError, TypeError) as err:
LOGGER.debug("Invalid entry-id: %s", err)
# See if we've inadvertently duplicated an entry ID
if entry_id is not None:
try:
other_entry = model.Entry.get(id=entry_id)
if (other_entry
and os.path.isfile(other_entry.file_path)
and not os.path.samefile(other_entry.file_path, fullpath)
and other_entry.status != model.PublishStatus.DRAFT.value):
entry_id = None
else:
other_entry = None
except FileNotFoundError:
# the other file doesn't exist, so just let it go
pass
# Do we need to assign a new ID?
if not entry_id and not assign_id:
# We're not assigning IDs yet
return None
def get_entry(entry):
""" Helper function to get an entry by ID or by object """
if isinstance(entry, model.Entry):
return entry
if hasattr(entry, '_record'):
return getattr(entry, '_record')
if isinstance(entry, (int, str)):
return model.Entry.get(id=int(entry))
raise ValueError(f"entry is of unknown type {type(entry)}")
def render_entry(entry_id, slug_text='', category=''):
""" Render an entry page.
Arguments:
entry_id -- The numeric ID of the entry to render
slug_text -- The expected URL slug text
category -- The expected category
"""
# pylint: disable=too-many-return-statements,too-many-branches,unused-argument
# check if it's a valid entry
record = model.Entry.get(id=entry_id)
# see if the file still exists
if record and not os.path.isfile(record.file_path):
entry_expire_record(record)
record = None
if not record:
# It's not a valid entry, so see if it's a redirection
result = handle_path_alias()
if result:
return result
LOGGER.info("Attempted to retrieve nonexistent entry %d", entry_id)
raise http_error.NotFound("No such entry")
return render_entry_record(record, category, None)
last_modified_str, tzinfo=config.timezone)
except arrow.parser.ParserError:
last_modified = arrow.get()
del entry['Last-Modified']
entry['Last-Modified'] = last_modified.format()
fixup_needed = True
values['display_date'] = entry_date.isoformat()
values['utc_date'] = entry_date.to('utc').datetime
values['local_date'] = entry_date.naive
LOGGER.debug("getting entry %s with id %d", fullpath, entry_id)
remove_by_path(fullpath, entry_id)
record = model.Entry.get(id=entry_id)
if record:
LOGGER.debug("Reusing existing entry %d", record.id)
record.set(**values)
else:
record = model.Entry(id=entry_id, **values)
# Update the entry ID
if str(record.id) != entry['Entry-ID']:
del entry['Entry-ID']
entry['Entry-ID'] = str(record.id)
fixup_needed = True
if 'UUID' not in entry:
entry['UUID'] = str(uuid.uuid5(
uuid.NAMESPACE_URL, 'file://' + fullpath))
fixup_needed = True
def find_entry(rel_path: str, search_path: typing.Tuple[str, ...]) -> typing.Optional[model.Entry]:
""" Find an entry by relative path. Arguments:
rel_path -- the entry's filename (or entry ID)
search_path -- a list of directories to check in
Returns: the resolved Entry object
"""
try:
entry_id = int(rel_path)
record = model.Entry.get(id=entry_id)
if record:
return record
except ValueError:
pass
if rel_path.startswith('/'):
search_path = (config.content_folder,)
rel_path = '.' + rel_path
for where in search_path:
abspath = os.path.normpath(os.path.join(where, rel_path))
record = model.Entry.get(file_path=abspath)
if record:
return record
return None
if not entry_id:
# See if we already have an entry with this file path
by_filepath = model.Entry.select(lambda e: e.file_path == fullpath).first()
if by_filepath:
entry_id = by_filepath.id
if not entry_id:
# We still don't have an ID; generate one pseudo-randomly, based on the
# entry file path. This approach averages around 0.25 collisions per ID
# generated while keeping the entry ID reasonably short. In general,
# count*N averages 1/(N-1) collisions per ID.
limit = max(10, orm.get(orm.count(e)
for e in model.Entry) * 5) # type:ignore
attempt = 0
while not entry_id or model.Entry.get(id=entry_id):
# Stably generate a quasi-random entry ID from the file path
md5 = hashlib.md5()
md5.update(f"{fullpath} {attempt}".encode('utf-8'))
entry_id = int.from_bytes(md5.digest(), byteorder='big') % limit
attempt = attempt + 1
if other_entry:
LOGGER.warning("Entry '%s' had ID %d, which belongs to '%s'. Reassigned to %d",
fullpath, other_entry.id, other_entry.file_path, entry_id)
return entry_id