Skip to content

Commit

Permalink
fix bug when deleting files
Browse files Browse the repository at this point in the history
  • Loading branch information
zzjjzzgggg committed Oct 3, 2023
1 parent 187b1b9 commit 037246b
Showing 1 changed file with 61 additions and 64 deletions.
125 changes: 61 additions & 64 deletions olsync/olclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,36 @@

import json
import time
import uuid

import requests as reqs
from bs4 import BeautifulSoup
from socketIO_client import SocketIO

# Where to get the CSRF Token and where to send the login request to
LOGIN_URL = "https://www.overleaf.com/login"
PROJECT_URL = "https://www.overleaf.com/project" # The dashboard URL
PROJECT_URL = "https://www.overleaf.com/project" # The dashboard URL
# The URL to download all the files in zip format
DOWNLOAD_URL = "https://www.overleaf.com/project/{}/download/zip"
# UPLOAD_URL = "https://www.overleaf.com/project/{}/upload" # The URL to upload files
UPLOAD_URL = "https://www.overleaf.com/project/{}/upload"
FOLDER_URL = "https://www.overleaf.com/project/{}/folder" # The URL to create folders
DELETE_URL = "https://www.overleaf.com/project/{}/doc/{}" # The URL to delete files
COMPILE_URL = "https://www.overleaf.com/project/{}/compile?enable_pdf_caching=true" # The URL to compile the project
BASE_URL = "https://www.overleaf.com" # The Overleaf Base URL
PATH_SEP = "/" # Use hardcoded path separator for both windows and posix system
FOLDER_URL = "https://www.overleaf.com/project/{}/folder" # The URL to create folders
DELETE_URL = "https://www.overleaf.com/project/{}/{}/{}" # The URL to delete files
COMPILE_URL = "https://www.overleaf.com/project/{}/compile?enable_pdf_caching=true" # The URL to compile the project
BASE_URL = "https://www.overleaf.com" # The Overleaf Base URL
PATH_SEP = "/" # Use hardcoded path separator for both windows and posix system


def search_dic(name, dic):
""" Search `name' in dic['docs'] and dic['fileRefs']
Return file_id and file_type
"""
for v in dic['docs']:
if v['name'] == name:
return v['_id'], 'doc'
for v in dic['fileRefs']:
if v['name'] == name:
return v['_id'], 'file'
return None, None


class OverleafClient(object):
Expand All @@ -47,8 +59,8 @@ def filter_projects(json_content, more_attrs=None):
yield p

def __init__(self, cookie=None, csrf=None):
self._cookie = cookie # Store the cookie for authenticated requests
self._csrf = csrf # Store the CSRF token since it is needed for some requests
self._cookie = cookie # Store the cookie for authenticated requests
self._csrf = csrf # Store the CSRF token since it is needed for some requests

def login(self, username, password):
"""
Expand All @@ -63,14 +75,8 @@ def login(self, username, password):
'html.parser').find('input', {
'name': '_csrf'
}).get('value')
login_json = {
"_csrf": self._csrf,
"email": username,
"password": password
}
post_login = reqs.post(LOGIN_URL,
json=login_json,
cookies=get_login.cookies)
login_json = {"_csrf": self._csrf, "email": username, "password": password}
post_login = reqs.post(LOGIN_URL, json=login_json, cookies=get_login.cookies)

# On a successful authentication the Overleaf API returns a new authenticated cookie.
# If the cookie is different than the cookie of the GET request the authentication was successful
Expand All @@ -95,10 +101,10 @@ def all_projects(self):
projects_page = reqs.get(PROJECT_URL, cookies=self._cookie)

json_content = json.loads(
BeautifulSoup(projects_page.content, 'html.parser').find(
'meta', {
'name': 'ol-prefetchedProjectsBlob'
}).get('content'))
BeautifulSoup(projects_page.content,
'html.parser').find('meta', {
'name': 'ol-prefetchedProjectsBlob'
}).get('content'))

return list(OverleafClient.filter_projects(json_content['projects']))

Expand All @@ -111,10 +117,10 @@ def get_project(self, project_name):

projects_page = reqs.get(PROJECT_URL, cookies=self._cookie)
json_content = json.loads(
BeautifulSoup(projects_page.content, 'html.parser').find(
'meta', {
'name': 'ol-prefetchedProjectsBlob'
}).get('content'))
BeautifulSoup(projects_page.content,
'html.parser').find('meta', {
'name': 'ol-prefetchedProjectsBlob'
}).get('content'))
return next(
OverleafClient.filter_projects(json_content['projects'],
{"name": project_name}), None)
Expand All @@ -125,9 +131,7 @@ def download_project(self, project_id):
Params: project_id, the id of the project
Returns: bytes string (zip file)
"""
r = reqs.get(DOWNLOAD_URL.format(project_id),
stream=True,
cookies=self._cookie)
r = reqs.get(DOWNLOAD_URL.format(project_id), stream=True, cookies=self._cookie)
return r.content

