Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 42 additions & 29 deletions drive/api/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,44 +150,47 @@ def upload_file(
return drive_file


IMAGE_THUMBNAILS = ["Image", "Video", "PDF", "Presentation"]


def _get_default_thumbnail(file_type: str) -> BytesIO:
file_path = frappe.get_app_path("drive", "public", "images", "icons", f"{file_type.lower()}.svg")
try:
with open(file_path, "rb") as f:
return BytesIO(f.read())
except FileNotFoundError as e:
return None


@frappe.whitelist(allow_guest=True)
def get_thumbnail(entity_name):
drive_file = frappe.get_value(
def get_thumbnail(entity_name, image=True):
drive_file = frappe.get_cached_doc(
"Drive File",
entity_name,
[
"is_group",
"path",
"title",
"mime_type",
"file_size",
"owner",
"team",
"document",
"name",
],
as_dict=1,
)
if not drive_file or drive_file.is_group or drive_file.is_link:
).as_dict()
if not drive_file or not user_has_permission(drive_file, "read"):
return
if user_has_permission(drive_file, "read") is False:
return

thumbnail_data = None
default = False

if frappe.cache().exists(entity_name):
try:
thumbnail_data = frappe.cache().get_value(entity_name)
cache = frappe.cache().get_value(entity_name)
thumbnail_data = cache["thumbnail"]
default = cache["default"]
except:
frappe.cache().delete_value(entity_name)

if not thumbnail_data:
file_type = get_file_type(dict(drive_file))
manager = FileManager()
try:
if drive_file.mime_type.startswith("text"):
if not image and drive_file.mime_type.startswith("text"):
with manager.get_file(drive_file) as f:
thumbnail_data = f.read()[:1000].decode("utf-8").replace("\n", "<br/>")
elif drive_file.mime_type == "frappe_doc":
elif not image and drive_file.mime_type == "frappe_doc":
html = frappe.get_value("Drive Document", drive_file.document, "raw_content")
thumbnail_data = html[:1000] if html else ""
thumbnail_data = html[:1000]
elif drive_file.mime_type == "frappe/slides":
# Use this until the thumbnail method is whitelisted
thumbnails = frappe.call(
Expand All @@ -197,22 +200,32 @@ def get_thumbnail(entity_name):
frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = thumbnails[0]
return
else:
elif file_type in IMAGE_THUMBNAILS:
thumbnail = manager.get_thumbnail(drive_file.team, entity_name)
thumbnail_data = BytesIO(thumbnail.read())
thumbnail.close()
except:
return ""

if thumbnail_data:
frappe.cache().set_value(entity_name, thumbnail_data, expires_in_sec=60 * 60)
pass
finally:
if not thumbnail_data:
thumbnail_data = _get_default_thumbnail(file_type)
default = True
if thumbnail_data:
frappe.cache().set_value(
entity_name, {"thumbnail": thumbnail_data, "default": default}, expires_in_sec=60 * 60
)

if isinstance(thumbnail_data, BytesIO):
response = Response(
wrap_file(frappe.request.environ, thumbnail_data),
direct_passthrough=True,
)
response.headers.set("Content-Type", "image/jpeg")
if default:
response.headers.set("Content-Type", "image/svg+xml")
response.headers.set("Cache-Control", "public, max-age=3600")
else:
response.headers.set("Content-Type", "image/jpeg")
response.headers.set("X-Thumbnail-Default", "1" if default else "0")
response.headers.set("Content-Disposition", "inline", filename=entity_name)
return response
else:
Expand Down
30 changes: 24 additions & 6 deletions drive/api/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
def files(
team,
entity_name=None,
parent=None,
order_by="modified 1",
is_active=1,
limit=20,
cursor=None,
limit=1000,
start=0,
favourites_only=0,
recents_only=0,
shared=None,
Expand All @@ -44,9 +45,13 @@ def files(
field, ascending = order_by.replace("modified", "_modified").split(" ")
is_active = int(is_active)
only_parent = int(only_parent)
limit = int(limit)
start = int(start)
folders = int(folders)
favourites_only = int(favourites_only)
ascending = int(ascending)
if not entity_name:
entity_name = parent

all_teams = False
if team == "all":
Expand Down Expand Up @@ -99,10 +104,6 @@ def files(
fn.Coalesce(DrivePermission.read, 1).as_("read") == 1
)

# Cursor pagination
if cursor:
query = query.where((Binary(DriveFile[field]) > cursor if ascending else field < cursor)).limit(limit)

# Cleaner way?
if only_parent and (not recents_only and not favourites_only and not shared):
query = query.where(DriveFile.parent_entity == entity_name)
Expand Down Expand Up @@ -156,8 +157,15 @@ def files(

if folders:
query = query.where(DriveFile.is_group == 1)
query = query.limit(limit + 1).offset(start)
res = query.run(as_dict=True)

# Check if there's a next page
has_next_page = len(res) > limit

# Remove the extra record if it exists
if has_next_page:
res = res[:limit]
child_count_query = (
frappe.qb.from_(DriveFile)
.where((DriveFile.team == team) & (DriveFile.is_active == 1))
Expand Down Expand Up @@ -208,6 +216,11 @@ def files(
else:
r["share_count"] = default
r |= get_user_access(r["name"])

# Return in the format useList expects
frappe.response["data"] = res
frappe.response["has_next_page"] = has_next_page

return res


Expand All @@ -217,3 +230,8 @@ def get_transfers():
"Drive Transfer", filters={"owner": frappe.session.user}, fields=["title", "file_size", "creation", "name"]
)
return transfers


@frappe.whitelist(allow_guest=True)
def search(query, parent=None, limit=None):
return files(parent=parent, limit=limit, search=query)
28 changes: 21 additions & 7 deletions drive/api/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ def get_link(entity):


@frappe.whitelist()
def get_notifications(only_unread):
def get_notifications(only_unread, limit=20, offset=0):
"""
Get notifications for current user

:param only_unread: only get notifications where read is False
Get notifications for current user (paged)
:param limit: page size
:param offset: offset for pagination
"""

limit = int(limit)
offset = int(offset)

User = frappe.qb.DocType("User")
Notification = frappe.qb.DocType("Drive Notification")

fields = [
Notification.name,
Notification.to_user,
Expand All @@ -30,19 +35,28 @@ def get_notifications(only_unread):
User.user_image,
User.full_name,
]

query = (
frappe.qb.from_(Notification)
.left_join(User)
.on(Notification.from_user == User.name)
.select(*fields)
.where(Notification.to_user == frappe.session.user)
.orderby(Notification.creation, order=Order.desc)
.limit(limit + 1)
.offset(offset)
)

if only_unread:
query = query.where(Notification.read == 0)
query = query.where(Notification.to_user == frappe.session.user)
result = query.run(as_dict=True)
return result

rows = query.run(as_dict=True)

has_next_page = len(rows) > limit
res = rows[:limit]

frappe.response["data"] = res
frappe.response["has_next_page"] = has_next_page


@frappe.whitelist()
Expand Down
2 changes: 1 addition & 1 deletion frappe-ui
Submodule frappe-ui updated 153 files
8 changes: 4 additions & 4 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
property="og:description"
content="{{ description }}"
/>
{% if og_image %}
<!-- {% if og_image %}
<meta
property="og:image"
content="{{ og_image }}"
/>
{% endif %}
{% endif %} -->

<!-- Twitter Meta Tags -->
<meta
Expand All @@ -38,12 +38,12 @@
name="twitter:description"
content="{{ description }}"
/>
{% if og_image %}
<!-- {% if og_image %}
<meta
name="twitter:image"
content="{{ og_image }}"
/>
{% endif %}
{% endif %} -->

<link
rel="apple-touch-icon"
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"access-key-label-polyfill": "^1.0.0",
"date-fns": "^4.1.0",
"dropzone": "^6.0.0-beta.2",
"frappe-ui": "^0.1.212",
"frappe-ui": "github:frappe/frappe-ui#48812eb8496fc954178d55ff2dc11a1dec5af518",
"hast-util-to-html": "^9.0.5",
"html2pdf.js": "^0.10.3",
"idb-keyval": "^6.2.1",
Expand Down
10 changes: 5 additions & 5 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 3 additions & 21 deletions frontend/src/components/CustomListRowItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,11 @@
#prefix
>
<img
v-if="!imgLoaded"
loading="lazy"
class="h-[16px] w-[16px] rounded-sm"
:src="backupLink"
:draggable="false"
/>
<img
v-show="imgLoaded"
class="h-[16px] w-[16px] object-cover rounded-sm"
:src="src"
:src="
'/api/method/drive.api.files.get_thumbnail?entity_name=' + row.name
"
:draggable="false"
@load="imgLoaded = true"
/>
</template>
<template #default="{ label }">
Expand Down Expand Up @@ -71,15 +64,4 @@ const props = defineProps({
item: String,
contextMenu: Function,
})

let src, imgLoaded, thumbnailLink, backupLink, _

if (props.column.prefix && props.column.key === "title") {
;[thumbnailLink, backupLink, _] = props.column.prefix({
row: props.row,
})

src = ref(thumbnailLink || backupLink)
imgLoaded = ref(false)
}
</script>
Loading