def create_folder(self, project_id, parent_folder_id, folder_name):
Expand Down Expand Up @@ -175,8 +179,8 @@ def set_project_infos(a, project_infos_dict, c, d):
project_infos = project_infos_dict

# Convert cookie from CookieJar to string
cookie = "GCLB={}; overleaf_session2={}".format(
self._cookie["GCLB"], self._cookie["overleaf_session2"])
cookie = "GCLB={}; overleaf_session2={}".format(self._cookie["GCLB"],
self._cookie["overleaf_session2"])

# Connect to Overleaf Socket.IO, send a time parameter and the cookies
socket_io = SocketIO(BASE_URL,
Expand All @@ -188,8 +192,7 @@ def set_project_infos(a, project_infos_dict, c, d):
socket_io.wait_for_callbacks()

# Send the joinProject event and receive the project infos
socket_io.emit('joinProject', {'project_id': project_id},
set_project_infos)
socket_io.emit('joinProject', {'project_id': project_id}, set_project_infos)
socket_io.wait_for_callbacks()

# Disconnect from the socket if still connected
Expand All @@ -198,8 +201,7 @@ def set_project_infos(a, project_infos_dict, c, d):

return project_infos

def upload_file(self, project_id, project_infos, file_name, file_size,
file):
def upload_file(self, project_id, project_infos, file_name, file_size, file):
"""
Upload a file to the project
Expand All @@ -215,10 +217,13 @@ def upload_file(self, project_id, project_infos, file_name, file_size,
# Set the folder_id to the id of the root folder
folder_id = project_infos['rootFolder'][0]['_id']

only_file_name = file_name

# The file name contains path separators, check folders
if PATH_SEP in file_name:
# Remove last item since this is the file name
local_folders = file_name.split(PATH_SEP)[:-1]
items = file_name.split(PATH_SEP)
local_folders, only_file_name = items[:-1], items[-1]
# Set the current remote folder
current_overleaf_folder = project_infos['rootFolder'][0]['folders']

Expand All @@ -233,8 +238,7 @@ def upload_file(self, project_id, project_infos, file_name, file_size,
break
# Create the folder if it doesn't exist
if not exists_on_remote:
new_folder = self.create_folder(project_id, folder_id,
local_folder)
new_folder = self.create_folder(project_id, folder_id, local_folder)
current_overleaf_folder.append(new_folder)
folder_id = new_folder['_id']
current_overleaf_folder = new_folder['folders']
Expand All @@ -243,7 +247,7 @@ def upload_file(self, project_id, project_infos, file_name, file_size,
params = {'folder_id': folder_id}
data = {
"relativePath": "null",
"name": file_name,
"name": only_file_name,
}
files = {"qqfile": (file_name, file)}
headers = {
Expand Down Expand Up @@ -272,41 +276,35 @@ def delete_file(self, project_id, project_infos, file_name):
Returns: True on success, False on fail
"""

file = None

file_type = file_id = None
# The file name contains path separators, check folders
if PATH_SEP in file_name:
local_folders = file_name.split(
PATH_SEP)[:-1] # Remove last item since this is the file name
current_overleaf_folder = project_infos['rootFolder'][0][
'folders'] # Set the current remote folder

for local_folder in local_folders:
for remote_folder in current_overleaf_folder:
if local_folder.lower() == remote_folder['name'].lower():
file = next(
(v for v in remote_folder['docs']
if v['name'] == file_name.split(PATH_SEP)[-1]),
None)
current_overleaf_folder = remote_folder['folders']
break
items = file_name.split(PATH_SEP)
if len(items) > 2:
print('Folder depth is larger than 2. Cannot handle it!')
return False
local_folder, only_file_name = items
# Remove last item since this is the file name
current_overleaf_folder = project_infos['rootFolder'][0]['folders']
for remote_folder in current_overleaf_folder:
if local_folder == remote_folder['name']:
file_id, file_type = search_dic(only_file_name, remote_folder)
break
# File is in root folder
else:
file = next((v for v in project_infos['rootFolder'][0]['docs']
if v['name'] == file_name), None)
remote_folder = project_infos['rootFolder'][0]
file_id, file_type = search_dic(file_name, remote_folder)

# File not found!
if file is None:
return False
if file_id is None: return False

headers = {"X-Csrf-Token": self._csrf}

r = reqs.delete(DELETE_URL.format(project_id, file['_id']),
r = reqs.delete(DELETE_URL.format(project_id, file_type, file_id),
cookies=self._cookie,
headers=headers,
json={})
headers=headers)

return r.status_code == str(204)
return r.status_code == '204'

def download_pdf(self, project_id):
"""
Expand Down Expand Up @@ -340,8 +338,7 @@ def download_pdf(self, project_id):
if compile_result["status"] != "success":
raise reqs.HTTPError()

pdf_file = next(v for v in compile_result['outputFiles']
if v['type'] == 'pdf')
pdf_file = next(v for v in compile_result['outputFiles'] if v['type'] == 'pdf')

download_req = reqs.get(BASE_URL + pdf_file['url'],
cookies=self._cookie,
Expand Down

0 comments on commit 037246b

Please sign in to comment.